Documentation ¶
Overview ¶
SPDX-License-Identifier: Apache-2.0 Copyright © 2021 Roberto Hidalgo <milpa@un.rob.mx>
SPDX-License-Identifier: Apache-2.0 Copyright © 2021 Roberto Hidalgo <milpa@un.rob.mx>
SPDX-License-Identifier: Apache-2.0 Copyright © 2021 Roberto Hidalgo <milpa@un.rob.mx>
Index ¶
Constants ¶
This section is empty.
Variables ¶
View Source
var AfterHelp = os.Exit
View Source
var CommandTree = &command.Command{ Path: []string{"__command_tree"}, Hidden: true, Summary: "Outputs a representation of the command tree at a given PREFIX", Description: `Prints out command names and descriptions, or optionally all properties as ﹅json﹅ or ﹅yaml﹅. ## Examples ﹅﹅﹅sh # print all known subcommands ` + runtime.Executable + ` __command_tree # print a tree of "` + runtime.Executable + ` itself" sub-commands ` + runtime.Executable + ` __command_tree # print out all commands, skipping groups ` + runtime.Executable + ` __command_tree --template '{{ if (not (eq .Meta.Kind "virtual")) }}{{ .FullName }}'$'\n''{{ end }}' # get all commands as a json tree ` + runtime.Executable + ` __command_tree --output json # same, but as the yaml representation of this command itself ` + runtime.Executable + ` __command_tree --output json itself command-tree ﹅﹅﹅`, Arguments: command.Arguments{ { Name: "prefix", Description: "The prefix to traverse the command tree from", Variadic: true, Default: []string{}, }, }, Options: command.Options{ "depth": &command.Option{ Default: 15, Type: command.ValueTypeInt, Description: "The maximum depth to search for commands", }, "format": &command.Option{ Default: "text", Description: "The format to output results in", Values: &command.ValueSource{ Static: &([]string{"yaml", "json", "text", "autocomplete"}), }, }, "template": &command.Option{ Default: "{{ .Name }} - {{ .Summary }}\n", Description: "a go-template to apply to every command", }, }, Action: func(cmd *command.Command) error { args := cmd.Arguments[0].ToValue().([]string) base, remainingArgs, err := cmd.Cobra.Root().Find(args) if err != nil { return err } if len(remainingArgs) > 0 && len(remainingArgs) == len(args) { return nil } depth := cmd.Options["depth"].ToValue().(int) format := cmd.Options["format"].ToString() ctLog.Debugf("looking for commands at %s depth: %d", base.Name(), depth) tree.Build(base, depth) var serializationFn serializar addMeta := func(res serializar) serializar { return func(i interface{}) ([]byte, error) { if t, ok := i.(*tree.CommandTree); ok { addMetaToTree(t) } return res(i) } } switch format { case "yaml": serializationFn = addMeta(yaml.Marshal) case "json": serializationFn = addMeta(func(t interface{}) ([]byte, error) { return json.MarshalIndent(t, "", " ") }) case "text": outputTpl := cmd.Options["template"].ToString() tpl := template.Must(template.New("treeItem").Funcs(render.TemplateFuncs).Parse(outputTpl)) serializationFn = func(t interface{}) ([]byte, error) { tree := t.(*tree.CommandTree) addMetaToTree(tree) var output bytes.Buffer if err := tpl.Execute(&output, tree.Command); err != nil { return output.Bytes(), err } err := tree.Traverse(func(cmd *command.Command) error { return tpl.Execute(&output, cmd) }) return output.Bytes(), err } case "autocomplete": serializationFn = func(interface{}) ([]byte, error) { return []byte(strings.Join(tree.ChildrenNames(), "\n") + "\n"), nil } default: return errors.BadArguments{Msg: fmt.Sprintf("Unknown format <%s> for command tree serialization", format)} } serialized, err := tree.Serialize(serializationFn) if err != nil { return err } fmt.Print(serialized) return nil }, }
View Source
var Docs = &command.Command{ Path: []string{"help", "docs"}, Summary: "Displays docs on TOPIC", Description: "Shows markdown-formatted documentation from milpa repos. See `" + _c.Milpa + " " + _c.HelpCommandName + " docs milpa repo docs` for more information on how to write your own.", Arguments: command.Arguments{ &command.Argument{ Name: "topic", Description: "The topic to show docs for", Variadic: true, Required: false, Values: &command.ValueSource{ Suggestion: true, Func: func(cmd *command.Command, currentValue, config string) (values []string, flag cobra.ShellCompDirective, err error) { args := cmd.Arguments[0].ToValue().([]string) dlog.Debugf("looking for docs given %v and %s", args, currentValue) cv := "" if len(args) > 1 && args[len(args)-1] == "" { cv = args[len(args)-1] args = args[0 : len(args)-1] } dlog.Debugf("looking for docs given %v and %s", args, cv) docs, err := lookup.Docs(args, cv, false) if err != nil { return nil, cobra.ShellCompDirectiveNoFileComp, err } return docs, cobra.ShellCompDirectiveNoFileComp, nil }, }, }, }, Options: command.Options{ "server": { Description: "Starts an http server at the specified address", Type: command.ValueTypeBoolean, Default: false, }, "listen": { Description: "The address to listen at when using `--server`", Type: command.ValueTypeString, Default: "localhost:4242", }, "base": { Description: "A URL base to use for rendering html links", Type: command.ValueTypeString, Default: "http://localhost:4242", }, }, Meta: milpaCommand.Meta{ Path: os.Getenv(_c.EnvVarMilpaRoot) + "/milpa/docs", Name: []string{_c.HelpCommandName, "docs"}, Repo: os.Getenv(_c.EnvVarMilpaRoot), Kind: "docs", }, Action: func(cmd *command.Command) error { args := cmd.Arguments[0].ToValue().([]string) if len(args) == 0 { if cmd.Options["server"].ToValue().(bool) { listen := cmd.Options["listen"].ToString() base := cmd.Options["base"] defaultListen := cmd.Options["listen"].Default.(string) address := strings.ReplaceAll(base.ToString(), defaultListen, listen) dlog.Infof("Starting docs server at http://%s, press CTRL-C to stop...", listen) return startServer(listen, address) } dlog.Debug("Rendering docs help page") err := cmd.Cobra.Help() if err != nil { return err } AfterHelp(statuscode.RenderHelp) dlog.Debug("Rendered docs help page") return nil } contents, err := docs.FromQuery(args) if err != nil { switch err.(type) { case errors.BadArguments: helpErr := cmd.Cobra.Help() if helpErr != nil { os.Exit(statuscode.ProgrammerError) } logrus.Error(err) os.Exit(statuscode.Usage) } return errors.NotFound{Msg: err.Error()} } titleExp := regexp.MustCompile("^title: (.+)") frontmatterSep := []byte("---\n") if len(contents) > 3 && string(contents[0:4]) == string(frontmatterSep) { parts := bytes.SplitN(contents, frontmatterSep, 3) title := titleExp.FindString(string(parts[1])) if title != "" { title = strings.TrimPrefix(title, "title: ") } else { title = strings.Join(args, " ") } contents = bytes.Join([][]byte{[]byte("# " + title + "\n"), parts[2]}, []byte("\n")) } withColor, _ := cmd.Cobra.Flags().GetBool("no-color") doc, err := render.Markdown(contents, !withColor) if err != nil { return err } if _, err := cmd.Cobra.OutOrStderr().Write(doc); err != nil { return err } AfterHelp(statuscode.RenderHelp) return nil }, }
View Source
var Doctor = &command.Command{ Path: []string{"itself", "doctor"}, Summary: "Validates all commands found on the `MILPA_PATH`", Description: `This command will run checks on all known commands, parsing specs and validating their values.`, Options: command.Options{ "summary": { Type: command.ValueTypeBoolean, Description: "Only print errors, if any", }, }, Action: func(cmd *command.Command) (err error) { bold := color.New(color.Bold) warn := color.New(color.FgYellow) fail := color.New(color.FgRed) success := color.New(color.FgGreen) failedOverall := false failures := map[string]uint8{} var out = cmd.Cobra.OutOrStdout() summarize := cmd.Options["summary"].ToValue().(bool) var milpaRoot string if mp := os.Getenv(_c.EnvVarMilpaRoot); mp != "" { milpaRoot = strings.Join(strings.Split(mp, ":"), "\n") } else { milpaRoot = warn.Sprint("empty") } bold.Fprintf(out, "%s is: %s\n", _c.EnvVarMilpaRoot, milpaRoot) var milpaPath string bold.Fprintf(out, "%s is: ", _c.EnvVarMilpaPath) if mp := os.Getenv(_c.EnvVarMilpaPath); mp != "" { milpaPath = "\n" + strings.Join(bootstrap.MilpaPath, "\n") } else { milpaPath = warn.Sprint("empty") } fmt.Fprintf(out, "%s\n", milpaPath) fmt.Fprintln(out, "") bold.Fprintf(out, "Runnable commands:\n") for _, cmd := range tree.CommandList() { if cmd.Hidden { continue } docLog.Debugf("Validating %s", cmd.FullName()) message := "" hasFailures := false report := map[string]int{} if meta, ok := cmd.Meta.(mcmd.Meta); ok { parsingErrors := meta.ParsingErrors() if len(parsingErrors) > 0 { hasFailures = true for _, err := range parsingErrors { failures[cmd.FullName()]++ message += fail.Sprintf(" - %s\n", err) } } else { report = cmd.Validate() } } else { report = cmd.Validate() } for property, status := range report { formatter := success if status == 1 { hasFailures = true failures[cmd.FullName()]++ formatter = fail } else if status == 2 { formatter = warn } message += formatter.Sprintf(" - %s\n", property) } prefix := "✅" if hasFailures { failedOverall = true prefix = "❌" } fmt.Println(bold.Sprintf("%s %s", prefix, cmd.FullName()), "—", cmd.Path) if !summarize || hasFailures { if message != "" { fmt.Fprintln(out, message) } fmt.Fprintln(out, "-----------") } } if failedOverall { failureReport := []string{} for cmd, count := range failures { plural := "" if count > 1 { plural = "s" } failureReport = append(failureReport, fmt.Sprintf("%s - %d issue%s", cmd, count, plural)) } return fmt.Errorf("your milpa could use some help with the following commands:\n%s", strings.Join(failureReport, "\n")) } return nil }, }
Functions ¶
func DoctorModeEnabled ¶
func DoctorModeEnabled() bool
Types ¶
This section is empty.
Click to show internal directories.
Click to hide internal directories.