diff --git a/ares-package/src/main.rs b/ares-package/src/main.rs index a4aa250..409973c 100644 --- a/ares-package/src/main.rs +++ b/ares-package/src/main.rs @@ -88,4 +88,5 @@ fn main() { }; ar.append_control(&control, mtime).unwrap(); ar.append_data(&data, mtime).unwrap(); + println!("Done."); } diff --git a/ares-package/src/packaging/data.rs b/ares-package/src/packaging/data.rs index ec27650..433a32a 100644 --- a/ares-package/src/packaging/data.rs +++ b/ares-package/src/packaging/data.rs @@ -1,19 +1,21 @@ +use std::collections::HashSet; use std::fs; use std::fs::File; use std::io::{Cursor, Result, Write as IoWrite, Write}; use std::ops::Deref; -use std::path::Path; +use std::path::{Path, PathBuf}; use ar::{Builder as ArBuilder, Header as ArHeader}; use flate2::write::GzEncoder; use flate2::Compression; -use path_slash::{PathBufExt, PathExt as _}; +use path_slash::PathExt as _; use regex::Regex; use tar::{Builder as TarBuilder, EntryType, Header as TarHeader}; use walkdir::WalkDir; use crate::input::data::DataInfo; use crate::input::filter_by_excludes; +use crate::PackageInfo; pub trait AppendData { fn append_data(&mut self, details: &DataInfo, mtime: u64) -> Result<()>; @@ -30,40 +32,27 @@ where let gz = GzEncoder::new(&mut data_tar_gz, Compression::default()); let mut tar = TarBuilder::new(gz); - append_dirs( - &mut tar, - &format!("usr/palm/applications/"), - Option::<&Path>::None, - mtime, - )?; + let mut dir_entries: HashSet = HashSet::new(); + append_tree( &mut tar, format!("usr/palm/applications/{}/", info.app), &details.app.path, + &mut dir_entries, details.excludes.as_ref(), + mtime, )?; for service in &details.services { append_tree( &mut tar, format!("usr/palm/services/{}/", service.info.id), &service.path, + &mut dir_entries, details.excludes.as_ref(), + mtime, )?; } - - append_dirs( - &mut tar, - &format!("usr/palm/packages/{}/", info.id), - Some(Path::new("usr/palm")), - mtime, - )?; - let mut tar_header = TarHeader::new_gnu(); - tar_header.set_path(format!("usr/palm/packages/{}/packageinfo.json", info.id))?; - tar_header.set_mode(0o100644); - tar_header.set_size(details.package_data.len() as u64); - tar_header.set_mtime(mtime); - tar_header.set_cksum(); - tar.append(&tar_header, details.package_data.deref())?; + append_package_info(&mut tar, &mut dir_entries, info, details, mtime)?; drop(tar); let mut ar_header = ArHeader::new(b"data.tar.gz".to_vec(), data_tar_gz.len() as u64); @@ -76,7 +65,7 @@ where fn append_dirs( tar: &mut TarBuilder, path: P, - path_stop: Option<&Path>, + dir_entries: &mut HashSet, mtime: u64, ) -> Result<()> where @@ -87,36 +76,54 @@ where let empty = Vec::::new(); let mut p = path.as_ref(); while p != Path::new("") { - if let Some(s) = path_stop { - if p == s { - break; - } + if dir_entries.contains(p) { + break; } stack.insert(0, p); + dir_entries.insert(p.to_path_buf()); if let Some(parent) = p.parent() { p = parent; } } for p in stack { let mut header = TarHeader::new_gnu(); - header.set_path(format!("{}/", p.to_slash_lossy()))?; + let mut dir = String::from(p.to_slash_lossy()); + if !dir.ends_with('/') { + dir.push('/'); + } + header.set_path(&dir)?; header.set_entry_type(EntryType::Directory); - header.set_mode(0o100755); + header.set_mode(0o100775); header.set_size(0); header.set_uid(0); - header.set_gid(0); + header.set_gid(5000); header.set_mtime(mtime); header.set_cksum(); + println!("Adding {path}", path = dir); tar.append(&header, empty.deref())?; } return Ok(()); } +fn tar_path(prefix: S, path: P) -> PathBuf +where + S: AsRef, + P: AsRef, +{ + return PathBuf::from(format!( + "{}{}", + prefix.as_ref(), + path.as_ref().to_slash_lossy() + )); +} + fn append_tree( tar: &mut TarBuilder, prefix: S, path: P, + dir_entries: &mut HashSet, excludes: Option<&Regex>, + mtime: u64, ) -> Result<()> where W: Write, @@ -134,33 +141,62 @@ where let entry = entry?; let entry_type = entry.file_type(); let entry_metadata = entry.metadata()?; - let tar_path = format!( - "{}{}", - prefix.as_ref(), - entry - .path() - .strip_prefix(base_path) - .unwrap() - .to_slash_lossy() - ); + let entry_path = entry.path(); + let tar_path = tar_path(&prefix, entry_path.strip_prefix(base_path).unwrap()); + if entry_type.is_dir() { + append_dirs(tar, &tar_path, dir_entries, mtime)?; + } else if let Some(parent) = tar_path.parent() { + append_dirs(tar, parent, dir_entries, mtime)?; + } if entry_type.is_symlink() { - let link_target = fs::read_link(entry.path())?; + let link_target = fs::read_link(entry_path)?; + let mut header = TarHeader::new_gnu(); + header.set_metadata(&entry_metadata); + header.set_uid(0); + header.set_gid(5000); + header.set_cksum(); println!( - "Adding symlink {tar_path} => {} ({} bytes)", - link_target.to_slash_lossy(), - entry_metadata.len(), + "Adding {path} -> {target}", + path = tar_path.to_string_lossy(), + target = link_target.to_string_lossy() ); + tar.append_link(&mut header, tar_path, link_target)?; + } else if entry_type.is_file() { let mut header = TarHeader::new_gnu(); + header.set_path(&tar_path)?; header.set_metadata(&entry_metadata); + header.set_uid(0); + header.set_gid(5000); header.set_cksum(); - tar.append_link(&mut header, tar_path, link_target)?; - } else if entry_type.is_dir() { - println!("Adding dir {tar_path} ({} bytes)", entry_metadata.len()); - tar.append_dir(tar_path, entry.path())?; - } else { - println!("Adding file {tar_path} ({} bytes)", entry_metadata.len()); - tar.append_file(tar_path, &mut File::open(entry.path())?)?; + println!("Adding {path}", path = tar_path.to_string_lossy()); + tar.append_data(&mut header, tar_path, &mut File::open(entry_path)?)?; } } return Ok(()); } + +fn append_package_info( + tar: &mut TarBuilder, + dir_entries: &mut HashSet, + info: &PackageInfo, + details: &DataInfo, + mtime: u64, +) -> Result<()> +where + W: Write, +{ + let package_dir = format!("usr/palm/packages/{}/", info.id); + append_dirs(tar, &package_dir, dir_entries, mtime)?; + let mut header = TarHeader::new_gnu(); + let pkg_info_path = format!("usr/palm/packages/{}/packageinfo.json", info.id); + header.set_path(&pkg_info_path)?; + header.set_mode(0o100644); + header.set_size(details.package_data.len() as u64); + header.set_mtime(mtime); + header.set_uid(0); + header.set_gid(5000); + header.set_cksum(); + tar.append(&header, details.package_data.deref())?; + println!("Adding {path}", path = pkg_info_path); + return Ok(()); +}