$30 off During Our Annual Pro Sale. View Details »

Gunosy.go #4 ~ flag.go ~ #gunosygo

zoncoen
July 02, 2014
210

Gunosy.go #4 ~ flag.go ~ #gunosygo

Gunosy.go #4 の発表資料です。

zoncoen

July 02, 2014
Tweet

Transcript

  1. Gunosy.go #4 ~ flag.go ~ Kenta Mori (@zoncoen)

  2. Contents 1. flag package ͱ͸ʁ 2. flag ͷجຊతͳಈ࡞֬ೝ 3. flag

    ͷ࣮૷ 4. ·ͱΊ
  3. ࣗݾ঺հ • ৿݈ଠ (@zoncoen) - ໋ཱؗ (ੜ໋Պֶ) → ಸྑઌ୺ (৘ใ)

    - ৽ଔݚमத@DeNA - Baby Gopher
  4. What is the flag pkg? • ίϚϯυϥΠϯͷϑϥάղੳΛఏڙ • String(), Bool(),

    Int() ͳͲͰϑϥάΛఆٛ • Parse() ͰϑϥάΛύʔε͢Δ ?
  5. جຊతͳ࢖͍ํ

  6. ҎԼͷίʔυΛ demo.go ͱͯ͠อଘ package main ! import ( "flag" "fmt"

    "os" ) ! func main() { help := flag.Bool("help", false, "print help message and exit") flag.Parse() ! if *help { fmt.Println("demo.go - This is a demo of flag pkg.") os.Exit(0) } ! fmt.Println("Hello, Gopher!") }
  7. ΦϓγϣϯΛ༩͑Δͱڍಈ͕มΘΔ $ go run demo.go Hello, Gopher! ! $ go

    run demo.go -help demo.go - This is a demo of flag pkg. ! $ go run --help // ϋΠϑϯ͸1ͭͰ΋2ͭͰ΋OK demo.go - This is a demo of flag pkg.
  8. ஋͸ = Ͱͭͳ͙͔࣍ͷҾ਺ͰΘͨ͢ ... snip ... ! name := flag.String("name",

    "Gopher", "set your name") flag.Parse() ! ...snip... ! fmt.Printf("Hello, %v!\n", *name) } $ go run demo.go Hello, Gopher! ! $ go run demo.go --name zoncoen Hello, zoncoen! ! $ go run demo.go --name=zoncoen Hello, zoncoen!
  9. ผশ͸ StringVar()ɼ BoolVar()ɼIntVar() Λ࢖͏ ... snip ... ! help :=

    flag.Bool("help", false, "print help message and exit") flag.BoolVar(help, "h", false, "print help message and exit") flag.Parse() ! ...snip... $ go run demo.go --help demo.go - This is a demo of flag pkg. ! $ go run demo.go -h demo.go - This is a demo of flag pkg.
  10. Usage() Ͱඪ४Τϥʔʹ usage Λग़ྗ σϑΥϧτͷঢ়ଶͰh/helpΦϓγϣϯΛ͚ͭͯ΋ ͜Ε͕ग़ྗ͞ΕΔ ... snip ... !

    if *help { fmt.Println("demo.go - This is a demo of flag pkg.") flag.Usage() os.Exit(0) } ! ...snip... $ go run demo.go -h demo.go - This is a demo of flag pkg. Usage of /var/folders/c3/vwntnjg517v2pxzd6072hrnjhggkq_/T/go- build178147611/command-line-arguments/_obj/exe/demo: -h=false: print help message and exit -help=false: print help message and exit -name="Gopher": set your name
  11. flag pkg ͷ࣮૷

  12. e.g.: flag.Bool() ͰͷΦϓγϣϯऔಘ 1. Bool() Ͱ৽͍͠ϑϥάΛొ࿥ 2. Parse()ͰϑϥάΛղੳ

  13. e.g.: flag.Bool() ͰͷΦϓγϣϯऔಘ 1. Bool() Ͱ৽͍͠ϑϥάΛొ࿥ 2. Parse()ͰϑϥάΛղੳ

  14. • Bool() ͸ BoolVar() Ͱొ࿥ͨ͠ม਺Λฦ͢ • BoolVar() ͸ Var() Ͱม਺

    p Λొ࿥ // flag.go L461-465 func (f *FlagSet) Bool(name string, value bool, usage string) *bool { p := new(bool) f.BoolVar(p, name, value, usage) return p } ! // flag.go L461-465 func (f *FlagSet) BoolVar(p *bool, name string, value bool, usage string) { f.Var(newBoolValue(value, p), name, usage) }
  15. • Var() ͸ formal ʹϑϥάΛొ࿥ • ॏෳొ࿥͕͋Ε͹Panic() // flag.go L461-465

    func (f *FlagSet) Var(value Value, name string, usage string) { flag := &Flag{name, usage, value, value.String()} _, alreadythere := f.formal[name] if alreadythere { var msg string if f.name == "" { msg = fmt.Sprintf("flag redefined: %s", name) } else { msg = fmt.Sprintf("%s flag redefined: %s", f.name, name) } fmt.Fprintln(f.out(), msg) panic(msg) } if f.formal == nil { f.formal = make(map[string]*Flag) } f.formal[name] = flag }
  16. // flag.go L262-275 type FlagSet struct { Usage func() !

    name string parsed bool actual map[string]*Flag formal map[string]*Flag args []string errorHandling ErrorHandling output io.Writer } // flag.go L278-283 type Flag struct { Name string Usage string Value Value DefValue string } • formal ͸ొ࿥͞Εͨϑϥά໊΍σϑΥϧτ஋Λ อ࣋
  17. e.g.: flag.Bool() ͰͷΦϓγϣϯऔಘ 1. Bool() Ͱ৽͍͠ϑϥάΛొ࿥ 2. Parse()ͰϑϥάΛղੳ

  18. • Parse()͸ϑϥάΛ1ͭͣͭparseOne()Ͱparse͢Δ // flag.go L792-813 func (f *FlagSet) Parse(arguments []string)

    error { f.parsed = true f.args = arguments // arguments = os.Args[1:] for { seen, err := f.parseOne() if seen { continue } if err == nil { break } switch f.errorHandling { case ContinueOnError: return err case ExitOnError: os.Exit(2) case PanicOnError: panic(err) } } return nil }
  19. • parseOne()ͰҾ਺͔ΒϑϥάΛऔಘ func (f *FlagSet) parseOne() (bool, error) { if

    len(f.args) == 0 { // args ͕ۭʹͳͬͨΒऴྃ return false, nil } s := f.args[0] if len(s) == 0 || s[0] != '-' || len(s) == 1 { return false, nil } num_minuses := 1 if s[1] == '-' { num_minuses++ if len(s) == 2 { // "--" Ͱϑϥάղੳऴྃ f.args = f.args[1:] return false, nil } } name := s[num_minuses:] // = ͕͋Ε͹nameͱvalueΛ෼͚Δ if len(name) == 0 || name[0] == '-' || name[0] == '=' { return false, f.failf("bad flag syntax: %s", s) } ! ... cont ...
  20. ... cont ... ! f.args = f.args[1:] has_value := false

    value := "" for i := 1; i < len(name); i++ { // 1จࣈ໨͸ = Ͱ͸ͳΒͳ͍ if name[i] == '=' { value = name[i+1:] has_value = true name = name[0:i] break ɹ } } m := f.formal flag, alreadythere := m[name] // BUG if !alreadythere { if name == "help" || name == "h" { // usageͷදࣔ f.usage() return false, ErrHelp } return false, f.failf("flag provided but not defined: -%s", name) } ! ... cont ...
  21. ... cont ... ! if fv, ok := flag.Value.(boolFlag); ok

    && fv.IsBoolFlag() { // bool ͸ value͸ඞཁͳ͍ if has_value { if err := fv.Set(value); err != nil { return false, f.failf("invalid boolean value %q for - %s: %v", value, name, err) } } else { fv.Set("true") } } else { // = ͕ͳ͚Ε͹࣍ͷҾ਺Λ value ͱͯ͠ॲཧ if !has_value && len(f.args) > 0 { // value is the next arg has_value = true value, f.args = f.args[0], f.args[1:] } if !has_value { return false, f.failf("flag needs an argument: -%s", name) } if err := flag.Value.Set(value); err != nil { return false, f.failf("invalid value %q for flag -%s: %v", value, name, err) } } if f.actual == nil { f.actual = make(map[string]*Flag) } f.actual[name] = flag // औಘͨ͠ϑϥάΛ actual ʹ௥Ճ return true, nil }
  22. ·ͱΊ • Go ͷΦϓγϣϯղੳ͸ flag pkg ͰͰ͖Δ • ͱ͸͍͑͋·Γ࢖͍উख͕Α͘ͳ͍ •

    ུশఆٛͱ͔ϔϧϓͷࣗಈੜ੒ͱ͔ • go-flags ΍ docopt.go, docker ͷ mflag ͳͲ 3rd Party ͷ pkg Λ࢖ͬͯ΋͍͍ͱࢥ͍·͢