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}) +}