Getting Started

How to install shadowenv and take it for a spin

Home Shadowlisp API

Installation

On macOS, you can brew install shadowenv or download the binary from GitHub and drop it somewhere on your path. If this build isn’t right for your architecture, the only other option for now is to build it manually from source.

Building from Source

Clone the git repo

dev clone shadowenv if you work at Shopify, or:

git clone https://github.com/Shopify/shadowenv
cd shadowenv

Install Rust

dev up if you work at Shopify, or:

# Install rustup
curl https://sh.rustup.rs -sSf | sh

# Install the version of rust that we need
rustup switch nightly-2018-12-26k

Build and Install

cargo build --release

This will generate an artifact at target/release/shadowenv. You can copy this wherever you like on your path, for example:

cp target/release/shadowenv /usr/local/bin/shadowenv

Add to your shell profile

Shell support

We're not in principle against supporting other shells, but for now Shadowenv only works with bash, zsh, and fish.

Shadowenv relies on a shell hook to make changes when you change directories. In order to use it, add a line to your shell profile (.zshrc, .bash_profile, or config.fish) reading:

# (only add one of these!)
eval "$(shadowenv init bash)" # for bash
eval "$(shadowenv init zsh)"  # for zsh
shadowenv init fish | source  # for fish

Make sure to restart your shell after adding this.

A Quick Demo

Shadowenv constantly scans your current directory and all of its parents for a directory named .shadowenv.d, which is called your closest shadowenv. Shadowenv environments can stack by linking to each other using a parent symlink (.shadowenv.d/parent). Shadowenv will collect and apply all linked environments from the closest shadowenv in order from highest to lowest in the file system tree (closest environment is applied last).

When .shadowenv.d directories are found, Shadowenv first checks that you’ve Trusted them. Then, it looks for any files ending with .lisp in those directories, and runs them as Shadowlisp.

Here’s an example of what a Shadowlisp file might look like:

.shadowenv.d/500_default.lisp
(env/set "DEBUG" "1")
(env/prepend-to-pathlist "PATH" "./bin")

If you try creating .shadowenv.d directories, and then adding that content to *.lisp files inside them, you’ll get an error back about “untrusted” shadowenvs. In order to fix this, run:

shadowenv trust

This will mark the closest shadowenv directory as trusted, telling shadowenv that it can safely run any shadowlisp programs it finds inside. Note: To trust other shadowenvs further up, you’ll need to cd up the tree and run shadowenv trust there. You should see an activation message in your terminal, which now includes information about added and removed directories. Then, if you echo $DEBUG, you will see “1” printed, because the script set “DEBUG” to “1”.

Next, cd .. to get out of the directory containing the shadowenv. You will see a deactivation message printed automatically, also showing which directories were removed. If you echo $DEBUG, you’ll see whatever value you had prior to activating the Shadowenv: most likely no value.

Those are the basics! There’s a bit more you can do with Shadowlisp, and we have some suggestions for how to actually use Shadowenv in an organization.

Add to your editor or IDE

Depending on you use your editor, you may find it helpful to have the same environment variable settings as in your shell. We have plugins for most common editors, and writing new plugins is relatively straightforward.

Check out the Integration page for more information and a list of available plugins.

Usage in Scripts

Sometimes you may want Shadowenvs loaded in a non-interactive script. This is what shadowenv exec is for. When you run shadowenv exec, Shadowenv will load the Shadowlisp from the current directory and all its ancestors, and execute the specified program. For example, imagine a directory structure with Shadowenvs that set up the environment for nginx:

#!/bin/sh
cd /path/to/thing/with/dot-shadowenv

shadowenv exec -- nginx -g 'daemon off;'

In this case, we didn’t need to load the Shadowenv shell hook, as shadowenv exec loaded the environments before executing nginx.

Nested Shadowenvs

Shadowenv supports nested environments. In order for a shadowenv to inherit from another shadowenv further up the path, create a symlink at .shadowenv.d/parent to the higher .shadowenv.d. For example:

ln -s /a/.shadowenv.d /a/b/c/.shadowenv.d/parent

When this is done, shadowlisp files in a will be evaluated before those in c.