chiark / gitweb /
zipfile: Actually read bundle metadata
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Tue, 4 May 2021 19:16:18 +0000 (20:16 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Tue, 4 May 2021 21:01:58 +0000 (22:01 +0100)
Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
src/bundles.rs
src/prelude.rs

index 7ead949b98b5e57b379ded28803611d815cba360..7a8eb0a953edf5bcb65f566a479966deef6ee2de 100644 (file)
@@ -189,6 +189,28 @@ where S: Display + Debug
           index, suffix)
 }
 
+#[ext(pub)]
+impl<R> ZipArchive<R> where R: Read + io::Seek {
+  fn by_name_caseless<'a>(&'a mut self, name: &str)
+                          -> Result<ZipFile<'a>, ZipError>
+  {
+    fn search<'a,R>(za: &'a mut ZipArchive<R>, name: &str)
+                    -> Result<usize, ZipError>
+    where R: Read + io::Seek
+    {
+      for i in 0..za.len() {
+        let m = za.by_index(i);
+        if matches!(m, Err(ZipError::FileNotFound)) { continue }
+        let m = m?;
+        if m.name_raw().eq_ignore_ascii_case(name.as_bytes()) { return Ok(i) }
+      }
+      return Err(ZipError::FileNotFound);
+    }
+    let i = search(self, name)?;
+    self.by_index(i)
+  }
+}
+
 impl Display for Id {
   #[throws(fmt::Error)]
   fn fmt(&self, f: &mut fmt::Formatter) {
@@ -266,6 +288,13 @@ fn load_bundle(ib: &mut InstanceBundles, ig: &mut Instance,
     IE(#[from] IE),
   }
   display_as_debug!{LoadError}
+  use LoadError as LE;
+
+  impl From<ZipError> for LoadError {
+    fn from(ze: ZipError) -> LoadError {
+      LE::BadBundle(format!("bad zipfile: {}", ze))
+    }
+  }
 
   let iu: usize = id.index.into();
 
@@ -281,9 +310,26 @@ fn load_bundle(ib: &mut InstanceBundles, ig: &mut Instance,
   let slot = &mut ib.bundles[iu];
 
   #[throws(LoadError)]
-  fn inner(_ig: &mut Instance,
-           _id: Id, _path: &str) -> Loaded {
-    Loaded { meta: BundleMeta { title: "title!".to_owned() } }
+  fn inner(_ig: &mut Instance, id: Id, path: &str) -> Loaded {
+    match id.kind { Kind::Zip => () }
+    let za = File::open(path)
+      .with_context(|| path.to_owned()).context("open zipfile")
+      .map_err(IE::from)?;
+    let mut za = ZipArchive::new(za)?;
+
+    let meta = {
+      let mut mf = za.by_name_caseless("otter.toml")?;
+      let mut meta = String::new();
+      mf.read_to_string(&mut meta).map_err(
+        |e| LE::BadBundle(format!("access toml zip member: {}", e)))?;
+      let meta = meta.parse().map_err(
+        |e| LE::BadBundle(format!("parse zip member as toml: {}", e)))?;
+      let meta = toml_de::from_value(&meta).map_err(
+        |e| LE::BadBundle(format!("interpret zip member metadata: {}", e)))?;
+      meta
+    };
+
+    Loaded { meta }
     // todo: find zipfile, read metdata toml
     // todo:: show in UI for download
     // todo: do actual things, eg libraries and specs
index cc9dbe039a58a5f070b802bc823ff72ce8e34d3d..4b5538f54b8f282f6b06ec1fa812d4b5cea44849 100644 (file)
@@ -101,6 +101,8 @@ pub use thiserror::Error;
 pub use url::Url;
 pub use vecdeque_stableix::Deque as StableIndexVecDeque;
 pub use void::{unreachable, Void, ResultVoidExt, ResultVoidErrExt};
+pub use zipfile::read::{ZipArchive, ZipFile};
+pub use zipfile::result::ZipError;
 
 use nix::time::ClockId;
 pub const CLOCK_REALTIME : ClockId = ClockId::CLOCK_REALTIME ;