<commit_before>package main

import (
	"bytes"
	"encoding/base64"
	"fmt"
	"os"
	"path"
	"path/filepath"

	context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
	cmds "github.com/jbenet/go-ipfs/commands"
	core "github.com/jbenet/go-ipfs/core"
	corecmds "github.com/jbenet/go-ipfs/core/commands"
	imp "github.com/jbenet/go-ipfs/importer"
	chunk "github.com/jbenet/go-ipfs/importer/chunk"
	ci "github.com/jbenet/go-ipfs/p2p/crypto"
	peer "github.com/jbenet/go-ipfs/p2p/peer"
	repo "github.com/jbenet/go-ipfs/repo"
	config "github.com/jbenet/go-ipfs/repo/config"
	"github.com/jbenet/go-ipfs/repo/fsrepo"
	u "github.com/jbenet/go-ipfs/util"
	debugerror "github.com/jbenet/go-ipfs/util/debugerror"
)

const nBitsForKeypairDefault = 4096

var initCmd = &cmds.Command{
	Helptext: cmds.HelpText{
		Tagline:          "Initializes IPFS config file",
		ShortDescription: "Initializes IPFS configuration files and generates a new keypair.",
	},

	Options: []cmds.Option{
		cmds.IntOption("bits", "b", "Number of bits to use in the generated RSA private key (defaults to 4096)"),
		cmds.StringOption("passphrase", "p", "Passphrase for encrypting the private key"),
		cmds.BoolOption("force", "f", "Overwrite existing config (if it exists)"),
		cmds.StringOption("datastore", "d", "Location for the IPFS data store"),

		// TODO need to decide whether to expose the override as a file or a
		// directory. That is: should we allow the user to also specify the
		// name of the file?
		// TODO cmds.StringOption("event-logs", "l", "Location for machine-readable event logs"),
	},
	Run: func(req cmds.Request) (interface{}, error) {

		dspathOverride, _, err := req.Option("d").String() // if !found it's okay. Let == ""
		if err != nil {
			return nil, err
		}

		force, _, err := req.Option("f").Bool() // if !found, it's okay force == false
		if err != nil {
			return nil, err
		}

		nBitsForKeypair, bitsOptFound, err := req.Option("b").Int()
		if err != nil {
			return nil, err
		}
		if !bitsOptFound {
			nBitsForKeypair = nBitsForKeypairDefault
		}

		return doInit(req.Context().ConfigRoot, dspathOverride, force, nBitsForKeypair)
	},
}

var errCannotInitConfigExists = debugerror.New(`ipfs configuration file already exists!
Reinitializing would overwrite your keys.
(use -f to force overwrite)
`)

var welcomeMsg = `Hello and Welcome to IPFS!

██╗██████╗ ███████╗███████╗
██║██╔══██╗██╔════╝██╔════╝
██║██████╔╝█████╗  ███████╗
██║██╔═══╝ ██╔══╝  ╚════██║
██║██║     ██║     ███████║
╚═╝╚═╝     ╚═╝     ╚══════╝

If you're seeing this, you have successfully installed
IPFS and are now interfacing with the ipfs merkledag!

For a short demo of what you can do, enter 'ipfs tour'
`

func initWithDefaults(configRoot string) error {
	_, err := doInit(configRoot, "", false, nBitsForKeypairDefault)
	return debugerror.Wrap(err)
}

func doInit(configRoot string, dspathOverride string, force bool, nBitsForKeypair int) (interface{}, error) {

	u.POut("initializing ipfs node at %s\n", configRoot)

	configFilename, err := config.Filename(configRoot)
	if err != nil {
		return nil, debugerror.New("Couldn't get home directory path")
	}

	if fsrepo.ConfigIsInitialized(configRoot) && !force {
		return nil, errCannotInitConfigExists
	}

	conf, err := initConfig(configFilename, dspathOverride, nBitsForKeypair)
	if err != nil {
		return nil, err
	}

	err = addTheWelcomeFile(conf)
	if err != nil {
		return nil, err
	}

	return nil, nil
}

// addTheWelcomeFile adds a file containing the welcome message to the newly
// minted node. On success, it calls onSuccess
func addTheWelcomeFile(conf *config.Config) error {
	// TODO extract this file creation operation into a function
	ctx, cancel := context.WithCancel(context.Background())
	nd, err := core.NewIPFSNode(ctx, core.Offline(conf))
	if err != nil {
		return err
	}
	defer nd.Close()
	defer cancel()

	// Set up default file
	reader := bytes.NewBufferString(welcomeMsg)

	defnd, err := imp.BuildDagFromReader(reader, nd.DAG, nd.Pinning.GetManual(), chunk.DefaultSplitter)
	if err != nil {
		return err
	}

	k, err := defnd.Key()
	if err != nil {
		return fmt.Errorf("failed to write test file: %s", err)
	}
	fmt.Printf("\nto get started, enter: ipfs cat %s\n", k)
	return nil
}

func datastoreConfig(dspath string) (config.Datastore, error) {
	ds := config.Datastore{}
	if len(dspath) == 0 {
		var err error
		dspath, err = config.DataStorePath("")
		if err != nil {
			return ds, err
		}
	}
	ds.Path = dspath
	ds.Type = "leveldb"

	err := initCheckDir(dspath)
	if err != nil {
		return ds, debugerror.Errorf("datastore: %s", err)
	}

	return ds, nil
}

func initConfig(configFilename string, dspathOverride string, nBitsForKeypair int) (*config.Config, error) {
	ds, err := datastoreConfig(dspathOverride)
	if err != nil {
		return nil, err
	}

	identity, err := identityConfig(nBitsForKeypair)
	if err != nil {
		return nil, err
	}

	logConfig, err := initLogs("") // TODO allow user to override dir
	if err != nil {
		return nil, err
	}

	bootstrapPeers, err := corecmds.DefaultBootstrapPeers()
	if err != nil {
		return nil, err
	}

	conf := &config.Config{

		// setup the node's default addresses.
		// Note: two swarm listen addrs, one tcp, one utp.
		Addresses: config.Addresses{
			Swarm: []string{
				"/ip4/0.0.0.0/tcp/4001",
				// "/ip4/0.0.0.0/udp/4002/utp", // disabled for now.
			},
			API: "/ip4/127.0.0.1/tcp/5001",
		},

		Bootstrap: bootstrapPeers,
		Datastore: ds,
		Logs:      logConfig,
		Identity:  identity,

		// setup the node mount points.
		Mounts: config.Mounts{
			IPFS: "/ipfs",
			IPNS: "/ipns",
		},

		// tracking ipfs version used to generate the init folder and adding
		// update checker default setting.
		Version: config.VersionDefaultValue(),
	}

	if err := config.WriteConfigFile(configFilename, conf); err != nil {
		return nil, err
	}

	return conf, nil
}

// identityConfig initializes a new identity.
func identityConfig(nbits int) (config.Identity, error) {
	// TODO guard higher up
	ident := config.Identity{}
	if nbits < 1024 {
		return ident, debugerror.New("Bitsize less than 1024 is considered unsafe.")
	}

	fmt.Printf("generating key pair...")
	sk, pk, err := ci.GenerateKeyPair(ci.RSA, nbits)
	if err != nil {
		return ident, err
	}
	fmt.Printf("done\n")

	// currently storing key unencrypted. in the future we need to encrypt it.
	// TODO(security)
	skbytes, err := sk.Bytes()
	if err != nil {
		return ident, err
	}
	ident.PrivKey = base64.StdEncoding.EncodeToString(skbytes)

	id, err := peer.IDFromPublicKey(pk)
	if err != nil {
		return ident, err
	}
	ident.PeerID = id.Pretty()
	fmt.Printf("peer identity: %s\n", ident.PeerID)
	return ident, nil
}

// initLogs initializes the event logger at the specified path. It uses the
// default log path if no path is provided.
func initLogs(logpath string) (config.Logs, error) {
	if len(logpath) == 0 {
		var err error
		logpath, err = config.LogsPath("")
		if err != nil {
			return config.Logs{}, debugerror.Wrap(err)
		}
	}
	err := initCheckDir(logpath)
	if err != nil {
		return config.Logs{}, debugerror.Errorf("logs: %s", err)
	}
	conf := config.Logs{
		Filename: path.Join(logpath, "events.log"),
	}
	err = repo.ConfigureEventLogger(conf)
	if err != nil {
		return conf, err
	}
	return conf, nil
}

// initCheckDir ensures the directory exists and is writable
func initCheckDir(path string) error {
	// Construct the path if missing
	if err := os.MkdirAll(path, os.ModePerm); err != nil {
		return err
	}

	// Check the directory is writeable
	if f, err := os.Create(filepath.Join(path, "._check_writeable")); err == nil {
		os.Remove(f.Name())
	} else {
		return debugerror.New("'" + path + "' is not writeable")
	}
	return nil
}
<commit_msg>refactor(init): write config at top level<commit_after>package main

import (
	"bytes"
	"encoding/base64"
	"fmt"
	"os"
	"path"
	"path/filepath"

	context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
	cmds "github.com/jbenet/go-ipfs/commands"
	core "github.com/jbenet/go-ipfs/core"
	corecmds "github.com/jbenet/go-ipfs/core/commands"
	imp "github.com/jbenet/go-ipfs/importer"
	chunk "github.com/jbenet/go-ipfs/importer/chunk"
	ci "github.com/jbenet/go-ipfs/p2p/crypto"
	peer "github.com/jbenet/go-ipfs/p2p/peer"
	repo "github.com/jbenet/go-ipfs/repo"
	config "github.com/jbenet/go-ipfs/repo/config"
	"github.com/jbenet/go-ipfs/repo/fsrepo"
	u "github.com/jbenet/go-ipfs/util"
	debugerror "github.com/jbenet/go-ipfs/util/debugerror"
)

const nBitsForKeypairDefault = 4096

var initCmd = &cmds.Command{
	Helptext: cmds.HelpText{
		Tagline:          "Initializes IPFS config file",
		ShortDescription: "Initializes IPFS configuration files and generates a new keypair.",
	},

	Options: []cmds.Option{
		cmds.IntOption("bits", "b", "Number of bits to use in the generated RSA private key (defaults to 4096)"),
		cmds.StringOption("passphrase", "p", "Passphrase for encrypting the private key"),
		cmds.BoolOption("force", "f", "Overwrite existing config (if it exists)"),
		cmds.StringOption("datastore", "d", "Location for the IPFS data store"),

		// TODO need to decide whether to expose the override as a file or a
		// directory. That is: should we allow the user to also specify the
		// name of the file?
		// TODO cmds.StringOption("event-logs", "l", "Location for machine-readable event logs"),
	},
	Run: func(req cmds.Request) (interface{}, error) {

		dspathOverride, _, err := req.Option("d").String() // if !found it's okay. Let == ""
		if err != nil {
			return nil, err
		}

		force, _, err := req.Option("f").Bool() // if !found, it's okay force == false
		if err != nil {
			return nil, err
		}

		nBitsForKeypair, bitsOptFound, err := req.Option("b").Int()
		if err != nil {
			return nil, err
		}
		if !bitsOptFound {
			nBitsForKeypair = nBitsForKeypairDefault
		}

		return doInit(req.Context().ConfigRoot, dspathOverride, force, nBitsForKeypair)
	},
}

var errCannotInitConfigExists = debugerror.New(`ipfs configuration file already exists!
Reinitializing would overwrite your keys.
(use -f to force overwrite)
`)

var welcomeMsg = `Hello and Welcome to IPFS!

██╗██████╗ ███████╗███████╗
██║██╔══██╗██╔════╝██╔════╝
██║██████╔╝█████╗  ███████╗
██║██╔═══╝ ██╔══╝  ╚════██║
██║██║     ██║     ███████║
╚═╝╚═╝     ╚═╝     ╚══════╝

If you're seeing this, you have successfully installed
IPFS and are now interfacing with the ipfs merkledag!

For a short demo of what you can do, enter 'ipfs tour'
`

func initWithDefaults(configRoot string) error {
	_, err := doInit(configRoot, "", false, nBitsForKeypairDefault)
	return debugerror.Wrap(err)
}

func doInit(configRoot string, dspathOverride string, force bool, nBitsForKeypair int) (interface{}, error) {

	u.POut("initializing ipfs node at %s\n", configRoot)

	configFilename, err := config.Filename(configRoot)
	if err != nil {
		return nil, debugerror.New("Couldn't get home directory path")
	}

	if fsrepo.ConfigIsInitialized(configRoot) && !force {
		return nil, errCannotInitConfigExists
	}

	conf, err := initConfig(dspathOverride, nBitsForKeypair)
	if err != nil {
		return nil, err
	}

	if err := config.WriteConfigFile(configFilename, conf); err != nil {
		return nil, err
	}

	err = addTheWelcomeFile(conf)
	if err != nil {
		return nil, err
	}

	return nil, nil
}

// addTheWelcomeFile adds a file containing the welcome message to the newly
// minted node. On success, it calls onSuccess
func addTheWelcomeFile(conf *config.Config) error {
	// TODO extract this file creation operation into a function
	ctx, cancel := context.WithCancel(context.Background())
	nd, err := core.NewIPFSNode(ctx, core.Offline(conf))
	if err != nil {
		return err
	}
	defer nd.Close()
	defer cancel()

	// Set up default file
	reader := bytes.NewBufferString(welcomeMsg)

	defnd, err := imp.BuildDagFromReader(reader, nd.DAG, nd.Pinning.GetManual(), chunk.DefaultSplitter)
	if err != nil {
		return err
	}

	k, err := defnd.Key()
	if err != nil {
		return fmt.Errorf("failed to write test file: %s", err)
	}
	fmt.Printf("\nto get started, enter: ipfs cat %s\n", k)
	return nil
}

