package cli import ( "flag" "fmt" "path/filepath" "strings" "git.vakhrushev.me/av/convy/internal/manifest" "git.vakhrushev.me/av/convy/internal/project" ) // convy list answers two questions in one view: what this repository takes and // what the suite has that it does not. The second half is the reason the // command reaches the suite at all — a listing of the manifest alone is the // manifest, and reading it needs no tool. func runList(env Env, args []string) ExitCode { fs := flag.NewFlagSet("convy list", flag.ContinueOnError) fs.SetOutput(env.Err) root := fs.String("root", "", "root of the project; it is looked up upwards by default") forComponent := fs.String("for", "", "component to show; every one of them by default") if err := fs.Parse(args); err != nil { return Usage } if code := noStrayArgs(env, "convy list", fs.Args()); code != OK { return code } o, code := openProject(env, *root) if code != OK { return code } defer o.Close() names, code := components(env, o.Manifest, *forComponent) if code != OK { return code } fmt.Fprintf(env.Out, "source %s\n", o.Manifest.Source) fmt.Fprintf(env.Out, "%s, language version %d (%s)\n", plural(len(o.Suite.Manifest.LiveTopics()), "topic"), o.Suite.Manifest.Language.Version, o.Suite.Manifest.Language.Lang) for _, name := range names { c := o.Manifest.Components[name] fmt.Fprintf(env.Out, "\n%s — %s%s\n", name, c.Dir, axisOf(c)) listComponent(env, o, c) } return OK } func listComponent(env Env, o *opened, c manifest.Component) { if len(c.Topics) == 0 { fmt.Fprintln(env.Out, " subscribed to nothing yet") } for _, topic := range c.Topics { if !o.Suite.Manifest.TopicLive(topic) { fmt.Fprintf(env.Out, " %-20s the suite declares no such topic any more\n", topic) continue } taken, _ := o.Suite.Assemble(topic, project.Axis(c)) file := filepath.ToSlash(filepath.Join(c.Dir, topic+".md")) mark := " " if !exists(filepath.Join(o.Root, filepath.FromSlash(file))) { mark = "!" } fmt.Fprintf(env.Out, "%s %-20s %-16s %s\n", mark, topic, plural(len(taken), "layer"), o.Suite.Manifest.Topics.Live[topic]) if mark == "!" { fmt.Fprintf(env.Out, " %-20s subscribed, and no file: convy pull assembles it\n", "") } } var free []string for _, topic := range o.Suite.Manifest.LiveTopics() { if !c.Subscribed(topic) { free = append(free, topic) } } if len(free) == 0 { return } fmt.Fprintln(env.Out, "\n not taken:") for _, topic := range free { taken, _ := o.Suite.Assemble(topic, project.Axis(c)) if len(taken) == 0 { fmt.Fprintf(env.Out, "· %-20s %-16s %s\n", topic, "no layer fits", o.Suite.Manifest.Topics.Live[topic]) continue } fmt.Fprintf(env.Out, "· %-20s %-16s %s\n", topic, plural(len(taken), "layer"), o.Suite.Manifest.Topics.Live[topic]) } } // axisOf describes the axis of a component the way the suite writes it. func axisOf(c manifest.Component) string { var parts []string if len(c.Lang) > 0 { parts = append(parts, "lang="+strings.Join(c.Lang, ",")) } if len(c.Stack) > 0 { parts = append(parts, "stack="+strings.Join(c.Stack, ",")) } if len(parts) == 0 { return "" } return " (" + strings.Join(parts, " ") + ")" }