{"id":26021943,"url":"https://github.com/simonhyll/cargo-commander","last_synced_at":"2025-03-06T09:53:59.131Z","repository":{"id":57533293,"uuid":"401157271","full_name":"simonhyll/cargo-commander","owner":"simonhyll","description":"Like npm scripts, but better","archived":false,"fork":false,"pushed_at":"2022-12-02T14:15:39.000Z","size":1604,"stargazers_count":17,"open_issues_count":2,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-03-02T03:52:11.643Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/simonhyll.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"github":["adaptive-simon"],"patreon":"seranth"}},"created_at":"2021-08-29T22:46:33.000Z","updated_at":"2025-02-01T21:46:27.000Z","dependencies_parsed_at":"2023-01-22T13:10:13.116Z","dependency_job_id":null,"html_url":"https://github.com/simonhyll/cargo-commander","commit_stats":null,"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simonhyll%2Fcargo-commander","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simonhyll%2Fcargo-commander/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simonhyll%2Fcargo-commander/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simonhyll%2Fcargo-commander/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/simonhyll","download_url":"https://codeload.github.com/simonhyll/cargo-commander/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":242187633,"owners_count":20086217,"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":"2025-03-06T09:53:58.506Z","updated_at":"2025-03-06T09:53:59.113Z","avatar_url":"https://github.com/simonhyll.png","language":"Rust","funding_links":["https://github.com/sponsors/adaptive-simon","https://patreon.com/seranth","https://www.patreon.com/simonhyll"],"categories":["Development tools"],"sub_categories":["Build system"],"readme":"\u003cdiv align=\"center\"\u003e\n\n# Cargo Commander\n\nThe simple way of running commands\n\n[![Crates.io](https://img.shields.io/crates/v/cargo-commander)](https://crates.io/crates/cargo-commander)\n[![GitHub Sponsors](https://img.shields.io/github/sponsors/simonhyll)](https://www.patreon.com/simonhyll)\n[![GitHub last commit (branch)](https://img.shields.io/github/last-commit/simonhyll/cargo-commander/main)](https://github.com/simonhyll/cargo-commander/commit/main)\n[![Build and test](https://github.com/simonhyll/cargo-commander/actions/workflows/build.yml/badge.svg)](https://github.com/simonhyll/cargo-commander/actions/workflows/build.yml)\n[![Website](https://img.shields.io/website?down_color=red\u0026down_message=offline\u0026up_color=green\u0026up_message=online\u0026url=https%3A%2F%2Fsimonhyll.github.io%2Fcargo-commander%2F)](https://simonhyll.github.io/cargo-commander/)\n\u003c/div\u003e\n\n## Introduction\n\nCargo Commander serves to fill the gap in the `cargo` commands capabilities, namely not being able to run commands in a\nsimilar fashion the way `npm` does with scripts. But while I was at it I decided to add some extra functionality to it.\n\nNew: In addition to running commands specified in either `Commands.toml`, `Cargo.toml` or `package.json`, functionality to execute scripts similar to how `cargo-script` does is being worked on. You can try it by either running a local script, `cargo cmd script.rs`, or running a remote script, `cargo cmd https://url.to.script`. This is currently in the early beta stages and functions by running `rustc input -o output`, then executing the output, so it's currently limited to using the standard library and the script has to be contained within that singular file. More features to come!\n\n## Getting started\n\nEither create your commands under a `[commands]` or `[package.metadata.commands]` section in `Cargo.toml`, or create a\nnew `Commands.toml` file. They all use the same syntax. Cargo commander also parses the `scripts` section\ninside `package.json` if it's found. Normally scripts inside package.json are only allowed to be strings, but Cargo\nCommander parses `package.json` by converting from json to toml, meaning you can add all the same options in json as you\ncan in toml.\n\n```bash\n# Install cargo-commander\ncargo install cargo-commander\n# Run your command\ncargo cmd COMMAND\n\n# Output of 'cargo cmd --help'\ncargo-commander 2.0.15\nA powerful tool for managing project commands\n\nUSAGE:\n    cargo cmd [OPTIONS] [COMMAND/URL/FILE] [\u003cARGUMENTS\u003e...]\n\nARGS:\n    COMMAND              Name of the command to run\n    URL                  Downloads a script, compiles then runs it\n    FILE                 Compiles a file then runs it\n    \u003cARGUMENTS\u003e...       Arguments to the command\n\nOPTIONS:\n    -h, --help           Print help information\n    -f, --file PATH      Custom path to command file to parse\n    -p, --parallel       Forces all commands to run in parallel\n```\n\n## Command\n\nA command can either be a string or a command object using the below fields to customize its behavior.\n\n```text\ncmd = String or Array, where an array can either contain string commands or other command objects\nparallel = true/false, only makes a difference if the command object contains an array, makes all commands run in parallel\nshell = String, the syntax is simply \"program arg arg arg\"\nenv = Array, an array of strings in the format \"VAR=SOMETHING\"\nargs = Array, an array of strings in the format \"ARG=Default value\", if no default is given an empty string is used\nworking_dir = String, path to the directory to use as working directory either relative to the command file or the current directory\n```\n\n### cmd\n\nThis can be either a string, a command object or an array of command objects.\n\nIf `cmd` is a multiline string the contents of the command is saved to a temporary file that gets safely deleted after\nthe program finishes. The arguments are then used to replace content within the string, and the only argument sent to\nthe shell is the path to the temporary file. We can use this behavior together with the `shell` option to create a file\nwhose absolute path gets passed as an argument to whatever program you specify as a shell. See the examples for how this\nmight look.\n\n```toml\ncommand = \"echo Basic usage\"\ncommand = [\"echo As an array\"]\ncommand = { cmd = \"echo Hello\" }\ncommand = { cmd = [\"echo Hello\", \"echo World\"] }\ncommand = { cmd = [{ cmd = \"echo And hello again\" }] }\ncommand = { cmd = { cmd = \"echo Hello again\" } }\n```\n\n### parallel\n\nBoolean, defaults to false. If the `cmd` of the command object is an array, all sub commands will be run at the same\ntime.\n\n```toml\ncommand = { cmd = [\"echo first\", \"echo second\", \"echo third\"], parallel = true }\n```\n\n### working_dir\n\nString. The path where the command is supposed to execute in.\n\n```toml\ncommand = { cmd = \"ls\", working_dir = \"src\" }\ncommand = { cmd = \"ls\", working_dir = \"path/to/folder\" }\n```\n\n### args\n\nArray of strings in the format `args=[\"arg\",\"argument=Default\"]`. If an argument is a string without a default value set\nit'll simply be replaced with an empty string.\n\n```toml\ncommand = { cmd = \"echo $name\", args = [\"name=World\"] }\n```\n\n### env\n\nArray of strings in the format `env=[\"variable=Value\"]`. Sets environment variables in the command. This is similar to\nhow `args` works, but the difference is\nthat `env` changes environment variables. This option is generally speaking not super useful, you probably want to\nuse `load_dotenv` instead.\n\n```toml\n# Unix\ncommand = { cmd = \"echo $HELLO\", env = [\"HELLO=World\"] }\n# Windows\ncommand = { cmd = \"echo %HELLO%\", env = [\"HELLO=World\"] }\n```\n\n### load_dotenv\n\nBoolean, defaults to false. Allows you to load environment variables from a .env file. The .env file should be located\nin the same folder as the file that contains the command being run. This option is unaffected by the `working_dir`\noption.\n\n```toml\n# Create a .env file with the contents \"HELLO=World\"\n# Unix\ncommand = { cmd = \"echo $HELLO\", load_dotenv = true }\n# Windows\ncommand = { cmd = \"echo %HELLO%\", load_dotenv = true }\n```\n\n### until\n\nInteger. Which status code counts as a successful run. Normally we don't check the status code of the command, but with\nthis option we can tell the command to keep repeating until it reaches a specific exit code. If you set this\nto `until=0` it would mean that you keep running the command until you reach a status 0 exit code. With `until=404` it\nwould keep running until you reach code 404. If you want to avoid infinite looping you should set `max_repeat` as well.\n\n```toml\ncommand = { cmd = \"echo Hello\", until = 0 }\n```\n\n### repeat\n\nInteger. Minimum number of times the command is meant to run. If you run this together with `until` you'll always be\nrunning the command at least this number of times.\n\n```toml\ncommand = { cmd = \"echo Hello\", repeat = 2 }\n```\n\n### delay\n\nInteger or float. Amount of time to sleep before running the command. If you use this together with any of the\nrepetition based options this delay will be added before every run of the command.\n\n```toml\ncommand = { cmd = \"echo Hello\", delay = 2 }\ncommand = { cmd = \"echo Hello\", delay = 3.7 }\n```\n\n### max_repeat\n\nInteger. Sets the maximum number of times the command is allowed to retry. This is mostly useful when running together\nwith `until`.\n\n```toml\ncommand = { cmd = \"echo Hello\", repeat = 5, max_repeat = 1 }\ncommand = { cmd = \"echo Hello\", until = 0, max_repeat = 1000 }\n```\n\n## Examples\n\n### Opening documentation\n\nI have a tendency to create multiple `mdbook` books for documenting my projects. It's really neat, but it can be a bit\nof a bother to open them all one by one. So what I do is put the command to open each document under a `docs` section,\nthen run the section rather than each individual page, using the `-p` flag to make the section run in parallel.\n\n```toml\n# Commands.toml\n[docs]\ncrate_one = { cmd = \"mdbook serve --open --port 9001\", working_dir = \"crates/one/docs\" }\ncrate_two = { cmd = \"mdbook serve --open --port 9002\", working_dir = \"crates/two/docs\" }\ncrate_three = { cmd = \"mdbook serve --open --port 9003\", working_dir = \"crates/three/docs\" }\ncrate_four = { cmd = \"mdbook serve --open --port 9004\", working_dir = \"crates/four/docs\" }\n```\n\nNow we can open all documents using a single command!\n\n```bash\ncargo cmd -p docs\n```\n\n### Passing a custom argument\n\nLet's say you want to get a running shell inside a Kubernetes pod where you don't know the pod name beforehand, probably\nbecause the pod was created by e.g. a deployment or a cronjob. There is a `kubectl` command you know of that can get you\na running shell inside the pod, the problem is that the command is pretty long and annoying to write every time, and\ncopy pasting the command from somewhere else every time gets repetitive really fast.\n\n```toml\n# Commands.toml\nshell = { cmd = \"kubectl exec --stdin --tty $pod -- /bin/bash\", args = [\"pod\"] }\n```\n\nNow we can always get a shell to our pod by simple running the below simplified syntax. Now instead of having to both\nfind the name of your pod and copy it into the longer `kubectl` command, you can now easily remember that you have\na `shell` command that takes the argument `pod`.\n\n```bash\ncargo cmd shell pod=my-pod-123-654\n```\n\n### Running a script\n\nWith a mix of the `shell` option and the behavior we've set for when a command is a multiline string we can achieve\nrunning scripts written directly in your command.\n\n```toml\n# Using python -c\nhello_py_c = { cmd = \"print('Hello')\", shell = \"python -c\" }\n# Using python and multiline string and an argument\nhello_py = { cmd = \"\"\"import os\nprint(\"Hello\")\nprint(\"$name\")\n\"\"\", args = [\"name=World\"], shell = \"python\" }\n```\n\nYou can then run it as follows:\n\n```bash\ncargo cmd hello_py_c\nHello\n# Or multiline\ncargo cmd hello_py\nHello\nWorld\n# ... With argument\ncargo cmd hello_py name=Commander\nHello\nCommander\n```\n\n### Keep retrying until command succeeds\n\nSometimes you run programs or write scripts that can fail. It's ok, it happens to everyone. Maybe it's a networked\nresource it's trying to reach, or maybe a file on your computer. No matter what the reason, the program will sometimes\nexit with a successful code `0`, other times it exits with code `404` because the page it tried to reach wasn't found.\n\nWe can easily create a simple retry loop using `until`, combined with `delay` so that the program isn't ran too often,\nand `max_repeat` so that we don't try forever.\n\n```toml\ncommand = { cmd = \"python script.py\", until = 0, delay = 3, max_repeat = 1000 }\n```\n\nRunning that command makes it keep retrying with a 3 seconds delay between retries. It will retry until it gets a 0\nstatus returned, or a maximum of 1000 times.\n\n## Notes\n\n### Environment variables don't persist\n\nI've tried to get this to work as intended but for now I've kind of given up on this since it appears to be anywhere\nbetween impossible and really, really annoying to get to work right. So each each command will have a \"fresh\" set of\nenvironment variables, if one command changes environment variables another command won't pick up on those changes, they\nare run in different shells. You can either use the `env` option, or you can run a script in every command that sets up\nenvironment variables, or you can use `load_dotenv` to load variables from a `.env` file. I consider these options to be\nsufficient, if you really want variables to persist across commands you'll have to make a pull request with your\nchanges, or wait until I feel like delving deeper into the issue.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsimonhyll%2Fcargo-commander","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsimonhyll%2Fcargo-commander","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsimonhyll%2Fcargo-commander/lists"}