| OLD | NEW |
| (Empty) |
| 1 // Copyright 2016 The LUCI Authors. All rights reserved. | |
| 2 // Use of this source code is governed under the Apache License, Version 2.0 | |
| 3 // that can be found in the LICENSE file. | |
| 4 | |
| 5 package main | |
| 6 | |
| 7 import ( | |
| 8 "flag" | |
| 9 "os" | |
| 10 "os/signal" | |
| 11 | |
| 12 "github.com/maruel/subcommands" | |
| 13 "golang.org/x/net/context" | |
| 14 | |
| 15 "github.com/luci/luci-go/client/authcli" | |
| 16 "github.com/luci/luci-go/common/auth" | |
| 17 "github.com/luci/luci-go/common/cli" | |
| 18 log "github.com/luci/luci-go/common/logging" | |
| 19 "github.com/luci/luci-go/common/logging/gologger" | |
| 20 ) | |
| 21 | |
| 22 type application struct { | |
| 23 cli.Application | |
| 24 | |
| 25 authFlags authcli.Flags | |
| 26 layoutPath string | |
| 27 workers int | |
| 28 | |
| 29 layout deployLayout | |
| 30 tools tools | |
| 31 } | |
| 32 | |
| 33 func (a *application) addFlags(fs *flag.FlagSet) { | |
| 34 fs.StringVar(&a.layoutPath, "layout", a.layoutPath, | |
| 35 "Path to the base layout file.") | |
| 36 fs.IntVar(&a.workers, "workers", 0, | |
| 37 "Maximum number of workers to use. If <= 0, no limit will be app
lied.") | |
| 38 } | |
| 39 | |
| 40 func (a *application) runWork(c context.Context, fn func(*work) error) error { | |
| 41 return runWork(c, a.workers, &a.tools, fn) | |
| 42 } | |
| 43 | |
| 44 func mainImpl(args []string) int { | |
| 45 authOptions := auth.Options{ | |
| 46 Scopes: []string{ | |
| 47 "https://www.googleapis.com/auth/cloud-platform", | |
| 48 }, | |
| 49 } | |
| 50 | |
| 51 c := gologger.StdConfig.Use(context.Background()) | |
| 52 a := application{ | |
| 53 Application: cli.Application{ | |
| 54 Name: os.Args[0], | |
| 55 Title: "LUCI Deployment Tool", | |
| 56 Context: func(context.Context) context.Context { return
c }, | |
| 57 Commands: []*subcommands.Command{ | |
| 58 subcommands.CmdHelp, | |
| 59 &cmdCheckout, | |
| 60 &cmdDeploy, | |
| 61 &cmdManage, | |
| 62 | |
| 63 authcli.SubcommandLogin(authOptions, "auth-login
"), | |
| 64 authcli.SubcommandLogout(authOptions, "auth-logo
ut"), | |
| 65 authcli.SubcommandInfo(authOptions, "auth-info")
, | |
| 66 }, | |
| 67 }, | |
| 68 } | |
| 69 logFlags := log.Config{ | |
| 70 Level: log.Warning, | |
| 71 } | |
| 72 | |
| 73 var fs flag.FlagSet | |
| 74 logFlags.AddFlags(&fs) | |
| 75 a.authFlags.Register(&fs, authOptions) | |
| 76 a.addFlags(&fs) | |
| 77 if err := fs.Parse(args); err != nil { | |
| 78 log.WithError(err).Errorf(c, "Failed to parse flags.") | |
| 79 return 1 | |
| 80 } | |
| 81 c = logFlags.Set(c) | |
| 82 | |
| 83 // Install a signal handler to cancel everything in response to a Ctrl+C
. | |
| 84 var cancelFunc context.CancelFunc | |
| 85 c, cancelFunc = context.WithCancel(c) | |
| 86 signalC := make(chan os.Signal, 1) | |
| 87 signal.Notify(signalC, os.Interrupt) | |
| 88 go func(c context.Context) { | |
| 89 signalled := false | |
| 90 for range signalC { | |
| 91 if !signalled { | |
| 92 signalled = true | |
| 93 | |
| 94 // First '^C'; soft-terminate | |
| 95 log.Infof(c, "Received Control-C (keyboard inter
rupt), shutting down. Interrupt again for immediate exit.") | |
| 96 cancelFunc() | |
| 97 } else { | |
| 98 // Multiple '^C'; terminate immediately | |
| 99 os.Exit(1) | |
| 100 } | |
| 101 } | |
| 102 }(c) | |
| 103 defer func() { | |
| 104 signal.Stop(signalC) | |
| 105 close(signalC) | |
| 106 }() | |
| 107 | |
| 108 // Load our layout file. | |
| 109 if err := a.layout.load(c, a.layoutPath); err != nil { | |
| 110 logError(c, err, "Failed to load layout file from [%s]", a.layou
tPath) | |
| 111 return 1 | |
| 112 } | |
| 113 | |
| 114 // Run our subcommand (and parse subcommand flags). | |
| 115 return subcommands.Run(&a, fs.Args()) | |
| 116 } | |
| 117 | |
| 118 func main() { | |
| 119 os.Exit(mainImpl(os.Args[1:])) | |
| 120 } | |
| OLD | NEW |