<commit_before>// Copyright 2016 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.
package model

import (
	"bytes"
	"io"
	"sort"
	"strings"

	"gopkg.in/juju/names.v2"

	"github.com/juju/cmd"
	"github.com/juju/errors"
	"github.com/juju/gnuflag"
	"github.com/juju/utils/keyvalues"

	"github.com/juju/juju/api"
	"github.com/juju/juju/api/base"
	cloudapi "github.com/juju/juju/api/cloud"
	"github.com/juju/juju/api/modelmanager"
	jujucloud "github.com/juju/juju/cloud"
	"github.com/juju/juju/cmd/juju/block"
	"github.com/juju/juju/cmd/modelcmd"
	"github.com/juju/juju/cmd/output"
	"github.com/juju/juju/environs/config"
)

const (
	modelDefaultsSummary = `Displays or sets default configuration settings for a model.`
	modelDefaultsHelpDoc = `
By default, all default configuration (keys and values) are
displayed if a key is not specified. Supplying key=value will set the
supplied key to the supplied value. This can be repeated for multiple keys.
By default, the model is the current model.


Examples:
    juju model-defaults
    juju model-defaults http-proxy
    juju model-defaults -m mymodel type
    juju model-defaults ftp-proxy=10.0.0.1:8000
    juju model-defaults -m othercontroller:mymodel default-series=yakkety test-mode=false
    juju model-defaults --reset default-series test-mode

See also:
    models
    model-config
`
)

// NewDefaultsCommand wraps defaultsCommand with sane model settings.
func NewDefaultsCommand() cmd.Command {
	defaultsCmd := &defaultsCommand{
		newCloudAPI: func(caller base.APICallCloser) cloudAPI {
			return cloudapi.NewClient(caller)
		},
		newDefaultsAPI: func(caller base.APICallCloser) defaultsCommandAPI {
			return modelmanager.NewClient(caller)
		},
	}
	defaultsCmd.newAPIRoot = defaultsCmd.NewAPIRoot
	return modelcmd.WrapController(defaultsCmd)
}

// defaultsCommand is compound command for accessing and setting attributes
// related to default model configuration.
type defaultsCommand struct {
	out cmd.Output
	modelcmd.ControllerCommandBase

	newAPIRoot     func() (api.Connection, error)
	newDefaultsAPI func(base.APICallCloser) defaultsCommandAPI
	newCloudAPI    func(base.APICallCloser) cloudAPI

	action                func(defaultsCommandAPI, *cmd.Context) error // The function handling the input, set in Init.
	key                   string
	resetKeys             []string // Holds the keys to be reset once parsed.
	cloudName, regionName string
	reset                 []string // Holds the keys to be reset until parsed.
	values                attributes
}

// cloudAPI defines an API to be passed in for testing.
type cloudAPI interface {
	Close() error
	DefaultCloud() (names.CloudTag, error)
	Cloud(names.CloudTag) (jujucloud.Cloud, error)
}

// defaultsCommandAPI defines an API to be used during testing.
type defaultsCommandAPI interface {
	// Close closes the api connection.
	Close() error

	// ModelDefaults returns the default config values used when creating a new model.
	ModelDefaults() (config.ModelDefaultAttributes, error)

	// SetModelDefaults sets the default config values to use
	// when creating new models.
	SetModelDefaults(cloud, region string, config map[string]interface{}) error

	// UnsetModelDefaults clears the default model
	// configuration values.
	UnsetModelDefaults(cloud, region string, keys ...string) error
}

// Info implements part of the cmd.Command interface.
func (c *defaultsCommand) Info() *cmd.Info {
	return &cmd.Info{
		Args:    "[<model-key>[<=value>] ...]",
		Doc:     modelDefaultsHelpDoc,
		Name:    "model-defaults",
		Purpose: modelDefaultsSummary,
	}
}

// SetFlags implements part of the cmd.Command interface.
func (c *defaultsCommand) SetFlags(f *gnuflag.FlagSet) {
	c.ControllerCommandBase.SetFlags(f)

	c.out.AddFlags(f, "tabular", map[string]cmd.Formatter{
		"yaml":    cmd.FormatYaml,
		"json":    cmd.FormatJson,
		"tabular": formatDefaultConfigTabular,
	})
	f.Var(cmd.NewAppendStringsValue(&c.reset), "reset", "Reset the provided keys")
}

// Init implements part of the cmd.Command interface.
// This needs to parse a command line invocation to reset and set, or get
// model-default values. The arguments may be interspersed as demosntrated in
// the examples.
//
// This sets foo=baz and unsets bar in aws/us-east-1
//     juju model-defaults aws/us-east-1 foo=baz --reset bar
//
// If aws is the cloud of the current or specified controller -- specified by
// -c somecontroller -- then the following would also be equivalent.
//     juju model-defaults --reset bar us-east-1 foo=baz
//
// If one doesn't specify a cloud or region the command is still valid but for
// setting the default on the controller:
//     juju model-defaults foo=baz --reset bar
//
// Of course one can specify multiple keys to reset --reset a,b,c and one can<commit_msg>Update signature with cloud region & --reset desc<commit_after>// Copyright 2016 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.
package model

