Skip to content

Commit

Permalink
implement go-arg for parsing in main (#73)
Browse files Browse the repository at this point in the history
this implements go-arg and argv to handle argument parsing from the command line and go-arg in each command to handle any command specific arguments passed to it.
  • Loading branch information
mattlqx authored Feb 5, 2021
1 parent 75a69c9 commit 5ed1676
Show file tree
Hide file tree
Showing 19 changed files with 409 additions and 299 deletions.
93 changes: 37 additions & 56 deletions cli/append.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,32 @@ const (
// AppendCommand container for all 'append' parameters
type AppendCommand struct {
name string
args *AppendCommandArgs

client *client.Client
Source string
Target string
Mode AppendMode
}

// AppendCommandArgs provides a struct for go-arg parsing
type AppendCommandArgs struct {
Source string `arg:"positional,required"`
Target string `arg:"positional,required"`
Force bool `arg:"-f,--force" help:"Overwrite key if exists"`
Skip bool `arg:"-s,--skip" help:"Skip key if exists (default)"`
Rename bool `arg:"-r,--rename" help:"Rename key if exists"`
}

// Description provides detail on what the command does
func (AppendCommandArgs) Description() string {
return "appends the contents of one secret to another"
}

// NewAppendCommand creates a new AppendCommand parameter container
func NewAppendCommand(c *client.Client) *AppendCommand {
return &AppendCommand{
name: "append",
client: c,
args: &AppendCommandArgs{},
Mode: ModeSkip,
}
}
Expand All @@ -48,75 +62,42 @@ func (cmd *AppendCommand) GetName() string {
return cmd.name
}

// IsSane returns true if command is sane
func (cmd *AppendCommand) IsSane() bool {
return cmd.Source != "" && cmd.Target != "" && cmd.Mode != ModeInvalid
}

func isFlag(flag string) bool {
return strings.HasPrefix(flag, "-")
}

func parseFlag(flag string) AppendMode {
switch strings.TrimSpace(flag) {
case "-f", "--force":
return ModeOverwrite
case "", "-s", "--skip":
return ModeSkip
case "-r", "--rename":
return ModeRename
default:
return ModeInvalid
}
}

func (cmd *AppendCommand) parseArgs(src, dest, flag string) bool {
cmd.Source = src
cmd.Target = dest
mode := parseFlag(flag)
cmd.Mode = mode
if mode == ModeInvalid {
return false
}
return true
// GetArgs provides the struct holding arguments for the command
func (cmd *AppendCommand) GetArgs() interface{} {
return cmd.args
}

// tryParse returns true when parsing succeeded, false otherwise
func (cmd *AppendCommand) tryParse(args []string) (success bool) {
if len(args) == 3 {
return cmd.parseArgs(args[1], args[2], "--skip") // --skip is default
}
if len(args) == 4 {
// flag can be given at the end or immediately after `append`
if isFlag(args[3]) {
return cmd.parseArgs(args[1], args[2], args[3])
}
if isFlag(args[1]) {
return cmd.parseArgs(args[2], args[3], args[1])
}
}
// wrong number of params or flag at incorrect position
return false
// IsSane returns true if command is sane
func (cmd *AppendCommand) IsSane() bool {
return cmd.args.Source != "" && cmd.args.Target != "" && cmd.Mode != ModeInvalid
}

// PrintUsage print command usage
func (cmd *AppendCommand) PrintUsage() {
log.UserInfo("Usage:\nappend <from> <to> [-f|--force|-r|--rename|-s|--skip]")
fmt.Println(Help(cmd))
}

// Parse parses the arguments and returns true on success; otherwise it prints usage and returns false
// Parse parses the arguments into the Command and Args structs
func (cmd *AppendCommand) Parse(args []string) error {
success := cmd.tryParse(args)
if !success {
return fmt.Errorf("cannot parse arguments")
_, err := parseCommandArgs(args, cmd)
if err != nil {
return err
}

if cmd.args.Skip == true {
cmd.Mode = ModeSkip
} else if cmd.args.Force == true {
cmd.Mode = ModeOverwrite
} else if cmd.args.Rename == true {
cmd.Mode = ModeRename
}
return nil
}

// Run executes 'append' with given AppendCommand's parameters
func (cmd *AppendCommand) Run() int {
newSrcPwd := cmdPath(cmd.client.Pwd, cmd.Source)
newTargetPwd := cmdPath(cmd.client.Pwd, cmd.Target)
newSrcPwd := cmdPath(cmd.client.Pwd, cmd.args.Source)
newTargetPwd := cmdPath(cmd.client.Pwd, cmd.args.Target)

src := cmd.client.GetType(newSrcPwd)
if src != client.LEAF {
Expand Down
44 changes: 44 additions & 0 deletions cli/args.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package cli

import (
"bytes"

"github.com/alexflint/go-arg"
)

func parseCommandArgs(args []string, cmd Command) (*arg.Parser, error) {
p, err := argParser(args, cmd)
if err != nil {
return nil, err
}

if len(args) > 1 {
err = p.Parse(args[1:])
} else {
err = p.Parse([]string{})
}
if err != nil {
return nil, err
}
return p, nil
}

func argParser(args []string, cmd Command) (*arg.Parser, error) {
return arg.NewParser(arg.Config{Program: args[0]}, cmd.GetArgs())
}

// Usage returns usage information
func Usage(cmd Command) string {
var b bytes.Buffer
p, _ := argParser([]string{cmd.GetName()}, cmd)
p.WriteUsage(&b)
return b.String()
}

// Help returns extended usage information
func Help(cmd Command) string {
var b bytes.Buffer
p, _ := argParser([]string{cmd.GetName()}, cmd)
p.WriteHelp(&b)
return b.String()
}
32 changes: 25 additions & 7 deletions cli/cat.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,35 @@ package cli

import (
"fmt"

"github.com/fishi0x01/vsh/client"
"github.com/fishi0x01/vsh/log"
)

// CatCommand container for all 'cat' parameters
type CatCommand struct {
name string
args *CatCommandArgs

client *client.Client
Path string
}

// CatCommandArgs provides a struct for go-arg parsing
type CatCommandArgs struct {
Path string `arg:"positional,required" help:"path to display contents"`
}

// Description provides detail on what the command does
func (CatCommandArgs) Description() string {
return "displays the content of a secret"
}

// NewCatCommand creates a new CatCommand parameter container
func NewCatCommand(c *client.Client) *CatCommand {
return &CatCommand{
name: "cat",
client: c,
args: &CatCommandArgs{},
}
}

Expand All @@ -27,28 +39,34 @@ func (cmd *CatCommand) GetName() string {
return cmd.name
}

// GetArgs provides the struct holding arguments for the command
func (cmd *CatCommand) GetArgs() interface{} {
return cmd.args
}

// IsSane returns true if command is sane
func (cmd *CatCommand) IsSane() bool {
return cmd.Path != ""
return cmd.args.Path != ""
}

// PrintUsage print command usage
func (cmd *CatCommand) PrintUsage() {
log.UserInfo("Usage:\ncat <secret>")
fmt.Println(Help(cmd))
}

// Parse given arguments and return status
func (cmd *CatCommand) Parse(args []string) error {
if len(args) != 2 {
return fmt.Errorf("cannot parse arguments")
_, err := parseCommandArgs(args, cmd)
if err != nil {
return err
}
cmd.Path = args[1]

return nil
}

// Run executes 'cat' with given CatCommand's parameters
func (cmd *CatCommand) Run() int {
absPath := cmdPath(cmd.client.Pwd, cmd.Path)
absPath := cmdPath(cmd.client.Pwd, cmd.args.Path)
t := cmd.client.GetType(absPath)

if t == client.LEAF {
Expand Down
31 changes: 24 additions & 7 deletions cli/cd.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,27 @@ import (
// CdCommand container for all 'cd' parameters
type CdCommand struct {
name string
args *CdCommandArgs

client *client.Client
Path string
}

// CdCommandArgs provides a struct for go-arg parsing
type CdCommandArgs struct {
Path string `arg:"positional,required" help:"change cwd to path"`
}

// Description provides detail on what the command does
func (CdCommandArgs) Description() string {
return "changes the working path"
}

// NewCdCommand creates a new CdCommand parameter container
func NewCdCommand(c *client.Client) *CdCommand {
return &CdCommand{
name: "cd",
client: c,
args: &CdCommandArgs{},
}
}

Expand All @@ -29,28 +40,34 @@ func (cmd *CdCommand) GetName() string {
return cmd.name
}

// GetArgs provides the struct holding arguments for the command
func (cmd *CdCommand) GetArgs() interface{} {
return cmd.args
}

// IsSane returns true if command is sane
func (cmd *CdCommand) IsSane() bool {
return cmd.Path != ""
return cmd.args.Path != ""
}

// PrintUsage print command usage
func (cmd *CdCommand) PrintUsage() {
log.UserInfo("Usage:\ncd <path>")
fmt.Println(Help(cmd))
}

// Parse given arguments and return status
func (cmd *CdCommand) Parse(args []string) error {
if len(args) != 2 {
return fmt.Errorf("cannot parse arguments")
_, err := parseCommandArgs(args, cmd)
if err != nil {
return err
}
cmd.Path = args[1]

return nil
}

// Run executes 'cd' with given CdCommand's parameters
func (cmd *CdCommand) Run() int {
newPwd := cmdPath(cmd.client.Pwd, cmd.Path)
newPwd := cmdPath(cmd.client.Pwd, cmd.args.Path)

t := cmd.client.GetType(newPwd)

Expand Down
Loading

0 comments on commit 5ed1676

Please sign in to comment.