Home

Awesome

switchenv: An environment manger for bash

In my analysis work, I will frequently put auth credentials into environment variables. This allows me to check my code into Github without divulging any secrets. So, for example, I might have code in a Jupyter notebook that looks something like

import os
from my_module import get_database_connection

connection = get_database_connection(
    port=os.environ('PGPORT'),
    password=os.environ('PGPASSWORD'),
    user=os.environ('PGUSER'),
    database=os.environ('PGDATABASE'),
    host=os.environ('PGHOST'),
)

The database I connect to will be completely determined by the environment variables I have defined.

switchenv gives me a way to easily navigate between different environments so that, for example, I can quickly switch between development and production databases.

Install

switchenv is written in python. You can install it with

pip install switchenv

Use Case

Imagine I have the following bash files I can source in order to set up my bash environment the way I'd like. Typically I would just run source rc_development_db.sh before running my code in order to set up my dev environment. However, I have to be very careful about where I place my rc files so that I don't accidentally check them into Github. Furthermore, it can be annoying to keep track of these files when I'd like to reuse them for different projects. This is where switchenv comes in.

rc_development_db.sh

export MY_MESSAGE="You are in dev profile"
export PGPORT=5432
export PGPASSWORD=my_dev_password
export PGUSER=my_dev_username
export PGDATABASE=my_dev_database
export PGHOST=my_dev_host

rc_production_db.sh

export MY_MESSAGE="You are in prod profile"
export PGPORT=5432
export PGPASSWORD=my_prod_password
export PGUSER=my_prod_username
export PGDATABASE=my_prod_database
export PGHOST=my_prod_host

rc_bash_functions.sh


print_message () {
   echo "Current message is ${MY_MESSAGE}"
}

Setting up switchenv

Basic Setup

Below is copy-paste from an interactive bash session showing how to set up the switchenv workflow.

bash>
bash> # Make sure I'm in a directory with the rc files I want
bash> ls *.sh
rc_development_db.sh  rc_production_db.sh  rc_bash_functions.sh
bash>
bash> # Load my rc scripts into switchenv giving them profile names
bash> switchenv add -p dev -f ./rc_development_db.sh
bash> switchenv add -p prod -f ./rc_production_db.sh
bash>
bash> # Profiles can hold any legal bash code, including function definitions.
bash> switchenv add -p func -f ./rc_bash_functions.sh
bash>
bash> # Show list of stored profile names
bash> switchenv list
dev
prod
func
bash>
bash> # Show contents of single profile
bash> switchenv show -p prod


#========================================
# prod
#========================================
export PGPORT=5432
export PGPASSWORD=my_prod_password
export PGUSER=my_prod_username
export PGDATABASE=my_prod_database
export PGHOST=my_prod_host

Under the hood, switchenv placed a json file in a hidden directory off of my home directory.

~/.switchenv/profiles.json

This json file serves as the centralized data-store for all of my profile information.

Advanced Setup (Composed profiles)

I can also create composed profiles. These profiles will source other named profiles in the order they are specified. Any changes I make to one of the sourced profiles will automatically carry over to the composite profile. Composed profiles can be nested. So, a composed profile can have another composed profile as one of its sub-profiles. Here is an example of setting up a composed profile

bash>
bash> # Create a composed profile based on two other profiles
bash> switchenv compose -c prod_with_func -p prod -p func
bash>
bash> # Show all profiles including new composite profile
bash> switchenv list
dev
prod
prod_with_func -> ['prod', 'func']
func
bash>

Now when you list profiles, you can easily identify composed profiles and see the order in which they will execute their sub-profiles.

Customizing switchenv

The default location for switchenv config files is ~/.switchenv. Occasionally, you may want to have those files located in a different directory. This can be accomplished with the switchenv config command.

Exporting / Importing switchenv configuration

You can export the internal state of your switchenv installation by running

switchenv export-config > my_export.json

This will save all of your profiles into a json blob. To reload this state into switchenv (perhaps on a different computer) you can simply run

switchenv import-config -f my_export.json

Navigating Between Environments with switchenv

Using switchenv involves interacting with a simple console-based UI, so it is best illustrated using a gif. Shown here is my admittedly sub-par screen recording of how to use switchenv.

For a more thorough description use

switchenv --help

Or use the switchenv alias (because I hate typing)

bash> sw --help

Usage: sw [OPTIONS] COMMAND [ARGS]...

Options:
  --help  Show this message and exit.

Commands:
  add            Create a profile from file
  compose        Compose a new profile from existing profiles
  config         View or set where the config directory lives
  delete         Delete a profile
  examples       Show usage examples
  exec           Execute a QUOTED command in the specified env
  export-config  Export config to stdout (see also import-config)
  import-config  Import config from file (see also export-config)
  list           List all profile names
  show           Show contents of a single profile
  snapshot       Snapshot current env into a profile
  source         Drop into subshell with named profile (useful in scripts)

Just for my future reference, I made this recording by using the native OSX screen recording feature to make a .mov file. I then used Gif Brewary 3 to convert it to a .gif file by manually setting the speed to 150% and frames-per-sec to 6. I let the software figure it out from there.

Demo Gif

If you feel like digging around under the hood to see what switchenv actually sourced when activating your environment, you can look at

~/.switchenv/switchenvrc.sh

Your subshell was essentially invoked with the command

bash --init-file ~/.switchenv/switchenvrc.sh

You can manually execute this command in a new terminal window if you would like an exact clone of your environment in a new console.

Executing a single command in a switchenv environment

Switchenv comes with the ability of executing single commands inside the specified environment. The command MUST be contained in quotes. Within those quotes, you may use all bash features such as pipes, redirects, etc. So for example, this should just work

sw exec -p my_profile  'printenv | grep PG >/tmp/my_file.txt'

Projects by robdmc.