Skip to content

Commit

Permalink
- First attempt at using a new cli framework. WIP.
Browse files Browse the repository at this point in the history
  • Loading branch information
Kristoffer Ahl committed Mar 27, 2020
1 parent 8bb3c37 commit 5848048
Show file tree
Hide file tree
Showing 8 changed files with 236 additions and 64 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,10 @@ scripts/test
```bash
scripts/run-centry
```




https://github.com/kristofferahl/go-centry
https://github.com/urfave/cli/blob/master/docs/v2/manual.md#subcommands
https://github.com/spf13/cobra
1 change: 1 addition & 0 deletions cmd/centry/help.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/mitchellh/cli"
)

// TODO: Remove if unused???
func cliHelpFunc(manifest *config.Manifest, globalOptions *cmd.OptionsSet) cli.HelpFunc {
return func(commands map[string]cli.CommandFactory) string {
var buf bytes.Buffer
Expand Down
61 changes: 61 additions & 0 deletions cmd/centry/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package main

import (
"github.com/kristofferahl/go-centry/internal/pkg/cmd"
"github.com/urfave/cli/v2"
)

// OptionSetGlobal is the name of the global OptionsSet
Expand Down Expand Up @@ -75,3 +76,63 @@ func createGlobalOptions(context *Context) *cmd.OptionsSet {

return options
}

func createGlobalFlags(context *Context) []cli.Flag {
options := make([]cli.Flag, 0)
manifest := context.manifest

options = append(options, &cli.StringFlag{
Name: "config.log.level",
Usage: "Overrides the log level",
Value: manifest.Config.Log.Level,
})

options = append(options, &cli.BoolFlag{
Name: "quiet",
Aliases: []string{"q"},
Usage: "Disables logging",
Value: false,
})

// Adding global options specified by the manifest
for _, o := range manifest.Options {
o := o

if context.optionEnabledFunc != nil && context.optionEnabledFunc(o) == false {
continue
}

short := []string{o.Short}
if o.Short == "" {
short = nil
}

//TODO: Handle EnvName??
switch o.Type {
case cmd.SelectOption:

options = append(options, &cli.BoolFlag{
Name: o.Name,
Aliases: short,
Usage: o.Description,
Value: false,
})
case cmd.BoolOption:
options = append(options, &cli.BoolFlag{
Name: o.Name,
Aliases: short,
Usage: o.Description,
Value: false,
})
case cmd.StringOption:
options = append(options, &cli.StringFlag{
Name: o.Name,
Aliases: short,
Usage: o.Description,
Value: o.Default,
})
}
}

return options
}
146 changes: 101 additions & 45 deletions cmd/centry/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@ import (
"github.com/kristofferahl/go-centry/internal/pkg/config"
"github.com/kristofferahl/go-centry/internal/pkg/log"
"github.com/kristofferahl/go-centry/internal/pkg/shell"
"github.com/mitchellh/cli"
"github.com/sirupsen/logrus"
"github.com/urfave/cli/v2"
)

// Runtime defines the runtime
type Runtime struct {
context *Context
cli *cli.CLI
cli *cli.App
args []string
}

// NewRuntime builds a runtime based on the given arguments
Expand All @@ -23,10 +24,10 @@ func NewRuntime(inputArgs []string, context *Context) (*Runtime, error) {

// Args
file := ""
args := []string{}
runtime.args = []string{}
if len(inputArgs) >= 1 {
file = inputArgs[0]
args = inputArgs[1:]
runtime.args = inputArgs[1:]
}

// Load manifest
Expand All @@ -42,47 +43,47 @@ func NewRuntime(inputArgs []string, context *Context) (*Runtime, error) {

// Create global options
options := createGlobalOptions(context)
flags := createGlobalFlags(context)

// Parse global options to get cli args
args, err = options.Parse(args, context.io)
if err != nil {
return nil, err
}
// args, err = options.Parse(args, context.io)
// if err != nil {
// return nil, err
// }

// Initialize cli
c := &cli.CLI{
Name: context.manifest.Config.Name,
Version: context.manifest.Config.Version,

Commands: map[string]cli.CommandFactory{},
Args: args,
HelpFunc: cliHelpFunc(context.manifest, options),
HelpWriter: context.io.Stderr,

// Autocomplete: true,
// AutocompleteInstall: "install-autocomplete",
// AutocompleteUninstall: "uninstall-autocomplete",
app := &cli.App{
Name: context.manifest.Config.Name,
HelpName: context.manifest.Config.Name,
Usage: "A tool for building declarative CLI's over bash scripts, written in go.", // TODO: Set from manifest config
UsageText: "",
Version: context.manifest.Config.Version,
HideHelpCommand: true,

Commands: make([]*cli.Command, 0),
Flags: flags,
}

// TODO: Fix log level from options
// Override the current log level from options
logLevel := options.GetString("config.log.level")
if options.GetBool("quiet") {
logLevel = "panic"
}
context.log.TrySetLogLevel(logLevel)
// logLevel := options.GetString("config.log.level")
// if options.GetBool("quiet") {
// logLevel = "panic"
// }
//context.log.TrySetLogLevel(logLevel)
context.log.TrySetLogLevel("debug")

logger := context.log.GetLogger()

// Register builtin commands
if context.executor == CLI {
c.Commands["serve"] = func() (cli.Command, error) {
return &ServeCommand{
Manifest: context.manifest,
Log: logger.WithFields(logrus.Fields{
"command": "serve",
}),
}, nil
serveCmd := &ServeCommand{
Manifest: context.manifest,
Log: logger.WithFields(logrus.Fields{
"command": "serve",
}),
}
app.Commands = append(app.Commands, serveCmd.ToCLICommand())
}

// Build commands
Expand All @@ -100,7 +101,6 @@ func NewRuntime(inputArgs []string, context *Context) (*Runtime, error) {
logger.WithFields(logrus.Fields{
"command": cmd.Name,
}).Errorf("Failed to parse script functions. %v", err)

} else {
for _, fn := range funcs {
fn := fn
Expand All @@ -111,24 +111,68 @@ func NewRuntime(inputArgs []string, context *Context) (*Runtime, error) {
continue
}

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

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

cmdKey := strings.Replace(fn.Name, script.FunctionNameSplitChar(), " ", -1)
c.Commands[cmdKey] = func() (cli.Command, error) {
return &ScriptCommand{
Context: context,
Log: logger.WithFields(logrus.Fields{}),
GlobalOptions: options,
Command: cmd,
Script: script,
Function: fn.Name,
}, nil
cmdKeyParts := strings.Split(cmdKey, " ")

scriptCmd := &ScriptCommand{
Context: context,
Log: logger.WithFields(logrus.Fields{}),
GlobalOptions: options,
Command: cmd,
Script: script,
Function: fn.Name,
}

cliCmd := scriptCmd.ToCLICommand()

var root *cli.Command

for depth, cmdKeyPart := range cmdKeyParts {
if depth == 0 {
if getCommand(app.Commands, cmdKeyPart) == nil {
if depth == len(cmdKeyParts)-1 {
// add destination command
app.Commands = append(app.Commands, cliCmd)
} else {
// add placeholder
app.Commands = append(app.Commands, &cli.Command{
Name: cmdKeyPart,
Usage: cmdDescription,
UsageText: cmdHelp,
HideHelpCommand: true,
Action: nil,
})
}
}
root = getCommand(app.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)
}
}

logger.Debugf("Registered command \"%s\"", cmdKey)
Expand All @@ -137,21 +181,23 @@ func NewRuntime(inputArgs []string, context *Context) (*Runtime, error) {
}

runtime.context = context
runtime.cli = c
runtime.cli = app

return runtime, nil
}

// Execute runs the CLI and exits with a code
func (runtime *Runtime) Execute() int {
args := append([]string{""}, runtime.args...)

// Run cli
exitCode, err := runtime.cli.Run()
err := runtime.cli.Run(args)
if err != nil {
logger := runtime.context.log.GetLogger()
logger.Error(err)
}

return exitCode
return 0
}

func createScript(cmd config.Command, context *Context) shell.Script {
Expand All @@ -163,3 +209,13 @@ func createScript(cmd config.Command, context *Context) shell.Script {
}),
}
}

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

return nil
}
Loading

0 comments on commit 5848048

Please sign in to comment.