2017-06-26 23:46:34 +02:00
|
|
|
// Copyright 2016-2017, Pulumi Corporation. All rights reserved.
|
2017-03-06 16:07:24 +01:00
|
|
|
|
2017-09-22 04:18:21 +02:00
|
|
|
package cmd
|
2017-03-06 16:07:24 +01:00
|
|
|
|
|
|
|
import (
|
2017-10-02 22:35:39 +02:00
|
|
|
"fmt"
|
|
|
|
"sort"
|
2017-10-17 01:01:34 +02:00
|
|
|
"strings"
|
2017-10-02 22:35:39 +02:00
|
|
|
|
2017-10-10 02:09:32 +02:00
|
|
|
"github.com/pulumi/pulumi/pkg/util/contract"
|
|
|
|
|
2017-08-31 23:31:33 +02:00
|
|
|
"github.com/pkg/errors"
|
2017-03-06 16:07:24 +01:00
|
|
|
"github.com/spf13/cobra"
|
|
|
|
|
2017-09-22 04:18:21 +02:00
|
|
|
"github.com/pulumi/pulumi/pkg/tokens"
|
|
|
|
"github.com/pulumi/pulumi/pkg/util/cmdutil"
|
2017-03-06 16:07:24 +01:00
|
|
|
)
|
|
|
|
|
Make major commands more pleasant
This change eliminates the need to constantly type in the environment
name when performing major commands like configuration, planning, and
deployment. It's probably due to my age, however, I keep fat-fingering
simple commands in front of investors and I am embarrassed!
In the new model, there is a notion of a "current environment", and
I have modeled it kinda sorta just like Git's notion of "current branch."
By default, the current environment is set when you `init` something.
Otherwise, there is the `coco env select <env>` command to change it.
(Running this command w/out a new <env> will show you the current one.)
The major commands `config`, `plan`, `deploy`, and `destroy` will prefer
to use the current environment, unless it is overridden by using the
--env flag. All of the `coco env <cmd> <env>` commands still require the
explicit passing of an environment which seems reasonable since they are,
after all, about manipulating environments.
As part of this, I've overhauled the aging workspace settings cruft,
which had fallen into disrepair since the initial prototype.
2017-03-22 03:23:32 +01:00
|
|
|
func newConfigCmd() *cobra.Command {
|
2017-10-16 21:04:35 +02:00
|
|
|
var stack string
|
2017-03-06 16:07:24 +01:00
|
|
|
var unset bool
|
|
|
|
cmd := &cobra.Command{
|
Make major commands more pleasant
This change eliminates the need to constantly type in the environment
name when performing major commands like configuration, planning, and
deployment. It's probably due to my age, however, I keep fat-fingering
simple commands in front of investors and I am embarrassed!
In the new model, there is a notion of a "current environment", and
I have modeled it kinda sorta just like Git's notion of "current branch."
By default, the current environment is set when you `init` something.
Otherwise, there is the `coco env select <env>` command to change it.
(Running this command w/out a new <env> will show you the current one.)
The major commands `config`, `plan`, `deploy`, and `destroy` will prefer
to use the current environment, unless it is overridden by using the
--env flag. All of the `coco env <cmd> <env>` commands still require the
explicit passing of an environment which seems reasonable since they are,
after all, about manipulating environments.
As part of this, I've overhauled the aging workspace settings cruft,
which had fallen into disrepair since the initial prototype.
2017-03-22 03:23:32 +01:00
|
|
|
Use: "config [<key> [value]]",
|
2017-03-06 16:07:24 +01:00
|
|
|
Short: "Query, set, replace, or unset configuration values",
|
2017-04-12 20:12:25 +02:00
|
|
|
Run: cmdutil.RunFunc(func(cmd *cobra.Command, args []string) error {
|
2017-10-16 21:04:35 +02:00
|
|
|
stackName, err := explicitOrCurrent(stack)
|
2017-10-03 01:37:12 +02:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2017-08-18 00:35:14 +02:00
|
|
|
if len(args) == 0 {
|
2017-10-16 21:04:35 +02:00
|
|
|
return listConfig(stackName)
|
2017-03-06 16:07:24 +01:00
|
|
|
}
|
2017-03-07 14:47:42 +01:00
|
|
|
|
2017-10-17 01:01:34 +02:00
|
|
|
key, err := parseConfigKey(args[0])
|
2017-08-31 23:31:33 +02:00
|
|
|
if err != nil {
|
|
|
|
return errors.Wrap(err, "invalid configuration key")
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(args) == 1 {
|
|
|
|
if !unset {
|
2017-10-16 21:04:35 +02:00
|
|
|
return getConfig(stackName, key)
|
2017-08-31 23:31:33 +02:00
|
|
|
}
|
2017-10-16 21:04:35 +02:00
|
|
|
return deleteConfiguration(stackName, key)
|
2017-08-31 23:31:33 +02:00
|
|
|
}
|
|
|
|
|
2017-10-16 21:04:35 +02:00
|
|
|
return setConfiguration(stackName, key, args[1])
|
2017-03-07 14:47:42 +01:00
|
|
|
}),
|
2017-03-06 16:07:24 +01:00
|
|
|
}
|
Make major commands more pleasant
This change eliminates the need to constantly type in the environment
name when performing major commands like configuration, planning, and
deployment. It's probably due to my age, however, I keep fat-fingering
simple commands in front of investors and I am embarrassed!
In the new model, there is a notion of a "current environment", and
I have modeled it kinda sorta just like Git's notion of "current branch."
By default, the current environment is set when you `init` something.
Otherwise, there is the `coco env select <env>` command to change it.
(Running this command w/out a new <env> will show you the current one.)
The major commands `config`, `plan`, `deploy`, and `destroy` will prefer
to use the current environment, unless it is overridden by using the
--env flag. All of the `coco env <cmd> <env>` commands still require the
explicit passing of an environment which seems reasonable since they are,
after all, about manipulating environments.
As part of this, I've overhauled the aging workspace settings cruft,
which had fallen into disrepair since the initial prototype.
2017-03-22 03:23:32 +01:00
|
|
|
|
|
|
|
cmd.PersistentFlags().StringVarP(
|
2017-10-16 21:04:35 +02:00
|
|
|
&stack, "stack", "s", "",
|
|
|
|
"Choose an stack other than the currently selected one")
|
Make major commands more pleasant
This change eliminates the need to constantly type in the environment
name when performing major commands like configuration, planning, and
deployment. It's probably due to my age, however, I keep fat-fingering
simple commands in front of investors and I am embarrassed!
In the new model, there is a notion of a "current environment", and
I have modeled it kinda sorta just like Git's notion of "current branch."
By default, the current environment is set when you `init` something.
Otherwise, there is the `coco env select <env>` command to change it.
(Running this command w/out a new <env> will show you the current one.)
The major commands `config`, `plan`, `deploy`, and `destroy` will prefer
to use the current environment, unless it is overridden by using the
--env flag. All of the `coco env <cmd> <env>` commands still require the
explicit passing of an environment which seems reasonable since they are,
after all, about manipulating environments.
As part of this, I've overhauled the aging workspace settings cruft,
which had fallen into disrepair since the initial prototype.
2017-03-22 03:23:32 +01:00
|
|
|
cmd.PersistentFlags().BoolVar(
|
|
|
|
&unset, "unset", false,
|
|
|
|
"Unset a configuration value")
|
|
|
|
|
2017-03-06 16:07:24 +01:00
|
|
|
return cmd
|
|
|
|
}
|
2017-10-02 22:35:39 +02:00
|
|
|
|
2017-10-17 01:01:34 +02:00
|
|
|
func parseConfigKey(key string) (tokens.ModuleMember, error) {
|
|
|
|
|
|
|
|
// As a convience, we'll treat any key with no delimiter as if:
|
|
|
|
// <program-name>:config:<key> had been written instead
|
|
|
|
if !strings.Contains(key, tokens.TokenDelimiter) {
|
|
|
|
_, pkg, err := getPackage()
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
return tokens.ParseModuleMember(fmt.Sprintf("%s:config:%s", pkg.Name, key))
|
|
|
|
}
|
|
|
|
|
|
|
|
return tokens.ParseModuleMember(key)
|
|
|
|
}
|
|
|
|
|
|
|
|
func prettyKey(key string) string {
|
|
|
|
_, pkg, err := getPackage()
|
|
|
|
if err != nil {
|
|
|
|
return key
|
|
|
|
}
|
|
|
|
|
|
|
|
s := key
|
|
|
|
defaultPrefix := fmt.Sprintf("%s:config:", pkg.Name)
|
|
|
|
|
|
|
|
if strings.HasPrefix(s, defaultPrefix) {
|
|
|
|
return s[len(defaultPrefix):]
|
|
|
|
}
|
|
|
|
|
|
|
|
return s
|
|
|
|
}
|
|
|
|
|
2017-10-16 21:04:35 +02:00
|
|
|
func listConfig(stackName tokens.QName) error {
|
|
|
|
config, err := getConfiguration(stackName)
|
2017-10-02 22:35:39 +02:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if config != nil {
|
|
|
|
fmt.Printf("%-32s %-32s\n", "KEY", "VALUE")
|
|
|
|
var keys []string
|
|
|
|
for key := range config {
|
2017-10-17 01:01:34 +02:00
|
|
|
// Note that we use the fully qualified module member here instead of a `prettyKey`, this lets us ensure that all the config
|
|
|
|
// values for the current program are displayed next to one another in the output.
|
2017-10-02 22:35:39 +02:00
|
|
|
keys = append(keys, string(key))
|
|
|
|
}
|
|
|
|
sort.Strings(keys)
|
|
|
|
for _, key := range keys {
|
2017-10-17 01:01:34 +02:00
|
|
|
fmt.Printf("%-32s %-32s\n", prettyKey(key), config[tokens.ModuleMember(key)])
|
2017-10-02 22:35:39 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2017-10-16 21:04:35 +02:00
|
|
|
func getConfig(stackName tokens.QName, key tokens.ModuleMember) error {
|
|
|
|
config, err := getConfiguration(stackName)
|
2017-10-02 22:35:39 +02:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if config != nil {
|
|
|
|
if v, ok := config[key]; ok {
|
|
|
|
fmt.Printf("%v\n", v)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-17 01:01:34 +02:00
|
|
|
return errors.Errorf("configuration key '%v' not found for stack '%v'", prettyKey(key.String()), stackName)
|
2017-10-10 02:09:32 +02:00
|
|
|
}
|
|
|
|
|
2017-10-16 21:04:35 +02:00
|
|
|
func getConfiguration(stackName tokens.QName) (map[tokens.ModuleMember]string, error) {
|
|
|
|
target, _, err := getStack(stackName)
|
2017-10-10 02:09:32 +02:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2017-10-02 22:35:39 +02:00
|
|
|
|
2017-10-10 02:09:32 +02:00
|
|
|
contract.Assert(target != nil)
|
|
|
|
return target.Config, nil
|
2017-10-02 22:35:39 +02:00
|
|
|
}
|
2017-10-10 02:14:21 +02:00
|
|
|
|
2017-10-16 21:04:35 +02:00
|
|
|
func deleteConfiguration(stackName tokens.QName, key tokens.ModuleMember) error {
|
|
|
|
target, snapshot, err := getStack(stackName)
|
2017-10-10 02:14:21 +02:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
contract.Assert(target != nil)
|
|
|
|
|
|
|
|
if target.Config != nil {
|
|
|
|
delete(target.Config, key)
|
|
|
|
}
|
|
|
|
|
2017-10-16 21:04:35 +02:00
|
|
|
return saveStack(target, snapshot)
|
2017-10-10 02:14:21 +02:00
|
|
|
}
|
2017-10-10 02:25:44 +02:00
|
|
|
|
2017-10-16 21:04:35 +02:00
|
|
|
func setConfiguration(stackName tokens.QName, key tokens.ModuleMember, value string) error {
|
|
|
|
target, snapshot, err := getStack(stackName)
|
2017-10-10 02:25:44 +02:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
contract.Assert(target != nil)
|
|
|
|
|
|
|
|
if target.Config == nil {
|
|
|
|
target.Config = make(map[tokens.ModuleMember]string)
|
|
|
|
}
|
|
|
|
|
|
|
|
target.Config[key] = value
|
|
|
|
|
2017-10-16 21:04:35 +02:00
|
|
|
return saveStack(target, snapshot)
|
2017-10-10 02:25:44 +02:00
|
|
|
}
|