Beispiel #1
0
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
	}
}
Beispiel #2
0
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.
}
Beispiel #3
0
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)
}
Beispiel #4
0
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()
}
Beispiel #5
0
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()
}
Beispiel #6
0
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
}
Beispiel #7
0
// 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
}
Beispiel #8
0
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)
}