envish is a library to help you emulate UNIX-like program environments in Golang packages.
It is released under the 3-clause New BSD license. See LICENSE.md for details.
import envish "github.com/ganbarodigital/go_envish/v4"
env := envish.NewLocalEnv()
// add to this temporary environment
// WITHOUT changing your program's environment
env.Setenv("EXAMPLE_KEY", "EXAMPLE VALUE")
// pass it into run a child process
cmd := exec.Command('example-cmd')
cmd.Env = env.Environ()
cmd.Start()
We've built Envish for anyone who needs to emulate a UNIX-like environment in their own Golang packages. Or anyone who just needs a simple key/value store with a familiar API.
We're using it ourselves for our Pipe and Scriptish packages.
Golang's os
package provides support for working with your program's
environment. But what if you want to make temporary changes to that
environment, just to pass environment variables into child processes?
This is a very common pattern used in UNIX shell script programming:
DEBIAN_FRONTEND=noninteractive apt-get install -y mysql
In the example above, the environment variable DEBIAN_FRONTEND
is only set
for the child process apt-get
.
Import Envish into your Golang code:
import envish "github.com/ganbarodigital/go_envish/v4"
Create a copy of your program's environment:
localEnv := envish.NewLocalEnv(envish.CopyProgramEnv)
or simply start with an empty environment store:
localVars := envish.NewLocalEnv()
Get and set variables in the environment store as needed:
home := localEnv.Getenv()
localEnv.Setenv("DEBIAN_FRONTEND", "noninteractive")
func CopyProgramEnv
func CopyProgramEnv(e *LocalEnv)
CopyProgramEnv copies your program's environment into the given environment store.
It replaces any existing variables in the environment store.
func GetKeyFromPair
func GetKeyFromPair(pair string) string
GetKeyFromPair returns the KEY
from a string KEY=VALUE
.
func GetValueFromPair
func GetValueFromPair(pair string, key string) string
GetValueFromPair returns the VALUE
from a string KEY=VALUE
.
func LookupHomeDir
func LookupHomeDir(username string) (string, bool)
LookupHomeDir retrieves the given user's home directory, or false if that cannot be found.
It does not use the value of $HOME at all.
package main
import (
"fmt"
envish "github.com/ganbarodigital/go_envish/v4"
)
func main() {
// ask the operating system where your home directory is
homedir, ok := envish.LookupHomeDir("")
// print the results
fmt.Printf("ok is %v", ok)
fmt.Printf("your homedir is: %s", homedir)
}
func SetAsExporter
func SetAsExporter(e *LocalEnv)
SetAsExporter sets a flag so that the EnvStack will include its contents when building an environ to export to Golang's exec package.
type ErrEmptyKey
type ErrEmptyKey struct{ ... }
ErrEmptyKey is returned whenever we're given a key that is zero-length or only contains whitespace
func (ErrEmptyKey) Error
func (e ErrEmptyKey) Error() string
type ErrEmptyOverlayEnv
type ErrEmptyOverlayEnv struct { ... }
ErrEmptyOverlayEnv is returned whenever you call a method on an empty EnvStack
func (ErrEmptyOverlayEnv) Error
func (e ErrEmptyOverlayEnv) Error() string
type ErrNilPointer
type ErrNilPointer struct { ... }
ErrNilPointer is returned whenever you call a method on the Env struct with a nil pointer
func (ErrNilPointer) Error
func (e ErrNilPointer) Error() string
type ErrNoExporterEnv
type ErrNoExporterEnv struct { ... }
func (ErrNoExporterEnv) Error
func (e ErrNoExporterEnv) Error() string
type Expander
type Expander interface { ... }
Expander is the interface that wraps a key/value store that also supports string expansion.
type LocalEnv
type LocalEnv struct { ... }
LocalEnv holds a list key/value pairs.
package main
import (
"fmt"
envish "github.com/ganbarodigital/go_envish/v4"
)
func main() {
// create a local environment
localEnv := envish.NewLocalEnv()
// it starts as an empty environment
fmt.Print(localEnv.Getenv("$USER"))
}
func NewLocalEnv
func NewLocalEnv(options ...func(*LocalEnv)) *LocalEnv
NewLocalEnv creates an empty environment store.
You can pass functional options into NewLocalEnv to change the environment store before it is returned to you.
package main
import (
"fmt"
envish "github.com/ganbarodigital/go_envish/v4"
)
func main() {
// create a local environment
localEnv := envish.NewLocalEnv()
// it starts as an empty environment
fmt.Print(localEnv.Getenv("$USER"))
}
CopyProgramEnv is a functional option that will populate the environment store with a copy of your program's environment.
package main
import (
"fmt"
envish "github.com/ganbarodigital/go_envish/v4"
)
func main() {
// create a local environment
//
// it will start with a copy of your program's environment
localEnv := envish.NewLocalEnv(envish.CopyProgramEnv)
// on UNIX-like systems, this will print the name of the user
// who is running the program
fmt.Print(localEnv.Getenv("$USER"))
}
SetAsExporter is a functional option that will tell the OverlayEnv to include your LocalEnv's contents in any call to the OverlayEnv's Environ function.
package main
import (
"fmt"
envish "github.com/ganbarodigital/go_envish/v4"
)
func main() {
// create a local environment
//
// if you add this to an OverlayEnv, the OverlayEnv will include
// its contents when you call the OverlayEnv's Environ method.
localEnv := envish.NewLocalEnv(envish.SetAsExporter)
// this environment is now an exporter
fmt.Print(localEnv.IsExporter())
}
Output:
true
func (*LocalEnv) Clearenv
func (e *LocalEnv) Clearenv()
Clearenv deletes all entries from the given LocalEnv. The program's environment remains unchanged.
package main
import (
envish "github.com/ganbarodigital/go_envish/v4"
)
func main() {
// create a environment store
localEnv := envish.NewLocalEnv(envish.CopyProgramEnv)
// empty the environment store completely
localEnv.Clearenv()
}
func (*LocalEnv) Environ
func (e *LocalEnv) Environ() []string
Environ returns a copy of all entries in the form "key=value".
This is compatible with any Golang standard library, such as os/exec
.
package main
import (
envish "github.com/ganbarodigital/go_envish/v4"
"os/exec"
)
func main() {
// create an environment store
localEnv := envish.NewLocalEnv()
// get a copy to pass into `os/exec`
cmd := exec.Command("go", "doc")
cmd.Env = localEnv.Environ()
}
func (*LocalEnv) Expand
func (e *LocalEnv) Expand(fmt string) string
Expand replaces ${var} or $var in the input string.
Internally, it uses https://github.com/ganbarodigital/go_shellexpand to do the expansion.
package main
import (
"fmt"
envish "github.com/ganbarodigital/go_envish/v4"
)
func main() {
// create an environment store
localEnv := envish.NewLocalEnv()
// show what we have
fmt.Print(localEnv.Expand("USER is ${USER}\n"))
}
func (*LocalEnv) Getenv
func (e *LocalEnv) Getenv(key string) string
Getenv returns the value of the variable named by the key.
If the key is not found, an empty string is returned.
package main
import (
"fmt"
envish "github.com/ganbarodigital/go_envish/v4"
)
func main() {
// create an environment store
localEnv := envish.NewLocalEnv()
// get a variable from the environment store
user := localEnv.Getenv("USER")
fmt.Print(user)
}
func (*LocalEnv) IsExporter
func (e *LocalEnv) IsExporter() bool
IsExporter returns true if this backing store holds variables that should be exported to external programs.
It is used by OverlayEnv.Environ to work out which keys and values the OverlayEnv should include in its output.
package main
import (
"fmt"
envish "github.com/ganbarodigital/go_envish/v4"
)
func main() {
// create an environment store
localEnv := envish.NewLocalEnv()
// by default, the environment store is NOT an exporter
//
// if you want to change this hint, use envish.SetAsExporter
exporting := localEnv.IsExporter()
fmt.Print(exporting)
}
Output:
false
func (*LocalEnv) Length
func (e *LocalEnv) Length() int
Length returns the number of key/value pairs stored in the LocalEnv.
package main
import (
"fmt"
envish "github.com/ganbarodigital/go_envish/v4"
)
func main() {
// create an environment store
localEnv := envish.NewLocalEnv()
// find out how many variables it contains
//
// a new LocalEnv starts with no entries
fmt.Printf("environment has %d entries\n", localEnv.Length())
}
Output:
environment has 0 entries
func (*LocalEnv) LookupEnv
func (e *LocalEnv) LookupEnv(key string) (string, bool)
LookupEnv returns the value of the variable named by the key.
If the key is not found, an empty string is returned, and the returned boolean is false.
package main
import (
"fmt"
envish "github.com/ganbarodigital/go_envish/v4"
)
func main() {
// create an environment store
localEnv := envish.NewLocalEnv()
// find out if a key exists
value, ok := localEnv.LookupEnv("USER")
fmt.Printf("key exists: %v", ok)
fmt.Printf("value of key: %s", value)
}
func (*LocalEnv) MatchVarNames
func (e *LocalEnv) MatchVarNames(prefix string) []string
MatchVarNames returns a list of variable names that start with the given prefix.
It's a feature needed for ${!prefix*}
string expansion syntax.
package main
import (
"fmt"
envish "github.com/ganbarodigital/go_envish/v4"
)
func main() {
// create an environment store
localEnv := envish.NewLocalEnv()
// find all variables that begin with 'ANSIBLE_'
for _, key := range localEnv.MatchVarNames("ANSIBLE_") {
fmt.Printf("%s = %s", key, localEnv.Getenv(key))
}
}
func (*LocalEnv) Setenv
func (e *LocalEnv) Setenv(key, value string) error
Setenv sets the value of the variable named by the key. The program's environment remains unchanged.
package main
import (
envish "github.com/ganbarodigital/go_envish/v4"
)
func main() {
// create an environment store
localEnv := envish.NewLocalEnv()
// set a value in the environment store
localEnv.Setenv("DEBIAN_FRONTEND", "noninteractive")
}
Setenv will return a envish.ErrEmptyKey
error if you pass in a key that
is either empty, or contains only whitespace.
package main
import (
"fmt"
envish "github.com/ganbarodigital/go_envish/v4"
)
func main() {
// create an environment store
localEnv := envish.NewLocalEnv()
// try to create an invalid environment variable
err := localEnv.Setenv("", "key-is-invalid")
fmt.Print(err)
}
Output:
zero-length key, or key only contains whitespace
package main
import (
"fmt"
envish "github.com/ganbarodigital/go_envish/v4"
)
func main() {
var localEnv *envish.LocalEnv = nil
err := localEnv.Setenv("valid-key", "valid-value")
fmt.Print(err)
}
Output:
nil pointer to environment store passed to LocalEnv.Setenv
func (*LocalEnv) Unsetenv
func (e *LocalEnv) Unsetenv(key string)
Unsetenv deletes the variable named by the key.
package main
import (
envish "github.com/ganbarodigital/go_envish/v4"
)
func main() {
// create an environment store
localEnv := envish.NewLocalEnv()
// delete an entry from the environment store
localEnv.Unsetenv("$#")
}
type OverlayEnv
type OverlayEnv struct { ... }
OverlayEnv works on a collection of variable backing stores.
Use an OverlayEnv to combine one (or more) LocalEnv and a single ProgramEnv into a single logical environment.
We do this in https://github.com/ganbarodigital/go_scriptish to emulate local variable support.
func NewOverlayEnv
func NewOverlayEnv(envs []Expander) *OverlayEnv
NewOverlayEnv builds a single logical environments from the given set of underlying environments.
NewOverlayEnv returns a pointer to an OverlayEnv struct. You can use the methods of the OverlayStruct to read from and write to each of these environments.
The order of the arguments to NewOverlayEnv matters. The returned OverlayEnv's methods will read from / write to the underlying environments in the order you've given.
package main
import (
envish "github.com/ganbarodigital/go_envish/v4"
)
func main() {
// create individual environments
localVars := envish.NewLocalEnv()
progVars := envish.NewLocalEnv(envish.SetAsExporter)
progEnv := envish.NewProgramEnv()
// combine them
env := envish.NewOverlayEnv(
[]envish.Expander{
localVars,
progVars,
progEnv,
},
)
// you can now treat them as a single environment
env.Setenv("$1", "go")
}
func (*OverlayEnv) Clearenv
func (e *OverlayEnv) Clearenv()
Clearenv deletes all variables in every environment in the OverlayEnv. If your overlay env includes a ProgramEnv, this WILL delete all of your program's environment variables.
Use with extreme caution!
func (*OverlayEnv) Environ
func (e *OverlayEnv) Environ() []string
Environ() returns a copy of all of the variables in your OverlayEnv
in the form key=value
. This format is compatible with Golang's
built-in packages.
When it builds the list, it follows these rules:
-
it searches the environments in the order you provided them to NewOverlayEnv
-
it only includes variables from environments where the IsExporter method returns
true
-
if the same variable is set in multiple environments, it uses the first value it finds
package main
import (
envish "github.com/ganbarodigital/go_envish/v4"
"os/exec"
)
func main() {
// create our independent environments
localVars := envish.NewLocalEnv()
progVars := envish.NewLocalEnv(envish.SetAsExporter)
progEnv := envish.NewProgramEnv()
// combine them
env := envish.NewOverlayEnv(
[]envish.Expander{
localVars,
progVars,
progEnv,
},
)
// export their variables
//
// it will pick up variables from:
//
// - progVars (because it was called with the SetAsExporter functional option)
// - progEnv (because ProgramEnv.IsExporter() ALWAYS returns `true`)
//
// if a variable is set in both `progVars` and `progEnv`, it will use the
// value from `progVars`
environ := env.Environ()
// pass it into run a child process
cmd := exec.Command("godoc")
cmd.Env = environ
// you can now call cmd.Start()
}
func (*OverlayEnv) Expand
func (e *OverlayEnv) Expand(fmt string) string
Expand will replace ${key}
and $key
entries in a format string,
by looking up values from the environments contained within the OverlayEnv.
-
it uses the given OverlayEnv's LookupEnv to find the values of variables
-
it uses the given OverlayEnv's Setenv to set the values of variables
-
it uses the given OverlayEnv's MatchVarNames to expand variable name prefixes
-
it uses the given OverlayEnv's LookupHomeDir to expand
~
(tilde)
Hopefully, we've got the logic right, and you'll find that your expansions just work the way you'd naturally expect.
Internally, it uses https://github.com/ganbarodigital/go_shellexpand to do the shell expansion. It supports the vast majority of UNIX shell string expansion operations.
package main
import (
"fmt"
envish "github.com/ganbarodigital/go_envish/v4"
)
func main() {
// create individual environments
localVars := envish.NewLocalEnv()
progVars := envish.NewLocalEnv(envish.SetAsExporter)
progEnv := envish.NewProgramEnv()
// combine them
env := envish.NewOverlayEnv(
[]envish.Expander{
localVars,
progVars,
progEnv,
},
)
// use UNIX shell expansion to see what we have
fmt.Print(env.Expand("USER is ${USER}\n"))
}
func (*OverlayEnv) Export
func (e *OverlayEnv) Export(key, value string) error
Export emulates UNIX shell export XXX=YYY
behaviour. It returns an
error if the environment variable cannot be set.
-
It makes no changes at all if the given OverlayEnv does not have any environments that are exporters.
-
It searches each environment inside the given OverlayEnv in the order that you passed them into NewOverlayEnv.
-
It overwrites any existing value for the given key, in every environment that it searches (including environments that are not exporters). This should ensure consistent results whenever you call Getenv on the given OverlayEnv.
-
It stops once it has set the environment variable inside an environment that is an exporter.
package main
import (
envish "github.com/ganbarodigital/go_envish/v4"
)
func main() {
// build an environment stack without keeping a reference
// to any of the individual environments
env := envish.NewOverlayEnv(
[]envish.Expander{
envish.NewLocalEnv(),
envish.NewLocalEnv(envish.SetAsExporter),
envish.NewProgramEnv(),
},
)
// set a variable that we want to see appear in the Environ
// results
//
// this will be set in the second environment that we passed
// into NewOverlayEnv above
env.Export("DEBIAN_FRONTEND", "noninteractive")
}
func (*OverlayEnv) GetEnvByID
func (e *OverlayEnv) GetEnvByID(id int) (Expander, bool)
GetEnvByID returns the requested environment from the given OverlayEnv.
ID 0
is the first environment you passed into NewOverlayEnv, ID 1
is the second environment, and so on.
If you request an ID that the given OverlayEnv does not have, it returns
nil, false
.
GetEnvByID is handy if you don't want to keep separate references to the environments after you've combined them into the OverlayEnv.
// Envish is a library to help you emulate UNIX-like program environments
// in Golang packages
//
// Copyright 2019-present Ganbaro Digital Ltd
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in
// the documentation and/or other materials provided with the
// distribution.
//
// * Neither the names of the copyright holders nor the names of his
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
package main
import (
envish "github.com/ganbarodigital/go_envish/v4"
)
const (
LocalVars = iota
ProgramVars
ProgramEnv
)
func main() {
// build an environment stack without keeping a reference
// to any of the individual environments
env := envish.NewOverlayEnv(
[]envish.Expander{
envish.NewLocalEnv(),
envish.NewLocalEnv(envish.SetAsExporter),
envish.NewProgramEnv(),
},
)
// NOTE how we use the constant defined earlier to find the right
// environment to set this variable in
localVars, _ := env.GetEnvByID(LocalVars)
// this will now be available to read and update in the `env` elsewhere
localVars.Setenv("$#", "2")
}
func (*OverlayEnv) GetTopMostEnv
func (e *OverlayEnv) GetTopMostEnv() (Expander, error)
GetTopMostEnv returns the envish environment that's at the top of the overlay stack.
If we don't have that environment, we return a suitable error.
package main
import (
envish "github.com/ganbarodigital/go_envish/v4"
)
func main() {
// build an environment stack without keeping a reference
// to any of the individual environments
env := envish.NewOverlayEnv(
[]envish.Expander{
envish.NewLocalEnv(),
envish.NewLocalEnv(envish.SetAsExporter),
envish.NewProgramEnv(),
},
)
// now, imagine we want to set some local variables
localVars, _ := env.GetTopMostEnv()
localVars.Setenv("$#", "2")
}
func (*OverlayEnv) Getenv
func (e *OverlayEnv) Getenv(key string) string
Getenv returns the value of the given variable. If the variable does not
exist, it returns ""
(empty string).
-
it searches the environments in the order you provided them to NewOverlayEnv
-
if the same variable is set in multiple environments, it uses the first value it finds
package main
import (
"fmt"
envish "github.com/ganbarodigital/go_envish/v4"
)
func main() {
// build an environment stack without keeping a reference
// to any of the individual environments
env := envish.NewOverlayEnv(
[]envish.Expander{
envish.NewLocalEnv(),
envish.NewLocalEnv(envish.SetAsExporter),
envish.NewProgramEnv(),
},
)
// show what we have
fmt.Printf("USER is %s`n", env.Getenv("USER"))
}
func (*OverlayEnv) IsExporter
func (e *OverlayEnv) IsExporter() bool
IsExporter returns true
if (and only if) any of the environments in
the overlay env hold variables that should be exported to external
programs.
package main
import (
"fmt"
envish "github.com/ganbarodigital/go_envish/v4"
)
func main() {
// build an environment stack without keeping a reference
// to any of the individual environments
env := envish.NewOverlayEnv(
[]envish.Expander{
envish.NewLocalEnv(),
envish.NewLocalEnv(envish.SetAsExporter),
envish.NewProgramEnv(),
},
)
fmt.Print(env.IsExporter())
}
Output:
true
If none of the environments passed to NewOverlayEnv are exporters,
IsExporter will return false
.
package main
import (
"fmt"
envish "github.com/ganbarodigital/go_envish/v4"
)
func main() {
// build an environment stack without keeping a reference
// to any of the individual environments
env := envish.NewOverlayEnv(
[]envish.Expander{
envish.NewLocalEnv(),
envish.NewLocalEnv(),
},
)
fmt.Print(env.IsExporter())
}
Output:
false
If you have a ProgramEnv anywhere in your OverlayEnv, IsExporter
will always return true
.
package main
import (
"fmt"
envish "github.com/ganbarodigital/go_envish/v4"
)
func main() {
// build an environment stack without keeping a reference
// to any of the individual environments
env := envish.NewOverlayEnv(
[]envish.Expander{
envish.NewLocalEnv(),
envish.NewProgramEnv(),
},
)
fmt.Print(env.IsExporter())
}
Output:
true
func (*OverlayEnv) LookupEnv
func (e *OverlayEnv) LookupEnv(key string) (string, bool)
LookupEnv returns the value of the given variable. If the variable does
not exist, it returns "", false
.
-
it searches the environments in the order you provided them to NewOverlayEnv
-
if the same variable is set in multiple environments, it uses the first value it finds
package main
import (
"fmt"
envish "github.com/ganbarodigital/go_envish/v4"
)
func main() {
// build an environment stack without keeping a reference
// to any of the individual environments
env := envish.NewOverlayEnv(
[]envish.Expander{
envish.NewLocalEnv(),
envish.NewLocalEnv(envish.SetAsExporter),
envish.NewProgramEnv(),
},
)
home, ok := env.LookupEnv("HOME")
fmt.Printf("did we find $HOME?: %v", ok)
fmt.Printf("what value did we find?: %v", home)
}
func (*OverlayEnv) MatchVarNames
func (e *OverlayEnv) MatchVarNames(prefix string) []string
MatchVarNames returns a list of variable names that start with the given prefix.
It's a feature needed for ${!prefix*}
string expansion syntax.
-
it searches the environments in the order you provided them to NewOverlayEnv
-
if the same key is found in multiple environments, it only returns the key once (ie, results are deduped before they are returned)
package main
import (
"fmt"
envish "github.com/ganbarodigital/go_envish/v4"
)
func main() {
// build an environment stack without keeping a reference
// to any of the individual environments
env := envish.NewOverlayEnv(
[]envish.Expander{
envish.NewLocalEnv(),
envish.NewLocalEnv(envish.SetAsExporter),
envish.NewProgramEnv(),
},
)
// print out all the variables with the prefix ANSIBLE_
for _, key := range env.MatchVarNames("ANSIBLE_") {
fmt.Printf("%s = %s", key, env.Getenv(key))
}
}
func (*OverlayEnv) Setenv
func (e *OverlayEnv) Setenv(key, value string) error
Setenv creates a variable (if it doesn't already exist) or updates its value (if it does exist).
-
it searches the environments in the order you provided to NewOverlayEnv
-
if the same variable is set in multiple environments, it updates the first variable it finds
-
if the variable does not exist, it is always created in the first environment you provided to NewOverlayEnv
package main
import (
envish "github.com/ganbarodigital/go_envish/v4"
)
func main() {
// create individual environments
localVars := envish.NewLocalEnv()
progVars := envish.NewLocalEnv(envish.SetAsExporter)
progEnv := envish.NewProgramEnv()
// combine them
env := envish.NewOverlayEnv(
[]envish.Expander{
localVars,
progVars,
progEnv,
},
)
// some example data to show how Setenv() works
localVars.Setenv("LOCAL", "100")
progVars.Setenv("PROG", "200")
progEnv.Setenv("ENV", "300")
// this will update the variable "PROG" in the `progVars` environment,
// because it already exists
env.Setenv("PROG", "250")
// this will create the variable "NEWVAR" in the `localVars` environment,
// because:
//
// a) NEWVAR does not yet exist, and
// b) `localVars` was the first environment passed into `NewOverlayEnv()`
env.Setenv("NEWVAR", "101")
}
func (*OverlayEnv) Unsetenv
func (e *OverlayEnv) Unsetenv(key string)
Unsetenv deletes the variable named by the key.
It will be deleted from all the environments in the stack.
package main
import (
"fmt"
envish "github.com/ganbarodigital/go_envish/v4"
)
func main() {
// create individual environments
localVars := envish.NewLocalEnv()
progVars := envish.NewLocalEnv(envish.SetAsExporter)
progEnv := envish.NewProgramEnv()
// combine them
env := envish.NewOverlayEnv(
[]envish.Expander{
localVars,
progVars,
progEnv,
},
)
// some example data to show how Unsetenv() works
localVars.Setenv("VAR", "100")
progVars.Setenv("VAR", "200")
progEnv.Setenv("VAR", "300")
// `value` is "100"
value := env.Getenv("VAR")
fmt.Printf("value is: %s\n", value)
// delete it
env.Unsetenv("VAR")
// `ok1` is false; "VAR" has been deleted from here
_, ok1 := localVars.LookupEnv("VAR")
fmt.Printf("ok1 is: %v\n", ok1)
// `ok2` is also false; "VAR" has been deleted from here as well
_, ok2 := progVars.LookupEnv("VAR")
fmt.Printf("ok2 is: %v\n", ok2)
// `ok3` is also false; "VAR" has been deleted from here as well
_, ok3 := progEnv.LookupEnv("VAR")
fmt.Printf("ok3 is: %v\n", ok3)
}
Output:
value is: 100
ok1 is: false
ok2 is: false
ok3 is: false
type ProgramEnv
type ProgramEnv struct { ... }
ProgramEnv puts helper wrapper functions around your program's environment.
func NewProgramEnv
func NewProgramEnv() *ProgramEnv
NewProgramEnv returns an envish environment that works directly with your program's environment.
package main
import (
"fmt"
envish "github.com/ganbarodigital/go_envish/v4"
)
func main() {
env := envish.NewProgramEnv()
fmt.Printf("USER is %s", env.Getenv("USER"))
}
func (*ProgramEnv) Clearenv
func (e *ProgramEnv) Clearenv()
Clearenv deletes all entries from your program's environment. Use with extreme caution!
func (*ProgramEnv) Environ
func (e *ProgramEnv) Environ() []string
Environ returns a copy of all entries in the form "key=value". This format is compatible with Golang's built-in packages.
package main
import (
envish "github.com/ganbarodigital/go_envish/v4"
"os/exec"
)
func main() {
// get access to our program environment
env := envish.NewProgramEnv()
// get a list of all entries in the environment
environ := env.Environ()
// pass it into run a child process
cmd := exec.Command("godoc")
cmd.Env = environ
// you can now call cmd.Start()
}
func (*ProgramEnv) Expand
func (e *ProgramEnv) Expand(fmt string) string
Expand replaces ${var} or $var in the input string, by looking up values from your program's environment.
Internally, it uses https://github.com/ganbarodigital/go_shellexpand to do the shell expansion. It supports the vast majority of UNIX shell string expansion operations.
package main
import (
"fmt"
envish "github.com/ganbarodigital/go_envish/v4"
)
func main() {
// get access to our program environment
env := envish.NewProgramEnv()
// show what we have
fmt.Print(env.Expand("USER is ${USER}"))
}
func (*ProgramEnv) Getenv
func (e *ProgramEnv) Getenv(key string) string
Getenv returns the value of the variable named by the key.
If the key is not found, an empty string is returned.
package main
import (
"fmt"
envish "github.com/ganbarodigital/go_envish/v4"
)
func main() {
// get access to our program environment
env := envish.NewProgramEnv()
// show what we have
fmt.Printf("USER is %s", env.Getenv("USER"))
}
func (*ProgramEnv) IsExporter
func (e *ProgramEnv) IsExporter() bool
IsExporter always returns true
.
It is used by OverlayEnv.Environ to work out which keys and values the OverlayEnv should include in its output.
package main
import (
"fmt"
envish "github.com/ganbarodigital/go_envish/v4"
)
func main() {
// get access to our program environment
env := envish.NewProgramEnv()
// a ProgramEnv is always an environment exporter
fmt.Printf("env.IsExporter() is %v", env.IsExporter())
}
Output:
env.IsExporter() is true
func (*ProgramEnv) LookupEnv
func (e *ProgramEnv) LookupEnv(key string) (string, bool)
LookupEnv returns the value of the variable named by the key.
If the key is not found, an empty string is returned, and the returned boolean is false.
package main
import (
"fmt"
envish "github.com/ganbarodigital/go_envish/v4"
)
func main() {
// get access to our program environment
env := envish.NewProgramEnv()
value, ok := env.LookupEnv("USER")
fmt.Printf("ok is: %v\n", ok)
fmt.Printf("value is: %v\n", value)
}
func (*ProgramEnv) MatchVarNames
func (e *ProgramEnv) MatchVarNames(prefix string) []string
MatchVarNames returns a list of variable names that start with the given prefix.
It's a feature needed for ${!prefix*}
string expansion syntax.
package main
import (
"fmt"
envish "github.com/ganbarodigital/go_envish/v4"
)
func main() {
// get access to your program environment
env := envish.NewProgramEnv()
// print out all the variables with the prefix ANSIBLE_
for _, key := range env.MatchVarNames("ANSIBLE_") {
fmt.Printf("%s = %s", key, env.Getenv(key))
}
}
func (*ProgramEnv) RestoreEnvironment
func (e *ProgramEnv) RestoreEnvironment(pairs []string)
RestoreEnvironment writes the given "key=value" pairs into your program's environment.
It does not empty your program's environment first!
It was originally added so that our unit tests could put the 'go test' program environment back in place after each test had run.
package main
import (
envish "github.com/ganbarodigital/go_envish/v4"
)
func main() {
// get access to your program environment
env := envish.NewProgramEnv()
// take a backup of the whole environment
backup := env.Environ()
// nuke the environment
env.Clearenv()
// restore from backup
env.RestoreEnvironment(backup)
}
func (*ProgramEnv) Setenv
func (e *ProgramEnv) Setenv(key, value string) error
Setenv sets the value of the variable named by the key.
package main
import (
envish "github.com/ganbarodigital/go_envish/v4"
"os/exec"
)
func main() {
// get access to your program environment
env := envish.NewProgramEnv()
// set a new environment variable
//
// this will be picked up the next time you call a child process
env.Setenv("DEBIAN_FRONTEND", "noninteractive")
// pass it into run a child process
cmd := exec.Command("apt-get", "install", "mysql-server")
cmd.Env = env.Environ()
// you can now call cmd.Start()
}
func (*ProgramEnv) Unsetenv
func (e *ProgramEnv) Unsetenv(key string)
Unsetenv deletes the variable named by the key.
This will remove the given variable from your program's environment. Use with caution!
package main
import (
envish "github.com/ganbarodigital/go_envish/v4"
"os/exec"
)
func main() {
// get access to your program environment
env := envish.NewProgramEnv()
// set a new environment variable
//
// this will be picked up the next time you call a child process
env.Setenv("DEBIAN_FRONTEND", "noninteractive")
// pass it into run a child process
cmd := exec.Command("apt-get", "install", "mysql-server")
cmd.Env = env.Environ()
// you can now call cmd.Start()
// afterwards, undo what you originally set
env.Unsetenv("DEBIAN_FRONTEND")
}
type Reader
type Reader interface { ... }
Reader is the interface that wraps a basic, read-only key/value store.
type ReaderWriter
type ReaderWriter interface { ... }
ReaderWriter is the interface that groups the basic Read and Write methods for a key/value backing store.
type Writer
type Writer interface { ... }
Writer is the interface that wraps a basic, write-only key/value store.
Readme created from Go doc with goreadme