From 3878c83e462635da732ff17d8983bf4ea0bc4501 Mon Sep 17 00:00:00 2001 From: sigoden Date: Fri, 26 Apr 2024 12:51:13 +0000 Subject: [PATCH 1/3] feat: add features for easily integrating argc as lib --- .github/workflows/ci.yaml | 17 +- Argcfile.sh | 5 + Cargo.toml | 49 +- examples/multiline.sh | 2 +- src/argc_value.rs | 4 +- src/bin/argc/main.rs | 62 +- src/bin/argc/parallel.rs | 16 +- src/build.rs | 14 +- src/command/mod.rs | 116 ++-- src/compgen.rs | 567 ++---------------- src/lib.rs | 33 +- src/matcher.rs | 71 ++- src/param.rs | 6 + src/runtime/mod.rs | 90 +++ src/runtime/navite.rs | 177 ++++++ src/shell.rs | 424 +++++++++++++ src/utils.rs | 183 +----- tests/fixtures.rs | 5 +- tests/macros.rs | 36 +- .../integration__compgen__filedir__cd.snap | 8 + ...gration__compgen__filedir__value_name.snap | 5 + 21 files changed, 1095 insertions(+), 795 deletions(-) create mode 100644 src/runtime/mod.rs create mode 100644 src/runtime/navite.rs create mode 100644 src/shell.rs diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 9cbf67a6..6399a10f 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -43,4 +43,19 @@ jobs: run: cargo clippy --all --all-targets - name: Format - run: cargo fmt --all --check \ No newline at end of file + run: cargo fmt --all --check + + features: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Install Rust Toolchain Components + uses: dtolnay/rust-toolchain@stable + + - uses: Swatinem/rust-cache@v2 + + - uses: taiki-e/install-action@cargo-hack + + - run: cargo hack --no-dev-deps check --feature-powerset --depth 2 --lib \ No newline at end of file diff --git a/Argcfile.sh b/Argcfile.sh index 2b698a0d..79cab7e9 100644 --- a/Argcfile.sh +++ b/Argcfile.sh @@ -7,6 +7,11 @@ test() { cargo test "$@" } +# @cmd Test features matrix +test-features() { + cargo hack --no-dev-deps check --feature-powerset --depth 2 --lib +} + # @cmd Check the project # @alias c check() { diff --git a/Cargo.toml b/Cargo.toml index b488bbef..d63691f0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,23 +11,52 @@ autotests = false categories = ["command-line-utilities", "development-tools"] keywords = ["cli", "bash", "runner", "arg", "parser"] +[features] +default = ["application"] +# Feature required for argc the application. Should be disabled when depending on +# argc as a library. +application = [ + "native-runtime", + "eval-bash", + "build", + "mangen", + "completions", + "compgen", + "export", + "wrap-help", + + # deps + "num_cpus", + "threadpool", + "base64", +] +native-runtime = ["which"] +eval = [] +eval-bash = ["eval"] +build = [] +mangen = ["roff"] +completions = [] +compgen = ["dirs", "natord"] +export = ["serde_json", "indexmap/serde"] +wrap-help = ["textwrap"] + [dependencies] anyhow = "1" convert_case = "0.6" -indexmap = { version = "2.1", features = ["serde"] } +indexmap = { version = "2.1" } nom = "7.1" either = "1.8" serde = { version = "1.0", features = ["derive"] } -serde_json = { version = "1.0", features = ["preserve_order"] } -which = "6.0" +serde_json = { version = "1.0", features = ["preserve_order"], optional = true } +which = { version = "6.0", optional = true } shell-words = "1.1" -textwrap = "0.16" -dirs = "5.0" -num_cpus = "1.16" -threadpool = "1.8" -base64 = "0.22" -natord = "1.0" -roff = "0.2" +textwrap = { version = "0.16", optional = true } +dirs = { version = "5.0", optional = true } +num_cpus = { version = "1.16", optional = true } +threadpool = { version = "1.8", optional = true } +base64 = { version = "0.22", optional = true } +natord = { version = "1.0", optional = true } +roff = { version = "0.2", optional = true } [dev-dependencies] insta = "1.30" diff --git a/examples/multiline.sh b/examples/multiline.sh index 361b602c..6820fba5 100755 --- a/examples/multiline.sh +++ b/examples/multiline.sh @@ -19,4 +19,4 @@ # are treated as the long description. A line which is not a comment ends the block. cmd() { :; } -eval "$(TERM_WIDTH=`tput cols` argc --argc-eval "$0" "$@")" \ No newline at end of file +eval "$(TERM_WIDTH=${TERM_WIDTH:-`tput cols`} argc --argc-eval "$0" "$@")" \ No newline at end of file diff --git a/src/argc_value.rs b/src/argc_value.rs index 65436861..d64f90a9 100644 --- a/src/argc_value.rs +++ b/src/argc_value.rs @@ -1,5 +1,6 @@ use indexmap::IndexMap; +#[cfg(feature = "eval-bash")] use crate::utils::{ argc_var_name, escape_shell_words, expand_dotenv, AFTER_HOOK, ARGC_REQUIRE_TOOLS, BEFORE_HOOK, VARIABLE_PREFIX, @@ -25,8 +26,9 @@ pub enum ArgcValue { Error((String, i32)), } +#[cfg(feature = "eval-bash")] impl ArgcValue { - pub fn to_shell(values: &[Self]) -> String { + pub fn to_bash(values: &[Self]) -> String { let mut list = vec![]; let mut last = String::new(); let mut exit = false; diff --git a/src/bin/argc/main.rs b/src/bin/argc/main.rs index 78df1dcd..a9eebcbb 100644 --- a/src/bin/argc/main.rs +++ b/src/bin/argc/main.rs @@ -2,8 +2,8 @@ mod parallel; use anyhow::{anyhow, bail, Context, Result}; use argc::{ - utils::{escape_shell_words, get_current_dir, get_shell_path, is_true_value, termwidth}, - Shell, + utils::{escape_shell_words, is_true_value, ARGC_COMPLETION_SCRIPT_PATH}, + NativeRuntime, Runtime, Shell, }; use base64::{engine::general_purpose, Engine as _}; use std::{ @@ -12,7 +12,6 @@ use std::{ path::{Path, PathBuf}, process, }; -use which::which; const ARGC_SCRIPT_NAMES: [&str; 6] = [ "Argcfile.sh", @@ -38,6 +37,7 @@ fn main() { } fn run() -> Result { + let runtime = NativeRuntime; let args: Vec = std::env::args().collect(); let mut argc_cmd = None; if let Some(arg) = args.get(1) { @@ -65,9 +65,15 @@ fn run() -> Result { code.push_str(&cmds.join(" ")); println!("{code}") } else { - let values = argc::eval(&source, &cmd_args, Some(&args[2]), termwidth())?; + let values = argc::eval( + runtime, + &source, + &cmd_args, + Some(&args[2]), + get_term_width(), + )?; let dir_vars = export_dir_vars(&args[2]); - let code = argc::ArgcValue::to_shell(&values); + let code = argc::ArgcValue::to_bash(&values); let export_vars = export_argc_variables(&code); println!("{dir_vars}{export_vars}{code}") } @@ -85,7 +91,7 @@ fn run() -> Result { "--argc-build" => { let script_path = &args[2]; let (source, args) = parse_script_args(&args[2..])?; - let script = argc::build(&source, &args[0])?; + let script = argc::build(&source, &args[0], get_term_width())?; if let Some(outpath) = args.get(1) { let script_name = get_script_name(script_path)?; let (outpath, new) = ensure_outpath(outpath, script_name) @@ -127,7 +133,7 @@ fn run() -> Result { print!("{}", script); } "--argc-compgen" => { - run_compgen(args.to_vec()); + run_compgen(runtime, args.to_vec()); } "--argc-export" => { let (source, args) = parse_script_args(&args[2..])?; @@ -138,13 +144,13 @@ fn run() -> Result { if args.len() <= 3 { bail!("Usage: argc --argc-parallel