Sauce

license Version info Build Status

The central truth is the central truth, and nothing that I care about is relative

A tool to help manage context/project specific shell-things like environment variables.

Core Goals:

Example Workflow

``` bash

Suppose you've got some new directory structure

❯ mkdir -p foo/bar ❯ cd foo

You want to start recording things here

❯ sauce No file at ~/.local/share/sauce/foo.toml ❯ sauce new

My "foo" project has got some corresponding aws profile

❯ sauce set var AWS_PROFILE=foo

The "bar" subdirectory has something more specific

❯ cd bar ❯ sauce set var foo=bar

The core purpose!

❯ sauce Sourced ~/.local/share/sauce/foo/bar.toml

❯ env ... AWS_PROFILE=foo foo=bar ```

Installation

Install

With Cargo

Download Release

Setup

Currently explicitly supported shells include: zsh, bash, and fish. The scaffolding exists to support other shells, which should make supporting other common shells that might require "$SHELL" specific behavior.

Loading things into the environment requires a minimal amount of shell code to be executed, so after installing the binary (suggestion below), you will need to add add a hook to your bashrc/zshrc/config.fish, etc.

Depending on the level of similarity to the above shells, you may be able to get away with using one of the above shell init hooks until explicit support is added

Targets

A thing which sauce can load/unload is called a “target”.

Currently supported targets include:

Planned/Ideally supported targets include:

Features

sauce command

The primary usecase is the sauce command. Explicitly no arguments, you load the environment with all sauce targets, cascaded from the uppermost parent.

Cascades

Given a directory structure

~/ projects/ foo/ subfoo/ bar/

You can run sauce at any folder level/depth, say subfoo. The values saved for the folders: ~, ~/projects, ~/projects/foo, and ~/projects/foo/subfoo will all be loaded.

The more specific/deep folder’s values will take precedence over the values of more general/shallow folders.

All saucefiles are located in the $XDG_DATA_HOME/sauce folder, after which the folder structure mirrors that of the folders who’s values are being tracked. Given the above example you might see:

~/.local/share/sauce/

      foo/
          subfoo.toml
      foo.toml
      bar.toml
  projects.toml

sauce set <target-type> NAME=value

For example, sauce set var AWS_PROFILE=foo FOO=bar.

This is convenient when you realize you want to sauce a var or whatever. There is also sauce edit which will open your $EDITOR so you can bulk update whatever values you like.

sauce --as foo

Any key-value pair can be tagged with, you might call “namespaces”.

Consider an env var definition

toml AWS_PROFILE = {default = "projectname-dev", uat = "projectname-uat", prod = "projectname-prod"}

Given a sauce, you will get the “default” namespace (i.e. AWS_PROFILE=projectname-dev) for this value, as well as all other unnamespaced values.

Given sauce --as prod, you will get the “prod” namespace (i.e. AWS_PROFILE=projectname-prod) for this value, as well as all other unnamespaced values.

sauce --glob glob and sauce --filter filter

Either --glob and/or --filter can be applied in order to filter down the set of things which are returned from sauce (or any subcommand).

You can supply multiple globs/filters by separating them by ,, i.e. --filter foo,bar,baz.

You can also specify globs/filters specific to a particular target, which might be important given that there can be overlap between targets. Targets are separated from their search term by :, i.e. --glob env:database*,function:work-*.

sauce clear

clearing will “unset” everything defined in any cascaded saucefiles, abiding by any options (–filter/–glob/–as) provided to the command.

The general intent is that one would only/primarily be including targets which would be safe to unset (or that you will avoid running clear if that’s not true for you), given that they were overwritten when you run sauce.

Settings

direnv-like automatic execution of sauce on cd

sauce loads configuration from $XDG_CONFIG_HOME/sauce.toml, and so generally this will be ~/.config/sauce.toml.

By default this feature is off (given that it changes the shell generated on sauce shell init and causes it to be executed on every cd).

To enable, add:

``` toml

Enables the shell hook which makes this feature possible.

You must start a new shell before autoload will work.

autoload-hook = true

Enables the feature itself (globally).

autoload = true ```

You can additionally/alternatively omit autoload from the global config, and instead opt to only include it in the saucefile for a given directory i.e.

``` toml

~/.local/share/sauce/work/example.toml

[settings] autoload = true ```

Which allows you to globally opt in, globally opt out, locally opt in, or locally opt out.

Alternatives

Why would you choose to use sauce over certain alternatives? sauce does have significant conceptual feature overlap with, in particular, direnv, but the additional features may make it worth using sauce instead!

Features which distinguish sauce from all the below alternatives

dotenv

dotenv is the more obvious of the two, which is specifically for the loading of environment variables, which is essentially the primary usecase of sauce.

I find choice of toml files for sauce, while not necessarily important to the actual featureset of sauce, to be useful because it supports multiline strings.

The main advantage, is sauce --as <context>. In order to reproduce this behavior, you need multiple dotenv files, (with all common values duplicated, or contained in yet another file).

direnv

direnv may be less obvious, but given that it executes user-supplied shell code, directly, on cd, it can essentially do anything that sauce can do.

The advantage, lies in the fact that sauce is specifically tailored to the usecases documented above. That means, it’s just a lot easier to get the behaviors of sauce compared to writing the shell code (for each project) which would enable things like sauce --as prod or sauce --glob database*.

Planned Work

Local development

For local development, it can be useful to enable the --feature dev. This alters the behavior so that the shell hook(s) point to the absolute location of the debug build.

An example alias that might be helpful could be:

toml [alias] build = 'cargo build --features dev && eval "$(./target/debug/sauce shell init)"'

At which point, you’re a quick build away from being able to cd around to test sauce, while always pointing at your project version of sauce for the current shell.