Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEATURE] additional (and optional) system-wide configuration path PREFIX/etc/direnv #1038

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 12 additions & 0 deletions GNUmakefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
# Set this to change the target installation path
PREFIX = /usr/local
BINDIR = ${PREFIX}/bin
SYSCONFDIR = ${PREFIX}/etc/direnv
SHAREDIR = ${PREFIX}/share
MANDIR = ${SHAREDIR}/man
DISTDIR ?= dist
Expand Down Expand Up @@ -51,6 +52,12 @@ endif

ifdef BASH_PATH
GO_LDFLAGS += -X main.bashPath=$(BASH_PATH)
else
BASH_PATH=
endif

ifdef SYSCONFDIR
GO_LDFLAGS += -X main.sysConfDir=$(SYSCONFDIR)
endif

ifneq ($(strip $(GO_LDFLAGS)),)
Expand Down Expand Up @@ -154,8 +161,13 @@ test-zsh:
install: all
install -d $(DESTDIR)$(BINDIR)
install $(exe) $(DESTDIR)$(BINDIR)
install -d $(DESTDIR)$(SYSCONFDIR)
cp -R etc/* $(DESTDIR)$(SYSCONFDIR)
sed -i -e 's|bash_path = ""|bash_path = "$(BASH_PATH)"|' $(DESTDIR)$(SYSCONFDIR)/direnv.toml-default
install -d $(DESTDIR)$(MANDIR)/man1
cp -R man/*.1 $(DESTDIR)$(MANDIR)/man1
sed -i -e 's|/etc/direnv|$(SYSCONFDIR)|' $(DESTDIR)$(MANDIR)/man1/direnv.1
sed -i -e 's|/etc/direnv|$(SYSCONFDIR)|' $(DESTDIR)$(MANDIR)/man1/direnv-stdlib.1
install -d $(DESTDIR)$(SHAREDIR)/fish/vendor_conf.d
echo "$(BINDIR)/direnv hook fish | source" > $(DESTDIR)$(SHAREDIR)/fish/vendor_conf.d/direnv.fish

Expand Down
1 change: 1 addition & 0 deletions default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ let
buildGoModule
lib
stdenv
gnused
;
in
buildGoModule rec {
Expand Down
10 changes: 10 additions & 0 deletions etc/direnv.d/extension.sh-example
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/usr/bin/env bash

# ---------------------------------------------------------------------------
# Hint: To activate this direnv extension, remove the '-example' suffix
# ---------------------------------------------------------------------------

use_foobar() {
log_status "direnv: example-extension setting FOO=bar"
export FOO=bar
}
45 changes: 45 additions & 0 deletions etc/direnv.toml-default
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
[global]

# ---------------------------------------------------------------------------
# This is the system-wide direnv configuration file.
# Remove the '-default' suffix to activate!
# ---------------------------------------------------------------------------

# ---------------------------------------------------------------------------
# This allows one to hard-code the position of bash. It maybe be useful
# to set this to avoid having direnv to fail when PATH is being mutated
# ---------------------------------------------------------------------------

# bash_path = ""

# ---------------------------------------------------------------------------
# If set to `true`, stdin is disabled (redirected to /dev/null)
# during the `.envrc` evaluation
# ---------------------------------------------------------------------------

# disable_stdin = false

# ---------------------------------------------------------------------------
# Also look for and load `.env` files on top of the `.envrc` files. If both
# `.envrc` and `.env` files exist, the `.envrc` will always be chosen first.
# ---------------------------------------------------------------------------

# load_dotenv = false

# ---------------------------------------------------------------------------
# If set to true, the `.envrc` will be loaded with `set -euo pipefail`. This
# option will be the default in the future.
# ---------------------------------------------------------------------------

# strict_env = false

# ---------------------------------------------------------------------------
# Specify how long to wait before warning the user that the command is taking
# too long to execute. Defaults to "5s".
#
# A duration string is a possibly signed sequence of decimal numbers, each
# with optional fraction and a unit suffix, such as "300ms", "-1.5h" or
# "2h45m". Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
# ---------------------------------------------------------------------------

# warn_timeout = "5s"
6 changes: 6 additions & 0 deletions etc/direnvrc-default
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/usr/bin/env bash

# ---------------------------------------------------------------------------
# This is the system-wide direnv runtime configuration file
# Remove the '-default' suffix to activate!
# ---------------------------------------------------------------------------
1 change: 1 addition & 0 deletions internal/cmd/cmd_status.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ var CmdStatus = &Cmd{
Action: actionWithConfig(func(env Env, args []string, config *Config) error {
fmt.Println("direnv exec path", config.SelfPath)
fmt.Println("DIRENV_CONFIG", config.ConfDir)
fmt.Println("DIRENV_SYSCONFIG", config.SysConfDir)

fmt.Println("bash_path", config.BashPath)
fmt.Println("disable_stdin", config.DisableStdin)
Expand Down
33 changes: 28 additions & 5 deletions internal/cmd/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@ type Config struct {
Env Env
WorkDir string // Current directory
ConfDir string
SysConfDir string
CacheDir string
DataDir string
SelfPath string
BashPath string
RCFile string
TomlPath string
SysTomlPath string
DisableStdin bool
StrictEnv bool
LoadDotenv bool
Expand Down Expand Up @@ -92,6 +94,11 @@ func LoadConfig(env Env) (config *Config, err error) {
return
}

config.SysConfDir = env[DIRENV_SYSCONFIG]
if config.SysConfDir == "" {
config.SysConfDir = sysConfDir
}

var exePath string
if exePath, err = os.Executable(); err != nil {
err = fmt.Errorf("LoadConfig() os.Executable() failed: %w", err)
Expand All @@ -111,7 +118,13 @@ func LoadConfig(env Env) (config *Config, err error) {
config.WhitelistPrefix = make([]string, 0)
config.WhitelistExact = make(map[string]bool)

// Load the TOML config
// Load system-wide TOML config
config.SysTomlPath = filepath.Join(config.SysConfDir, "direnv.toml")
if _, statErr := os.Stat(config.SysTomlPath); statErr != nil {
config.SysTomlPath = ""
}

// Load user-specific TOML config
config.TomlPath = filepath.Join(config.ConfDir, "direnv.toml")
if _, statErr := os.Stat(config.TomlPath); statErr != nil {
config.TomlPath = filepath.Join(config.ConfDir, "config.toml")
Expand All @@ -120,7 +133,7 @@ func LoadConfig(env Env) (config *Config, err error) {
}
}

if config.TomlPath != "" {
if config.TomlPath != "" || config.SysTomlPath != "" {
// Declare global once and then share it between the top-level and Global
// keys. The goal here is to let the decoder fill global regardless of if
// the values are in the [global] section or not. The reason we do that is
Expand All @@ -130,9 +143,19 @@ func LoadConfig(env Env) (config *Config, err error) {
tomlGlobal: &global,
Global: &global,
}
if _, err = toml.DecodeFile(config.TomlPath, &tomlConf); err != nil {
err = fmt.Errorf("LoadConfig() failed to parse %s: %w", config.TomlPath, err)
return

if config.SysTomlPath != "" {
if _, err = toml.DecodeFile(config.SysTomlPath, &tomlConf); err != nil {
err = fmt.Errorf("LoadConfig() failed to parse %s: %w", config.SysTomlPath, err)
return
}
}

if config.TomlPath != "" {
if _, err = toml.DecodeFile(config.TomlPath, &tomlConf); err != nil {
err = fmt.Errorf("LoadConfig() failed to parse %s: %w", config.TomlPath, err)
return
}
}

for _, path := range tomlConf.Whitelist.Prefix {
Expand Down
1 change: 1 addition & 0 deletions internal/cmd/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const (
DIRENV_CONFIG = "DIRENV_CONFIG"
DIRENV_BASH = "DIRENV_BASH"
DIRENV_DEBUG = "DIRENV_DEBUG"
DIRENV_SYSCONFIG = "DIRENV_SYSCONFIG"

DIRENV_DIR = "DIRENV_DIR"
DIRENV_FILE = "DIRENV_FILE"
Expand Down
4 changes: 3 additions & 1 deletion internal/cmd/mod.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,20 @@ import (
var (
bashPath string
stdlib string
sysConfDir string
version string
)

// Main is the main entrypoint to direnv
func Main(env Env, args []string, modBashPath string, modStdlib string, modVersion string) error {
func Main(env Env, args []string, modBashPath string, modSysConfDir string, modStdlib string, modVersion string) error {
// We drop $PWD from caller since it can include symlinks, which will
// break relative path access when finding .envrc or .env in a parent.
_ = os.Unsetenv("PWD")

setupLogging(env)
bashPath = modBashPath
stdlib = modStdlib
sysConfDir = modSysConfDir
version = modVersion

err := CommandsDispatch(env, args)
Expand Down
4 changes: 3 additions & 1 deletion internal/cmd/stdlib.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,7 @@ import "strings"

// getStdlib returns the stdlib.sh, with references to direnv replaced.
func getStdlib(config *Config) string {
return strings.Replace(stdlib, "$(command -v direnv)", config.SelfPath, 1)
str := strings.Replace(stdlib, "${DIRENV_SYSCONFIG:-/etc/direnv}", "${DIRENV_SYSCONFIG:-"+config.SysConfDir+"}", 1)

return strings.Replace(str, "$(command -v direnv)", config.SelfPath, 1)
}
4 changes: 3 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ var (
bashPath string
//go:embed stdlib.sh
stdlib string
// Configured at compile time
sysConfDir string
//go:embed version.txt
version string
)
Expand All @@ -21,7 +23,7 @@ func main() {
env = cmd.GetEnv()
args = os.Args
)
err := cmd.Main(env, args, bashPath, stdlib, strings.TrimSpace(version))
err := cmd.Main(env, args, bashPath, sysConfDir, stdlib, strings.TrimSpace(version))
if err != nil {
os.Exit(1)
}
Expand Down
2 changes: 1 addition & 1 deletion man/direnv-stdlib.1
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ direnv-stdlib - functions for the \fB\fC\&.envrc\fR

.SH DESCRIPTION
.PP
Outputs a bash script called the \fIstdlib\fP\&. The following commands are included in that script and loaded in the context of an \fB\fC\&.envrc\fR\&. In addition, it also loads the file in \fB\fC~/.config/direnv/direnvrc\fR if it exists.
Outputs a bash script called the \fIstdlib\fP\&. The following commands are included in that script and loaded in the context of an \fB\fC\&.envrc\fR\&. In addition, it also loads the files in \fB\fC/etc/direnv/direnvrc\fR and \fB\fC~/.config/direnv/direnvrc\fR if one of them exists.

.SH STDLIB
.SS \fB\fChas <command>\fR
Expand Down
2 changes: 1 addition & 1 deletion man/direnv-stdlib.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ SYNOPSIS
DESCRIPTION
-----------

Outputs a bash script called the *stdlib*. The following commands are included in that script and loaded in the context of an `.envrc`. In addition, it also loads the file in `~/.config/direnv/direnvrc` if it exists.
Outputs a bash script called the *stdlib*. The following commands are included in that script and loaded in the context of an `.envrc`. In addition, it also loads the files in `/etc/direnv/direnvrc` and `~/.config/direnv/direnvrc` if one of them exists.

STDLIB
------
Expand Down
38 changes: 30 additions & 8 deletions man/direnv.1
Original file line number Diff line number Diff line change
Expand Up @@ -178,8 +178,10 @@ things.
Exporting variables by hand is a bit repetitive so direnv provides a set of
utility functions that are made available in the context of the \fB\fC\&.envrc\fR file.
Check the direnv-stdlib(1) man page for more details. You can also define your
own extensions inside \fB\fC$XDG_CONFIG_HOME/direnv/direnvrc\fR or
\fB\fC$XDG_CONFIG_HOME/direnv/lib/*.sh\fR files.
user-specific extensions inside \fB\fC$DIRENV_CONFIG/direnvrc\fR or
\fB\fC$DIRENV_CONFIG/lib/*.sh\fR files. Additionally system-wide extensions can be
placed in \fB\fC$DIRENV_SYSCONFIG/direnvrc\fR, which in turn loads system-wide
extensions from \fB\fC$DIRENV_SYSCONFIG/direnv.d/*.sh\fR\&.

.PP
Hopefully this is enough to get you started.
Expand All @@ -189,23 +191,43 @@ Hopefully this is enough to get you started.
\fB\fCXDG_CONFIG_HOME\fR
Defaults to \fB\fC$HOME/.config\fR\&.

.TP
\fB\fCDIRENV_CONFIG\fR
Defaults to \fB\fC$XDG_CONFIG_HOME/direnv\fR\&.

.TP
\fB\fCDIRENV_SYSCONFIG\fR
Defaults to \fB\fC/etc/direnv\fR\&.

.SH FILES
.TP
\fB\fC$XDG_CONFIG_HOME/direnv/direnv.toml\fR
Direnv configuration. See direnv.toml(1).
\fB\fC$DIRENV_CONFIG/direnv.toml\fR
Direnv user-specific configuration. See direnv.toml(1).

.TP
\fB\fC$XDG_CONFIG_HOME/direnv/direnvrc\fR
\fB\fC$DIRENV_CONFIG/direnvrc\fR
Bash code loaded before every \fB\fC\&.envrc\fR\&. Good for personal extensions.

.TP
\fB\fC$XDG_CONFIG_HOME/direnv/lib/*.sh\fR
Bash code loaded before every \fB\fC\&.envrc\fR\&. Good for third-party extensions.
\fB\fC$DIRENV_CONFIG/lib/*.sh\fR
Bash code loaded before every \fB\fC\&.envrc\fR\&. Good for personal third-party extensions.

.TP
\fB\fC$XDG_DATA_HOME/direnv/allow\fR
\fB\fC$DIRENV_CONFIG/allow\fR
Records which \fB\fC\&.envrc\fR files have been \fB\fCdirenv allow\fRed.

.TP
\fB\fC$DIRENV_SYSCONFIG/direnv.toml\fR
Direnv system-wide configuration loaded before user-specific configuration. See direnv.toml(1).

.TP
\fB\fC$DIRENV_SYSCONFIG/direnvrc\fR
Bash code loaded before every \fB\fC\&.envrc\fR\&. Good for system-wide extensions.

.TP
\fB\fC$DIRENV_SYSCONFIG/direnv.d/*.sh\fR
Bash code loaded before every \fB\fC\&.envrc\fR\&. Good for system-wide third-party extensions.

.SH CONTRIBUTE
.PP
Bug reports, contributions and forks are welcome.
Expand Down
33 changes: 25 additions & 8 deletions man/direnv.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,10 @@ things.
Exporting variables by hand is a bit repetitive so direnv provides a set of
utility functions that are made available in the context of the `.envrc` file.
Check the direnv-stdlib(1) man page for more details. You can also define your
own extensions inside `$XDG_CONFIG_HOME/direnv/direnvrc` or
`$XDG_CONFIG_HOME/direnv/lib/*.sh` files.
user-specific extensions inside `$DIRENV_CONFIG/direnvrc` or
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should still respect XDG spec and refer to XDG spec IMHO.

`$DIRENV_CONFIG/lib/*.sh` files. Additionally system-wide extensions can be
placed in `$DIRENV_SYSCONFIG/direnvrc`, which in turn loads system-wide
extensions from `$DIRENV_SYSCONFIG/direnv.d/*.sh`.

Hopefully this is enough to get you started.

Expand All @@ -149,21 +151,36 @@ ENVIRONMENT
`XDG_CONFIG_HOME`
: Defaults to `$HOME/.config`.

`DIRENV_CONFIG`
: Defaults to `$XDG_CONFIG_HOME/direnv`.

`DIRENV_SYSCONFIG`
: Defaults to `/etc/direnv`.

FILES
-----

`$XDG_CONFIG_HOME/direnv/direnv.toml`
: Direnv configuration. See direnv.toml(1).
`$DIRENV_CONFIG/direnv.toml`
: Direnv user-specific configuration. See direnv.toml(1).

`$XDG_CONFIG_HOME/direnv/direnvrc`
`$DIRENV_CONFIG/direnvrc`
: Bash code loaded before every `.envrc`. Good for personal extensions.

`$XDG_CONFIG_HOME/direnv/lib/*.sh`
: Bash code loaded before every `.envrc`. Good for third-party extensions.
`$DIRENV_CONFIG/lib/*.sh`
: Bash code loaded before every `.envrc`. Good for personal third-party extensions.

`$XDG_DATA_HOME/direnv/allow`
`$DIRENV_CONFIG/allow`
: Records which `.envrc` files have been `direnv allow`ed.

`$DIRENV_SYSCONFIG/direnv.toml`
: Direnv system-wide configuration loaded before user-specific configuration. See direnv.toml(1).

`$DIRENV_SYSCONFIG/direnvrc`
: Bash code loaded before every `.envrc`. Good for system-wide extensions.

`$DIRENV_SYSCONFIG/direnv.d/*.sh`
: Bash code loaded before every `.envrc`. Good for system-wide third-party extensions.

CONTRIBUTE
----------

Expand Down
1 change: 1 addition & 0 deletions shell.nix
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ mkShell {
go
go-md2man
gox
gnused

# Shells
bashInteractive
Expand Down