import (
	"bytes"
	"io"
	"sort"
	"strings"

	"gopkg.in/juju/names.v2"

	"github.com/juju/cmd"
	"github.com/juju/errors"
	"github.com/juju/gnuflag"
	"github.com/juju/utils/keyvalues"

	"github.com/juju/juju/api"
	"github.com/juju/juju/api/base"
	cloudapi "github.com/juju/juju/api/cloud"
	"github.com/juju/juju/api/modelmanager"
	jujucloud "github.com/juju/juju/cloud"
	"github.com/juju/juju/cmd/juju/block"
	"github.com/juju/juju/cmd/modelcmd"
	"github.com/juju/juju/cmd/output"
	"github.com/juju/juju/environs/config"
)

const (
	modelDefaultsSummary = `Displays or sets default configuration settings for a model.`
	modelDefaultsHelpDoc = `
By default, all default configuration (keys and values) are
displayed if a key is not specified. Supplying key=value will set the
supplied key to the supplied value. This can be repeated for multiple keys.
By default, the model is the current model.


Examples:
    juju model-defaults
    juju model-defaults http-proxy
    juju model-defaults -m mymodel type
    juju model-defaults ftp-proxy=10.0.0.1:8000
    juju model-defaults -m othercontroller:mymodel default-series=yakkety test-mode=false
    juju model-defaults --reset default-series test-mode

See also:
    models
    model-config
`
)

// NewDefaultsCommand wraps defaultsCommand with sane model settings.
func NewDefaultsCommand() cmd.Command {
	defaultsCmd := &defaultsCommand{
		newCloudAPI: func(caller base.APICallCloser) cloudAPI {
			return cloudapi.NewClient(caller)
		},
		newDefaultsAPI: func(caller base.APICallCloser) defaultsCommandAPI {
			return modelmanager.NewClient(caller)
		},
	}
	defaultsCmd.newAPIRoot = defaultsCmd.NewAPIRoot
	return modelcmd.WrapController(defaultsCmd)
}

// defaultsCommand is compound command for accessing and setting attributes
// related to default model configuration.
type defaultsCommand struct {
	out cmd.Output
	modelcmd.ControllerCommandBase

	newAPIRoot     func() (api.Connection, error)
	newDefaultsAPI func(base.APICallCloser) defaultsCommandAPI
	newCloudAPI    func(base.APICallCloser) cloudAPI

	action                func(defaultsCommandAPI, *cmd.Context) error // The function handling the input, set in Init.
	key                   string
	resetKeys             []string // Holds the keys to be reset once parsed.
	cloudName, regionName string
	reset                 []string // Holds the keys to be reset until parsed.
	values                attributes
}

// cloudAPI defines an API to be passed in for testing.
type cloudAPI interface {
	Close() error
	DefaultCloud() (names.CloudTag, error)
	Cloud(names.CloudTag) (jujucloud.Cloud, error)
}

// defaultsCommandAPI defines an API to be used during testing.
type defaultsCommandAPI interface {
	// Close closes the api connection.
	Close() error

	// ModelDefaults returns the default config values used when creating a new model.
	ModelDefaults() (config.ModelDefaultAttributes, error)

	// SetModelDefaults sets the default config values to use
	// when creating new models.
	SetModelDefaults(cloud, region string, config map[string]interface{}) error

	// UnsetModelDefaults clears the default model
	// configuration values.
	UnsetModelDefaults(cloud, region string, keys ...string) error
}

// Info implements part of the cmd.Command interface.
func (c *defaultsCommand) Info() *cmd.Info {
	return &cmd.Info{
		Args:    "[[<cloud/>]<region> ]<model-key>[<=value>] ...]",
		Doc:     modelDefaultsHelpDoc,
		Name:    "model-defaults",
		Purpose: modelDefaultsSummary,
	}
}

// SetFlags implements part of the cmd.Command interface.
func (c *defaultsCommand) SetFlags(f *gnuflag.FlagSet) {
	c.ControllerCommandBase.SetFlags(f)

	c.out.AddFlags(f, "tabular", map[string]cmd.Formatter{
		"yaml":    cmd.FormatYaml,
		"json":    cmd.FormatJson,
		"tabular": formatDefaultConfigTabular,
	})
	f.Var(cmd.NewAppendStringsValue(&c.reset), "reset", "Reset the provided comma delimited keys")
}

// Init implements part of the cmd.Command interface.
// This needs to parse a command line invocation to reset and set, or get
// model-default values. The arguments may be interspersed as demosntrated in
// the examples.
//
// This sets foo=baz and unsets bar in aws/us-east-1
//     juju model-defaults aws/us-east-1 foo=baz --reset bar
//
// If aws is the cloud of the current or specified controller -- specified by
// -c somecontroller -- then the following would also be equivalent.
//     juju model-defaults --reset bar us-east-1 foo=baz
//
// If one doesn't specify a cloud or region the command is still valid but for
// setting the default on the controller:
//     juju model-defaults foo=baz --reset bar
//
// Of course one can specify multiple keys to reset --reset a,b,c and one can
{'fraction_non_alphanumeric': 0.09865702479338843, 'fraction_numerical': 0.00371900826446281, 'mean_word_length': 3.7086575875486383, 'pattern_counts': {'":': 6, '<': 9, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 2, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2626487', 'n_tokens_mistral': 3107, 'n_tokens_neox': 2929, 'n_words': 944}