summaryrefslogtreecommitdiff
path: root/cli/tools/registry/tar.rs
diff options
context:
space:
mode:
authorBartek IwaƄczuk <biwanczuk@gmail.com>2023-11-24 00:38:07 +0100
committerGitHub <noreply@github.com>2023-11-23 23:38:07 +0000
commit585cf2de89f1d253bc14e0835790445d14e324f3 (patch)
tree901234e85d502d960c0cb3126367ca78d17b3225 /cli/tools/registry/tar.rs
parent778e4c971077e38bf8f7d03b8b299d3dd111ba22 (diff)
feat(unstable): tar up directory with deno.json (#21228)
Co-authored-by: David Sherret <dsherret@gmail.com> Co-authored-by: Luca Casonato <lucacasonato@yahoo.com> Co-authored-by: Luca Casonato <hello@lcas.dev>
Diffstat (limited to 'cli/tools/registry/tar.rs')
-rw-r--r--cli/tools/registry/tar.rs85
1 files changed, 85 insertions, 0 deletions
diff --git a/cli/tools/registry/tar.rs b/cli/tools/registry/tar.rs
new file mode 100644
index 000000000..e8097357d
--- /dev/null
+++ b/cli/tools/registry/tar.rs
@@ -0,0 +1,85 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+
+use deno_core::anyhow;
+use deno_core::anyhow::Context;
+use deno_core::error::AnyError;
+use deno_core::url::Url;
+use hyper::body::Bytes;
+use std::io::Write;
+use std::path::PathBuf;
+use tar::Header;
+
+use crate::util::import_map::ImportMapUnfurler;
+
+pub fn create_gzipped_tarball(
+ dir: PathBuf,
+ // TODO(bartlomieju): this is too specific, factor it out into a callback that
+ // returns data
+ unfurler: ImportMapUnfurler,
+) -> Result<Bytes, AnyError> {
+ let mut tar = TarGzArchive::new();
+ let dir_url = Url::from_directory_path(&dir).unwrap();
+
+ for entry in walkdir::WalkDir::new(dir).follow_links(false) {
+ let entry = entry?;
+
+ if entry.file_type().is_file() {
+ let url = Url::from_file_path(entry.path())
+ .map_err(|_| anyhow::anyhow!("Invalid file path {:?}", entry.path()))?;
+ let relative_path = dir_url
+ .make_relative(&url)
+ .expect("children can be relative to parent");
+ let data = std::fs::read(entry.path())
+ .with_context(|| format!("Unable to read file {:?}", entry.path()))?;
+ let content = unfurler
+ .unfurl(&url, data)
+ .with_context(|| format!("Unable to unfurl file {:?}", entry.path()))?;
+ tar.add_file(relative_path, &content).with_context(|| {
+ format!("Unable to add file to tarball {:?}", entry.path())
+ })?;
+ } else if entry.file_type().is_dir() {
+ // skip
+ } else {
+ log::warn!("Unsupported file type at path {:?}", entry.path());
+ }
+ }
+
+ let v = tar.finish().context("Unable to finish tarball")?;
+ Ok(Bytes::from(v))
+}
+
+struct TarGzArchive {
+ builder: tar::Builder<Vec<u8>>,
+}
+
+impl TarGzArchive {
+ pub fn new() -> Self {
+ Self {
+ builder: tar::Builder::new(Vec::new()),
+ }
+ }
+
+ pub fn add_file(
+ &mut self,
+ path: String,
+ data: &[u8],
+ ) -> Result<(), AnyError> {
+ let mut header = Header::new_gnu();
+ header.set_size(data.len() as u64);
+ self.builder.append_data(&mut header, &path, data)?;
+ Ok(())
+ }
+
+ fn finish(mut self) -> Result<Vec<u8>, AnyError> {
+ self.builder.finish()?;
+ let bytes = self.builder.into_inner()?;
+ let mut gz_bytes = Vec::new();
+ let mut encoder = flate2::write::GzEncoder::new(
+ &mut gz_bytes,
+ flate2::Compression::default(),
+ );
+ encoder.write_all(&bytes)?;
+ encoder.finish()?;
+ Ok(gz_bytes)
+ }
+}