github.com/coreos/mantle@v0.13.0/cli/cli.go (about)

     1  // Copyright 2014 CoreOS, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package cli
    16  
    17  import (
    18  	"os"
    19  
    20  	"github.com/coreos/pkg/capnslog"
    21  	"github.com/spf13/cobra"
    22  
    23  	"github.com/coreos/mantle/system/exec"
    24  	"github.com/coreos/mantle/version"
    25  )
    26  
    27  var (
    28  	versionCmd = &cobra.Command{
    29  		Use:   "version",
    30  		Short: "Print the version number and exit.",
    31  		Run: func(cmd *cobra.Command, args []string) {
    32  			cmd.Printf("mantle/%s version %s\n",
    33  				cmd.Root().Name(), version.Version)
    34  		},
    35  	}
    36  
    37  	logDebug   bool
    38  	logVerbose bool
    39  	logLevel   = capnslog.NOTICE
    40  
    41  	plog = capnslog.NewPackageLogger("github.com/coreos/mantle", "cli")
    42  )
    43  
    44  // Execute sets up common features that all mantle commands should share
    45  // and then executes the command. It does not return.
    46  func Execute(main *cobra.Command) {
    47  	// If we were invoked via a multicall entrypoint run it instead.
    48  	// TODO(marineam): should we figure out a way to initialize logging?
    49  	exec.MaybeExec()
    50  
    51  	main.AddCommand(versionCmd)
    52  
    53  	// TODO(marineam): pflags defines the Value interface differently,
    54  	// update capnslog accordingly...
    55  	main.PersistentFlags().Var(&logLevel, "log-level",
    56  		"Set global log level.")
    57  	main.PersistentFlags().BoolVarP(&logVerbose, "verbose", "v", false,
    58  		"Alias for --log-level=INFO")
    59  	main.PersistentFlags().BoolVarP(&logDebug, "debug", "d", false,
    60  		"Alias for --log-level=DEBUG")
    61  
    62  	WrapPreRun(main, func(cmd *cobra.Command, args []string) error {
    63  		startLogging(cmd)
    64  		return nil
    65  	})
    66  
    67  	if err := main.Execute(); err != nil {
    68  		plog.Fatal(err)
    69  	}
    70  	os.Exit(0)
    71  }
    72  
    73  func setRepoLogLevel(repo string, l capnslog.LogLevel) {
    74  	r, err := capnslog.GetRepoLogger(repo)
    75  	if err != nil {
    76  		return // don't care if it isn't linked in
    77  	}
    78  	r.SetRepoLogLevel(l)
    79  }
    80  
    81  func startLogging(cmd *cobra.Command) {
    82  	switch {
    83  	case logDebug:
    84  		logLevel = capnslog.DEBUG
    85  	case logVerbose:
    86  		logLevel = capnslog.INFO
    87  	}
    88  
    89  	capnslog.SetFormatter(capnslog.NewStringFormatter(cmd.Out()))
    90  	capnslog.SetGlobalLogLevel(logLevel)
    91  
    92  	// In the context of the internally linked etcd, the NOTICE messages
    93  	// aren't really interesting, so translate NOTICE to WARNING instead.
    94  	if logLevel == capnslog.NOTICE {
    95  		// etcd sure has a lot of repos in its repo
    96  		setRepoLogLevel("github.com/coreos/etcd", capnslog.WARNING)
    97  		setRepoLogLevel("github.com/coreos/etcd/etcdserver", capnslog.WARNING)
    98  		setRepoLogLevel("github.com/coreos/etcd/etcdserver/etcdhttp", capnslog.WARNING)
    99  		setRepoLogLevel("github.com/coreos/etcd/pkg", capnslog.WARNING)
   100  	}
   101  
   102  	plog.Infof("Started logging at level %s", logLevel)
   103  }
   104  
   105  type PreRunEFunc func(cmd *cobra.Command, args []string) error
   106  
   107  func WrapPreRun(root *cobra.Command, f PreRunEFunc) {
   108  	preRun, preRunE := root.PersistentPreRun, root.PersistentPreRunE
   109  	root.PersistentPreRun, root.PersistentPreRunE = nil, nil
   110  
   111  	root.PersistentPreRunE = func(cmd *cobra.Command, args []string) error {
   112  		if err := f(cmd, args); err != nil {
   113  			return err
   114  		}
   115  		if preRun != nil {
   116  			preRun(cmd, args)
   117  		} else if preRunE != nil {
   118  			return preRunE(cmd, args)
   119  		}
   120  		return nil
   121  	}
   122  }