package xos import ( "fmt" "os" "path/filepath" "strings" "sync" ) type Env struct { environMu sync.RWMutex environ []string } func NewEnv(environ []string) *Env { return &Env{ environ: environ, } } func (e *Env) Environ() []string { e.environMu.RLock() defer e.environMu.RUnlock() environ2 := make([]string, 0, len(e.environ)) return append(environ2, e.environ...) } func (e *Env) Setenv(name, value string) { e.environMu.Lock() defer e.environMu.Unlock() l := fmt.Sprintf("%s=%s", name, value) for i, l2 := range e.environ { j := strings.Index(l2, "=") if j == -1 { continue } name2 := l2[:j] if name != name2 { continue } e.environ[i] = l return } e.environ = append(e.environ, l) } func (e *Env) Getenv(name string) string { e.environMu.RLock() defer e.environMu.RUnlock() for _, l := range e.environ { i := strings.Index(l, "=") if i == -1 { continue } name2 := l[:i] if name == name2 { return l[i+1:] } } return "" } func (e *Env) Bool(name string) (*bool, error) { ev := e.Getenv(name) if ev == "" { return nil, nil } eb := new(bool) if ev == "0" || ev == "false" { return eb, nil } if ev == "1" || ev == "true" { *eb = true return eb, nil } return nil, fmt.Errorf("$%s must be 0, 1, false or true but got %q", name, ev) } func (e *Env) HumanPath(fp string) string { if strings.HasPrefix(fp, e.Getenv("HOME")) { return filepath.Join("~", strings.TrimPrefix(fp, e.Getenv("HOME"))) } return fp } func (e *Env) Debug() bool { debug, err := e.Bool("DEBUG") if err != nil { os.Stderr.WriteString(fmt.Sprintf("env: %v", err)) return false } if debug == nil || !*debug { return false } return true } func (e *Env) CI() bool { ci, err := e.Bool("CI") if err != nil { os.Stderr.WriteString(fmt.Sprintf("env: %v", err)) return false } if ci == nil || !*ci { return false } return true }