Skip to content
This repository has been archived by the owner on May 26, 2023. It is now read-only.

Commit

Permalink
add extra flag types and validation method
Browse files Browse the repository at this point in the history
  • Loading branch information
robert-zaremba committed Mar 24, 2020
1 parent 4683636 commit 4c27757
Show file tree
Hide file tree
Showing 10 changed files with 215 additions and 13 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ $ cat > gopher.go

import (
"fmt"
"github.com/namsral/flag"
"github.com/robert-zaremba/flag"
)

func main() {
Expand Down Expand Up @@ -83,7 +83,7 @@ It's intended for projects which require a simple configuration made available t
Example:

```go
import "github.com/namsral/flag"
import "github.com/robert-zaremba/flag"

flag.String(flag.DefaultConfigFlagname, "", "path to config file")
flag.Int("age", 24, "help message for age")
Expand Down Expand Up @@ -161,7 +161,7 @@ age=33

For more examples see the [examples][] directory in the project repository.

[examples]: https://github.com/namsral/flag/tree/master/examples
[examples]: https://github.com/robert-zaremba/flag/tree/master/examples

That's it.

Expand Down
2 changes: 1 addition & 1 deletion examples/gopher.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package main

import (
"github.com/namsral/flag"
"github.com/robert-zaremba/flag"
"fmt"
)

Expand Down
6 changes: 1 addition & 5 deletions extras.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,9 +178,5 @@ func (f *FlagSet) ParseFile(path string) error {
f.actual[name] = flag
}

if err := scanner.Err(); err != nil {
return err
}

return nil
return scanner.Err()
}
2 changes: 1 addition & 1 deletion extras_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
"testing"
"time"

. "github.com/namsral/flag"
. "github.com/robert-zaremba/flag"
)

// ResetForTesting clears all flag state and sets the usage function as directed.
Expand Down
14 changes: 12 additions & 2 deletions flag_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
"testing"
"time"

. "github.com/namsral/flag"
. "github.com/robert-zaremba/flag"
)

func boolString(s string) string {
Expand Down Expand Up @@ -379,6 +379,16 @@ func TestHelp(t *testing.T) {
}
}

const defaultOutput2 = " -A=false: for bootstrapping, allow 'any' type\n" +
" -Alongflagname=false: disable bounds checking\n" +
" -C=true: a boolean defaulting to true\n" +
" -D=\"\": set relative `path` for local imports\n" +
" -F=2.7: a non-zero `number`\n" +
" -G=0: a float that defaults to zero\n" +
" -N=27: a non-zero int\n" +
" -Z=0: an int that defaults to zero\n" +
" -maxT=0s: set `timeout` for dial\n"

const defaultOutput = ` -A for bootstrapping, allow 'any' type
-Alongflagname
disable bounds checking
Expand Down Expand Up @@ -413,6 +423,6 @@ func TestPrintDefaults(t *testing.T) {
fs.PrintDefaults()
got := buf.String()
if got != defaultOutput {
t.Errorf("got %q want %q\n", got, defaultOutput)
t.Errorf("got\n%q want\n%q\n", got, defaultOutput)
}
}
7 changes: 6 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,9 @@ module github.com/robert-zaremba/flag

go 1.13

require github.com/namsral/flag v1.7.4-pre
require (
github.com/robert-zaremba/checkers v1.0.1
github.com/robert-zaremba/errstack v1.0.2
github.com/robert-zaremba/go-bat v1.0.1
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f
)
27 changes: 27 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,2 +1,29 @@
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A=
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg=
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 h1:iQTw/8FWTuc7uiaSepXwyf3o52HaUYcV+Tu66S3F5GA=
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/mozillazg/go-unidecode v0.1.1 h1:uiRy1s4TUqLbcROUrnCN/V85Jlli2AmDF6EeAXOeMHE=
github.com/mozillazg/go-unidecode v0.1.1/go.mod h1:fYMdhyjni9ZeEmS6OE/GJHDLsF8TQvIVDwYR/drR26Q=
github.com/namsral/flag v1.7.4-pre h1:b2ScHhoCUkbsq0d2C15Mv+VU8bl8hAXV8arnWiOHNZs=
github.com/namsral/flag v1.7.4-pre/go.mod h1:OXldTctbM6SWH1K899kPZcf65KxJiD7MsceFUpB5yDo=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/robert-zaremba/checkers v1.0.1 h1:AjxF5P+YkOeWsvFSbTcdk/0lvNDDdkzaM3HrEc4XSEE=
github.com/robert-zaremba/checkers v1.0.1/go.mod h1:wUVuqhZje9IKym5bZuW1nbA0GqRRgnYTMehly17F56Q=
github.com/robert-zaremba/errstack v1.0.2 h1:WSNVsQnd3YFLDBW1FysLkJxHkbRsbpgaYk7R8gBJyRQ=
github.com/robert-zaremba/errstack v1.0.2/go.mod h1:KCGDqMDzP5xgeKXM33WryQ8+Zj7EaxnP+J6t3OBhU14=
github.com/robert-zaremba/errstack v3.1.0+incompatible h1:wLAs0u9qr7u4s9UVtCAhx1I4dagUVx5d/MuYhK9sNr4=
github.com/robert-zaremba/errstack v3.1.0+incompatible/go.mod h1:YiMUuTTLstXOe9Ao1J0w0eTf8CaGS+q4WDIJaypSwVI=
github.com/robert-zaremba/go-bat v1.0.1 h1:5C/UryVjj0sKPvT4UPCI2gaIrsXR7sXASMM45ZxCcKo=
github.com/robert-zaremba/go-bat v1.0.1/go.mod h1:GYLn+EyFubUfo/yPrQsma+cri4vCjRC+Qlovomu6sWw=
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
73 changes: 73 additions & 0 deletions srv.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package flag

import (
"flag"
"net/url"
"os"

"github.com/robert-zaremba/errstack"
bat "github.com/robert-zaremba/go-bat"
)

// URL is a structure containing network connection details to a service
// The value should have the following structure:
// //username:password@host:port/directory
type URL struct {
url.URL
}

// Set implements github.com/robert-zaremba/flag Value interface
func (a *URL) Set(value string) error {
u, err := url.Parse(value)
if err != nil {
return errstack.WrapAsReq(err, "Can't parse network address config")
}
a.URL = *u
return nil
}

// Path represents a file in a filesystem
type Path struct {
Path string
}

// Set implements github.com/robert-zaremba/flag Value interface
func (a *Path) Set(filePath string) error {
a.Path = filePath
return a.Check()
}

// String implements github.com/robert-zaremba/flag Value interface
func (a *Path) String() string {
return a.Path
}

// Check returns an error if it can't find the file
func (a Path) Check() error {
if a.Path == "" {
return errstack.NewReq("File path can't be empty")
}
_, err := os.Stat(a.Path)
return err
}

// SrvFlags represents common server flags
type SrvFlags struct {
Production *bool
Port *string
}

// NewSrvFlags setups common server flags
func NewSrvFlags() SrvFlags {
return SrvFlags{
flag.Bool("production", false, "Run in production mode"),
flag.String("port", "8000", "The HTTP listening port"),
}
}

// Check validates the flags. It may panic!
func (f SrvFlags) Check() error {
errb := errstack.NewBuilder()
bat.Atoi64Errp(*f.Port, errb.Putter("port"))
return errb.ToReqErr()
}
54 changes: 54 additions & 0 deletions srv_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package flag

import (
"testing"

rzcheck "github.com/robert-zaremba/checkers"
gocheck "gopkg.in/check.v1"
)

// Hook up gocheck into the "go test" runner.
func Test(t *testing.T) { gocheck.TestingT(t) }

type ExtraSuite struct{}

func init() {
gocheck.Suite(&ExtraSuite{})
}

func (s *ExtraSuite) TestValidateDirExists(c *gocheck.C) {
ff := Path{}
err := ff.Set("/tmp")
c.Assert(err, gocheck.IsNil)
c.Assert(ff.String(), gocheck.Equals, "/tmp")
}

func (s *ExtraSuite) TestValidatePermissionDenied(c *gocheck.C) {
ff := Path{}
_ = ff.Set("/root/secret")
err := ff.Check()
c.Assert(err, gocheck.ErrorMatches, "stat /root/secret: permission denied")
}

func (s *ExtraSuite) TestValidateNoFile(c *gocheck.C) {
ff := Path{}
_ = ff.Set("")
err := ff.Check()
c.Assert(err, rzcheck.ErrorContains, "File path can't be empty")
}

func (s *ExtraSuite) TestHandleBadDefaultWithPanic(c *gocheck.C) {
ff := Path{"hello-world"}
err := ff.Check()
c.Assert(err, gocheck.ErrorMatches, "stat hello-world: no such file or directory")
}

func (s *ExtraSuite) TestHandleDefault(c *gocheck.C) {
ff := Path{"/tmp"}
c.Assert(ff.String(), gocheck.Equals, "/tmp")
ff = Path{"/"}
c.Assert(ff.String(), gocheck.Equals, "/")
err := ff.Set("/tmp")
c.Assert(err, gocheck.IsNil)
c.Assert(ff.String(), gocheck.Equals, "/tmp")
}
37 changes: 37 additions & 0 deletions validate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package flag

import (
"flag"
"fmt"
"strings"
)

// Checker is an interface for type which has a Check function
type Checker interface {
Check() error
}

// Validate runs flag checkers
func Validate(positionalArgs string, checkers ...Checker) error {
expected := strings.Fields(positionalArgs)
if len(expected) != flag.NArg() {
return fmt.Errorf("missing required positional arguments: %s. Number of args Provided: %d, expected: %d",
expected, flag.NArg(), len(expected))
}
for _, c := range checkers {
if err := c.Check(); err != nil {
return err
}
}
return nil
}

// CheckMany is a helper function to check many flag components
func CheckMany(checkers ...Checker) error {
for _, c := range checkers {
if err := c.Check(); err != nil {
return err
}
}
return nil
}

0 comments on commit 4c27757

Please sign in to comment.