Skip to content

Commit

Permalink
Allow to create additional entries via the command-line
Browse files Browse the repository at this point in the history
  • Loading branch information
Byron committed Jul 22, 2023
1 parent 567b1a4 commit 4a9d0f1
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 16 deletions.
39 changes: 34 additions & 5 deletions gitoxide-core/src/repository/archive.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,50 @@
use anyhow::bail;
use anyhow::{anyhow, bail};
use gix::worktree::archive;
use gix::Progress;
use std::path::Path;
use std::path::{Path, PathBuf};

pub struct Options {
pub format: Option<archive::Format>,
pub files: Vec<(String, String)>,
pub prefix: Option<String>,
pub add_paths: Vec<PathBuf>,
}

pub fn stream(
repo: gix::Repository,
destination_path: &Path,
rev_spec: Option<&str>,
mut progress: impl Progress,
format: Option<archive::Format>,
Options {
format,
prefix,
add_paths,
files,
}: Options,
) -> anyhow::Result<()> {
let format = format.map_or_else(|| format_from_ext(destination_path), Ok)?;
let object = repo.rev_parse_single(rev_spec.unwrap_or("HEAD"))?.object()?;
let (modification_date, tree) = fetch_rev_info(object)?;

let start = std::time::Instant::now();
let (stream, index) = repo.worktree_stream(tree)?;
let (mut stream, index) = repo.worktree_stream(tree)?;
if !add_paths.is_empty() {
let root = gix::path::realpath(
repo.work_dir()
.ok_or_else(|| anyhow!("Adding files requires a worktree directory that contains them"))?,
)?;
for path in add_paths {
stream.add_entry_from_path(&root, &gix::path::realpath(path)?)?;
}
}
for (path, content) in files {
stream.add_entry(gix::worktree::stream::AdditionalEntry {
id: gix::hash::Kind::Sha1.null(),
mode: gix::object::tree::EntryMode::Blob,
relative_path: path.into(),
source: gix::worktree::stream::entry::Source::Memory(content.into()),
});
}

let mut entries = progress.add_child("entries");
entries.init(Some(index.entries().len()), gix::progress::count("entries"));
Expand All @@ -33,7 +62,7 @@ pub fn stream(
&gix::interrupt::IS_INTERRUPTED,
gix::worktree::archive::Options {
format,
tree_prefix: None,
tree_prefix: prefix.map(gix::bstr::BString::from),
modification_time: modification_date.unwrap_or_else(|| {
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
Expand Down
37 changes: 27 additions & 10 deletions src/plumbing/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,10 @@ pub fn main() -> Result<()> {
#[cfg(feature = "gitoxide-core-tools-archive")]
Subcommands::Archive(crate::plumbing::options::archive::Platform {
format,
prefix,
compression_level,
add_path,
add_virtual_file,
output_file,
treeish,
}) => prepare_and_run(
Expand All @@ -149,21 +152,35 @@ pub fn main() -> Result<()> {
progress_keep_open,
None,
move |progress, _out, _err| {
if add_virtual_file.len() % 2 != 0 {
anyhow::bail!(
"Virtual files must be specified in pairs of two: slash/separated/path content, got {}",
add_virtual_file.join(", ")
)
}
core::repository::archive::stream(
repository(Mode::Lenient)?,
&output_file,
treeish.as_deref(),
progress,
format.map(|f| match f {
crate::plumbing::options::archive::Format::Internal => {
gix::worktree::archive::Format::InternalTransientNonPersistable
}
crate::plumbing::options::archive::Format::Tar => gix::worktree::archive::Format::Tar,
crate::plumbing::options::archive::Format::TarGz => gix::worktree::archive::Format::TarGz,
crate::plumbing::options::archive::Format::Zip => {
gix::worktree::archive::Format::Zip { compression_level }
}
}),
core::repository::archive::Options {
add_paths: add_path,
prefix,
files: add_virtual_file
.chunks(2)
.map(|c| (c[0].to_owned(), c[1].clone()))
.collect(),
format: format.map(|f| match f {
crate::plumbing::options::archive::Format::Internal => {
gix::worktree::archive::Format::InternalTransientNonPersistable
}
crate::plumbing::options::archive::Format::Tar => gix::worktree::archive::Format::Tar,
crate::plumbing::options::archive::Format::TarGz => gix::worktree::archive::Format::TarGz,
crate::plumbing::options::archive::Format::Zip => {
gix::worktree::archive::Format::Zip { compression_level }
}
}),
},
)
},
),
Expand Down
11 changes: 10 additions & 1 deletion src/plumbing/options/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,9 +156,18 @@ pub mod archive {
/// Explicitly set the format. Otherwise derived from the suffix of the output file.
#[clap(long, short = 'f', value_enum)]
pub format: Option<Format>,
/// Apply the prefix verbatim to any path we add to the archive. Use a trailing `/` if prefix is a directory.
#[clap(long)]
pub prefix: Option<String>,
/// The compression strength to use. Currently only used for `.zip` archives, valid from 0-9.
#[clap(long, short = 'c', value_enum)]
#[clap(long, short = 'l', value_enum)]
pub compression_level: Option<u8>,
/// Add the given path to the archive. Directories will always be empty.
#[clap(long, short = 'p')]
pub add_path: Vec<PathBuf>,
/// Add the new file from a slash-separated path, which must happen in pairs of two, first the path, then the content.
#[clap(long, short = 'v')]
pub add_virtual_file: Vec<String>,
/// The file to write the archive to.
///
/// It's extension determines the archive format, unless `--format` is set.
Expand Down

0 comments on commit 4a9d0f1

Please sign in to comment.