// Copyright 2017 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +build !plan9 package main import ( "bufio" "context" "fmt" "os" "os/user" "path/filepath" "runtime" "strings" ) const ( bashConfig = ".bash_profile" zshConfig = ".zshrc" ) // appendToPATH adds the given path to the PATH environment variable and // persists it for future sessions. func appendToPATH(value string) error { if isInPATH(value) { return nil } return persistEnvVar("PATH", pathVar+envSeparator+value) } func isInPATH(dir string) bool { p := os.Getenv("PATH") paths := strings.Split(p, envSeparator) for _, d := range paths { if d == dir { return true } } return false } func getHomeDir() (string, error) { home := os.Getenv(homeKey) if home != "" { return home, nil } u, err := user.Current() if err != nil { return "", err } return u.HomeDir, nil } func checkStringExistsFile(filename, value string) (bool, error) { file, err := os.OpenFile(filename, os.O_RDONLY, 0600) if err != nil { if os.IsNotExist(err) { return false, nil } return false, err } defer file.Close() scanner := bufio.NewScanner(file) for scanner.Scan() { line := scanner.Text() if line == value { return true, nil } } return false, scanner.Err() } func appendToFile(filename, value string) error { verbosef("Adding %q to %s", value, filename) ok, err := checkStringExistsFile(filename, value) if err != nil { return err } if ok { // Nothing to do. return nil } f, err := os.OpenFile(filename, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600) if err != nil { return err } defer f.Close() _, err = f.WriteString(lineEnding + value + lineEnding) return err } func isShell(name string) bool { return strings.Contains(currentShell(), name) } // persistEnvVarWindows sets an environment variable in the Windows // registry. func persistEnvVarWindows(name, value string) error { _, err := runCommand(context.Background(), "powershell", "-command", fmt.Sprintf(`[Environment]::SetEnvironmentVariable("%s", "%s", "User")`, name, value)) return err } func persistEnvVar(name, value string) error { if runtime.GOOS == "windows" { if err := persistEnvVarWindows(name, value); err != nil { return err } if isShell("cmd.exe") || isShell("powershell.exe") { return os.Setenv(strings.ToUpper(name), value) } // User is in bash, zsh, etc. // Also set the environment variable in their shell config. } rc, err := shellConfigFile() if err != nil { return err } line := fmt.Sprintf("export %s=%s", strings.ToUpper(name), value) if err := appendToFile(rc, line); err != nil { return err } return os.Setenv(strings.ToUpper(name), value) } func shellConfigFile() (string, error) { home, err := getHomeDir() if err != nil { return "", err } switch { case isShell("bash"): return filepath.Join(home, bashConfig), nil case isShell("zsh"): return filepath.Join(home, zshConfig), nil default: return "", fmt.Errorf("%q is not a supported shell", currentShell()) } }