func datastoreConfig(dspath string) (config.Datastore, error) {
	ds := config.Datastore{}
	if len(dspath) == 0 {
		var err error
		dspath, err = config.DataStorePath("")
		if err != nil {
			return ds, err
		}
	}
	ds.Path = dspath
	ds.Type = "leveldb"

	err := initCheckDir(dspath)
	if err != nil {
		return ds, debugerror.Errorf("datastore: %s", err)
	}

	return ds, nil
}

func initConfig(dspathOverride string, nBitsForKeypair int) (*config.Config, error) {
	ds, err := datastoreConfig(dspathOverride)
	if err != nil {
		return nil, err
	}

	identity, err := identityConfig(nBitsForKeypair)
	if err != nil {
		return nil, err
	}

	logConfig, err := initLogs("") // TODO allow user to override dir
	if err != nil {
		return nil, err
	}

	bootstrapPeers, err := corecmds.DefaultBootstrapPeers()
	if err != nil {
		return nil, err
	}

	conf := &config.Config{

		// setup the node's default addresses.
		// Note: two swarm listen addrs, one tcp, one utp.
		Addresses: config.Addresses{
			Swarm: []string{
				"/ip4/0.0.0.0/tcp/4001",
				// "/ip4/0.0.0.0/udp/4002/utp", // disabled for now.
			},
			API: "/ip4/127.0.0.1/tcp/5001",
		},

		Bootstrap: bootstrapPeers,
		Datastore: ds,
		Logs:      logConfig,
		Identity:  identity,

		// setup the node mount points.
		Mounts: config.Mounts{
			IPFS: "/ipfs",
			IPNS: "/ipns",
		},

		// tracking ipfs version used to generate the init folder and adding
		// update checker default setting.
		Version: config.VersionDefaultValue(),
	}

	return conf, nil
}

// identityConfig initializes a new identity.
func identityConfig(nbits int) (config.Identity, error) {
	// TODO guard higher up
	ident := config.Identity{}
	if nbits < 1024 {
		return ident, debugerror.New("Bitsize less than 1024 is considered unsafe.")
	}

	fmt.Printf("generating key pair...")
	sk, pk, err := ci.GenerateKeyPair(ci.RSA, nbits)
	if err != nil {
		return ident, err
	}
	fmt.Printf("done\n")

	// currently storing key unencrypted. in the future we need to encrypt it.
	// TODO(security)
	skbytes, err := sk.Bytes()
	if err != nil {
		return ident, err
	}
	ident.PrivKey = base64.StdEncoding.EncodeToString(skbytes)

	id, err := peer.IDFromPublicKey(pk)
	if err != nil {
		return ident, err
	}
	ident.PeerID = id.Pretty()
	fmt.Printf("peer identity: %s\n", ident.PeerID)
	return ident, nil
}

// initLogs initializes the event logger at the specified path. It uses the
// default log path if no path is provided.
func initLogs(logpath string) (config.Logs, error) {
	if len(logpath) == 0 {
		var err error
		logpath, err = config.LogsPath("")
		if err != nil {
			return config.Logs{}, debugerror.Wrap(err)
		}
	}
	err := initCheckDir(logpath)
	if err != nil {
		return config.Logs{}, debugerror.Errorf("logs: %s", err)
	}
	conf := config.Logs{
		Filename: path.Join(logpath, "events.log"),
	}
	err = repo.ConfigureEventLogger(conf)
	if err != nil {
		return conf, err
	}
	return conf, nil
}

// initCheckDir ensures the directory exists and is writable
func initCheckDir(path string) error {
	// Construct the path if missing
	if err := os.MkdirAll(path, os.ModePerm); err != nil {
		return err
	}

	// Check the directory is writeable
	if f, err := os.Create(filepath.Join(path, "._check_writeable")); err == nil {
		os.Remove(f.Name())
	} else {
		return debugerror.New("'" + path + "' is not writeable")
	}
	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	"bytes"
	goflag "flag"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"strings"

	"github.com/spf13/cobra"
	"github.com/spf13/viper"
	"k8s.io/apimachinery/pkg/util/validation/field"
	"k8s.io/client-go/tools/clientcmd"
	"k8s.io/client-go/util/homedir"
	"k8s.io/klog"
	"k8s.io/kops/cmd/kops/util"
	kopsapi "k8s.io/kops/pkg/apis/kops"
	"k8s.io/kops/pkg/client/simple"
	"k8s.io/kops/pkg/kubeconfig"
	"k8s.io/kops/upup/pkg/kutil"
	"k8s.io/kubernetes/pkg/kubectl/util/i18n"
	"k8s.io/kubernetes/pkg/kubectl/util/templates"
)

const (
	validResources = `

	* cluster
	* instancegroup
	* secret

	`
)

var (
	rootLong = templates.LongDesc(i18n.T(`
	kops is Kubernetes ops.

	kops is the easiest way to get a production grade Kubernetes cluster up and running.
	We like to think of it as kubectl for clusters.

	kops helps you create, destroy, upgrade and maintain production-grade, highly available,
	Kubernetes clusters from the command line.  AWS (Amazon Web Services) is currently
	officially supported, with GCE and VMware vSphere in alpha support.
	`))

	rootShort = i18n.T(`kops is Kubernetes ops.`)
)

type Factory interface {
	Clientset() (simple.Clientset, error)
}

type RootCmd struct {
	util.FactoryOptions

	factory *util.Factory

	configFile string

	clusterName string

	cobraCommand *cobra.Command
}

var _ Factory = &RootCmd{}

var rootCommand = RootCmd{
	cobraCommand: &cobra.Command{
		Use:   "kops",
		Short: rootShort,
		Long:  rootLong,
	},
}

func Execute() {
	goflag.Set("logtostderr", "true")
	goflag.CommandLine.Parse([]string{})
	if err := rootCommand.cobraCommand.Execute(); err != nil {
		exitWithError(err)
	}
}

func init() {
	cobra.OnInitialize(initConfig)

	klog.InitFlags(nil)

	factory := util.NewFactory(&rootCommand.FactoryOptions)
	rootCommand.factory = factory

	NewCmdRoot(factory, os.Stdout)
}

func NewCmdRoot(f *util.Factory, out io.Writer) *cobra.Command {

	cmd := rootCommand.cobraCommand

	//cmd.PersistentFlags().AddGoFlagSet(goflag.CommandLine)
	goflag.CommandLine.VisitAll(func(goflag *goflag.Flag) {
		switch goflag.Name {
		case "cloud-provider-gce-lb-src-cidrs":
			// Skip; this is dragged in by the google cloudprovider dependency

		default:
			cmd.PersistentFlags().AddGoFlag(goflag)
		}
	})

	cmd.PersistentFlags().StringVar(&rootCommand.configFile, "config", "", "yaml config file (default is $HOME/.kops.yaml)")
	viper.BindPFlag("config", cmd.PersistentFlags().Lookup("config"))
	viper.SetDefault("config", "$HOME/.kops.yaml")

	cmd.PersistentFlags().StringVar(&rootCommand.RegistryPath, "state", "", "Location of state storage (kops 'config' file). Overrides KOPS_STATE_STORE environment variable")
	viper.BindPFlag("KOPS_STATE_STORE", cmd.PersistentFlags().Lookup("state"))
	viper.BindEnv("KOPS_STATE_STORE")

	defaultClusterName := os.Getenv("KOPS_CLUSTER_NAME")
	cmd.PersistentFlags().StringVarP(&rootCommand.clusterName, "name", "", defaultClusterName, "Name of cluster. Overrides KOPS_CLUSTER_NAME environment variable")

	// create subcommands
	cmd.AddCommand(NewCmdCompletion(f, out))
	cmd.AddCommand(NewCmdCreate(f, out))
	cmd.AddCommand(NewCmdDelete(f, out))
	cmd.AddCommand(NewCmdEdit(f, out))
	cmd.AddCommand(NewCmdExport(f, out))
	cmd.AddCommand(NewCmdGet(f, out))
	cmd.AddCommand(NewCmdUpdate(f, out))
	cmd.AddCommand(NewCmdReplace(f, out))
	cmd.AddCommand(NewCmdRollingUpdate(f, out))
	cmd.AddCommand(NewCmdSet(f, out))
	cmd.AddCommand(NewCmdToolbox(f, out))
	cmd.AddCommand(NewCmdValidate(f, out))
	cmd.AddCommand(NewCmdVersion(f, out))

	return cmd
}

// initConfig reads in config file and ENV variables if set.
func initConfig() {
	// Config file precedence: --config flag, ${HOME}/.kops.yaml ${HOME}/.kops/config
	configFile := rootCommand.configFile
	if configFile == "" {
		home := homedir.HomeDir()
		configPaths := []string{
			filepath.Join(home, ".kops.yaml"),
			filepath.Join(home, ".kops", "config"),
		}
		for _, p := range configPaths {
			_, err := os.Stat(p)
			if err == nil {
				configFile = p
				break
			} else if !os.IsNotExist(err) {
				klog.V(2).Infof("error checking for file %s: %v", p, err)
			}
		}
	}

	if configFile != "" {
		viper.SetConfigFile(configFile)
		viper.SetConfigType("yaml")

		if err := viper.ReadInConfig(); err != nil {
			klog.Warningf("error reading config: %v", err)
		}
	}

	rootCommand.RegistryPath = viper.GetString("KOPS_STATE_STORE")

	// Tolerate multiple slashes at end
	rootCommand.RegistryPath = strings.TrimSuffix(rootCommand.RegistryPath, "/")
}

func (c *RootCmd) AddCommand(cmd *cobra.Command) {
	c.cobraCommand.AddCommand(cmd)
}

// ProcessArgs will parse the positional args.  It assumes one of these formats:
//  * <no arguments at all>
//  * <clustername> (and --name not specified)
// Everything else is an error.
func (c *RootCmd) ProcessArgs(args []string) error {
	if len(args) == 0 {
		return nil
	}

	if len(args) == 1 {
		// Assume <clustername>
		if c.clusterName == "" {
			c.clusterName = args[0]
			return nil
		}
	}

	fmt.Printf("\nFound multiple arguments which look like a cluster name\n")
	if c.clusterName != "" {
		fmt.Printf("\t%q (via flag)\n", c.clusterName)
	}
	for _, arg := range args {
		fmt.Printf("\t%q (as argument)\n", arg)
	}
	fmt.Printf("\n")
	fmt.Printf("This often happens if you specify an argument to a boolean flag without using =\n")
	fmt.Printf("For example: use `--bastion=true` or `--bastion`, not `--bastion true`\n\n")

	if len(args) == 1 {
		return fmt.Errorf("Cannot specify cluster via --name and positional argument")
	}
	return fmt.Errorf("expected a single <clustername> to be passed as an argument")
}

func (c *RootCmd) ClusterName() string {
	if c.clusterName != "" {
		return c.clusterName
	}

	c.clusterName = ClusterNameFromKubecfg()

	return c.clusterName
}

func ClusterNameFromKubecfg() string {
	// Read from kubeconfig
	pathOptions := clientcmd.NewDefaultPathOptions()

	clusterName := ""

	config, err := pathOptions.GetStartingConfig()
	if err != nil {
		klog.Warningf("error reading kubecfg: %v", err)
	} else if config.CurrentContext == "" {
		klog.Warningf("no context set in kubecfg")
	} else {
		context := config.Contexts[config.CurrentContext]
		if context == nil {
			klog.Warningf("context %q in kubecfg not found", config.CurrentContext)
		} else if context.Cluster == "" {
			klog.Warningf("context %q in kubecfg did not have a cluster", config.CurrentContext)
		} else {
			fmt.Fprintf(os.Stderr, "Using cluster from kubectl context: %s\n\n", context.Cluster)
			clusterName = context.Cluster
		}
	}

	//config, err := readKubectlClusterConfig()
	//if err != nil {
	//	klog.Warningf("error reading kubecfg: %v", err)
	//} else if config != nil && config.Name != "" {
	//	fmt.Fprintf(os.Stderr, "Using cluster from kubectl context: %s\n\n", config.Name)
	//	c.clusterName = config.Name
	//}

	return clusterName
}

func readKubectlClusterConfig() (*kubeconfig.KubectlClusterWithName, error) {
	kubectl := &kutil.Kubectl{}
	context, err := kubectl.GetCurrentContext()
	if err != nil {
		return nil, fmt.Errorf("error getting current context from kubectl: %v", err)
	}
	klog.V(4).Infof("context = %q", context)

	config, err := kubectl.GetConfig(true)
	if err != nil {
		return nil, fmt.Errorf("error getting current config from kubectl: %v", err)
	}

	// Minify should have done this
	if len(config.Clusters) != 1 {
		return nil, fmt.Errorf("expected exactly one cluster in kubectl config, found %d", len(config.Clusters))
	}

	return config.Clusters[0], nil
}

func (c *RootCmd) Clientset() (simple.Clientset, error) {
	return c.factory.Clientset()
}

func (c *RootCmd) Cluster() (*kopsapi.Cluster, error) {
	clusterName := c.ClusterName()
	if clusterName == "" {
		return nil, fmt.Errorf("--name is required")
	}

	return GetCluster(c.factory, clusterName)
}

func GetCluster(factory Factory, clusterName string) (*kopsapi.Cluster, error) {
	if clusterName == "" {
		return nil, field.Required(field.NewPath("ClusterName"), "Cluster name is required")
	}

	clientset, err := factory.Clientset()
	if err != nil {
		return nil, err
	}

	cluster, err := clientset.GetCluster(clusterName)
	if err != nil {
		return nil, fmt.Errorf("error reading cluster configuration: %v", err)
	}
	if cluster == nil {
		return nil, fmt.Errorf("cluster %q not found", clusterName)
	}

	if clusterName != cluster.ObjectMeta.Name {
		return nil, fmt.Errorf("cluster name did not match expected name: %v vs %v", clusterName, cluster.ObjectMeta.Name)
	}
	return cluster, nil
}

