From 47a412375fd57dad5f612a210e46db23e735eb76 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Fri, 4 Aug 2017 12:00:22 -0400 Subject: [PATCH] Resolved compile-time errors since merging from v1 --- app_test.go | 380 ++++++++++++++++++------------------------------ command_test.go | 85 +++++------ context.go | 5 + context_test.go | 73 ---------- errors.go | 6 +- errors_test.go | 10 +- flag.go | 113 +++++++++++++- flag_test.go | 66 ++++----- help.go | 24 ++- help_test.go | 10 +- runtests | 25 ++-- 11 files changed, 365 insertions(+), 432 deletions(-) diff --git a/app_test.go b/app_test.go index 15d6a74..88c66ac 100644 --- a/app_test.go +++ b/app_test.go @@ -11,6 +11,8 @@ import ( "reflect" "strings" "testing" + + "github.com/stretchr/testify/assert" ) var ( @@ -201,14 +203,15 @@ func ExampleApp_Run_noAction() { } func ExampleApp_Run_subcommandNoAction() { - app := App{} - app.Name = "greet" - app.Commands = []Command{ - { - Name: "describeit", - Aliases: []string{"d"}, - Usage: "use it to see a description", - Description: "This is how we describe describeit the function", + app := &App{ + Name: "greet", + Commands: []*Command{ + { + Name: "describeit", + Aliases: []string{"d"}, + Usage: "use it to see a description", + Description: "This is how we describe describeit the function", + }, }, } app.Run([]string{"greet", "describeit"}) @@ -273,10 +276,10 @@ func TestApp_Run(t *testing.T) { } err := app.Run([]string{"command", "foo"}) - expect(t, err, nil) + assert.Nil(t, err) err = app.Run([]string{"command", "bar"}) - expect(t, err, nil) - expect(t, s, "foobar") + assert.Nil(t, err) + assert.Equal(t, "foobar", s) } var commandAppTests = []struct { @@ -292,12 +295,11 @@ var commandAppTests = []struct { } func TestApp_Command(t *testing.T) { - app := &App{} - fooCommand := &Command{Name: "foobar", Aliases: []string{"f"}} - batCommand := &Command{Name: "batbaz", Aliases: []string{"b"}} - app.Commands = []*Command{ - fooCommand, - batCommand, + app := &App{ + Commands: []*Command{ + {Name: "foobar", Aliases: []string{"f"}}, + {Name: "batbaz", Aliases: []string{"b"}}, + }, } for _, test := range commandAppTests { @@ -314,24 +316,25 @@ func TestApp_Setup_defaultsWriter(t *testing.T) { func TestApp_CommandWithArgBeforeFlags(t *testing.T) { var parsedOption, firstArg string - app := NewApp() - command := Command{ - Name: "cmd", - Flags: []Flag{ - StringFlag{Name: "option", Value: "", Usage: "some option"}, - }, - Action: func(c *Context) error { - parsedOption = c.String("option") - firstArg = c.Args().First() - return nil + app := &App{ + Commands: []*Command{ + { + Name: "cmd", + Flags: []Flag{ + &StringFlag{Name: "option", Value: "", Usage: "some option"}, + }, + Action: func(c *Context) error { + parsedOption = c.String("option") + firstArg = c.Args().First() + return nil + }, + }, }, } - app.Commands = []Command{command} - app.Run([]string{"", "cmd", "my-arg", "--option", "my-option"}) - expect(t, parsedOption, "my-option") - expect(t, firstArg, "my-arg") + assert.Equal(t, parsedOption, "my-option") + assert.Equal(t, firstArg, "my-arg") } func TestApp_RunAsSubcommandParseFlags(t *testing.T) { @@ -384,19 +387,21 @@ func TestApp_CommandWithFlagBeforeTerminator(t *testing.T) { var parsedOption string var args Args - app := &App{} - command := &Command{ - Name: "cmd", - Flags: []Flag{ - &StringFlag{Name: "option", Value: "", Usage: "some option"}, - }, - Action: func(c *Context) error { - parsedOption = c.String("option") - args = c.Args() - return nil + app := &App{ + Commands: []*Command{ + { + Name: "cmd", + Flags: []Flag{ + &StringFlag{Name: "option", Value: "", Usage: "some option"}, + }, + Action: func(c *Context) error { + parsedOption = c.String("option") + args = c.Args() + return nil + }, + }, }, } - app.Commands = []*Command{command} app.Run([]string{"", "cmd", "--option", "my-option", "my-arg", "--", "--notARealFlag"}) @@ -409,15 +414,17 @@ func TestApp_CommandWithFlagBeforeTerminator(t *testing.T) { func TestApp_CommandWithDash(t *testing.T) { var args Args - app := &App{} - command := &Command{ - Name: "cmd", - Action: func(c *Context) error { - args = c.Args() - return nil + app := &App{ + Commands: []*Command{ + { + Name: "cmd", + Action: func(c *Context) error { + args = c.Args() + return nil + }, + }, }, } - app.Commands = []*Command{command} app.Run([]string{"", "cmd", "my-arg", "-"}) @@ -428,15 +435,17 @@ func TestApp_CommandWithDash(t *testing.T) { func TestApp_CommandWithNoFlagBeforeTerminator(t *testing.T) { var args Args - app := &App{} - command := &Command{ - Name: "cmd", - Action: func(c *Context) error { - args = c.Args() - return nil + app := &App{ + Commands: []*Command{ + { + Name: "cmd", + Action: func(c *Context) error { + args = c.Args() + return nil + }, + }, }, } - app.Commands = []*Command{command} app.Run([]string{"", "cmd", "my-arg", "--", "notAFlagAtAll"}) @@ -518,22 +527,24 @@ func TestApp_ParseSliceFlags(t *testing.T) { var parsedIntSlice []int var parsedStringSlice []string - app := &App{} - command := &Command{ - Name: "cmd", - Flags: []Flag{ - &IntSliceFlag{Name: "p", Value: NewIntSlice(), Usage: "set one or more ip addr"}, - &StringSliceFlag{Name: "ip", Value: NewStringSlice(), Usage: "set one or more ports to open"}, - }, - Action: func(c *Context) error { - parsedIntSlice = c.IntSlice("p") - parsedStringSlice = c.StringSlice("ip") - parsedOption = c.String("option") - firstArg = c.Args().First() - return nil + app := &App{ + Commands: []*Command{ + { + Name: "cmd", + Flags: []Flag{ + &IntSliceFlag{Name: "p", Value: NewIntSlice(), Usage: "set one or more ip addr"}, + &StringSliceFlag{Name: "ip", Value: NewStringSlice(), Usage: "set one or more ports to open"}, + }, + Action: func(c *Context) error { + parsedIntSlice = c.IntSlice("p") + parsedStringSlice = c.StringSlice("ip") + parsedOption = c.String("option") + firstArg = c.Args().First() + return nil + }, + }, }, } - app.Commands = []*Command{command} app.Run([]string{"", "cmd", "-p", "22", "-p", "80", "-ip", "8.8.8.8", "-ip", "8.8.4.4", "my-arg"}) @@ -576,20 +587,22 @@ func TestApp_ParseSliceFlagsWithMissingValue(t *testing.T) { var parsedIntSlice []int var parsedStringSlice []string - app := &App{} - command := &Command{ - Name: "cmd", - Flags: []Flag{ - &IntSliceFlag{Name: "a", Usage: "set numbers"}, - &StringSliceFlag{Name: "str", Usage: "set strings"}, - }, - Action: func(c *Context) error { - parsedIntSlice = c.IntSlice("a") - parsedStringSlice = c.StringSlice("str") - return nil + app := &App{ + Commands: []*Command{ + { + Name: "cmd", + Flags: []Flag{ + &IntSliceFlag{Name: "a", Usage: "set numbers"}, + &StringSliceFlag{Name: "str", Usage: "set strings"}, + }, + Action: func(c *Context) error { + parsedIntSlice = c.IntSlice("a") + parsedStringSlice = c.StringSlice("str") + return nil + }, + }, }, } - app.Commands = []*Command{command} app.Run([]string{"", "cmd", "-a", "2", "-str", "A", "my-arg"}) @@ -1569,8 +1582,8 @@ func (c *customBoolFlag) String() string { return "***" + c.Nombre + "***" } -func (c *customBoolFlag) GetName() string { - return c.Nombre +func (c *customBoolFlag) Names() []string { + return []string{c.Nombre} } func (c *customBoolFlag) Apply(set *flag.FlagSet) { @@ -1578,8 +1591,9 @@ func (c *customBoolFlag) Apply(set *flag.FlagSet) { } func TestCustomFlagsUnused(t *testing.T) { - app := NewApp() - app.Flags = []Flag{&customBoolFlag{"custom"}} + app := &App{ + Flags: []Flag{&customBoolFlag{"custom"}}, + } err := app.Run([]string{"foo"}) if err != nil { @@ -1588,8 +1602,9 @@ func TestCustomFlagsUnused(t *testing.T) { } func TestCustomFlagsUsed(t *testing.T) { - app := NewApp() - app.Flags = []Flag{&customBoolFlag{"custom"}} + app := &App{ + Flags: []Flag{&customBoolFlag{"custom"}}, + } err := app.Run([]string{"foo", "--custom=bar"}) if err != nil { @@ -1598,12 +1613,12 @@ func TestCustomFlagsUsed(t *testing.T) { } func TestCustomHelpVersionFlags(t *testing.T) { - app := NewApp() + app := &App{} // Be sure to reset the global flags defer func(helpFlag Flag, versionFlag Flag) { - HelpFlag = helpFlag - VersionFlag = versionFlag + HelpFlag = helpFlag.(*BoolFlag) + VersionFlag = versionFlag.(*BoolFlag) }(HelpFlag, VersionFlag) HelpFlag = &customBoolFlag{"help-custom"} @@ -1615,166 +1630,47 @@ func TestCustomHelpVersionFlags(t *testing.T) { } } -func TestHandleAction_WithNonFuncAction(t *testing.T) { - app := NewApp() - app.Action = 42 - fs, err := flagSet(app.Name, app.Flags) - if err != nil { - t.Errorf("error creating FlagSet: %s", err) - } - err = HandleAction(app.Action, NewContext(app, fs, nil)) - - if err == nil { - t.Fatalf("expected to receive error from Run, got none") - } - - exitErr, ok := err.(*ExitError) - - if !ok { - t.Fatalf("expected to receive a *ExitError") - } - - if !strings.HasPrefix(exitErr.Error(), "ERROR invalid Action type.") { - t.Fatalf("expected an unknown Action error, but got: %v", exitErr.Error()) - } - - if exitErr.ExitCode() != 2 { - t.Fatalf("expected error exit code to be 2, but got: %v", exitErr.ExitCode()) - } -} - -func TestHandleAction_WithInvalidFuncSignature(t *testing.T) { - app := NewApp() - app.Action = func() string { return "" } - fs, err := flagSet(app.Name, app.Flags) - if err != nil { - t.Errorf("error creating FlagSet: %s", err) - } - err = HandleAction(app.Action, NewContext(app, fs, nil)) - - if err == nil { - t.Fatalf("expected to receive error from Run, got none") - } - - exitErr, ok := err.(*ExitError) - - if !ok { - t.Fatalf("expected to receive a *ExitError") - } - - if !strings.HasPrefix(exitErr.Error(), "ERROR invalid Action type") { - t.Fatalf("expected an unknown Action error, but got: %v", exitErr.Error()) - } - - if exitErr.ExitCode() != 2 { - t.Fatalf("expected error exit code to be 2, but got: %v", exitErr.ExitCode()) - } -} - -func TestHandleAction_WithInvalidFuncReturnSignature(t *testing.T) { - app := NewApp() - app.Action = func(_ *Context) (int, error) { return 0, nil } - fs, err := flagSet(app.Name, app.Flags) - if err != nil { - t.Errorf("error creating FlagSet: %s", err) - } - err = HandleAction(app.Action, NewContext(app, fs, nil)) - - if err == nil { - t.Fatalf("expected to receive error from Run, got none") - } - - exitErr, ok := err.(*ExitError) - - if !ok { - t.Fatalf("expected to receive a *ExitError") - } - - if !strings.HasPrefix(exitErr.Error(), "ERROR invalid Action type") { - t.Fatalf("expected an invalid Action signature error, but got: %v", exitErr.Error()) - } - - if exitErr.ExitCode() != 2 { - t.Fatalf("expected error exit code to be 2, but got: %v", exitErr.ExitCode()) - } -} - -func TestHandleAction_WithUnknownPanic(t *testing.T) { - defer func() { refute(t, recover(), nil) }() - - var fn ActionFunc - - app := NewApp() - app.Action = func(ctx *Context) error { - fn(ctx) - return nil - } - fs, err := flagSet(app.Name, app.Flags) - if err != nil { - t.Errorf("error creating FlagSet: %s", err) - } - HandleAction(app.Action, NewContext(app, fs, nil)) -} - func TestShellCompletionForIncompleteFlags(t *testing.T) { - app := NewApp() - app.Flags = []Flag{ - IntFlag{ - Name: "test-completion", + app := &App{ + Flags: []Flag{ + &IntFlag{ + Name: "test-completion", + }, }, - } - app.EnableBashCompletion = true - app.BashComplete = func(ctx *Context) { - for _, command := range ctx.App.Commands { - if command.Hidden { - continue - } - - for _, name := range command.Names() { - fmt.Fprintln(ctx.App.Writer, name) - } - } - - for _, flag := range ctx.App.Flags { - for _, name := range strings.Split(flag.GetName(), ",") { - if name == BashCompletionFlag.GetName() { + EnableShellCompletion: true, + ShellComplete: func(ctx *Context) { + for _, command := range ctx.App.Commands { + if command.Hidden { continue } - switch name = strings.TrimSpace(name); len(name) { - case 0: - case 1: - fmt.Fprintln(ctx.App.Writer, "-"+name) - default: - fmt.Fprintln(ctx.App.Writer, "--"+name) + for _, name := range command.Names() { + fmt.Fprintln(ctx.App.Writer, name) } } - } - } - app.Action = func(ctx *Context) error { - return fmt.Errorf("should not get here") - } - err := app.Run([]string{"", "--test-completion", "--" + BashCompletionFlag.GetName()}) - if err != nil { - t.Errorf("app should not return an error: %s", err) - } -} -func TestHandleActionActuallyWorksWithActions(t *testing.T) { - var f ActionFunc - called := false - f = func(c *Context) error { - called = true - return nil + for _, flag := range ctx.App.Flags { + for _, name := range flag.Names() { + if name == genCompName() { + continue + } + + switch name = strings.TrimSpace(name); len(name) { + case 0: + case 1: + fmt.Fprintln(ctx.App.Writer, "-"+name) + default: + fmt.Fprintln(ctx.App.Writer, "--"+name) + } + } + } + }, + Action: func(ctx *Context) error { + return fmt.Errorf("should not get here") + }, } - - err := HandleAction(f, nil) - + err := app.Run([]string{"", "--test-completion", "--" + genCompName()}) if err != nil { - t.Errorf("Should not have errored: %v", err) - } - - if !called { - t.Errorf("Function was not called") + t.Errorf("app should not return an error: %s", err) } } diff --git a/command_test.go b/command_test.go index 6a9f3bd..7fb3980 100644 --- a/command_test.go +++ b/command_test.go @@ -124,15 +124,16 @@ func TestCommand_Run_BeforeSavesMetadata(t *testing.T) { } func TestCommand_OnUsageError_hasCommandContext(t *testing.T) { - app := NewApp() - app.Commands = []Command{ - { - Name: "bar", - Flags: []Flag{ - IntFlag{Name: "flag"}, - }, - OnUsageError: func(c *Context, err error, _ bool) error { - return fmt.Errorf("intercepted in %s: %s", c.Command.Name, err.Error()) + app := &App{ + Commands: []*Command{ + { + Name: "bar", + Flags: []Flag{ + &IntFlag{Name: "flag"}, + }, + OnUsageError: func(c *Context, err error, _ bool) error { + return fmt.Errorf("intercepted in %s: %s", c.Command.Name, err.Error()) + }, }, }, } @@ -176,23 +177,24 @@ func TestCommand_OnUsageError_WithWrongFlagValue(t *testing.T) { } func TestCommand_OnUsageError_WithSubcommand(t *testing.T) { - app := NewApp() - app.Commands = []Command{ - { - Name: "bar", - Subcommands: []Command{ - { - Name: "baz", + app := &App{ + Commands: []*Command{ + { + Name: "bar", + Subcommands: []*Command{ + { + Name: "baz", + }, + }, + Flags: []Flag{ + &IntFlag{Name: "flag"}, + }, + OnUsageError: func(c *Context, err error, _ bool) error { + if !strings.HasPrefix(err.Error(), "invalid value \"wrong\"") { + t.Errorf("Expect an invalid value error, but got \"%v\"", err) + } + return errors.New("intercepted: " + err.Error()) }, - }, - Flags: []Flag{ - IntFlag{Name: "flag"}, - }, - OnUsageError: func(c *Context, err error, _ bool) error { - if !strings.HasPrefix(err.Error(), "invalid value \"wrong\"") { - t.Errorf("Expect an invalid value error, but got \"%v\"", err) - } - return errors.New("intercepted: " + err.Error()) }, }, } @@ -208,22 +210,23 @@ func TestCommand_OnUsageError_WithSubcommand(t *testing.T) { } func TestCommand_Run_SubcommandsCanUseErrWriter(t *testing.T) { - app := NewApp() - app.ErrWriter = ioutil.Discard - app.Commands = []Command{ - { - Name: "bar", - Usage: "this is for testing", - Subcommands: []Command{ - { - Name: "baz", - Usage: "this is for testing", - Action: func(c *Context) error { - if c.App.ErrWriter != ioutil.Discard { - return fmt.Errorf("ErrWriter not passed") - } - - return nil + app := &App{ + ErrWriter: ioutil.Discard, + Commands: []*Command{ + { + Name: "bar", + Usage: "this is for testing", + Subcommands: []*Command{ + { + Name: "baz", + Usage: "this is for testing", + Action: func(c *Context) error { + if c.App.ErrWriter != ioutil.Discard { + return fmt.Errorf("ErrWriter not passed") + } + + return nil + }, }, }, }, diff --git a/context.go b/context.go index 2b80442..aa015b9 100644 --- a/context.go +++ b/context.go @@ -121,6 +121,11 @@ func (c *Context) Lineage() []*Context { return lineage } +// value returns the value of the flag coressponding to `name` +func (c *Context) value(name string) interface{} { + return c.flagSet.Lookup(name).Value.(flag.Getter).Get() +} + // Args returns the command line arguments associated with the context. func (c *Context) Args() Args { ret := args(c.flagSet.Args()) diff --git a/context_test.go b/context_test.go index 688bda1..edfbaee 100644 --- a/context_test.go +++ b/context_test.go @@ -2,7 +2,6 @@ package cli import ( "flag" - "os" "sort" "testing" "time" @@ -158,78 +157,6 @@ func TestContext_IsSet(t *testing.T) { expect(t, ctx.IsSet("bogus"), false) } -// XXX Corresponds to hack in context.IsSet for flags with EnvVar field -// Should be moved to `flag_test` in v2 -func TestContext_IsSet_fromEnv(t *testing.T) { - var ( - timeoutIsSet, tIsSet, noEnvVarIsSet, nIsSet bool - globalTimeoutIsSet, TIsSet, globalNoEnvVarIsSet, NIsSet bool - ) - - clearenv() - os.Setenv("GLOBAL_APP_TIMEOUT_SECONDS", "15.5") - os.Setenv("APP_TIMEOUT_SECONDS", "15.5") - os.Setenv("APP_PASSWORD", "") - a := App{ - Flags: []Flag{ - &Float64Flag{ - Name: "global-timeout", - Aliases: []string{"T"}, - EnvVars: []string{"GLOBAL_APP_TIMEOUT_SECONDS"}, - }, - &Float64Flag{ - Name: "global-no-env-var", - Aliases: []string{"N"}, - }, - }, - Commands: []*Command{ - { - Name: "hello", - Flags: []Flag{ - &Float64Flag{ - Name: "timeout", - Aliases: []string{"t"}, - EnvVars: []string{"APP_TIMEOUT_SECONDS"}, - }, - &Float64Flag{ - Name: "no-env-var", - Aliases: []string{"n"}, - }, - }, - Action: func(ctx *Context) error { - globalTimeoutIsSet = ctx.IsSet("global-timeout") - TIsSet = ctx.IsSet("T") - globalNoEnvVarIsSet = ctx.IsSet("global-no-env-var") - NIsSet = ctx.IsSet("N") - timeoutIsSet = ctx.IsSet("timeout") - tIsSet = ctx.IsSet("t") - noEnvVarIsSet = ctx.IsSet("no-env-var") - nIsSet = ctx.IsSet("n") - return nil - }, - }, - }, - } - a.Run([]string{"run", "hello"}) - expect(t, globalTimeoutIsSet, true) - expect(t, TIsSet, true) - expect(t, globalNoEnvVarIsSet, false) - expect(t, NIsSet, false) - expect(t, timeoutIsSet, true) - expect(t, tIsSet, true) - expect(t, passwordIsSet, true) - expect(t, pIsSet, true) - expect(t, noEnvVarIsSet, false) - expect(t, nIsSet, false) - - os.Setenv("APP_UNPARSABLE", "foobar") - if err := a.Run([]string{"run"}); err != nil { - t.Logf("error running Run(): %+v", err) - } - expect(t, unparsableIsSet, false) - expect(t, uIsSet, false) -} - func TestContext_NumFlags(t *testing.T) { set := flag.NewFlagSet("test", 0) set.Bool("myflag", false, "doc") diff --git a/errors.go b/errors.go index 963eb05..236ef02 100644 --- a/errors.go +++ b/errors.go @@ -66,7 +66,7 @@ type exitError struct { // Exit wraps a message and exit code into an ExitCoder suitable for handling by // HandleExitCoder -func Exit(message string, exitCode int) ExitCoder { +func Exit(message interface{}, exitCode int) ExitCoder { return &exitError{ exitCode: exitCode, message: message, @@ -74,7 +74,7 @@ func Exit(message string, exitCode int) ExitCoder { } func (ee *exitError) Error() string { - return ee.message + return fmt.Sprintf("%v", ee.message) } func (ee *exitError) ExitCode() int { @@ -112,7 +112,7 @@ func HandleExitCoder(err error) { func handleMultiError(multiErr MultiError) int { code := 1 - for _, merr := range multiErr.Errors { + for _, merr := range multiErr.Errors() { if multiErr2, ok := merr.(MultiError); ok { code = handleMultiError(multiErr2) } else { diff --git a/errors_test.go b/errors_test.go index 54f5348..7c85d7b 100644 --- a/errors_test.go +++ b/errors_test.go @@ -5,6 +5,8 @@ import ( "errors" "fmt" "testing" + + "github.com/stretchr/testify/assert" ) func TestHandleExitCoder_nil(t *testing.T) { @@ -95,7 +97,7 @@ func TestHandleExitCoder_ErrorWithFormat(t *testing.T) { ErrWriter = fakeErrWriter }() - err := NewExitError(NewErrorWithFormat("I am formatted"), 1) + err := Exit(NewErrorWithFormat("I am formatted"), 1) HandleExitCoder(err) expect(t, called, true) @@ -114,9 +116,9 @@ func TestHandleExitCoder_MultiErrorWithFormat(t *testing.T) { defer func() { OsExiter = fakeOsExiter }() - err := NewMultiError(NewErrorWithFormat("err1"), NewErrorWithFormat("err2")) + err := newMultiError(NewErrorWithFormat("err1"), NewErrorWithFormat("err2")) HandleExitCoder(err) - expect(t, called, true) - expect(t, ErrWriter.(*bytes.Buffer).String(), "This the format: err1\nThis the format: err2\n") + assert.True(t, called) + assert.Equal(t, "This the format: err1\nThis the format: err2\n", ErrWriter.(*bytes.Buffer).String()) } diff --git a/flag.go b/flag.go index ce768f0..8e6920a 100644 --- a/flag.go +++ b/flag.go @@ -22,11 +22,19 @@ var ( ) // GenerateCompletionFlag enables completion for all commands and subcommands -var GenerateCompletionFlag = &BoolFlag{ +var GenerateCompletionFlag Flag = &BoolFlag{ Name: "generate-completion", Hidden: true, } +func genCompName() string { + names := GenerateCompletionFlag.Names() + if len(names) == 0 { + return "generate-completion" + } + return names[0] +} + // InitCompletionFlag generates completion code var InitCompletionFlag = &StringFlag{ Name: "init-completion", @@ -34,7 +42,7 @@ var InitCompletionFlag = &StringFlag{ } // VersionFlag prints the version for the application -var VersionFlag = &BoolFlag{ +var VersionFlag Flag = &BoolFlag{ Name: "version", Aliases: []string{"v"}, Usage: "print the version", @@ -43,7 +51,7 @@ var VersionFlag = &BoolFlag{ // HelpFlag prints the help for all commands and subcommands. // Set to nil to disable the flag. The subcommand // will still be added unless HideHelp is set to true. -var HelpFlag = &BoolFlag{ +var HelpFlag Flag = &BoolFlag{ Name: "help", Aliases: []string{"h"}, Usage: "show help", @@ -121,7 +129,14 @@ type Generic interface { // Apply takes the flagset and calls Set on the generic flag with the value // provided by the user for parsing by the flag +// Ignores parsing errors func (f *GenericFlag) Apply(set *flag.FlagSet) { + f.ApplyWithError(set) +} + +// ApplyWithError takes the flagset and calls Set on the generic flag with the +// value provided by the user for parsing by the flag +func (f *GenericFlag) ApplyWithError(set *flag.FlagSet) error { val := f.Value if f.EnvVars != nil { for _, envVar := range f.EnvVars { @@ -135,6 +150,7 @@ func (f *GenericFlag) Apply(set *flag.FlagSet) { for _, name := range f.Names() { set.Var(val, name, f.Usage) } + return nil } // StringSlice wraps a []string to satisfy flag.Value @@ -188,7 +204,13 @@ func (f *StringSlice) Get() interface{} { } // Apply populates the flag given the flag set and environment +// Ignores errors func (f *StringSliceFlag) Apply(set *flag.FlagSet) { + f.ApplyWithError(set) +} + +// ApplyWithError populates the flag given the flag set and environment +func (f *StringSliceFlag) ApplyWithError(set *flag.FlagSet) error { if f.EnvVars != nil { for _, envVar := range f.EnvVars { if envVal, ok := syscall.Getenv(envVar); ok { @@ -212,6 +234,7 @@ func (f *StringSliceFlag) Apply(set *flag.FlagSet) { for _, name := range f.Names() { set.Var(f.Value, name, f.Usage) } + return nil } // IntSlice wraps an []int to satisfy flag.Value @@ -285,7 +308,13 @@ func (f *IntSlice) Get() interface{} { } // Apply populates the flag given the flag set and environment +// Ignores errors func (f *IntSliceFlag) Apply(set *flag.FlagSet) { + f.ApplyWithError(set) +} + +// ApplyWithError populates the flag given the flag set and environment +func (f *IntSliceFlag) ApplyWithError(set *flag.FlagSet) error { if f.EnvVars != nil { for _, envVar := range f.EnvVars { if envVal, ok := syscall.Getenv(envVar); ok { @@ -309,6 +338,7 @@ func (f *IntSliceFlag) Apply(set *flag.FlagSet) { for _, name := range f.Names() { set.Var(f.Value, name, f.Usage) } + return nil } // Int64Slice is an opaque type for []int to satisfy flag.Value @@ -362,7 +392,13 @@ func (f *Int64Slice) Get() interface{} { } // Apply populates the flag given the flag set and environment +// Ignores errors func (f *Int64SliceFlag) Apply(set *flag.FlagSet) { + f.ApplyWithError(set) +} + +// ApplyWithError populates the flag given the flag set and environment +func (f *Int64SliceFlag) ApplyWithError(set *flag.FlagSet) error { if f.EnvVars != nil { for _, envVar := range f.EnvVars { if envVal, ok := syscall.Getenv(envVar); ok { @@ -386,10 +422,17 @@ func (f *Int64SliceFlag) Apply(set *flag.FlagSet) { for _, name := range f.Names() { set.Var(f.Value, name, f.Usage) } + return nil } // Apply populates the flag given the flag set and environment +// Ignores errors func (f *BoolFlag) Apply(set *flag.FlagSet) { + f.ApplyWithError(set) +} + +// ApplyWithError populates the flag given the flag set and environment +func (f *BoolFlag) ApplyWithError(set *flag.FlagSet) error { if f.EnvVars != nil { for _, envVar := range f.EnvVars { if envVal, ok := syscall.Getenv(envVar); ok { @@ -398,7 +441,6 @@ func (f *BoolFlag) Apply(set *flag.FlagSet) { f.Value = envValBool } - val = envValBool break } } @@ -411,10 +453,17 @@ func (f *BoolFlag) Apply(set *flag.FlagSet) { } set.Bool(name, f.Value, f.Usage) } + return nil } // Apply populates the flag given the flag set and environment +// Ignores errors func (f *StringFlag) Apply(set *flag.FlagSet) { + f.ApplyWithError(set) +} + +// ApplyWithError populates the flag given the flag set and environment +func (f *StringFlag) ApplyWithError(set *flag.FlagSet) error { if f.EnvVars != nil { for _, envVar := range f.EnvVars { if envVal, ok := syscall.Getenv(envVar); ok { @@ -431,10 +480,17 @@ func (f *StringFlag) Apply(set *flag.FlagSet) { } set.String(name, f.Value, f.Usage) } + return nil } // Apply populates the flag given the flag set and environment +// Ignores errors func (f *IntFlag) Apply(set *flag.FlagSet) { + f.ApplyWithError(set) +} + +// ApplyWithError populates the flag given the flag set and environment +func (f *IntFlag) ApplyWithError(set *flag.FlagSet) error { if f.EnvVars != nil { for _, envVar := range f.EnvVars { if envVal, ok := syscall.Getenv(envVar); ok { @@ -455,10 +511,17 @@ func (f *IntFlag) Apply(set *flag.FlagSet) { } set.Int(name, f.Value, f.Usage) } + return nil } // Apply populates the flag given the flag set and environment +// Ignores errors func (f *Int64Flag) Apply(set *flag.FlagSet) { + f.ApplyWithError(set) +} + +// ApplyWithError populates the flag given the flag set and environment +func (f *Int64Flag) ApplyWithError(set *flag.FlagSet) error { if f.EnvVars != nil { for _, envVar := range f.EnvVars { if envVal, ok := syscall.Getenv(envVar); ok { @@ -476,14 +539,21 @@ func (f *Int64Flag) Apply(set *flag.FlagSet) { for _, name := range f.Names() { if f.Destination != nil { set.Int64Var(f.Destination, name, f.Value, f.Usage) - return + return nil } set.Int64(name, f.Value, f.Usage) } + return nil } // Apply populates the flag given the flag set and environment +// Ignores errors func (f *UintFlag) Apply(set *flag.FlagSet) { + f.ApplyWithError(set) +} + +// ApplyWithError populates the flag given the flag set and environment +func (f *UintFlag) ApplyWithError(set *flag.FlagSet) error { if f.EnvVars != nil { for _, envVar := range f.EnvVars { if envVal, ok := syscall.Getenv(envVar); ok { @@ -501,14 +571,21 @@ func (f *UintFlag) Apply(set *flag.FlagSet) { for _, name := range f.Names() { if f.Destination != nil { set.UintVar(f.Destination, name, f.Value, f.Usage) - return + return nil } set.Uint(name, f.Value, f.Usage) } + return nil } // Apply populates the flag given the flag set and environment +// Ignores errors func (f *Uint64Flag) Apply(set *flag.FlagSet) { + f.ApplyWithError(set) +} + +// ApplyWithError populates the flag given the flag set and environment +func (f *Uint64Flag) ApplyWithError(set *flag.FlagSet) error { if f.EnvVars != nil { for _, envVar := range f.EnvVars { if envVal, ok := syscall.Getenv(envVar); ok { @@ -526,14 +603,21 @@ func (f *Uint64Flag) Apply(set *flag.FlagSet) { for _, name := range f.Names() { if f.Destination != nil { set.Uint64Var(f.Destination, name, f.Value, f.Usage) - return + return nil } set.Uint64(name, f.Value, f.Usage) } + return nil } // Apply populates the flag given the flag set and environment +// Ignores errors func (f *DurationFlag) Apply(set *flag.FlagSet) { + f.ApplyWithError(set) +} + +// ApplyWithError populates the flag given the flag set and environment +func (f *DurationFlag) ApplyWithError(set *flag.FlagSet) error { if f.EnvVars != nil { for _, envVar := range f.EnvVars { if envVal, ok := syscall.Getenv(envVar); ok { @@ -555,10 +639,17 @@ func (f *DurationFlag) Apply(set *flag.FlagSet) { } set.Duration(name, f.Value, f.Usage) } + return nil } // Apply populates the flag given the flag set and environment +// Ignores errors func (f *Float64Flag) Apply(set *flag.FlagSet) { + f.ApplyWithError(set) +} + +// ApplyWithError populates the flag given the flag set and environment +func (f *Float64Flag) ApplyWithError(set *flag.FlagSet) error { if f.EnvVars != nil { for _, envVar := range f.EnvVars { if envVal, ok := syscall.Getenv(envVar); ok { @@ -580,6 +671,7 @@ func (f *Float64Flag) Apply(set *flag.FlagSet) { } set.Float64(name, f.Value, f.Usage) } + return nil } // NewFloat64Slice makes a *Float64Slice with default values @@ -633,7 +725,13 @@ func (f *Float64Slice) Value() []float64 { } // Apply populates the flag given the flag set and environment +// Ignores errors func (f *Float64SliceFlag) Apply(set *flag.FlagSet) { + f.ApplyWithError(set) +} + +// ApplyWithError populates the flag given the flag set and environment +func (f *Float64SliceFlag) ApplyWithError(set *flag.FlagSet) error { if f.EnvVars != nil { for _, envVar := range f.EnvVars { if envVal, ok := syscall.Getenv(envVar); ok { @@ -658,6 +756,7 @@ func (f *Float64SliceFlag) Apply(set *flag.FlagSet) { for _, name := range f.Names() { set.Var(f.Value, name, f.Usage) } + return nil } func visibleFlags(fl []Flag) []Flag { diff --git a/flag_test.go b/flag_test.go index 9f31f27..1e44db6 100644 --- a/flag_test.go +++ b/flag_test.go @@ -49,57 +49,57 @@ func TestFlagsFromEnv(t *testing.T) { flag Flag errRegexp string }{ - {"", false, &BoolFlag{Name: "debug", EnvVar: "DEBUG"}, ""}, - {"1", true, &BoolFlag{Name: "debug", EnvVar: "DEBUG"}, ""}, - {"false", false, &BoolFlag{Name: "debug", EnvVar: "DEBUG"}, ""}, - {"foobar", true, &BoolFlag{Name: "debug", EnvVar: "DEBUG"}, fmt.Sprintf(`could not parse foobar as bool value for flag debug: .*`)}, + {"", false, &BoolFlag{Name: "debug", EnvVars: []string{"DEBUG"}}, ""}, + {"1", true, &BoolFlag{Name: "debug", EnvVars: []string{"DEBUG"}}, ""}, + {"false", false, &BoolFlag{Name: "debug", EnvVars: []string{"DEBUG"}}, ""}, + {"foobar", true, &BoolFlag{Name: "debug", EnvVars: []string{"DEBUG"}}, fmt.Sprintf(`could not parse foobar as bool value for flag debug: .*`)}, - {"1s", 1 * time.Second, &DurationFlag{Name: "time", EnvVar: "TIME"}, ""}, - {"foobar", false, &DurationFlag{Name: "time", EnvVar: "TIME"}, fmt.Sprintf(`could not parse foobar as duration for flag time: .*`)}, + {"1s", 1 * time.Second, &DurationFlag{Name: "time", EnvVars: []string{"TIME"}}, ""}, + {"foobar", false, &DurationFlag{Name: "time", EnvVars: []string{"TIME"}}, fmt.Sprintf(`could not parse foobar as duration for flag time: .*`)}, - {"1.2", 1.2, &Float64Flag{Name: "seconds", EnvVar: "SECONDS"}, ""}, - {"1", 1.0, &Float64Flag{Name: "seconds", EnvVar: "SECONDS"}, ""}, - {"foobar", 0, &Float64Flag{Name: "seconds", EnvVar: "SECONDS"}, fmt.Sprintf(`could not parse foobar as float64 value for flag seconds: .*`)}, + {"1.2", 1.2, &Float64Flag{Name: "seconds", EnvVars: []string{"SECONDS"}}, ""}, + {"1", 1.0, &Float64Flag{Name: "seconds", EnvVars: []string{"SECONDS"}}, ""}, + {"foobar", 0, &Float64Flag{Name: "seconds", EnvVars: []string{"SECONDS"}}, fmt.Sprintf(`could not parse foobar as float64 value for flag seconds: .*`)}, - {"1", int64(1), &Int64Flag{Name: "seconds", EnvVar: "SECONDS"}, ""}, - {"1.2", 0, &Int64Flag{Name: "seconds", EnvVar: "SECONDS"}, fmt.Sprintf(`could not parse 1.2 as int value for flag seconds: .*`)}, - {"foobar", 0, &Int64Flag{Name: "seconds", EnvVar: "SECONDS"}, fmt.Sprintf(`could not parse foobar as int value for flag seconds: .*`)}, + {"1", int64(1), &Int64Flag{Name: "seconds", EnvVars: []string{"SECONDS"}}, ""}, + {"1.2", 0, &Int64Flag{Name: "seconds", EnvVars: []string{"SECONDS"}}, fmt.Sprintf(`could not parse 1.2 as int value for flag seconds: .*`)}, + {"foobar", 0, &Int64Flag{Name: "seconds", EnvVars: []string{"SECONDS"}}, fmt.Sprintf(`could not parse foobar as int value for flag seconds: .*`)}, - {"1", 1, &IntFlag{Name: "seconds", EnvVar: "SECONDS"}, ""}, - {"1.2", 0, &IntFlag{Name: "seconds", EnvVar: "SECONDS"}, fmt.Sprintf(`could not parse 1.2 as int value for flag seconds: .*`)}, - {"foobar", 0, &IntFlag{Name: "seconds", EnvVar: "SECONDS"}, fmt.Sprintf(`could not parse foobar as int value for flag seconds: .*`)}, + {"1", 1, &IntFlag{Name: "seconds", EnvVars: []string{"SECONDS"}}, ""}, + {"1.2", 0, &IntFlag{Name: "seconds", EnvVars: []string{"SECONDS"}}, fmt.Sprintf(`could not parse 1.2 as int value for flag seconds: .*`)}, + {"foobar", 0, &IntFlag{Name: "seconds", EnvVars: []string{"SECONDS"}}, fmt.Sprintf(`could not parse foobar as int value for flag seconds: .*`)}, - {"1,2", NewIntSlice(1, 2), &IntSliceFlag{Name: "seconds", EnvVar: "SECONDS"}, ""}, - {"1.2,2", NewIntSlice(), &IntSliceFlag{Name: "seconds", EnvVar: "SECONDS"}, fmt.Sprintf(`could not parse 1.2,2 as int slice value for flag seconds: .*`)}, - {"foobar", NewIntSlice(), &IntSliceFlag{Name: "seconds", EnvVar: "SECONDS"}, fmt.Sprintf(`could not parse foobar as int slice value for flag seconds: .*`)}, + {"1,2", NewIntSlice(1, 2), &IntSliceFlag{Name: "seconds", EnvVars: []string{"SECONDS"}}, ""}, + {"1.2,2", NewIntSlice(), &IntSliceFlag{Name: "seconds", EnvVars: []string{"SECONDS"}}, fmt.Sprintf(`could not parse 1.2,2 as int slice value for flag seconds: .*`)}, + {"foobar", NewIntSlice(), &IntSliceFlag{Name: "seconds", EnvVars: []string{"SECONDS"}}, fmt.Sprintf(`could not parse foobar as int slice value for flag seconds: .*`)}, - {"1,2", NewInt64Slice(1, 2), &Int64SliceFlag{Name: "seconds", EnvVar: "SECONDS"}, ""}, - {"1.2,2", NewInt64Slice(), &Int64SliceFlag{Name: "seconds", EnvVar: "SECONDS"}, fmt.Sprintf(`could not parse 1.2,2 as int64 slice value for flag seconds: .*`)}, - {"foobar", NewInt64Slice(), &Int64SliceFlag{Name: "seconds", EnvVar: "SECONDS"}, fmt.Sprintf(`could not parse foobar as int64 slice value for flag seconds: .*`)}, + {"1,2", NewInt64Slice(1, 2), &Int64SliceFlag{Name: "seconds", EnvVars: []string{"SECONDS"}}, ""}, + {"1.2,2", NewInt64Slice(), &Int64SliceFlag{Name: "seconds", EnvVars: []string{"SECONDS"}}, fmt.Sprintf(`could not parse 1.2,2 as int64 slice value for flag seconds: .*`)}, + {"foobar", NewInt64Slice(), &Int64SliceFlag{Name: "seconds", EnvVars: []string{"SECONDS"}}, fmt.Sprintf(`could not parse foobar as int64 slice value for flag seconds: .*`)}, - {"foo", "foo", &StringFlag{Name: "name", EnvVar: "NAME"}, ""}, + {"foo", "foo", &StringFlag{Name: "name", EnvVars: []string{"NAME"}}, ""}, - {"foo,bar", NewStringSlice("foo", "bar"), &StringSliceFlag{Name: "names", EnvVar: "NAMES"}, ""}, + {"foo,bar", NewStringSlice("foo", "bar"), &StringSliceFlag{Name: "names", EnvVars: []string{"NAMES"}}, ""}, - {"1", uint(1), &UintFlag{Name: "seconds", EnvVar: "SECONDS"}, ""}, - {"1.2", 0, &UintFlag{Name: "seconds", EnvVar: "SECONDS"}, fmt.Sprintf(`could not parse 1.2 as uint value for flag seconds: .*`)}, - {"foobar", 0, &UintFlag{Name: "seconds", EnvVar: "SECONDS"}, fmt.Sprintf(`could not parse foobar as uint value for flag seconds: .*`)}, + {"1", uint(1), &UintFlag{Name: "seconds", EnvVars: []string{"SECONDS"}}, ""}, + {"1.2", 0, &UintFlag{Name: "seconds", EnvVars: []string{"SECONDS"}}, fmt.Sprintf(`could not parse 1.2 as uint value for flag seconds: .*`)}, + {"foobar", 0, &UintFlag{Name: "seconds", EnvVars: []string{"SECONDS"}}, fmt.Sprintf(`could not parse foobar as uint value for flag seconds: .*`)}, - {"1", uint64(1), &Uint64Flag{Name: "seconds", EnvVar: "SECONDS"}, ""}, - {"1.2", 0, &Uint64Flag{Name: "seconds", EnvVar: "SECONDS"}, fmt.Sprintf(`could not parse 1.2 as uint64 value for flag seconds: .*`)}, - {"foobar", 0, &Uint64Flag{Name: "seconds", EnvVar: "SECONDS"}, fmt.Sprintf(`could not parse foobar as uint64 value for flag seconds: .*`)}, + {"1", uint64(1), &Uint64Flag{Name: "seconds", EnvVars: []string{"SECONDS"}}, ""}, + {"1.2", 0, &Uint64Flag{Name: "seconds", EnvVars: []string{"SECONDS"}}, fmt.Sprintf(`could not parse 1.2 as uint64 value for flag seconds: .*`)}, + {"foobar", 0, &Uint64Flag{Name: "seconds", EnvVars: []string{"SECONDS"}}, fmt.Sprintf(`could not parse foobar as uint64 value for flag seconds: .*`)}, - {"foo,bar", &Parser{"foo", "bar"}, &GenericFlag{Name: "names", Value: &Parser{}, EnvVar: "NAMES"}, ""}, + {"foo,bar", &Parser{"foo", "bar"}, &GenericFlag{Name: "names", Value: &Parser{}, EnvVars: []string{"NAMES"}}, ""}, } for _, test := range flagTests { clearenv() - os.Setenv(reflect.ValueOf(test.flag).FieldByName("EnvVar").String(), test.input) + os.Setenv(reflect.ValueOf(test.flag).FieldByName("EnvVars").Slice(0, 1).String(), test.input) a := App{ Flags: []Flag{test.flag}, Action: func(ctx *Context) error { - if !reflect.DeepEqual(ctx.value(test.flag.GetName()), test.output) { - t.Errorf("expected %+v to be parsed as %+v, instead was %+v", test.input, test.output, ctx.value(test.flag.GetName())) + if !reflect.DeepEqual(ctx.value(test.flag.Names()[0]), test.output) { + t.Errorf("expected %+v to be parsed as %+v, instead was %+v", test.input, test.output, ctx.value(test.flag.Names()[0])) } return nil }, diff --git a/help.go b/help.go index 3e6a461..6c4f213 100644 --- a/help.go +++ b/help.go @@ -266,11 +266,9 @@ func printHelp(out io.Writer, templ string, data interface{}) { func checkVersion(c *Context) bool { found := false - if VersionFlag.Name != "" { - for _, name := range VersionFlag.Names() { - if c.Bool(name) { - found = true - } + for _, name := range VersionFlag.Names() { + if c.Bool(name) { + found = true } } return found @@ -278,11 +276,9 @@ func checkVersion(c *Context) bool { func checkHelp(c *Context) bool { found := false - if HelpFlag.Name != "" { - for _, name := range HelpFlag.Names() { - if c.Bool(name) { - found = true - } + for _, name := range HelpFlag.Names() { + if c.Bool(name) { + found = true } } return found @@ -307,14 +303,14 @@ func checkSubcommandHelp(c *Context) bool { } func checkShellCompleteFlag(a *App, arguments []string) (bool, []string) { - if !a.EnableBashCompletion { + if !a.EnableShellCompletion { return false, arguments } pos := len(arguments) - 1 lastArg := arguments[pos] - if lastArg != "--"+BashCompletionFlag.GetName() { + if lastArg != "--"+genCompName() { return false, arguments } @@ -322,7 +318,7 @@ func checkShellCompleteFlag(a *App, arguments []string) (bool, []string) { } func checkCompletions(c *Context) bool { - if !c.Bool(GenerateCompletionFlag.Name) && !c.App.EnableShellCompletion { + if !c.Bool(genCompName()) && !c.App.EnableShellCompletion { return false } @@ -339,7 +335,7 @@ func checkCompletions(c *Context) bool { } func checkCommandCompletions(c *Context, name string) bool { - if !c.Bool(GenerateCompletionFlag.Name) && !c.App.EnableShellCompletion { + if !c.Bool(genCompName()) && !c.App.EnableShellCompletion { return false } diff --git a/help_test.go b/help_test.go index 4fbb0fc..375b28e 100644 --- a/help_test.go +++ b/help_test.go @@ -259,7 +259,7 @@ func TestShowSubcommandHelp_CommandAliases(t *testing.T) { func TestShowCommandHelp_Customtemplate(t *testing.T) { app := &App{ - Commands: []Command{ + Commands: []*Command{ { Name: "frobbly", Action: func(ctx *Context) error { @@ -301,7 +301,7 @@ EXAMPLES: func TestShowSubcommandHelp_CommandUsageText(t *testing.T) { app := &App{ - Commands: []Command{ + Commands: []*Command{ { Name: "frobbly", UsageText: "this is usage text", @@ -321,10 +321,10 @@ func TestShowSubcommandHelp_CommandUsageText(t *testing.T) { func TestShowSubcommandHelp_SubcommandUsageText(t *testing.T) { app := &App{ - Commands: []Command{ + Commands: []*Command{ { Name: "frobbly", - Subcommands: []Command{ + Subcommands: []*Command{ { Name: "bobbly", UsageText: "this is usage text", @@ -377,7 +377,7 @@ func TestShowAppHelp_HiddenCommand(t *testing.T) { func TestShowAppHelp_CustomAppTemplate(t *testing.T) { app := &App{ - Commands: []Command{ + Commands: []*Command{ { Name: "frobbly", Action: func(ctx *Context) error { diff --git a/runtests b/runtests index bcd8f4c..fe0d011 100755 --- a/runtests +++ b/runtests @@ -1,7 +1,8 @@ #!/usr/bin/env python -from __future__ import print_function +from __future__ import print_function, unicode_literals import argparse +import codecs import glob import os import platform @@ -37,7 +38,7 @@ def _target(func): @_target def _test(): - if check_output('go version'.split()).split()[2] < 'go1.2': + if _go_version() < 'go1.2': _run('go test -v .') return @@ -61,7 +62,7 @@ def _test(): @_target def _gfmrun(): - go_version = check_output('go version'.split()).split()[2] + go_version = _go_version() if go_version < 'go1.3': print('runtests: skip on {}'.format(go_version), file=sys.stderr) return @@ -75,7 +76,7 @@ def _vet(): @_target def _migrations(): - go_version = check_output('go version'.split()).split()[2] + go_version = _go_version() if go_version < 'go1.3': print('runtests: skip on {}'.format(go_version), file=sys.stderr) return @@ -115,7 +116,7 @@ def _toc(): @_target def _gen(): - go_version = check_output('go version'.split()).split()[2] + go_version = _go_version() if go_version < 'go1.5': print('runtests: skip on {}'.format(go_version), file=sys.stderr) return @@ -133,26 +134,30 @@ def _run(command): def _gfmrun_count(): - with open('README.md') as infile: + with codecs.open('README.md', 'r', 'utf-8') as infile: lines = infile.read().splitlines() - return len(filter(_is_go_runnable, lines)) + return len(list(filter(_is_go_runnable, lines))) def _is_go_runnable(line): return line.startswith('package main') +def _go_version(): + return check_output('go version'.split()).decode('utf-8').split()[2] + + def _combine_coverprofiles(coverprofiles): combined = tempfile.NamedTemporaryFile( suffix='.coverprofile', delete=False ) - combined.write('mode: set\n') + combined.write(b'mode: set\n') for coverprofile in coverprofiles: - with open(coverprofile, 'r') as infile: + with codecs.open(coverprofile, 'r', 'utf-8') as infile: for line in infile.readlines(): if not line.startswith('mode: '): - combined.write(line) + combined.write(line.encode('utf-8')) combined.flush() name = combined.name