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 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 which(c *cli.Context) { path, err := common.TenetCfgPath(c) if err != nil { if os.IsNotExist(err) { // TODO(waigani) check for error not found. Throw unexpected errors. fmt.Println(common.ErrMissingDotLingo.Error()) } else { fmt.Println(err) } return } fmt.Println(path) }
func edit(c *cli.Context) { cfg, err := common.TenetCfgPath(c) if err != nil { fmt.Println(err) return } cmd, err := util.OpenFileCmd(c.String("editor"), cfg, 0) if err != nil { fmt.Println(err) return } cmd.Run() }
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 BeforeCMD(c *cli.Context) error { var currentCMDName string var flags []string args := c.Args() if args.Present() { currentCMDName = args.First() flags = args.Tail() } if needsLingoHome(currentCMDName, flags) { ensureLingoHome() } // ensure we have a .lingo file if needsDotLingo(currentCMDName, flags) { if cfgPath, _ := common.TenetCfgPath(c); cfgPath == "" { return errors.Wrap(common.ErrMissingDotLingo, errors.New("ui")) } } return nil }
// Pull all tenets from config using assigned drivers. func pullAll(c *cli.Context) error { cfgPath, err := common.TenetCfgPath(c) if err != nil { return err } cfg, err := common.BuildConfig(cfgPath, common.CascadeBoth) if err != nil { return err } ts, err := common.Tenets(c, cfg) if err != nil { return err } for _, t := range ts { // TODO(waigani) don't return on err, collect errs and report at end err = t.Pull(c.Bool("update")) if err != nil { return err } } return nil }
func writeTenetDoc(c *cli.Context, src string, w io.Writer) error { // Find every applicable tenet for this project cfgPath, err := common.TenetCfgPath(c) if err != nil { return err } cfg, err := common.BuildConfig(cfgPath, common.CascadeUp) if err != nil { return err } r := strings.NewReplacer("/", "_") // Add the description of every tenet to the var map and special All array // Add keys for each tenet group name // DEMOWARE: This structure could be a lot simpler type result struct { name string template string err error } var wg sync.WaitGroup var ts []TenetMeta var results []result for _, group := range cfg.TenetGroups { for range group.Tenets { results = append(results, result{ name: r.Replace(group.Name), }) } } var i int for _, group := range cfg.TenetGroups { for _, tenetCfg := range group.Tenets { wg.Add(1) go func(group common.TenetGroup, tenetCfg common.TenetConfig, result *result) { defer wg.Done() t, err := common.NewTenet(tenetCfg) if err != nil { result.err = err return } s, err := t.OpenService() if err != nil { result.err = err return } defer s.Close() info, err := s.Info() if err != nil { result.err = err return } d, err := renderedDescription(info, tenetCfg) if err != nil { result.err = err return } ts = append(ts, TenetMeta{ VarName: r.Replace(tenetCfg.Name), GroupName: r.Replace(group.Name), Description: d, }) result.template = group.Template }(group, tenetCfg, &results[i]) i++ } } wg.Wait() // If any of the tenets could not be rendered, return an error now. var errs []error for _, result := range results { if result.err != nil { errs = append(errs, result.err) } } switch len(errs) { case 0: case 1: return errs[0] default: errorStrings := make([]string, len(errs)) for i, err := range errs { errorStrings[i] = err.Error() } return errors.New(strings.Join(errorStrings, "\n")) } // Make the description available in multiple places: // Top level template // ├── All (array) // │ ├── desc1 // │ └── desc2 // ├── Groups (array) // │ ├── renderedGroup1 // │ └── renderedGroup2 // ├── tenetName1 (string) desc1 // ├── tenetName2 (string) desc2 // ├── groupName1 (string) renderedGroup1 // └── groupName2 (string) renderedGroup2 // // Group template // ├── All (array) // │ └── desc1 // ├── GroupName (string) name from config // └── tenetName1 (string) desc1 // Render groups first renderedGroups := make(map[string]string) for _, result := range results { g := make(map[string]interface{}) g["All"] = []string{} g["GroupName"] = result.name for _, tm := range ts { if tm.GroupName == result.name { g["All"] = append(g["All"].([]string), tm.Description) g[tm.VarName] = tm.Description } } tpl, err := makeTemplate(result.template, defaultGroupTemplate) if err != nil { return err } var rg bytes.Buffer if err = tpl.Execute(&rg, g); err != nil { return err } renderedGroups[result.name] = rg.String() } v := make(map[string]interface{}) v["All"] = []string{} v["Groups"] = renderedGroups for _, tm := range ts { v["All"] = append(v["All"].([]string), tm.Description) v[tm.VarName] = tm.Description for _, result := range results { v[result.name] = renderedGroups[result.name] } } if src == "" { src = cfg.Template } tpl, err := makeTemplate(src, defaultTemplate) if err != nil { return err } return tpl.Execute(w, v) }