diff --git a/README.md b/README.md index 07cbc29..7e61e4a 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ Perusing the cli options will show much of the intended functionality. ### What's already working - [x] initializing a package specs file on the command line -- [ ] creating a package archive from a directory of files +- [x] creating a package archive from a directory of files - [ ] installing local packages - [ ] installing remote packages - [ ] resolving dependencies diff --git a/cli/src/lib.rs b/cli/src/lib.rs index 6726c74..74276c0 100644 --- a/cli/src/lib.rs +++ b/cli/src/lib.rs @@ -23,7 +23,15 @@ fn create() -> Command { .about("Create a new package from a directory of files") .args([ Arg::new("directory") - .help("the directory where the files are located [default: current working directory]") + .help("the directory where the files are located") + .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") diff --git a/src/hpk.rs b/src/hpk.rs index f9a81a3..231074d 100644 --- a/src/hpk.rs +++ b/src/hpk.rs @@ -1,9 +1,9 @@ use { clap::ArgMatches, cli::cli, - hpk::Specs, + hpk::{Dependency, Specs, Version}, ron::ser::{to_writer_pretty, PrettyConfig}, - std::{error::Error, fs::File, io::BufWriter, path::PathBuf}, + std::{error::Error, env, fs::File, io::BufWriter, path::PathBuf}, }; fn main() -> Result<(), Box> { @@ -23,8 +23,41 @@ fn main() -> Result<(), Box> { Ok(()) } -fn create(_matches: &ArgMatches) -> Result<(), Box> { - unimplemented!(); +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)?; + let specs = ron::de::from_reader(fd)?; + specs + } 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); + } + } + hpk::create_package(&dir, specs, &outdir)?; + Ok(()) } fn init(matches: &ArgMatches) -> Result> { diff --git a/src/item/mod.rs b/src/item/mod.rs index c25460c..5ed1f33 100644 --- a/src/item/mod.rs +++ b/src/item/mod.rs @@ -66,6 +66,11 @@ impl Item { } fn fix_path(path: &Path) -> PathBuf { + let path = if let Ok(p) = path.strip_prefix("./") { + &p + } else { + path + }; if path.is_file() || path.is_symlink() { match path.ancestors().last().and_then(Path::to_str) { Some("etc" | "var") => { diff --git a/src/package/mod.rs b/src/package/mod.rs index 972064a..9d3cc33 100644 --- a/src/package/mod.rs +++ b/src/package/mod.rs @@ -1,5 +1,5 @@ use crate::Item; -use std::path::PathBuf; +use std::{path::PathBuf, fs}; use zstd::Encoder; mod dependency; @@ -11,6 +11,7 @@ use { ron::ser::{to_string_pretty, PrettyConfig}, serde::{Deserialize, Serialize}, std::{ + env, error::Error, fs::File, io::{BufWriter, Write}, @@ -88,13 +89,22 @@ impl Package { to_string_pretty(self, cfg) } - pub fn save_ron_and_create_tar_node(&self) -> Result> { - let buf = File::open("package.ron")?; - let meta = buf.metadata()?; + pub fn save_ron_and_create_tar_node(&self, outdir: &Path) -> Result> { + if !outdir.exists() { + fs::create_dir_all(outdir)?; + } + let mut outfile = outdir.to_path_buf(); + outfile.push("package.ron"); + let fd = File::create(&outfile)?; let s = self.as_ron()?; - let mut writer = BufWriter::new(buf); + let mut writer = BufWriter::new(&fd); writer.write_all(s.as_bytes())?; - let node = Node::read_data_to_tar(s.as_bytes(), "package.ron", &meta, None)?; + writer.flush()?; + println!("{} written", outfile.display()); + let dir = env::current_dir()?; + env::set_current_dir(outdir)?; + let node = Node::read_file_to_tar("package.ron")?; + env::set_current_dir(dir)?; Ok(node) } @@ -103,8 +113,13 @@ impl Package { } } -pub fn create(path: &Path, specs: Specs) -> Result<(), Box> { - let mut items = WalkDir::new(path) +pub fn create(path: &Path, specs: Specs, outdir: &Path) -> Result<(), Box> { + if !outdir.exists() { + fs::create_dir_all(outdir)?; + } + let outdir = outdir.canonicalize()?; + env::set_current_dir(path)?; + let mut items = WalkDir::new(".") .into_iter() .collect::>() .par_iter() @@ -132,15 +147,19 @@ pub fn create(path: &Path, specs: Specs) -> Result<(), Box> { let mut package: Package = specs.into(); package.plist = plist; package.size = totalsize; - let node = package.save_ron_and_create_tar_node()?.to_vec()?; + println!("creating package.ron"); + let node = package.save_ron_and_create_tar_node(&outdir)?.to_vec()?; archive.extend(node); - archive.write_all(&[0; 9216])?; + //archive.write_all(&[0; 9216])?; let name = package.fullname(); let mut path = PathBuf::from(&name); path.set_extension("tar.zst"); - let fd = File::open(&path)?; + let mut outfile = outdir.to_path_buf(); + outfile.push(path); + let fd = File::create(&outfile)?; let mut writer = Encoder::new(fd, 0)?; writer.write_all(&archive)?; let _fd = writer.finish()?; + println!("{} saved", outfile.display()); Ok(()) } diff --git a/tar/src/header.rs b/tar/src/header.rs index e56475d..a323c71 100644 --- a/tar/src/header.rs +++ b/tar/src/header.rs @@ -49,6 +49,7 @@ where } } +#[derive(Clone)] pub struct Owner { pub uid: u32, pub gid: u32, @@ -281,8 +282,7 @@ impl Header { header.device_minor[..minor.len()].copy_from_slice(minor.as_bytes()); } header.username[..owner.username.len()].copy_from_slice(owner.username.as_bytes()); - let group = "root"; - header.groupname[..group.len()].copy_from_slice(owner.groupname.as_bytes()); + header.groupname[..owner.groupname.len()].copy_from_slice(owner.groupname.as_bytes()); header.update_checksum()?; Ok(header) } diff --git a/tar/src/lib.rs b/tar/src/lib.rs index d6c2752..a5d6b95 100644 --- a/tar/src/lib.rs +++ b/tar/src/lib.rs @@ -65,7 +65,7 @@ impl Archive { /// /// let data = Archive::new("test/1.txt".to_string()).unwrap(); /// ``` - pub fn new(filename: String) -> Result { + pub fn new(filename: &str) -> Result { Ok(Self { nodes: vec![Node::read_file_to_tar(filename)?], }) @@ -81,7 +81,7 @@ impl Archive { /// let mut data = Archive::new("test/1.txt".to_string()).unwrap(); /// data.append("test/1.txt".to_string()).unwrap(); /// ``` - pub fn append(&mut self, filename: String) -> Result<(), Error> { + pub fn append(&mut self, filename: &str) -> Result<(), Error> { self.nodes.push(Node::read_file_to_tar(filename)?); Ok(()) diff --git a/tar/src/node.rs b/tar/src/node.rs index eb1b6c2..81356be 100644 --- a/tar/src/node.rs +++ b/tar/src/node.rs @@ -57,8 +57,8 @@ impl Node { } /// Open and read a file from the ``filename`` argument to a TarNode. - pub fn read_file_to_tar(filename: String) -> Result { - let header = Header::new(&filename)?; + pub fn read_file_to_tar(filename: &str) -> Result { + let header = Header::new(filename)?; if header.link_indicator[0] != FileType::Normal as u8 { return Ok(Node { header, @@ -66,7 +66,7 @@ impl Node { }); } - let file = File::open(&filename)?; + let file = File::open(filename)?; let mut reader = BufReader::new(file); Ok(Node { header,