github.com/chain5j/chain5j-pkg@v1.0.7/cli/cli.go (about)

     1  // Package cli
     2  //
     3  // @author: xwc1125
     4  package cli
     5  
     6  import (
     7  	"fmt"
     8  	"path/filepath"
     9  
    10  	"github.com/fsnotify/fsnotify"
    11  	"github.com/spf13/cobra"
    12  	"github.com/spf13/pflag"
    13  	"github.com/spf13/viper"
    14  )
    15  
    16  type Command *cobra.Command
    17  
    18  // Cli cobra 在使用中,如果执行过中任何的Run或RunE没有执行过,那么cobra.OnInitialize(func func1)
    19  // 中的func1 就不会执行
    20  type Cli struct {
    21  	appInfo *AppInfo
    22  	rootCmd *cobra.Command
    23  	viper   *viper.Viper
    24  
    25  	subCmds []Command
    26  
    27  	readConfigFunc func(viper *viper.Viper)
    28  	configFile     string
    29  	configEnv      string
    30  }
    31  
    32  // NewCli 创建新的命令对象
    33  func NewCli(a *AppInfo) *Cli {
    34  	return NewCliWithViper(a, nil)
    35  }
    36  
    37  // NewCliWithViper 添加viper创建新的命令对象
    38  func NewCliWithViper(a *AppInfo, _viper *viper.Viper) *Cli {
    39  	if _viper == nil {
    40  		_viper = viper.New()
    41  	}
    42  	rootCmd := &cobra.Command{
    43  		Use:     a.App,
    44  		Version: a.Version,
    45  		Run: func(cmd *cobra.Command, args []string) {
    46  			fmt.Println(a.Welcome)
    47  		},
    48  	}
    49  	return &Cli{
    50  		appInfo: a,
    51  		rootCmd: rootCmd,
    52  		viper:   _viper,
    53  		subCmds: make([]Command, 0),
    54  	}
    55  }
    56  
    57  // InitFlags 初始化flag
    58  // viper 按照如下顺序查找flag key:
    59  // - pflag里面的被命令行显式设置的key
    60  // - 环境变量显式设置的
    61  // - 配置文件显式设置的
    62  // - KV存储的
    63  // - 通过viper设置的default flag
    64  // - 如果前面都没有变化,最后使用pflag的默认值
    65  //
    66  // 所以在Unmarshal的时候命令行里面显式设置的flag会覆盖配置文件里面的flag
    67  // 如果配置文件没有这个flag,会用pflag的默认值
    68  // @params useDefaultFlags 是否使用默认的flag:config,env
    69  // @params flagSetFunc flag设置的回调函数,函数中为viper及rootFlags
    70  // @params readConfigFunc 读取配置的回调函数
    71  func (cli *Cli) InitFlags(useDefaultFlags bool, flagSetFunc func(rootFlags *pflag.FlagSet), readConfigFunc func(viper *viper.Viper)) (err error) {
    72  	// 获取当前命令行
    73  	{
    74  		rootFlags := cli.rootCmd.PersistentFlags()
    75  		if useDefaultFlags {
    76  			rootFlags.StringVar(&cli.configFile, "config", "./conf/config.yaml", "config file (default is ./conf/config.yaml)")
    77  			rootFlags.StringVar(&cli.configEnv, "env", "", "config env")
    78  		}
    79  		if flagSetFunc != nil {
    80  			flagSetFunc(rootFlags)
    81  		}
    82  		// 将完整的命令绑定到viper上
    83  		if err := cli.viper.BindPFlags(rootFlags); err != nil {
    84  			return err
    85  		}
    86  	}
    87  
    88  	// 进行config初始化
    89  	cobra.OnInitialize(func() {
    90  		if useDefaultFlags {
    91  			// 初始化配置文件
    92  			if cli.configFile != "" {
    93  				cli.configFile, err = filepath.Abs(cli.configFile)
    94  				if err != nil {
    95  					return
    96  				}
    97  				cli.viper.SetConfigFile(cli.configFile)
    98  			} else {
    99  				// 如果含有环境类型,那么使用config_{env}
   100  				if cli.configEnv != "" {
   101  					cli.viper.SetConfigName("config_" + cli.configEnv)
   102  				} else {
   103  					cli.viper.SetConfigName("config")
   104  				}
   105  				// 添加读取的配置文件路径
   106  				cli.viper.AddConfigPath(".")
   107  				cli.viper.AddConfigPath("./conf")
   108  			}
   109  			// viper加载配置
   110  			if err = cli.viper.ReadInConfig(); err != nil {
   111  				return
   112  			}
   113  		}
   114  		cli.viper.AutomaticEnv()
   115  
   116  		if readConfigFunc != nil {
   117  			cli.readConfigFunc = readConfigFunc
   118  			cli.readConfigFunc(cli.viper)
   119  		}
   120  
   121  		// 观察配置变更
   122  		cli.watchConfig()
   123  	})
   124  	return nil
   125  }
   126  
   127  // 监听配置文件是否改变,用于热更新
   128  func (cli *Cli) watchConfig() {
   129  	cli.viper.WatchConfig()
   130  	cli.viper.OnConfigChange(func(e fsnotify.Event) {
   131  		fmt.Printf("Config file changed: %s\n", e.Name)
   132  		if cli.readConfigFunc != nil {
   133  			cli.readConfigFunc(cli.viper)
   134  		}
   135  	})
   136  }
   137  
   138  // RootCmd 获取cobra.Command
   139  func (cli *Cli) RootCmd() *cobra.Command {
   140  	return cli.rootCmd
   141  }
   142  
   143  // Viper 获取viper
   144  func (cli *Cli) Viper() *viper.Viper {
   145  	return cli.viper
   146  }
   147  
   148  // AddCommands 往cobra.Command添加多个命令
   149  func (cli *Cli) AddCommands(cmds ...Command) {
   150  	if cmds == nil {
   151  		return
   152  	}
   153  	cli.subCmds = cmds
   154  	for _, cmd := range cmds {
   155  		cli.rootCmd.AddCommand(cmd)
   156  	}
   157  }
   158  
   159  // GetCommands 获取所有的命令command
   160  func (cli *Cli) GetCommands() []Command {
   161  	return cli.subCmds
   162  }
   163  
   164  // Execute 执行命令
   165  func (cli *Cli) Execute() error {
   166  	return cli.rootCmd.Execute()
   167  }
   168  
   169  // Get 从配置文件中获取参数
   170  func (cli *Cli) Get(key string) interface{} {
   171  	return cli.viper.Get(key)
   172  }
   173  
   174  // GetString 获取字符串参数
   175  func (cli *Cli) GetString(key string) string {
   176  	return cli.viper.GetString(key)
   177  }
   178  
   179  // GetInt 获取int参数
   180  func (cli *Cli) GetInt(key string) int {
   181  	return cli.viper.GetInt(key)
   182  }
   183  
   184  // GetInt64 获取int64参数
   185  func (cli *Cli) GetInt64(key string) int64 {
   186  	return cli.viper.GetInt64(key)
   187  }
   188  
   189  // GetBool 获取bool参数
   190  func (cli *Cli) GetBool(key string) bool {
   191  	return cli.viper.GetBool(key)
   192  }
   193  
   194  // GetConfigFile 获取配置文件
   195  func (cli *Cli) GetConfigFile() string {
   196  	return cli.configFile
   197  }
   198  
   199  // GetConfigEnv 获取环境
   200  func (cli *Cli) GetConfigEnv() string {
   201  	return cli.configEnv
   202  }
   203  
   204  // AppInfo 获取appInfo
   205  func (cli *Cli) AppInfo() *AppInfo {
   206  	return cli.appInfo
   207  }