github.com/grahambrereton-form3/tilt@v0.10.18/internal/cli/up.go (about) 1 package cli 2 3 import ( 4 "context" 5 "fmt" 6 "log" 7 "net/url" 8 "os" 9 "time" 10 11 "github.com/fatih/color" 12 "github.com/mattn/go-isatty" 13 "github.com/opentracing/opentracing-go" 14 "github.com/spf13/cobra" 15 "golang.org/x/sync/errgroup" 16 "k8s.io/klog" 17 18 "github.com/windmilleng/tilt/internal/analytics" 19 "github.com/windmilleng/tilt/internal/engine" 20 engineanalytics "github.com/windmilleng/tilt/internal/engine/analytics" 21 "github.com/windmilleng/tilt/internal/hud" 22 "github.com/windmilleng/tilt/internal/k8s" 23 "github.com/windmilleng/tilt/internal/output" 24 "github.com/windmilleng/tilt/internal/store" 25 "github.com/windmilleng/tilt/internal/tiltfile" 26 "github.com/windmilleng/tilt/internal/tracer" 27 "github.com/windmilleng/tilt/pkg/assets" 28 "github.com/windmilleng/tilt/pkg/logger" 29 "github.com/windmilleng/tilt/pkg/model" 30 "github.com/windmilleng/tilt/web" 31 ) 32 33 const DefaultWebHost = "localhost" 34 const DefaultWebPort = 10350 35 const DefaultWebDevPort = 46764 36 37 var updateModeFlag string = string(engine.UpdateModeAuto) 38 var webModeFlag model.WebMode = model.DefaultWebMode 39 var webPort = 0 40 var webHost = DefaultWebHost 41 var webDevPort = 0 42 var noBrowser bool = false 43 var logActionsFlag bool = false 44 45 type upCmd struct { 46 watch bool 47 traceTags string 48 hud bool 49 fileName string 50 } 51 52 func (c *upCmd) register() *cobra.Command { 53 cmd := &cobra.Command{ 54 Use: "up [<resource_name1>] [<resource_name2>] [...]", 55 Short: "stand up one or more resources (if no resource names specified, stand up all known resources specified in Tiltfile)", 56 } 57 58 cmd.Flags().BoolVar(&c.watch, "watch", true, "If true, services will be automatically rebuilt and redeployed when files change. Otherwise, each service will be started once.") 59 cmd.Flags().Var(&webModeFlag, "web-mode", "Values: local, prod. Controls whether to use prod assets or a local dev server") 60 cmd.Flags().StringVar(&updateModeFlag, "update-mode", string(engine.UpdateModeAuto), 61 fmt.Sprintf("Control the strategy Tilt uses for updating instances. Possible values: %v", engine.AllUpdateModes)) 62 cmd.Flags().StringVar(&c.traceTags, "traceTags", "", "tags to add to spans for easy querying, of the form: key1=val1,key2=val2") 63 cmd.Flags().BoolVar(&c.hud, "hud", true, "If true, tilt will open in HUD mode.") 64 cmd.Flags().BoolVar(&logActionsFlag, "logactions", false, "log all actions and state changes") 65 cmd.Flags().IntVar(&webPort, "port", DefaultWebPort, "Port for the Tilt HTTP server. Set to 0 to disable.") 66 cmd.Flags().StringVar(&webHost, "host", DefaultWebHost, "Host for the Tilt HTTP server. Set to 0.0.0.0 to listen on all interfaces.") 67 cmd.Flags().IntVar(&webDevPort, "webdev-port", DefaultWebDevPort, "Port for the Tilt Dev Webpack server. Only applies when using --web-mode=local") 68 cmd.Flags().Lookup("logactions").Hidden = true 69 cmd.Flags().StringVar(&c.fileName, "file", tiltfile.FileName, "Path to Tiltfile") 70 cmd.Flags().BoolVar(&noBrowser, "no-browser", false, "If true, web UI will not open on startup.") 71 72 return cmd 73 } 74 75 func (c *upCmd) run(ctx context.Context, args []string) error { 76 a := analytics.Get(ctx) 77 cmdUpTags := engineanalytics.CmdUpTags(map[string]string{ 78 "watch": fmt.Sprintf("%v", c.watch), 79 "mode": string(updateModeFlag), 80 }) 81 a.Incr("cmd.up", cmdUpTags.AsMap()) 82 a.IncrIfUnopted("analytics.up.optdefault") 83 defer a.Flush(time.Second) 84 85 span, ctx := opentracing.StartSpanFromContext(ctx, "Up") 86 defer span.Finish() 87 88 tags := tracer.TagStrToMap(c.traceTags) 89 90 for k, v := range tags { 91 span.SetTag(k, v) 92 } 93 94 deferred := logger.NewDeferredLogger(ctx) 95 ctx = redirectLogs(ctx, deferred) 96 97 logOutput(fmt.Sprintf("Starting Tilt (%s)…", buildStamp())) 98 99 if analytics.IsAnalyticsDisabledFromEnv() { 100 logOutput("Tilt analytics manually disabled by environment") 101 } 102 103 threads, err := wireCmdUp(ctx, a, cmdUpTags) 104 if err != nil { 105 deferred.SetOutput(deferred.Original()) 106 return err 107 } 108 109 upper := threads.upper 110 h := threads.hud 111 112 l := store.NewLogActionLogger(ctx, upper.Dispatch) 113 deferred.SetOutput(l) 114 ctx = redirectLogs(ctx, l) 115 116 if trace { 117 traceID, err := tracer.TraceID(ctx) 118 if err != nil { 119 return err 120 } 121 logger.Get(ctx).Infof("TraceID: %s", traceID) 122 } 123 124 g, ctx := errgroup.WithContext(ctx) 125 ctx, cancel := context.WithCancel(ctx) 126 defer cancel() 127 128 hudEnabled := c.hud && isatty.IsTerminal(os.Stdout.Fd()) 129 if hudEnabled { 130 err := output.CaptureAllOutput(logger.Get(ctx).Writer(logger.InfoLvl)) 131 if err != nil { 132 logger.Get(ctx).Infof("Error capturing stdout and stderr: %v", err) 133 } 134 g.Go(func() error { 135 err := h.Run(ctx, upper.Dispatch, hud.DefaultRefreshInterval) 136 return err 137 }) 138 } 139 140 g.Go(func() error { 141 defer cancel() 142 return upper.Start(ctx, args, threads.tiltBuild, c.watch, c.fileName, hudEnabled, a.UserOpt(), threads.token, string(threads.cloudAddress)) 143 }) 144 145 err = g.Wait() 146 if err != context.Canceled { 147 return err 148 } else { 149 return nil 150 } 151 } 152 153 func redirectLogs(ctx context.Context, l logger.Logger) context.Context { 154 ctx = logger.WithLogger(ctx, l) 155 log.SetOutput(l.Writer(logger.InfoLvl)) 156 klog.SetOutput(l.Writer(logger.InfoLvl)) 157 return ctx 158 } 159 160 func logOutput(s string) { 161 log.SetFlags(log.Flags() &^ (log.Ldate | log.Ltime)) 162 log.Print(color.GreenString(s)) 163 } 164 165 func provideUpdateModeFlag() engine.UpdateModeFlag { 166 return engine.UpdateModeFlag(updateModeFlag) 167 } 168 169 func provideLogActions() store.LogActionsFlag { 170 return store.LogActionsFlag(logActionsFlag) 171 } 172 173 func provideKubectlLogLevel() k8s.KubectlLogLevel { 174 return k8s.KubectlLogLevel(klogLevel) 175 } 176 177 func provideWebMode(b model.TiltBuild) (model.WebMode, error) { 178 switch webModeFlag { 179 case model.LocalWebMode, model.ProdWebMode, model.PrecompiledWebMode: 180 return webModeFlag, nil 181 case model.DefaultWebMode: 182 if b.Dev { 183 return model.LocalWebMode, nil 184 } else { 185 return model.ProdWebMode, nil 186 } 187 } 188 return "", model.UnrecognizedWebModeError(string(webModeFlag)) 189 } 190 191 func provideWebHost() model.WebHost { 192 return model.WebHost(webHost) 193 } 194 195 func provideWebPort() model.WebPort { 196 return model.WebPort(webPort) 197 } 198 199 func provideNoBrowserFlag() model.NoBrowser { 200 return model.NoBrowser(noBrowser) 201 } 202 203 func provideWebURL(webHost model.WebHost, webPort model.WebPort) (model.WebURL, error) { 204 if webPort == 0 { 205 return model.WebURL{}, nil 206 } 207 208 u, err := url.Parse(fmt.Sprintf("http://%s:%d/", webHost, webPort)) 209 if err != nil { 210 return model.WebURL{}, err 211 } 212 return model.WebURL(*u), nil 213 } 214 215 func provideAssetServer(mode model.WebMode, version model.WebVersion) (assets.Server, error) { 216 if mode == model.ProdWebMode { 217 return assets.NewProdServer(assets.ProdAssetBucket, version) 218 } 219 if mode == model.PrecompiledWebMode || mode == model.LocalWebMode { 220 path, err := web.StaticPath() 221 if err != nil { 222 return nil, err 223 } 224 pkgDir := assets.PackageDir(path) 225 if mode == model.PrecompiledWebMode { 226 return assets.NewPrecompiledServer(pkgDir), nil 227 } else { 228 return assets.NewDevServer(pkgDir, model.WebDevPort(webDevPort)) 229 } 230 } 231 return nil, model.UnrecognizedWebModeError(string(mode)) 232 }