chiark / gitweb /
bundle auto-zip: works, but needs some progress reporting
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Sun, 15 May 2022 19:16:48 +0000 (20:16 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Sun, 15 May 2022 23:26:51 +0000 (00:26 +0100)
Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
Cargo.toml
cli/usebundles.rs
support/imports.rs

index 684dbe46dd90e909ee00e8b8ccb1877fd4154172..fc7fa67bd4020da429d039a24905dbc33e00a862 100644 (file)
@@ -65,7 +65,6 @@ unicase="2"
 url="2"
 vecdeque-stableix="1"
 xmlparser = "0.13"
-zip="0.6"
 
 ambassador = "0.3.1"
 
@@ -74,6 +73,7 @@ const-default = { version="1",    features=["derive"      ] }
 enum-map     = { version="2"    , features=["serde"       ] }
 image = { version = "0.24", default-features=false, features=["jpeg","png"] }
 index_vec    = { version="0.1.1", features=["serde"       ] }
+zip          = { version="0.6",   features=["time"        ] }
 
 # Repeated in other Cargo.toml's because importing does not work properly
 fehler="1"
index 1f0461a4df1b81f053709929260f8dcb12149ad7..83b70367b9fef6b225c8f599bffb0c8bbb15fcc2 100644 (file)
@@ -74,14 +74,62 @@ impl BundleForUpload {
     bundle
   }
 
-//  #[throws(AE)]
-  pub fn prepare_from_dir<W>(_file: &str, walk: W) -> Result<Self,AE>
+  #[throws(AE)]
+  pub fn prepare_from_dir<W>(dir: &str, walk: W) -> Self
   where W: Iterator<Item=walkdir::Result<walkdir::DirEntry>>
   {
+    let zipfile = tempfile::tempfile().context("create tmp zipfile")?;
+    let zipfile = BufWriter::new(zipfile);
+    let mut zipfile = zipfile::ZipWriter::new(zipfile);
+
     for ent in walk {
-      eprintln!("GOT {:?} {:?}", &ent, &ent.as_ref().unwrap().file_name());
+      let ent = ent?;
+      if ent.file_type().is_dir() { continue }
+
+      let tail = {
+        let comps = ent.path().components().rev()
+          .take(ent.depth())
+          .collect_vec();
+        comps.into_iter().rev().collect::<PathBuf>()
+      };
+
+      let tail = tail.to_str()
+        .ok_or_else(|| anyhow!("non-UTF-8 path in bundle {:?}", tail))?;
+
+      (||{
+        let mut f = File::open(ent.path())
+          .context("start to read")?;
+
+        let metadata = f.metadata().context("fstat")?;
+
+        let perms = metadata.permissions().mode() & 0o700;
+        let perms = perms * 0o111;
+
+        // Can't copy timestamp due to lack of useful support in
+        // the `zip` crate.
+
+        let options = zipfile::write::FileOptions::default()
+          .compression_level(Some(1))
+          .unix_permissions(perms);
+
+        let () = zipfile.start_file(tail, options) // yoy no typestate!
+          .context("start to write")?;
+
+        io::copy(&mut f, &mut zipfile)
+          .context("copy data")?;
+
+        Ok::<_,AE>(())
+      })()
+        .with_context(|| format!("{:?}", tail))
+        .context("add member")?;
     }
-    panic!("NYI")
+
+    let zipfile = zipfile.finish().context("finish zipfile")?;
+    let mut zipfile = zipfile.into_inner()
+      .map_err(|e| e.into_error()).context("flush zipfile")?;
+    zipfile.rewind().context("rewind zipfile")?;
+
+    Self::prepare_open_file(dir, zipfile)?
   }
 }
 
index f244656d47e552123540b35590a8892ad54831e2..4b2b7968c63347b31fc4af675bac8b6cd7f2755a 100644 (file)
@@ -21,7 +21,7 @@ pub use std::net::{IpAddr, SocketAddr, ToSocketAddrs, Ipv6Addr, Ipv4Addr};
 pub use std::os::linux::fs::MetadataExt as _; // todo why linux for st_mode??
 pub use std::os::unix;
 pub use std::os::unix::ffi::OsStrExt;
-pub use std::os::unix::fs::{MetadataExt, OpenOptionsExt};
+pub use std::os::unix::fs::{MetadataExt, OpenOptionsExt, PermissionsExt};
 pub use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd};
 pub use std::os::unix::net::UnixStream;
 pub use std::os::unix::process::{CommandExt, ExitStatusExt};