From 31e87f6956af8cabfa32c21a50600e860a4dc8dc Mon Sep 17 00:00:00 2001 From: zimbatm Date: Fri, 22 Jul 2022 12:52:22 +0200 Subject: [PATCH] feat: add environ format Adds a `direnv export environ` command that outputs the diff in `(=/environ on Linux. Each line is NUL-terminated. If the `=` is not present on a line, consider that the should be unset. The idea was to find a format that could eventually replace the evals in the hooks in the various shells. --- internal/cmd/shell.go | 2 ++ internal/cmd/shell_environ.go | 51 +++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 internal/cmd/shell_environ.go diff --git a/internal/cmd/shell.go b/internal/cmd/shell.go index 62db86daf..f5e564d52 100644 --- a/internal/cmd/shell.go +++ b/internal/cmd/shell.go @@ -46,6 +46,8 @@ func DetectShell(target string) Shell { return Bash case "elvish": return Elvish + case "environ": + return Environ case "fish": return Fish case "gha": diff --git a/internal/cmd/shell_environ.go b/internal/cmd/shell_environ.go new file mode 100644 index 000000000..0708b64f2 --- /dev/null +++ b/internal/cmd/shell_environ.go @@ -0,0 +1,51 @@ +package cmd + +import ( + "errors" +) + +// environShell is not a real shell +type environShell struct{} + +// Environ is a format exporter and not a shell. It implements a similar +// format as /proc//environ in Linux. +var Environ Shell = environShell{} + +func (sh environShell) Hook() (string, error) { + return "", errors.New("this feature is not supported") +} + +// Exports emits a string composed of (=), separated by \0. +// +// It's the same as the Dump format with one additional case: if there is no = +// in the line, the environment variable should be unset. +func (sh environShell) Export(e ShellExport) (out string) { + for key, value := range e { + if value == nil { + out += sh.unset(key) + } else { + out += sh.export(key, *value) + } + } + return out +} + +// Dump emits a string composed of =/environ and works with +// values that include special characters like \n. +func (sh environShell) Dump(env Env) (out string) { + for key, value := range env { + out += sh.export(key, value) + } + return out +} + +// = , terminated by \0 +func (sh environShell) export(key, value string) string { + return key + "=" + value + string([]byte{0}) +} + +// , terminated by \0 +func (sh environShell) unset(key string) string { + return key + string([]byte{0}) +}