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  }