Skip to content

avirshup/cargo-lab

Repository files navigation

cargo-lab

Crates.io License

A cargo plugin for managing quick, disposable, local, and IDE-friendly Rust experiments with arbitrary dependencies.

Contents

What is this for?

cargo-lab is a tool for setting up, running, and managing collections of one-off experiments in rust.

Like the Rust Playground, this tool aims to make it as fast and painless as possible to run some rust code. However, cargo-lab makes some different choices - it lets you experiment:

  1. on your machine;
  2. with your normal dev tooling (including your IDE's autocomplete, typechecking, linting, ...);
  3. with arbitrary dependencies and features;
  4. in a completely standard, tooling-friendly cargo project;
  5. with a persistent collection of all your experiments.

WARNING: This is not a sandbox.

Don't run untrusted code or dependencies without protection.

A cargo lab-managed "lab" is just a local cargo project; the same security principles apply. Running a malicious lab script or dependency - or even just building a malicious dependency - is exactly as dangerous here as it would be in any other cargo project.

Quick start

This program is designed to run as a cargo subcommand, and can be installed via cargo install cargo-lab. (To setup tab-completion in your shell, see cargo lab completions --help).

You can then set up a new "lab" project:

# create or initialize a lab project
mkdir new-lab
cargo lab init ./new-lab

# Creates a new script, setting up the file and adding it to Cargo.toml
cargo lab new my-script-name dep1 -F dep1/feature

# Add dependencies and activate features for a script
cargo lab inject my-script-name dep1 dep2 -F dep1/featurename -F dep2/featurename

# Run a script (with all dependencies automatically activated)
cargo lab run my-script-name

The basic idea

A "cargo laboratory" is cargo project with lots of one-off experiments (we'll call these "scripts"), all with their own arbitrary dependencies. You can create a new laboratory project by running cargo lab init $path where $path is an empty or new directory.

$ cargo lab init ./labdir
  Initializing project directory ...
  Creating first script ...
  success: Created minimal script at: src/my_first_experiment.rs

  success: Lab initialized in directory '/path/to/labdir'

  Tips:
   1) To enable tab-completion, see `cargo lab completions --help`
   2) To easily run experiments from any working directory, set
      `CARGO_LAB_MANIFEST_DIR=/path/to/labdir`
      or use the `--manifest-path` flag
      (`cargo lab --manifest-path=/path/to/labdir`).
   3) To alias this command to something shorter, prefer a shell alias
      (e.g., `alias clb="cargo lab"`) over a cargo alias (in `.cargo/config.toml`),
      as tab-completion does not currently support cargo aliases.

This will create a completely normal cargo project and Cargo.toml manifest that the dev tooling of your choice should happily work with:

$ cd labdir
$ tree .
  ./
  ├── Cargo.toml
  ├── src
  │   └── my_first_experiment.rs
  └── templates
      ├── bare.rs.template
      ├── basic.rs.template
      ├── clap.rs.template
      └── clap_subcmd.rs.template

Each script managed by cargo-lab will have an entry like this in Cargo.toml:

[[bin]]
name = "my-first-experiment"
path = "./src/my_first_experiment.rs"
required-features = ["dep1", "dep2", "dep3/feature"]

Note that you can (and should) edit the generated Cargo.toml if you want, and cargo lab should continue to work normally. (If something gets messed up, try running cargo check and cargo lab check to detect config issues.)

When executing these scripts, cargo lab run takes care of automatically activating all the features listed in required-features (cargo run requires them all to be listed manually):

# this "cargo lab run" command:
cargo lab run my-first-experiment
# is the same as running:
cargo run --bin my-first-script --features 'dep1,dep2,dep3/feature'

Useful commands

(Use cargo lab --help and cargo lab [subcmd] --help to see complete docs.)

Installation and setup

  • cargo install --locked cargo-lab will build and install the latest stable version from crates.io and make the cargo lab subcommand available.
  • cargo lab completions --help will print out the tab-completion setup steps for supported shells (fish, bash, zsh).
  • cargo lab init (lab path) will create a new lab project.

After creating a project, you can set the CARGO_LAB_MANIFEST_PATH environment variable to quickly run your experiments from any working dir.

Creating scripts

  • cargo lab quick [deps] [-F (features)] [--edit]: create a new script with autogenerated name
  • cargo lab new (SCRIPTNAME) [deps] [-F (features)] [--edit]: create a new script with a chosen name

Working with scripts

