Skip to content

Commit

Permalink
Merge branch 'feature/new-cli-and-subcommand-options'
Browse files Browse the repository at this point in the history
  • Loading branch information
Kristoffer Ahl committed Oct 15, 2020
2 parents 8bb3c37 + 7e0bb98 commit 8780fa2
Show file tree
Hide file tree
Showing 41 changed files with 1,521 additions and 1,147 deletions.
147 changes: 147 additions & 0 deletions cmd/centry/commands.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
package main

import (
"fmt"
"sort"
"strings"

"github.com/kristofferahl/go-centry/internal/pkg/cmd"
"github.com/kristofferahl/go-centry/internal/pkg/config"
"github.com/kristofferahl/go-centry/internal/pkg/shell"
"github.com/sirupsen/logrus"
"github.com/urfave/cli/v2"
)

func registerBuiltinCommands(runtime *Runtime) {
context := runtime.context

if context.executor == CLI {
serveCmd := &ServeCommand{
Manifest: context.manifest,
Log: context.log.GetLogger().WithFields(logrus.Fields{
"command": "serve",
}),
}
runtime.cli.Commands = append(runtime.cli.Commands, serveCmd.ToCLICommand())
}
}

func registerManifestCommands(runtime *Runtime, options *cmd.OptionsSet) {
context := runtime.context

for _, cmd := range context.manifest.Commands {
cmd := cmd

if context.commandEnabledFunc != nil && context.commandEnabledFunc(cmd) == false {
continue
}

script := createScript(cmd, context)

funcs, err := script.Functions()
if err != nil {
context.log.GetLogger().WithFields(logrus.Fields{
"command": cmd.Name,
}).Errorf("Failed to parse script functions. %v", err)
} else {
for _, fn := range funcs {
fn := fn
cmd := cmd
namespace := script.FunctionNamespace(cmd.Name)

if fn.Name != cmd.Name && strings.HasPrefix(fn.Name, namespace) == false {
continue
}

cmdDescription := cmd.Description
if fn.Description != "" {
cmd.Description = fn.Description
}

cmdHelp := cmd.Help
if fn.Help != "" {
cmd.Help = fn.Help
}

scriptCmd := &ScriptCommand{
Context: context,
Log: context.log.GetLogger().WithFields(logrus.Fields{}),
GlobalOptions: options,
Command: cmd,
Script: script,
Function: *fn,
}
cliCmd := scriptCmd.ToCLICommand()

cmdKeyParts := scriptCmd.GetCommandInvocationPath()

var root *cli.Command
for depth, cmdKeyPart := range cmdKeyParts {
if depth == 0 {
if getCommand(runtime.cli.Commands, cmdKeyPart) == nil {
if depth == len(cmdKeyParts)-1 {
// add destination command
runtime.cli.Commands = append(runtime.cli.Commands, cliCmd)
} else {
// add placeholder
runtime.cli.Commands = append(runtime.cli.Commands, &cli.Command{
Name: cmdKeyPart,
Usage: cmdDescription,
UsageText: cmdHelp,
HideHelpCommand: true,
Action: nil,
})
}
}
root = getCommand(runtime.cli.Commands, cmdKeyPart)
} else {
if getCommand(root.Subcommands, cmdKeyPart) == nil {
if depth == len(cmdKeyParts)-1 {
// add destination command
root.Subcommands = append(root.Subcommands, cliCmd)
} else {
// add placeholder
root.Subcommands = append(root.Subcommands, &cli.Command{
Name: cmdKeyPart,
Usage: "...",
UsageText: "",
HideHelpCommand: true,
Action: nil,
})
}
}
root = getCommand(root.Subcommands, cmdKeyPart)
}
}

runtime.events = append(runtime.events, fmt.Sprintf("Registered command \"%s\"", scriptCmd.GetCommandInvocation()))
}
}
}
}

func getCommand(commands []*cli.Command, name string) *cli.Command {
for _, c := range commands {
if c.HasName(name) {
return c
}
}

return nil
}

func sortCommands(commands []*cli.Command) {
sort.Slice(commands, func(i, j int) bool {
return commands[i].Name < commands[j].Name
})
}

