Skip to content
This repository has been archived by the owner on Dec 13, 2020. It is now read-only.

Commit

Permalink
No subcommand flags. Testing stdout line length.
Browse files Browse the repository at this point in the history
No planned sub command flags. Making Config field items non-pointers
since FromCLI() is only called once.

Adding --target and --user flags to global options.

Polishing off CLI help texts.

Testing --help line lengths (80 chars max).
  • Loading branch information
Robpol86 committed Sep 1, 2016
1 parent 5e177f6 commit bcb219d
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 61 deletions.
46 changes: 16 additions & 30 deletions config.go
Original file line number Diff line number Diff line change
@@ -1,49 +1,35 @@
package main

import (
"reflect"

"github.com/urfave/cli"
)

// Config defines the application configuration.
type Config struct {
LogFile *string `cli:"log"`
Quiet *bool `cli:"quiet"`
Verbose *bool `cli:"verbose"`
LogFile string
Quiet bool
TargetDir string
Username string
Verbose bool
}

// FromCLI is passed to cli.App{} in the Action field. It populates the GlobalConfig.
func (c *Config) FromCLI(ctx *cli.Context) error {
if s := ctx.String("log"); c.LogFile == nil {
c.LogFile = &s
}
if b := ctx.Bool("quiet"); c.Quiet == nil {
c.Quiet = &b
c.LogFile = ctx.String("log")
c.Quiet = ctx.Bool("quiet")
c.TargetDir = ctx.String("target")
c.Username = ctx.String("user")
c.Verbose = ctx.Bool("verbose")

// Set defaults.
if c.TargetDir == "" {
c.TargetDir = "ghbackup"
}
if b := ctx.Bool("verbose"); c.Verbose == nil {
c.Verbose = &b
if c.Username == "" {
c.Username = "TODO"
}
return nil
}

// Finalize resolves remaining nil pointers to empty *values.
func (c *Config) Finalize() {
emptyBool := false
emptyString := ""
structValue := reflect.ValueOf(c).Elem()
for i := 0; i < structValue.NumField(); i++ {
field := structValue.Field(i)
if !field.IsNil() {
continue
}
if field.Type() == reflect.TypeOf(&emptyBool) {
field.Set(reflect.ValueOf(&emptyBool))
} else if field.Type() == reflect.TypeOf(&emptyString) {
field.Set(reflect.ValueOf(&emptyString))
}
}
}

// GlobalConfig will hold the config values for the entire application during runtime.
var GlobalConfig Config
19 changes: 0 additions & 19 deletions config_test.go

This file was deleted.

36 changes: 24 additions & 12 deletions githubBackup.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,21 @@ import (

func github(ctx *cli.Context) error {
fmt.Println("Hello World")
fmt.Printf("LogFile: %s\n", *GlobalConfig.LogFile)
fmt.Printf("Quiet: %v\n", *GlobalConfig.Quiet)
fmt.Printf("Verbose: %v\n", *GlobalConfig.Verbose)
fmt.Printf("LogFile: %s\n", GlobalConfig.LogFile)
fmt.Printf("Quiet: %v\n", GlobalConfig.Quiet)
fmt.Printf("TargetDir: %s\n", GlobalConfig.TargetDir)
fmt.Printf("Username: %s\n", GlobalConfig.Username)
fmt.Printf("Verbose: %v\n", GlobalConfig.Verbose)
return nil
}

func gist(ctx *cli.Context) error {
fmt.Println("Hello World!")
fmt.Printf("LogFile: %s\n", *GlobalConfig.LogFile)
fmt.Printf("Quiet: %v\n", *GlobalConfig.Quiet)
fmt.Printf("Verbose: %v\n", *GlobalConfig.Verbose)
fmt.Printf("LogFile: %s\n", GlobalConfig.LogFile)
fmt.Printf("Quiet: %v\n", GlobalConfig.Quiet)
fmt.Printf("TargetDir: %s\n", GlobalConfig.TargetDir)
fmt.Printf("Username: %s\n", GlobalConfig.Username)
fmt.Printf("Verbose: %v\n", GlobalConfig.Verbose)
return nil
}

Expand All @@ -35,22 +39,30 @@ func all(ctx *cli.Context) error {

func main() {
app := cli.NewApp()

// Global properties.
app.Before = GlobalConfig.FromCLI
app.Usage = usage
app.Version = version
app.Authors = []cli.Author{
{Name: "Robpol86", Email: "robpol86@gmail.com"},
}
app.Flags = []cli.Flag{
&cli.StringFlag{Name: "log, l", Usage: "Write debug output to log file."},
&cli.BoolFlag{Name: "quiet, q", Usage: "Don't print to terminal."},
&cli.BoolFlag{Name: "verbose, V", Usage: "Debug output to terminal."},
&cli.StringFlag{Name: "log, l", Usage: "write debug output to log file."},
&cli.BoolFlag{Name: "quiet, q", Usage: "don't print to terminal."},
&cli.StringFlag{Name: "target, t", Usage: "create sub directories here (default: ./ghbackup)."},
&cli.StringFlag{Name: "user, u", Usage: "use this GitHub username instead of auto detecting."},
&cli.BoolFlag{Name: "verbose, V", Usage: "debug output to terminal."},
}

// Sub commands.
app.Commands = []cli.Command{
{Name: "github", Action: github, Usage: "Backup only GitHub repositories."},
{Name: "gist", Action: gist, Usage: "Backup only GitHub Gists."},
{Name: "all", Action: all, Usage: "Backup both GitHub repos and Gists."},
{Name: "github", Action: github, Usage: "Backup only GitHub repositories.", ArgsUsage: " "},
{Name: "gist", Action: gist, Usage: "Backup only GitHub Gists.", ArgsUsage: " "},
{Name: "all", Action: all, Usage: "Backup both GitHub repos and Gists.", ArgsUsage: " "},
}

// Run. Exit 1 if user has bad arguments.
if err := app.Run(os.Args); err != nil {
os.Exit(1)
}
Expand Down
70 changes: 70 additions & 0 deletions main_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package main

import (
"bytes"
"fmt"
"io"
"os"
"strings"
"testing"

"github.com/stretchr/testify/require"
)

// From http://stackoverflow.com/questions/10473800/in-go-how-do-i-capture-stdout-of-a-function-into-a-string
func withStdoutRedir(args []string) (*string, error) {
var output string
stdout := make(chan string)

// Replace args.
oldArgs := os.Args
os.Args = args
defer func() { os.Args = oldArgs }()

// Replace stream.
old := os.Stdout
r, w, err := os.Pipe()
if err != nil {
return nil, err
}
os.Stdout = w
defer func() {
w.Close()
os.Stdout = old
out := <-stdout
output = out
}()

// Start copy.
go func() {
var buf bytes.Buffer
io.Copy(&buf, r)
stdout <- buf.String()
}()

// Run the main function.
main()

return &output, nil
}

func TestMain_HelpLineLength(t *testing.T) {
assert := require.New(t)
allArgs := [][]string{
{"githubBackup", "--help"},
{"githubBackup", "gist", "--help"},
{"githubBackup", "github", "--help"},
{"githubBackup", "all", "--help"},
}

for _, args := range allArgs {
output, err := withStdoutRedir(args)
assert.NoError(err)
assert.Contains(*output, "githubBackup")
assert.Contains(*output, "USAGE")
for _, line := range strings.Split(*output, "\n") {
truncated := fmt.Sprintf("%.80s", line)
assert.Equal(truncated, line)
}
}
}

0 comments on commit bcb219d

Please sign in to comment.