├── .gitignore ├── Makefile ├── chromium └── mtime.sh ├── getopt ├── string.go ├── var.go ├── duration.go ├── int.go ├── uint.go ├── int16.go ├── int32.go ├── int64.go ├── uint16.go ├── uint32.go ├── uint64.go ├── bool.go ├── list.go ├── counter.go ├── enum.go ├── error.go ├── signed.go ├── unsigned.go ├── option.go ├── set.go └── getopt.go ├── README.md ├── main.go └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | /mtool1\.txt 2 | /testcase1\.txt 3 | /bin/ 4 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: bin/mtool test 2 | 3 | build: bin/mtool 4 | 5 | bin/mtool: *.go 6 | mkdir -p bin/ 7 | GOBIN=$(CURDIR)/bin go install . 8 | 9 | test: bin/mtool 10 | git ls-files --stage > testcase1.txt 11 | $(CURDIR)/bin/mtool < testcase1.txt > $(CURDIR)/mtool1.txt 12 | $(CURDIR)/bin/mtool --verify --verbose --snapshot=$(CURDIR)/mtool1.txt < testcase1.txt 13 | 14 | clean: 15 | rm -f bin/mtool 16 | 17 | .PHONY: all test build clean 18 | -------------------------------------------------------------------------------- /chromium/mtime.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ## mtime.sh 3 | ## @author csagan5 4 | ## @url https://github.com/bromite/mtool 5 | ## 6 | ## Script to backup/verify/restore mtime of files across Chromium source checkouts. 7 | ## Run it from the root git repository. 8 | ## 9 | # 10 | 11 | set -e 12 | 13 | function usage() { 14 | echo "Usage: mtime.sh (--backup | --verify | --restore)" 1>&2 15 | } 16 | 17 | if [ ! $# -eq 1 ]; then 18 | usage 19 | exit 1 20 | fi 21 | 22 | case "$1" in 23 | --backup) 24 | MTOOL="mtool --snapshot=.mtool --create" 25 | ;; 26 | --verify) 27 | MTOOL="mtool --snapshot=.mtool --verify" 28 | ;; 29 | --restore) 30 | MTOOL="mtool --snapshot=.mtool --restore" 31 | ;; 32 | *) 33 | usage 34 | exit 1 35 | esac 36 | 37 | # temporary file for all git repositories 38 | GITTMP="$(mktemp)" 39 | # commands to run to take a snapshot of mtimes 40 | CMDTMP="$(mktemp)" 41 | trap "rm '$GITTMP' '$CMDTMP'" EXIT 42 | 43 | # find all git directories 44 | find -type d -name .git | awk '{ print substr($0, 3, length($0)-7) }' | grep -v ^$ > "$GITTMP" 45 | 46 | # first the root directory 47 | echo "git ls-files --exclude-standard --stage | grep -vF third_party/WebKit/LayoutTests/ | %MTOOL%" > "$CMDTMP" 48 | 49 | # contains some common exclusion patterns for Chromium e.g. broken links and similar 50 | awk '{ printf "cd %s && git ls-files --exclude-standard --stage | grep -vF /test/ | grep -vF test/data | grep -vF tools/gyp | grep -vF ui/src/gen | grep -vF example/payload | grep -vF static_test_env/ | %%MTOOL%% || echo \"%s: FAILED\"\n", $0, $0 }' "$GITTMP" >> "$CMDTMP" 51 | 52 | sed -i "s/%MTOOL%/${MTOOL}/g" "$CMDTMP" 53 | 54 | # run all commands in parallel 55 | # add --will-cite after making a donation of at least 10k EUR to the author of parallel (see man parallel) 56 | parallel < "$CMDTMP" 57 | -------------------------------------------------------------------------------- /getopt/string.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package getopt 6 | 7 | type stringValue string 8 | 9 | func (s *stringValue) Set(value string, opt Option) error { 10 | *s = stringValue(value) 11 | return nil 12 | } 13 | 14 | func (s *stringValue) String() string { 15 | return string(*s) 16 | } 17 | 18 | // String returns a value option that stores is value as a string. The 19 | // initial value of the string is passed in value. 20 | func String(name rune, value string, helpvalue ...string) *string { 21 | return CommandLine.String(name, value, helpvalue...) 22 | } 23 | 24 | func (s *Set) String(name rune, value string, helpvalue ...string) *string { 25 | p := value 26 | s.StringVarLong(&p, "", name, helpvalue...) 27 | return &p 28 | } 29 | 30 | func StringLong(name string, short rune, value string, helpvalue ...string) *string { 31 | return CommandLine.StringLong(name, short, value, helpvalue...) 32 | } 33 | 34 | func (s *Set) StringLong(name string, short rune, value string, helpvalue ...string) *string { 35 | s.StringVarLong(&value, name, short, helpvalue...) 36 | return &value 37 | } 38 | 39 | func StringVar(p *string, name rune, helpvalue ...string) Option { 40 | return CommandLine.StringVar(p, name, helpvalue...) 41 | } 42 | 43 | func (s *Set) StringVar(p *string, name rune, helpvalue ...string) Option { 44 | return s.VarLong((*stringValue)(p), "", name, helpvalue...) 45 | } 46 | 47 | func StringVarLong(p *string, name string, short rune, helpvalue ...string) Option { 48 | return CommandLine.StringVarLong(p, name, short, helpvalue...) 49 | } 50 | 51 | func (s *Set) StringVarLong(p *string, name string, short rune, helpvalue ...string) Option { 52 | return s.VarLong((*stringValue)(p), name, short, helpvalue...) 53 | } 54 | -------------------------------------------------------------------------------- /getopt/var.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package getopt 6 | 7 | import ( 8 | "fmt" 9 | "runtime" 10 | ) 11 | 12 | // Value is the interface to the dynamic value stored in a flag. (The default 13 | // value is represented as a string.) Set is passed the string to set the 14 | // value to as well as the Option that is being processed. 15 | type Value interface { 16 | Set(string, Option) error 17 | String() string 18 | } 19 | 20 | // Var creates an option of the specified name. The type and value of the option 21 | // are represented by the first argument, of type Value, which typically holds a 22 | // user-defined implementation of Value. All options are ultimately created 23 | // as a Var. 24 | func Var(p Value, name rune, helpvalue ...string) Option { 25 | return CommandLine.VarLong(p, "", name, helpvalue...) 26 | } 27 | 28 | func VarLong(p Value, name string, short rune, helpvalue ...string) Option { 29 | return CommandLine.VarLong(p, name, short, helpvalue...) 30 | } 31 | 32 | func (s *Set) Var(p Value, name rune, helpvalue ...string) Option { 33 | return s.VarLong(p, "", name, helpvalue...) 34 | } 35 | 36 | func (s *Set) VarLong(p Value, name string, short rune, helpvalue ...string) Option { 37 | opt := &option{ 38 | short: short, 39 | long: name, 40 | value: p, 41 | defval: p.String(), 42 | } 43 | 44 | switch len(helpvalue) { 45 | case 2: 46 | opt.name = helpvalue[1] 47 | fallthrough 48 | case 1: 49 | opt.help = helpvalue[0] 50 | case 0: 51 | default: 52 | panic("Too many strings for String helpvalue") 53 | } 54 | if _, file, line, ok := runtime.Caller(1); ok { 55 | opt.where = fmt.Sprintf("%s:%d", file, line) 56 | } 57 | if opt.short == 0 && opt.long == "" { 58 | fmt.Fprintf(stderr, opt.where+": no short or long option given") 59 | exit(1) 60 | } 61 | s.AddOption(opt) 62 | return opt 63 | } 64 | -------------------------------------------------------------------------------- /getopt/duration.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package getopt 6 | 7 | import "time" 8 | 9 | type durationValue time.Duration 10 | 11 | func (d *durationValue) Set(value string, opt Option) error { 12 | v, err := time.ParseDuration(value) 13 | if err != nil { 14 | return err 15 | } 16 | *d = durationValue(v) 17 | return nil 18 | } 19 | 20 | func (d *durationValue) String() string { 21 | return time.Duration(*d).String() 22 | } 23 | 24 | // Duration creates an option that parses its value as a time.Duration. 25 | func Duration(name rune, value time.Duration, helpvalue ...string) *time.Duration { 26 | return CommandLine.Duration(name, value, helpvalue...) 27 | } 28 | 29 | func (s *Set) Duration(name rune, value time.Duration, helpvalue ...string) *time.Duration { 30 | return s.DurationLong("", name, value, helpvalue...) 31 | } 32 | 33 | func DurationLong(name string, short rune, value time.Duration, helpvalue ...string) *time.Duration { 34 | return CommandLine.DurationLong(name, short, value, helpvalue...) 35 | } 36 | 37 | func (s *Set) DurationLong(name string, short rune, value time.Duration, helpvalue ...string) *time.Duration { 38 | s.DurationVarLong(&value, name, short, helpvalue...) 39 | return &value 40 | } 41 | 42 | func DurationVar(p *time.Duration, name rune, helpvalue ...string) Option { 43 | return CommandLine.DurationVar(p, name, helpvalue...) 44 | } 45 | 46 | func (s *Set) DurationVar(p *time.Duration, name rune, helpvalue ...string) Option { 47 | return s.DurationVarLong(p, "", name, helpvalue...) 48 | } 49 | 50 | func DurationVarLong(p *time.Duration, name string, short rune, helpvalue ...string) Option { 51 | return CommandLine.DurationVarLong(p, name, short, helpvalue...) 52 | } 53 | 54 | func (s *Set) DurationVarLong(p *time.Duration, name string, short rune, helpvalue ...string) Option { 55 | return s.VarLong((*durationValue)(p), name, short, helpvalue...) 56 | } 57 | -------------------------------------------------------------------------------- /getopt/int.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package getopt 6 | 7 | import ( 8 | "fmt" 9 | "strconv" 10 | ) 11 | 12 | type intValue int 13 | 14 | func (i *intValue) Set(value string, opt Option) error { 15 | v, err := strconv.ParseInt(value, 0, strconv.IntSize) 16 | if err != nil { 17 | if e, ok := err.(*strconv.NumError); ok { 18 | switch e.Err { 19 | case strconv.ErrRange: 20 | err = fmt.Errorf("value out of range: %s", value) 21 | case strconv.ErrSyntax: 22 | err = fmt.Errorf("not a valid number: %s", value) 23 | } 24 | } 25 | return err 26 | } 27 | *i = intValue(v) 28 | return nil 29 | } 30 | 31 | func (i *intValue) String() string { 32 | return strconv.FormatInt(int64(*i), 10) 33 | } 34 | 35 | // Int creates an option that parses its value as an integer. 36 | func Int(name rune, value int, helpvalue ...string) *int { 37 | return CommandLine.Int(name, value, helpvalue...) 38 | } 39 | 40 | func (s *Set) Int(name rune, value int, helpvalue ...string) *int { 41 | return s.IntLong("", name, value, helpvalue...) 42 | } 43 | 44 | func IntLong(name string, short rune, value int, helpvalue ...string) *int { 45 | return CommandLine.IntLong(name, short, value, helpvalue...) 46 | } 47 | 48 | func (s *Set) IntLong(name string, short rune, value int, helpvalue ...string) *int { 49 | s.IntVarLong(&value, name, short, helpvalue...) 50 | return &value 51 | } 52 | 53 | func IntVar(p *int, name rune, helpvalue ...string) Option { 54 | return CommandLine.IntVar(p, name, helpvalue...) 55 | } 56 | 57 | func (s *Set) IntVar(p *int, name rune, helpvalue ...string) Option { 58 | return s.IntVarLong(p, "", name, helpvalue...) 59 | } 60 | 61 | func IntVarLong(p *int, name string, short rune, helpvalue ...string) Option { 62 | return CommandLine.IntVarLong(p, name, short, helpvalue...) 63 | } 64 | 65 | func (s *Set) IntVarLong(p *int, name string, short rune, helpvalue ...string) Option { 66 | return s.VarLong((*intValue)(p), name, short, helpvalue...) 67 | } 68 | -------------------------------------------------------------------------------- /getopt/uint.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package getopt 6 | 7 | import ( 8 | "fmt" 9 | "strconv" 10 | ) 11 | 12 | type uintValue uint 13 | 14 | func (i *uintValue) Set(value string, opt Option) error { 15 | v, err := strconv.ParseUint(value, 0, strconv.IntSize) 16 | if err != nil { 17 | if e, ok := err.(*strconv.NumError); ok { 18 | switch e.Err { 19 | case strconv.ErrRange: 20 | err = fmt.Errorf("value out of range: %s", value) 21 | case strconv.ErrSyntax: 22 | err = fmt.Errorf("not a valid number: %s", value) 23 | } 24 | } 25 | return err 26 | } 27 | *i = uintValue(v) 28 | return nil 29 | } 30 | 31 | func (i *uintValue) String() string { 32 | return strconv.FormatUint(uint64(*i), 10) 33 | } 34 | 35 | // Uint creates an option that parses its value as an unsigned integer. 36 | func Uint(name rune, value uint, helpvalue ...string) *uint { 37 | return CommandLine.Uint(name, value, helpvalue...) 38 | } 39 | 40 | func (s *Set) Uint(name rune, value uint, helpvalue ...string) *uint { 41 | return s.UintLong("", name, value, helpvalue...) 42 | } 43 | 44 | func UintLong(name string, short rune, value uint, helpvalue ...string) *uint { 45 | return CommandLine.UintLong(name, short, value, helpvalue...) 46 | } 47 | 48 | func (s *Set) UintLong(name string, short rune, value uint, helpvalue ...string) *uint { 49 | s.UintVarLong(&value, name, short, helpvalue...) 50 | return &value 51 | } 52 | 53 | func UintVar(p *uint, name rune, helpvalue ...string) Option { 54 | return CommandLine.UintVar(p, name, helpvalue...) 55 | } 56 | 57 | func (s *Set) UintVar(p *uint, name rune, helpvalue ...string) Option { 58 | return s.UintVarLong(p, "", name, helpvalue...) 59 | } 60 | 61 | func UintVarLong(p *uint, name string, short rune, helpvalue ...string) Option { 62 | return CommandLine.UintVarLong(p, name, short, helpvalue...) 63 | } 64 | 65 | func (s *Set) UintVarLong(p *uint, name string, short rune, helpvalue ...string) Option { 66 | return s.VarLong((*uintValue)(p), name, short, helpvalue...) 67 | } 68 | -------------------------------------------------------------------------------- /getopt/int16.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package getopt 6 | 7 | import ( 8 | "fmt" 9 | "strconv" 10 | ) 11 | 12 | type int16Value int16 13 | 14 | func (i *int16Value) Set(value string, opt Option) error { 15 | v, err := strconv.ParseInt(value, 0, 16) 16 | if err != nil { 17 | if e, ok := err.(*strconv.NumError); ok { 18 | switch e.Err { 19 | case strconv.ErrRange: 20 | err = fmt.Errorf("value out of range: %s", value) 21 | case strconv.ErrSyntax: 22 | err = fmt.Errorf("not a valid number: %s", value) 23 | } 24 | } 25 | return err 26 | } 27 | *i = int16Value(v) 28 | return nil 29 | } 30 | 31 | func (i *int16Value) String() string { 32 | return strconv.FormatInt(int64(*i), 10) 33 | } 34 | 35 | // Int16 creates an option that parses its value as an int16. 36 | func Int16(name rune, value int16, helpvalue ...string) *int16 { 37 | return CommandLine.Int16(name, value, helpvalue...) 38 | } 39 | 40 | func (s *Set) Int16(name rune, value int16, helpvalue ...string) *int16 { 41 | return s.Int16Long("", name, value, helpvalue...) 42 | } 43 | 44 | func Int16Long(name string, short rune, value int16, helpvalue ...string) *int16 { 45 | return CommandLine.Int16Long(name, short, value, helpvalue...) 46 | } 47 | 48 | func (s *Set) Int16Long(name string, short rune, value int16, helpvalue ...string) *int16 { 49 | s.Int16VarLong(&value, name, short, helpvalue...) 50 | return &value 51 | } 52 | 53 | func Int16Var(p *int16, name rune, helpvalue ...string) Option { 54 | return CommandLine.Int16Var(p, name, helpvalue...) 55 | } 56 | 57 | func (s *Set) Int16Var(p *int16, name rune, helpvalue ...string) Option { 58 | return s.Int16VarLong(p, "", name, helpvalue...) 59 | } 60 | 61 | func Int16VarLong(p *int16, name string, short rune, helpvalue ...string) Option { 62 | return CommandLine.Int16VarLong(p, name, short, helpvalue...) 63 | } 64 | 65 | func (s *Set) Int16VarLong(p *int16, name string, short rune, helpvalue ...string) Option { 66 | return s.VarLong((*int16Value)(p), name, short, helpvalue...) 67 | } 68 | -------------------------------------------------------------------------------- /getopt/int32.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package getopt 6 | 7 | import ( 8 | "fmt" 9 | "strconv" 10 | ) 11 | 12 | type int32Value int32 13 | 14 | func (i *int32Value) Set(value string, opt Option) error { 15 | v, err := strconv.ParseInt(value, 0, 32) 16 | if err != nil { 17 | if e, ok := err.(*strconv.NumError); ok { 18 | switch e.Err { 19 | case strconv.ErrRange: 20 | err = fmt.Errorf("value out of range: %s", value) 21 | case strconv.ErrSyntax: 22 | err = fmt.Errorf("not a valid number: %s", value) 23 | } 24 | } 25 | return err 26 | } 27 | *i = int32Value(v) 28 | return nil 29 | } 30 | 31 | func (i *int32Value) String() string { 32 | return strconv.FormatInt(int64(*i), 10) 33 | } 34 | 35 | // Int32 creates an option that parses its value as an int32. 36 | func Int32(name rune, value int32, helpvalue ...string) *int32 { 37 | return CommandLine.Int32(name, value, helpvalue...) 38 | } 39 | 40 | func (s *Set) Int32(name rune, value int32, helpvalue ...string) *int32 { 41 | return s.Int32Long("", name, value, helpvalue...) 42 | } 43 | 44 | func Int32Long(name string, short rune, value int32, helpvalue ...string) *int32 { 45 | return CommandLine.Int32Long(name, short, value, helpvalue...) 46 | } 47 | 48 | func (s *Set) Int32Long(name string, short rune, value int32, helpvalue ...string) *int32 { 49 | s.Int32VarLong(&value, name, short, helpvalue...) 50 | return &value 51 | } 52 | 53 | func Int32Var(p *int32, name rune, helpvalue ...string) Option { 54 | return CommandLine.Int32Var(p, name, helpvalue...) 55 | } 56 | 57 | func (s *Set) Int32Var(p *int32, name rune, helpvalue ...string) Option { 58 | return s.Int32VarLong(p, "", name, helpvalue...) 59 | } 60 | 61 | func Int32VarLong(p *int32, name string, short rune, helpvalue ...string) Option { 62 | return CommandLine.Int32VarLong(p, name, short, helpvalue...) 63 | } 64 | 65 | func (s *Set) Int32VarLong(p *int32, name string, short rune, helpvalue ...string) Option { 66 | return s.VarLong((*int32Value)(p), name, short, helpvalue...) 67 | } 68 | -------------------------------------------------------------------------------- /getopt/int64.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package getopt 6 | 7 | import ( 8 | "fmt" 9 | "strconv" 10 | ) 11 | 12 | type int64Value int64 13 | 14 | func (i *int64Value) Set(value string, opt Option) error { 15 | v, err := strconv.ParseInt(value, 0, 64) 16 | if err != nil { 17 | if e, ok := err.(*strconv.NumError); ok { 18 | switch e.Err { 19 | case strconv.ErrRange: 20 | err = fmt.Errorf("value out of range: %s", value) 21 | case strconv.ErrSyntax: 22 | err = fmt.Errorf("not a valid number: %s", value) 23 | } 24 | } 25 | return err 26 | } 27 | *i = int64Value(v) 28 | return nil 29 | } 30 | 31 | func (i *int64Value) String() string { 32 | return strconv.FormatInt(int64(*i), 10) 33 | } 34 | 35 | // Int64 creates an option that parses its value as an int64. 36 | func Int64(name rune, value int64, helpvalue ...string) *int64 { 37 | return CommandLine.Int64(name, value, helpvalue...) 38 | } 39 | 40 | func (s *Set) Int64(name rune, value int64, helpvalue ...string) *int64 { 41 | return s.Int64Long("", name, value, helpvalue...) 42 | } 43 | 44 | func Int64Long(name string, short rune, value int64, helpvalue ...string) *int64 { 45 | return CommandLine.Int64Long(name, short, value, helpvalue...) 46 | } 47 | 48 | func (s *Set) Int64Long(name string, short rune, value int64, helpvalue ...string) *int64 { 49 | s.Int64VarLong(&value, name, short, helpvalue...) 50 | return &value 51 | } 52 | 53 | func Int64Var(p *int64, name rune, helpvalue ...string) Option { 54 | return CommandLine.Int64Var(p, name, helpvalue...) 55 | } 56 | 57 | func (s *Set) Int64Var(p *int64, name rune, helpvalue ...string) Option { 58 | return s.Int64VarLong(p, "", name, helpvalue...) 59 | } 60 | 61 | func Int64VarLong(p *int64, name string, short rune, helpvalue ...string) Option { 62 | return CommandLine.Int64VarLong(p, name, short, helpvalue...) 63 | } 64 | 65 | func (s *Set) Int64VarLong(p *int64, name string, short rune, helpvalue ...string) Option { 66 | return s.VarLong((*int64Value)(p), name, short, helpvalue...) 67 | } 68 | -------------------------------------------------------------------------------- /getopt/uint16.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package getopt 6 | 7 | import ( 8 | "fmt" 9 | "strconv" 10 | ) 11 | 12 | type uint16Value uint16 13 | 14 | func (i *uint16Value) Set(value string, opt Option) error { 15 | v, err := strconv.ParseUint(value, 0, 16) 16 | if err != nil { 17 | if e, ok := err.(*strconv.NumError); ok { 18 | switch e.Err { 19 | case strconv.ErrRange: 20 | err = fmt.Errorf("value out of range: %s", value) 21 | case strconv.ErrSyntax: 22 | err = fmt.Errorf("not a valid number: %s", value) 23 | } 24 | } 25 | return err 26 | } 27 | *i = uint16Value(v) 28 | return nil 29 | } 30 | 31 | func (i *uint16Value) String() string { 32 | return strconv.FormatUint(uint64(*i), 10) 33 | } 34 | 35 | // Uint16 creates an option that parses its value as an uint16. 36 | func Uint16(name rune, value uint16, helpvalue ...string) *uint16 { 37 | return CommandLine.Uint16(name, value, helpvalue...) 38 | } 39 | 40 | func (s *Set) Uint16(name rune, value uint16, helpvalue ...string) *uint16 { 41 | return s.Uint16Long("", name, value, helpvalue...) 42 | } 43 | 44 | func Uint16Long(name string, short rune, value uint16, helpvalue ...string) *uint16 { 45 | return CommandLine.Uint16Long(name, short, value, helpvalue...) 46 | } 47 | 48 | func (s *Set) Uint16Long(name string, short rune, value uint16, helpvalue ...string) *uint16 { 49 | s.Uint16VarLong(&value, name, short, helpvalue...) 50 | return &value 51 | } 52 | 53 | func Uint16Var(p *uint16, name rune, helpvalue ...string) Option { 54 | return CommandLine.Uint16Var(p, name, helpvalue...) 55 | } 56 | 57 | func (s *Set) Uint16Var(p *uint16, name rune, helpvalue ...string) Option { 58 | return s.Uint16VarLong(p, "", name, helpvalue...) 59 | } 60 | 61 | func Uint16VarLong(p *uint16, name string, short rune, helpvalue ...string) Option { 62 | return CommandLine.Uint16VarLong(p, name, short, helpvalue...) 63 | } 64 | 65 | func (s *Set) Uint16VarLong(p *uint16, name string, short rune, helpvalue ...string) Option { 66 | return s.VarLong((*uint16Value)(p), name, short, helpvalue...) 67 | } 68 | -------------------------------------------------------------------------------- /getopt/uint32.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package getopt 6 | 7 | import ( 8 | "fmt" 9 | "strconv" 10 | ) 11 | 12 | type uint32Value uint32 13 | 14 | func (i *uint32Value) Set(value string, opt Option) error { 15 | v, err := strconv.ParseUint(value, 0, 32) 16 | if err != nil { 17 | if e, ok := err.(*strconv.NumError); ok { 18 | switch e.Err { 19 | case strconv.ErrRange: 20 | err = fmt.Errorf("value out of range: %s", value) 21 | case strconv.ErrSyntax: 22 | err = fmt.Errorf("not a valid number: %s", value) 23 | } 24 | } 25 | return err 26 | } 27 | *i = uint32Value(v) 28 | return nil 29 | } 30 | 31 | func (i *uint32Value) String() string { 32 | return strconv.FormatUint(uint64(*i), 10) 33 | } 34 | 35 | // Uint32 creates an option that parses its value as an uint32. 36 | func Uint32(name rune, value uint32, helpvalue ...string) *uint32 { 37 | return CommandLine.Uint32(name, value, helpvalue...) 38 | } 39 | 40 | func (s *Set) Uint32(name rune, value uint32, helpvalue ...string) *uint32 { 41 | return s.Uint32Long("", name, value, helpvalue...) 42 | } 43 | 44 | func Uint32Long(name string, short rune, value uint32, helpvalue ...string) *uint32 { 45 | return CommandLine.Uint32Long(name, short, value, helpvalue...) 46 | } 47 | 48 | func (s *Set) Uint32Long(name string, short rune, value uint32, helpvalue ...string) *uint32 { 49 | s.Uint32VarLong(&value, name, short, helpvalue...) 50 | return &value 51 | } 52 | 53 | func Uint32Var(p *uint32, name rune, helpvalue ...string) Option { 54 | return CommandLine.Uint32Var(p, name, helpvalue...) 55 | } 56 | 57 | func (s *Set) Uint32Var(p *uint32, name rune, helpvalue ...string) Option { 58 | return s.Uint32VarLong(p, "", name, helpvalue...) 59 | } 60 | 61 | func Uint32VarLong(p *uint32, name string, short rune, helpvalue ...string) Option { 62 | return CommandLine.Uint32VarLong(p, name, short, helpvalue...) 63 | } 64 | 65 | func (s *Set) Uint32VarLong(p *uint32, name string, short rune, helpvalue ...string) Option { 66 | return s.VarLong((*uint32Value)(p), name, short, helpvalue...) 67 | } 68 | -------------------------------------------------------------------------------- /getopt/uint64.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package getopt 6 | 7 | import ( 8 | "fmt" 9 | "strconv" 10 | ) 11 | 12 | type uint64Value uint64 13 | 14 | func (i *uint64Value) Set(value string, opt Option) error { 15 | v, err := strconv.ParseUint(value, 0, 64) 16 | if err != nil { 17 | if e, ok := err.(*strconv.NumError); ok { 18 | switch e.Err { 19 | case strconv.ErrRange: 20 | err = fmt.Errorf("value out of range: %s", value) 21 | case strconv.ErrSyntax: 22 | err = fmt.Errorf("not a valid number: %s", value) 23 | } 24 | } 25 | return err 26 | } 27 | *i = uint64Value(v) 28 | return nil 29 | } 30 | 31 | func (i *uint64Value) String() string { 32 | return strconv.FormatUint(uint64(*i), 10) 33 | } 34 | 35 | // Uint64 creates an option that parses its value as a uint64. 36 | func Uint64(name rune, value uint64, helpvalue ...string) *uint64 { 37 | return CommandLine.Uint64(name, value, helpvalue...) 38 | } 39 | 40 | func (s *Set) Uint64(name rune, value uint64, helpvalue ...string) *uint64 { 41 | return s.Uint64Long("", name, value, helpvalue...) 42 | } 43 | 44 | func Uint64Long(name string, short rune, value uint64, helpvalue ...string) *uint64 { 45 | return CommandLine.Uint64Long(name, short, value, helpvalue...) 46 | } 47 | 48 | func (s *Set) Uint64Long(name string, short rune, value uint64, helpvalue ...string) *uint64 { 49 | s.Uint64VarLong(&value, name, short, helpvalue...) 50 | return &value 51 | } 52 | 53 | func Uint64Var(p *uint64, name rune, helpvalue ...string) Option { 54 | return CommandLine.Uint64Var(p, name, helpvalue...) 55 | } 56 | 57 | func (s *Set) Uint64Var(p *uint64, name rune, helpvalue ...string) Option { 58 | return s.Uint64VarLong(p, "", name, helpvalue...) 59 | } 60 | 61 | func Uint64VarLong(p *uint64, name string, short rune, helpvalue ...string) Option { 62 | return CommandLine.Uint64VarLong(p, name, short, helpvalue...) 63 | } 64 | 65 | func (s *Set) Uint64VarLong(p *uint64, name string, short rune, helpvalue ...string) Option { 66 | return s.VarLong((*uint64Value)(p), name, short, helpvalue...) 67 | } 68 | -------------------------------------------------------------------------------- /getopt/bool.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package getopt 6 | 7 | import ( 8 | "fmt" 9 | "strings" 10 | ) 11 | 12 | type boolValue bool 13 | 14 | func (b *boolValue) Set(value string, opt Option) error { 15 | switch strings.ToLower(value) { 16 | case "", "1", "true", "on", "t": 17 | *b = true 18 | case "0", "false", "off", "f": 19 | *b = false 20 | default: 21 | return fmt.Errorf("invalid value for bool %s: %q", opt.Name(), value) 22 | } 23 | return nil 24 | } 25 | 26 | func (b *boolValue) String() string { 27 | if *b { 28 | return "true" 29 | } 30 | return "false" 31 | } 32 | 33 | // Bool creates a flag option that is a bool. Bools normally do not take a 34 | // value however one can be assigned by using the long form of the option: 35 | // 36 | // --option=true 37 | // --o=false 38 | // 39 | // Its value is case insenstive and one of true, false, t, f, on, off, t and 0. 40 | func Bool(name rune, helpvalue ...string) *bool { 41 | return CommandLine.Bool(name, helpvalue...) 42 | } 43 | 44 | func (s *Set) Bool(name rune, helpvalue ...string) *bool { 45 | var p bool 46 | s.BoolVarLong(&p, "", name, helpvalue...) 47 | return &p 48 | } 49 | 50 | func BoolLong(name string, short rune, helpvalue ...string) *bool { 51 | return CommandLine.BoolLong(name, short, helpvalue...) 52 | } 53 | 54 | func (s *Set) BoolLong(name string, short rune, helpvalue ...string) *bool { 55 | var p bool 56 | s.BoolVarLong(&p, name, short, helpvalue...) 57 | return &p 58 | } 59 | 60 | func BoolVar(p *bool, name rune, helpvalue ...string) Option { 61 | return CommandLine.BoolVar(p, name, helpvalue...) 62 | } 63 | 64 | func (s *Set) BoolVar(p *bool, name rune, helpvalue ...string) Option { 65 | return s.BoolVarLong(p, "", name, helpvalue...) 66 | } 67 | 68 | func BoolVarLong(p *bool, name string, short rune, helpvalue ...string) Option { 69 | return CommandLine.BoolVarLong(p, name, short, helpvalue...) 70 | } 71 | 72 | func (s *Set) BoolVarLong(p *bool, name string, short rune, helpvalue ...string) Option { 73 | return s.VarLong((*boolValue)(p), name, short, helpvalue...).SetFlag() 74 | } 75 | -------------------------------------------------------------------------------- /getopt/list.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package getopt 6 | 7 | import "strings" 8 | 9 | type listValue []string 10 | 11 | func (s *listValue) Set(value string, opt Option) error { 12 | a := strings.Split(value, ",") 13 | // If this is the first time we are seen then nil out the 14 | // default value. 15 | if opt.Count() <= 1 { 16 | *s = nil 17 | } 18 | *s = append(*s, a...) 19 | return nil 20 | } 21 | 22 | func (s *listValue) String() string { 23 | return strings.Join([]string(*s), ",") 24 | } 25 | 26 | // List creates an option that returns a slice of strings. The parameters 27 | // passed are converted from a comma separated value list into a slice. 28 | // Subsequent occurrences append to the list. 29 | func List(name rune, helpvalue ...string) *[]string { 30 | return CommandLine.List(name, helpvalue...) 31 | } 32 | 33 | func (s *Set) List(name rune, helpvalue ...string) *[]string { 34 | p := []string{} 35 | s.ListVar(&p, name, helpvalue...) 36 | return &p 37 | } 38 | 39 | func ListLong(name string, short rune, helpvalue ...string) *[]string { 40 | return CommandLine.ListLong(name, short, helpvalue...) 41 | } 42 | 43 | func (s *Set) ListLong(name string, short rune, helpvalue ...string) *[]string { 44 | p := []string{} 45 | s.ListVarLong(&p, name, short, helpvalue...) 46 | return &p 47 | } 48 | 49 | // ListVar creats a list option and places the values in p. If p is pointing 50 | // to a list of values then those are considered the default values. The first 51 | // time name is seen in the options the list will be set to list specified by 52 | // the parameter to the option. Subsequent instances of the option will append 53 | // to the list. 54 | func ListVar(p *[]string, name rune, helpvalue ...string) Option { 55 | return CommandLine.ListVar(p, name, helpvalue...) 56 | } 57 | 58 | func (s *Set) ListVar(p *[]string, name rune, helpvalue ...string) Option { 59 | return s.ListVarLong(p, "", name, helpvalue...) 60 | } 61 | 62 | func ListVarLong(p *[]string, name string, short rune, helpvalue ...string) Option { 63 | return CommandLine.ListVarLong(p, name, short, helpvalue...) 64 | } 65 | 66 | func (s *Set) ListVarLong(p *[]string, name string, short rune, helpvalue ...string) Option { 67 | opt := s.VarLong((*listValue)(p), name, short, helpvalue...) 68 | return opt 69 | } 70 | -------------------------------------------------------------------------------- /getopt/counter.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package getopt 6 | 7 | import ( 8 | "fmt" 9 | "strconv" 10 | ) 11 | 12 | type counterValue int 13 | 14 | func (b *counterValue) Set(value string, opt Option) error { 15 | if value == "" { 16 | *b++ 17 | } else { 18 | v, err := strconv.ParseInt(value, 0, strconv.IntSize) 19 | if err != nil { 20 | if e, ok := err.(*strconv.NumError); ok { 21 | switch e.Err { 22 | case strconv.ErrRange: 23 | err = fmt.Errorf("value out of range: %s", value) 24 | case strconv.ErrSyntax: 25 | err = fmt.Errorf("not a valid number: %s", value) 26 | } 27 | } 28 | return err 29 | } 30 | *b = counterValue(v) 31 | } 32 | return nil 33 | } 34 | 35 | func (b *counterValue) String() string { 36 | return strconv.Itoa(int(*b)) 37 | } 38 | 39 | // Counter creates a counting flag stored as an int. Each time the option 40 | // is seen while parsing the value is incremented. The value of the counter 41 | // may be explicitly set by using the long form: 42 | // 43 | // --counter=5 44 | // --c=5 45 | // 46 | // Further instances of the option will increment from the set value. 47 | func Counter(name rune, helpvalue ...string) *int { 48 | return CommandLine.Counter(name, helpvalue...) 49 | } 50 | 51 | func (s *Set) Counter(name rune, helpvalue ...string) *int { 52 | var p int 53 | s.CounterVarLong(&p, "", name, helpvalue...) 54 | return &p 55 | } 56 | 57 | func CounterLong(name string, short rune, helpvalue ...string) *int { 58 | return CommandLine.CounterLong(name, short, helpvalue...) 59 | } 60 | 61 | func (s *Set) CounterLong(name string, short rune, helpvalue ...string) *int { 62 | var p int 63 | s.CounterVarLong(&p, name, short, helpvalue...) 64 | return &p 65 | } 66 | 67 | func CounterVar(p *int, name rune, helpvalue ...string) Option { 68 | return CommandLine.CounterVar(p, name, helpvalue...) 69 | } 70 | 71 | func (s *Set) CounterVar(p *int, name rune, helpvalue ...string) Option { 72 | return s.CounterVarLong(p, "", name, helpvalue...) 73 | } 74 | 75 | func CounterVarLong(p *int, name string, short rune, helpvalue ...string) Option { 76 | return CommandLine.CounterVarLong(p, name, short, helpvalue...) 77 | } 78 | 79 | func (s *Set) CounterVarLong(p *int, name string, short rune, helpvalue ...string) Option { 80 | return s.VarLong((*counterValue)(p), name, short, helpvalue...).SetFlag() 81 | } 82 | -------------------------------------------------------------------------------- /getopt/enum.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package getopt 6 | 7 | import "errors" 8 | 9 | type enumValue string 10 | 11 | var enumValues = make(map[*enumValue]map[string]struct{}) 12 | 13 | func (s *enumValue) Set(value string, opt Option) error { 14 | es, ok := enumValues[s] 15 | if !ok || es == nil { 16 | return errors.New("this option has no values") 17 | } 18 | if _, ok := es[value]; !ok { 19 | return errors.New("invalid value: " + value) 20 | } 21 | *s = enumValue(value) 22 | return nil 23 | } 24 | 25 | func (s *enumValue) String() string { 26 | return string(*s) 27 | } 28 | 29 | // Enum creates an option that can only be set to one of the enumerated strings 30 | // passed in values. Passing nil or an empty slice results in an option that 31 | // will always fail. 32 | func Enum(name rune, values []string, helpvalue ...string) *string { 33 | return CommandLine.Enum(name, values, helpvalue...) 34 | } 35 | 36 | func (s *Set) Enum(name rune, values []string, helpvalue ...string) *string { 37 | var p string 38 | s.EnumVarLong(&p, "", name, values, helpvalue...) 39 | return &p 40 | } 41 | 42 | func EnumLong(name string, short rune, values []string, helpvalue ...string) *string { 43 | return CommandLine.EnumLong(name, short, values, helpvalue...) 44 | } 45 | 46 | func (s *Set) EnumLong(name string, short rune, values []string, helpvalue ...string) *string { 47 | var p string 48 | s.EnumVarLong(&p, name, short, values, helpvalue...) 49 | return &p 50 | } 51 | 52 | // EnumVar creates an enum option that defaults to the starting value of *p. 53 | // If *p is not found in values then a reset of this option will fail. 54 | func EnumVar(p *string, name rune, values []string, helpvalue ...string) Option { 55 | return CommandLine.EnumVar(p, name, values, helpvalue...) 56 | } 57 | 58 | func (s *Set) EnumVar(p *string, name rune, values []string, helpvalue ...string) Option { 59 | return s.EnumVarLong(p, "", name, values, helpvalue...) 60 | } 61 | 62 | func EnumVarLong(p *string, name string, short rune, values []string, helpvalue ...string) Option { 63 | return CommandLine.EnumVarLong(p, name, short, values, helpvalue...) 64 | } 65 | 66 | func (s *Set) EnumVarLong(p *string, name string, short rune, values []string, helpvalue ...string) Option { 67 | m := make(map[string]struct{}) 68 | for _, v := range values { 69 | m[v] = struct{}{} 70 | } 71 | enumValues[(*enumValue)(p)] = m 72 | return s.VarLong((*enumValue)(p), name, short, helpvalue...) 73 | } 74 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mtool 2 | 3 | mtool is a tool to snapshot, verify and restore file modification timestamp (mtime) of files in git repositories and it is designed to overcome a ninja build tool limitation; 4 | see also: https://github.com/ninja-build/ninja/issues/1459 5 | 6 | The typical use-case is restoring a timestamp known to the ninja build system after changing git branches so that - given the same original file content - the ninja build system 7 | will not invalidte the intermediate and final build artifacts. 8 | 9 | # How does it work? 10 | 11 | The first step is to create an mtool snapshot; when creating the snapshot mtool expects the `git ls-files --stage` output 12 | and will store relative filename, hash and file modification time in the mtool snapshot (either a file or standard output). 13 | 14 | After you have done some git operations (changing branches, cherry-picking commits, rebasing etc) you may want to restore 15 | the file modification timestamps you have previously saved if the file content did not change. 16 | 17 | mtool will verify or change these modification timestamps if the file hash (as provided in the `git ls-files --stage` output) 18 | did not change and if it differs from the one stored in the mtool snapshot. 19 | 20 | # Usage 21 | 22 | ``` 23 | Usage: mtool [-achnrsv] [-i value] [-m value] [-o value] [parameters ...] 24 | -a, --append Append to existing mtool snapshot, if any; only valid when 25 | creating snapshot and when not using stdout 26 | -c, --create create mtool snapshot; this is the default action 27 | -h, --help display help and exit 28 | -i, --input=value input filename; content is in 'git ls-files --stage' format; 29 | - is for stdin (default) 30 | -m, --snapshot=value 31 | mtool snapshot filename; - is for stdout (default) 32 | -n, --verify verify that reference timestamps in current filesystem and 33 | mtool snapshot are the same 34 | -o, --concurrency=value 35 | how many goroutines to use for file mtime 36 | verification/restore; 1024 is the default 37 | -r, --restore restore reference timestamps into current filesystem from 38 | mtool snapshot, if any changed 39 | -s, --ignore-missing 40 | Ignore missing files during verify/restore 41 | -v, --verbose Be verbose about mtime differences found during 42 | verify/restore 43 | ``` 44 | 45 | See [chromium/mtime.sh](./chromium/mtime.sh) for a real-life use case. 46 | 47 | All invocations expect the 'git ls-files --stage' output on stdin when `--input` is not specified. 48 | 49 | # License 50 | 51 | [GNU GPL v3](./LICENSE) 52 | -------------------------------------------------------------------------------- /getopt/error.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package getopt 6 | 7 | import "fmt" 8 | 9 | // An Error is returned by Getopt when it encounters an error. 10 | type Error struct { 11 | ErrorCode // General reason of failure. 12 | Err error // The actual error. 13 | Parameter string // Parameter passed to option, if any 14 | Name string // Option that cause error, if any 15 | } 16 | 17 | // Error returns the error message, implementing the error interface. 18 | func (i *Error) Error() string { return i.Err.Error() } 19 | 20 | // An ErrorCode indicates what sort of error was encountered. 21 | type ErrorCode int 22 | 23 | const ( 24 | NoError = ErrorCode(iota) 25 | UnknownOption // an invalid option was encountered 26 | MissingParameter // the options parameter is missing 27 | ExtraParameter // a value was set to a long flag 28 | Invalid // attempt to set an invalid value 29 | ) 30 | 31 | func (e ErrorCode) String() string { 32 | switch e { 33 | case UnknownOption: 34 | return "unknow option" 35 | case MissingParameter: 36 | return "missing argument" 37 | case ExtraParameter: 38 | return "unxpected value" 39 | case Invalid: 40 | return "error setting value" 41 | } 42 | return "unknown error" 43 | } 44 | 45 | // unknownOption returns an Error indicating an unknown option was 46 | // encountered. 47 | func unknownOption(name interface{}) *Error { 48 | i := &Error{ErrorCode: UnknownOption} 49 | switch n := name.(type) { 50 | case rune: 51 | if n == '-' { 52 | i.Name = "-" 53 | } else { 54 | i.Name = "-" + string(n) 55 | } 56 | case string: 57 | i.Name = "--" + n 58 | } 59 | i.Err = fmt.Errorf("unknown option: %s", i.Name) 60 | return i 61 | } 62 | 63 | // missingArg returns an Error inidicating option o was not passed 64 | // a required parameter. 65 | func missingArg(o Option) *Error { 66 | return &Error{ 67 | ErrorCode: MissingParameter, 68 | Name: o.Name(), 69 | Err: fmt.Errorf("missing parameter for %s", o.Name()), 70 | } 71 | } 72 | 73 | // extraArg returns an Error inidicating option o was passed the 74 | // unexpected parameter value. 75 | func extraArg(o Option, value string) *Error { 76 | return &Error{ 77 | ErrorCode: ExtraParameter, 78 | Name: o.Name(), 79 | Parameter: value, 80 | Err: fmt.Errorf("unexpected parameter passed to %s: %q", o.Name(), value), 81 | } 82 | } 83 | 84 | // setError returns an Error inidicating option o and the specified 85 | // error while setting it to value. 86 | func setError(o Option, value string, err error) *Error { 87 | return &Error{ 88 | ErrorCode: Invalid, 89 | Name: o.Name(), 90 | Parameter: value, 91 | Err: err, 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /getopt/signed.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package getopt 6 | 7 | import ( 8 | "fmt" 9 | "strconv" 10 | ) 11 | 12 | type signed int64 13 | 14 | type SignedLimit struct { 15 | Base int // Base for conversion as per strconv.ParseInt 16 | Bits int // Number of bits as per strconv.ParseInt 17 | Min int64 // Minimum allowed value if both Min and Max are not 0 18 | Max int64 // Maximum allowed value if both Min and Max are not 0 19 | } 20 | 21 | var signedLimits = make(map[*signed]*SignedLimit) 22 | 23 | func (n *signed) Set(value string, opt Option) error { 24 | l := signedLimits[n] 25 | if l == nil { 26 | return fmt.Errorf("no limits defined for %s", opt.Name()) 27 | } 28 | v, err := strconv.ParseInt(value, l.Base, l.Bits) 29 | if err != nil { 30 | if e, ok := err.(*strconv.NumError); ok { 31 | switch e.Err { 32 | case strconv.ErrRange: 33 | err = fmt.Errorf("value out of range: %s", value) 34 | case strconv.ErrSyntax: 35 | err = fmt.Errorf("not a valid number: %s", value) 36 | } 37 | } 38 | return err 39 | } 40 | if l.Min != 0 || l.Max != 0 { 41 | if v < l.Min { 42 | return fmt.Errorf("value out of range (<%v): %s", l.Min, value) 43 | } 44 | if v > l.Max { 45 | return fmt.Errorf("value out of range (>%v): %s", l.Max, value) 46 | } 47 | } 48 | *n = signed(v) 49 | return nil 50 | } 51 | 52 | func (n *signed) String() string { 53 | l := signedLimits[n] 54 | if l != nil && l.Base != 0 { 55 | return strconv.FormatInt(int64(*n), l.Base) 56 | } 57 | return strconv.FormatInt(int64(*n), 10) 58 | } 59 | 60 | // Signed creates an option that is stored in an int64 and is constrained 61 | // by the limits pointed to by l. The Max and Min values are only used if 62 | // at least one of the values are not 0. If Base is 0, the base is implied by 63 | // the string's prefix: base 16 for "0x", base 8 for "0", and base 10 otherwise. 64 | func Signed(name rune, value int64, l *SignedLimit, helpvalue ...string) *int64 { 65 | return CommandLine.Signed(name, value, l, helpvalue...) 66 | } 67 | 68 | func (s *Set) Signed(name rune, value int64, l *SignedLimit, helpvalue ...string) *int64 { 69 | return s.SignedLong("", name, value, l, helpvalue...) 70 | } 71 | 72 | func SignedLong(name string, short rune, value int64, l *SignedLimit, helpvalue ...string) *int64 { 73 | return CommandLine.SignedLong(name, short, value, l, helpvalue...) 74 | } 75 | 76 | func (s *Set) SignedLong(name string, short rune, value int64, l *SignedLimit, helpvalue ...string) *int64 { 77 | s.SignedVarLong(&value, name, short, l, helpvalue...) 78 | return &value 79 | } 80 | 81 | func SignedVar(p *int64, name rune, l *SignedLimit, helpvalue ...string) Option { 82 | return CommandLine.SignedVar(p, name, l, helpvalue...) 83 | } 84 | 85 | func (s *Set) SignedVar(p *int64, name rune, l *SignedLimit, helpvalue ...string) Option { 86 | return s.SignedVarLong(p, "", name, l, helpvalue...) 87 | } 88 | 89 | func SignedVarLong(p *int64, name string, short rune, l *SignedLimit, helpvalue ...string) Option { 90 | return CommandLine.SignedVarLong(p, name, short, l, helpvalue...) 91 | } 92 | 93 | func (s *Set) SignedVarLong(p *int64, name string, short rune, l *SignedLimit, helpvalue ...string) Option { 94 | opt := s.VarLong((*signed)(p), name, short, helpvalue...) 95 | if l.Base > 36 || l.Base == 1 || l.Base < 0 { 96 | fmt.Fprintf(stderr, "invalid base for %s: %d\n", opt.Name(), l.Base) 97 | exit(1) 98 | } 99 | if l.Bits < 0 || l.Bits > 64 { 100 | fmt.Fprintf(stderr, "invalid bit size for %s: %d\n", opt.Name(), l.Bits) 101 | exit(1) 102 | } 103 | if l.Min > l.Max { 104 | fmt.Fprintf(stderr, "min greater than max for %s\n", opt.Name()) 105 | exit(1) 106 | } 107 | lim := *l 108 | signedLimits[(*signed)(p)] = &lim 109 | return opt 110 | } 111 | -------------------------------------------------------------------------------- /getopt/unsigned.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package getopt 6 | 7 | import ( 8 | "fmt" 9 | "strconv" 10 | ) 11 | 12 | type unsigned uint64 13 | 14 | type UnsignedLimit struct { 15 | Base int // Base for conversion as per strconv.ParseInt 16 | Bits int // Number of bits as per strconv.ParseInt 17 | Min uint64 // Minimum allowed value if both Min and Max are not 0 18 | Max uint64 // Maximum allowed value if both Min and Max are not 0 19 | } 20 | 21 | var unsignedLimits = make(map[*unsigned]*UnsignedLimit) 22 | 23 | func (n *unsigned) Set(value string, opt Option) error { 24 | l := unsignedLimits[n] 25 | if l == nil { 26 | return fmt.Errorf("no limits defined for %s", opt.Name()) 27 | } 28 | v, err := strconv.ParseUint(value, l.Base, l.Bits) 29 | if err != nil { 30 | if e, ok := err.(*strconv.NumError); ok { 31 | switch e.Err { 32 | case strconv.ErrRange: 33 | err = fmt.Errorf("value out of range: %s", value) 34 | case strconv.ErrSyntax: 35 | err = fmt.Errorf("not a valid number: %s", value) 36 | } 37 | } 38 | return err 39 | } 40 | if l.Min != 0 || l.Max != 0 { 41 | if v < l.Min { 42 | return fmt.Errorf("value out of range (<%v): %s", l.Min, value) 43 | } 44 | if v > l.Max { 45 | return fmt.Errorf("value out of range (>%v): %s", l.Max, value) 46 | } 47 | } 48 | *n = unsigned(v) 49 | return nil 50 | } 51 | 52 | func (n *unsigned) String() string { 53 | l := unsignedLimits[n] 54 | if l != nil && l.Base != 0 { 55 | return strconv.FormatUint(uint64(*n), l.Base) 56 | } 57 | return strconv.FormatUint(uint64(*n), 10) 58 | } 59 | 60 | // Unsigned creates an option that is stored in a uint64 and is 61 | // constrained by the limits pointed to by l. The Max and Min values are only 62 | // used if at least one of the values are not 0. If Base is 0, the base is 63 | // implied by the string's prefix: base 16 for "0x", base 8 for "0", and base 64 | // 10 otherwise. 65 | func Unsigned(name rune, value uint64, l *UnsignedLimit, helpvalue ...string) *uint64 { 66 | return CommandLine.Unsigned(name, value, l, helpvalue...) 67 | } 68 | 69 | func (s *Set) Unsigned(name rune, value uint64, l *UnsignedLimit, helpvalue ...string) *uint64 { 70 | return s.UnsignedLong("", name, value, l, helpvalue...) 71 | } 72 | 73 | func UnsignedLong(name string, short rune, value uint64, l *UnsignedLimit, helpvalue ...string) *uint64 { 74 | return CommandLine.UnsignedLong(name, short, value, l, helpvalue...) 75 | } 76 | 77 | func (s *Set) UnsignedLong(name string, short rune, value uint64, l *UnsignedLimit, helpvalue ...string) *uint64 { 78 | s.UnsignedVarLong(&value, name, short, l, helpvalue...) 79 | return &value 80 | } 81 | 82 | func UnsignedVar(p *uint64, name rune, l *UnsignedLimit, helpvalue ...string) Option { 83 | return CommandLine.UnsignedVar(p, name, l, helpvalue...) 84 | } 85 | 86 | func (s *Set) UnsignedVar(p *uint64, name rune, l *UnsignedLimit, helpvalue ...string) Option { 87 | return s.UnsignedVarLong(p, "", name, l, helpvalue...) 88 | } 89 | 90 | func UnsignedVarLong(p *uint64, name string, short rune, l *UnsignedLimit, helpvalue ...string) Option { 91 | return CommandLine.UnsignedVarLong(p, name, short, l, helpvalue...) 92 | } 93 | 94 | func (s *Set) UnsignedVarLong(p *uint64, name string, short rune, l *UnsignedLimit, helpvalue ...string) Option { 95 | opt := s.VarLong((*unsigned)(p), name, short, helpvalue...) 96 | if l.Base > 36 || l.Base == 1 || l.Base < 0 { 97 | fmt.Fprintf(stderr, "invalid base for %s: %d\n", opt.Name(), l.Base) 98 | exit(1) 99 | } 100 | if l.Bits < 0 || l.Bits > 64 { 101 | fmt.Fprintf(stderr, "invalid bit size for %s: %d\n", opt.Name(), l.Bits) 102 | exit(1) 103 | } 104 | if l.Min > l.Max { 105 | fmt.Fprintf(stderr, "min greater than max for %s\n", opt.Name()) 106 | exit(1) 107 | } 108 | lim := *l 109 | unsignedLimits[(*unsigned)(p)] = &lim 110 | return opt 111 | } 112 | -------------------------------------------------------------------------------- /getopt/option.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package getopt 6 | 7 | import ( 8 | "fmt" 9 | "strings" 10 | ) 11 | 12 | // An Option can be either a Flag or a Value 13 | type Option interface { 14 | // Name returns the name of the option. If the option has been seen 15 | // then the last way it was referenced (short or long) is returned 16 | // otherwise if there is a short name then this will be the short name 17 | // as a string, else it will be the long name. 18 | Name() string 19 | 20 | // IsFlag returns true if Option is a flag. 21 | IsFlag() bool 22 | 23 | // Seen returns true if the flag was seen. 24 | Seen() bool 25 | 26 | // Count returns the number of times the flag was seen. 27 | Count() int 28 | 29 | // String returns the last value the option was set to. 30 | String() string 31 | 32 | // Value returns the Value of the option. 33 | Value() Value 34 | 35 | // SetOptional makes the value optional. The option and value are 36 | // always a single argument. Either --option or --option=value. In 37 | // the former case the value of the option does not change but the Set() 38 | // will return true and the value returned by Count() is incremented. 39 | // The short form is either -o or -ovalue. SetOptional returns 40 | // the Option 41 | SetOptional() Option 42 | 43 | // SetFlag makes the value a flag. Flags are boolean values and 44 | // normally do not taken a value. They are set to true when seen. 45 | // If a value is passed in the long form then it must be on, case 46 | // insenstive, one of "true", "false", "t", "f", "on", "off", "1", "0". 47 | // SetFlag returns the Option 48 | SetFlag() Option 49 | 50 | // Reset resets the state of the option so it appears it has not 51 | // yet been seen, including resetting the value of the option 52 | // to its original default state. 53 | Reset() 54 | } 55 | 56 | type option struct { 57 | isLong bool // True if they used the long name 58 | flag bool // true if a boolean flag 59 | optional bool // true if we take an optional value 60 | short rune // 0 means no short name 61 | count int // number of times we have seen this option 62 | long string // "" means no long name 63 | defval string // default value 64 | help string // help message 65 | where string // file where the option was defined 66 | value Value // current value of option 67 | name string // name of the value (for usage) 68 | uname string // name of the option (for usage) 69 | } 70 | 71 | // usageName returns the name of the option for printing usage lines in one 72 | // of the following forms: 73 | // 74 | // -f 75 | // --flag 76 | // -f, --flag 77 | // -s value 78 | // --set=value 79 | // -s, --set=value 80 | func (o *option) usageName() string { 81 | // Don't print help messages if we have none and there is only one 82 | // way to specify the option. 83 | if o.help == "" && (o.short == 0 || o.long == "") { 84 | return "" 85 | } 86 | n := "" 87 | 88 | switch { 89 | case o.short != 0 && o.long == "": 90 | n = "-" + string(o.short) 91 | case o.short == 0 && o.long != "": 92 | n = " --" + o.long 93 | case o.short != 0 && o.long != "": 94 | n = "-" + string(o.short) + ", --" + o.long 95 | } 96 | 97 | switch { 98 | case o.flag: 99 | return n 100 | case o.optional: 101 | return n + "[=" + o.name + "]" 102 | case o.long != "": 103 | return n + "=" + o.name 104 | } 105 | return n + " " + o.name 106 | } 107 | 108 | // sortName returns the name to sort the option on. 109 | func (o *option) sortName() string { 110 | if o.short != 0 { 111 | return string(o.short) + o.long 112 | } 113 | return o.long[:1] + o.long 114 | } 115 | 116 | func (o *option) Seen() bool { return o.count > 0 } 117 | func (o *option) Count() int { return o.count } 118 | func (o *option) IsFlag() bool { return o.flag } 119 | func (o *option) String() string { return o.value.String() } 120 | func (o *option) SetOptional() Option { o.optional = true; return o } 121 | func (o *option) SetFlag() Option { o.flag = true; return o } 122 | 123 | func (o *option) Value() Value { 124 | if o == nil { 125 | return nil 126 | } 127 | return o.value 128 | } 129 | 130 | func (o *option) Name() string { 131 | if !o.isLong && o.short != 0 { 132 | return "-" + string(o.short) 133 | } 134 | return "--" + o.long 135 | } 136 | 137 | // Reset rests an option so that it appears it has not yet been seen. 138 | func (o *option) Reset() { 139 | o.isLong = false 140 | o.count = 0 141 | o.value.Set(o.defval, o) 142 | } 143 | 144 | type optionList []*option 145 | 146 | func (ol optionList) Len() int { return len(ol) } 147 | func (ol optionList) Swap(i, j int) { ol[i], ol[j] = ol[j], ol[i] } 148 | func (ol optionList) Less(i, j int) bool { 149 | // first check the short names (or the first letter of the long name) 150 | // If they are not equal (case insensitive) then we have our answer 151 | n1 := ol[i].sortName() 152 | n2 := ol[j].sortName() 153 | l1 := strings.ToLower(n1) 154 | l2 := strings.ToLower(n2) 155 | if l1 < l2 { 156 | return true 157 | } 158 | if l2 < l1 { 159 | return false 160 | } 161 | return n1 < n2 162 | } 163 | 164 | // AddOption add the option o to set CommandLine if o is not already in set 165 | // CommandLine. 166 | func AddOption(o Option) { 167 | CommandLine.AddOption(o) 168 | } 169 | 170 | // AddOption add the option o to set s if o is not already in set s. 171 | func (s *Set) AddOption(o Option) { 172 | opt := o.(*option) 173 | for _, eopt := range s.options { 174 | if opt == eopt { 175 | return 176 | } 177 | } 178 | if opt.short != 0 { 179 | if oo, ok := s.shortOptions[opt.short]; ok { 180 | fmt.Fprintf(stderr, "%s: -%c already declared at %s\n", opt.where, opt.short, oo.where) 181 | exit(1) 182 | } 183 | s.shortOptions[opt.short] = opt 184 | } 185 | if opt.long != "" { 186 | if oo, ok := s.longOptions[opt.long]; ok { 187 | fmt.Fprintf(stderr, "%s: --%s already declared at %s\n", opt.where, opt.long, oo.where) 188 | exit(1) 189 | } 190 | s.longOptions[opt.long] = opt 191 | } 192 | s.options = append(s.options, opt) 193 | } 194 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "io" 7 | "os" 8 | "strconv" 9 | "strings" 10 | "sync" 11 | "sync/atomic" 12 | "time" 13 | 14 | "./getopt" 15 | ) 16 | 17 | var ( 18 | nonVerifyingFiles, totalFiles uint64 19 | verbose bool 20 | ignoreMissing = true 21 | ) 22 | 23 | func main() { 24 | var ( 25 | help, verify, restore, create bool 26 | append bool 27 | inputFileName = "-" 28 | mtoolFileName = "-" 29 | concurrency = 1024 30 | ) 31 | 32 | getopt.StringVarLong(&inputFileName, "input", 'i', "input filename; content is in 'git ls-files --stage' format; - is for stdin (default)") 33 | getopt.StringVarLong(&mtoolFileName, "snapshot", 'm', "mtool snapshot filename; - is for stdout (default)") 34 | getopt.BoolVarLong(&append, "append", 'a', "Append to existing mtool snapshot, if any; only valid when creating snapshot and when not using stdout") 35 | getopt.BoolVarLong(&verbose, "verbose", 'v', "Be verbose about mtime differences found during verify/restore") 36 | getopt.BoolVarLong(&ignoreMissing, "ignore-missing", 's', "Ignore missing files during verify/restore") 37 | getopt.BoolVarLong(&help, "help", 'h', "display help and exit") 38 | getopt.BoolVarLong(&create, "create", 'c', "create mtool snapshot; this is the default action") 39 | getopt.BoolVarLong(&verify, "verify", 'n', "verify that reference timestamps in current filesystem and mtool snapshot are the same") 40 | getopt.BoolVarLong(&restore, "restore", 'r', "restore reference timestamps into current filesystem from mtool snapshot, if any changed") 41 | getopt.IntVarLong(&concurrency, "concurrency", 'o', "how many goroutines to use for file mtime verification/restore; 1024 is the default") 42 | 43 | getopt.Parse() 44 | 45 | if len(getopt.Args()) != 0 { 46 | getopt.Usage() 47 | os.Exit(1) 48 | } 49 | 50 | if concurrency < 1 { 51 | fmt.Fprintf(os.Stderr, "ERROR: concurrency should be 1 or more\n") 52 | os.Exit(1) 53 | } 54 | 55 | cmd := 0 56 | if verify { 57 | cmd++ 58 | } 59 | if restore { 60 | cmd++ 61 | } 62 | if create { 63 | cmd++ 64 | } 65 | if help { 66 | cmd++ 67 | } 68 | 69 | switch cmd { 70 | case 0: 71 | create = true 72 | case 1: 73 | // ok 74 | if help { 75 | getopt.Usage() 76 | return 77 | } 78 | default: 79 | fmt.Fprintf(os.Stderr, "ERROR: specify one command\n") 80 | getopt.Usage() 81 | os.Exit(10) 82 | } 83 | 84 | var src io.Reader 85 | if inputFileName != "-" { 86 | f, err := os.Open(inputFileName) 87 | if err != nil { 88 | fmt.Fprintf(os.Stderr, "ERROR: %v\n", err) 89 | os.Exit(15) 90 | } 91 | src = f 92 | defer f.Close() 93 | } else { 94 | src = os.Stdin 95 | } 96 | 97 | inputScanner := bufio.NewScanner(src) 98 | 99 | switch { 100 | case create: 101 | var dst io.Writer 102 | if mtoolFileName != "-" { 103 | if append { 104 | f, err := os.OpenFile(mtoolFileName, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) 105 | if err != nil { 106 | fmt.Fprintf(os.Stderr, "ERROR: %v\n", err) 107 | os.Exit(15) 108 | } 109 | defer f.Close() 110 | dst = f 111 | } else { 112 | f, err := os.Create(mtoolFileName) 113 | if err != nil { 114 | fmt.Fprintf(os.Stderr, "ERROR: %v\n", err) 115 | os.Exit(15) 116 | } 117 | defer f.Close() 118 | dst = f 119 | } 120 | } else { 121 | dst = os.Stdout 122 | } 123 | mustScanGitLsInput(inputScanner, func(_ int, fileName, sha1 string, mtime time.Time) error { 124 | _, err := fmt.Fprintf(dst, "%s\t%s\t%d\n", fileName, sha1, mtime.UnixNano()) 125 | return err 126 | }) 127 | return 128 | case restore, verify: 129 | if inputFileName == mtoolFileName { 130 | fmt.Fprintf(os.Stderr, "ERROR: input and snapshot cannot be the same when restoring\n") 131 | os.Exit(10) 132 | } 133 | var mtoolSrc io.Reader 134 | if mtoolFileName != "-" { 135 | f, err := os.Open(mtoolFileName) 136 | if err != nil { 137 | fmt.Fprintf(os.Stderr, "ERROR: %v\n", err) 138 | os.Exit(15) 139 | } 140 | mtoolSrc = f 141 | defer f.Close() 142 | } else { 143 | mtoolSrc = os.Stdin 144 | } 145 | // load the mtool snapshot 146 | m := mustLoadMtool(bufio.NewScanner(mtoolSrc)) 147 | 148 | // create a pool of goroutines 149 | res := make(chan struct{}, concurrency) 150 | for i := 0; i < concurrency; i++ { 151 | res <- struct{}{} 152 | } 153 | 154 | var wg sync.WaitGroup 155 | mustScanGitLsInput(inputScanner, func(lineNo int, fileName, sha1 string, mtime time.Time) error { 156 | wg.Add(1) 157 | go func() { 158 | defer func() { 159 | wg.Done() 160 | res <- struct{}{} 161 | }() 162 | <-res 163 | err := restoreCallback(m, fileName, sha1, mtime, verify) 164 | if err != nil { 165 | // stop at first error 166 | fmt.Fprintf(os.Stderr, "ERROR: line %d: %v\n", lineNo, err) 167 | os.Exit(20) 168 | } 169 | }() 170 | 171 | return nil 172 | }) 173 | 174 | // wait for all goroutines to complete 175 | wg.Wait() 176 | 177 | if verbose { 178 | fmt.Fprintf(os.Stderr, "mtool: %d/%d files verified successfully\n", totalFiles-nonVerifyingFiles, totalFiles) 179 | } 180 | 181 | if verify { 182 | // return 0 only when no changes are needed 183 | os.Exit(int(nonVerifyingFiles)) 184 | } 185 | 186 | return 187 | } 188 | panic("NOT REACHED") 189 | } 190 | 191 | func restoreCallback(m map[string]*entry, fileName, sha1 string, mtime time.Time, verifyOnly bool) error { 192 | // first verify if file is in the mtool snapshot and hash did not change 193 | var expectedMtime time.Time 194 | if e, ok := m[fileName]; !ok { 195 | return nil 196 | } else { 197 | // not deleting from map since it is accessed concurrently 198 | if e.sha1 != sha1 { 199 | return nil 200 | } 201 | expectedMtime = e.mtime 202 | } 203 | 204 | atomic.AddUint64(&totalFiles, 1) 205 | 206 | foundMtime := mtime.UnixNano() 207 | if foundMtime != expectedMtime.UnixNano() { 208 | atomic.AddUint64(&nonVerifyingFiles, 1) 209 | if verifyOnly { 210 | if verbose { 211 | fmt.Fprintf(os.Stderr, "%s: modified time expected %d but found %d\n", fileName, expectedMtime.UnixNano(), foundMtime) 212 | } 213 | } else { 214 | // set the mtime; atime is not preserved 215 | err := os.Chtimes(fileName, time.Now(), expectedMtime) 216 | if err == nil && verbose { 217 | fmt.Fprintf(os.Stderr, "%s: changed modified time from %v to %v\n", fileName, mtime, expectedMtime) 218 | } 219 | return err 220 | } 221 | } 222 | return nil 223 | } 224 | 225 | type entry struct { 226 | sha1 string 227 | mtime time.Time 228 | } 229 | 230 | func mustLoadMtool(scanner *bufio.Scanner) map[string]*entry { 231 | m := map[string]*entry{} 232 | lineNo := 0 233 | for scanner.Scan() { 234 | lineNo++ 235 | parts := strings.SplitN(strings.TrimSpace(scanner.Text()), "\t", 3) 236 | 237 | if len(parts) != 3 { 238 | fmt.Fprintf(os.Stderr, "ERROR: line %d: expected 3 tab-separated fields for restore/verify, got %d\n", lineNo, len(parts)) 239 | os.Exit(10) 240 | } 241 | 242 | mtime, err := strconv.ParseInt(parts[2], 10, 64) 243 | if err != nil { 244 | fmt.Fprintf(os.Stderr, "ERROR: %v\n", err) 245 | os.Exit(15) 246 | } 247 | 248 | fileName, sha1 := parts[0], parts[1] 249 | 250 | if _, ok := m[fileName]; ok { 251 | fmt.Fprintf(os.Stderr, "ERROR: line %d: filename collision in mtool snapshot for %q\n", lineNo, fileName) 252 | os.Exit(10) 253 | } 254 | 255 | m[fileName] = &entry{ 256 | sha1: sha1, 257 | mtime: time.Unix(0, mtime), 258 | } 259 | } 260 | 261 | if err := scanner.Err(); err != nil { 262 | fmt.Fprintf(os.Stderr, "ERROR: %v\n", err) 263 | os.Exit(15) 264 | } 265 | 266 | return m 267 | } 268 | 269 | type gitLsCallback func(lineNo int, fileName, sha1 string, mtime time.Time) error 270 | 271 | func mustScanGitLsInput(scanner *bufio.Scanner, fn gitLsCallback) { 272 | lineNo := 0 273 | for scanner.Scan() { 274 | lineNo++ 275 | parts := strings.SplitN(strings.TrimSpace(scanner.Text()), "\t", 2) 276 | 277 | if len(parts) != 2 { 278 | fmt.Fprintf(os.Stderr, "ERROR: line %d: expected 2 tab-separated fields in 'git ls-files --stage' output\n", lineNo) 279 | os.Exit(10) 280 | } 281 | 282 | fileName := parts[1] 283 | s, err := os.Stat(fileName) 284 | if err != nil { 285 | if ignoreMissing && os.IsNotExist(err) { 286 | if verbose { 287 | fmt.Fprintf(os.Stderr, "Line %d: ignoring missing file %q\n", lineNo, fileName) 288 | } 289 | continue 290 | } 291 | fmt.Fprintf(os.Stderr, "ERROR: %v\n", err) 292 | os.Exit(15) 293 | } 294 | mtime := s.ModTime() 295 | 296 | parts = strings.SplitN(parts[0], " ", 3) 297 | if len(parts) != 3 { 298 | fmt.Fprintf(os.Stderr, "ERROR: line %d: malformed first field\n", lineNo) 299 | os.Exit(10) 300 | } 301 | 302 | err = fn(lineNo, fileName, parts[1], mtime) 303 | if err != nil { 304 | fmt.Fprintf(os.Stderr, "ERROR: line %d: %v\n", lineNo, err) 305 | os.Exit(20) 306 | } 307 | } 308 | 309 | if err := scanner.Err(); err != nil { 310 | fmt.Fprintf(os.Stderr, "ERROR: %v\n", err) 311 | os.Exit(15) 312 | } 313 | } 314 | -------------------------------------------------------------------------------- /getopt/set.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package getopt 6 | 7 | import ( 8 | "io" 9 | "os" 10 | "sort" 11 | ) 12 | 13 | // A Termination says why Getopt returned. 14 | type State int 15 | 16 | const ( 17 | InProgress = State(iota) // Getopt is still running 18 | Dash // Returned on "-" 19 | DashDash // Returned on "--" 20 | EndOfOptions // End of options reached 21 | EndOfArguments // No more arguments 22 | Terminated // Terminated by callback function 23 | Failure // Terminated due to error 24 | Unknown // Indicates internal error 25 | ) 26 | 27 | type Set struct { 28 | State // State of getopt 29 | 30 | // args are the parameters remaining after parsing the optoins. 31 | args []string 32 | 33 | // program is the name of the program for usage and error messages. 34 | // If not set it will automatically be set to the base name of the 35 | // first argument passed to parse. 36 | program string 37 | 38 | // parameters is what is displayed on the usage line after displaying 39 | // the various options. 40 | parameters string 41 | 42 | usage func() // usage should print the programs usage and exit. 43 | 44 | shortOptions map[rune]*option 45 | longOptions map[string]*option 46 | options optionList 47 | } 48 | 49 | // New returns a newly created option set. 50 | func New() *Set { 51 | s := &Set{ 52 | shortOptions: make(map[rune]*option), 53 | longOptions: make(map[string]*option), 54 | parameters: "[parameters ...]", 55 | } 56 | 57 | s.usage = func() { 58 | s.PrintUsage(stderr) 59 | } 60 | return s 61 | } 62 | 63 | // CommandLine is the default set of command-line options. 64 | var CommandLine = New() 65 | 66 | // PrintUsage calls PrintUsage in the default option set. 67 | func PrintUsage(w io.Writer) { CommandLine.PrintUsage(w) } 68 | 69 | // Usage calls the usage function in the default option set. 70 | func Usage() { CommandLine.usage() } 71 | 72 | // Parse calls Parse in the default option set with the command line arguments 73 | // found in os.Args. 74 | func Parse() { CommandLine.Parse(os.Args) } 75 | 76 | // Getops returns the result of calling Getop in the default option set with the 77 | // command line arguments found in os.Args. The fn function, which may be nil, 78 | // is passed to Getopt. 79 | func Getopt(fn func(Option) bool) error { return CommandLine.Getopt(os.Args, fn) } 80 | 81 | // Arg returns the n'th command-line argument. Arg(0) is the first remaining 82 | // argument after options have been processed. 83 | func Arg(n int) string { 84 | if n >= 0 && n < len(CommandLine.args) { 85 | return CommandLine.args[n] 86 | } 87 | return "" 88 | } 89 | 90 | // Arg returns the n'th argument. Arg(0) is the first remaining 91 | // argument after options have been processed. 92 | func (s *Set) Arg(n int) string { 93 | if n >= 0 && n < len(s.args) { 94 | return s.args[n] 95 | } 96 | return "" 97 | } 98 | 99 | // Args returns the non-option command line arguments. 100 | func Args() []string { 101 | return CommandLine.args 102 | } 103 | 104 | // Args returns the non-option arguments. 105 | func (s *Set) Args() []string { 106 | return s.args 107 | } 108 | 109 | // NArgs returns the number of non-option command line arguments. 110 | func NArgs() int { 111 | return len(CommandLine.args) 112 | } 113 | 114 | // NArgs returns the number of non-option arguments. 115 | func (s *Set) NArgs() int { 116 | return len(s.args) 117 | } 118 | 119 | // SetParameters sets the parameters string for printing the command line 120 | // usage. It defaults to "[parameters ...]" 121 | func SetParameters(parameters string) { 122 | CommandLine.parameters = parameters 123 | } 124 | 125 | // SetParameters sets the parameters string for printing the s's usage. 126 | // It defaults to "[parameters ...]" 127 | func (s *Set) SetParameters(parameters string) { 128 | s.parameters = parameters 129 | } 130 | 131 | // SetProgram sets the program name to program. Nomrally it is determined 132 | // from the zeroth command line argument (see os.Args). 133 | func SetProgram(program string) { 134 | CommandLine.program = program 135 | } 136 | 137 | // SetProgram sets s's program name to program. Nomrally it is determined 138 | // from the zeroth argument passed to Getopt or Parse. 139 | func (s *Set) SetProgram(program string) { 140 | s.program = program 141 | } 142 | 143 | // SetUsage sets the function used by Parse to display the commands usage 144 | // on error. It defaults to calling PrintUsage(os.Stderr). 145 | func SetUsage(usage func()) { 146 | CommandLine.usage = usage 147 | } 148 | 149 | // SetUsage sets the function used by Parse to display usage on error. It 150 | // defaults to calling f.PrintUsage(os.Stderr). 151 | func (s *Set) SetUsage(usage func()) { 152 | s.usage = usage 153 | } 154 | 155 | // Lookup returns the Option associated with name. Name should either be 156 | // a rune (the short name) or a string (the long name). 157 | func Lookup(name interface{}) Option { 158 | return CommandLine.Lookup(name) 159 | } 160 | 161 | // Lookup returns the Option associated with name in s. Name should either be 162 | // a rune (the short name) or a string (the long name). 163 | func (s *Set) Lookup(name interface{}) Option { 164 | switch v := name.(type) { 165 | case rune: 166 | return s.shortOptions[v] 167 | case int: 168 | return s.shortOptions[rune(v)] 169 | case string: 170 | return s.longOptions[v] 171 | } 172 | return nil 173 | } 174 | 175 | // IsSet returns true if the Option associated with name was seen while 176 | // parsing the command line arguments. Name should either be a rune (the 177 | // short name) or a string (the long name). 178 | func IsSet(name interface{}) bool { 179 | return CommandLine.IsSet(name) 180 | } 181 | 182 | // IsSet returns true if the Option associated with name was seen while 183 | // parsing s. Name should either be a rune (the short name) or a string (the 184 | // long name). 185 | func (s *Set) IsSet(name interface{}) bool { 186 | if opt := s.Lookup(name); opt != nil { 187 | return opt.Seen() 188 | } 189 | return false 190 | } 191 | 192 | // GetCount returns the number of times the Option associated with name has been 193 | // seen while parsing the command line arguments. Name should either be a rune 194 | // (the short name) or a string (the long name). 195 | func GetCount(name interface{}) int { 196 | return CommandLine.GetCount(name) 197 | } 198 | 199 | // GetCount returns the number of times the Option associated with name has been 200 | // seen while parsing s's arguments. Name should either be a rune (the short 201 | // name) or a string (the long name). 202 | func (s *Set) GetCount(name interface{}) int { 203 | if opt := s.Lookup(name); opt != nil { 204 | return opt.Count() 205 | } 206 | return 0 207 | } 208 | 209 | // GetValue returns the final value set to the command-line Option with name. 210 | // If the option has not been seen while parsing s then the default value is 211 | // returned. Name should either be a rune (the short name) or a string (the 212 | // long name). 213 | func GetValue(name interface{}) string { 214 | return CommandLine.GetValue(name) 215 | } 216 | 217 | // GetValue returns the final value set to the Option in s associated with name. 218 | // If the option has not been seen while parsing s then the default value is 219 | // returned. Name should either be a rune (the short name) or a string (the 220 | // long name). 221 | func (s *Set) GetValue(name interface{}) string { 222 | if opt := s.Lookup(name); opt != nil { 223 | return opt.String() 224 | } 225 | return "" 226 | } 227 | 228 | // Visit visits the command-line options in lexicographical order, calling fn 229 | // for each. It visits only those options that have been set. 230 | func Visit(fn func(Option)) { CommandLine.Visit(fn) } 231 | 232 | // Visit visits the options in s in lexicographical order, calling fn 233 | // for each. It visits only those options that have been set. 234 | func (s *Set) Visit(fn func(Option)) { 235 | sort.Sort(s.options) 236 | for _, opt := range s.options { 237 | if opt.count > 0 { 238 | fn(opt) 239 | } 240 | } 241 | } 242 | 243 | // VisitAll visits the options in s in lexicographical order, calling fn 244 | // for each. It visits all options, even those not set. 245 | func VisitAll(fn func(Option)) { CommandLine.VisitAll(fn) } 246 | 247 | // VisitAll visits the command-line flags in lexicographical order, calling fn 248 | // for each. It visits all flags, even those not set. 249 | func (s *Set) VisitAll(fn func(Option)) { 250 | sort.Sort(s.options) 251 | for _, opt := range s.options { 252 | fn(opt) 253 | } 254 | } 255 | 256 | // Reset resets all the command line options to the initial state so it 257 | // appears none of them have been seen. 258 | func Reset() { 259 | CommandLine.Reset() 260 | } 261 | 262 | // Reset resets all the options in s to the initial state so it 263 | // appears none of them have been seen. 264 | func (s *Set) Reset() { 265 | for _, opt := range s.options { 266 | opt.Reset() 267 | } 268 | } 269 | -------------------------------------------------------------------------------- /getopt/getopt.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package getopt (v1) provides traditional getopt processing for implementing 6 | // commands that use traditional command lines. The standard Go flag package 7 | // cannot be used to write a program that parses flags the way ls or ssh does, 8 | // for example. 9 | // 10 | // A new version of this package (v2) (whose package name is also getopt) is 11 | // available as: 12 | // 13 | // "github.com/pborman/getopt/v2" 14 | // 15 | // Getopt supports functionality found in both the standard BSD getopt as well 16 | // as (one of the many versions of) the GNU getopt_long. Being a Go package, 17 | // this package makes common usage easy, but still enables more controlled usage 18 | // if needed. 19 | // 20 | // Typical usage: 21 | // 22 | // // Declare the flags to be used 23 | // helpFlag := getopt.Bool('?', "display help") 24 | // cmdFlag := getopt.StringLong("command", 'c', "", "the command) 25 | // 26 | // func main() { 27 | // // Parse the program arguments 28 | // getopt.Parse() 29 | // // Get the remaining positional parameters 30 | // args := getopt.Args() 31 | // 32 | // If you don't want the program to exit on error, use getopt.Getopt: 33 | // 34 | // err := getopt.Getopt(nil) 35 | // if err != nil { 36 | // // code to handle error 37 | // fmt.Fprintln(os.Stderr, err) 38 | // } 39 | // 40 | // Support is provided for both short (-f) and long (--flag) options. A single 41 | // option may have both a short and a long name. Each option may be a flag or a 42 | // value. A value takes an argument. 43 | // 44 | // Declaring no long names causes this package to process arguments like the 45 | // traditional BSD getopt. 46 | // 47 | // Short flags may be combined into a single parameter. For example, "-a -b -c" 48 | // may also be expressed "-abc". Long flags must stand on their own "--alpha 49 | // --beta" 50 | // 51 | // Values require an argument. For short options the argument may either be 52 | // immediately following the short name or as the next argument. Only one short 53 | // value may be combined with short flags in a single argument; the short value 54 | // must be after all short flags. For example, if f is a flag and v is a value, 55 | // then: 56 | // 57 | // -vvalue (sets v to "value") 58 | // -v value (sets v to "value") 59 | // -fvvalue (sets f, and sets v to "value") 60 | // -fv value (sets f, and sets v to "value") 61 | // -vf value (set v to "f" and value is the first parameter) 62 | // 63 | // For the long value option val: 64 | // 65 | // --val value (sets val to "value") 66 | // --val=value (sets val to "value") 67 | // --valvalue (invalid option "valvalue") 68 | // 69 | // Values with an optional value only set the value if the value is part of the 70 | // same argument. In any event, the option count is increased and the option is 71 | // marked as seen. 72 | // 73 | // -v -f (sets v and f as being seen) 74 | // -vvalue -f (sets v to "value" and sets f) 75 | // --val -f (sets v and f as being seen) 76 | // --val=value -f (sets v to "value" and sets f) 77 | // 78 | // There is no convience function defined for making the value optional. The 79 | // SetOptional method must be called on the actual Option. 80 | // 81 | // v := String("val", 'v', "", "the optional v") 82 | // Lookup("v").SetOptional() 83 | // 84 | // var s string 85 | // StringVar(&s, "val", 'v', "the optional v).SetOptional() 86 | // 87 | // Parsing continues until the first non-option or "--" is encountered. 88 | // 89 | // The short name "-" can be used, but it either is specified as "-" or as part 90 | // of a group of options, for example "-f-". If there are no long options 91 | // specified then "--f" could also be used. If "-" is not declared as an option 92 | // then the single "-" will also terminate the option processing but unlike 93 | // "--", the "-" will be part of the remaining arguments. 94 | // 95 | // Normally the parsing is performed by calling the Parse function. If it is 96 | // important to see the order of the options then the Getopt function should be 97 | // used. The standard Parse function does the equivalent of: 98 | // 99 | // func Parse() { 100 | // if err := getopt.Getopt(os.Args, nil); err != nil { 101 | // fmt.Fprintln(os.Stderr, err) 102 | // s.usage() 103 | // os.Exit(1) 104 | // } 105 | // 106 | // When calling Getopt it is the responsibility of the caller to print any 107 | // errors. 108 | // 109 | // Normally the default option set, CommandLine, is used. Other option sets may 110 | // be created with New. 111 | // 112 | // After parsing, the sets Args will contain the non-option arguments. If an 113 | // error is encountered then Args will begin with argument that caused the 114 | // error. 115 | // 116 | // It is valid to call a set's Parse a second time to amend the current set of 117 | // flags or values. As an example: 118 | // 119 | // var a = getopt.Bool('a', "", "The a flag") 120 | // var b = getopt.Bool('b', "", "The a flag") 121 | // var cmd = "" 122 | // 123 | // var opts = getopt.CommandLine 124 | // 125 | // opts.Parse(os.Args) 126 | // if opts.NArgs() > 0 { 127 | // cmd = opts.Arg(0) 128 | // opts.Parse(opts.Args()) 129 | // } 130 | // 131 | // If called with set to { "prog", "-a", "cmd", "-b", "arg" } then both and and 132 | // b would be set, cmd would be set to "cmd", and opts.Args() would return { 133 | // "arg" }. 134 | // 135 | // Unless an option type explicitly prohibits it, an option may appear more than 136 | // once in the arguments. The last value provided to the option is the value. 137 | // 138 | // SYNTAX 139 | // 140 | // For each option type there are an unfortunately large number of ways, 8, to 141 | // initialize the option. This number is derived from three attributes: 142 | // 143 | // 1) Short or Long name 144 | // 2) Normal vs Var 145 | // 3) Command Line vs Option Set 146 | // 147 | // The first two variations provide 4 signature: 148 | // 149 | // Option(name rune, [value type,] helpvalue... string) 150 | // OptionLong(name string, short rune, [value type,] helpvalue... string) 151 | // OptionVar(p *type, name rune, helpvalue... string) 152 | // OptionVarLong(p *type, name string, short rune, helpvalue... string) 153 | // 154 | // Foo can actually be expressed in terms of FooLong: 155 | // 156 | // func Foo(name rune, value type, helpvalue... string) *type { 157 | // return FooLong("", name, value, helpvalue...) 158 | // } 159 | // 160 | // Normally Foo is used, unless long options are needed. Setting short to 0 161 | // creates only a long option. 162 | // 163 | // The difference bentween Foo and FooVar is that you pass a pointer, p, to the 164 | // location of the value to FooVar. The default value is simply *p. The 165 | // initial value of *p is the defaut value of the option. 166 | // 167 | // Foo is actually a wrapper around FooVar: 168 | // 169 | // func Foo(name rune, value type, helpvalue... string) *type { 170 | // p := value 171 | // FooVar(&p, name, helpvalue... string) 172 | // return &p 173 | // } 174 | // 175 | // 176 | // The third variation provides a top-level function and a method on a Set: 177 | // 178 | // func Option(...) 179 | // func (s *Set) Option(...) 180 | // 181 | // The top-level function is simply: 182 | // 183 | // func Option(...) *type { 184 | // return CommandLine.Option(...) { 185 | // } 186 | // 187 | // To simplify documentation, typically only the main top-level function is fully 188 | // documented. The others will have documentation when there is something 189 | // special about them. 190 | // 191 | // VALUEHELP 192 | // 193 | // All non-flag options are created with a "valuehelp" as the last parameter. 194 | // Valuehelp should be 0, 1, or 2 strings. The first string, if provided, is 195 | // the usage message for the option. If the second string, if provided, is the 196 | // name to use for the value when displaying the usage. If not provided the 197 | // term "value" is assumed. 198 | // 199 | // The usage message for the option created with 200 | // 201 | // StringLong("option", 'o', "defval", "a string of letters") 202 | // 203 | // is 204 | // 205 | // -o, -option=value 206 | // 207 | // StringLong("option", 'o', "defval", "a string of letters", "string") 208 | // 209 | // is 210 | // 211 | // -o, -option=string 212 | package getopt 213 | 214 | import ( 215 | "fmt" 216 | "io" 217 | "os" 218 | "path" 219 | "sort" 220 | "strings" 221 | ) 222 | 223 | // stderr allows tests to capture output to standard error. 224 | var stderr io.Writer = os.Stderr 225 | 226 | // exit allows tests to capture an os.Exit call 227 | var exit = os.Exit 228 | 229 | // DisplayWidth is used to determine where to split usage long lines. 230 | var DisplayWidth = 80 231 | 232 | // HelpColumn is the maximum column position that help strings start to display 233 | // at. If the option usage is too long then the help string will be displayed 234 | // on the next line. For example: 235 | // 236 | // -a this is the a flag 237 | // -u, --under=location 238 | // the u flag's usage is quite long 239 | var HelpColumn = 20 240 | 241 | // PrintUsage prints the usage of the program to w. 242 | func (s *Set) PrintUsage(w io.Writer) { 243 | sort.Sort(s.options) 244 | flags := "" 245 | 246 | // Build up the list of short flag names and also compute 247 | // how to display the option in the longer help listing. 248 | // We also keep track of the longest option usage string 249 | // that is no more than HelpColumn-3 bytes (at which point 250 | // we use two lines to display the help). The three 251 | // is for the leading space and the two spaces before the 252 | // help string. 253 | for _, opt := range s.options { 254 | if opt.name == "" { 255 | opt.name = "value" 256 | } 257 | if opt.uname == "" { 258 | opt.uname = opt.usageName() 259 | } 260 | if opt.flag && opt.short != 0 && opt.short != '-' { 261 | flags += string(opt.short) 262 | } 263 | } 264 | 265 | var opts []string 266 | 267 | // The short option - is special 268 | if s.shortOptions['-'] != nil { 269 | opts = append(opts, "-") 270 | } 271 | 272 | // If we have a bundle of flags, add them to the list 273 | if flags != "" { 274 | opts = append(opts, "-"+flags) 275 | } 276 | 277 | // Now append all the long options and options that require 278 | // values. 279 | for _, opt := range s.options { 280 | if opt.flag { 281 | if opt.short != 0 { 282 | continue 283 | } 284 | flags = "--" + opt.long 285 | } else if opt.short != 0 { 286 | flags = "-" + string(opt.short) + " " + opt.name 287 | } else { 288 | flags = "--" + string(opt.long) + " " + opt.name 289 | } 290 | opts = append(opts, flags) 291 | } 292 | flags = strings.Join(opts, "] [") 293 | if flags != "" { 294 | flags = " [" + flags + "]" 295 | } 296 | if s.parameters != "" { 297 | flags += " " + s.parameters 298 | } 299 | fmt.Fprintf(w, "Usage: %s%s\n", s.program, flags) 300 | s.PrintOptions(w) 301 | } 302 | 303 | // PrintOptions prints the list of options in s to w. 304 | func (s *Set) PrintOptions(w io.Writer) { 305 | sort.Sort(s.options) 306 | max := 4 307 | for _, opt := range s.options { 308 | if opt.name == "" { 309 | opt.name = "value" 310 | } 311 | if opt.uname == "" { 312 | opt.uname = opt.usageName() 313 | } 314 | if max < len(opt.uname) && len(opt.uname) <= HelpColumn-3 { 315 | max = len(opt.uname) 316 | } 317 | } 318 | // Now print one or more usage lines per option. 319 | for _, opt := range s.options { 320 | if opt.uname != "" { 321 | opt.help = strings.TrimSpace(opt.help) 322 | if len(opt.help) == 0 { 323 | fmt.Fprintf(w, " %s\n", opt.uname) 324 | continue 325 | } 326 | help := strings.Split(opt.help, "\n") 327 | // If they did not put in newlines then we will insert 328 | // them to keep the help messages from wrapping. 329 | if len(help) == 1 { 330 | help = breakup(help[0], DisplayWidth-HelpColumn) 331 | } 332 | if len(opt.uname) <= max { 333 | fmt.Fprintf(w, " %-*s %s\n", max, opt.uname, help[0]) 334 | help = help[1:] 335 | } else { 336 | fmt.Fprintf(w, " %s\n", opt.uname) 337 | } 338 | for _, s := range help { 339 | fmt.Fprintf(w, " %-*s %s\n", max, " ", s) 340 | } 341 | } 342 | } 343 | } 344 | 345 | // breakup breaks s up into strings no longer than max bytes. 346 | func breakup(s string, max int) []string { 347 | var a []string 348 | 349 | for { 350 | // strip leading spaces 351 | for len(s) > 0 && s[0] == ' ' { 352 | s = s[1:] 353 | } 354 | // If the option is no longer than the max just return it 355 | if len(s) <= max { 356 | if len(s) != 0 { 357 | a = append(a, s) 358 | } 359 | return a 360 | } 361 | x := max 362 | for s[x] != ' ' { 363 | // the first word is too long?! 364 | if x == 0 { 365 | x = max 366 | for x < len(s) && s[x] != ' ' { 367 | x++ 368 | } 369 | if x == len(s) { 370 | x-- 371 | } 372 | break 373 | } 374 | x-- 375 | } 376 | for s[x] == ' ' { 377 | x-- 378 | } 379 | a = append(a, s[:x+1]) 380 | s = s[x+1:] 381 | } 382 | } 383 | 384 | // Parse uses Getopt to parse args using the options set for s. The first 385 | // element of args is used to assign the program for s if it is not yet set. On 386 | // error, Parse displays the error message as well as a usage message on 387 | // standard error and then exits the program. 388 | func (s *Set) Parse(args []string) { 389 | if err := s.Getopt(args, nil); err != nil { 390 | fmt.Fprintln(stderr, err) 391 | s.usage() 392 | exit(1) 393 | } 394 | } 395 | 396 | // Parse uses Getopt to parse args using the options set for s. The first 397 | // element of args is used to assign the program for s if it is not yet set. 398 | // Getop calls fn, if not nil, for each option parsed. 399 | // 400 | // Getopt returns nil when all options have been processed (a non-option 401 | // argument was encountered, "--" was encountered, or fn returned false). 402 | // 403 | // On error getopt returns a reference to an InvalidOption (which implements 404 | // the error interface). 405 | func (s *Set) Getopt(args []string, fn func(Option) bool) (err error) { 406 | s.State = InProgress 407 | defer func() { 408 | if s.State == InProgress { 409 | switch { 410 | case err != nil: 411 | s.State = Failure 412 | case len(s.args) == 0: 413 | s.State = EndOfArguments 414 | default: 415 | s.State = Unknown 416 | } 417 | } 418 | }() 419 | if fn == nil { 420 | fn = func(Option) bool { return true } 421 | } 422 | if len(args) == 0 { 423 | return nil 424 | } 425 | 426 | if s.program == "" { 427 | s.program = path.Base(args[0]) 428 | } 429 | args = args[1:] 430 | Parsing: 431 | for len(args) > 0 { 432 | arg := args[0] 433 | s.args = args 434 | args = args[1:] 435 | 436 | // end of options? 437 | if arg == "" || arg[0] != '-' { 438 | s.State = EndOfOptions 439 | return nil 440 | } 441 | 442 | if arg == "-" { 443 | goto ShortParsing 444 | } 445 | 446 | // explicitly request end of options? 447 | if arg == "--" { 448 | s.args = args 449 | s.State = DashDash 450 | return nil 451 | } 452 | 453 | // Long option processing 454 | if len(s.longOptions) > 0 && arg[1] == '-' { 455 | e := strings.IndexRune(arg, '=') 456 | var value string 457 | if e > 0 { 458 | value = arg[e+1:] 459 | arg = arg[:e] 460 | } 461 | opt := s.longOptions[arg[2:]] 462 | // If we are processing long options then --f is -f 463 | // if f is not defined as a long option. 464 | // This lets you say --f=false 465 | if opt == nil && len(arg[2:]) == 1 { 466 | opt = s.shortOptions[rune(arg[2])] 467 | } 468 | if opt == nil { 469 | return unknownOption(arg[2:]) 470 | } 471 | opt.isLong = true 472 | // If we require an option and did not have an = 473 | // then use the next argument as an option. 474 | if !opt.flag && e < 0 && !opt.optional { 475 | if len(args) == 0 { 476 | return missingArg(opt) 477 | } 478 | value = args[0] 479 | args = args[1:] 480 | } 481 | opt.count++ 482 | 483 | if err := opt.value.Set(value, opt); err != nil { 484 | return setError(opt, value, err) 485 | } 486 | 487 | if !fn(opt) { 488 | s.State = Terminated 489 | return nil 490 | } 491 | continue Parsing 492 | } 493 | 494 | // Short option processing 495 | arg = arg[1:] // strip - 496 | ShortParsing: 497 | for i, c := range arg { 498 | opt := s.shortOptions[c] 499 | if opt == nil { 500 | // In traditional getopt, if - is not registered 501 | // as an option, a lone - is treated as 502 | // if there were a -- in front of it. 503 | if arg == "-" { 504 | s.State = Dash 505 | return nil 506 | } 507 | return unknownOption(c) 508 | } 509 | opt.isLong = false 510 | opt.count++ 511 | var value string 512 | if !opt.flag { 513 | value = arg[1+i:] 514 | if value == "" && !opt.optional { 515 | if len(args) == 0 { 516 | return missingArg(opt) 517 | } 518 | value = args[0] 519 | args = args[1:] 520 | } 521 | } 522 | if err := opt.value.Set(value, opt); err != nil { 523 | return setError(opt, value, err) 524 | } 525 | if !fn(opt) { 526 | s.State = Terminated 527 | return nil 528 | } 529 | if !opt.flag { 530 | continue Parsing 531 | } 532 | } 533 | } 534 | s.args = []string{} 535 | return nil 536 | } 537 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | --------------------------------------------------------------------------------