Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

zip-cli binary crate #235

Draft
wants to merge 68 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 62 commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
58b088c
add new zip-cli crate in workspace
cosmicexplorer Aug 11, 2024
0039b06
implement matching logic except for --match
cosmicexplorer Aug 22, 2024
5bd3cd6
FINALLY fix input zips iteration
cosmicexplorer Aug 25, 2024
fd539cc
implement a couple basic transforms
cosmicexplorer Aug 25, 2024
0598598
add terrible ContentTransformer
cosmicexplorer Aug 25, 2024
0c78496
add entry spec transformer
cosmicexplorer Aug 25, 2024
459ee82
give up and use an unsafecell
cosmicexplorer Aug 25, 2024
9713c6c
impl transform_name
cosmicexplorer Aug 25, 2024
7dcf7a5
initial extract impl
cosmicexplorer Aug 25, 2024
095167c
add name matchers
cosmicexplorer Aug 25, 2024
b397d6a
impl --match
cosmicexplorer Aug 25, 2024
d361907
modularize extract
cosmicexplorer Aug 25, 2024
e2ae4c5
begin impl transforms
cosmicexplorer Aug 25, 2024
12fb722
refactor args modules
cosmicexplorer Aug 25, 2024
adcc1f2
init entry data
cosmicexplorer Aug 25, 2024
c7176a4
stub out utterly absurd cli spec
cosmicexplorer Aug 25, 2024
28654f6
parse our absurd cli spec
cosmicexplorer Aug 26, 2024
ea507f1
impl merged input
cosmicexplorer Aug 26, 2024
8851583
do absurd stuff without checking for compilation success
cosmicexplorer Aug 26, 2024
93c3bb9
ok it compiles now
cosmicexplorer Aug 26, 2024
bda400d
ok it might even run correctly now?
cosmicexplorer Aug 26, 2024
90e1951
make output files work
cosmicexplorer Aug 26, 2024
559691d
default to regexp for replacement and disallow globs from replacement
cosmicexplorer Aug 26, 2024
8127539
add --{min,max}-size match exprs
cosmicexplorer Aug 26, 2024
c34fbdf
impl pattern transformers
cosmicexplorer Aug 26, 2024
764250e
support --transform!!
cosmicexplorer Aug 26, 2024
0dc57d2
anchoring, prefixes, the whole shebang. i think we're done here
cosmicexplorer Aug 27, 2024
b4914b7
make glob and rx optional dependencies
cosmicexplorer Aug 27, 2024
972d77a
add stub for info command
cosmicexplorer Aug 27, 2024
5a1f812
parameterize the match help text to reuse for info
cosmicexplorer Aug 27, 2024
1254236
stub out info format specs
cosmicexplorer Aug 27, 2024
fbc4264
write out some more help text
cosmicexplorer Aug 27, 2024
d5b14d7
remove unnecessary unsafe
cosmicexplorer Aug 27, 2024
3502d4f
parse archive overview format strings
cosmicexplorer Aug 27, 2024
4ca7ca1
make a trait for format parsing
cosmicexplorer Aug 27, 2024
f9cad05
parse entry format
cosmicexplorer Aug 27, 2024
9967050
finish help text for info
cosmicexplorer Aug 27, 2024
c5018ee
add info command stub
cosmicexplorer Aug 27, 2024
e641d41
implement basic entry info
cosmicexplorer Aug 28, 2024
0c189b2
write directly to the output stream, don't allocate a string
cosmicexplorer Aug 28, 2024
a76244b
add escaped tab component
cosmicexplorer Aug 28, 2024
cd8a9c7
rename some traits and methods
cosmicexplorer Aug 28, 2024
4efaa43
pass around a reference to EntryData instead
cosmicexplorer Aug 28, 2024
2b82478
mess with mode bits to make them look more like ls
cosmicexplorer Aug 28, 2024
1c9c081
add some verbose logs
cosmicexplorer Aug 28, 2024
2aa66de
refactor info modules
cosmicexplorer Aug 28, 2024
3d3afb9
refactor parseable directive
cosmicexplorer Aug 28, 2024
cad8dce
make compiled format strings much more generic (!)
cosmicexplorer Aug 28, 2024
c5f5ebb
refactor modules of compiled formatting
cosmicexplorer Aug 28, 2024
6a29b56
archive format works!!!!! omg
cosmicexplorer Aug 28, 2024
f08b59f
move entry and archive iteration into helper methods
cosmicexplorer Aug 29, 2024
8ecc1b1
make archive formatting work fully with ArchiveData
cosmicexplorer Aug 29, 2024
1d1d347
archive data works for stdin!
cosmicexplorer Aug 29, 2024
b88afb8
add more logging to extraction
cosmicexplorer Aug 29, 2024
eee542f
remove allocations in perms todo sorting
cosmicexplorer Aug 29, 2024
cc8fab9
several preliminary notes added to extract command
cosmicexplorer Aug 29, 2024
a09f020
make process_entry() helper method
cosmicexplorer Aug 29, 2024
b5046a5
remove UnsafeCell!!!
cosmicexplorer Aug 29, 2024
22c417b
don't reallocate the symlink target
cosmicexplorer Aug 29, 2024
e2ec868
move symlink processing to a helper
cosmicexplorer Aug 29, 2024
bc73856
refactor a lot of extraction
cosmicexplorer Aug 29, 2024
0ccd578
ok extract makes a lot more sense now
cosmicexplorer Aug 29, 2024
4167b11
support --archive-comment for compression
cosmicexplorer Aug 29, 2024
fc90ce6
add a TODO
cosmicexplorer Aug 29, 2024
c19b554
make symlink creation more readable
cosmicexplorer Aug 29, 2024
bc1c6ac
refactor output parsing into modules
cosmicexplorer Aug 29, 2024
404de6a
make parsing outputs much MUCH more readable with a builder
cosmicexplorer Aug 29, 2024
69670e3
all info directives are now supported
cosmicexplorer Aug 29, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ authors = [
license = "MIT"
repository = "https://github.com/zip-rs/zip2.git"
keywords = ["zip", "archive", "compression"]
categories = ["compression", "filesystem", "parser-implementations"]
rust-version = "1.73.0"
description = """
Library to support the reading and writing of zip files.
Expand All @@ -23,7 +24,9 @@ all-features = true
rustdoc-args = ["--cfg", "docsrs"]

[workspace.dependencies]
arbitrary = { version = "1.3.2", features = ["derive"] }
time = { version = "0.3.36", default-features = false }
zip = { path = ".", default-features = false }

[dependencies]
aes = { version = "0.8.4", optional = true }
Expand Down Expand Up @@ -53,7 +56,7 @@ lzma-rs = { version = "0.3.0", default-features = false, optional = true }
crossbeam-utils = "0.8.20"

[target.'cfg(fuzzing)'.dependencies]
arbitrary = { version = "1.3.2", features = ["derive"] }
arbitrary.workspace = true

[dev-dependencies]
bencher = "0.1.5"
Expand Down
70 changes: 70 additions & 0 deletions cli/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
[package]
name = "zip-cli"
version = "0.0.1"
authors = [
"Danny McClanahan <dmcC2@hypnicjerk.ai>",
]
license = "MIT"
repository = "https://github.com/zip-rs/zip2.git"
keywords = ["zip", "archive", "compression", "cli"]
categories = ["command-line-utilities", "compression", "filesystem", "development-tools::build-utils"]
rust-version = "1.74.0"
description = """
Binary for creation and manipulation of zip files.
"""
edition = "2021"

# Prevent this from interfering with workspaces
[workspace]
members = ["."]

[lib]

[[bin]]
name = "zip-cli"

cosmicexplorer marked this conversation as resolved.
Show resolved Hide resolved
[dependencies]
glob = { version = "0.3", optional = true }
regex = { version = "1", optional = true }

[dependencies.zip]
path = ".."
default-features = false

[features]
aes-crypto = ["zip/aes-crypto"]
bzip2 = ["zip/bzip2"]
chrono = ["zip/chrono"]
deflate64 = ["zip/deflate64"]
deflate = ["zip/deflate"]
deflate-flate2 = ["zip/deflate-flate2"]
deflate-zlib = ["zip/deflate-zlib"]
deflate-zlib-ng = ["zip/deflate-zlib-ng"]
deflate-zopfli = ["zip/deflate-zopfli"]
lzma = ["zip/lzma"]
time = ["zip/time"]
xz = ["zip/xz"]
zstd = ["zip/zstd"]

glob = ["dep:glob"]
rx = ["dep:regex"]

default = [
"aes-crypto",
"bzip2",
"deflate64",
"deflate",
"lzma",
"time",
"xz",
"zstd",
"glob",
"rx",
]


[profile.release]
strip = true
lto = true
opt-level = 3
codegen-units = 1
35 changes: 35 additions & 0 deletions cli/clite/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
[package]
name = "zip-clite"
version = "0.0.1"
authors = [
"Danny McClanahan <dmcC2@hypnicjerk.ai>",
]
license = "MIT"
repository = "https://github.com/zip-rs/zip2.git"
keywords = ["zip", "archive", "compression", "cli"]
categories = ["command-line-utilities", "compression", "filesystem", "development-tools::build-utils"]
rust-version = "1.74.0"
description = """
Binary for creation and manipulation of zip files.
"""
edition = "2021"

# Prevent this from interfering with workspaces
[workspace]
members = ["."]

[[bin]]
name = "zip-clite"

[dependencies]

[dependencies.zip-cli]
path = ".."
default-features = false
features = ["deflate-flate2", "deflate-zlib"]

[profile.release]
strip = true
lto = true
opt-level = "s"
cosmicexplorer marked this conversation as resolved.
Show resolved Hide resolved
codegen-units = 1
3 changes: 3 additions & 0 deletions cli/clite/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fn main() {
zip_cli::driver::main();
}
208 changes: 208 additions & 0 deletions cli/src/args.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
use std::{collections::VecDeque, ffi::OsString, fmt, sync::OnceLock};

#[derive(Debug)]
pub enum ArgParseError {
StdoutMessage(String),
StderrMessage(String),
}

#[derive(Debug)]
pub struct ZipCli {
pub verbose: bool,
pub command: ZipCommand,
}

#[derive(Debug)]
enum SubcommandName {
Compress,
Info,
Extract,
}

static PARSED_EXE_NAME: OnceLock<String> = OnceLock::new();

impl ZipCli {
const VERSION: &'static str = env!("CARGO_PKG_VERSION");
const DESCRIPTION: &'static str = env!("CARGO_PKG_DESCRIPTION");

pub const INTERNAL_ERROR_EXIT_CODE: i32 = 3;
pub const ARGV_PARSE_FAILED_EXIT_CODE: i32 = 2;
pub const NON_FAILURE_EXIT_CODE: i32 = 0;

pub fn binary_name() -> &'static str {
PARSED_EXE_NAME.get().expect("binary name was not set yet")
}

fn generate_version_text() -> String {
format!("{} {}\n", Self::binary_name(), Self::VERSION)
}

fn generate_usage_line() -> String {
format!("Usage: {} [OPTIONS] <COMMAND>", Self::binary_name())
}

fn generate_full_help_text() -> String {
format!(
"\
{}

{}

Commands:
{}{}{}
{}{}{}
{}{}{}

Options:
-v, --verbose Write information logs to stderr
-h, --help Print help
-V, --version Print version
",
Self::DESCRIPTION,
Self::generate_usage_line(),
compress::Compress::COMMAND_NAME,
compress::Compress::COMMAND_TABS,
compress::Compress::COMMAND_DESCRIPTION,
info::Info::COMMAND_NAME,
info::Info::COMMAND_TABS,
info::Info::COMMAND_DESCRIPTION,
extract::Extract::COMMAND_NAME,
extract::Extract::COMMAND_TABS,
extract::Extract::COMMAND_DESCRIPTION,
)
}

fn generate_brief_help_text(context: &str) -> String {
format!(
"\
error: {context}

{}

For more information, try '--help'.
",
Self::generate_usage_line()
)
}

fn parse_up_to_subcommand_name(
argv: &mut VecDeque<OsString>,
) -> Result<(bool, SubcommandName), ArgParseError> {
let mut verbose: bool = false;
let mut subcommand_name: Option<SubcommandName> = None;
while subcommand_name.is_none() {
match argv.pop_front() {
None => {
let help_text = Self::generate_full_help_text();
return Err(ArgParseError::StderrMessage(help_text));
}
Some(arg) => match arg.as_encoded_bytes() {
b"-v" | b"--verbose" => verbose = true,
b"-V" | b"--version" => {
let version_text = Self::generate_version_text();
return Err(ArgParseError::StdoutMessage(version_text));
}
b"-h" | b"--help" => {
let help_text = Self::generate_full_help_text();
return Err(ArgParseError::StdoutMessage(help_text));
}
b"compress" => subcommand_name = Some(SubcommandName::Compress),
b"info" => subcommand_name = Some(SubcommandName::Info),
b"extract" => subcommand_name = Some(SubcommandName::Extract),
arg_bytes => {
let context = if arg_bytes.starts_with(b"-") {
format!("unrecognized global flag {arg:?}")
} else {
format!("unrecognized subcommand name {arg:?}")
};
let help_text = Self::generate_brief_help_text(&context);
return Err(ArgParseError::StderrMessage(help_text));
}
},
}
}
Ok((verbose, subcommand_name.unwrap()))
}

pub fn parse_argv(argv: impl IntoIterator<Item = OsString>) -> Result<Self, ArgParseError> {
let mut argv: VecDeque<OsString> = argv.into_iter().collect();
let exe_name: String = argv
.pop_front()
.expect("exe name not on command line")
.into_string()
.expect("exe name not valid unicode");
PARSED_EXE_NAME
.set(exe_name)
.expect("exe name already written");
let (verbose, subcommand_name) = Self::parse_up_to_subcommand_name(&mut argv)?;
let command = match subcommand_name {
SubcommandName::Info => ZipCommand::Info(info::Info::parse_argv(argv)?),
SubcommandName::Extract => ZipCommand::Extract(extract::Extract::parse_argv(argv)?),
SubcommandName::Compress => ZipCommand::Compress(compress::Compress::parse_argv(argv)?),
};
Ok(Self { verbose, command })
}
}

#[derive(Debug)]
pub enum ZipCommand {
Compress(compress::Compress),
Info(info::Info),
Extract(extract::Extract),
}

pub trait CommandFormat: fmt::Debug {
const COMMAND_NAME: &'static str;
const COMMAND_TABS: &'static str;
const COMMAND_DESCRIPTION: &'static str;

const USAGE_LINE: &'static str;

fn generate_usage_line() -> String {
format!(
"Usage: {} {} {}",
ZipCli::binary_name(),
Self::COMMAND_NAME,
Self::USAGE_LINE,
)
}

fn generate_help() -> String;

fn generate_full_help_text() -> String {
format!(
"\
{}

{}
{}",
Self::COMMAND_DESCRIPTION,
Self::generate_usage_line(),
Self::generate_help(),
)
}

fn generate_brief_help_text(context: &str) -> String {
format!(
"\
error: {context}

{}
",
Self::generate_usage_line()
)
}

fn exit_arg_invalid(context: &str) -> ArgParseError {
let message = Self::generate_brief_help_text(context);
ArgParseError::StderrMessage(message)
}

fn parse_argv(argv: VecDeque<OsString>) -> Result<Self, ArgParseError>
where
Self: Sized;
}

pub mod compress;
pub mod extract;
pub mod info;
Loading
Loading