func pull(c *cli.Context) { all := c.Bool("all") expectedArgs := 1 if all { expectedArgs = 0 } if l := len(c.Args()); l != expectedArgs { common.OSErrf("expected %d argument(s), got %d", expectedArgs, l) return } if all { fmt.Println("pulling all tenets found in .lingo ...") if err := pullAll(c); err != nil { common.OSErrf(err.Error()) } return } // TODO(waigani) It doesn't make sense to have both registry and source. // Either registry for docker or source for binary. reg := c.String("registry") source := c.String("source") driver := c.String("driver") if err := pullOne(c, c.Args().First(), driver, reg, source); err != nil { common.OSErrf(err.Error()) } }
// TenetCMD is a fallthrough CMD which treats command as the tenet name and // passes through any arguments to the tenet. func TenetCMD(ctx *cli.Context, command string) { var commandIsTenet bool var cfg common.TenetConfig // Does the command match an installed tenet? for _, cfg = range listTenets(ctx) { if command == cfg.Name { commandIsTenet = true break } } if !commandIsTenet { fmt.Println("command not found") return } tnCMDs, err := newTenetCMDs(ctx, cfg) if err != nil { common.OSErrf(err.Error()) return } defer tnCMDs.closeService() if err := tnCMDs.run(); err != nil { common.OSErrf(err.Error()) return } return }
func reviewAction(ctx *cli.Context) { opts := review.Options{ Files: ctx.Args(), Diff: ctx.Bool("diff"), SaveToFile: ctx.String("save"), KeepAll: ctx.Bool("keep-all"), } issues, err := review.Review(opts) if err != nil { common.OSErrf(err.Error()) return } // TODO(waigani) I'm not happy that we're doing this here, can't find a // better place though. saveToFile := ctx.String("save") if saveToFile != "" { err := review.Save(saveToFile, issues) if err != nil { common.OSErrf("could not save to file: %s", err.Error()) return } fmt.Printf("review saved to %s\n", saveToFile) } // TODO(waigani) make more informative // TODO(waigani) if !ctx.String("quiet") fmt.Printf("Done! Found %d issues \n", len(issues)) }
func pull(c *cli.Context) { all := c.Bool("all") expectedArgs := 1 if all { expectedArgs = 0 } if l := len(c.Args()); l != expectedArgs { common.OSErrf("expected %d argument(s), got %d", expectedArgs, l) return } if all { fmt.Println("pulling all tenets found in .lingo ...") if err := pullAll(c); err != nil { common.OSErrf(err.Error()) } return } reg := c.String("registry") driver := c.String("driver") if err := pullOne(c, c.Args().First(), driver, reg); err != nil { common.OSErrf(err.Error()) } }
func add(c *cli.Context) { if l := len(c.Args()); l != 1 { common.OSErrf("expected 1 argument, got %d", l) return } cfgPath, err := common.TenetCfgPath(c) if err != nil { common.OSErrf("reading config file: %s", err.Error()) return } cfg, err := common.BuildConfig(cfgPath, common.CascadeNone) if err != nil { common.OSErrf("reading config file: %s", err.Error()) return } imageName := c.Args().First() groupName := c.String("group") g, err := cfg.FindTenetGroup(groupName) if err == nil && common.HasTenet(g.Tenets, imageName) { common.OSErrf(`error: tenet "%s" already added`, imageName) return } // TODO(waigani) DEMOWARE. This will panic with wrong input. Matt didn't // your first PR bring in options? opts := map[string]interface{}{} if optStr := c.String("options"); optStr != "" { // TODO: DEMOWARE. Only set one option at a time to allow spaces in value //for _, part := range strings.Split(optStr, " ") { p := strings.Split(optStr, "=") opts[p[0]] = p[1] //} } var registry string driver := c.String("driver") if driver == "docker" { registry = c.String("registry") } cfg.AddTenet(common.TenetConfig{ Name: imageName, Driver: driver, Registry: registry, Options: opts, }, groupName) if err := common.WriteConfigFile(c, cfg); err != nil { common.OSErrf(err.Error()) return } // TODO(waigani) open an interactive shell, prompt to set options. }
func copr(c *cli.Context) { cliArgs := c.Args() if err := common.ExactArgs(c, 1); err != nil { common.OSErrf(err.Error()) return } repoPath, err := exec.Command("git", "rev-parse", "--show-toplevel").Output() if err != nil { common.OSErrf(err.Error()) return } repo := path.Base(strings.Trim(string(repoPath), "\n")) var fetchAll string if !c.Bool("skip-fetch-all") { fetchAll = "git fetch --all" } argParts := strings.Split(cliArgs[0], ":") args := map[string]string{ "User": argParts[0], "Repo": repo, "Branch": argParts[1], "Base": strings.Replace(c.String("base"), ":", "/", -1), "FetchAll": fetchAll, "Host": c.String("host"), } bashScript, err := util.FormatOutput(args, coprcmd) if err != nil { common.OSErrf(err.Error()) return } if c.Bool("dry-run") { fmt.Println("execute the following bash script:") fmt.Println(bashScript) return } cmd := exec.Command("bash", "-c", bashScript) cmd.Stderr = os.Stderr cmd.Stdout = os.Stdout err = cmd.Run() if err != nil { common.OSErrf(err.Error()) return } }
func rbAction(ctx *cli.Context) { if err := rb(ctx); err != nil { common.OSErrf(err.Error()) return } fmt.Println("Done! Review sent to Review Board.") }
func validate(c *cli.Context) { if err := common.ExactArgs(c, 1); err != nil { common.OSErrf(err.Error()) return } // imageName := c.Args().First() }
func listTenets(c *cli.Context) []common.TenetConfig { cfgPath, err := common.TenetCfgPath(c) if err != nil { if _, ok := err.(*os.PathError); ok { // For missing config files, there are just no tenets return nil } // For malformed config show the error to the user common.OSErrf("could not read configuration: %s", err.Error()) return nil } cfg, err := common.BuildConfig(cfgPath, common.CascadeNone) if err != nil { common.OSErrf("could not read configuration: %s", err.Error()) return nil } return cfg.AllTenets() }
func editConfigAction(ctx *cli.Context) { cfg := config.DefaultsCfgFile if args := ctx.Args(); len(args) > 0 { cfg = args[0] + ".yaml" } if err := config.Edit(cfg, "vi"); err != nil { common.OSErrf(err.Error()) } }
func buildAction(ctx *cli.Context) { drivers := ctx.Args() if len(drivers) == 0 { drivers = allDrivers } if err := build(drivers, ctx.Bool("all")); err != nil { common.OSErrf(err.Error()) } }
func docs(c *cli.Context) { fmt.Println("Opening tenet documentation in a new browser window ...") var mdBuf bytes.Buffer if err := writeTenetDoc(c, "", &mdBuf); err != nil { common.OSErrf("%v", err) return } // Render markdown to HTML, and sanitise it to protect from // malicious tenets. htmlUnsafe := blackfriday.MarkdownBasic(mdBuf.Bytes()) html := bluemonday.UGCPolicy().SanitizeBytes(htmlUnsafe) if err := browser.OpenReader(bytes.NewReader(html)); err != nil { common.OSErrf("opening docs in browser: %v", err) return } }
func defaultDriver() string { cfg, err := config.Defaults() if err != nil { return "binary" } driver := cfg.Tenet.Driver if driver != "binary" && driver != "docker" { common.OSErrf("invalid driver default: %q", driver) } return driver }
func remove(c *cli.Context) { if l := len(c.Args()); l != 1 { common.OSErrf("error: expected 1 argument, got %d", l) return } cfgPath, err := common.TenetCfgPath(c) if err != nil { common.OSErrf("reading config file: %s", err.Error()) return } cfg, err := common.BuildConfig(cfgPath, common.CascadeNone) if err != nil { common.OSErrf("reading config file: %s", err.Error()) return } imageName := c.Args().First() if !cfg.HasTenet(imageName) { common.OSErrf(`error: tenet "%s" not found in %q`, imageName, c.GlobalString(common.TenetCfgFlg.Long)) return } if err := cfg.RemoveTenet(imageName, c.String("group")); err != nil { common.OSErrf(err.Error()) return } if err := common.WriteConfigFile(c, cfg); err != nil { common.OSErrf(err.Error()) return } }
func writeDoc(c *cli.Context) { outputPath := c.String("output") if dir, _ := path.Split(outputPath); dir != "" { err := os.MkdirAll(dir, 0775) if err != nil { common.OSErrf(err.Error()) return } } outputFile, err := os.Create(outputPath) if err != nil { common.OSErrf(err.Error()) return } defer outputFile.Close() if err := writeTenetDoc(c, c.String("template"), outputFile); err != nil { common.OSErrf(err.Error()) return } fmt.Printf("Tenet documentation written to %s\n", outputFile.Name()) }
func push(ctx *cli.Context) { // TODO(waigani) a lot of this code is to support multiple drivers. It's // copied from build. It's left so we can easily add remote. We just hard // code to docker for now. if len(ctx.Args()) > 0 { common.OSErrf("push takes no arguments") } // drivers := ctx.Args() // if len(drivers) == 0 { // drivers = allDrivers // } drivers := []string{"docker"} lingofiles, err := getLingoFiles(ctx.Bool("all")) if err != nil { common.OSErrf(err.Error()) return } fn := len(lingofiles) if fn == 0 { util.Printf("WARNING tenet not built. No %s found.\n", common.Lingofile) return } // set up drivers, waitgroups and progress bars allErrsc := make(chan error) allWaits := sync.WaitGroup{} dn := len(drivers) allWaits.Add(dn) driverWaits := make(map[string]*bt.DriverWait, dn) for _, driver := range drivers { bar := pb.New(fn) bar.Prefix(driver + " ") start := &sync.WaitGroup{} start.Add(fn) end := &sync.WaitGroup{} end.Add(fn) driverWaits[driver] = &bt.DriverWait{ Start: start, End: end, Bar: bar, } errsc := make(chan error) go func(wg *sync.WaitGroup, errc chan error) { wg.Wait() bar.FinishPrint("Success! All " + driver + " tenets built.") close(errsc) allWaits.Done() }(end, errsc) go func(errsc chan error) { for err := range errsc { allErrsc <- err } }(errsc) } // print progress bars to user for driver, dw := range driverWaits { go func(dw *bt.DriverWait) { dw.Start.Wait() msg := "The %s tenet is being pushed ..." if fn > 0 { msg = "All %s tenets are being pushed ..." } util.Printf(msg, driver) dw.Bar.Start() }(dw) } // start building all tenets for _, f := range lingofiles { go func(f string) { errs := pushTenet(f, driverWaits) for _, err := range errs { allErrsc <- err } }(f) } // wait for all results and print errors at the end go func() { allWaits.Wait() close(allErrsc) }() var errs []error for err := range allErrsc { errs = append(errs, err) } // util.NoPrint = false for _, err := range errs { util.Printf("push error: %v\n", err) } }
// TODO(waigani) add more user output func build(ctx *cli.Context) { drivers := ctx.Args() if len(drivers) == 0 { drivers = allDrivers } lingofiles, err := getLingofiles(ctx) if err != nil { common.OSErrf(err.Error()) return } fn := len(lingofiles) if fn == 0 { util.Printf("WARNING tenet not built. No %s found.\n", lingofile) return } // set up drivers, waitgroups and progress bars allErrsc := make(chan error) allWaits := sync.WaitGroup{} dn := len(drivers) allWaits.Add(dn) driverWaits := make(map[string]*driverWait, dn) for _, driver := range drivers { bar := pb.New(fn) bar.Prefix(driver + " ") start := &sync.WaitGroup{} start.Add(fn) end := &sync.WaitGroup{} end.Add(fn) driverWaits[driver] = &driverWait{ start: start, end: end, bar: bar, } errsc := make(chan error) go func(wg *sync.WaitGroup, errc chan error) { wg.Wait() bar.FinishPrint("Success! All " + driver + " tenets built.") close(errsc) allWaits.Done() }(end, errsc) go func(errsc chan error) { for err := range errsc { allErrsc <- err } }(errsc) } // print progress bars to user for driver, dw := range driverWaits { go func(dw *driverWait) { dw.start.Wait() msg := "The %s tenet has started to build ..." if fn > 0 { msg = "All %s tenets have started to build ..." } util.Printf(msg, driver) dw.bar.Start() }(dw) } // start building all tenets for _, f := range lingofiles { go func(f string) { errs := buildTenet(f, driverWaits) for _, err := range errs { allErrsc <- err } }(f) } // wait for all results and print errors at the end go func() { allWaits.Wait() close(allErrsc) }() var errs []error for err := range allErrsc { errs = append(errs, err) } // util.NoPrint = false for _, err := range errs { util.Printf("build error: %v\n", err) } }