diff --git a/src/args.rs b/src/args.rs index 42b6ed9..f0e6228 100644 --- a/src/args.rs +++ b/src/args.rs @@ -45,6 +45,10 @@ pub enum Operation { #[clap(name = "clean", aliases = & ["clean", "cl", "reset"])] Clean, + /// Removes all but the latest 3 versions of each package in a repository + #[clap(name = "prune", aliases = & ["prune", "p"])] + Prune, + /// Pulls in git repositories from mlc.toml branching from current directory #[clap(name = "pull", aliases = & ["u"])] Pull { diff --git a/src/main.rs b/src/main.rs index 97e1297..26aa8fc 100755 --- a/src/main.rs +++ b/src/main.rs @@ -70,6 +70,7 @@ fn main() { repository::generate(verbose); } Operation::Config => operations::config(verbose), + Operation::Prune => operations::prune(verbose), Operation::Clean => operations::clean(verbose), } } diff --git a/src/operations/mod.rs b/src/operations/mod.rs index 1a251dd..e2afbff 100644 --- a/src/operations/mod.rs +++ b/src/operations/mod.rs @@ -3,9 +3,11 @@ pub use clean::*; pub use clone::*; pub use config::*; pub use pull::*; +pub use prune::*; mod build; mod clean; mod clone; mod config; mod pull; +mod prune; \ No newline at end of file diff --git a/src/operations/prune.rs b/src/operations/prune.rs new file mode 100644 index 0000000..9ce0f73 --- /dev/null +++ b/src/operations/prune.rs @@ -0,0 +1,116 @@ +use std::env; +use std::path::PathBuf; +use std::fs; +use crate::info; +use crate::log; +use crate::read_cfg; + +#[derive(Debug, Clone)] +struct PackageFile { + name: String, + ver: String, + ext: String, +} + +pub fn prune(verbose: bool) { + // Read config struct from mlc.toml + let config = read_cfg(verbose); + log!(verbose, "Config: {:?}", config); + + // Read current directory + let current_dir = env::current_dir().unwrap(); + log!(verbose, "Current dir: {:?}", current_dir); + + // Enter out directory + env::set_current_dir("out").unwrap(); + log!(verbose, "Current dir: {:?}", env::current_dir().unwrap()); + + // Read all files from ./ into a Vec, except for .sig files + let mut files: Vec = vec![]; + for entry in fs::read_dir("./").unwrap() { + let entry = entry.unwrap(); + let path = entry.path(); + if path.extension().unwrap() != "sig" { + files.push(path); + } + } + log!(verbose, "Files: {:?}", files); + + // Split files into Vec, turning name-1.0.0-1-x86_64.tar.gz into PackageFile { name: "name", ver: "1.0.0-1", ext: "x86_64.tar.gz" } + let mut packages: Vec = vec![]; + for file in files { + let file = file.to_str().unwrap(); + let mut parts = file.split('-'); + let name = parts.next().unwrap(); + let ver = parts.next().unwrap(); + let rel = parts.next().unwrap(); + let ext = parts.next().unwrap(); + let package = PackageFile { + name: name.to_string(), + ver: ver.to_string() + "-" + &rel.to_string(), + ext: ext.to_string(), + }; + log!(verbose, "Package: {:?}", package); + packages.push(package); + } + + // Split packages into a Vector of Vectors by unique name + let mut packages_by_name: Vec> = vec![]; + for package in &packages { + log!(verbose, "Sorting Package: {:?}", package); + let name = &package.name; + let mut found = false; + for p in packages_by_name.iter_mut() { + if &p[0].name == name { + log!(verbose, "Found {}", name); + found = true; + p.push(package); + } + } + if !found { + log!(verbose, "Creating {}", name); + packages_by_name.push(vec![package]); + } + } + + // Sort each Vector of Vectors by version + for p in packages_by_name.iter_mut() { + log!(verbose, "Sorting {:?}", p); + p.sort_by(|a, b| b.ver.cmp(&a.ver)); + } + + // Pushes all but the 4 most recent versions of each package into a new Vector of PackageFiles + let mut packages_to_delete: Vec = vec![]; + for p in packages_by_name.iter() { + let mut to_delete = vec![]; + for i in 0..p.len() { + if i >= 4 { + log!(verbose, "Deleting {:?}", p[i]); + to_delete.push(p[i].clone()); + } + } + packages_to_delete.extend(to_delete); + } + log!(verbose, "Packages to delete: {:?}", packages_to_delete); + + // Delete all packages in packages_to_delete + for p in packages_to_delete.iter() { + let path = format!("{}-{}-{}", p.name, p.ver, p.ext); + log!(verbose, "Deleting {}", path); + std::process::Command::new("bash").args(&["-c", + &format!("rm -rf ./{} ./{}.sig", path, path) + ]) + .output() + .unwrap(); + } + + // Return to current directory + env::set_current_dir(current_dir).unwrap(); + log!(verbose, "Current dir: {:?}", env::current_dir().unwrap()); + + // Print which packages were deleted + info!("Deleted the following packages:"); + for p in packages_to_delete.iter_mut() { + info!("{}-{}-{}", p.name, p.ver, p.ext); + } +} \ No newline at end of file