{"id":17519874,"url":"https://github.com/brainiumllc/bossy","last_synced_at":"2025-04-23T14:10:53.067Z","repository":{"id":57523856,"uuid":"285423064","full_name":"BrainiumLLC/bossy","owner":"BrainiumLLC","description":"Opinionated convenience wrappers for `std::process::Command` and friends.","archived":false,"fork":false,"pushed_at":"2022-08-16T15:20:54.000Z","size":46,"stargazers_count":8,"open_issues_count":1,"forks_count":1,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-03-30T00:23:19.230Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/BrainiumLLC.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE-APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-08-05T23:06:06.000Z","updated_at":"2024-03-21T08:13:43.000Z","dependencies_parsed_at":"2022-09-26T18:10:51.909Z","dependency_job_id":null,"html_url":"https://github.com/BrainiumLLC/bossy","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BrainiumLLC%2Fbossy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BrainiumLLC%2Fbossy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BrainiumLLC%2Fbossy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BrainiumLLC%2Fbossy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/BrainiumLLC","download_url":"https://codeload.github.com/BrainiumLLC/bossy/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249336995,"owners_count":21253488,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-20T10:07:19.759Z","updated_at":"2025-04-17T11:31:53.031Z","avatar_url":"https://github.com/BrainiumLLC.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# `bossy`\n\n[![crates.io badge](http://meritbadge.herokuapp.com/bossy)](https://crates.io/crates/bossy)\n[![docs.rs badge](https://docs.rs/bossy/badge.svg)](https://docs.rs/bossy)\n[![CI Status](https://github.com/BrainiumLLC/bossy/workflows/CI/badge.svg)](https://github.com/BrainiumLLC/bossy/actions)\n\nOpinionated convenience wrappers for `std::process::Command` and friends.\n\nThis crate arose from patterns I found while working on [`cargo-mobile`](https://github.com/BrainiumLLC/cargo-mobile), which does a *ton* of subprocessing. In my not-entirely-humble opinion, `bossy` makes working with commands super convenient!\n\n```rust\nuse bossy::Command;\nuse std::{io::Write as _, path::Path};\n\n// `bossy::Error` contains detailed error information; the process failing to\n// spawn, the process exiting with a non-zero status, stderr contents, etc.\n// For commands with piped output, you'll even have access to the stdout\n// contents.\nfn main() -\u003e bossy::Result\u003c()\u003e {\n    // We generate a ton of helpful logging, if you're into that sort of thing.\n    simple_logger::init().unwrap();\n\n    let path = Path::new(\"src\");\n    println!(\"{:?} directory contents:\", path);\n    // `impure` indicates that this command inherits the parent process's\n    // environment. For more reproducability, you can use `pure` to get a\n    // completely empty environment.\n    let status = Command::impure_parse(\"ls -l\")\n        // `std::process::Command::arg` takes `\u0026mut self` and returns\n        // `\u0026mut Self`; our equivalent of that is `add_arg`, but I personally\n        // prefer using `with_arg`, which takes `self` and returns `Self`.\n        .with_arg(path)\n        // We use more explicit names for our run methods than\n        // `std::process::Command` does:\n        // - `run` (equivalent to `spawn`)\n        // - `run_and_wait` (equivalent to `status`)\n        // - `run_and_wait_for_output` (equivalent to `output`)\n        .run_and_wait()?;\n    // `bossy::ExitStatus` is just a re-export of `std::process::ExitStatus`.\n    println!(\"exited with code {:?}\", status.code());\n\n    let readme_output = Command::impure_parse(\"cat README.md\")\n        // Just like with `std::process::Command::output`, this will\n        // automatically pipe stdout and stderr.\n        .run_and_wait_for_output()?;\n    // `bossy::Output` has cute conveniences for the very common task of\n    // converting output to a string.\n    println!(\n        \"README.md contents:\\n{}\",\n        readme_output\n            .stdout_str()\n            .expect(\"README.md contained invalid utf-8\")\n    );\n\n    let mut handle = Command::impure(\"shasum\")\n        // We also have methods that let you set these using `bossy::Stdio`\n        // (which is currently just a re-export of `std::process::Stdio`), but\n        // this spares you some typing and an import.\n        .with_stdin_piped()\n        .with_stdout_piped()\n        .with_stderr_piped()\n        .run()?;\n    handle\n        .stdin()\n        // This will only be `None` if you forgot to set stdin to piped above.\n        .expect(\"developer error: `handle` stdin not captured\")\n        .write_all(readme_output.stdout())\n        .expect(\"failed to write to `handle` stdin\");\n    // `bossy::Handle` is very similar to `std::process::Child`, but will\n    // log an error message if it's dropped without being waited on.\n    let shasum_output = handle.wait_for_output()?;\n    println!(\n        \"README.md SHA-1 sum: {}\",\n        shasum_output\n            .stdout_str()\n            .expect(\"shasum output contained invalid utf-8\")\n    );\n\n    Ok(())\n}\n```\n\nYou can run [the example](examples/commands.rs) to see the exact same code as above, but like, with output:\n\n```sh\ncargo run --example commands\n```\n\nThere isn't a ton of documentation, but this is a pretty thin wrapper, so documentation for `std::process` will typically apply here as well.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbrainiumllc%2Fbossy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbrainiumllc%2Fbossy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbrainiumllc%2Fbossy/lists"}