// ConsumeStdin reads all the bytes available from stdin
func ConsumeStdin() ([]byte, error) {
	file := os.Stdin
	buf := new(bytes.Buffer)
	_, err := buf.ReadFrom(file)
	if err != nil {
		return nil, fmt.Errorf("error reading stdin: %v", err)
	}
	return buf.Bytes(), nil
}
<commit_msg>clear whitespace<commit_after>/*
Copyright 2019 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	"bytes"
	goflag "flag"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"strings"

	"github.com/spf13/cobra"
	"github.com/spf13/viper"
	"k8s.io/apimachinery/pkg/util/validation/field"
	"k8s.io/client-go/tools/clientcmd"
	"k8s.io/client-go/util/homedir"
	"k8s.io/klog"
	"k8s.io/kops/cmd/kops/util"
	kopsapi "k8s.io/kops/pkg/apis/kops"
	"k8s.io/kops/pkg/client/simple"
	"k8s.io/kops/pkg/kubeconfig"
	"k8s.io/kops/upup/pkg/kutil"
	"k8s.io/kubernetes/pkg/kubectl/util/i18n"
	"k8s.io/kubernetes/pkg/kubectl/util/templates"
)

const (
	validResources = `

	* cluster
	* instancegroup
	* secret

	`
)

var (
	rootLong = templates.LongDesc(i18n.T(`
	kops is Kubernetes ops.

	kops is the easiest way to get a production grade Kubernetes cluster up and running.
	We like to think of it as kubectl for clusters.

	kops helps you create, destroy, upgrade and maintain production-grade, highly available,
	Kubernetes clusters from the command line. AWS (Amazon Web Services) is currently
	officially supported, with GCE and VMware vSphere in alpha support.
	`))

	rootShort = i18n.T(`kops is Kubernetes ops.`)
)

type Factory interface {
	Clientset() (simple.Clientset, error)
}

type RootCmd struct {
	util.FactoryOptions

	factory *util.Factory

	configFile string

	clusterName string

	cobraCommand *cobra.Command
}

var _ Factory = &RootCmd{}

var rootCommand = RootCmd{
	cobraCommand: &cobra.Command{
		Use:   "kops",
		Short: rootShort,
		Long:  rootLong,
	},
}

func Execute() {
	goflag.Set("logtostderr", "true")
	goflag.CommandLine.Parse([]string{})
	if err := rootCommand.cobraCommand.Execute(); err != nil {
		exitWithError(err)
	}
}

func init() {
	cobra.OnInitialize(initConfig)

	klog.InitFlags(nil)

	factory := util.NewFactory(&rootCommand.FactoryOptions)
	rootCommand.factory = factory

	NewCmdRoot(factory, os.Stdout)
}

func NewCmdRoot(f *util.Factory, out io.Writer) *cobra.Command {

	cmd := rootCommand.cobraCommand

	//cmd.PersistentFlags().AddGoFlagSet(goflag.CommandLine)
	goflag.CommandLine.VisitAll(func(goflag *goflag.Flag) {
		switch goflag.Name {
		case "cloud-provider-gce-lb-src-cidrs":
			// Skip; this is dragged in by the google cloudprovider dependency

		default:
			cmd.PersistentFlags().AddGoFlag(goflag)
		}
	})

	cmd.PersistentFlags().StringVar(&rootCommand.configFile, "config", "", "yaml config file (default is $HOME/.kops.yaml)")
	viper.BindPFlag("config", cmd.PersistentFlags().Lookup("config"))
	viper.SetDefault("config", "$HOME/.kops.yaml")

	cmd.PersistentFlags().StringVar(&rootCommand.RegistryPath, "state", "", "Location of state storage (kops 'config' file). Overrides KOPS_STATE_STORE environment variable")
	viper.BindPFlag("KOPS_STATE_STORE", cmd.PersistentFlags().Lookup("state"))
	viper.BindEnv("KOPS_STATE_STORE")

	defaultClusterName := os.Getenv("KOPS_CLUSTER_NAME")
	cmd.PersistentFlags().StringVarP(&rootCommand.clusterName, "name", "", defaultClusterName, "Name of cluster. Overrides KOPS_CLUSTER_NAME environment variable")

	// create subcommands
	cmd.AddCommand(NewCmdCompletion(f, out))
	cmd.AddCommand(NewCmdCreate(f, out))
	cmd.AddCommand(NewCmdDelete(f, out))
	cmd.AddCommand(NewCmdEdit(f, out))
	cmd.AddCommand(NewCmdExport(f, out))
	cmd.AddCommand(NewCmdGet(f, out))
	cmd.AddCommand(NewCmdUpdate(f, out))
	cmd.AddCommand(NewCmdReplace(f, out))
	cmd.AddCommand(NewCmdRollingUpdate(f, out))
	cmd.AddCommand(NewCmdSet(f, out))
	cmd.AddCommand(NewCmdToolbox(f, out))
	cmd.AddCommand(NewCmdValidate(f, out))
	cmd.AddCommand(NewCmdVersion(f, out))

	return cmd
}

// initConfig reads in config file and ENV variables if set.
func initConfig() {
	// Config file precedence: --config flag, ${HOME}/.kops.yaml ${HOME}/.kops/config
	configFile := rootCommand.configFile
	if configFile == "" {
		home := homedir.HomeDir()
		configPaths := []string{
			filepath.Join(home, ".kops.yaml"),
			filepath.Join(home, ".kops", "config"),
		}
		for _, p := range configPaths {
			_, err := os.Stat(p)
			if err == nil {
				configFile = p
				break
			} else if !os.IsNotExist(err) {
				klog.V(2).Infof("error checking for file %s: %v", p, err)
			}
		}
	}

	if configFile != "" {
		viper.SetConfigFile(configFile)
		viper.SetConfigType("yaml")

		if err := viper.ReadInConfig(); err != nil {
			klog.Warningf("error reading config: %v", err)
		}
	}

	rootCommand.RegistryPath = viper.GetString("KOPS_STATE_STORE")

	// Tolerate multiple slashes at end
	rootCommand.RegistryPath = strings.TrimSuffix(rootCommand.RegistryPath, "/")
}

func (c *RootCmd) AddCommand(cmd *cobra.Command) {
	c.cobraCommand.AddCommand(cmd)
}

// ProcessArgs will parse the positional args.  It assumes one of these formats:
//  * <no arguments at all>
//  * <clustername> (and --name not specified)
// Everything else is an error.
func (c *RootCmd) ProcessArgs(args []string) error {
	if len(args) == 0 {
		return nil
	}

	if len(args) == 1 {
		// Assume <clustername>
		if c.clusterName == "" {
			c.clusterName = args[0]
			return nil
		}
	}

	fmt.Printf("\nFound multiple arguments which look like a cluster name\n")
	if c.clusterName != "" {
		fmt.Printf("\t%q (via flag)\n", c.clusterName)
	}
	for _, arg := range args {
		fmt.Printf("\t%q (as argument)\n", arg)
	}
	fmt.Printf("\n")
	fmt.Printf("This often happens if you specify an argument to a boolean flag without using =\n")
	fmt.Printf("For example: use `--bastion=true` or `--bastion`, not `--bastion true`\n\n")

	if len(args) == 1 {
		return fmt.Errorf("Cannot specify cluster via --name and positional argument")
	}
	return fmt.Errorf("expected a single <clustername> to be passed as an argument")
}

func (c *RootCmd) ClusterName() string {
	if c.clusterName != "" {
		return c.clusterName
	}

	c.clusterName = ClusterNameFromKubecfg()

	return c.clusterName
}

func ClusterNameFromKubecfg() string {
	// Read from kubeconfig
	pathOptions := clientcmd.NewDefaultPathOptions()

	clusterName := ""

	config, err := pathOptions.GetStartingConfig()
	if err != nil {
		klog.Warningf("error reading kubecfg: %v", err)
	} else if config.CurrentContext == "" {
		klog.Warningf("no context set in kubecfg")
	} else {
		context := config.Contexts[config.CurrentContext]
		if context == nil {
			klog.Warningf("context %q in kubecfg not found", config.CurrentContext)
		} else if context.Cluster == "" {
			klog.Warningf("context %q in kubecfg did not have a cluster", config.CurrentContext)
		} else {
			fmt.Fprintf(os.Stderr, "Using cluster from kubectl context: %s\n\n", context.Cluster)
			clusterName = context.Cluster
		}
	}

	//config, err := readKubectlClusterConfig()
	//if err != nil {
	//	klog.Warningf("error reading kubecfg: %v", err)
	//} else if config != nil && config.Name != "" {
	//	fmt.Fprintf(os.Stderr, "Using cluster from kubectl context: %s\n\n", config.Name)
	//	c.clusterName = config.Name
	//}

	return clusterName
}

func readKubectlClusterConfig() (*kubeconfig.KubectlClusterWithName, error) {
	kubectl := &kutil.Kubectl{}
	context, err := kubectl.GetCurrentContext()
	if err != nil {
		return nil, fmt.Errorf("error getting current context from kubectl: %v", err)
	}
	klog.V(4).Infof("context = %q", context)

	config, err := kubectl.GetConfig(true)
	if err != nil {
		return nil, fmt.Errorf("error getting current config from kubectl: %v", err)
	}

	// Minify should have done this
	if len(config.Clusters) != 1 {
		return nil, fmt.Errorf("expected exactly one cluster in kubectl config, found %d", len(config.Clusters))
	}

	return config.Clusters[0], nil
}

func (c *RootCmd) Clientset() (simple.Clientset, error) {
	return c.factory.Clientset()
}

func (c *RootCmd) Cluster() (*kopsapi.Cluster, error) {
	clusterName := c.ClusterName()
	if clusterName == "" {
		return nil, fmt.Errorf("--name is required")
	}

	return GetCluster(c.factory, clusterName)
}

func GetCluster(factory Factory, clusterName string) (*kopsapi.Cluster, error) {
	if clusterName == "" {
		return nil, field.Required(field.NewPath("ClusterName"), "Cluster name is required")
	}

	clientset, err := factory.Clientset()
	if err != nil {
		return nil, err
	}

	cluster, err := clientset.GetCluster(clusterName)
	if err != nil {
		return nil, fmt.Errorf("error reading cluster configuration: %v", err)
	}
	if cluster == nil {
		return nil, fmt.Errorf("cluster %q not found", clusterName)
	}

	if clusterName != cluster.ObjectMeta.Name {
		return nil, fmt.Errorf("cluster name did not match expected name: %v vs %v", clusterName, cluster.ObjectMeta.Name)
	}
	return cluster, nil
}

// ConsumeStdin reads all the bytes available from stdin
func ConsumeStdin() ([]byte, error) {
	file := os.Stdin
	buf := new(bytes.Buffer)
	_, err := buf.ReadFrom(file)
	if err != nil {
		return nil, fmt.Errorf("error reading stdin: %v", err)
	}
	return buf.Bytes(), nil
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"
	"strings"
	"time"

	"github.com/mgutz/ansi"
)

type ResultSet struct {
	name     string
	id       string
	kind     string
	at       time.Time
	vals     map[string]bool
	status   Status
	err      error
	output   string
	children []ResultSet
}

func (rs ResultSet) PrettyPrint(level int, ts bool, vals bool) string {
	ident := strings.Repeat("   ", level)
	out := rs.status.Colorize(fmt.Sprintf("%s%s %s is %v", ident, rs.kind, rs.name, rs.status))

	ident = strings.Repeat("   ", level+1)
	if ts {
		timestamp := rs.at.Format("2006-01-02 15:04:05")
		out += fmt.Sprintf(" (%s)", timestamp)
	}
	if rs.err != nil {
		out += fmt.Sprintf("\n%sError occured: %s", ident, rs.err.Error())
	}
	if rs.status == StatusNOK && rs.output != "" {
		out += fmt.Sprintf("\n%sMessage from Monitoring: %s", ident, rs.output)
	}
	if vals && len(rs.vals) > 0 {
		out += fmt.Sprintf("\n%sValues:", ident)
		for key, value := range rs.vals {
			out += " "
			if !value {
				out += ansi.Color(key, "magenta+s")
			} else {
				out += ansi.Color(key, "green")
			}
		}
	}
	out += "\n"
	for _, childRs := range rs.children {
		out += childRs.PrettyPrint(level+1, ts, vals)
	}
	return out
}

func (rs ResultSet) AsInflux(parentTags map[string]string, saveOK []string) []Point {
	var out []Point

	tags := make(map[string]string)
	for k, v := range parentTags {
		tags[k] = v
	}
	tags[rs.kind] = rs.id

	if rs.status != StatusOK || stringInSlice(rs.kind, saveOK) {
		fields := map[string]interface{}{
			"status": rs.status.toInt(),
		}
		for key, value := range rs.vals {
			fields[key] = value
		}
		if rs.output != "" {
			fields["output"] = fmt.Sprintf("Output: %s", rs.output)
		}
		if rs.err != nil {
			fields["err"] = fmt.Sprintf("Error: %s", rs.err.Error())
		}
		pt := Point{
			Timestamp: rs.at,
			Series:    rs.kind,
			Tags:      tags,
			Fields:    fields,
		}
		out = append(out, pt)
	}

	for _, childRs := range rs.children {
		out = append(out, childRs.AsInflux(tags, saveOK)...)
	}
	return out
}

func stringInSlice(a string, list []string) bool {
	for _, b := range list {
		if strings.ToUpper(b) == strings.ToUpper(a) {
			return true
		}
	}
	return false
}
<commit_msg>sort values for pretty printed output<commit_after>package cmd

import (
	"fmt"
	"sort"
	"strings"
	"time"

	"github.com/mgutz/ansi"
)

type ResultSet struct {
	name     string
	id       string
	kind     string
	at       time.Time
	vals     map[string]bool
	status   Status
	err      error
	output   string
	children []ResultSet
}

func (rs ResultSet) PrettyPrint(level int, ts bool, vals bool) string {
	ident := strings.Repeat("   ", level)
	out := rs.status.Colorize(fmt.Sprintf("%s%s %s is %v", ident, rs.kind, rs.name, rs.status))

	ident = strings.Repeat("   ", level+1)
	if ts {
		timestamp := rs.at.Format("2006-01-02 15:04:05")
		out += fmt.Sprintf(" (%s)", timestamp)
	}
	if rs.err != nil {
		out += fmt.Sprintf("\n%sError occured: %s", ident, rs.err.Error())
	}
	if rs.status == StatusNOK && rs.output != "" {
		out += fmt.Sprintf("\n%sMessage from Monitoring: %s", ident, rs.output)
	}
	if vals && len(rs.vals) > 0 {
		out += fmt.Sprintf("\n%sValues:", ident)
		var keys []string
		for k := range rs.vals {
			keys = append(keys, k)
		}
		sort.Strings(keys)
		for _, key := range keys {
			value := rs.vals[key]
			out += " "
			if !value {
				out += ansi.Color(key, "magenta+s")
			} else {
				out += ansi.Color(key, "green")
			}
		}
	}
	out += "\n"
	for _, childRs := range rs.children {
		out += childRs.PrettyPrint(level+1, ts, vals)
	}
	return out
}

func (rs ResultSet) AsInflux(parentTags map[string]string, saveOK []string) []Point {
	var out []Point

	tags := make(map[string]string)
	for k, v := range parentTags {
		tags[k] = v
	}
	tags[rs.kind] = rs.id

	if rs.status != StatusOK || stringInSlice(rs.kind, saveOK) {
		fields := map[string]interface{}{
			"status": rs.status.toInt(),
		}
		for key, value := range rs.vals {
			fields[key] = value
		}
		if rs.output != "" {
			fields["output"] = fmt.Sprintf("Output: %s", rs.output)
		}
		if rs.err != nil {
			fields["err"] = fmt.Sprintf("Error: %s", rs.err.Error())
		}
		pt := Point{
			Timestamp: rs.at,
			Series:    rs.kind,
			Tags:      tags,
			Fields:    fields,
		}
		out = append(out, pt)
	}

	for _, childRs := range rs.children {
		out = append(out, childRs.AsInflux(tags, saveOK)...)
	}
	return out
}

func stringInSlice(a string, list []string) bool {
	for _, b := range list {
		if strings.ToUpper(b) == strings.ToUpper(a) {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>// Copyright 2017 The kubecfg authors
//
//
//    Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//    See the License for the specific language governing permissions and
//    limitations under the License.

package cmd

import (
	"bytes"
	"encoding/json"
	"os"
	"path/filepath"
	"reflect"
	"testing"

	"gopkg.in/yaml.v2"
)

func cmdOutput(t *testing.T, args []string) string {
	var buf bytes.Buffer
	RootCmd.SetOutput(&buf)
	defer RootCmd.SetOutput(nil)

	t.Log("Running args", args)
	RootCmd.SetArgs(args)
	if err := RootCmd.Execute(); err != nil {
		t.Fatal("command failed:", err)
	}

	return buf.String()
}

func TestShow(t *testing.T) {
	formats := map[string]func(string) (interface{}, error){
		"json": func(text string) (ret interface{}, err error) {
			err = json.Unmarshal([]byte(text), &ret)
			return
		},
		"yaml": func(text string) (ret interface{}, err error) {
			err = yaml.Unmarshal([]byte(text), &ret)
			return
		},
	}

	// Use the fact that JSON is also valid YAML ..
	expected := `
{
  "apiVersion": "v0alpha1",
  "kind": "TestObject",
  "nil": null,
  "bool": true,
  "number": 42,
  "string": "bar",
  "notAVal": "aVal",
  "notAnotherVal": "aVal2",
  "filevar": "foo\n",
  "array": ["one", 2, [3]],
  "object": {"foo": "bar"}
}
`

	for format, parser := range formats {
		expected, err := parser(expected)
		if err != nil {
			t.Fatalf("error parsing *expected* value: %v", err)
		}

		os.Setenv("anVar", "aVal2")
		defer os.Unsetenv("anVar")

		output := cmdOutput(t, []string{"show",
			"-J", filepath.FromSlash("../testdata/lib"),
			"-o", format,
			filepath.FromSlash("../testdata/test.jsonnet"),
			"-V", "aVar=aVal",
			"-V", "anVar",
			"--ext-str-file", "filevar=" + filepath.FromSlash("../testdata/extvar.file"),
		})

		t.Log("output is", output)
		actual, err := parser(output)
		if err != nil {
			t.Errorf("error parsing output of format %s: %v", format, err)
		} else if !reflect.DeepEqual(expected, actual) {
			t.Errorf("format %s expected != actual: %s != %s", format, expected, actual)
		}
	}
}

func TestShowUsingExtVarFiles(t *testing.T) {
	expectedText := `
{
  "apiVersion": "v1",
  "kind": "ConfigMap",
  "metadata": {
    "name": "sink"
  },
  "data": {
    "input": {
      "greeting": "Hello!",
      "helper": true,
      "top": true
    },
    "var": "I'm a var!"
  }
}
`
	var expected interface{}
	if err := json.Unmarshal([]byte(expectedText), &expected); err != nil {
		t.Fatalf("error parsing *expected* value: %v", err)
	}

	cwd, err := os.Getwd()
	if err != nil {
		t.Fatalf("failed to get current working directory: %v", err)
	}
	if err := os.Chdir("../testdata/extvars/feed"); err != nil {
		t.Fatalf("failed to change to target directory: %v", err)
	}
	defer os.Chdir(cwd)

	output := cmdOutput(t, []string{"show",
		"top.jsonnet",
		"-o", "json",
		"--tla-code-file", "input=input.jsonnet",
		"--tla-code-file", "sink=sink.jsonnet",
		"--ext-str-file", "filevar=var.txt",
	})

	t.Log("output is", output)
	var actual interface{}
	err = json.Unmarshal([]byte(output), &actual)
	if err != nil {
		t.Errorf("error parsing output: %v", err)
	} else if !reflect.DeepEqual(expected, actual) {
		t.Errorf("expected != actual: %s != %s", expected, actual)
	}
}
<commit_msg>Reset flags set on RootCmd in "show" test<commit_after>// Copyright 2017 The kubecfg authors
//
//
//    Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//    See the License for the specific language governing permissions and
//    limitations under the License.

package cmd

import (
	"bytes"
	"encoding/json"
	"os"
	"path/filepath"
	"reflect"
	"testing"

	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
	"gopkg.in/yaml.v2"
)

func resetFlagsOf(cmd *cobra.Command) {
	cmd.Flags().VisitAll(func(f *pflag.Flag) {
		if sv, ok := f.Value.(pflag.SliceValue); ok {
			sv.Replace(nil)
		} else {
			f.Value.Set(f.DefValue)
		}
	})
}

func cmdOutput(t *testing.T, args []string) string {
	var buf bytes.Buffer
	RootCmd.SetOutput(&buf)
	defer RootCmd.SetOutput(nil)

	t.Log("Running args", args)
	RootCmd.SetArgs(args)
	if err := RootCmd.Execute(); err != nil {
		t.Fatal("command failed:", err)
	}

	return buf.String()
}

func TestShow(t *testing.T) {
	formats := map[string]func(string) (interface{}, error){
		"json": func(text string) (ret interface{}, err error) {
			err = json.Unmarshal([]byte(text), &ret)
			return
		},
		"yaml": func(text string) (ret interface{}, err error) {
			err = yaml.Unmarshal([]byte(text), &ret)
			return
		},
	}

	// Use the fact that JSON is also valid YAML ..
	expected := `
{
  "apiVersion": "v0alpha1",
  "kind": "TestObject",
  "nil": null,
  "bool": true,
  "number": 42,
  "string": "bar",
  "notAVal": "aVal",
  "notAnotherVal": "aVal2",
  "filevar": "foo\n",
  "array": ["one", 2, [3]],
  "object": {"foo": "bar"}
}
`

	for format, parser := range formats {
		expected, err := parser(expected)
		if err != nil {
			t.Fatalf("error parsing *expected* value: %v", err)
		}

		os.Setenv("anVar", "aVal2")
		defer os.Unsetenv("anVar")

		output := cmdOutput(t, []string{"show",
			"-J", filepath.FromSlash("../testdata/lib"),
			"-o", format,
			filepath.FromSlash("../testdata/test.jsonnet"),
			"-V", "aVar=aVal",
			"-V", "anVar",
			"--ext-str-file", "filevar=" + filepath.FromSlash("../testdata/extvar.file"),
		})
		defer resetFlagsOf(RootCmd)

		t.Log("output is", output)
		actual, err := parser(output)
		if err != nil {
			t.Errorf("error parsing output of format %s: %v", format, err)
		} else if !reflect.DeepEqual(expected, actual) {
			t.Errorf("format %s expected != actual: %s != %s", format, expected, actual)
		}
	}
}

func TestShowUsingExtVarFiles(t *testing.T) {
	expectedText := `
{
  "apiVersion": "v1",
  "kind": "ConfigMap",
  "metadata": {
    "name": "sink"
  },
  "data": {
    "input": {
      "greeting": "Hello!",
      "helper": true,
      "top": true
    },
    "var": "I'm a var!"
  }
}
`
	var expected interface{}
	if err := json.Unmarshal([]byte(expectedText), &expected); err != nil {
		t.Fatalf("error parsing *expected* value: %v", err)
	}

	cwd, err := os.Getwd()
	if err != nil {
		t.Fatalf("failed to get current working directory: %v", err)
	}
	if err := os.Chdir("../testdata/extvars/feed"); err != nil {
		t.Fatalf("failed to change to target directory: %v", err)
	}
	defer os.Chdir(cwd)

	output := cmdOutput(t, []string{"show",
		"top.jsonnet",
		"-o", "json",
		"--tla-code-file", "input=input.jsonnet",
		"--tla-code-file", "sink=sink.jsonnet",
		"--ext-str-file", "filevar=var.txt",
	})
	defer resetFlagsOf(RootCmd)

	t.Log("output is", output)
	var actual interface{}
	err = json.Unmarshal([]byte(output), &actual)
	if err != nil {
		t.Errorf("error parsing output: %v", err)
	} else if !reflect.DeepEqual(expected, actual) {
		t.Errorf("expected != actual: %s != %s", expected, actual)
	}
}
<|endoftext|>


<commit_before>package service

import (
	"context"
	"sync"

	"github.com/micro/go-micro/client"
	"github.com/micro/go-micro/runtime"
	pb "github.com/micro/go-micro/runtime/service/proto"
)

type svc struct {
	sync.RWMutex
	options runtime.Options
	runtime pb.RuntimeService
}

// Init initializes runtime with given options
func (s *svc) Init(opts ...runtime.Option) error {
	s.Lock()
	defer s.Unlock()

	for _, o := range opts {
		o(&s.options)
	}

	return nil
}

// Create registers a service in the runtime
func (s *svc) Create(svc *runtime.Service, opts ...runtime.CreateOption) error {
	options := runtime.CreateOptions{}
	// apply requested options
	for _, o := range opts {
		o(&options)
	}

	// runtime service create request
	req := &pb.CreateRequest{
		Service: &pb.Service{
			Name:     svc.Name,
			Version:  svc.Version,
			Source:   svc.Source,
			Metadata: svc.Metadata,
		},
		Options: &pb.CreateOptions{
			Command: options.Command,
			Env:     options.Env,
		},
	}

	if _, err := s.runtime.Create(context.Background(), req); err != nil {
		return err
	}

	return nil
}

// Read returns the service with the given name from the runtime
func (s *svc) Read(opts ...runtime.ReadOption) ([]*runtime.Service, error) {
	options := runtime.ReadOptions{}
	// apply requested options
	for _, o := range opts {
		o(&options)
	}

	// runtime service create request
	req := &pb.ReadRequest{
		Options: &pb.ReadOptions{
			Service: options.Service,
			Version: options.Version,
			Type:    options.Type,
		},
	}

	resp, err := s.runtime.Read(context.Background(), req)
	if err != nil {
		return nil, err
	}

	services := make([]*runtime.Service, 0, len(resp.Services))
	for _, service := range resp.Services {
		svc := &runtime.Service{
			Name:     service.Name,
			Version:  service.Version,
			Source:   service.Source,
			Metadata: service.Metadata,
		}
		services = append(services, svc)
	}

	return services, nil
}

// Update updates the running service
func (s *svc) Update(svc *runtime.Service) error {
	// runtime service create request
	req := &pb.UpdateRequest{
		Service: &pb.Service{
			Name:    svc.Name,
			Version: svc.Version,
		},
	}

	if _, err := s.runtime.Update(context.Background(), req); err != nil {
		return err
	}

	return nil
}

// Delete stops and removes the service from the runtime
func (s *svc) Delete(svc *runtime.Service) error {
	// runtime service create request
	req := &pb.DeleteRequest{
		Service: &pb.Service{
			Name:    svc.Name,
			Version: svc.Version,
		},
	}

	if _, err := s.runtime.Delete(context.Background(), req); err != nil {
		return err
	}

	return nil
}

// List lists all services managed by the runtime
func (s *svc) List() ([]*runtime.Service, error) {
	// list all services managed by the runtime
	resp, err := s.runtime.List(context.Background(), &pb.ListRequest{})
	if err != nil {
		return nil, err
	}

	services := make([]*runtime.Service, 0, len(resp.Services))
	for _, service := range resp.Services {
		svc := &runtime.Service{
			Name:     service.Name,
			Version:  service.Version,
			Source:   service.Source,
			Metadata: service.Metadata,
		}
		services = append(services, svc)
	}

	return services, nil
}

// Start starts the runtime
func (s *svc) Start() error {
	// NOTE: nothing to be done here
	return nil
}

// Stop stops the runtime
func (s *svc) Stop() error {
	// NOTE: nothing to be done here
	return nil
}

// Returns the runtime service implementation
func (s *svc) String() string {
	return "service"
}

// NewRuntime creates new service runtime and returns it
func NewRuntime(opts ...runtime.Option) runtime.Runtime {
	// get default options
	options := runtime.Options{}

	// apply requested options
	for _, o := range opts {
		o(&options)
	}

	// create default client
	cli := client.DefaultClient

	return &svc{
		options: options,
		runtime: pb.NewRuntimeService(runtime.DefaultName, cli),
	}
}

<commit_msg>go fmt<commit_after>package service

import (
	"context"
	"sync"

	"github.com/micro/go-micro/client"
	"github.com/micro/go-micro/runtime"
	pb "github.com/micro/go-micro/runtime/service/proto"
)

type svc struct {
	sync.RWMutex
	options runtime.Options
	runtime pb.RuntimeService
}

// Init initializes runtime with given options
func (s *svc) Init(opts ...runtime.Option) error {
	s.Lock()
	defer s.Unlock()

	for _, o := range opts {
		o(&s.options)
	}

	return nil
}

// Create registers a service in the runtime
func (s *svc) Create(svc *runtime.Service, opts ...runtime.CreateOption) error {
	options := runtime.CreateOptions{}
	// apply requested options
	for _, o := range opts {
		o(&options)
	}

	// runtime service create request
	req := &pb.CreateRequest{
		Service: &pb.Service{
			Name:     svc.Name,
			Version:  svc.Version,
			Source:   svc.Source,
			Metadata: svc.Metadata,
		},
		Options: &pb.CreateOptions{
			Command: options.Command,
			Env:     options.Env,
		},
	}

	if _, err := s.runtime.Create(context.Background(), req); err != nil {
		return err
	}

	return nil
}

// Read returns the service with the given name from the runtime
func (s *svc) Read(opts ...runtime.ReadOption) ([]*runtime.Service, error) {
	options := runtime.ReadOptions{}
	// apply requested options
	for _, o := range opts {
		o(&options)
	}

	// runtime service create request
	req := &pb.ReadRequest{
		Options: &pb.ReadOptions{
			Service: options.Service,
			Version: options.Version,
			Type:    options.Type,
		},
	}

	resp, err := s.runtime.Read(context.Background(), req)
	if err != nil {
		return nil, err
	}

	services := make([]*runtime.Service, 0, len(resp.Services))
	for _, service := range resp.Services {
		svc := &runtime.Service{
			Name:     service.Name,
			Version:  service.Version,
			Source:   service.Source,
			Metadata: service.Metadata,
		}
		services = append(services, svc)
	}

	return services, nil
}

// Update updates the running service
func (s *svc) Update(svc *runtime.Service) error {
	// runtime service create request
	req := &pb.UpdateRequest{
		Service: &pb.Service{
			Name:    svc.Name,
			Version: svc.Version,
		},
	}

	if _, err := s.runtime.Update(context.Background(), req); err != nil {
		return err
	}

	return nil
}

// Delete stops and removes the service from the runtime
func (s *svc) Delete(svc *runtime.Service) error {
	// runtime service create request
	req := &pb.DeleteRequest{
		Service: &pb.Service{
			Name:    svc.Name,
			Version: svc.Version,
		},
	}

	if _, err := s.runtime.Delete(context.Background(), req); err != nil {
		return err
	}

	return nil
}

// List lists all services managed by the runtime
func (s *svc) List() ([]*runtime.Service, error) {
	// list all services managed by the runtime
	resp, err := s.runtime.List(context.Background(), &pb.ListRequest{})
	if err != nil {
		return nil, err
	}

	services := make([]*runtime.Service, 0, len(resp.Services))
	for _, service := range resp.Services {
		svc := &runtime.Service{
			Name:     service.Name,
			Version:  service.Version,
			Source:   service.Source,
			Metadata: service.Metadata,
		}
		services = append(services, svc)
	}

	return services, nil
}

// Start starts the runtime
func (s *svc) Start() error {
	// NOTE: nothing to be done here
	return nil
}

// Stop stops the runtime
func (s *svc) Stop() error {
	// NOTE: nothing to be done here
	return nil
}

// Returns the runtime service implementation
func (s *svc) String() string {
	return "service"
}

// NewRuntime creates new service runtime and returns it
func NewRuntime(opts ...runtime.Option) runtime.Runtime {
	// get default options
	options := runtime.Options{}

	// apply requested options
	for _, o := range opts {
		o(&options)
	}

	// create default client
	cli := client.DefaultClient

	return &svc{
		options: options,
		runtime: pb.NewRuntimeService(runtime.DefaultName, cli),
	}
}
<|endoftext|>


<commit_before>/**
 * Copyright (C) 2015 Red Hat, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cmds

import (
	"strings"

	"fmt"

	"github.com/fabric8io/gofabric8/client"
	"github.com/fabric8io/gofabric8/util"
	oclient "github.com/openshift/origin/pkg/client"
	"github.com/spf13/cobra"
	"k8s.io/kubernetes/pkg/api"
	k8sclient "k8s.io/kubernetes/pkg/client/unversioned"
	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
	"k8s.io/kubernetes/pkg/labels"
	"k8s.io/kubernetes/pkg/util/sets"
)

type validateFunc func(c *k8sclient.Client, f *cmdutil.Factory) (Result, error)
type oValidateFunc func(c *oclient.Client, f *cmdutil.Factory) (Result, error)

func NewCmdValidate(f *cmdutil.Factory) *cobra.Command {
	cmd := &cobra.Command{
		Use:   "validate",
		Short: "Validate your Kubernetes or OpenShift environment",
		Long:  `validate your Kubernetes or OpenShift environment`,
		PreRun: func(cmd *cobra.Command, args []string) {
			showBanner()
		},
		Run: func(cmd *cobra.Command, args []string) {
			c, cfg := client.NewClient(f)
			ns, _, _ := f.DefaultNamespace()
			util.Info("Validating your ")
			util.Success(string(util.TypeOfMaster(c)))
			util.Info(" installation at ")
			util.Success(cfg.Host)
			util.Info(" in namespace ")
			util.Successf("%s\n\n", ns)
			printValidationResult("Service account", validateServiceAccount, c, f)
			printValidationResult("Console", validateConsoleDeployment, c, f)

			if util.TypeOfMaster(c) == util.Kubernetes {
				printValidationResult("Jenkinshift Service", validateJenkinshiftService, c, f)
			}

			if util.TypeOfMaster(c) == util.OpenShift {
				printValidationResult("Router", validateRouter, c, f)
				oc, _ := client.NewOpenShiftClient(cfg)
				printOValidationResult("Templates", validateTemplates, oc, f)
				printValidationResult("SecurityContextConstraints", validateSecurityContextConstraints, c, f)
			}

			printValidationResult("PersistentVolumeClaims", validatePersistenceVolumeClaims, c, f)
			printValidationResult("ConfigMaps", validateConfigMaps, c, f)
		},
	}

	return cmd
}

func printValidationResult(check string, v validateFunc, c *k8sclient.Client, f *cmdutil.Factory) {
	r, err := v(c, f)
	printResult(check, r, err)
}

func printOValidationResult(check string, v oValidateFunc, c *oclient.Client, f *cmdutil.Factory) {
	r, err := v(c, f)
	printResult(check, r, err)
}

func printError(check string, err error) {
	r := Success
	if err != nil {
		r = Failure
	}
	printResult(check, r, err)
}

func printResult(check string, r Result, err error) {
	if err != nil {
		r = Failure
	}
	padLen := 78 - len(check)
	pad := ""
	if padLen > 0 {
		pad = strings.Repeat(".", padLen)
	}
	util.Infof("%s%s", check, pad)
	if r == Failure {
		util.Failuref("%-2s", r)
	} else {
		util.Successf("%-2s", r)
	}
	if err != nil {
		util.Failuref("%v", err)
	}
	util.Blank()
}

func validateServiceAccount(c *k8sclient.Client, f *cmdutil.Factory) (Result, error) {
	ns, _, err := f.DefaultNamespace()
	if err != nil {
		return Failure, err
	}
	sa, err := c.ServiceAccounts(ns).Get("fabric8")
	if sa != nil {
		return Success, err
	}
	return Failure, err
}

func validateConsoleDeployment(c *k8sclient.Client, f *cmdutil.Factory) (Result, error) {
	ns, _, err := f.DefaultNamespace()
	if err != nil {
		return Failure, err
	}
	rc, err := c.ReplicationControllers(ns).Get("fabric8")
	if rc != nil {
		return Success, err
	}
	return Failure, err
}

func validateProxyServiceRestAPI(c *k8sclient.Client, f *cmdutil.Factory, host string) (Result, error) {
	ns, _, err := f.DefaultNamespace()
	if err != nil {
		return Failure, err
	}
	uri := host + "/api/v1/proxy/namespaces/" + ns + "/services/fabric8/"

	resp, err := c.Client.Get(uri)
	if err != nil {
		err = fmt.Errorf("Cannot query the API Server REST Proxy Service API at %s. Can the master node see the service IPs? Got error: %v", uri, err)
		return Failure, err
	}
	defer resp.Body.Close()

	statusCode := resp.StatusCode
	if statusCode < 200 || statusCode >= 300 {
		err = fmt.Errorf("Cannot query the API Server REST Proxy Service API at %s. Can the master node see the service IPs? Got status code: %d", uri, statusCode)
		return Failure, err
	}
	return Success, err
}

func validatePersistenceVolumeClaims(c *k8sclient.Client, f *cmdutil.Factory) (Result, error) {
	ns, _, err := f.DefaultNamespace()
	if err != nil {
		return Failure, err
	}
	rc, err := c.PersistentVolumeClaims(ns).List(api.ListOptions{})
	if err != nil {
		util.Fatalf("Failed to get PersistentVolumeClaims, %s in namespace %s\n", err, ns)
	}
	if rc != nil {
		items := rc.Items
		pendingClaimNames := make([]string, 0, len(items))
		for _, item := range items {
			status := item.Status.Phase
			if status != "Bound" {
				pendingClaimNames = append(pendingClaimNames, item.ObjectMeta.Name)
			}
		}
		if len(pendingClaimNames) > 0 {
			util.Failuref("PersistentVolumeClaim not Bound for: %s. You need to create a PersistentVolume!\n", strings.Join(pendingClaimNames, ", "))
			util.Info(`
to generate a single node PersistentVolume then type something like this:

cat <<EOF | oc create -f -
---
kind: PersistentVolume
apiVersion: v1
metadata:
  name: fabric8
spec:
  accessModes:
    - ReadWrite
  capacity:
    storage: 1000
  hostPath:
    path: /opt/fabric8-data
EOF

`)
			return Failure, err
		}
		return Success, err
	}
	return Failure, err
}

func validateRouter(c *k8sclient.Client, f *cmdutil.Factory) (Result, error) {
	ns, _, err := f.DefaultNamespace()
	if err != nil {
		return Failure, err
	}
	requirement, err := labels.NewRequirement("router", labels.EqualsOperator, sets.NewString("router"))
	if err != nil {
		return Failure, err
	}
	label := labels.NewSelector().Add(*requirement)

	rc, err := c.ReplicationControllers(ns).List(api.ListOptions{LabelSelector: label})
	if err != nil {
		util.Fatalf("Failed to get PersistentVolumeClaims, %s in namespace %s\n", err, ns)
	}
	if rc != nil {
		items := rc.Items
		if len(items) > 0 {
			return Success, err
		}
	}
	//util.Fatalf("No router running in namespace %s\n", ns)
	// TODO lets create a router
	return Failure, err
}

func validateSecurityContextConstraints(c *k8sclient.Client, f *cmdutil.Factory) (Result, error) {
	ns, _, err := f.DefaultNamespace()
	if err != nil {
		return Failure, err
	}
	name := Fabric8SCC
	if ns != "default" {
		name += "-" + ns
	}
	rc, err := c.SecurityContextConstraints().Get(name)
	if err != nil {
		util.Fatalf("Failed to get SecurityContextConstraints, %s in namespace %s\n", err, ns)
	}
	if rc != nil {
		return Success, err
	}
	return Failure, err
}

func validateJenkinshiftService(c *k8sclient.Client, f *cmdutil.Factory) (Result, error) {
	ns, _, err := f.DefaultNamespace()
	if err != nil {
		return Failure, err
	}
	svc, err := c.Services(ns).Get("jenkinshift")
	if svc != nil {
		return Success, err
	}
	return Failure, err
}

func validateTemplates(c *oclient.Client, f *cmdutil.Factory) (Result, error) {
	ns, _, err := f.DefaultNamespace()
	if err != nil {
		return Failure, err
	}
	rc, err := c.Templates(ns).Get("management")
	if rc != nil {
		return Success, err
	}
	return Failure, err
}

func validateConfigMaps(c *k8sclient.Client, f *cmdutil.Factory) (Result, error) {
	ns, _, err := f.DefaultNamespace()
	if err != nil {
		return Failure, err
	}
	list, err := c.ConfigMaps(ns).List(api.ListOptions{})
	if err == nil && list != nil {
		return Success, err
	}
	return Failure, err
}
<commit_msg>better validation so we don't complain about stuff that is no longer an issue and give more meaningful help on the PVC being unbound<commit_after>/**
 * Copyright (C) 2015 Red Hat, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cmds

import (
	"strings"

	"github.com/fabric8io/gofabric8/client"
	"github.com/fabric8io/gofabric8/util"
	oclient "github.com/openshift/origin/pkg/client"
	"github.com/spf13/cobra"
	"k8s.io/kubernetes/pkg/api"
	k8sclient "k8s.io/kubernetes/pkg/client/unversioned"
	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
	"k8s.io/kubernetes/pkg/labels"
	"k8s.io/kubernetes/pkg/util/sets"
)

type validateFunc func(c *k8sclient.Client, f *cmdutil.Factory) (Result, error)
type oValidateFunc func(c *oclient.Client, f *cmdutil.Factory) (Result, error)

func NewCmdValidate(f *cmdutil.Factory) *cobra.Command {
	cmd := &cobra.Command{
		Use:   "validate",
		Short: "Validate your Kubernetes or OpenShift environment",
		Long:  `validate your Kubernetes or OpenShift environment`,
		PreRun: func(cmd *cobra.Command, args []string) {
			showBanner()
		},
		Run: func(cmd *cobra.Command, args []string) {
			c, cfg := client.NewClient(f)
			ns, _, _ := f.DefaultNamespace()
			util.Info("Validating your ")
			util.Success(string(util.TypeOfMaster(c)))
			util.Info(" installation at ")
			util.Success(cfg.Host)
			util.Info(" in namespace ")
			util.Successf("%s\n\n", ns)
			printValidationResult("Service account", validateServiceAccount, c, f)

			if util.TypeOfMaster(c) == util.Kubernetes {
				printValidationResult("Console", validateConsoleDeployment, c, f)
				printValidationResult("Jenkinshift Service", validateJenkinshiftService, c, f)
			}

			if util.TypeOfMaster(c) == util.OpenShift {
				oc, _ := client.NewOpenShiftClient(cfg)

				// we don't need the router any more!
				//printValidationResult("Router", validateRouter, c, f)
				printOValidationResult("Console", validateConsoleDeploymentConfig, oc, f)
				printOValidationResult("Templates", validateTemplates, oc, f)
				printValidationResult("SecurityContextConstraints", validateSecurityContextConstraints, c, f)
			}

			printValidationResult("PersistentVolumeClaims", validatePersistenceVolumeClaims, c, f)
			printValidationResult("ConfigMaps", validateConfigMaps, c, f)
		},
	}

	return cmd
}

func printValidationResult(check string, v validateFunc, c *k8sclient.Client, f *cmdutil.Factory) {
	r, err := v(c, f)
	printResult(check, r, err)
}

func printOValidationResult(check string, v oValidateFunc, c *oclient.Client, f *cmdutil.Factory) {
	r, err := v(c, f)
	printResult(check, r, err)
}

func printError(check string, err error) {
	r := Success
	if err != nil {
		r = Failure
	}
	printResult(check, r, err)
}

func printResult(check string, r Result, err error) {
	if err != nil {
		r = Failure
	}
	padLen := 78 - len(check)
	pad := ""
	if padLen > 0 {
		pad = strings.Repeat(".", padLen)
	}
	util.Infof("%s%s", check, pad)
	if r == Failure {
		util.Failuref("%-2s", r)
	} else {
		util.Successf("%-2s", r)
	}
	if err != nil {
		util.Failuref("%v", err)
	}
	util.Blank()
}

func validateServiceAccount(c *k8sclient.Client, f *cmdutil.Factory) (Result, error) {
	ns, _, err := f.DefaultNamespace()
	if err != nil {
		return Failure, err
	}
	sa, err := c.ServiceAccounts(ns).Get("fabric8")
	if sa != nil {
		return Success, err
	}
	return Failure, err
}

func validateConsoleDeployment(c *k8sclient.Client, f *cmdutil.Factory) (Result, error) {
	ns, _, err := f.DefaultNamespace()
	if err != nil {
		return Failure, err
	}
	rc, err := c.Deployments(ns).Get("fabric8")
	if rc != nil {
		return Success, err
	}
	return Failure, err
}

func validateConsoleDeploymentConfig(c *oclient.Client, f *cmdutil.Factory) (Result, error) {
	ns, _, err := f.DefaultNamespace()
	if err != nil {
		return Failure, err
	}
	rc, err := c.DeploymentConfigs(ns).Get("fabric8")
	if rc != nil {
		return Success, err
	}
	return Failure, err
}

func validatePersistenceVolumeClaims(c *k8sclient.Client, f *cmdutil.Factory) (Result, error) {
	ns, _, err := f.DefaultNamespace()
	if err != nil {
		return Failure, err
	}
	rc, err := c.PersistentVolumeClaims(ns).List(api.ListOptions{})
	if err != nil {
		util.Fatalf("Failed to get PersistentVolumeClaims, %s in namespace %s\n", err, ns)
	}
	if rc != nil {
		items := rc.Items
		pendingClaimNames := make([]string, 0, len(items))
		for _, item := range items {
			status := item.Status.Phase
			if status != "Bound" {
				pendingClaimNames = append(pendingClaimNames, item.ObjectMeta.Name)
			}
		}
		if len(pendingClaimNames) > 0 {
			util.Failuref("PersistentVolumeClaim not Bound for: %s. You need to create a PersistentVolume!\n", strings.Join(pendingClaimNames, ", "))
			util.Info(`
You can enable dynamic PersistentVolume creation with Kubernetes 1.4 or later.

Or to get gofabric8 to create HostPath based PersistentVolume resources for you on minikube and minishift type:

  gofabric8 volumes

For other clusters you could do something like this - though ideally with a persistent volume implementation other than hostPath:

cat <<EOF | oc create -f -
---
kind: PersistentVolume
apiVersion: v1
metadata:
  name: fabric8
spec:
  accessModes:
    - ReadWrite
  capacity:
    storage: 1000
  hostPath:
    path: /opt/fabric8-data
EOF

`)
			return Failure, err
		}
		return Success, err
	}
	return Failure, err
}

func validateRouter(c *k8sclient.Client, f *cmdutil.Factory) (Result, error) {
	ns, _, err := f.DefaultNamespace()
	if err != nil {
		return Failure, err
	}
	requirement, err := labels.NewRequirement("router", labels.EqualsOperator, sets.NewString("router"))
	if err != nil {
		return Failure, err
	}
	label := labels.NewSelector().Add(*requirement)

	rc, err := c.ReplicationControllers(ns).List(api.ListOptions{LabelSelector: label})
	if err != nil {
		util.Fatalf("Failed to get PersistentVolumeClaims, %s in namespace %s\n", err, ns)
	}
	if rc != nil {
		items := rc.Items
		if len(items) > 0 {
			return Success, err
		}
	}
	//util.Fatalf("No router running in namespace %s\n", ns)
	// TODO lets create a router
	return Failure, err
}

func validateSecurityContextConstraints(c *k8sclient.Client, f *cmdutil.Factory) (Result, error) {
	ns, _, err := f.DefaultNamespace()
	if err != nil {
		return Failure, err
	}
	name := Fabric8SCC
	if ns != "default" {
		name += "-" + ns
	}
	rc, err := c.SecurityContextConstraints().Get(name)
	if err != nil {
		util.Fatalf("Failed to get SecurityContextConstraints, %s in namespace %s\n", err, ns)
	}
	if rc != nil {
		return Success, err
	}
	return Failure, err
}

func validateJenkinshiftService(c *k8sclient.Client, f *cmdutil.Factory) (Result, error) {
	ns, _, err := f.DefaultNamespace()
	if err != nil {
		return Failure, err
	}
	svc, err := c.Services(ns).Get("jenkinshift")
	if svc != nil {
		return Success, err
	}
	return Failure, err
}

func validateTemplates(c *oclient.Client, f *cmdutil.Factory) (Result, error) {
	ns, _, err := f.DefaultNamespace()
	if err != nil {
		return Failure, err
	}
	rc, err := c.Templates(ns).Get("management")
	if rc != nil {
		return Success, err
	}
	return Failure, err
}

func validateConfigMaps(c *k8sclient.Client, f *cmdutil.Factory) (Result, error) {
	ns, _, err := f.DefaultNamespace()
	if err != nil {
		return Failure, err
	}
	list, err := c.ConfigMaps(ns).List(api.ListOptions{})
	if err == nil && list != nil {
		return Success, err
	}
	return Failure, err
}
<|endoftext|>


<commit_before>package rt

import (
	"fmt"
	"os"
	"sync"
	"time"

	"veyron/runtimes/google/appcycle"
	vflag "veyron/security/flag"
	"veyron/services/mgmt/lib/exec"

	"veyron2"
	"veyron2/ipc"
	"veyron2/mgmt"
	"veyron2/naming"
)

type mgmtImpl struct {
	sync.RWMutex
	waiters      []chan<- string
	taskTrackers []chan<- veyron2.Task
	task         veyron2.Task
	shutDown     bool
	rt           *vrt
	server       ipc.Server // Serves AppCycle service.
}

// parentName returns the object name for the Config service on which we should
// communicate the object name of the app cycle service.  Currently, this can
// be configured either via env vars or via the exec config passed from parent.
func parentName() (name string) {
	name = os.Getenv(mgmt.ParentNodeManagerConfigKey)
	if len(name) > 0 {
		return
	}
	handle, _ := exec.GetChildHandle()
	if handle == nil {
		return
	}
	name, _ = handle.Config.Get(mgmt.ParentNodeManagerConfigKey)
	return
}

func (m *mgmtImpl) init(rt *vrt) error {
	m.rt = rt
	parentName := parentName()
	if len(parentName) == 0 {
		return nil
	}
	var err error
	if m.server, err = rt.NewServer(); err != nil {
		return err
	}
	// TODO(caprita): We should pick the address to listen on from config.
	var ep naming.Endpoint
	if ep, err = m.server.Listen("tcp", "127.0.0.1:0"); err != nil {
		return err
	}
	if err := m.server.Serve("", ipc.SoloDispatcher(appcycle.NewServerAppCycle(m), vflag.NewAuthorizerOrDie())); err != nil {
		return err
	}
	return m.callbackToParent(parentName, naming.JoinAddressName(ep.String(), ""))
}

func (m *mgmtImpl) callbackToParent(parentName, myName string) error {
	call, err := m.rt.Client().StartCall(m.rt.NewContext(), parentName, "Set", []interface{}{mgmt.AppCycleManagerConfigKey, myName}, veyron2.CallTimeout(10*time.Second))
	if err != nil {
		return err
	}
	if ierr := call.Finish(&err); ierr != nil {
		return ierr
	}
	return err
}

func (m *mgmtImpl) shutdown() {
	m.Lock()
	if m.shutDown {
		m.Unlock()
		return
	}
	m.shutDown = true
	for _, t := range m.taskTrackers {
		close(t)
	}
	m.taskTrackers = nil
	server := m.server
	m.Unlock()
	if server != nil {
		server.Stop()
	}
}

func (rt *vrt) stop(msg string) {
	rt.mgmt.RLock()
	defer rt.mgmt.RUnlock()
	if len(rt.mgmt.waiters) == 0 {
		os.Exit(veyron2.UnhandledStopExitCode)
	}
	for _, w := range rt.mgmt.waiters {
		select {
		case w <- msg:
		default:
		}
	}
}

func (rt *vrt) Stop() {
	rt.stop(veyron2.LocalStop)
}

func (*vrt) ForceStop() {
	os.Exit(veyron2.ForceStopExitCode)
}

func (rt *vrt) WaitForStop(ch chan<- string) {
	rt.mgmt.Lock()
	defer rt.mgmt.Unlock()
	rt.mgmt.waiters = append(rt.mgmt.waiters, ch)
}

func (rt *vrt) TrackTask(ch chan<- veyron2.Task) {
	rt.mgmt.Lock()
	defer rt.mgmt.Unlock()
	if rt.mgmt.shutDown {
		close(ch)
		return
	}
	rt.mgmt.taskTrackers = append(rt.mgmt.taskTrackers, ch)
}

func (rt *vrt) advanceTask(progress, goal int) {
	rt.mgmt.Lock()
	defer rt.mgmt.Unlock()
	rt.mgmt.task.Goal += goal
	rt.mgmt.task.Progress += progress
	for _, t := range rt.mgmt.taskTrackers {
		select {
		case t <- rt.mgmt.task:
		default:
			// TODO(caprita): Make it such that the latest task
			// update is always added to the channel even if channel
			// is full.  One way is to pull an element from t and
			// then re-try the push.
		}
	}
}

func (rt *vrt) AdvanceGoal(delta int) {
	if delta <= 0 {
		return
	}
	rt.advanceTask(0, delta)
}

func (rt *vrt) AdvanceProgress(delta int) {
	if delta <= 0 {
		return
	}
	rt.advanceTask(delta, 0)
}

func (m *mgmtImpl) Stop(_ ipc.ServerContext, stream appcycle.AppCycleServiceStopStream) error {
	// TODO(caprita): Include identity of Stop issuer in message.
	m.rt.stop(veyron2.RemoteStop)
	// The size of the channel should be reasonably sized to expect not to
	// miss updates while we're waiting for the stream to unblock.
	ch := make(chan veyron2.Task, 10)
	m.rt.TrackTask(ch)
	for {
		task, ok := <-ch
		if !ok {
			// Channel closed, meaning process shutdown is imminent.
			break
		}
		stream.Send(task)
	}
	return nil
}

func (m *mgmtImpl) ForceStop(ipc.ServerContext) error {
	m.rt.ForceStop()
	return fmt.Errorf("ForceStop should not reply as the process should be dead")
}
<commit_msg>veyron/runtimes/google/rt: Avoid using global flags in the library.<commit_after>package rt

import (
	"fmt"
	"os"
	"sync"
	"time"

	"veyron/runtimes/google/appcycle"
	"veyron/services/mgmt/lib/exec"

	"veyron2"
	"veyron2/ipc"
	"veyron2/mgmt"
	"veyron2/naming"
)

type mgmtImpl struct {
	sync.RWMutex
	waiters      []chan<- string
	taskTrackers []chan<- veyron2.Task
	task         veyron2.Task
	shutDown     bool
	rt           *vrt
	server       ipc.Server // Serves AppCycle service.
}

// parentName returns the object name for the Config service on which we should
// communicate the object name of the app cycle service.  Currently, this can
// be configured either via env vars or via the exec config passed from parent.
func parentName() (name string) {
	name = os.Getenv(mgmt.ParentNodeManagerConfigKey)
	if len(name) > 0 {
		return
	}
	handle, _ := exec.GetChildHandle()
	if handle == nil {
		return
	}
	name, _ = handle.Config.Get(mgmt.ParentNodeManagerConfigKey)
	return
}

func (m *mgmtImpl) init(rt *vrt) error {
	m.rt = rt
	parentName := parentName()
	if len(parentName) == 0 {
		return nil
	}
	var err error
	if m.server, err = rt.NewServer(); err != nil {
		return err
	}
	// TODO(caprita): We should pick the address to listen on from config.
	var ep naming.Endpoint
	if ep, err = m.server.Listen("tcp", "127.0.0.1:0"); err != nil {
		return err
	}
	if err := m.server.Serve("", ipc.SoloDispatcher(appcycle.NewServerAppCycle(m), nil)); err != nil {
		return err
	}
	return m.callbackToParent(parentName, naming.JoinAddressName(ep.String(), ""))
}

func (m *mgmtImpl) callbackToParent(parentName, myName string) error {
	call, err := m.rt.Client().StartCall(m.rt.NewContext(), parentName, "Set", []interface{}{mgmt.AppCycleManagerConfigKey, myName}, veyron2.CallTimeout(10*time.Second))
	if err != nil {
		return err
	}
	if ierr := call.Finish(&err); ierr != nil {
		return ierr
	}
	return err
}

func (m *mgmtImpl) shutdown() {
	m.Lock()
	if m.shutDown {
		m.Unlock()
		return
	}
	m.shutDown = true
	for _, t := range m.taskTrackers {
		close(t)
	}
	m.taskTrackers = nil
	server := m.server
	m.Unlock()
	if server != nil {
		server.Stop()
	}
}

func (rt *vrt) stop(msg string) {
	rt.mgmt.RLock()
	defer rt.mgmt.RUnlock()
	if len(rt.mgmt.waiters) == 0 {
		os.Exit(veyron2.UnhandledStopExitCode)
	}
	for _, w := range rt.mgmt.waiters {
		select {
		case w <- msg:
		default:
		}
	}
}

func (rt *vrt) Stop() {
	rt.stop(veyron2.LocalStop)
}

func (*vrt) ForceStop() {
	os.Exit(veyron2.ForceStopExitCode)
}

func (rt *vrt) WaitForStop(ch chan<- string) {
	rt.mgmt.Lock()
	defer rt.mgmt.Unlock()
	rt.mgmt.waiters = append(rt.mgmt.waiters, ch)
}

func (rt *vrt) TrackTask(ch chan<- veyron2.Task) {
	rt.mgmt.Lock()
	defer rt.mgmt.Unlock()
	if rt.mgmt.shutDown {
		close(ch)
		return
	}
	rt.mgmt.taskTrackers = append(rt.mgmt.taskTrackers, ch)
}

func (rt *vrt) advanceTask(progress, goal int) {
	rt.mgmt.Lock()
	defer rt.mgmt.Unlock()
	rt.mgmt.task.Goal += goal
	rt.mgmt.task.Progress += progress
	for _, t := range rt.mgmt.taskTrackers {
		select {
		case t <- rt.mgmt.task:
		default:
			// TODO(caprita): Make it such that the latest task
			// update is always added to the channel even if channel
			// is full.  One way is to pull an element from t and
			// then re-try the push.
		}
	}
}

func (rt *vrt) AdvanceGoal(delta int) {
	if delta <= 0 {
		return
	}
	rt.advanceTask(0, delta)
}

func (rt *vrt) AdvanceProgress(delta int) {
	if delta <= 0 {
		return
	}
	rt.advanceTask(delta, 0)
}

func (m *mgmtImpl) Stop(_ ipc.ServerContext, stream appcycle.AppCycleServiceStopStream) error {
	// TODO(caprita): Include identity of Stop issuer in message.
	m.rt.stop(veyron2.RemoteStop)
	// The size of the channel should be reasonably sized to expect not to
	// miss updates while we're waiting for the stream to unblock.
	ch := make(chan veyron2.Task, 10)
	m.rt.TrackTask(ch)
	for {
		task, ok := <-ch
		if !ok {
			// Channel closed, meaning process shutdown is imminent.
			break
		}
		stream.Send(task)
	}
	return nil
}

func (m *mgmtImpl) ForceStop(ipc.ServerContext) error {
	m.rt.ForceStop()
	return fmt.Errorf("ForceStop should not reply as the process should be dead")
}
<|endoftext|>


<commit_before>// Package sortmap allows for sorting maps by a custom comparator.
// For convenience, functions sorting by keys or values in ascending or descending
// order are provided – these can deal with limited types only, which are:
// bool, all inbuilt numerical types and string.
//
// Functions provided by this package panic when non-map type is passed for sorting
// or, in case of the key/value sorters, the underyling type is not supported.
package sortmap

import (
	"fmt"
	"reflect"
	"sort"
)

// KV is a key-value pair representing element in the map
type KV struct {
	K, V interface{}
}

// Less compares two map elements and returns true if x < y
type Less func(x, y KV) bool

// flatmap is a flattened map with a comparator to be used with sort
type flatmap struct {
	kv []KV
	c  Less
}

func newFlatMap(m interface{}, c Less) *flatmap {
	fm := &flatmap{c: c}
	mv := reflect.ValueOf(m)
	for _, v := range mv.MapKeys() {
		fm.kv = append(fm.kv, KV{v.Interface(), mv.MapIndex(v).Interface()})
	}
	return fm
}

func (m flatmap) Len() int {
	return len(m.kv)
}
func (m flatmap) Less(i, j int) bool {
	return m.c(m.kv[i], m.kv[j])
}
func (m flatmap) Swap(i, j int) {
	m.kv[i], m.kv[j] = m.kv[j], m.kv[i]
}

// ByFunc sorts map using a provided comparator
func ByFunc(m interface{}, c Less) []KV {
	fm := newFlatMap(m, c)
	sort.Sort(fm)
	return fm.kv
}

// ByKey sorts map by keys in the ascending order
func ByKey(m interface{}) []KV {
	ls := getLess(reflect.ValueOf(m).Type().Key())
	return ByFunc(m, func(x, y KV) bool { return ls(x.K, y.K) })
}

// ByKeyDesc sorts map by keys in the descending order
func ByKeyDesc(m interface{}) []KV {
	ls := getLess(reflect.ValueOf(m).Type().Key())
	return ByFunc(m, func(x, y KV) bool { return ls(y.K, x.K) })
}

// ByVal sorts map by values in the ascending order
func ByVal(m interface{}) []KV {
	ls := getLess(reflect.ValueOf(m).Type().Elem())
	return ByFunc(m, func(x, y KV) bool { return ls(x.V, y.V) })
}

// ByValDesc sorts map by values in the descending order
func ByValDesc(m interface{}) []KV {
	ls := getLess(reflect.ValueOf(m).Type().Elem())
	return ByFunc(m, func(x, y KV) bool { return ls(y.V, x.V) })
}

// getLess returns default comparator for a type
func getLess(t reflect.Type) (f func(x, y interface{}) bool) {
	switch t.Kind() {
	case reflect.Bool:
		f = func(x, y interface{}) bool { return !x.(bool) && y.(bool) }
	case reflect.Int:
		f = func(x, y interface{}) bool { return x.(int) < y.(int) }
	case reflect.Int8:
		f = func(x, y interface{}) bool { return x.(int8) < y.(int8) }
	case reflect.Int16:
		f = func(x, y interface{}) bool { return x.(int16) < y.(int16) }
	case reflect.Int32:
		f = func(x, y interface{}) bool { return x.(int32) < y.(int32) }
	case reflect.Int64:
		f = func(x, y interface{}) bool { return x.(int64) < y.(int64) }
	case reflect.Uint:
		f = func(x, y interface{}) bool { return x.(uint) < y.(uint) }
	case reflect.Uint8:
		f = func(x, y interface{}) bool { return x.(uint8) < y.(uint8) }
	case reflect.Uint16:
		f = func(x, y interface{}) bool { return x.(uint16) < y.(uint16) }
	case reflect.Uint32:
		f = func(x, y interface{}) bool { return x.(uint32) < y.(uint32) }
	case reflect.Uint64:
		f = func(x, y interface{}) bool { return x.(uint64) < y.(uint64) }
	case reflect.Float32:
		f = func(x, y interface{}) bool { return x.(float32) < y.(float32) }
	case reflect.Float64:
		f = func(x, y interface{}) bool { return x.(float64) < y.(float64) }
	case reflect.String:
		f = func(x, y interface{}) bool { return x.(string) < y.(string) }
	default:
		panic(fmt.Sprintf("sortmap: unsupported type: %s", t))
	}
	return
}
<commit_msg>Preallocate flatmap list<commit_after>// Package sortmap allows for sorting maps by a custom comparator.
// For convenience, functions sorting by keys or values in ascending or descending
// order are provided – these can deal with limited types only, which are:
// bool, all inbuilt numerical types and string.
//
// Functions provided by this package panic when non-map type is passed for sorting
// or, in case of the key/value sorters, the underyling type is not supported.
package sortmap

import (
	"fmt"
	"reflect"
	"sort"
)

// KV is a key-value pair representing element in the map
type KV struct {
	K, V interface{}
}

// Less compares two map elements and returns true if x < y
type Less func(x, y KV) bool

// flatmap is a flattened map with a comparator to be used with sort
type flatmap struct {
	kv []KV
	c  Less
}

func newFlatMap(m interface{}, c Less) *flatmap {
	mv := reflect.ValueOf(m)
	keys := mv.MapKeys()
	fm := &flatmap{kv: make([]KV, len(keys)), c: c}
	for n := range keys {
		fm.kv[n] = KV{keys[n].Interface(), mv.MapIndex(keys[n]).Interface()}
	}
	return fm
}

func (m flatmap) Len() int {
	return len(m.kv)
}
func (m flatmap) Less(i, j int) bool {
	return m.c(m.kv[i], m.kv[j])
}
func (m flatmap) Swap(i, j int) {
	m.kv[i], m.kv[j] = m.kv[j], m.kv[i]
}

// ByFunc sorts map using a provided comparator
func ByFunc(m interface{}, c Less) []KV {
	fm := newFlatMap(m, c)
	sort.Sort(fm)
	return fm.kv
}

// ByKey sorts map by keys in the ascending order
func ByKey(m interface{}) []KV {
	ls := getLess(reflect.ValueOf(m).Type().Key())
	return ByFunc(m, func(x, y KV) bool { return ls(x.K, y.K) })
}

// ByKeyDesc sorts map by keys in the descending order
func ByKeyDesc(m interface{}) []KV {
	ls := getLess(reflect.ValueOf(m).Type().Key())
	return ByFunc(m, func(x, y KV) bool { return ls(y.K, x.K) })
}

// ByVal sorts map by values in the ascending order
func ByVal(m interface{}) []KV {
	ls := getLess(reflect.ValueOf(m).Type().Elem())
	return ByFunc(m, func(x, y KV) bool { return ls(x.V, y.V) })
}

// ByValDesc sorts map by values in the descending order
func ByValDesc(m interface{}) []KV {
	ls := getLess(reflect.ValueOf(m).Type().Elem())
	return ByFunc(m, func(x, y KV) bool { return ls(y.V, x.V) })
}

// getLess returns default comparator for a type
func getLess(t reflect.Type) (f func(x, y interface{}) bool) {
	switch t.Kind() {
	case reflect.Bool:
		f = func(x, y interface{}) bool { return !x.(bool) && y.(bool) }
	case reflect.Int:
		f = func(x, y interface{}) bool { return x.(int) < y.(int) }
	case reflect.Int8:
		f = func(x, y interface{}) bool { return x.(int8) < y.(int8) }
	case reflect.Int16:
		f = func(x, y interface{}) bool { return x.(int16) < y.(int16) }
	case reflect.Int32:
		f = func(x, y interface{}) bool { return x.(int32) < y.(int32) }
	case reflect.Int64:
		f = func(x, y interface{}) bool { return x.(int64) < y.(int64) }
	case reflect.Uint:
		f = func(x, y interface{}) bool { return x.(uint) < y.(uint) }
	case reflect.Uint8:
		f = func(x, y interface{}) bool { return x.(uint8) < y.(uint8) }
	case reflect.Uint16:
		f = func(x, y interface{}) bool { return x.(uint16) < y.(uint16) }
	case reflect.Uint32:
		f = func(x, y interface{}) bool { return x.(uint32) < y.(uint32) }
	case reflect.Uint64:
		f = func(x, y interface{}) bool { return x.(uint64) < y.(uint64) }
	case reflect.Float32:
		f = func(x, y interface{}) bool { return x.(float32) < y.(float32) }
	case reflect.Float64:
		f = func(x, y interface{}) bool { return x.(float64) < y.(float64) }
	case reflect.String:
		f = func(x, y interface{}) bool { return x.(string) < y.(string) }
	default:
		panic(fmt.Sprintf("sortmap: unsupported type: %s", t))
	}
	return
}
<|endoftext|>


<commit_before>package nsf

import (
	"errors"
	"io"
	"io/ioutil"
	"time"

	"github.com/mjibson/mog/codec/nsf/cpu6502"
)

const (
	// 1.79 MHz
	cpuClock = 236250000 / 11 / 12
)

var (
	// DefaultSampleRate is the default sample rate of a track after calling
	// Init().
	DefaultSampleRate = 44100
	ErrUnrecognized   = errors.New("nsf: unrecognized format")
)

const (
	NSF_HEADER_LEN = 0x80
	NSF_VERSION    = 0x5
	NSF_SONGS      = 0x6
	NSF_START      = 0x7
	NSF_LOAD       = 0x8
	NSF_INIT       = 0xa
	NSF_PLAY       = 0xc
	NSF_SONG       = 0xe
	NSF_ARTIST     = 0x2e
	NSF_COPYRIGHT  = 0x4e
	NSF_SPEED_NTSC = 0x6e
	NSF_BANKSWITCH = 0x70
	NSF_SPEED_PAL  = 0x78
	NSF_PAL_NTSC   = 0x7a
	NSF_EXTRA      = 0x7b
	NSF_ZERO       = 0x7c
)

func ReadNSF(r io.Reader) (n *NSF, err error) {
	n = New()
	n.b, err = ioutil.ReadAll(r)
	if err != nil {
		return
	}
	if len(n.b) < NSF_HEADER_LEN ||
		string(n.b[0:NSF_VERSION]) != "NESM\u001a" {
		return nil, ErrUnrecognized
	}
	n.Version = n.b[NSF_VERSION]
	n.Songs = n.b[NSF_SONGS]
	n.Start = n.b[NSF_START]
	n.LoadAddr = bLEtoUint16(n.b[NSF_LOAD:])
	n.InitAddr = bLEtoUint16(n.b[NSF_INIT:])
	n.PlayAddr = bLEtoUint16(n.b[NSF_PLAY:])
	n.Song = bToString(n.b[NSF_SONG:])
	n.Artist = bToString(n.b[NSF_ARTIST:])
	n.Copyright = bToString(n.b[NSF_COPYRIGHT:])
	n.SpeedNTSC = bLEtoUint16(n.b[NSF_SPEED_NTSC:])
	copy(n.Bankswitch[:], n.b[NSF_BANKSWITCH:NSF_SPEED_PAL])
	n.SpeedPAL = bLEtoUint16(n.b[NSF_SPEED_PAL:])
	n.PALNTSC = n.b[NSF_PAL_NTSC]
	n.Extra = n.b[NSF_EXTRA]
	n.Data = n.b[NSF_HEADER_LEN:]
	return
}

type NSF struct {
	*Ram
	*cpu6502.Cpu

	b []byte // raw NSF data

	Version byte
	Songs   byte
	Start   byte

	LoadAddr uint16
	InitAddr uint16
	PlayAddr uint16

	Song      string
	Artist    string
	Copyright string

	SpeedNTSC  uint16
	Bankswitch [8]byte
	SpeedPAL   uint16
	PALNTSC    byte
	Extra      byte
	Data       []byte

	// SampleRate is the sample rate at which samples will be generated. If not
	// set before Init(), it is set to DefaultSampleRate.
	SampleRate  int64
	totalTicks  int64
	frameTicks  int64
	sampleTicks int64
	playTicks   int64
	samples     []float32
	prevs       [4]float32
	pi          int // prevs index
}

func New() *NSF {
	n := NSF{
		Ram: new(Ram),
	}
	n.Cpu = cpu6502.New(n.Ram)
	n.Cpu.T = &n
	n.Cpu.DisableDecimal = true
	n.Cpu.P = 0x24
	n.Cpu.S = 0xfd
	return &n
}

func (n *NSF) Tick() {
	n.Ram.A.Step()
	n.totalTicks++
	n.frameTicks++
	if n.frameTicks == cpuClock/240 {
		n.frameTicks = 0
		n.Ram.A.FrameStep()
	}
	n.sampleTicks++
	if n.SampleRate > 0 && n.sampleTicks >= cpuClock/n.SampleRate {
		n.sampleTicks = 0
		n.append(n.Ram.A.Volume())
	}
	n.playTicks++
}

func (n *NSF) append(v float32) {
	n.prevs[n.pi] = v
	n.pi++
	if n.pi >= len(n.prevs) {
		n.pi = 0
	}
	var sum float32
	for _, s := range n.prevs {
		sum += s
	}
	sum /= float32(len(n.prevs))
	n.samples = append(n.samples, sum)
}

func (n *NSF) Init(song byte) {
	if n.SampleRate == 0 {
		n.SampleRate = int64(DefaultSampleRate)
	}
	copy(n.Ram.M[n.LoadAddr:], n.Data)
	n.Ram.A.Init()
	n.Cpu.A = song - 1
	n.Cpu.PC = n.InitAddr
	n.Cpu.T = nil
	n.Cpu.Run()
	n.Cpu.T = n
}

func (n *NSF) Step() {
	n.Cpu.Step()
	if !n.Cpu.I() && n.Ram.A.Interrupt {
		println("INTERRUPT")
		n.Cpu.Interrupt()
	}
}

func (n *NSF) Play(samples int) []float32 {
	playDur := time.Duration(n.SpeedNTSC) * time.Nanosecond * 1000
	ticksPerPlay := int64(playDur / (time.Second / cpuClock))
	n.samples = make([]float32, 0, samples)
	for len(n.samples) < samples {
		n.playTicks = 0
		n.Cpu.PC = n.PlayAddr
		for n.Cpu.PC != 0 && len(n.samples) < samples {
			n.Step()
		}
		for i := ticksPerPlay - n.playTicks; i > 0 && len(n.samples) < samples; i-- {
			n.Tick()
		}
	}
	return n.samples
}

// little-endian [2]byte to uint16 conversion
func bLEtoUint16(b []byte) uint16 {
	return uint16(b[1])<<8 + uint16(b[0])
}

// null-terminated bytes to string
func bToString(b []byte) string {
	i := 0
	for i = range b {
		if b[i] == 0 {
			break
		}
	}
	return string(b[:i])
}

type Ram struct {
	M [0xffff + 1]byte
	A Apu
}

func (r *Ram) Read(v uint16) byte {
	switch v {
	case 0x4015:
		return r.A.Read(v)
	default:
		return r.M[v]
	}
}

func (r *Ram) Write(v uint16, b byte) {
	r.M[v] = b
	if v&0xf000 == 0x4000 {
		r.A.Write(v, b)
	}
}
<commit_msg>Remove debug<commit_after>package nsf

import (
	"errors"
	"io"
	"io/ioutil"
	"time"

	"github.com/mjibson/mog/codec/nsf/cpu6502"
)

const (
	// 1.79 MHz
	cpuClock = 236250000 / 11 / 12
)

var (
	// DefaultSampleRate is the default sample rate of a track after calling
	// Init().
	DefaultSampleRate = 44100
	ErrUnrecognized   = errors.New("nsf: unrecognized format")
)

const (
	NSF_HEADER_LEN = 0x80
	NSF_VERSION    = 0x5
	NSF_SONGS      = 0x6
	NSF_START      = 0x7
	NSF_LOAD       = 0x8
	NSF_INIT       = 0xa
	NSF_PLAY       = 0xc
	NSF_SONG       = 0xe
	NSF_ARTIST     = 0x2e
	NSF_COPYRIGHT  = 0x4e
	NSF_SPEED_NTSC = 0x6e
	NSF_BANKSWITCH = 0x70
	NSF_SPEED_PAL  = 0x78
	NSF_PAL_NTSC   = 0x7a
	NSF_EXTRA      = 0x7b
	NSF_ZERO       = 0x7c
)

func ReadNSF(r io.Reader) (n *NSF, err error) {
	n = New()
	n.b, err = ioutil.ReadAll(r)
	if err != nil {
		return
	}
	if len(n.b) < NSF_HEADER_LEN ||
		string(n.b[0:NSF_VERSION]) != "NESM\u001a" {
		return nil, ErrUnrecognized
	}
	n.Version = n.b[NSF_VERSION]
	n.Songs = n.b[NSF_SONGS]
	n.Start = n.b[NSF_START]
	n.LoadAddr = bLEtoUint16(n.b[NSF_LOAD:])
	n.InitAddr = bLEtoUint16(n.b[NSF_INIT:])
	n.PlayAddr = bLEtoUint16(n.b[NSF_PLAY:])
	n.Song = bToString(n.b[NSF_SONG:])
	n.Artist = bToString(n.b[NSF_ARTIST:])
	n.Copyright = bToString(n.b[NSF_COPYRIGHT:])
	n.SpeedNTSC = bLEtoUint16(n.b[NSF_SPEED_NTSC:])
	copy(n.Bankswitch[:], n.b[NSF_BANKSWITCH:NSF_SPEED_PAL])
	n.SpeedPAL = bLEtoUint16(n.b[NSF_SPEED_PAL:])
	n.PALNTSC = n.b[NSF_PAL_NTSC]
	n.Extra = n.b[NSF_EXTRA]
	n.Data = n.b[NSF_HEADER_LEN:]
	return
}

type NSF struct {
	*Ram
	*cpu6502.Cpu

	b []byte // raw NSF data

	Version byte
	Songs   byte
	Start   byte

	LoadAddr uint16
	InitAddr uint16
	PlayAddr uint16

	Song      string
	Artist    string
	Copyright string

	SpeedNTSC  uint16
	Bankswitch [8]byte
	SpeedPAL   uint16
	PALNTSC    byte
	Extra      byte
	Data       []byte

	// SampleRate is the sample rate at which samples will be generated. If not
	// set before Init(), it is set to DefaultSampleRate.
	SampleRate  int64
	totalTicks  int64
	frameTicks  int64
	sampleTicks int64
	playTicks   int64
	samples     []float32
	prevs       [4]float32
	pi          int // prevs index
}

func New() *NSF {
	n := NSF{
		Ram: new(Ram),
	}
	n.Cpu = cpu6502.New(n.Ram)
	n.Cpu.T = &n
	n.Cpu.DisableDecimal = true
	n.Cpu.P = 0x24
	n.Cpu.S = 0xfd
	return &n
}

func (n *NSF) Tick() {
	n.Ram.A.Step()
	n.totalTicks++
	n.frameTicks++
	if n.frameTicks == cpuClock/240 {
		n.frameTicks = 0
		n.Ram.A.FrameStep()
	}
	n.sampleTicks++
	if n.SampleRate > 0 && n.sampleTicks >= cpuClock/n.SampleRate {
		n.sampleTicks = 0
		n.append(n.Ram.A.Volume())
	}
	n.playTicks++
}

func (n *NSF) append(v float32) {
	n.prevs[n.pi] = v
	n.pi++
	if n.pi >= len(n.prevs) {
		n.pi = 0
	}
	var sum float32
	for _, s := range n.prevs {
		sum += s
	}
	sum /= float32(len(n.prevs))
	n.samples = append(n.samples, sum)
}

func (n *NSF) Init(song byte) {
	if n.SampleRate == 0 {
		n.SampleRate = int64(DefaultSampleRate)
	}
	copy(n.Ram.M[n.LoadAddr:], n.Data)
	n.Ram.A.Init()
	n.Cpu.A = song - 1
	n.Cpu.PC = n.InitAddr
	n.Cpu.T = nil
	n.Cpu.Run()
	n.Cpu.T = n
}

func (n *NSF) Step() {
	n.Cpu.Step()
	if !n.Cpu.I() && n.Ram.A.Interrupt {
		n.Cpu.Interrupt()
	}
}

func (n *NSF) Play(samples int) []float32 {
	playDur := time.Duration(n.SpeedNTSC) * time.Nanosecond * 1000
	ticksPerPlay := int64(playDur / (time.Second / cpuClock))
	n.samples = make([]float32, 0, samples)
	for len(n.samples) < samples {
		n.playTicks = 0
		n.Cpu.PC = n.PlayAddr
		for n.Cpu.PC != 0 && len(n.samples) < samples {
			n.Step()
		}
		for i := ticksPerPlay - n.playTicks; i > 0 && len(n.samples) < samples; i-- {
			n.Tick()
		}
	}
	return n.samples
}

// little-endian [2]byte to uint16 conversion
func bLEtoUint16(b []byte) uint16 {
	return uint16(b[1])<<8 + uint16(b[0])
}

// null-terminated bytes to string
func bToString(b []byte) string {
	i := 0
	for i = range b {
		if b[i] == 0 {
			break
		}
	}
	return string(b[:i])
}

type Ram struct {
	M [0xffff + 1]byte
	A Apu
}

func (r *Ram) Read(v uint16) byte {
	switch v {
	case 0x4015:
		return r.A.Read(v)
	default:
		return r.M[v]
	}
}

func (r *Ram) Write(v uint16, b byte) {
	r.M[v] = b
	if v&0xf000 == 0x4000 {
		r.A.Write(v, b)
	}
}
<|endoftext|>