func createScript(cmd config.Command, context *Context) shell.Script {
return &shell.BashScript{
BasePath: context.manifest.BasePath,
Path: cmd.Path,
Log: context.log.GetLogger().WithFields(logrus.Fields{
"script": cmd.Path,
}),
}
}
77 changes: 0 additions & 77 deletions cmd/centry/env.go

This file was deleted.

105 changes: 21 additions & 84 deletions cmd/centry/help.go
Original file line number Diff line number Diff line change
@@ -1,93 +1,30 @@
package main

import (
"bytes"
"fmt"
"log"
"sort"
"strings"
var cliHelpTemplate = `NAME:
{{.Name}}{{if .Usage}} - {{.Usage}}{{end}}
"github.com/kristofferahl/go-centry/internal/pkg/cmd"
"github.com/kristofferahl/go-centry/internal/pkg/config"
"github.com/mitchellh/cli"
)
USAGE:
{{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}} {{if .VisibleFlags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Version}}{{if not .HideVersion}}
func cliHelpFunc(manifest *config.Manifest, globalOptions *cmd.OptionsSet) cli.HelpFunc {
return func(commands map[string]cli.CommandFactory) string {
var buf bytes.Buffer
buf.WriteString(fmt.Sprintf("Usage: %s [<global options>] <command> [<args>]\n\n", manifest.Config.Name))
VERSION:
{{.Version}}{{end}}{{end}}{{if .Description}}
writeCommands(&buf, commands, manifest)
writeOptionsSet(&buf, globalOptions)
DESCRIPTION:
{{.Description}}{{end}}{{if len .Authors}}
return buf.String()
}
}
AUTHOR{{with $length := len .Authors}}{{if ne 1 $length}}S{{end}}{{end}}:
{{range $index, $author := .Authors}}{{if $index}}
{{end}}{{$author}}{{end}}{{end}}{{if .VisibleCommands}}
func writeCommands(buf *bytes.Buffer, commands map[string]cli.CommandFactory, manifest *config.Manifest) {
buf.WriteString("Commands:\n")
COMMANDS:{{range .VisibleCategories}}{{if .Name}}
{{.Name}}:{{range .VisibleCommands}}
{{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}{{else}}{{range .VisibleCommands}}
{{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}{{end}}{{end}}{{end}}{{if .VisibleFlags}}
// Get the list of keys so we can sort them, and also get the maximum
// key length so they can be aligned properly.
keys := make([]string, 0, len(commands))
maxKeyLen := 0
for key := range commands {
if len(key) > maxKeyLen {
maxKeyLen = len(key)
}
GLOBAL OPTIONS:
{{range $index, $option := .VisibleFlags}}{{if $index}}
{{end}}{{$option}}{{end}}{{end}}{{if .Copyright}}
keys = append(keys, key)
}
sort.Strings(keys)

for _, key := range keys {
commandFunc, ok := commands[key]
if !ok {
// This should never happen since we JUST built the list of keys.
panic("command not found: " + key)
}

command, err := commandFunc()
if err != nil {
log.Printf("[ERR] cli: Command '%s' failed to load: %s", key, err)
continue
}

synopsis := command.Synopsis()
if synopsis == "" {
for _, mc := range manifest.Commands {
if mc.Name == key {
synopsis = mc.Description
}
}
}
key = fmt.Sprintf("%s%s", key, strings.Repeat(" ", maxKeyLen-len(key)))
buf.WriteString(fmt.Sprintf(" %s %s\n", key, synopsis))
}
}

func writeOptionsSet(buf *bytes.Buffer, set *cmd.OptionsSet) {
buf.WriteString(fmt.Sprintf("\n%s options:\n", set.Name))

sorted := set.Sorted()

maxKeyLen := 0
for _, o := range sorted {
key := fmt.Sprintf("--%s", o.Name)
if len(key) > maxKeyLen {
maxKeyLen = len(key)
}
}

for _, o := range sorted {
l := fmt.Sprintf("--%s", o.Name)

if o.Short != "" {
l = fmt.Sprintf("%s, -%s", l, o.Short)
}

n := fmt.Sprintf("%s%s", l, strings.Repeat(" ", maxKeyLen-len(l)))
d := o.Description
buf.WriteString(fmt.Sprintf(" %s %s\n", n, d))
}
}
COPYRIGHT:
{{.Copyright}}{{end}}
`
Loading

0 comments on commit 8780fa2

Please sign in to comment.