X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;f=main.go;h=ee0def8c97268c0278d00ab99be37843273cc6f0;hb=407b8190b86e31f5e1fbd31fae30dcbf8be36fe6;hp=eec23da46f5205ffc99b280d04d348f737f151c3;hpb=18893f9ed5f003133fad06b42a381effe4017bab;p=src%2Fxds%2Fxds-cli.git diff --git a/main.go b/main.go index eec23da..ee0def8 100644 --- a/main.go +++ b/main.go @@ -1,4 +1,23 @@ -// xds-cli: command line tool used to control / interface X(cross) Development System. +/* + * Copyright (C) 2017 "IoT.bzh" + * Author Sebastien Douheret + * + * 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. + * + * + * xds-cli: command line tool used to control / interface X(cross) Development System. + */ + package main import ( @@ -10,6 +29,7 @@ import ( "text/tabwriter" "github.com/Sirupsen/logrus" + "github.com/iotbzh/xds-agent/lib/xaapiv1" common "github.com/iotbzh/xds-common/golib" "github.com/joho/godotenv" socketio_client "github.com/sebd71/go-socket.io-client" @@ -37,7 +57,7 @@ var AppSubVersion = "unknown-dev" // Application details const ( - appCopyright = "Apache-2.0" + appCopyright = "Copyright (C) 2017 IoT.bzh - Apache-2.0" defaultLogLevel = "error" ) @@ -62,7 +82,7 @@ func exitError(code int, f string, a ...interface{}) { // main func main() { - EnvConfFileMap := make(map[string]string) + var earlyDebug []string // Allow to set app name from cli (useful for debugging) if AppName == "" { @@ -80,9 +100,9 @@ func main() { Setting of global options is driven either by environment variables or by command line options or using a config file knowning that the following priority order is used: 1. use option value (for example --url option), - 2. else use variable 'XDS_xxx' (for example 'XDS_SERVER_URL' variable) when a + 2. else use variable 'XDS_xxx' (for example 'XDS_AGENT_URL' variable) when a config file is specified with '--config|-c' option, - 3. else use 'XDS_xxx' (for example 'XDS_SERVER_URL') environment variable. + 3. else use 'XDS_xxx' (for example 'XDS_AGENT_URL') environment variable. Examples: # Get help of 'projects' sub-command @@ -143,10 +163,16 @@ func main() { Value: defaultLogLevel, }, cli.StringFlag{ - Name: "url", + Name: "url, u", + EnvVar: "XDS_AGENT_URL", + Value: "localhost:8800", + Usage: "local XDS agent url", + }, + cli.StringFlag{ + Name: "url-server, us", EnvVar: "XDS_SERVER_URL", - Value: "localhost:8000", - Usage: "remote XDS server url", + Value: "", + Usage: "overwrite remote XDS server url (default value set in xds-agent-config.json file)", }, cli.BoolFlag{ Name: "timestamp, ts", @@ -163,13 +189,59 @@ func main() { initCmdExec(&app.Commands) initCmdMisc(&app.Commands) + // Add --config option to all commands to support --config option either before or after command verb + // IOW support following both syntaxes: + // xds-cli exec --config myprj.conf ... + // xds-cli --config myprj.conf exec ... + for i, cmd := range app.Commands { + if len(cmd.Flags) > 0 { + app.Commands[i].Flags = append(cmd.Flags, cli.StringFlag{Hidden: true, Name: "config, c"}) + } + for j, subCmd := range cmd.Subcommands { + app.Commands[i].Subcommands[j].Flags = append(subCmd.Flags, cli.StringFlag{Hidden: true, Name: "config, c"}) + } + } + sort.Sort(cli.FlagsByName(app.Flags)) sort.Sort(cli.CommandsByName(app.Commands)) + // Early and manual processing of --config option in order to set XDS_xxx + // variables before parsing of option by app cli + confFile := os.Getenv("XDS_CONFIG") + for idx, a := range os.Args[1:] { + if a == "-c" || a == "--config" || a == "-config" { + confFile = os.Args[idx+2] + break + } + } + + // Load config file if requested + if confFile != "" { + earlyDebug = append(earlyDebug, fmt.Sprintf("confFile detected: %v", confFile)) + if !common.Exists(confFile) { + exitError(1, "Error env config file not found") + } + // Load config file variables that will overwrite env variables + err := godotenv.Overload(confFile) + if err != nil { + exitError(1, "Error loading env config file "+confFile) + } + + // Keep confFile settings in a map + EnvConfFileMap, err = godotenv.Read(confFile) + if err != nil { + exitError(1, "Error reading env config file "+confFile) + } + earlyDebug = append(earlyDebug, fmt.Sprintf("EnvConfFileMap: %v", EnvConfFileMap)) + } + app.Before = func(ctx *cli.Context) error { var err error - // Don't init anything when user wants help + // Don't init anything when no argument or help option is set + if ctx.NArg() == 0 { + return nil + } for _, a := range ctx.Args() { switch a { case "-h", "--h", "-help", "--help": @@ -177,24 +249,6 @@ func main() { } } - // Load config file if requested - confFile := ctx.String("config") - if confFile != "" { - if !common.Exists(confFile) { - exitError(1, "Error env config file not found") - } - // Load config file variables that will overwrite env variables - err := godotenv.Overload(confFile) - if err != nil { - exitError(1, "Error loading env config file "+confFile) - } - // Keep confFile settings in a map - EnvConfFileMap, err = godotenv.Read(confFile) - if err != nil { - exitError(1, "Error reading env config file "+confFile) - } - } - loglevel := ctx.String("log") // Set logger level and formatter if Log.Level, err = logrus.ParseLevel(loglevel); err != nil { @@ -204,7 +258,10 @@ func main() { Log.Formatter = &logrus.TextFormatter{} Log.Infof("%s version: %s", AppName, app.Version) - Log.Debugf("Environment: %v", os.Environ()) + for _, str := range earlyDebug { + Log.Infof("%s", str) + } + Log.Debugf("\nEnvironment: %v\n", os.Environ()) if err = XdsConnInit(ctx); err != nil { // Directly call HandleExitCoder to avoid to print help (ShowAppHelp) @@ -228,13 +285,26 @@ func XdsConnInit(ctx *cli.Context) error { var err error // Define HTTP and WS url - baseURL := ctx.String("url") - if !strings.HasPrefix(ctx.String("url"), "http://") { - baseURL = "http://" + ctx.String("url") + agentURL := ctx.String("url") + serverURL := ctx.String("url-server") + + // Allow to only set port number + if match, _ := regexp.MatchString("^([0-9]+)$", agentURL); match { + agentURL = "http://localhost:" + ctx.String("url") + } + if match, _ := regexp.MatchString("^([0-9]+)$", serverURL); match { + serverURL = "http://localhost:" + ctx.String("url-server") + } + // Add http prefix if missing + if agentURL != "" && !strings.HasPrefix(agentURL, "http://") { + agentURL = "http://" + agentURL + } + if serverURL != "" && !strings.HasPrefix(serverURL, "http://") { + serverURL = "http://" + serverURL } // Create HTTP client - Log.Debugln("Connect HTTP client on ", baseURL) + Log.Debugln("Connect HTTP client on ", agentURL) conf := common.HTTPClientConfig{ URLPrefix: "/api/v1", HeaderClientKeyName: "Xds-Agent-Sid", @@ -244,19 +314,20 @@ func XdsConnInit(ctx *cli.Context) error { LogLevel: common.HTTPLogLevelWarning, } - HTTPCli, err = common.HTTPNewClient(baseURL, conf) + HTTPCli, err = common.HTTPNewClient(agentURL, conf) if err != nil { errmsg := err.Error() if m, err := regexp.MatchString("Get http.?://", errmsg); m && err == nil { i := strings.LastIndex(errmsg, ":") - errmsg = "Cannot connection to " + baseURL + errmsg[i:] + errmsg = "Cannot connection to " + agentURL + errmsg[i:] } return cli.NewExitError(errmsg, 1) } HTTPCli.SetLogLevel(ctx.String("loglevel")) + Log.Infoln("HTTP session ID : ", HTTPCli.GetClientID()) // Create io Websocket client - Log.Debugln("Connecting IO.socket client on ", baseURL) + Log.Debugln("Connecting IO.socket client on ", agentURL) opts := &socketio_client.Options{ Transport: "websocket", @@ -264,7 +335,7 @@ func XdsConnInit(ctx *cli.Context) error { } opts.Header["XDS-AGENT-SID"] = []string{HTTPCli.GetClientID()} - IOsk, err = socketio_client.NewClient(baseURL, opts) + IOsk, err = socketio_client.NewClient(agentURL, opts) if err != nil { return cli.NewExitError("IO.socket connection error: "+err.Error(), 1) } @@ -276,6 +347,27 @@ func XdsConnInit(ctx *cli.Context) error { ctx.App.Metadata["httpCli"] = HTTPCli ctx.App.Metadata["ioskCli"] = IOsk + // Display version in logs (debug helpers) + ver := xaapiv1.XDSVersion{} + if err := XdsVersionGet(&ver); err != nil { + return cli.NewExitError("ERROR while retrieving XDS version: "+err.Error(), 1) + } + Log.Infof("XDS Agent/Server version: %v", ver) + + // Get current config and update connection to server when needed + xdsConf := xaapiv1.APIConfig{} + if err := XdsConfigGet(&xdsConf); err != nil { + return cli.NewExitError("ERROR while getting XDS config: "+err.Error(), 1) + } + svrCfg := xdsConf.Servers[XdsServerIndexGet()] + if serverURL != "" && (svrCfg.URL != serverURL || !svrCfg.Connected) { + svrCfg.URL = serverURL + svrCfg.ConnRetry = 10 + if err := XdsConfigSet(xdsConf); err != nil { + return cli.NewExitError("ERROR while updating XDS server URL: "+err.Error(), 1) + } + } + return nil }