github.com/rogpeppe/juju@v0.0.0-20140613142852-6337964b789e/cmd/envcmd/environmentcommand.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package envcmd 5 6 import ( 7 "fmt" 8 "io/ioutil" 9 "os" 10 "path/filepath" 11 "strings" 12 13 "github.com/juju/cmd" 14 "launchpad.net/gnuflag" 15 16 "github.com/juju/juju/environs" 17 "github.com/juju/juju/juju/osenv" 18 ) 19 20 const CurrentEnvironmentFilename = "current-environment" 21 22 // ErrNoEnvironmentSpecified is returned by commands that operate on 23 // an environment if there is no current environment, no environment 24 // has been explicitly specified, and there is no default environment. 25 var ErrNoEnvironmentSpecified = fmt.Errorf("no environment specified") 26 27 func getCurrentEnvironmentFilePath() string { 28 return filepath.Join(osenv.JujuHome(), CurrentEnvironmentFilename) 29 } 30 31 // Read the file $JUJU_HOME/current-environment and return the value stored 32 // there. If the file doesn't exist, or there is a problem reading the file, 33 // an empty string is returned. 34 func ReadCurrentEnvironment() string { 35 current, err := ioutil.ReadFile(getCurrentEnvironmentFilePath()) 36 // The file not being there, or not readable isn't really an error for us 37 // here. We treat it as "can't tell, so you get the default". 38 if err != nil { 39 return "" 40 } 41 return strings.TrimSpace(string(current)) 42 } 43 44 // Write the envName to the file $JUJU_HOME/current-environment file. 45 func WriteCurrentEnvironment(envName string) error { 46 path := getCurrentEnvironmentFilePath() 47 err := ioutil.WriteFile(path, []byte(envName+"\n"), 0644) 48 if err != nil { 49 return fmt.Errorf("unable to write to the environment file: %q, %s", path, err) 50 } 51 return nil 52 } 53 54 // There is simple ordering for the default environment. Firstly check the 55 // JUJU_ENV environment variable. If that is set, it gets used. If it isn't 56 // set, look in the $JUJU_HOME/current-environment file. If neither are 57 // available, read environments.yaml and use the default environment therein. 58 func getDefaultEnvironment() (string, error) { 59 if defaultEnv := os.Getenv(osenv.JujuEnvEnvKey); defaultEnv != "" { 60 return defaultEnv, nil 61 } 62 if currentEnv := ReadCurrentEnvironment(); currentEnv != "" { 63 return currentEnv, nil 64 } 65 envs, err := environs.ReadEnvirons("") 66 if err != nil { 67 return "", err 68 } 69 if envs.Default == "" { 70 return "", ErrNoEnvironmentSpecified 71 } 72 return envs.Default, nil 73 } 74 75 // EnvironCommand extends cmd.Command with a SetEnvName method. 76 type EnvironCommand interface { 77 cmd.Command 78 79 // SetEnvName is called prior to the wrapped command's Init method 80 // with the active environment name. The environment name is guaranteed 81 // to be non-empty at entry of Init. 82 SetEnvName(envName string) 83 } 84 85 // EnvCommandBase is a convenience type for embedding in commands 86 // that wish to implement EnvironCommand. 87 type EnvCommandBase struct { 88 cmd.CommandBase 89 EnvName string 90 } 91 92 func (c *EnvCommandBase) SetEnvName(envName string) { 93 c.EnvName = envName 94 } 95 96 // Wrap wraps the specified EnvironCommand, returning a Command 97 // that proxies to each of the EnvironCommand methods. 98 func Wrap(c EnvironCommand) cmd.Command { 99 return &environCommandWrapper{EnvironCommand: c} 100 } 101 102 type environCommandWrapper struct { 103 EnvironCommand 104 envName string 105 } 106 107 func (w *environCommandWrapper) EnvironName() string { 108 return w.envName 109 } 110 111 // ensureEnvName ensures that w.envName is non-empty, or sets it to 112 // the default environment name. If there is no default environment name, 113 // then ensureEnvName returns ErrNoEnvironmentSpecified. 114 func (w *environCommandWrapper) ensureEnvName() error { 115 if w.envName != "" { 116 return nil 117 } 118 defaultEnv, err := getDefaultEnvironment() 119 if err != nil { 120 return err 121 } 122 w.envName = defaultEnv 123 return nil 124 } 125 126 func (w *environCommandWrapper) SetFlags(f *gnuflag.FlagSet) { 127 f.StringVar(&w.envName, "e", "", "juju environment to operate in") 128 f.StringVar(&w.envName, "environment", "", "") 129 w.EnvironCommand.SetFlags(f) 130 } 131 132 func (w *environCommandWrapper) Init(args []string) error { 133 if err := w.ensureEnvName(); err != nil { 134 return err 135 } 136 w.SetEnvName(w.envName) 137 return w.EnvironCommand.Init(args) 138 }