Skip to content

Commit

Permalink
utils::{toml, zip}, scriptgen
Browse files Browse the repository at this point in the history
  • Loading branch information
TheAlan404 committed Jul 11, 2024
1 parent e4cb7bd commit 34cdad4
Show file tree
Hide file tree
Showing 12 changed files with 198 additions and 100 deletions.
6 changes: 3 additions & 3 deletions src/api/app/actions/build/mod.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
use std::{path::Path, sync::Arc};
use futures::stream::{self, StreamExt, TryStreamExt};

use anyhow::Result;

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

pub mod addons;
pub mod server_jar;
pub mod worlds;

impl App {
pub async fn action_build(self: Arc<Self>, base: &Path) -> Result<()> {
self.action_install_jar(base).await?;
self.clone().action_install_addons(base).await?;

self.action_generate_script().await?;
self.action_generate_scripts(base).await?;

Ok(())
}
Expand Down
Empty file.
71 changes: 22 additions & 49 deletions src/api/app/actions/script/mod.rs
Original file line number Diff line number Diff line change
@@ -1,66 +1,39 @@
use std::path::Path;

use anyhow::Result;

use crate::api::{app::App, models::server::Server, utils::script::Shell};

impl App {
pub fn get_args(&self, server: &Server) -> Vec<String> {
let (prefix, suffix) = self.get_args_prefix_suffix(server);
let exec = self.get_args_exec(server);

vec![prefix, exec, suffix].concat()
}

pub fn get_args_exec(&self, server: &Server) -> Vec<String> {
server.jar.as_ref().map(|s| s.get_exec_arguments()).unwrap_or_default()
}

pub fn get_args_prefix_suffix(&self, server: &Server) -> (Vec<String>, Vec<String>) {
let mut prefix = vec![];

prefix.extend(server.launcher.jvm_args.split_whitespace().map(ToOwned::to_owned));

// TODO: -Xmx -Xms

prefix.extend(server.launcher.preset_flags.get_flags());

if server.launcher.eula_args && server.jar.as_ref().is_some_and(|x| x.flavor().supports_eula_args()) {
prefix.push(String::from("-Dcom.mojang.eula.agree=true"));
}

for (key, value) in &server.launcher.properties {
let value = serde_json::to_string(value).unwrap();

prefix.push(format!("-D{key}={value}"));
}

let mut suffix = vec![];

if server.launcher.nogui && server.jar.as_ref().is_some_and(|x| x.flavor().supports_nogui()) {
suffix.push(String::from("--nogui"));
}

suffix.extend(server.launcher.game_args.split_whitespace().map(ToOwned::to_owned));

(prefix, suffix)
}

pub fn get_script_lines_for(&self, shell: Shell, server: &Server) -> Vec<String> {
fn get_script_lines_for(&self, shell: &Shell, server: &Server) -> Vec<String> {

Check warning on line 8 in src/api/app/actions/script/mod.rs

View workflow job for this annotation

GitHub Actions / clippy

this argument (1 byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)

warning: this argument (1 byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte) --> src/api/app/actions/script/mod.rs:8:43 | 8 | fn get_script_lines_for(&self, shell: &Shell, server: &Server) -> Vec<String> { | ^^^^^^ help: consider passing by value instead: `Shell` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref = note: `-W clippy::trivially-copy-pass-by-ref` implied by `-W clippy::pedantic` = help: to override `-W clippy::pedantic` add `#[allow(clippy::trivially_copy_pass_by_ref)]`

Check warning on line 8 in src/api/app/actions/script/mod.rs

View workflow job for this annotation

GitHub Actions / clippy

unused `self` argument

warning: unused `self` argument --> src/api/app/actions/script/mod.rs:8:29 | 8 | fn get_script_lines_for(&self, shell: &Shell, server: &Server) -> Vec<String> { | ^^^^^ | = help: consider refactoring to an associated function = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#unused_self = note: `-W clippy::unused-self` implied by `-W clippy::pedantic` = help: to override `-W clippy::pedantic` add `#[allow(clippy::unused_self)]`
let mut lines = vec![];
if shell == Shell::Bat {

if *shell == Shell::Bat {
lines.push(format!("title {}", server.name));
}

lines.extend(server.launcher.prelaunch.clone());
let mut args = server.get_arguments();
args.push(shell.script_args().to_owned());
lines.push(args.join(" "));
lines.extend(server.launcher.postlaunch.clone());
lines
}

lines.push(self.get_args(server).join(" "));
pub fn action_generate_script(&self, shell: Shell, server: &Server, base: &Path) -> Result<()> {
let script = shell.generate_script(self.get_script_lines_for(&shell, server));

lines.extend(server.launcher.postlaunch.clone());
std::fs::write(base.join(format!("start.{}", shell.file_ext())), script)?;

lines
Ok(())
}

pub async fn action_generate_script(&self) -> Result<()> {
todo!()
pub async fn action_generate_scripts(&self, base: &Path) -> Result<()> {
if let Some((_, server)) = &*self.server.read().await {
self.action_generate_script(Shell::Bat, server, base)?;
self.action_generate_script(Shell::Sh, server, base)?;
}

Ok(())
}
}
2 changes: 1 addition & 1 deletion src/api/app/io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::sync::Arc;
use anyhow::Result;
use tokio::sync::RwLock;

use crate::api::{models::{network::{Network, NETWORK_TOML}, server::{Server, SERVER_TOML}}, utils::{try_find_toml_upwards, write_toml}};
use crate::api::{models::{network::{Network, NETWORK_TOML}, server::{Server, SERVER_TOML}}, utils::toml::{try_find_toml_upwards, write_toml}};

use super::App;

Expand Down
36 changes: 36 additions & 0 deletions src/api/models/server/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,39 @@ impl Default for Server {
}
}
}

impl Server {
pub fn get_execution_arguments(&self) -> Vec<String> {
self.jar.as_ref().map(|s| s.get_execution_arguments()).unwrap_or_default()

Check warning on line 50 in src/api/models/server/mod.rs

View workflow job for this annotation

GitHub Actions / clippy

redundant closure

warning: redundant closure --> src/api/models/server/mod.rs:50:31 | 50 | self.jar.as_ref().map(|s| s.get_execution_arguments()).unwrap_or_default() | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `server_type::ServerJar::get_execution_arguments` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure_for_method_calls = note: `-W clippy::redundant-closure-for-method-calls` implied by `-W clippy::pedantic` = help: to override `-W clippy::pedantic` add `#[allow(clippy::redundant_closure_for_method_calls)]`
}

pub fn get_arguments(&self) -> Vec<String> {
let mut args = vec![];

args.extend(self.launcher.jvm_args.split_whitespace().map(ToOwned::to_owned));

// TODO: -Xmx -Xms

args.extend(self.launcher.preset_flags.get_flags());

if self.launcher.eula_args && self.jar.as_ref().is_some_and(|x| x.flavor().supports_eula_args()) {
args.push(String::from("-Dcom.mojang.eula.agree=true"));
}

for (key, value) in &self.launcher.properties {
let value = serde_json::to_string(value).unwrap();

args.push(format!("-D{key}={value}"));
}

args.extend(self.get_execution_arguments());

if self.launcher.nogui && self.jar.as_ref().is_some_and(|x| x.flavor().supports_nogui()) {
args.push(String::from("--nogui"));
}

args.extend(self.launcher.game_args.split_whitespace().map(ToOwned::to_owned));

args
}
}
2 changes: 1 addition & 1 deletion src/api/models/server/server_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ impl ServerJar {
}
}

pub fn get_exec_arguments(&self) -> Vec<String> {
pub fn get_execution_arguments(&self) -> Vec<String> {
match &self.server_type {
ServerType::Forge { .. } => todo!(),
ServerType::Custom { exec, .. } => exec.clone()
Expand Down
2 changes: 1 addition & 1 deletion src/api/models/source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use anyhow::{Context, Result};
use serde::{Deserialize, Serialize};

use super::{mrpack::resolve_mrpack_addons, packwiz::resolve_packwiz_addons, Addon, AddonListFile, ModpackType};
use crate::api::{app::App, models::ModpackSource, utils::read_toml};
use crate::api::{app::App, models::ModpackSource, utils::toml::read_toml};

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(tag = "type", rename_all = "lowercase")]
Expand Down
45 changes: 2 additions & 43 deletions src/api/utils/mod.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,3 @@
use std::{
io::Write,
path::{Path, PathBuf},
};

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

pub mod accessor;
pub mod hashing;
pub mod pathdiff;
Expand All @@ -14,38 +6,5 @@ pub mod url;
pub mod console;
pub mod markdown;
pub mod script;

pub fn try_find_toml_upwards<T: DeserializeOwned>(filename: &str) -> Result<Option<(PathBuf, T)>> {
let mut path = std::env::current_dir()?;

let found_path = loop {
path.push(filename);

if path.is_file() {
break path;
}

if !(path.pop() && path.pop()) {
return Ok(None);
}
};

read_toml(&found_path).map(|data| Some((found_path, data)))
}

pub fn read_toml<T: DeserializeOwned>(path: &Path) -> Result<T> {
let data: T = toml::from_str(&std::fs::read_to_string(&path)?)?;

Ok(data)
}

pub fn write_toml<T: Serialize>(path: &Path, filename: &str, value: &T) -> Result<()> {
std::fs::create_dir_all(path)?;

let content = toml::to_string_pretty(value)?;

let mut file = std::fs::File::open(path.join(filename))?;
file.write_all(content.as_bytes())?;

Ok(())
}
pub mod zip;
pub mod toml;
22 changes: 20 additions & 2 deletions src/api/utils/pathdiff.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
//! https://github.com/Manishearth/pathdiff

Check warning on line 1 in src/api/utils/pathdiff.rs

View workflow job for this annotation

GitHub Actions / clippy

you should put bare URLs between `<`/`>` or make a proper Markdown link

warning: you should put bare URLs between `<`/`>` or make a proper Markdown link --> src/api/utils/pathdiff.rs:1:5 | 1 | //! https://github.com/Manishearth/pathdiff | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown

use std::path::*;

Check warning on line 3 in src/api/utils/pathdiff.rs

View workflow job for this annotation

GitHub Actions / clippy

usage of wildcard import

warning: usage of wildcard import --> src/api/utils/pathdiff.rs:3:5 | 3 | use std::path::*; | ^^^^^^^^^^^^ help: try: `std::path::{Component, Path, PathBuf}` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#wildcard_imports

use anyhow::{anyhow, Result};

pub trait DiffTo {
fn diff_to<P>(&self, path: P) -> Option<PathBuf>
where
P: AsRef<Path>,
Self: AsRef<Path>;

fn try_diff_to<P>(&self, path: P) -> Result<PathBuf>

Check warning on line 13 in src/api/utils/pathdiff.rs

View workflow job for this annotation

GitHub Actions / clippy

method `try_diff_to` is never used

warning: method `try_diff_to` is never used --> src/api/utils/pathdiff.rs:13:8 | 7 | pub trait DiffTo { | ------ method in this trait ... 13 | fn try_diff_to<P>(&self, path: P) -> Result<PathBuf> | ^^^^^^^^^^^
where
P: AsRef<Path>,
Self: AsRef<Path>;
}

impl<B> DiffTo for B
Expand All @@ -18,9 +27,18 @@ where
{
diff_paths(path, self)
}
}

use std::path::*;
fn try_diff_to<P>(&self, path: P) -> anyhow::Result<PathBuf>
where
P: AsRef<Path>,
Self: AsRef<Path>
{
diff_paths(&path, self)
.ok_or(anyhow!("Can't diff paths
Base: {}
Path: {}", self.as_ref().display(), path.as_ref().display()))
}
}

/// Construct a relative path from a provided base directory path to the provided path.
///
Expand Down
7 changes: 7 additions & 0 deletions src/api/utils/script.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@ impl Shell {
}
}

pub fn file_ext(&self) -> &'static str {

Check warning on line 31 in src/api/utils/script.rs

View workflow job for this annotation

GitHub Actions / clippy

this argument (1 byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)

warning: this argument (1 byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte) --> src/api/utils/script.rs:31:21 | 31 | pub fn file_ext(&self) -> &'static str { | ^^^^^ help: consider passing by value instead: `self` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref
match self {
Shell::Sh => "sh",
Shell::Bat => "bat",
}
}

pub fn line_sep(&self) -> &'static str {

Check warning on line 38 in src/api/utils/script.rs

View workflow job for this annotation

GitHub Actions / clippy

this argument (1 byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)

warning: this argument (1 byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte) --> src/api/utils/script.rs:38:21 | 38 | pub fn line_sep(&self) -> &'static str { | ^^^^^ help: consider passing by value instead: `self` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref
match self {
Shell::Sh => "\n",
Expand Down
39 changes: 39 additions & 0 deletions src/api/utils/toml.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
use std::{io::Write, path::{Path, PathBuf}};

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

pub fn try_find_toml_upwards<T: DeserializeOwned>(filename: &str) -> Result<Option<(PathBuf, T)>> {
let mut path = std::env::current_dir()?;

let found_path = loop {
path.push(filename);

if path.is_file() {
break path;
}

if !(path.pop() && path.pop()) {
return Ok(None);
}
};

read_toml(&found_path).map(|data| Some((found_path, data)))
}

pub fn read_toml<T: DeserializeOwned>(path: &Path) -> Result<T> {
let data: T = toml::from_str(&std::fs::read_to_string(&path)?)?;

Check failure on line 25 in src/api/utils/toml.rs

View workflow job for this annotation

GitHub Actions / clippy

the borrowed expression implements the required traits

error: the borrowed expression implements the required traits --> src/api/utils/toml.rs:25:59 | 25 | let data: T = toml::from_str(&std::fs::read_to_string(&path)?)?; | ^^^^^ help: change this to: `path` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrows_for_generic_args = note: `-D clippy::needless-borrows-for-generic-args` implied by `-D clippy::all` = help: to override `-D clippy::all` add `#[allow(clippy::needless_borrows_for_generic_args)]`

Ok(data)
}

pub fn write_toml<T: Serialize>(path: &Path, filename: &str, value: &T) -> Result<()> {

Check warning on line 30 in src/api/utils/toml.rs

View workflow job for this annotation

GitHub Actions / clippy

function `write_toml` is never used

warning: function `write_toml` is never used --> src/api/utils/toml.rs:30:8 | 30 | pub fn write_toml<T: Serialize>(path: &Path, filename: &str, value: &T) -> Result<()> { | ^^^^^^^^^^
std::fs::create_dir_all(path)?;

let content = toml::to_string_pretty(value)?;

let mut file = std::fs::File::open(path.join(filename))?;
file.write_all(content.as_bytes())?;

Ok(())
}
66 changes: 66 additions & 0 deletions src/api/utils/zip.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
use std::{io::{Read, Seek, Write}, path::Path};

use anyhow::{anyhow, Context, Result};

Check warning on line 3 in src/api/utils/zip.rs

View workflow job for this annotation

GitHub Actions / clippy

unused import: `anyhow`

warning: unused import: `anyhow` --> src/api/utils/zip.rs:3:14 | 3 | use anyhow::{anyhow, Context, Result}; | ^^^^^^
use walkdir::WalkDir;
use zip::{write::FileOptions, ZipArchive, ZipWriter};

use crate::api::app::APP_VERSION;

use super::pathdiff::DiffTo;

pub async fn unzip<T: Read + Seek>(reader: T, to: &Path, prefix: Option<String>) -> Result<()> {

Check warning on line 11 in src/api/utils/zip.rs

View workflow job for this annotation

GitHub Actions / clippy

function `unzip` is never used

warning: function `unzip` is never used --> src/api/utils/zip.rs:11:14 | 11 | pub async fn unzip<T: Read + Seek>(reader: T, to: &Path, prefix: Option<String>) -> Result<()> { | ^^^^^
let mut archive = ZipArchive::new(reader)?;

let mut files = archive.file_names().map(ToOwned::to_owned).collect::<Vec<_>>();

if let Some(prefix) = prefix.map(|p| format!("{p}/")) {
if files.iter().all(|f| f.starts_with(&prefix)) {
files = files.into_iter()
.map(|f| f.replacen(&prefix, "", 1))
.collect()

Check warning on line 20 in src/api/utils/zip.rs

View workflow job for this annotation

GitHub Actions / clippy

consider adding a `;` to the last statement for consistent formatting

warning: consider adding a `;` to the last statement for consistent formatting --> src/api/utils/zip.rs:18:13 | 18 | / files = files.into_iter() 19 | | .map(|f| f.replacen(&prefix, "", 1)) 20 | | .collect() | |__________________________^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_if_nothing_returned help: add a `;` here | 18 ~ files = files.into_iter() 19 + .map(|f| f.replacen(&prefix, "", 1)) 20 + .collect(); |
}
}


for filename in files {
if filename.ends_with('/') {
// directory
continue;
}

let mut file = archive.by_name(&filename)?;
let target_path = to.join(&filename);

std::fs::create_dir_all(target_path.parent().unwrap())?;
let mut target_file = std::fs::File::create(&target_path)?;

std::io::copy(&mut file, &mut target_file)?;
}

Ok(())
}

Check warning on line 41 in src/api/utils/zip.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/utils/zip.rs:11:1 | 11 | / pub async fn unzip<T: Read + Seek>(reader: T, to: &Path, prefix: Option<String>) -> Result<()> { 12 | | let mut archive = ZipArchive::new(reader)?; 13 | | 14 | | let mut files = archive.file_names().map(ToOwned::to_owned).collect::<Vec<_>>(); ... | 40 | | Ok(()) 41 | | } | |_^ | = 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

pub async fn zip<T: Write + Seek>(writer: T, folder: &Path) -> Result<()> {

Check warning on line 43 in src/api/utils/zip.rs

View workflow job for this annotation

GitHub Actions / clippy

function `zip` is never used

warning: function `zip` is never used --> src/api/utils/zip.rs:43:14 | 43 | pub async fn zip<T: Write + Seek>(writer: T, folder: &Path) -> Result<()> { | ^^^
let mut archive = ZipWriter::new(writer);

archive.set_comment(format!("generated by mcman/{APP_VERSION}"));

for entry in WalkDir::new(folder) {
let entry = entry.with_context(|| "WalkDir")?;

let path = folder.try_diff_to(entry.path())?;
let path = path.to_string_lossy();

if entry.file_type().is_dir() {
archive.add_directory(path, FileOptions::default())?;
continue;
}

archive.start_file(path, FileOptions::default())?;

let mut file = std::fs::File::open(entry.path())?;
std::io::copy(&mut file, &mut archive)?;
}

Ok(())
}

Check warning on line 66 in src/api/utils/zip.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/utils/zip.rs:43:1 | 43 | / pub async fn zip<T: Write + Seek>(writer: T, folder: &Path) -> Result<()> { 44 | | let mut archive = ZipWriter::new(writer); 45 | | 46 | | archive.set_comment(format!("generated by mcman/{APP_VERSION}")); ... | 65 | | Ok(()) 66 | | } | |_^ | = 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

0 comments on commit 34cdad4

Please sign in to comment.