mod commands;
mod exit_codes;
mod file_selector;
mod output;
mod password;
mod progress;
use clap::{CommandFactory, Parser, Subcommand, ValueEnum};
use clap_complete::{Shell, generate};
use std::path::PathBuf;
use exit_codes::ExitCode;
#[derive(Parser)]
#[command(name = "zesven")]
#[command(author, version, about = "Pure Rust 7z archive tool", long_about = None)]
#[command(propagate_version = true)]
pub struct Cli {
#[command(subcommand)]
command: Commands,
#[arg(long, short = 'f', value_enum, default_value = "human", global = true)]
format: OutputFormat,
#[arg(long, short = 'q', global = true)]
quiet: bool,
#[arg(long, short = 't', default_value = "0", global = true)]
threads: usize,
}
#[derive(Subcommand)]
enum Commands {
#[command(alias = "x")]
Extract {
archive: PathBuf,
#[arg(short = 'o', long, default_value = ".")]
output: PathBuf,
#[arg(short = 'i', long)]
include: Vec<String>,
#[arg(short = 'e', long)]
exclude: Vec<String>,
#[arg(long, value_enum, default_value = "prompt")]
overwrite: OverwriteMode,
#[arg(short = 'p', long)]
password: Option<String>,
#[arg(long)]
preserve_metadata: bool,
},
#[command(alias = "a")]
Create {
archive: PathBuf,
files: Vec<PathBuf>,
#[arg(short = 'm', long, value_enum, default_value = "lzma2")]
method: CompressionMethod,
#[arg(short = 'l', long, default_value = "5")]
level: u8,
#[arg(long)]
solid: bool,
#[arg(short = 'p', long)]
password: Option<String>,
#[arg(long)]
encrypt_headers: bool,
#[arg(long)]
deterministic: bool,
#[arg(short = 'x', long)]
exclude: Vec<String>,
#[arg(short = 'r', long, default_value = "true")]
recursive: bool,
},
#[command(alias = "l")]
List {
archive: PathBuf,
#[arg(long)]
technical: bool,
#[arg(short = 'p', long)]
password: Option<String>,
},
#[command(alias = "t")]
Test {
archive: PathBuf,
#[arg(short = 'p', long)]
password: Option<String>,
#[arg(short = 'i', long)]
include: Vec<String>,
},
#[command(alias = "i")]
Info {
archive: PathBuf,
#[arg(short = 'p', long)]
password: Option<String>,
},
Completions {
#[arg(value_enum)]
shell: Shell,
},
}
#[derive(Copy, Clone, PartialEq, Eq, ValueEnum)]
pub enum OutputFormat {
Human,
Json,
}
#[derive(Copy, Clone, PartialEq, Eq, ValueEnum)]
pub enum OverwriteMode {
Always,
Never,
Prompt,
}
#[derive(Copy, Clone, PartialEq, Eq, ValueEnum)]
pub enum CompressionMethod {
Copy,
Lzma,
Lzma2,
Deflate,
Bzip2,
}
impl From<CompressionMethod> for zesven::codec::CodecMethod {
fn from(method: CompressionMethod) -> Self {
match method {
CompressionMethod::Copy => zesven::codec::CodecMethod::Copy,
CompressionMethod::Lzma => zesven::codec::CodecMethod::Lzma,
CompressionMethod::Lzma2 => zesven::codec::CodecMethod::Lzma2,
CompressionMethod::Deflate => zesven::codec::CodecMethod::Deflate,
CompressionMethod::Bzip2 => zesven::codec::CodecMethod::BZip2,
}
}
}
fn main() {
ctrlc::set_handler(move || {
eprintln!("\nInterrupted");
std::process::exit(exit_codes::USER_INTERRUPT);
})
.ok();
let cli = Cli::parse();
let exit_code = match cli.command {
Commands::Extract {
archive,
output,
include,
exclude,
overwrite,
password,
preserve_metadata,
} => commands::extract(&commands::ExtractConfig {
archive_path: &archive,
output_dir: &output,
include: &include,
exclude: &exclude,
overwrite,
password,
preserve_metadata,
format: cli.format,
quiet: cli.quiet,
thread_count: cli.threads,
}),
Commands::Create {
archive,
files,
method,
level,
solid,
password,
encrypt_headers,
deterministic,
exclude,
recursive,
} => commands::create(&commands::CreateConfig {
archive_path: &archive,
files: &files,
method,
level,
solid,
password,
encrypt_headers,
deterministic,
exclude: &exclude,
recursive,
format: cli.format,
quiet: cli.quiet,
thread_count: cli.threads,
}),
Commands::List {
archive,
technical,
password,
} => commands::list(&archive, technical, password, cli.format, cli.quiet),
Commands::Test {
archive,
password,
include,
} => commands::test(
&archive,
password,
&include,
cli.format,
cli.quiet,
cli.threads,
),
Commands::Info { archive, password } => {
commands::info(&archive, password, cli.format, cli.quiet)
}
Commands::Completions { shell } => {
let mut cmd = Cli::command();
let name = cmd.get_name().to_string();
generate(shell, &mut cmd, name, &mut std::io::stdout());
ExitCode::Success
}
};
std::process::exit(exit_code.code());
}