// 2020 Rackspace, 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 core contains the core functionality of gomigrate and initializes the default // parser. package core import ( "fmt" "os" "strings" "sync" "syscall" "time" "github.com/gookit/color" "github.com/jokelyo/argparse" "github.com/sirupsen/logrus" "github.rackspace.com/gorax/clients/stepladder/appstats" "github.rackspace.com/gorax/gokeys" ) type ( // Parser type is used as the main parser for gomigrate. // It embeds the argparse Parser type. Parser struct { *argparse.Parser Plugins []Plugin } // Plugin is the command and calling function for each plugin Plugin struct { CMD *argparse.Command Func func(gokeys.Settings) } ) var debugFlag *bool // NewParser function will initiate and return the parent parser for the // gomigrate app. func NewParser(fn ...func(*Parser) Plugin) Parser { // Create new main parser object p := Parser{ Parser: argparse.NewParser(AppName, "Go app to run migration related tasks that used to be junky scripts"), Plugins: make([]Plugin, 0), } // Define the top-level arguments pinned to the gomigrate parser. debugFlag = p.Flag("", "debug", &argparse.Options{Help: "view debug level logging"}) // Register the plugin commands into the parser for _, f := range fn { p.Plugins = append(p.Plugins, f(&p)) } return p } // Run method will parse the arguments in the parser as well as range through all the // registered plugins to determine which action "Happened()" func (p *Parser) Run(version string, cfg gokeys.Settings) { // Parse input if err := p.Parse(os.Args); err != nil { // In case of error print error and print usage // This can also be done by passing -h or --help flags fmt.Print(p.Usage(color.Red.Sprint(err))) // abort if there is an error parsing arguments syscall.Exit(1) } if *debugFlag { logrus.SetLevel(logrus.DebugLevel) } var wg sync.WaitGroup for _, v := range p.Plugins { if v.CMD.Happened() { v.Func(cfg) wg.Add(1) go logToAppStats(&wg, version, getCommand(os.Args), cfg.User) } } wg.Wait() } func getCommand(args []string) string { end := 2 for i := range args[1:] { if strings.HasPrefix(args[i], "-") { end = i break } } return strings.Join(args[1:end], ".") } func logToAppStats(wg *sync.WaitGroup, version, function, username string) { defer wg.Done() stats, err := appstats.NewClient(AppName, version, AppName, false) if err != nil { logrus.Errorf("appstats.NewClient:%s", err) return } if err := stats.Event(function, username, time.Now()); err != nil { logrus.Errorf("appstats.Event:%s", err) return } logrus.Debugf("[appstats] app=%s version=v%s username=%s command=%s", AppName, version, username, function) }