Skip to content

a cli tool to simplify loading of your .env files (with gopass and custom commands support)

License

Notifications You must be signed in to change notification settings

revivalstack/setnv

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

12 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

setnv: Your .env files, supercharged.

Effortless environment variable loading and management for any workflow.

Manage your application's environment variables with simplicity and power. setnv helps you centralize configuration and sensitive data in easy-to-use .env files, supporting dynamic variable expansion and seamless secret integration. It also supports chaining multiple .env files, allowing for layered configurations.

Quick Example

Store your kopia environment variables in a myconfig.env file, and use setnv to call kopia with the resolved environment variables including gopass secrets.

setnv myconfig kopia [kopia-params]
  • setnv looks for a myconfig.env file in current directory, or in ~/.config/setnv/myconfig.env
  • reads myconfig.env file and loads KEY=VALUE pairs, e.g. KOPIA_PASSWORD=$(gopass show test/KOPIA_PASSWORD)
  • pass these resolved KEY=VALUE pairs to kopia <params>

For layered configurations, you can chain multiple .env files. For example, default.env defines default settings, and myconfig.env overrides some variables in the default:

setnv default,myconfig kopia [kopia-params]

Features

  • Chained Configuration: Specify multiple .env files (e.g., id1,id2,id3). Variables from later files in the chain override those from earlier ones, enabling powerful layered configurations.

  • Intelligent .env Parsing: Reads KEY=VALUE pairs, gracefully skipping comments and empty lines.

  • Smart Value Handling: Supports both double-quoted values (with full escape sequence support like \n, \") and literal single-quoted values.

  • Robust Variable Expansion: Resolve $VAR and ${VAR} references within your .env file. It handles recursive expansions and prevents infinite loops from circular dependencies, resolving unresolvable variables to empty strings with a warning.

  • Seamless Gopass Integration: Directly inject secrets from your gopass store using $(gopass show <path>) or $(gopass <path>) syntax. This is a specially handled command substitution for convenient secret retrieval, keeping sensitive data out of plain text.

  • Command Substitution: Dynamically set variable values by executing shell commands and capturing their standard output. setnv supports two main syntaxes for general command execution:

    • $(command args): The traditional shell command substitution syntax, e.g., MY_VAR=$(echo "hello"). While supported, this syntax has limitations with complex nested shell syntax (e.g., unquoted parentheses or backticks) within the command string.

    • $[command args]: Recommended for robust command execution, especially when your commands include internal parentheses, backticks, or other complex shell constructs. Example: APP_VERSION=$[git describe --tags --abbrev=0] or COMPLEX_CMD=$[echo "Current time is $(date) (GMT)"].

  • Flexible Execution Modes:

    • Execute a Command: Load variables and run a specified executable with its arguments, with the environment isolated to that process.

    • Launch a Subshell: Load variables and open a new interactive shell, handy for development sessions.

    • Export to Current Shell: Generate export commands for evaling the environment directly into your active shell session.

    • View Variables: Safely display the fully resolved environment variables before applying them, useful for debugging.

  • Environment Sandboxing (--sandboxed): Control whether setnv passes inherited system environment variables to the target process. With --sandboxed, only variables explicitly defined in your .env files are passed, creating a clean, isolated environment.

  • Portable & Minimal: Built in Go, setnv compiles into a single, self-contained binary, ensuring easy distribution and minimal external dependencies.

How Does It Work?

setnv first locates your .env file(s) based on the provided IDs, prioritizing the current directory before checking a central configuration directory (e.g., ~/.config/setnv/). When chaining multiple IDs (e.g., base,dev), files are processed in order, with later files overriding variables defined in earlier ones. It then meticulously reads each line, parsing key-value pairs, handling quoted strings, and executing gopass commands or other shell commands to fetch dynamic values.

After the initial parsing and command substitutions, setnv performs an iterative variable expansion process, resolving all $VAR and ${VAR} references within the loaded environment variables, handling nesting and detecting circularities. Finally, based on your chosen mode and the --sandboxed flag:

  • For running executables or launching subshells, setnv uses syscall.Exec to replace its own process with the target command, ensuring the environment is seamlessly passed. The environment passed includes variables from .env files, optionally merged with the inherited system environment based on the --sandboxed flag.
  • For exporting variables, it prints shell-compatible export commands to standard output.
  • For viewing, it simply prints the resolved variables to your terminal.

Why setnv?

While other tools exist for managing .env files, setnv aims to be a minimal, self-contained Go binary that's easy to distribute and use, especially in environments where installing Python or Node.js dependencies might be cumbersome. It provides built-in gopass integration for those who manage secrets with it, and clear modes of operation for various workflows. Its ability to chain multiple .env files and offer sandboxed execution provides powerful flexibility for complex configurations.

Installation

You can build setnv from source:

git clone https://github.com/revivalstack/setnv.git
cd setnv
go build -o setnv .
sudo mv setnv /usr/local/bin/

or via

go install github.com/revivalstack/setnv@latest

Usage

Environment files are expected to be located in ~/.config/setnv/<id>.env. You can override the base configuration directory by setting the LOAD_ENV_CONFIG_DIR environment variable.

Basic .env File Example (~/.config/setnv/myproject.env)

# My project's environment variables
DB_HOST=localhost
DB_PORT=5432
DB_USER=admin
DB_PASS=$(gopass show myproject/database/password) # Fetches password from gopass
BUILD_ID=$[date +%Y%m%d%H%M%S]                      # Example of robust command substitution using $[]
API_KEY="supersecret_key_with_\"quotes\""
APP_URL=http://$DB_HOST:$DB_PORT/app
MESSAGE='This is a literal string with $ and \' characters.'

Chaining .env Files

To load base.env then dev.env, with dev.env overriding variables from base.env:

setnv base,dev myapp-script.sh

Running an Executable

To load variables for myproject and then run a command:

setnv myproject node index.js --port 3000

Launching a Subshell

To load variables for myproject and launch a new interactive shell:

setnv myproject

Exporting to Current Shell

To load variables for myproject into your current shell session (variables will persist):

eval "$(setnv myproject --export)"

Warning: Variables exported this way are visible in your shell's environment (env, ps e) and can persist across commands. Use with caution for sensitive data.

Viewing Variables

To see the resolved environment variables for myproject without running any commands:

setnv myproject --view

Warning: This will print plaintext secrets (if any are resolved from gopass) to your terminal.

Sandboxed Execution

To run a command with only the environment variables defined in myproject.env, ignoring inherited system environment variables (unless overridden):

setnv myproject --sandboxed bash -c 'echo "PATH: $PATH, MY_VAR: $MY_VAR"'
# MY_VAR will be whatever is in myproject.env, PATH will likely be empty if not explicitly set there.

Version and Help

setnv --version
setnv --help

Integration with Container Runtimes (Podman & Docker)

Seamlessly inject setnv's variables into your containers:

  1. Via --env-file (Podman or Docker): Use setnv --view with your shell's process substitution (<()) to stream resolved variables as an environment file to your container runtime. This is the most robust method for both Podman and Docker.

    # For Podman:
    podman run --rm --env-file <(setnv base,dev --view) alpine env
    
    # For Docker:
    docker run --rm --env-file <(setnv base,dev --view) alpine env
    • Note: Requires shells supporting process substitution (e.g., Bash, Zsh).
    • Security: Output (including secrets) is streamed, not printed to terminal, but the command remains visible in shell history and process lists.
  2. Via --env-host (Podman only): Have setnv directly execute the podman run command. Use --env-host flag if you want environment variables set by setnv (and other host variables) to be passed into the container.

    # setnv sets env for the 'podman' process, and '--env-host' passes them to 'alpine'
    setnv base,dev podman run --rm --env-host alpine printenv

Contributing

We welcome contributions to setnv! If you have ideas for new features, bug fixes, or improvements, please feel free to open an issue or submit a pull request.

To contribute:

  1. Fork the repository.
  2. Create a new branch for your feature or bug fix.
  3. Make your changes and write tests.
  4. Ensure all tests pass (go test -v).
  5. Submit a pull request.

Code of Conduct

We strive to create a welcoming and inclusive community. Please be respectful and considerate in all your interactions. We expect all contributors to adhere to basic principles of polite and constructive communication. Any behavior that is harassing, discriminatory, or disruptive is not tolerated. Let's keep setnv a friendly place for everyone.

License

setnv is released under the MIT License.

About

a cli tool to simplify loading of your .env files (with gopass and custom commands support)

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages