Cross platform Unix-like shell scripting library
Find a file
2025-10-08 10:10:53 +01:00
.cargo chore: set rustc wrapper in .cargo/config.toml instead of mise 2025-10-08 06:56:54 +01:00
.github/workflows ci: use path.join for sccache path and force actions cache v2 2025-10-08 10:10:53 +01:00
src refactor(execute): address clippy lints 2025-10-08 09:37:44 +01:00
tests chore(tests): remove unused import in integration tests 2025-10-08 09:05:05 +01:00
.gitignore feat: support glob expansion (#85) 2023-05-10 19:51:03 -04:00
.rustfmt.toml chore(rustfmt): set rust edition to 2024 2025-10-05 14:08:11 +01:00
Cargo.lock chore(pkg): start versioning from v0.1.0 again 2025-10-06 12:24:08 +01:00
Cargo.toml chore(pkg): start versioning from v0.1.0 again 2025-10-06 12:24:08 +01:00
flake.lock feat: support $@ expansion syntax in commands 2025-09-27 12:02:51 +01:00
flake.nix build(nix): fix incorrect entry for aarch64 macOS 2025-10-07 15:30:30 +01:00
LICENSE chore: rebrand to croshet, remove references to old package 2025-09-29 07:58:42 +01:00
mise.lock chore(mise): include lockfile 2025-10-08 09:04:32 +01:00
mise.toml chore(mise): add redundant RUSTC_WRAPPER env var 2025-10-08 09:44:59 +01:00
README.md chore(README): add more stuff (naming reasoning, short description) 2025-10-06 18:02:52 +01:00

croshet

A cross-platform UNIX-like shell scripting library, developed by pesde primarily to solve the annoying rimraf problem.

Examples

Shorthand macro

Execute a singular command, or run them in bulk without much control over how:

println!(
    "singular exec result: {}, bulk exec results: {:?}",
    sh!("echo hello, croshet!").await?,
    sh!["echo $(pwd)", "mkdir hi_mom", "rm -rf hi_mom", "exit 1"].await?
);

Manual execution

Lower level API to manually run commands with full control over the options and lifecycle of the process:

// Parse the text
let list = croshet::parser::parse(&text)?;
let kill_signal = KillSignal::default();

let options = croshet::ExecuteOptionsBuilder::new()
  .args(std::env::args_os().collect())          // Args to be passed to the shell itself
  .env_vars(std::env::vars_os().collect())      // Environment variables that are set globally
  .cwd(std::env::current_dir()?)                // The working directory of the shell process
  .custom_commands(...)                         // HashMap of custom commands to be defined
  .kill_signal(kill_signal.clone())             // Pass the kill signal to control termination fo the process
  .stdin(croshet::ShellPipeReader::stdin())     // The standard input pipe
  .stdout(croshet::ShellPipeWriter::stdout())   // The standard output pipe
  .stderr(croshet::ShellPipeWriter::stderr())   // The standard error pipe
  .build()?;

// Execute!
println!("Command exited with code: {}", croshet::execute(list.clone(), options.clone()).await);

// ...Or, execute with a timeout
let rt = tokio::task::LocalSet::new()
rt.run_until(async move {
    // Execute the command in a separate task
    tokio::task::spawn_local(async move {
        let exit_code = croshet::execute(list, options).await;
        println!("Command exited with code: {}", exit_code);
    });

    // Wait for 5s to wait for the command to finish executing
    tokio::time::sleep(tokio::time::Duration::from_secs(5)).await;
    kill_signal.send(croshet::SignalKind::SIGKILL);
})

What's with the name?

This project was initially forked from Deno's deno_task_shell, which we found a bit too boring of a name :p

Instead, we settled for the name croshet, pronounced /kroʊˈʃeɪ/ (or simply, 'crochet'), as the library "crochets together" several UNIX-y shell features (most POSIX sh and some bash features, common UNIX command line tools, etc.) with a bit of shell related flair.