Note that if tab-completion has been enabled in your shell, all script names (in addition to subcommands, flags, and other CLI arguments) can be autocompleted in these commands.

  • cargo lab run (SCRIPT) [args ...]: run a script (unlike cargo run --bin, this automatically activates all required features)
  • cargo lab edit (SCRIPT): open the script in your editor (requires that the editor-cmd field to be set in the [package.metadata.cargo-lab] table Cargo.toml)
  • cargo lab inject (SCRIPT) [deps] [-F features] - add dependencies and activate features for an existing script
  • cargo lab rename (SCRIPT) (NEW_NAME) - rename a script

Example

Let's say I want to experiment with the proc-macro2 crate. First I'll create a new script and ask for it to be opened in my IDE immediately. (Note the cargo lab quick command automatically generates a name for the script so I don't have to think of one myself.)

$ cargo lab quick proc-macro2 --edit
  Generated script name: try-proc-macro2
  running:
  $ cargo add --optional proc-macro2
      Updating crates.io index
        Adding proc-macro2 v1.0.106 to optional dependencies
               Features:
               + proc-macro
               - nightly
               - span-locations
        Adding feature `proc-macro2`
      Updating crates.io index
       Locking 2 packages to latest Rust 1.94.1 compatible versions
  success: Created minimal script at: src/try_proc_macro2.rs
  Updated Cargo.toml:
  19a20,24
  > [[bin]]
  > name = "try-proc-macro2"
  > path = "src/try_proc_macro2.rs"
  > required-features = ["proc-macro2"]

Then, let's say I also decide to use the syn and quote crates in this experiment - and want to activate syn's "parsing" feature. I can inject these into the script later.

$ cargo lab inject try-proc-macro2 syn quote --feature syn/parsing
  running: "$ cargo add --optional syn quote"
      Updating crates.io index
        [...]

  Updating features for "try-proc-macro2" in Cargo.toml:
      < required-features = ["proc-macro2"]
      ---
      > required-features = ["proc-macro2", "syn", "quote", "syn/parsing"]

Now, I can make my changes and run it.

$ # ... make changes ...
$ cargo lab run try-proc-macro2
my experiment's output goes here

Configuration

Shell autocomplete

Instructions for setting up tab completions for various shells can displayed by running cargo lab completions --help. Fish, Bash, and ZSH are all supported; other shells supported by clap may work but have not been tested.

If you experience issues with tab completions, they may be due to conflicts with other cargo plugins or even cargo itself. One workaround is to call the executable directly (spelled "cargo-lab" with a hyphen, one word) instead of through cargo ("cargo lab" with a space in the middle, two words).

In Cargo.toml

cargo lab stores configuration lab's Cargo.toml in the [package.metadata.cargo-lab] table. Note that this tool won't make any modifications to your project unless this table is present.

[package.metadata.cargo-lab]
# cargo-lab won't make changes to any project unless
#    unless this field exists and is set to "true":
enabled = true

# Optional command to launch an editor when requested with
#   `--edit` flag or `edit` subcommand.
editor-cmd = ["rustrover"]

Why?

  1. for me, rust is a very IDE-driven language, so even if I'm working with a one-off experiment, I'd really like to have autocompletion, cargo fmt, clippy, pop-up docs, etc. available;
  2. Quick one-off scripts are the next best alternative to the live REPL-/jupyter- driven exploration that you can do in interpreted languages;
  3. it's nice to run experiments locally and maybe even keep them in a repo in case you want to refer back to them later; and finally
  4. it's a bit excessive to create entire new cargo projects for each one-off experiment.

Alternatives

  • The Official Rust Playground is wonderful and maybe the quickest way to write some rust code. But what if you want to try out a dependency that's not in top 100, or use your local IDE's autocompletion, or even just work offline?
  • single file cargo scripts are also a great idea, but don't yet have IDE support.
  • evcxr is an insanely impressive REPL for rust (which should not be even possible, but it actually works)
  • A normal crate with lots of [[bin]] entries also works ok - this project used to be my personal lab repository, which then evolved an xtask to help manage the dependencies, which then turned into this standalone tool.
  • Lutetium-Vanadium/cargo-playground, Actually seems very similar to this project, but unfortunately I didn't stumble on it it until after I finished this one.

Provenance

  • License: This project is provided under the MIT License.
  • 3rd party sources: The source code in the src/vendor_cargo directory is vendored from the cargo project and used under the MIT license.
  • Copyrightability: all first-party material in this repository was written solely by (and for) its human authors. It does not contain, nor was it derived from, LLM or other generative "AI" output.

This software provides a plugin for the cargo command-line tool. It is not a product of or otherwise affiliated with the Cargo project.

About

Dependency management for collections of local, IDE-friendly rust experiments

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors