diff --git a/Cargo.lock b/Cargo.lock index 5299ad4..50c8171 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,52 @@ dependencies = [ "libc", ] +[[package]] +name = "anstream" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "342258dd14006105c2b75ab1bd7543a03bdf0cfc94383303ac212a04939dff6f" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-wincon", + "concolor-override", + "concolor-query", + "is-terminal", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23ea9e81bd02e310c216d080f6223c179012256e5151c41db88d12c88a1684d2" + +[[package]] +name = "anstyle-parse" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7d1bb534e9efed14f3e5f44e7dd1a4f709384023a4165199a4241e18dff0116" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-wincon" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3127af6145b149f3287bb9a0d10ad9c5692dba8c53ad48285e5bec4063834fa" +dependencies = [ + "anstyle", + "windows-sys 0.45.0", +] + +[[package]] +name = "arrayvec" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" + [[package]] name = "autocfg" version = "1.1.0" @@ -105,6 +151,63 @@ dependencies = [ "winapi", ] +[[package]] +name = "clap" +version = "4.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "046ae530c528f252094e4a77886ee1374437744b2bff1497aa898bbddbbb29b3" +dependencies = [ + "clap_builder", +] + +[[package]] +name = "clap_builder" +version = "4.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "223163f58c9a40c3b0a43e1c4b50a9ce09f007ea2cb1ec258a687945b4b7929f" +dependencies = [ + "anstream", + "anstyle", + "bitflags", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_complete" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01c22dcfb410883764b29953103d9ef7bb8fe21b3fa1158bc99986c2067294bd" +dependencies = [ + "clap", +] + +[[package]] +name = "clap_complete_nushell" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7fa41f5e6aa83bd151b70fd0ceaee703d68cd669522795dc812df9edad1252c" +dependencies = [ + "clap", + "clap_complete", +] + +[[package]] +name = "clap_lex" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a2dd5a6fe8c6e3502f568a6353e5273bbb15193ad9a89e457b9970798efbea1" + +[[package]] +name = "clap_mangen" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4237e29de9c6949982ba87d51709204504fb8ed2fd38232fcb1e5bf7d4ba48c8" +dependencies = [ + "clap", + "roff", +] + [[package]] name = "codespan-reporting" version = "0.11.1" @@ -115,6 +218,34 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "concolor-override" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a855d4a1978dc52fb0536a04d384c2c0c1aa273597f08b77c8c4d3b2eec6037f" + +[[package]] +name = "concolor-query" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88d11d52c3d7ca2e6d0040212be9e4dbbcd78b6447f535b6b561f449427944cf" +dependencies = [ + "windows-sys 0.45.0", +] + +[[package]] +name = "console" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d79fbe8970a77e3e34151cc13d3b3e248aa0faaecb9f6091fa07ebefe5ad60" +dependencies = [ + "encode_unicode", + "lazy_static", + "libc", + "unicode-width", + "windows-sys 0.42.0", +] + [[package]] name = "core-foundation" version = "0.9.3" @@ -320,6 +451,33 @@ version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + +[[package]] +name = "errno" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + [[package]] name = "flate2" version = "1.0.25" @@ -376,12 +534,22 @@ dependencies = [ "libc", ] +[[package]] +name = "hermit-abi" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" + [[package]] name = "hpk" version = "0.1.0" dependencies = [ + "clap", "hpk-package", + "indicatif", + "package-bootstrap", "rayon", + "ron", "serde", "ureq", "url", @@ -455,6 +623,49 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "indicatif" +version = "0.17.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cef509aa9bc73864d6756f0d34d35504af3cf0844373afe9b8669a5b8005a729" +dependencies = [ + "console", + "number_prefix", + "portable-atomic", + "unicode-segmentation", + "unicode-width", + "vt100", +] + +[[package]] +name = "io-lifetimes" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220" +dependencies = [ + "hermit-abi 0.3.1", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "is-terminal" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" +dependencies = [ + "hermit-abi 0.3.1", + "io-lifetimes", + "rustix", + "windows-sys 0.48.0", +] + +[[package]] +name = "itoa" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" + [[package]] name = "jobserver" version = "0.1.26" @@ -473,6 +684,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + [[package]] name = "libc" version = "0.2.141" @@ -488,6 +705,12 @@ dependencies = [ "cc", ] +[[package]] +name = "linux-raw-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f" + [[package]] name = "log" version = "0.4.17" @@ -546,10 +769,16 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" dependencies = [ - "hermit-abi", + "hermit-abi 0.2.6", "libc", ] +[[package]] +name = "number_prefix" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" + [[package]] name = "once_cell" version = "1.17.1" @@ -562,6 +791,18 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +[[package]] +name = "package-bootstrap" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b733f09d474cde789d5a1f62eae77e27749f65a88306a9f60d37d7f5193f2beb" +dependencies = [ + "clap", + "clap_complete", + "clap_complete_nushell", + "clap_mangen", +] + [[package]] name = "percent-encoding" version = "2.2.0" @@ -574,6 +815,12 @@ version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" +[[package]] +name = "portable-atomic" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26f6a7b87c2e435a3241addceeeff740ff8b7e76b74c13bf9acb17fa454ea00b" + [[package]] name = "proc-macro-crate" version = "1.3.1" @@ -645,6 +892,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "roff" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" + [[package]] name = "ron" version = "0.8.0" @@ -656,6 +909,20 @@ dependencies = [ "serde", ] +[[package]] +name = "rustix" +version = "0.37.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85597d61f83914ddeba6a47b3b8ffe7365107221c2e557ed94426489fefb5f77" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys 0.48.0", +] + [[package]] name = "rustls" version = "0.20.8" @@ -704,7 +971,7 @@ version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" dependencies = [ - "windows-sys", + "windows-sys 0.42.0", ] [[package]] @@ -933,6 +1200,12 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-segmentation" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" + [[package]] name = "unicode-width" version = "0.1.10" @@ -975,12 +1248,51 @@ dependencies = [ "serde", ] +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + [[package]] name = "version_check" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "vt100" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84cd863bf0db7e392ba3bd04994be3473491b31e66340672af5d11943c6274de" +dependencies = [ + "itoa", + "log", + "unicode-width", + "vte", +] + +[[package]] +name = "vte" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aae21c12ad2ec2d168c236f369c38ff332bc1134f7246350dca641437365045" +dependencies = [ + "arrayvec", + "utf8parse", + "vte_generate_state_changes", +] + +[[package]] +name = "vte_generate_state_changes" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d257817081c7dffcdbab24b9e62d2def62e2ff7d00b1c20062551e6cccc145ff" +dependencies = [ + "proc-macro2", + "quote", +] + [[package]] name = "walkdir" version = "2.3.3" @@ -1117,7 +1429,7 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" dependencies = [ - "windows-targets", + "windows-targets 0.48.0", ] [[package]] @@ -1135,6 +1447,39 @@ dependencies = [ "windows_x86_64_msvc 0.42.2", ] +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.0", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + [[package]] name = "windows-targets" version = "0.48.0" diff --git a/Cargo.toml b/Cargo.toml index 546c114..90d6796 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,12 +6,41 @@ license = "GPL-3.0-only" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[features] +cli = ["clap", "indicatif", "package-bootstrap"] +bootstrap = ["cli", "package-bootstrap"] + +[[bin]] +name = "hpk" +path = "src/hpk.rs" +required-features = ["cli"] + +[[bin]] +name = "bootstrap" +path = "src/bootstrap.rs" +required-features = ["bootstrap"] + [dependencies] hpk-package = { git = "https://git.hitchhiker-linux.org/jeang3nie/hpk-package.git" } rayon = "1.7" +ron = "0.8" walkdir = "2.3" zstd = "0.12" +[dependencies.clap] +version = "4.1" +optional = true + +[dependencies.indicatif] +version = "0.17" +features = ["improved_unicode", "vt100"] +optional = true + +[dependencies.package-bootstrap] +version = "0.2" +features = ["mangen"] +optional = true + [dependencies.serde] version = "1.0" features = ["derive"] diff --git a/src/bootstrap.rs b/src/bootstrap.rs new file mode 100644 index 0000000..9ee1d91 --- /dev/null +++ b/src/bootstrap.rs @@ -0,0 +1,38 @@ +mod cli; +use { + clap::{Arg, Command}, + cli::cli, + package_bootstrap::Bootstrap, + std::{error::Error, path::PathBuf}, +}; + +fn main() -> Result<(), Box> { + let matches = Command::new("bootstrap") + .about("install the software") + .author("Nathan Fisher") + .version(env!("CARGO_PKG_VERSION")) + .args([ + Arg::new("arch") + .help("the architecture of the binary to be installed") + .short('a') + .long("arch") + .num_args(1), + Arg::new("output") + .help("the output directory for the installation") + .required(true) + .num_args(1), + ]) + .get_matches(); + let outdir = matches.get_one::("output").unwrap().to_string(); + let outdir = PathBuf::from(&outdir); + let arch = matches.get_one::("arch").map(|x| x.to_string()); + Bootstrap::new("hpk", cli(), &outdir).install(arch, 8)?; + Bootstrap::new("hpk-init", cli::init(), &outdir).manpage(8)?; + Bootstrap::new("hpk-create", cli::create(), &outdir).manpage(8)?; + Bootstrap::new("hpk-install", cli::install(), &outdir).manpage(8)?; + Bootstrap::new("hpk-info", cli::info(), &outdir).manpage(8)?; + Bootstrap::new("hpk-search", cli::search(), &outdir).manpage(8)?; + Bootstrap::new("hpk-remove", cli::remove(), &outdir).manpage(8)?; + Bootstrap::new("hpk-upgrade", cli::upgrade(), &outdir).manpage(8)?; + Ok(()) +} diff --git a/src/cli.rs b/src/cli.rs new file mode 100644 index 0000000..797e70e --- /dev/null +++ b/src/cli.rs @@ -0,0 +1,205 @@ +use clap::{value_parser, Arg, ArgAction, Command, ValueHint}; +use std::{env, io, process}; + +/// Open the given uri in an appropriate program +pub fn edit(file: &str) -> Result<(), io::Error> { + if let Ok(ed) = env::var("EDITOR") { + run(&ed, file) + } else { + run("vi", file) + .or_else(|_| run("vim", file)) + .or_else(|_| run("emacs", file)) + .or_else(|_| run("nano", file)) + .or_else(|_| run("ee", file)) + }?; + Ok(()) +} + +fn run(handler: &str, arg: &str) -> Result<(), io::Error> { + process::Command::new(handler).arg(arg).status()?; + Ok(()) +} + +pub fn cli() -> Command { + Command::new("hpk") + .about("A package manager for HitchHiker Linux") + .author("Nathan Fisher") + .version(env!("CARGO_PKG_VERSION")) + .propagate_version(true) + .arg_required_else_help(true) + .subcommands([ + create(), + init(), + search(), + info(), + install(), + remove(), + upgrade(), + ]) +} + +pub fn create() -> Command { + Command::new("create") + .about("Create a new package from a directory of files") + .args([ + Arg::new("directory") + .help("the directory where the files are located") + .value_hint(ValueHint::DirPath) + .required(true) + .num_args(1), + Arg::new("output") + .help("the location to save the package archive and package.ron [default: current working directory]") + .short('o') + .long("output") + .value_name("directory") + .value_hint(ValueHint::DirPath) + .num_args(1), + Arg::new("specs") + .help("path to the package specs file in `ron` format") + .short('s') + .long("specs") + .value_hint(ValueHint::FilePath) + .conflicts_with_all(["name", "package-version", "release", "dependencies"]) + .num_args(1), + Arg::new("name") + .help("package name") + .short('n') + .long("name") + .num_args(1) + .required_unless_present("specs"), + Arg::new("package-version") + .help("package version") + .short('v') + .long("package-version") + .num_args(1) + .required_unless_present("specs"), + Arg::new("release") + .help("release number") + .short('r') + .long("release") + .default_value("1") + .value_parser(value_parser!(u8)), + Arg::new("dependencies") + .help("a comma separated list of dependencies") + .short('d') + .long("dependencies") + .value_delimiter(',') + .num_args(1..), + ]) +} + +pub fn init() -> Command { + Command::new("init") + .about("Initialize a package `specs.ron` file in the current directory") + .args([ + Arg::new("name") + .help("package name") + .short('n') + .long("name") + .num_args(1), + Arg::new("package-version") + .help("package version") + .short('v') + .long("package-version") + .num_args(1), + Arg::new("release") + .help("release number") + .short('r') + .long("release") + .default_value("1") + .value_parser(value_parser!(usize)), + Arg::new("dependencies") + .help("a comma separated list of dependencies") + .short('d') + .long("dependencies") + .value_delimiter(',') + .num_args(1..), + Arg::new("edit") + .help("open specs file in an editor") + .short('e') + .long("edit") + .action(ArgAction::SetTrue), + ]) +} + +pub fn search() -> Command { + Command::new("search") + .about("Search for packages") + .visible_alias("se") + .args([ + Arg::new("installed") + .help("only list installed packages") + .short('i') + .long("installed") + .action(ArgAction::SetTrue), + Arg::new("remote") + .help("do not list installed packages") + .short('r') + .long("remote") + .conflicts_with("installed") + .action(ArgAction::SetTrue), + Arg::new("names") + .help("only search in package names, not descriptions") + .short('n') + .long("names") + .action(ArgAction::SetTrue), + Arg::new("verbose") + .help("display long descriptions for results") + .short('v') + .long("verbose") + .action(ArgAction::SetTrue), + Arg::new("query").use_value_delimiter(false).required(true), + ]) +} + +pub fn info() -> Command { + Command::new("info") + .about("Display information about a specific package") + .arg(Arg::new("name").required(true)) +} + +pub fn install() -> Command { + Command::new("install") + .about("Install packages") + .visible_aliases(["in", "add"]) + .args([ + Arg::new("package") + .required_unless_present("local") + .conflicts_with("local") + .num_args(1..), + Arg::new("local") + .help("install a package from the filesystem") + .short('l') + .long("local") + .value_name("package") + .value_hint(ValueHint::FilePath) + .num_args(1..), + Arg::new("root") + .help("install packages into a different root") + .short('r') + .long("root") + .value_hint(ValueHint::DirPath) + .num_args(1), + ]) +} + +pub fn remove() -> Command { + Command::new("remove") + .about("Remove packages") + .visible_aliases(["rm", "del"]) + .args([ + Arg::new("package").required(true).num_args(1..), + Arg::new("root") + .help("remove packages from a different root") + .short('r') + .long("root") + .value_hint(ValueHint::DirPath) + .num_args(1), + ]) +} + +pub fn upgrade() -> Command { + Command::new("upgrade") + .about("Upgrade packages") + .visible_aliases(["update", "up", "sync"]) +} diff --git a/src/hpk.rs b/src/hpk.rs new file mode 100644 index 0000000..7073466 --- /dev/null +++ b/src/hpk.rs @@ -0,0 +1,177 @@ +#![warn(clippy::all, clippy::pedantic)] +mod cli; +use { + clap::ArgMatches, + cli::cli, + hpk::{Creator, Dependency, Message, Specs, Version}, + indicatif::{ProgressBar, ProgressStyle}, + ron::ser::{to_writer_pretty, PrettyConfig}, + std::{ + env, + error::Error, + ffi::OsStr, + fs::File, + io::{self, BufWriter, ErrorKind}, + path::PathBuf, + sync::mpsc, + thread, + }, +}; + +static TEMPLATE: &str = "[ {prefix} ] {wide_bar}{pos:>5.cyan}/{len:5.green}{msg:>30}"; + +fn main() -> Result<(), Box> { + let matches = cli().get_matches(); + match matches.subcommand() { + Some(("create", matches)) => create(matches)?, + Some(("init", matches)) => { + let specsfile = init(matches)?; + println!("Created specsfile {}", specsfile.display()); + if matches.get_flag("edit") { + cli::edit(specsfile.to_str().unwrap())?; + } + } + Some(("search", matches)) => search(matches)?, + Some(("install", matches)) => install(matches)?, + Some(("remove", matches)) => remove(matches)?, + Some(("upgrade", _)) => upgrade()?, + _ => {} + } + Ok(()) +} + +fn create(matches: &ArgMatches) -> Result<(), Box> { + let dir = PathBuf::from(matches.get_one::("directory").unwrap().to_string()); + let outdir = if let Some(d) = matches.get_one::("output") { + PathBuf::from(&d.to_string()) + } else { + env::current_dir()? + }; + let mut specs = if let Some(s) = matches.get_one::("specs") { + let path = PathBuf::from(s.to_string()); + let fd = File::open(path)?; + ron::de::from_reader(fd)? + } else { + Specs::default() + }; + if let Some(n) = matches.get_one::("name") { + specs.name = n.to_string(); + } + if let Some(v) = matches.get_one::("package-version") { + specs.version = v.to_string().parse::()?; + } + if let Some(r) = matches.get_one::("release") { + specs.release = *r; + } + if let Some(deps) = matches.get_many::("dependencies") { + for d in deps { + let d = Dependency { + name: d.to_string(), + version: (None, None), + }; + specs.dependencies.push(d); + } + } + let creator = Creator::new(&dir, specs.clone())?; + let (sender, receiver) = mpsc::channel(); + let len = creator.len(); + let pb = ProgressBar::new(len as u64); + pb.set_style(ProgressStyle::with_template(TEMPLATE).unwrap()); + pb.set_prefix("Adding files"); + pb.println(format!( + "Creating package {}-{}_{}.tar.zst", + &specs.name, &specs.version, &specs.release + )); + let handle = thread::spawn(move || { + for msg in receiver.iter() { + match msg { + Message::MemberAdded(s) => { + pb.set_message(s.split('/').last().unwrap().to_string()); + pb.inc(1); + } + Message::Success(_s) => { + pb.inc(1); + pb.finish_and_clear(); + } + Message::Failure(s) => { + eprint!("{s}"); + return Err(io::Error::new(io::ErrorKind::Other, s)); + } + } + } + Ok(()) + }); + creator.create(&outdir, sender)?; + match handle.join() { + Ok(_) => { + println!("Package created successfully"); + Ok(()) + } + Err(e) => Err(io::Error::new(ErrorKind::Other, format!("{e:?}")).into()), + } +} + +fn init(matches: &ArgMatches) -> Result> { + let specsfile = PathBuf::from("package.specs"); + let cfg = PrettyConfig::new().struct_names(true); + let buf = File::create(&specsfile)?; + let writer = BufWriter::new(buf); + let specs = create_specs(matches)?; + to_writer_pretty(writer, &specs, cfg)?; + Ok(specsfile) +} + +fn search(_matches: &ArgMatches) -> Result<(), Box> { + unimplemented!(); +} + +fn install(_matches: &ArgMatches) -> Result<(), Box> { + unimplemented!(); +} + +fn remove(_matches: &ArgMatches) -> Result<(), Box> { + unimplemented!(); +} + +fn upgrade() -> Result<(), Box> { + unimplemented!(); +} + +#[allow(clippy::cast_possible_truncation)] +pub fn create_specs(matches: &ArgMatches) -> Result> { + let mut specs = Specs::default(); + let mut name: Option = None; + let mut version: Option = None; + let cwd = env::current_dir()?; + if let Some(dir) = cwd.file_name().and_then(OsStr::to_str) { + if let Some((n, v)) = dir.split_once('-') { + name = Some(n.to_string()); + if let Ok(v) = v.parse() { + version = Some(v); + } + } + } + if let Some(name) = matches.get_one::("name") { + specs.name = name.to_string(); + } else if let Some(n) = name { + specs.name = n; + } + if let Some(version) = matches.get_one::("package-version") { + specs.version = version.parse()?; + } else if let Some(v) = version { + specs.version = v; + } + if let Some(release) = matches.get_one::("release") { + specs.release = *release as u8; + } + if let Some(deps) = matches.get_many::("dependencies") { + let deps = deps + .map(|d| Dependency { + name: d.to_string(), + version: (None, None), + }) + .collect::>(); + specs.dependencies = deps; + } + Ok(specs) +}