Skip to content

Commit

Permalink
implement additional (and optional) system-wide configuration path PR…
Browse files Browse the repository at this point in the history
…EFIX/etc/direnv

Signed-off-by: Stephan Jorek <stephan.jorek@brandung.de>
  • Loading branch information
brandung-sjorek committed Dec 27, 2022
1 parent b6ebd2d commit 9799e7f
Show file tree
Hide file tree
Showing 17 changed files with 208 additions and 45 deletions.
22 changes: 17 additions & 5 deletions GNUmakefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
############################################################################

# Set this to change the target installation path
PREFIX = /usr/local
BINDIR = ${PREFIX}/bin
SHAREDIR = ${PREFIX}/share
MANDIR = ${SHAREDIR}/man
DISTDIR ?= dist
PREFIX = /usr/local
BINDIR = ${PREFIX}/bin
SYSCONFDIR = ${PREFIX}/etc/direnv
SHAREDIR = ${PREFIX}/share
MANDIR = ${SHAREDIR}/man
DISTDIR ?= dist

# filename of the executable
exe = direnv$(shell go env GOEXE)
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 @@ -145,8 +152,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
18 changes: 10 additions & 8 deletions internal/cmd/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@ package cmd

//nolint
const (
DIRENV_CONFIG = "DIRENV_CONFIG"
DIRENV_BASH = "DIRENV_BASH"
DIRENV_DEBUG = "DIRENV_DEBUG"

DIRENV_DIR = "DIRENV_DIR"
DIRENV_FILE = "DIRENV_FILE"
DIRENV_WATCHES = "DIRENV_WATCHES"
DIRENV_DIFF = "DIRENV_DIFF"
DIRENV_CONFIG = "DIRENV_CONFIG"
DIRENV_SYSCONFIG = "DIRENV_SYSCONFIG"
DIRENV_BASH = "DIRENV_BASH"
DIRENV_DEBUG = "DIRENV_DEBUG"

DIRENV_DIR = "DIRENV_DIR"
DIRENV_FILE = "DIRENV_FILE"
DIRENV_WATCHES = "DIRENV_WATCHES"
DIRENV_DIFF = "DIRENV_DIFF"


DIRENV_DUMP_FILE_PATH = "DIRENV_DUMP_FILE_PATH"
)
10 changes: 6 additions & 4 deletions internal/cmd/mod.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,22 @@ import (
)

var (
bashPath string
stdlib string
version string
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

0 comments on commit 9799e7f

Please sign in to comment.