Skip to content

Commit

Permalink
work
Browse files Browse the repository at this point in the history
  • Loading branch information
TheAlan404 committed Jul 20, 2024
1 parent a41a167 commit a6e2fee
Show file tree
Hide file tree
Showing 45 changed files with 281 additions and 62 deletions.
50 changes: 44 additions & 6 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,5 @@ indextree = "4.6"
schemars = "0.8"
ratatui = "0.27.0"
tokio-tungstenite = "0.23.1"
log = "0.4.22"
env_logger = "0.11.3"
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
46 changes: 41 additions & 5 deletions src/api/app/actions/build/addons.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,34 @@
use std::{path::Path, sync::Arc};
use std::{collections::HashSet, path::Path, sync::Arc};

use anyhow::{Context, Result};
use futures::{stream, StreamExt, TryStreamExt};

use crate::api::{app::App, models::Addon};
use crate::api::{app::App, models::Addon, step::Step};

impl App {
/// Installs new addons and removes old removed addons
pub async fn action_install_addons(self: Arc<Self>, base: &Path) -> Result<()> {
let addons = self.collect_addons().await?;
let base = Arc::new(base.to_owned());

const MAX_CONCURRENT_TASKS: usize = 20;
let (addons_to_add, addons_to_remove): (Vec<Addon>, Vec<Addon>) = if let Some(lockfile) = &*self.existing_lockfile.read().await {
let mut old = HashSet::new();
old.extend(lockfile.addons.clone());

stream::iter(addons).map(Ok).try_for_each_concurrent(
Some(MAX_CONCURRENT_TASKS),
let mut new = HashSet::new();
new.extend(addons);

(new.difference(&old).map(ToOwned::to_owned).collect(), old.difference(&new).map(ToOwned::to_owned).collect())
} else {
(addons, vec![])
};

for addon in &addons_to_remove {
self.clone().action_remove_addon(&base, addon).await?;
}

stream::iter(addons_to_add).map(Ok).try_for_each_concurrent(
Some(20),
move |addon| {
let app = self.clone();
let base = base.clone();
Expand All @@ -27,10 +42,31 @@ impl App {
Ok(())
}

/// Installs a single addon
pub async fn action_install_addon(self: Arc<Self>, base: &Path, addon: &Addon) -> Result<()> {
let steps = addon.resolve_steps(&self).await?;
let dir = base.join(addon.target.as_str());
self.execute_steps(&dir, &steps).await?;
Ok(())
}

/// Removes a single addon
pub async fn action_remove_addon(self: Arc<Self>, base: &Path, addon: &Addon) -> Result<()> {
let steps = addon.resolve_steps(&self).await?;
let dir = base.join(addon.target.as_str());

// TODO

if let Some(meta) = steps.iter().find_map(|x| match x {
Step::CacheCheck(meta) => Some(meta),
Step::Download { metadata, .. } => Some(metadata),
_ => None,
}) {
tokio::fs::remove_file(dir.join(&meta.filename)).await?;
} else {
log::error!("Couldn't remove addon: {addon:#?}");
}

Ok(())
}
}
12 changes: 9 additions & 3 deletions src/api/app/actions/build/bootstrap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ use walkdir::WalkDir;
use crate::api::{app::App, utils::{fs::create_parents, pathdiff::DiffTo}};

impl App {
/// Collects a list of paths to boostrap from
/// and calls [`Self::action_bootstrap_recursive`] for each folder root
pub async fn action_bootstrap(self: Arc<Self>, base: &Path) -> Result<()> {
let mut list = vec![];

Expand All @@ -23,12 +25,13 @@ impl App {
Ok(())
}

/// Recursively walks through the directory and bootstraps every eccountered file
pub async fn action_bootstrap_recursive(self: Arc<Self>, output_base: &Path, input_base: &Path) -> Result<()> {
let output_base = Arc::new(output_base);
let input_base = Arc::new(input_base);

if !input_base.exists() {
println!("{input_base:?} doesnt exist");
log::warn!("{input_base:?} doesnt exist");
return Ok(());
}

Expand Down Expand Up @@ -58,6 +61,7 @@ impl App {
Ok(())
}

/// Decides if file should be 'bootstrapped' (uses variables etc.) or not (straight up copy file)
pub async fn should_bootstrap_file(&self, file: &Path) -> bool {
let ext = file.extension().unwrap_or_default().to_str().unwrap_or_default();

Expand All @@ -77,6 +81,8 @@ impl App {
bootstrap_exts.contains(&ext)
}

Check warning on line 82 in src/api/app/actions/build/bootstrap.rs

View workflow job for this annotation

GitHub Actions / clippy

unused `async` for function with no await statements

warning: unused `async` for function with no await statements --> src/api/app/actions/build/bootstrap.rs:65:5 | 65 | / pub async fn should_bootstrap_file(&self, file: &Path) -> bool { 66 | | let ext = file.extension().unwrap_or_default().to_str().unwrap_or_default(); 67 | | 68 | | let bootstrap_exts = [ ... | 81 | | bootstrap_exts.contains(&ext) 82 | | } | |_____^ | = help: consider removing the `async` from this function = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#unused_async = note: `-W clippy::unused-async` implied by `-W clippy::pedantic` = help: to override `-W clippy::pedantic` add `#[allow(clippy::unused_async)]`

/// Process a single file. Calls [`Self::should_bootstrap_file`] on the file to decide if it should process it
/// or copy it.
pub async fn action_bootstrap_file(self: Arc<Self>, output_base: &Path, input_base: &Path, file: &Path) -> Result<()> {
let lockfile_entry = self.existing_lockfile.read().await.as_ref().map(|lock| lock.bootstrapped_files.get(file)).flatten().cloned();

Check failure on line 87 in src/api/app/actions/build/bootstrap.rs

View workflow job for this annotation

GitHub Actions / clippy

called `map(..).flatten()` on `Option`

error: called `map(..).flatten()` on `Option` --> src/api/app/actions/build/bootstrap.rs:87:75 | 87 | let lockfile_entry = self.existing_lockfile.read().await.as_ref().map(|lock| lock.bootstrapped_files.get(file)).flatten().cloned(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `and_then` and remove the `.flatten()`: `and_then(|lock| lock.bootstrapped_files.get(file))` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#map_flatten

Check warning on line 87 in src/api/app/actions/build/bootstrap.rs

View workflow job for this annotation

GitHub Actions / clippy

unused variable: `lockfile_entry`

warning: unused variable: `lockfile_entry` --> src/api/app/actions/build/bootstrap.rs:87:13 | 87 | let lockfile_entry = self.existing_lockfile.read().await.as_ref().map(|lock| lock.bootstrapped_files.get(file)).flatten().cloned(); | ^^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_lockfile_entry`

Expand All @@ -96,13 +102,13 @@ impl App {
tokio::fs::write(&output_path, bootstrapped_contents.as_ref()).await
.with_context(|| format!("Writing to {output_path:?}"))?;

println!("Bootstrapped: {relative:?}");
log::info!("Bootstrapped: {relative:?}");
} else {
create_parents(&output_path).await?;
tokio::fs::copy(file, &output_path).await
.with_context(|| format!("Copying {file:?} to {output_path:?}"))?;

println!("Copied: {relative:?}");
log::info!("Copied: {relative:?}");
}


Expand Down
1 change: 1 addition & 0 deletions src/api/app/actions/build/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub mod worlds;
pub mod bootstrap;

impl App {
/// Builds the entire server
pub async fn action_build(self: Arc<Self>, base: &Path) -> Result<()> {
self.action_install_jar(base).await?;
self.clone().action_install_addons(base).await?;
Expand Down
1 change: 1 addition & 0 deletions src/api/app/actions/build/server_jar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use anyhow::Result;
use crate::api::{app::App, models::Environment};

impl App {
/// Installs the server jar according to [`crate::api::models::server::Server::jar`]
pub async fn action_install_jar(&self, base: &Path) -> Result<()> {
if let Some(jar) = self.server.read().await.as_ref().map(|(_, server)| {
server.jar.clone()
Expand Down
4 changes: 3 additions & 1 deletion src/api/app/actions/script/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ use std::path::Path;

use anyhow::Result;

use crate::api::{app::App, models::server::Server, tools::java::{get_java_installation_for, JavaInstallation}, utils::script::Shell};
use crate::api::{app::{App, APP_VERSION}, models::server::Server, tools::java::get_java_installation_for, utils::script::Shell};

impl App {
async fn get_script_lines_for(&self, shell: &Shell, server: &Server) -> Result<Vec<String>> {
let mut lines = vec![];

lines.push(shell.comment(&format!("generated by mcman/{APP_VERSION}")));

if *shell == Shell::Bat {
lines.push(format!("title {}", server.name));
Expand Down
6 changes: 4 additions & 2 deletions src/api/app/cache/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ use std::{
path::PathBuf,
};

use anyhow::{anyhow, Context, Result};
use anyhow::{Context, Result};
use serde::de::DeserializeOwned;

use crate::api::{step::CacheLocation, utils::fs::{create_parents, create_parents_sync}};
use crate::api::{step::CacheLocation, utils::fs::create_parents_sync};

pub struct Cache(pub Option<PathBuf>);

Expand All @@ -25,6 +25,7 @@ impl Cache {
Some(self.0.as_ref()?.join(path))
}

/// Tries to read a json file from cache. Returns `None` if it's not in cache or there is not a cache folder
pub fn try_get_json<T: DeserializeOwned>(&self, path: &str) -> Result<Option<T>> {
match &self.0 {
Some(base) => {
Expand All @@ -44,6 +45,7 @@ impl Cache {
}
}

/// Try to write a json file to cache. Does nothing if there is no cache folder
pub fn try_write_json<T: serde::Serialize>(&self, path: &str, data: &T) -> Result<()> {
match &self.0 {
Some(base) => {
Expand Down
4 changes: 3 additions & 1 deletion src/api/app/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ impl App {
url: impl IntoUrl,
f: F,
) -> Result<Response> {
println!("HTTP GET {}", url.as_str());
log::trace!("GET {}", url.as_str());

let req = self.http_client.get(url.as_str());

Expand All @@ -26,6 +26,8 @@ impl App {
.get("x-ratelimit-remaining")
.is_some_and(|x| String::from_utf8_lossy(x.as_bytes()) == "1")
{
log::info!("Hit ratelimit");

let ratelimit_reset =
String::from_utf8_lossy(res.headers()["x-ratelimit-reset"].as_bytes())
.parse::<u64>()?;
Expand Down
11 changes: 11 additions & 0 deletions src/api/app/logging/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use std::path::PathBuf;

pub enum Message {

Check warning on line 3 in src/api/app/logging/mod.rs

View workflow job for this annotation

GitHub Actions / clippy

enum `Message` is never used

warning: enum `Message` is never used --> src/api/app/logging/mod.rs:3:10 | 3 | pub enum Message { | ^^^^^^^
File(FileMessage, PathBuf),
}

pub enum FileMessage {

Check warning on line 7 in src/api/app/logging/mod.rs

View workflow job for this annotation

GitHub Actions / clippy

enum `FileMessage` is never used

warning: enum `FileMessage` is never used --> src/api/app/logging/mod.rs:7:10 | 7 | pub enum FileMessage { | ^^^^^^^^^^^
Copied,
Bootstrapped,
CacheHit,
}
2 changes: 2 additions & 0 deletions src/api/app/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ mod io;
pub mod options;
mod step;
mod vars;
mod logging;
pub use logging::*;

Check warning on line 20 in src/api/app/mod.rs

View workflow job for this annotation

GitHub Actions / clippy

unused import: `logging::*`

warning: unused import: `logging::*` --> src/api/app/mod.rs:20:9 | 20 | pub use logging::*; | ^^^^^^^^^^

pub const APP_VERSION: &str = env!("CARGO_PKG_VERSION");

Expand Down
2 changes: 2 additions & 0 deletions src/api/app/options/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,6 @@ pub struct ApiUrls {
pub mclogs: String,
#[config(default = "https://api.papermc.io/v2", env = "API_URL_MCLOGS")]
pub papermc: String,
#[config(default = "https://raw.githubusercontent.com/ParadigmMC/mcman-meta/main", env = "API_URL_MCMAN_META")]
pub mcman_meta: String,
}
8 changes: 8 additions & 0 deletions src/api/app/step/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@ use crate::api::step::{Step, StepResult};
mod cache_check;
mod download;
mod execute_java;
mod remove_file;

use super::App;

impl App {
/// Execute a list of steps, taking care of their StepResult's.

Check warning on line 15 in src/api/app/step/mod.rs

View workflow job for this annotation

GitHub Actions / clippy

item in documentation is missing backticks

warning: item in documentation is missing backticks --> src/api/app/step/mod.rs:15:55 | 15 | /// Execute a list of steps, taking care of their StepResult's. | ^^^^^^^^^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown = note: `-W clippy::doc-markdown` implied by `-W clippy::pedantic` = help: to override `-W clippy::pedantic` add `#[allow(clippy::doc_markdown)]` help: try | 15 | /// Execute a list of steps, taking care of their `StepResult`'s. | ~~~~~~~~~~~~
/// Skips the next step when a step returns StepResult::Skip

Check warning on line 16 in src/api/app/step/mod.rs

View workflow job for this annotation

GitHub Actions / clippy

item in documentation is missing backticks

warning: item in documentation is missing backticks --> src/api/app/step/mod.rs:16:49 | 16 | /// Skips the next step when a step returns StepResult::Skip | ^^^^^^^^^^^^^^^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown help: try | 16 | /// Skips the next step when a step returns `StepResult::Skip` | ~~~~~~~~~~~~~~~~~~
pub async fn execute_steps(&self, dir: &Path, steps: &[Step]) -> Result<()> {
let mut iter = steps.iter();

Expand All @@ -24,6 +27,7 @@ impl App {
Ok(())
}

/// Execute a single step and return its result
pub async fn execute_step(&self, dir: &Path, step: &Step) -> Result<StepResult> {
match step {
Step::CacheCheck(metadata) => self.execute_step_cache_check(dir, metadata).await
Expand All @@ -43,6 +47,10 @@ impl App {
} => {
self.execute_step_execute_java(dir, args, *java_version, label).await
},

Step::RemoveFile(metadata) => {
self.execute_step_remove_file(dir, metadata).await
},
}
}
}
Loading

0 comments on commit a6e2fee

Please sign in to comment.