diff options
author | Bartek IwaĆczuk <biwanczuk@gmail.com> | 2023-11-24 00:38:07 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-11-23 23:38:07 +0000 |
commit | 585cf2de89f1d253bc14e0835790445d14e324f3 (patch) | |
tree | 901234e85d502d960c0cb3126367ca78d17b3225 /cli/tools/registry/tar.rs | |
parent | 778e4c971077e38bf8f7d03b8b299d3dd111ba22 (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.rs | 85 |
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) + } +} |