Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,58 @@ func main() {

検証は `go-flags` によるパース成功後、`Run` メソッドの呼び出し前に実行されます。`flagrun.Go` / `flagrun.Check` / `flagrun.Ship` のいずれでも利用できます。

## カスタムフラグ型

### `flagrun.Bytes` — 人間可読なバイト数

`flagrun.Bytes` は `go-flags` 向けのカスタム型で、`10MB` や `2GiB` のような人間可読な文字列を数値に変換します。内部では [go-humanize](https://github.com/dustin/go-humanize) の `ParseBytes` を利用しています。

```go
package main

import (
"fmt"

"github.com/monitoring-forge/flagrun"
)

type Opt struct {
MaxSize flagrun.Bytes `short:"s" long:"max-size" default:"1MB" description:"Maximum size"`
}

func (p *Opt) Run(args []string) (string, int) {
fmt.Printf("max size: %d bytes\n", p.MaxSize)
return "ok\t1", flagrun.OK
}
```

### `flagrun.Re` — 正規表現フラグ

`flagrun.Re` は `go-flags` 向けのカスタム型で、フラグ値を `regexp.Regexp` としてパースします。未指定時や空文字の場合は `Present()` が `false` を返し、正規表現のコンパイルに失敗した場合はエラーを返します。

```go
package main

import (
"fmt"

"github.com/monitoring-forge/flagrun"
)

type Opt struct {
Pattern flagrun.Re `short:"p" long:"pattern" description:"Filter pattern"`
}

func (p *Opt) Run(args []string) (string, int) {
if p.Pattern.Present() {
fmt.Printf("pattern: %s\n", p.Pattern.String())
matched := p.Pattern.Regexp().MatchString("example")
fmt.Printf("matched: %v\n", matched)
}
return "ok\t1", flagrun.OK
}
```

## オプション

| `flagrun.Go` / `flagrun.Check` / `flagrun.Ship` では、以下の関数を使って動作をカスタマイズできます。
Expand Down
16 changes: 16 additions & 0 deletions flaghuman.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package flagrun

import "github.com/dustin/go-humanize"

// Bytes is a custom type to handle human-readable byte inputs
type Bytes uint64

// UnmarshalFlag parses human inputs like "10MB" or "2GiB" using go-humanize
func (hb *Bytes) UnmarshalFlag(value string) error {
bytes, err := humanize.ParseBytes(value)
if err != nil {
return err
}
*hb = Bytes(bytes)
return nil
}
20 changes: 20 additions & 0 deletions flaghuman_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package flagrun

import "testing"

func TestHumanBytesUnmarshalFlag(t *testing.T) {
var hb Bytes
if err := hb.UnmarshalFlag("10MB"); err != nil {
t.Fatalf("UnmarshalFlag error: %v", err)
}
if hb != 10*1000*1000 {
t.Errorf("Bytes = %d; want 10000000", hb)
}
}

func TestHumanBytesUnmarshalFlagInvalid(t *testing.T) {
var hb Bytes
if err := hb.UnmarshalFlag("invalid"); err == nil {
t.Error("UnmarshalFlag should return error for invalid input")
}
}
35 changes: 35 additions & 0 deletions flagregexp.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package flagrun

import "regexp"

type Re struct {
value string
regexp *regexp.Regexp
}

func (fr *Re) UnmarshalFlag(value string) error {
if value == "" {
fr.value = ""
fr.regexp = nil
return nil
}
re, err := regexp.Compile(value)
if err != nil {
return err
}
fr.value = value
fr.regexp = re
return nil
}

func (fr *Re) String() string {
return fr.value
}

func (fr *Re) Regexp() *regexp.Regexp {
return fr.regexp
}

func (fr *Re) Present() bool {
return fr.regexp != nil
}
28 changes: 28 additions & 0 deletions flagregexp_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package flagrun

import "testing"

func TestFlagRegexp(t *testing.T) {
testCases := []struct {
input string
err bool
expected bool
}{
{"", false, false},
{"^example", false, true},
{"invalid[", true, false},
}
for _, tc := range testCases {
fr := &Re{}
err := fr.UnmarshalFlag(tc.input)
if !tc.err && err != nil {
t.Errorf("unexpected error for input %q: %v", tc.input, err)
}
if tc.err && err == nil {
t.Errorf("expected error for input %q, but got none", tc.input)
}
if fr.Present() != tc.expected {
t.Errorf("input: %q, expected Present: %v, got: %v", tc.input, tc.expected, fr.Present())
}
}
}
14 changes: 5 additions & 9 deletions flagrun.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,10 +159,6 @@ func buildFlagrun(options ...FlagrunOptions) *Flagrun {
return f
}

func nullint(i int) *int {
return &i
}

func (f *Flagrun) parseArgs(argv []string, stdout, stderr io.Writer, opt any) ([]string, *int) {
psr := flags.NewParser(opt, flags.HelpFlag|flags.PassDoubleDash)
if f.Usage != "" {
Expand All @@ -183,23 +179,23 @@ func (f *Flagrun) parseArgs(argv []string, stdout, stderr io.Writer, opt any) ([
runtime.GOARCH,
runtime.Version(),
f.Commit)
return nil, nullint(OK)
return nil, new(OK)
} else if flags.WroteHelp(err) {
fmt.Fprintf(stdout, "%v\n", err)
return nil, nullint(OK)
return nil, new(OK)
} else if err != nil {
fmt.Fprintf(stderr, "%v\n", err)
return nil, nullint(UNKNOWN)
return nil, new(UNKNOWN)
} else if f.ArgsRequired && len(args) == 0 {
fmt.Fprintf(stderr, "command is required\n")
psr.WriteHelp(stderr)
return nil, nullint(UNKNOWN)
return nil, new(UNKNOWN)
}

if f.Validator != nil {
if err := f.Validator(args); err != nil {
fmt.Fprintf(stderr, "%v\n", err)
return nil, nullint(UNKNOWN)
return nil, new(UNKNOWN)
}
}

Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ require (
)

require (
github.com/dustin/go-humanize v1.1.0
go.yaml.in/yaml/v3 v3.0.5 // indirect
golang.org/x/sys v0.49.0 // indirect
)
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
github.com/dustin/go-humanize v1.1.0 h1:dbKTrvD0klcbBV/h4AWJdMuZogJACoMlvWIWZ5b2xWg=
github.com/dustin/go-humanize v1.1.0/go.mod h1:hc1CvRkJMsgxqjmjMQF3QNRAZBwY8AXBAzKYoSX9sFI=
github.com/jessevdk/go-flags v1.6.1 h1:Cvu5U8UGrLay1rZfv/zP7iLpSHGUZ/Ou68T0iX1bBK4=
github.com/jessevdk/go-flags v1.6.1/go.mod h1:Mk8T1hIAWpOiJiHa9rJASDK2UGWji0EuPGBnNLMooyc=
github.com/mackerelio/checkers v0.2.1 h1:vRXzAT+CEyaLjSrHVxKUBjyWq1kfo8QcI8ZoSKZATQs=
Expand Down
Loading