From b1107a79738af21a64bce9d97a89d25220ea1868 Mon Sep 17 00:00:00 2001 From: FantasyPvP <80643031+FantasyPvP@users.noreply.github.com> Date: Tue, 19 Mar 2024 00:31:11 +0000 Subject: [PATCH] . . --- Cargo.lock | 11 ++ Cargo.toml | 1 + _v2/.idea/workspace.xml | 118 ++++++++++++++ src/cli.rs | 351 ++++++++++++++++++++-------------------- 4 files changed, 303 insertions(+), 178 deletions(-) create mode 100644 _v2/.idea/workspace.xml diff --git a/Cargo.lock b/Cargo.lock index 813159e..30ef881 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -102,6 +102,16 @@ dependencies = [ "inout", ] +[[package]] +name = "colored" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" +dependencies = [ + "lazy_static", + "windows-sys", +] + [[package]] name = "constant_time_eq" version = "0.1.5" @@ -392,6 +402,7 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" name = "pack_sync" version = "0.1.0" dependencies = [ + "colored", "dirs", "num_cpus", "serde", diff --git a/Cargo.toml b/Cargo.toml index 9422898..e021b97 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ path = "src/server.rs" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +colored = "2.1.0" dirs = "5.0.1" num_cpus = "1.16.0" serde = { version = "1.0.188", features = ["derive"] } diff --git a/_v2/.idea/workspace.xml b/_v2/.idea/workspace.xml new file mode 100644 index 0000000..6968fad --- /dev/null +++ b/_v2/.idea/workspace.xml @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + + + { + "associatedIndex": 5 +} + + + + { + "keyToString": { + "ASKED_SHARE_PROJECT_CONFIGURATION_FILES": "true", + "Cargo.Run Cli.executor": "Run", + "Cargo.Run.executor": "Run", + "RunOnceActivity.OpenProjectViewOnStart": "true", + "RunOnceActivity.ShowReadmeOnStart": "true", + "RunOnceActivity.rust.reset.selective.auto.import": "true", + "SHARE_PROJECT_CONFIGURATION_FILES": "true", + "git-widget-placeholder": "master", + "last_opened_file_path": "/home/fantasypvp/Everything else/packs/_pack_sync/_v2", + "node.js.detected.package.eslint": "true", + "node.js.detected.package.tslint": "true", + "node.js.selected.package.eslint": "(autodetect)", + "node.js.selected.package.tslint": "(autodetect)", + "nodejs_package_manager_path": "npm", + "org.rust.cargo.project.model.PROJECT_DISCOVERY": "true", + "org.rust.cargo.project.model.impl.CargoExternalSystemProjectAware.subscribe.first.balloon": "", + "settings.editor.selected.configurable": "preferences.lookFeel", + "vue.rearranger.settings.migration": "true" + } +} + + + + + + + + + + + 1710716737984 + + + + + + + + + + \ No newline at end of file diff --git a/src/cli.rs b/src/cli.rs index 92a23ff..ee0c18a 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -1,13 +1,13 @@ - - use num_cpus; use std::{ fs::{self, OpenOptions}, - io::{self, Error, ErrorKind, Write}, + io::{self, Error, ErrorKind, Write, Read}, path::{Path, PathBuf}, + collections::HashMap, + slice::SliceIndex }; -use std::collections::HashMap; -use std::slice::SliceIndex; +use colored::Colorize; + use tracing::{event, info, span, Level, warn, error}; use tracing_subscriber::{ filter::{EnvFilter, LevelFilter}, @@ -16,10 +16,11 @@ use tracing_subscriber::{ }; use toml; - use walkdir::WalkDir; -use zip::write::{FileOptions, ZipWriter}; -use zip::CompressionMethod; +use zip::{ + CompressionMethod, ZipArchive, + write::{FileOptions, ZipWriter} +}; use zip_archive::{get_dir_list, Archiver}; @@ -36,7 +37,7 @@ fn main() { ) .with( EnvFilter::builder() - .with_default_directive(LevelFilter::DEBUG.into()) + .with_default_directive(LevelFilter::WARN.into()) .from_env_lossy(), ) .init(); @@ -54,11 +55,27 @@ fn clear_resourcepacks(conf: &Config) -> io::Result<()> { let span = span!(Level::INFO, "clear_packs"); let _guard = span.enter(); - info!("Clearing existing resourcepacks folder"); + conf.versions.iter().for_each(|(k, v)| { + if let Some(folder) = v.resourcepacks.clone() { + match fs::remove_dir_all(&folder) { + Ok(_) => {} + Err(e) => warn!("No existing packs folder detected for version. Creating new folder."), + } + match fs::create_dir(&folder) { + Ok(_) => {} + Err(e) => { + error!("{}", e); + return; + } + }; + } + }); + match fs::remove_dir_all(&conf.resourcepacks) { Ok(_) => {} - Err(e) => warn!("No existing packs folder detected. Creating new folder."), + Err(e) => warn!("No existing global packs folder detected. Creating new folder."), }; + match fs::create_dir(&conf.resourcepacks) { Ok(_) => {} Err(e) => { @@ -66,35 +83,62 @@ fn clear_resourcepacks(conf: &Config) -> io::Result<()> { return Err(e); } }; - info!("Successfully reset resourcepacks folder"); Ok(()) } fn search_dir(path: &PathBuf, config: &Config) -> io::Result<()> { - let span = span!(Level::INFO, "Searching for packs"); + let span = span!(Level::INFO, "Searching"); let _guard = span.enter(); // info!("Searching for packs in {}", path.display()); // check if file is a valid pack - if path.clone().join("pack.toml").exists() { - println!("Found pack {}", path.display()); - Pack::load(&path).unwrap().archive(&path, config).unwrap(); - return Ok(()); - } else { - println!("1c| {}", path.display()); - - for entry in WalkDir::new(path.clone()) - .into_iter() - .filter_map(|e| e.ok()) - .filter(|e| e.file_type().is_dir() && e.file_name() != path) - .filter(|e| !e.file_name().to_str().unwrap().to_string().contains("/_")) - { - println!("PATH {}", entry.path().join(entry.file_name()).to_str().unwrap()); - // search_dir(&entry.path().join(entry.file_name()).to_path_buf(), config).unwrap(); - } - } + println!("{}", "\nArchiving Packs...".blue().underline()); + WalkDir::new(path.clone()) + .into_iter() + .filter_map(|e| e.ok()) + .filter(|e| !e.path().to_str().unwrap().contains("/_")) + .filter(|e| e.file_name().to_str().unwrap() == "pack.toml") + .for_each(|entry| { + if let Ok(pack) = Pack::from_path(&entry.path().to_path_buf()) { + println!(" {} {} {} : {}", "╠»".blue(), "Found".green(), entry.path().to_str().unwrap(), pack.name); + pack.archive( &mut entry.path().to_path_buf(), config).unwrap(); + } + }); + println!("{}", " ╚» Done!".blue()); + println!("{}", "\nChecking for existing zip files...".blue().underline()); + WalkDir::new(path.clone()) + .into_iter() + .filter_map(|e| e.ok()) + .filter(|e| !e.path().to_str().unwrap().contains("/_")) + .filter(|e| e.file_name().to_str().unwrap().ends_with(".zip")) + .for_each(|entry| { + if let Ok(file) = std::fs::File::open(&entry.path().to_path_buf()) { + if let Ok(mut archive) = ZipArchive::new(file) { + if let Ok(mut pack_config) = archive.by_name("pack.toml") { + if let Ok(pack) = Pack::from_string({ + let mut buff = String::new(); + pack_config.read_to_string(&mut buff).unwrap(); + buff + }) { + println!(" {} {} {} : {}", "╠»".blue(), "Found".green(), entry.path().display(), pack.name); + if pack.release { + pack.move_archive(&mut entry.path().to_path_buf(), config).unwrap() + } + } + } else { + println!(" {} {} {}", "╠»".blue(), "Found".green(), entry.path().display()); + if !fs::read_dir(&config.resourcepacks).unwrap().any(|f| f.unwrap().file_name().to_str().unwrap() == format!("{}.zip", entry.file_name().to_str().unwrap()).as_str()) { + fs::copy(entry.path(), format!("{}/{}", &config.resourcepacks, entry.file_name().to_str().unwrap())).unwrap(); + } else { + println!(" {} {}", "║".blue(), " File Already Exists: Ignoring".yellow()); + } + } + } + } + }); + println!("{}", " ╚» Done!".blue()); Ok(()) } @@ -107,56 +151,117 @@ struct Pack { name: String, version: String, description: String, - packs: HashMap, + packs: Option>, } impl Pack { - fn load(path: &PathBuf) -> io::Result { + fn from_path(path: &PathBuf) -> io::Result { + let pack_config = fs::read_to_string(path).unwrap(); + Pack::from_string(pack_config) + } + + fn from_string(pack_config: String) -> io::Result { let span = span!(Level::INFO, "Loading Pack Config file"); let _guard = span.enter(); - let contents = fs::read_to_string(path.join("pack.toml"))?; - let pack = toml::from_str::(&contents).map_err(|e| Error::new(ErrorKind::Other, e))?; - - Ok(pack) + toml::from_str::(&pack_config).map_err(|e| Error::new(ErrorKind::Other, e)) } - fn archive(&self, path: &PathBuf, config: &Config) -> Result<(), Box> { - let span = span!(Level::INFO, "Archiving Pack"); + fn archive( + &self, // pack config + path: &mut PathBuf, // the path to the pack in the filesystem + config: &Config // global config for pack sync + ) -> Result<(), Box> { + let span = span!(Level::INFO, "Archiving Pack "); let _guard = span.enter(); - let resourcepacks = if config.versions.contains_key(&self.version) { + path.pop(); + + if self.packs.is_none() { + return Ok(()) + } + for (k, v) in self.packs.clone().unwrap().iter() { + if v.release { + println!(" {} {} : {}", "╠════»".blue(), "Archiving Version".green(), k); + let zip_file = fs::File::create(format!("{}/{}-{}.zip", self.output_folder(config), self.name, k))?; + let mut zip_writer = ZipWriter::new(zip_file); + + let options = FileOptions::default() + .compression_method(CompressionMethod::Deflated) + .unix_permissions(0o755); + + for entry in WalkDir::new(path.clone()) + .into_iter() + .filter_map(|e| e.ok()) + .filter(|e| { + if v.prefix == "" { // for the "global" instance of the pack / base pack + // ignoring all files that contain a . in the file stem as these are not global textures + !e.path().file_stem().expect("unable to get file stem").to_str().unwrap().contains(".") + } else { + e.path().file_stem().expect("unable to get file stem").to_str().unwrap().starts_with(format!("{}.", v.prefix).as_str()) + } + }) + .filter(|e| e.file_name().to_str().unwrap() != "pack.toml") + { + let file_path = entry.path(); + + if file_path.is_file() { + let mut file = fs::File::open(file_path)?; + let relpath = file_path.strip_prefix(path.clone())?; + let mut zip_path = PathBuf::new(); + + if v.prefix == "" { + zip_path.push(relpath); + } else { + let dir = relpath.parent().unwrap(); + let filename = relpath + .file_name() + .unwrap() + .to_str() + .unwrap() + .to_string() + .strip_prefix(format!("{}.", v.prefix).as_str()) + .unwrap() + .to_string(); + let final_path = dir.join(filename); + zip_path.push(final_path); + } + + zip_writer.start_file(zip_path.to_string_lossy().into_owned(), options)?; + std::io::copy(&mut file, &mut zip_writer)?; + } + } + + zip_writer.finish()?; + } else { + println!(" {} {} : {}", "╠════»".blue(), "Ignoring Version ".yellow(), k); + } + }; + + + Ok(()) + } + + fn output_folder(&self, config: &Config) -> String { + if config.versions.contains_key(&self.version) { match config.versions.get(&self.version).unwrap().resourcepacks.clone() { Some(folder) => folder, None => config.resourcepacks.clone() } } else { config.resourcepacks.clone() - }; - let zip_file = fs::File::create(format!("{}/{}.zip", resourcepacks, self.name))?; - let mut zip_writer = ZipWriter::new(zip_file); - - let options = FileOptions::default() - .compression_method(CompressionMethod::Deflated) - .unix_permissions(0o755); - - for entry in WalkDir::new(path.clone()) - .into_iter() - .filter_map(|e| e.ok()) - { - let file_path = entry.path(); - if file_path.is_file() { - let mut file = fs::File::open(file_path)?; - let relpath = file_path.strip_prefix(path.clone())?; - let mut zip_path = PathBuf::new(); - zip_path.push(relpath); - - zip_writer.start_file(zip_path.to_string_lossy().into_owned(), options)?; - std::io::copy(&mut file, &mut zip_writer)?; - } } - zip_writer.finish()?; + } + fn move_archive(&self, path: &PathBuf, config: &Config) -> io::Result<()> { + let span = span!(Level::INFO, "Moving Pack"); + let _guard = span.enter(); + + if !fs::read_dir(self.output_folder(config)).unwrap().any(|f| f.unwrap().file_name().to_str().unwrap() == format!("{}.zip",self.name).as_str()) { + fs::copy(path, format!("{}/{}.zip", self.output_folder(config), self.name))?; + } else { + println!(" {} {}", "║".blue(), " File Already Exists: Ignoring".yellow()); + } Ok(()) } } @@ -168,110 +273,6 @@ struct PackComponent { release: bool, } -// -// fn scan_directory(path: PathBuf, config: &Config) -> io::Result<()> { -// let mut pack_mcmeta = path.clone(); -// pack_mcmeta.push("pack.mcmeta"); -// if pack_mcmeta.exists() { -// // if pack metadata exists, put the pack into a zip folder. -// get_archive(path, config).map_err(|_| Error::new(ErrorKind::Other, "failed to archive zip"))?; -// return Ok(()); -// } else { -// // recursively scans subdirectories for other packs -// for entry in fs::read_dir(path)? { -// let entry = entry?; -// -// if entry -// .path() -// .file_name() -// .unwrap() -// .to_os_string() -// .into_string() -// .map_err(|_| Error::new(ErrorKind::Other, "failed to convert os_str to string"))? -// .starts_with("_") -// { -// println!("found _"); -// continue; -// } -// if let Some(zip_str) = entry.path().extension() { -// if zip_str == "zip" { -// fs::copy( -// entry.path(), -// format!( -// "{}/{}", -// config.resourcepacks, -// entry -// .path() -// .file_name() -// .unwrap() -// .to_os_string() -// .into_string() -// .map_err(|_| Error::new( -// ErrorKind::Other, -// "failed to convert os_str to string" -// ))? -// ), -// )?; -// } -// } -// -// if let Ok(file_type) = entry.file_type() { -// if file_type.is_dir() { -// scan_directory(entry.path(), &config)?; -// } -// } -// } -// } -// Ok(()) -// } -// -// fn get_archive(path: PathBuf, config: &Config) -> Result<(), Box> { -// println!("CREATING ARCHIVE: {}", &path.display()); -// if let Some(f) = path.file_stem() { -// let mut filename = f -// .to_os_string() -// .into_string() -// .map_err(|_| Error::new(ErrorKind::Other, "failed to convert os_str to string"))?; -// filename.push_str("_0"); -// loop { -// if !Path::new(&format!("{}/{}.zip", config.resourcepacks, filename.to_string())).exists() { -// // checks if zip file already exists -// let zip_file = fs::File::create(format!("{}/{}.zip", config.resourcepacks, filename))?; -// let mut zip_writer = ZipWriter::new(zip_file); -// -// let options = FileOptions::default() -// .compression_method(CompressionMethod::Deflated) -// .unix_permissions(0o755); -// -// for entry in WalkDir::new(path.clone()) -// .into_iter() -// .filter_map(|e| e.ok()) -// { -// let file_path = entry.path(); -// if file_path.is_file() { -// let mut file = fs::File::open(file_path)?; -// let relpath = file_path.strip_prefix(path.clone())?; -// let mut zip_path = PathBuf::new(); -// zip_path.push(relpath); -// -// zip_writer.start_file(zip_path.to_string_lossy().into_owned(), options)?; -// std::io::copy(&mut file, &mut zip_writer)?; -// } -// } -// zip_writer.finish()?; -// break; -// } else { -// // 10 increments the last digit of the filename by 1 -// // TODO: add support for more than one digit -// let i: u32 = filename.pop().unwrap().to_digit(10).unwrap(); -// filename.push(char::from_digit(i + 1, 10).unwrap()); -// } -// } -// } -// Ok(()) -// } - - #[derive(Debug, Deserialize, Serialize)] pub struct VersionConfig { pub pack_repo: Option, @@ -308,16 +309,10 @@ impl Config { if conf_path.exists() { let config: Config = toml::from_str(fs::read_to_string(&conf_path)?.as_str()) .map_err(|_| Error::new(ErrorKind::Other, "failed to deserialise"))?; - info!( - "Loaded Config File: \n\trepo: {}\n\tpacks folder: {}\n\tignore with prefix: {}", - config.repository, config.resourcepacks, config.ignore_folder_prefix - ); + info!("Loaded Config File: \n\trepo: {}\n\tpacks folder: {}\n\tignore with prefix: {}", config.repository, config.resourcepacks, config.ignore_folder_prefix); Ok(config) } else { - warn!( - "No config file detected. Creating config file with default values at:\n\t{}", - conf_path.display() - ); + warn!("No config file detected. Creating config file with default values at:\n\t{}", conf_path.display()); create_config_file(&conf_path)?; Ok(Config::default()) } @@ -326,21 +321,21 @@ impl Config { fn path() -> Option { Some(PathBuf::from(".").join("config.toml")) } + #[cfg(not(debug_assertions))] fn path() -> Option { - dirs::config_dir()?.join("pack_sync").join("config.toml") + Some(dirs::config_dir()?.join("pack_sync").join("config.toml")) } } - fn create_config_file(path: &PathBuf) -> Result<(), Error> { println!("{}", path.display()); fs::create_dir_all(path.parent().unwrap())?; fs::File::create(path)?; - let yaml = serde_yaml::to_string(&Config::default()) + let output = toml::to_string(&Config::default()) .map_err(|_| Error::new(ErrorKind::Other, "failed to serialise"))?; let mut file = OpenOptions::new() @@ -348,7 +343,7 @@ fn create_config_file(path: &PathBuf) -> Result<(), Error> { .create(true) .truncate(true) .open(path)? - .write_all(yaml.as_bytes())?; + .write_all(output.as_bytes())?; Ok(()) } \ No newline at end of file