Quellcode durchsuchen

Finished poller

Brendan Abolivier vor 6 Jahren
Ursprung
Commit
71a03f599d
Signiert von: Brendan Abolivier <contact@brendanabolivier.com> GPG Schlüssel ID: 8EF1500759F70623
100 geänderte Dateien mit 18951 neuen und 2 gelöschten Zeilen
  1. 116
    0
      src/git/git.go
  2. 5
    0
      src/grafana/client.go
  3. 35
    2
      src/grafana/dashboards.go
  4. 165
    0
      src/puller/main.go
  5. 45
    0
      src/puller/versions.go
  6. 127
    0
      vendor/manifest
  7. 21
    0
      vendor/src/github.com/alcortesm/tgz/LICENSE
  8. 41
    0
      vendor/src/github.com/alcortesm/tgz/README.md
  9. BIN
      vendor/src/github.com/alcortesm/tgz/fixtures/invalid-gzip.tgz
  10. BIN
      vendor/src/github.com/alcortesm/tgz/fixtures/not-a-tar.tgz
  11. BIN
      vendor/src/github.com/alcortesm/tgz/fixtures/test-01.tgz
  12. BIN
      vendor/src/github.com/alcortesm/tgz/fixtures/test-02.tgz
  13. BIN
      vendor/src/github.com/alcortesm/tgz/fixtures/test-03.tgz
  14. 121
    0
      vendor/src/github.com/alcortesm/tgz/tgz.go
  15. 135
    0
      vendor/src/github.com/alcortesm/tgz/tgz_test.go
  16. 120
    0
      vendor/src/github.com/jbenet/go-context/io/ctxio.go
  17. 273
    0
      vendor/src/github.com/jbenet/go-context/io/ctxio_test.go
  18. 26
    0
      vendor/src/github.com/jessevdk/go-flags/LICENSE
  19. 134
    0
      vendor/src/github.com/jessevdk/go-flags/README.md
  20. 27
    0
      vendor/src/github.com/jessevdk/go-flags/arg.go
  21. 163
    0
      vendor/src/github.com/jessevdk/go-flags/arg_test.go
  22. 177
    0
      vendor/src/github.com/jessevdk/go-flags/assert_test.go
  23. 16
    0
      vendor/src/github.com/jessevdk/go-flags/check_crosscompile.sh
  24. 59
    0
      vendor/src/github.com/jessevdk/go-flags/closest.go
  25. 465
    0
      vendor/src/github.com/jessevdk/go-flags/command.go
  26. 582
    0
      vendor/src/github.com/jessevdk/go-flags/command_test.go
  27. 309
    0
      vendor/src/github.com/jessevdk/go-flags/completion.go
  28. 315
    0
      vendor/src/github.com/jessevdk/go-flags/completion_test.go
  29. 348
    0
      vendor/src/github.com/jessevdk/go-flags/convert.go
  30. 159
    0
      vendor/src/github.com/jessevdk/go-flags/convert_test.go
  31. 134
    0
      vendor/src/github.com/jessevdk/go-flags/error.go
  32. 110
    0
      vendor/src/github.com/jessevdk/go-flags/example_test.go
  33. 23
    0
      vendor/src/github.com/jessevdk/go-flags/examples/add.go
  34. 9
    0
      vendor/src/github.com/jessevdk/go-flags/examples/bash-completion
  35. 79
    0
      vendor/src/github.com/jessevdk/go-flags/examples/main.go
  36. 23
    0
      vendor/src/github.com/jessevdk/go-flags/examples/rm.go
  37. 258
    0
      vendor/src/github.com/jessevdk/go-flags/flags.go
  38. 406
    0
      vendor/src/github.com/jessevdk/go-flags/group.go
  39. 255
    0
      vendor/src/github.com/jessevdk/go-flags/group_test.go
  40. 491
    0
      vendor/src/github.com/jessevdk/go-flags/help.go
  41. 538
    0
      vendor/src/github.com/jessevdk/go-flags/help_test.go
  42. 597
    0
      vendor/src/github.com/jessevdk/go-flags/ini.go
  43. 1053
    0
      vendor/src/github.com/jessevdk/go-flags/ini_test.go
  44. 85
    0
      vendor/src/github.com/jessevdk/go-flags/long_test.go
  45. 205
    0
      vendor/src/github.com/jessevdk/go-flags/man.go
  46. 119
    0
      vendor/src/github.com/jessevdk/go-flags/marshal_test.go
  47. 140
    0
      vendor/src/github.com/jessevdk/go-flags/multitag.go
  48. 461
    0
      vendor/src/github.com/jessevdk/go-flags/option.go
  49. 45
    0
      vendor/src/github.com/jessevdk/go-flags/options_test.go
  50. 67
    0
      vendor/src/github.com/jessevdk/go-flags/optstyle_other.go
  51. 108
    0
      vendor/src/github.com/jessevdk/go-flags/optstyle_windows.go
  52. 700
    0
      vendor/src/github.com/jessevdk/go-flags/parser.go
  53. 612
    0
      vendor/src/github.com/jessevdk/go-flags/parser_test.go
  54. 164
    0
      vendor/src/github.com/jessevdk/go-flags/pointer_test.go
  55. 234
    0
      vendor/src/github.com/jessevdk/go-flags/short_test.go
  56. 38
    0
      vendor/src/github.com/jessevdk/go-flags/tag_test.go
  57. 28
    0
      vendor/src/github.com/jessevdk/go-flags/termsize.go
  58. 7
    0
      vendor/src/github.com/jessevdk/go-flags/termsize_nosysioctl.go
  59. 7
    0
      vendor/src/github.com/jessevdk/go-flags/tiocgwinsz_bsdish.go
  60. 7
    0
      vendor/src/github.com/jessevdk/go-flags/tiocgwinsz_linux.go
  61. 7
    0
      vendor/src/github.com/jessevdk/go-flags/tiocgwinsz_other.go
  62. 66
    0
      vendor/src/github.com/jessevdk/go-flags/unknown_test.go
  63. 21
    0
      vendor/src/github.com/mitchellh/go-homedir/LICENSE
  64. 14
    0
      vendor/src/github.com/mitchellh/go-homedir/README.md
  65. 137
    0
      vendor/src/github.com/mitchellh/go-homedir/homedir.go
  66. 112
    0
      vendor/src/github.com/mitchellh/go-homedir/homedir_test.go
  67. 28
    0
      vendor/src/github.com/sergi/go-diff/diffmatchpatch/benchutil_test.go
  68. 1344
    0
      vendor/src/github.com/sergi/go-diff/diffmatchpatch/diff.go
  69. 1427
    0
      vendor/src/github.com/sergi/go-diff/diffmatchpatch/diff_test.go
  70. 46
    0
      vendor/src/github.com/sergi/go-diff/diffmatchpatch/diffmatchpatch.go
  71. 160
    0
      vendor/src/github.com/sergi/go-diff/diffmatchpatch/match.go
  72. 174
    0
      vendor/src/github.com/sergi/go-diff/diffmatchpatch/match_test.go
  73. 23
    0
      vendor/src/github.com/sergi/go-diff/diffmatchpatch/mathutil.go
  74. 556
    0
      vendor/src/github.com/sergi/go-diff/diffmatchpatch/patch.go
  75. 339
    0
      vendor/src/github.com/sergi/go-diff/diffmatchpatch/patch_test.go
  76. 88
    0
      vendor/src/github.com/sergi/go-diff/diffmatchpatch/stringutil.go
  77. 116
    0
      vendor/src/github.com/sergi/go-diff/diffmatchpatch/stringutil_test.go
  78. 28
    0
      vendor/src/github.com/src-d/gcfg/LICENSE
  79. 4
    0
      vendor/src/github.com/src-d/gcfg/README
  80. 145
    0
      vendor/src/github.com/src-d/gcfg/doc.go
  81. 41
    0
      vendor/src/github.com/src-d/gcfg/errors.go
  82. 132
    0
      vendor/src/github.com/src-d/gcfg/example_test.go
  83. 7
    0
      vendor/src/github.com/src-d/gcfg/go1_0.go
  84. 9
    0
      vendor/src/github.com/src-d/gcfg/go1_2.go
  85. 63
    0
      vendor/src/github.com/src-d/gcfg/issues_test.go
  86. 273
    0
      vendor/src/github.com/src-d/gcfg/read.go
  87. 474
    0
      vendor/src/github.com/src-d/gcfg/read_test.go
  88. 121
    0
      vendor/src/github.com/src-d/gcfg/scanner/errors.go
  89. 46
    0
      vendor/src/github.com/src-d/gcfg/scanner/example_test.go
  90. 342
    0
      vendor/src/github.com/src-d/gcfg/scanner/scanner.go
  91. 417
    0
      vendor/src/github.com/src-d/gcfg/scanner/scanner_test.go
  92. 332
    0
      vendor/src/github.com/src-d/gcfg/set.go
  93. 3
    0
      vendor/src/github.com/src-d/gcfg/testdata/gcfg_test.gcfg
  94. 3
    0
      vendor/src/github.com/src-d/gcfg/testdata/gcfg_unicode_test.gcfg
  95. 435
    0
      vendor/src/github.com/src-d/gcfg/token/position.go
  96. 181
    0
      vendor/src/github.com/src-d/gcfg/token/position_test.go
  97. 56
    0
      vendor/src/github.com/src-d/gcfg/token/serialize.go
  98. 111
    0
      vendor/src/github.com/src-d/gcfg/token/serialize_test.go
  99. 83
    0
      vendor/src/github.com/src-d/gcfg/token/token.go
  100. 0
    0
      vendor/src/github.com/src-d/gcfg/types/bool.go

+ 116
- 0
src/git/git.go Datei anzeigen

@@ -0,0 +1,116 @@
1
+package git
2
+
3
+import (
4
+	"io/ioutil"
5
+	"os"
6
+	"strings"
7
+	"time"
8
+
9
+	"gopkg.in/src-d/go-git.v4"
10
+	"gopkg.in/src-d/go-git.v4/plumbing"
11
+	"gopkg.in/src-d/go-git.v4/plumbing/object"
12
+
13
+	"golang.org/x/crypto/ssh"
14
+	gitssh "gopkg.in/src-d/go-git.v4/plumbing/transport/ssh"
15
+)
16
+
17
+func Sync(repo string, clonePath string, privateKeyPath string) (r *git.Repository, err error) {
18
+	auth, err := getAuth(privateKeyPath)
19
+	if err != nil {
20
+		return
21
+	}
22
+
23
+	exists, err := dirExists(clonePath)
24
+	if err != nil {
25
+		return
26
+	}
27
+
28
+	if exists {
29
+		r, err = pull(clonePath, auth)
30
+	} else {
31
+		r, err = clone(repo, clonePath, auth)
32
+	}
33
+
34
+	return
35
+}
36
+
37
+func getAuth(privateKeyPath string) (*gitssh.PublicKeys, error) {
38
+	privateKey, err := ioutil.ReadFile(privateKeyPath)
39
+	if err != nil {
40
+		return nil, err
41
+	}
42
+
43
+	signer, err := ssh.ParsePrivateKey(privateKey)
44
+	if err != nil {
45
+		return nil, err
46
+	}
47
+
48
+	return &gitssh.PublicKeys{User: "git", Signer: signer}, nil
49
+}
50
+
51
+func clone(repo string, clonePath string, auth *gitssh.PublicKeys) (*git.Repository, error) {
52
+	return git.PlainClone(clonePath, false, &git.CloneOptions{
53
+		URL:  repo,
54
+		Auth: auth,
55
+	})
56
+}
57
+
58
+func pull(clonePath string, auth *gitssh.PublicKeys) (*git.Repository, error) {
59
+	r, err := git.PlainOpen(clonePath)
60
+	if err != nil {
61
+		return nil, err
62
+	}
63
+
64
+	w, err := r.Worktree()
65
+	if err != nil {
66
+		return nil, err
67
+	}
68
+
69
+	err = w.Pull(&git.PullOptions{
70
+		RemoteName: "origin",
71
+		Auth:       auth,
72
+	})
73
+
74
+	if err == git.NoErrAlreadyUpToDate {
75
+		return r, nil
76
+	}
77
+
78
+	// go-git doesn't have an error variable for "non-fast-forward update", so
79
+	// this is the only way to detect it
80
+	if strings.HasPrefix("non-fast-forward update", err.Error()) {
81
+		return r, nil
82
+	}
83
+
84
+	return r, err
85
+}
86
+
87
+func dirExists(path string) (bool, error) {
88
+	_, err := os.Stat(path)
89
+
90
+	if os.IsNotExist(err) {
91
+		return false, nil
92
+	}
93
+
94
+	return true, err
95
+}
96
+
97
+func Commit(message string, w *git.Worktree) (plumbing.Hash, error) {
98
+	return w.Commit(message, &git.CommitOptions{
99
+		Author: &object.Signature{
100
+			Name:  "Grafana Dashboard Manager",
101
+			Email: "grafana@cozycloud.cc",
102
+			When:  time.Now(),
103
+		},
104
+	})
105
+}
106
+
107
+func Push(r *git.Repository, keyPath string) error {
108
+	auth, err := getAuth(keyPath)
109
+	if err != nil {
110
+		return err
111
+	}
112
+
113
+	return r.Push(&git.PushOptions{
114
+		Auth: auth,
115
+	})
116
+}

+ 5
- 0
src/grafana/client.go Datei anzeigen

@@ -5,6 +5,7 @@ import (
5 5
 	"fmt"
6 6
 	"io/ioutil"
7 7
 	"net/http"
8
+	"strings"
8 9
 )
9 10
 
10 11
 type Client struct {
@@ -14,6 +15,10 @@ type Client struct {
14 15
 }
15 16
 
16 17
 func NewClient(baseURL string, apiKey string) (c *Client) {
18
+	if strings.HasSuffix(baseURL, "/") {
19
+		baseURL = baseURL[:len(baseURL)-1]
20
+	}
21
+
17 22
 	return &Client{
18 23
 		BaseURL:    baseURL,
19 24
 		APIKey:     apiKey,

+ 35
- 2
src/grafana/dashboards.go Datei anzeigen

@@ -2,6 +2,7 @@ package grafana
2 2
 
3 3
 import (
4 4
 	"encoding/json"
5
+	// "fmt"
5 6
 )
6 7
 
7 8
 type dbSearchResponse struct {
@@ -13,6 +14,31 @@ type dbSearchResponse struct {
13 14
 	Starred bool     `json:"isStarred"`
14 15
 }
15 16
 
17
+type Dashboard struct {
18
+	RawJSON []byte
19
+	Slug    string
20
+	Version int
21
+}
22
+
23
+func (d *Dashboard) UnmarshalJSON(b []byte) (err error) {
24
+	var body struct {
25
+		Dashboard interface{} `json:"dashboard"`
26
+		Meta      struct {
27
+			Slug    string `json:"slug"`
28
+			Version int    `json:"version"`
29
+		} `json:"meta"`
30
+	}
31
+
32
+	if err = json.Unmarshal(b, &body); err != nil {
33
+		return
34
+	}
35
+	d.Slug = body.Meta.Slug
36
+	d.Version = body.Meta.Version
37
+	d.RawJSON, err = json.Marshal(body.Dashboard)
38
+
39
+	return
40
+}
41
+
16 42
 func (c *Client) GetDashboardsURIs() (URIs []string, err error) {
17 43
 	resp, err := c.request("GET", "search", nil)
18 44
 
@@ -29,6 +55,13 @@ func (c *Client) GetDashboardsURIs() (URIs []string, err error) {
29 55
 	return
30 56
 }
31 57
 
32
-func (c *Client) GetDashboardJSON(URI string) ([]byte, error) {
33
-	return c.request("GET", URI, nil)
58
+func (c *Client) GetDashboard(URI string) (db *Dashboard, err error) {
59
+	body, err := c.request("GET", "dashboards/"+URI, nil)
60
+	if err != nil {
61
+		return
62
+	}
63
+
64
+	db = new(Dashboard)
65
+	err = json.Unmarshal(body, db)
66
+	return
34 67
 }

+ 165
- 0
src/puller/main.go Datei anzeigen

@@ -0,0 +1,165 @@
1
+package main
2
+
3
+import (
4
+	"bytes"
5
+	"encoding/json"
6
+	"flag"
7
+	"fmt"
8
+	"io/ioutil"
9
+	"os"
10
+
11
+	"git"
12
+	"grafana"
13
+)
14
+
15
+type diffVersion struct {
16
+	oldVersion int
17
+	newVersion int
18
+}
19
+
20
+var (
21
+	grafanaURL     = flag.String("grafana-url", "", "Base URL of the Grafana instance")
22
+	grafanaAPIKey  = flag.String("api-key", "", "API key to use in authenticated requests")
23
+	clonePath      = flag.String("clone-path", "/tmp/grafana-dashboards", "Path to directory where the repo will be cloned")
24
+	repoURL        = flag.String("git-repo", "", "SSH URL for the Git repository, without the user part")
25
+	privateKeyPath = flag.String("private-key", "", "Path to the private key used to talk with the Git remote")
26
+)
27
+
28
+func main() {
29
+	dv := make(map[string]diffVersion)
30
+
31
+	flag.Parse()
32
+
33
+	if *grafanaURL == "" {
34
+		println("Error: No Grafana URL provided")
35
+		flag.Usage()
36
+		os.Exit(1)
37
+	}
38
+	if *grafanaAPIKey == "" {
39
+		println("Error: No Grafana API key provided")
40
+		flag.Usage()
41
+		os.Exit(1)
42
+	}
43
+	if *repoURL == "" {
44
+		println("Error: No Git repository provided")
45
+		flag.Usage()
46
+		os.Exit(1)
47
+	}
48
+	if *privateKeyPath == "" {
49
+		println("Error: No private key provided")
50
+		flag.Usage()
51
+		os.Exit(1)
52
+	}
53
+
54
+	dbVersions, err := getDashboardsVersions()
55
+	if err != nil {
56
+		panic(err)
57
+	}
58
+
59
+	repo, err := git.Sync(
60
+		*repoURL,
61
+		*clonePath,
62
+		*privateKeyPath,
63
+	)
64
+	if err != nil {
65
+		panic(err)
66
+	}
67
+
68
+	w, err := repo.Worktree()
69
+	if err != nil {
70
+		panic(err)
71
+	}
72
+
73
+	client := grafana.NewClient(*grafanaURL, *grafanaAPIKey)
74
+	uris, err := client.GetDashboardsURIs()
75
+	if err != nil {
76
+		panic(err)
77
+	}
78
+
79
+	for _, uri := range uris {
80
+		dashboard, err := client.GetDashboard(uri)
81
+		if err != nil {
82
+			panic(err)
83
+		}
84
+
85
+		version, ok := dbVersions[dashboard.Slug]
86
+		if !ok || dashboard.Version > version {
87
+			slugExt := dashboard.Slug + ".json"
88
+			if err = rewriteFile(
89
+				*clonePath+"/"+slugExt,
90
+				dashboard.RawJSON,
91
+			); err != nil {
92
+				panic(err)
93
+			}
94
+
95
+			if _, err = w.Add(slugExt); err != nil {
96
+				panic(err)
97
+			}
98
+
99
+			dv[dashboard.Slug] = diffVersion{
100
+				oldVersion: version,
101
+				newVersion: dashboard.Version,
102
+			}
103
+		}
104
+	}
105
+
106
+	status, err := w.Status()
107
+	if err != nil {
108
+		panic(err)
109
+	}
110
+
111
+	if !status.IsClean() {
112
+		if err = writeVersions(dbVersions, dv); err != nil {
113
+			panic(err)
114
+		}
115
+
116
+		if _, err = w.Add("versions.json"); err != nil {
117
+			panic(err)
118
+		}
119
+
120
+		if _, err = git.Commit(getCommitMessage(dv), w); err != nil {
121
+			panic(err)
122
+		}
123
+
124
+	}
125
+
126
+	if err = git.Push(repo, *privateKeyPath); err != nil {
127
+		panic(err)
128
+	}
129
+}
130
+
131
+func rewriteFile(filename string, content []byte) error {
132
+	if err := os.Remove(filename); err != nil {
133
+		pe, ok := err.(*os.PathError)
134
+		if !ok || pe.Err.Error() != "no such file or directory" {
135
+			return err
136
+		}
137
+	}
138
+
139
+	indentedContent, err := indent(content)
140
+	if err != nil {
141
+		return err
142
+	}
143
+
144
+	return ioutil.WriteFile(filename, indentedContent, 0644)
145
+}
146
+
147
+func indent(srcJSON []byte) (indentedJSON []byte, err error) {
148
+	buf := bytes.NewBuffer(nil)
149
+	if err = json.Indent(buf, srcJSON, "", "\t"); err != nil {
150
+		return
151
+	}
152
+
153
+	indentedJSON, err = ioutil.ReadAll(buf)
154
+	return
155
+}
156
+
157
+func getCommitMessage(dv map[string]diffVersion) string {
158
+	message := "Updated dashboards\n"
159
+
160
+	for slug, diff := range dv {
161
+		message += fmt.Sprintf("%s: %d => %d\n", slug, diff.oldVersion, diff.newVersion)
162
+	}
163
+
164
+	return message
165
+}

+ 45
- 0
src/puller/versions.go Datei anzeigen

@@ -0,0 +1,45 @@
1
+package main
2
+
3
+import (
4
+	"io/ioutil"
5
+	"os"
6
+	"encoding/json"
7
+)
8
+
9
+func getDashboardsVersions() (versions map[string]int, err error) {
10
+	versions = make(map[string]int)
11
+
12
+	filename := *clonePath + "/versions.json"
13
+
14
+	_, err = os.Stat(filename)
15
+	if os.IsNotExist(err) {
16
+		return versions, nil
17
+	}
18
+
19
+	data, err := ioutil.ReadFile(filename)
20
+	if err != nil {
21
+		return
22
+	}
23
+
24
+	err = json.Unmarshal(data, &versions)
25
+	return
26
+}
27
+
28
+func writeVersions(versions map[string]int, dv map[string]diffVersion) (err error) {
29
+	for slug, diff := range dv {
30
+		versions[slug] = diff.newVersion
31
+	}
32
+
33
+	rawJSON, err := json.Marshal(versions)
34
+	if err != nil {
35
+		return
36
+	}
37
+
38
+	indentedJSON, err := indent(rawJSON)
39
+	if err != nil {
40
+		return
41
+	}
42
+
43
+	filename := *clonePath + "/versions.json"
44
+	return rewriteFile(filename, indentedJSON)
45
+}

+ 127
- 0
vendor/manifest Datei anzeigen

@@ -0,0 +1,127 @@
1
+{
2
+	"version": 0,
3
+	"dependencies": [
4
+		{
5
+			"importpath": "github.com/alcortesm/tgz",
6
+			"repository": "https://github.com/alcortesm/tgz",
7
+			"revision": "9c5fe88206d7765837fed3732a42ef88fc51f1a1",
8
+			"branch": "master"
9
+		},
10
+		{
11
+			"importpath": "github.com/jbenet/go-context/io",
12
+			"repository": "https://github.com/jbenet/go-context",
13
+			"revision": "d14ea06fba99483203c19d92cfcd13ebe73135f4",
14
+			"branch": "master",
15
+			"path": "/io"
16
+		},
17
+		{
18
+			"importpath": "github.com/jessevdk/go-flags",
19
+			"repository": "https://github.com/jessevdk/go-flags",
20
+			"revision": "f88afde2fa19a30cf50ba4b05b3d13bc6bae3079",
21
+			"branch": "master"
22
+		},
23
+		{
24
+			"importpath": "github.com/mitchellh/go-homedir",
25
+			"repository": "https://github.com/mitchellh/go-homedir",
26
+			"revision": "b8bc1bf767474819792c23f32d8286a45736f1c6",
27
+			"branch": "master"
28
+		},
29
+		{
30
+			"importpath": "github.com/sergi/go-diff/diffmatchpatch",
31
+			"repository": "https://github.com/sergi/go-diff",
32
+			"revision": "1744e2970ca51c86172c8190fadad617561ed6e7",
33
+			"branch": "master",
34
+			"path": "/diffmatchpatch"
35
+		},
36
+		{
37
+			"importpath": "github.com/src-d/gcfg",
38
+			"repository": "https://github.com/src-d/gcfg",
39
+			"revision": "f187355171c936ac84a82793659ebb4936bc1c23",
40
+			"branch": "v1"
41
+		},
42
+		{
43
+			"importpath": "github.com/src-d/go-git-fixtures",
44
+			"repository": "https://github.com/src-d/go-git-fixtures",
45
+			"revision": "a29d269c3be65e4d1b20c29133c74e0551e1aa5d",
46
+			"branch": "master"
47
+		},
48
+		{
49
+			"importpath": "github.com/xanzy/ssh-agent",
50
+			"repository": "https://github.com/xanzy/ssh-agent",
51
+			"revision": "ba9c9e33906f58169366275e3450db66139a31a9",
52
+			"branch": "master"
53
+		},
54
+		{
55
+			"importpath": "golang.org/x/crypto/curve25519",
56
+			"repository": "https://go.googlesource.com/crypto",
57
+			"revision": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8",
58
+			"branch": "master",
59
+			"path": "/curve25519"
60
+		},
61
+		{
62
+			"importpath": "golang.org/x/crypto/ed25519",
63
+			"repository": "https://go.googlesource.com/crypto",
64
+			"revision": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8",
65
+			"branch": "master",
66
+			"path": "/ed25519"
67
+		},
68
+		{
69
+			"importpath": "golang.org/x/crypto/ssh",
70
+			"repository": "https://go.googlesource.com/crypto",
71
+			"revision": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8",
72
+			"branch": "master",
73
+			"path": "/ssh"
74
+		},
75
+		{
76
+			"importpath": "golang.org/x/net/context",
77
+			"repository": "https://go.googlesource.com/net",
78
+			"revision": "d866cfc389cec985d6fda2859936a575a55a3ab6",
79
+			"branch": "master",
80
+			"path": "/context"
81
+		},
82
+		{
83
+			"importpath": "golang.org/x/text/transform",
84
+			"repository": "https://go.googlesource.com/text",
85
+			"revision": "e19ae1496984b1c655b8044a65c0300a3c878dd3",
86
+			"branch": "master",
87
+			"path": "/transform"
88
+		},
89
+		{
90
+			"importpath": "golang.org/x/text/unicode/norm",
91
+			"repository": "https://go.googlesource.com/text",
92
+			"revision": "e19ae1496984b1c655b8044a65c0300a3c878dd3",
93
+			"branch": "master",
94
+			"path": "/unicode/norm"
95
+		},
96
+		{
97
+			"importpath": "gopkg.in/check.v1",
98
+			"repository": "https://gopkg.in/check.v1",
99
+			"revision": "20d25e2804050c1cd24a7eea1e7a6447dd0e74ec",
100
+			"branch": "v1"
101
+		},
102
+		{
103
+			"importpath": "gopkg.in/src-d/go-billy.v3",
104
+			"repository": "https://gopkg.in/src-d/go-billy.v3",
105
+			"revision": "c329b7bc7b9d24905d2bc1b85bfa29f7ae266314",
106
+			"branch": "master"
107
+		},
108
+		{
109
+			"importpath": "gopkg.in/src-d/go-billy.v4",
110
+			"repository": "https://gopkg.in/src-d/go-billy.v4",
111
+			"revision": "053dbd006f81a230434f712314aacfb540b52cc5",
112
+			"branch": "master"
113
+		},
114
+		{
115
+			"importpath": "gopkg.in/src-d/go-git.v4",
116
+			"repository": "https://gopkg.in/src-d/go-git.v4",
117
+			"revision": "f9879dd043f84936a1f8acb8a53b74332a7ae135",
118
+			"branch": "v4"
119
+		},
120
+		{
121
+			"importpath": "gopkg.in/warnings.v0",
122
+			"repository": "https://gopkg.in/warnings.v0",
123
+			"revision": "ec4a0fea49c7b46c2aeb0b51aac55779c607e52b",
124
+			"branch": "master"
125
+		}
126
+	]
127
+}

+ 21
- 0
vendor/src/github.com/alcortesm/tgz/LICENSE Datei anzeigen

@@ -0,0 +1,21 @@
1
+The MIT License (MIT)
2
+
3
+Copyright (c) 2016 Alberto Cortés
4
+
5
+Permission is hereby granted, free of charge, to any person obtaining a copy
6
+of this software and associated documentation files (the "Software"), to deal
7
+in the Software without restriction, including without limitation the rights
8
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+copies of the Software, and to permit persons to whom the Software is
10
+furnished to do so, subject to the following conditions:
11
+
12
+The above copyright notice and this permission notice shall be included in all
13
+copies or substantial portions of the Software.
14
+
15
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+SOFTWARE.

+ 41
- 0
vendor/src/github.com/alcortesm/tgz/README.md Datei anzeigen

@@ -0,0 +1,41 @@
1
+# tgz [![GoDoc](https://godoc.org/github.com/alcortesm/tgz?status.svg)](https://godoc.org/github.com/alcortesm/tgz) [![Build Status](https://travis-ci.org/alcortesm/tgz.svg)](https://travis-ci.org/alcortesm/tgz) [![codecov](https://codecov.io/gh/alcortesm/tgz/branch/master/graph/badge.svg)](https://codecov.io/gh/alcortesm/tgz)
2
+
3
+
4
+A Go library to extract tgz files to temporal directories.
5
+
6
+# Example
7
+
8
+The following program will decompress the file "/tmp/foo.tgz" to a temporal
9
+directory, print the names of all the files and directories in it and delete the
10
+temporal directory:
11
+
12
+```go
13
+package main
14
+
15
+import (
16
+	"fmt"
17
+	"io/ioutil"
18
+	"os"
19
+
20
+	"github.com/alcortesm/tgz"
21
+)
22
+
23
+func main() {
24
+	tmpPath, err := tgz.Extract("/tmp/foo.tgz")
25
+	if tmpPath != "" {
26
+		defer os.RemoveAll(tmpPath)
27
+	}
28
+	if err != nil {
29
+		panic(err)
30
+	}
31
+
32
+	infos, err := ioutil.ReadDir(tmpPath)
33
+	if err != nil {
34
+		panic(err)
35
+	}
36
+
37
+	for _, info := range infos {
38
+		fmt.Println(info.Name())
39
+	}
40
+}
41
+```

BIN
vendor/src/github.com/alcortesm/tgz/fixtures/invalid-gzip.tgz Datei anzeigen


BIN
vendor/src/github.com/alcortesm/tgz/fixtures/not-a-tar.tgz Datei anzeigen


BIN
vendor/src/github.com/alcortesm/tgz/fixtures/test-01.tgz Datei anzeigen


BIN
vendor/src/github.com/alcortesm/tgz/fixtures/test-02.tgz Datei anzeigen


BIN
vendor/src/github.com/alcortesm/tgz/fixtures/test-03.tgz Datei anzeigen


+ 121
- 0
vendor/src/github.com/alcortesm/tgz/tgz.go Datei anzeigen

@@ -0,0 +1,121 @@
1
+package tgz
2
+
3
+import (
4
+	"archive/tar"
5
+	"compress/gzip"
6
+	"fmt"
7
+	"io"
8
+	"io/ioutil"
9
+	"os"
10
+)
11
+
12
+const (
13
+	useDefaultTempDir = ""
14
+	tmpPrefix         = "tmp-tgz-"
15
+)
16
+
17
+// Extract decompress a gziped tarball into a new temporal directory
18
+// created just for this purpose.
19
+//
20
+// On success, the path of the newly created directory and a nil error
21
+// is returned.
22
+//
23
+// A non-nil error is returned if the method fails to complete. The
24
+// returned path will be an empty string if no information was extracted
25
+// before the error and the temporal directory has not been created.
26
+// Otherwise, a non-empty string with the temporal directory holding
27
+// whatever information was extracted before the error is returned.
28
+func Extract(tgz string) (d string, err error) {
29
+	f, err := os.Open(tgz)
30
+	if err != nil {
31
+		return "", err
32
+	}
33
+
34
+	defer func() {
35
+		errClose := f.Close()
36
+		if err == nil {
37
+			err = errClose
38
+		}
39
+	}()
40
+
41
+	d, err = ioutil.TempDir(useDefaultTempDir, tmpPrefix)
42
+	if err != nil {
43
+		return "", err
44
+	}
45
+
46
+	tar, err := zipTarReader(f)
47
+	if err != nil {
48
+		return d, err
49
+	}
50
+
51
+	if err = unTar(tar, d); err != nil {
52
+		return d, err
53
+	}
54
+
55
+	return d, nil
56
+}
57
+
58
+func zipTarReader(r io.Reader) (*tar.Reader, error) {
59
+	zip, err := gzip.NewReader(r)
60
+	if err != nil {
61
+		return nil, err
62
+	}
63
+
64
+	return tar.NewReader(zip), nil
65
+}
66
+
67
+func unTar(src *tar.Reader, dstPath string) error {
68
+	for {
69
+		header, err := src.Next()
70
+		if err != nil {
71
+			if err == io.EOF {
72
+				break
73
+			}
74
+			return err
75
+		}
76
+
77
+		dst := dstPath + "/" + header.Name
78
+		mode := os.FileMode(header.Mode)
79
+		switch header.Typeflag {
80
+		case tar.TypeDir:
81
+			err := os.MkdirAll(dst, mode)
82
+			if err != nil {
83
+				return err
84
+			}
85
+		case tar.TypeReg:
86
+			err := makeFile(dst, mode, src)
87
+			if err != nil {
88
+				return err
89
+			}
90
+		default:
91
+			return fmt.Errorf("Unable to untar type : %c in file %s",
92
+				header.Typeflag, header.Name)
93
+		}
94
+	}
95
+
96
+	return nil
97
+}
98
+
99
+func makeFile(path string, mode os.FileMode, contents io.Reader) (err error) {
100
+	w, err := os.Create(path)
101
+	if err != nil {
102
+		return err
103
+	}
104
+	defer func() {
105
+		errClose := w.Close()
106
+		if err == nil {
107
+			err = errClose
108
+		}
109
+	}()
110
+
111
+	_, err = io.Copy(w, contents)
112
+	if err != nil {
113
+		return err
114
+	}
115
+
116
+	if err = os.Chmod(path, mode); err != nil {
117
+		return err
118
+	}
119
+
120
+	return nil
121
+}

+ 135
- 0
vendor/src/github.com/alcortesm/tgz/tgz_test.go Datei anzeigen

@@ -0,0 +1,135 @@
1
+package tgz
2
+
3
+import (
4
+	"fmt"
5
+	"os"
6
+	"path/filepath"
7
+	"reflect"
8
+	"regexp"
9
+	"sort"
10
+	"testing"
11
+)
12
+
13
+func TestExtractError(t *testing.T) {
14
+	for i, test := range [...]struct {
15
+		tgz    string
16
+		errRgx *regexp.Regexp
17
+	}{
18
+		{
19
+			tgz:    "not-found",
20
+			errRgx: regexp.MustCompile("open not-found: no such file .*"),
21
+		}, {
22
+			tgz:    "fixtures/invalid-gzip.tgz",
23
+			errRgx: regexp.MustCompile("gzip: invalid header"),
24
+		}, {
25
+			tgz:    "fixtures/not-a-tar.tgz",
26
+			errRgx: regexp.MustCompile("unexpected EOF"),
27
+		},
28
+	} {
29
+		com := fmt.Sprintf("%d) tgz path = %s", i, test.tgz)
30
+		path, err := Extract(test.tgz)
31
+		if err == nil {
32
+			t.Errorf("%s: expect an error, but none was returned", com)
33
+		} else if errorNotMatch(err, test.errRgx) {
34
+			t.Errorf("%s:\n\treceived error: %s\n\texpected regexp: %s\n",
35
+				com, err, test.errRgx)
36
+		}
37
+
38
+		if path != "" {
39
+			if err = os.RemoveAll(path); err != nil {
40
+				t.Fatalf("%s: cannot remove temp directory: %s", com, err)
41
+			}
42
+		}
43
+	}
44
+}
45
+
46
+func errorNotMatch(err error, regexp *regexp.Regexp) bool {
47
+	return !regexp.MatchString(err.Error())
48
+}
49
+
50
+func TestExtract(t *testing.T) {
51
+	for i, test := range [...]struct {
52
+		tgz  string
53
+		tree []string
54
+	}{
55
+		{
56
+			tgz: "fixtures/test-01.tgz",
57
+			tree: []string{
58
+				"foo.txt",
59
+			},
60
+		}, {
61
+			tgz: "fixtures/test-02.tgz",
62
+			tree: []string{
63
+				"baz.txt",
64
+				"bla.txt",
65
+				"foo.txt",
66
+			},
67
+		}, {
68
+			tgz: "fixtures/test-03.tgz",
69
+			tree: []string{
70
+				"bar",
71
+				"bar/baz.txt",
72
+				"bar/foo.txt",
73
+				"baz",
74
+				"baz/bar",
75
+				"baz/bar/foo.txt",
76
+				"baz/baz",
77
+				"baz/baz/baz",
78
+				"baz/baz/baz/foo.txt",
79
+				"foo.txt",
80
+			},
81
+		},
82
+	} {
83
+		com := fmt.Sprintf("%d) tgz path = %s", i, test.tgz)
84
+
85
+		path, err := Extract(test.tgz)
86
+		if err != nil {
87
+			t.Fatalf("%s: unexpected error extracting: %s", err)
88
+		}
89
+
90
+		obt, err := relativeTree(path)
91
+		if err != nil {
92
+			t.Errorf("%s: unexpected error calculating relative path: %s", com, err)
93
+		}
94
+
95
+		sort.Strings(test.tree)
96
+		if !reflect.DeepEqual(obt, test.tree) {
97
+			t.Fatalf("%s:\n\tobtained: %v\n\t expected: %v", com, obt, test.tree)
98
+		}
99
+
100
+		err = os.RemoveAll(path)
101
+		if err != nil {
102
+			t.Fatalf("%s: unexpected error removing temporal path: %s", com, err)
103
+		}
104
+	}
105
+}
106
+
107
+// relativeTree returns the list of relative paths to the files and
108
+// directories inside a given directory, recursively.
109
+func relativeTree(dir string) ([]string, error) {
110
+	dir = filepath.Clean(dir)
111
+
112
+	absPaths := []string{}
113
+	walkFn := func(path string, _ os.FileInfo, _ error) error {
114
+		absPaths = append(absPaths, path)
115
+		return nil
116
+	}
117
+
118
+	_ = filepath.Walk(dir, walkFn)
119
+
120
+	return toRelative(absPaths[1:], dir)
121
+}
122
+
123
+// toRelative returns the relative paths (form b) of the list of paths in l.
124
+func toRelative(l []string, b string) ([]string, error) {
125
+	r := []string{}
126
+	for _, p := range l {
127
+		rel, err := filepath.Rel(b, p)
128
+		if err != nil {
129
+			return nil, err
130
+		}
131
+		r = append(r, rel)
132
+	}
133
+
134
+	return r, nil
135
+}

+ 120
- 0
vendor/src/github.com/jbenet/go-context/io/ctxio.go Datei anzeigen

@@ -0,0 +1,120 @@
1
+// Package ctxio provides io.Reader and io.Writer wrappers that
2
+// respect context.Contexts. Use these at the interface between
3
+// your context code and your io.
4
+//
5
+// WARNING: read the code. see how writes and reads will continue
6
+// until you cancel the io. Maybe this package should provide
7
+// versions of io.ReadCloser and io.WriteCloser that automatically
8
+// call .Close when the context expires. But for now -- since in my
9
+// use cases I have long-lived connections with ephemeral io wrappers
10
+// -- this has yet to be a need.
11
+package ctxio
12
+
13
+import (
14
+	"io"
15
+
16
+	context "golang.org/x/net/context"
17
+)
18
+
19
+type ioret struct {
20
+	n   int
21
+	err error
22
+}
23
+
24
+type Writer interface {
25
+	io.Writer
26
+}
27
+
28
+type ctxWriter struct {
29
+	w   io.Writer
30
+	ctx context.Context
31
+}
32
+
33
+// NewWriter wraps a writer to make it respect given Context.
34
+// If there is a blocking write, the returned Writer will return
35
+// whenever the context is cancelled (the return values are n=0
36
+// and err=ctx.Err().)
37
+//
38
+// Note well: this wrapper DOES NOT ACTUALLY cancel the underlying
39
+// write-- there is no way to do that with the standard go io
40
+// interface. So the read and write _will_ happen or hang. So, use
41
+// this sparingly, make sure to cancel the read or write as necesary
42
+// (e.g. closing a connection whose context is up, etc.)
43
+//
44
+// Furthermore, in order to protect your memory from being read
45
+// _after_ you've cancelled the context, this io.Writer will
46
+// first make a **copy** of the buffer.
47
+func NewWriter(ctx context.Context, w io.Writer) *ctxWriter {
48
+	if ctx == nil {
49
+		ctx = context.Background()
50
+	}
51
+	return &ctxWriter{ctx: ctx, w: w}
52
+}
53
+
54
+func (w *ctxWriter) Write(buf []byte) (int, error) {
55
+	buf2 := make([]byte, len(buf))
56
+	copy(buf2, buf)
57
+
58
+	c := make(chan ioret, 1)
59
+
60
+	go func() {
61
+		n, err := w.w.Write(buf2)
62
+		c <- ioret{n, err}
63
+		close(c)
64
+	}()
65
+
66
+	select {
67
+	case r := <-c:
68
+		return r.n, r.err
69
+	case <-w.ctx.Done():
70
+		return 0, w.ctx.Err()
71
+	}
72
+}
73
+
74
+type Reader interface {
75
+	io.Reader
76
+}
77
+
78
+type ctxReader struct {
79
+	r   io.Reader
80
+	ctx context.Context
81
+}
82
+
83
+// NewReader wraps a reader to make it respect given Context.
84
+// If there is a blocking read, the returned Reader will return
85
+// whenever the context is cancelled (the return values are n=0
86
+// and err=ctx.Err().)
87
+//
88
+// Note well: this wrapper DOES NOT ACTUALLY cancel the underlying
89
+// write-- there is no way to do that with the standard go io
90
+// interface. So the read and write _will_ happen or hang. So, use
91
+// this sparingly, make sure to cancel the read or write as necesary
92
+// (e.g. closing a connection whose context is up, etc.)
93
+//
94
+// Furthermore, in order to protect your memory from being read
95
+// _before_ you've cancelled the context, this io.Reader will
96
+// allocate a buffer of the same size, and **copy** into the client's
97
+// if the read succeeds in time.
98
+func NewReader(ctx context.Context, r io.Reader) *ctxReader {
99
+	return &ctxReader{ctx: ctx, r: r}
100
+}
101
+
102
+func (r *ctxReader) Read(buf []byte) (int, error) {
103
+	buf2 := make([]byte, len(buf))
104
+
105
+	c := make(chan ioret, 1)
106
+
107
+	go func() {
108
+		n, err := r.r.Read(buf2)
109
+		c <- ioret{n, err}
110
+		close(c)
111
+	}()
112
+
113
+	select {
114
+	case ret := <-c:
115
+		copy(buf, buf2)
116
+		return ret.n, ret.err
117
+	case <-r.ctx.Done():
118
+		return 0, r.ctx.Err()
119
+	}
120
+}

+ 273
- 0
vendor/src/github.com/jbenet/go-context/io/ctxio_test.go Datei anzeigen

@@ -0,0 +1,273 @@
1
+package ctxio
2
+
3
+import (
4
+	"bytes"
5
+	"io"
6
+	"testing"
7
+	"time"
8
+
9
+	context "golang.org/x/net/context"
10
+)
11
+
12
+func TestReader(t *testing.T) {
13
+	buf := []byte("abcdef")
14
+	buf2 := make([]byte, 3)
15
+	r := NewReader(context.Background(), bytes.NewReader(buf))
16
+
17
+	// read first half
18
+	n, err := r.Read(buf2)
19
+	if n != 3 {
20
+		t.Error("n should be 3")
21
+	}
22
+	if err != nil {
23
+		t.Error("should have no error")
24
+	}
25
+	if string(buf2) != string(buf[:3]) {
26
+		t.Error("incorrect contents")
27
+	}
28
+
29
+	// read second half
30
+	n, err = r.Read(buf2)
31
+	if n != 3 {
32
+		t.Error("n should be 3")
33
+	}
34
+	if err != nil {
35
+		t.Error("should have no error")
36
+	}
37
+	if string(buf2) != string(buf[3:6]) {
38
+		t.Error("incorrect contents")
39
+	}
40
+
41
+	// read more.
42
+	n, err = r.Read(buf2)
43
+	if n != 0 {
44
+		t.Error("n should be 0", n)
45
+	}
46
+	if err != io.EOF {
47
+		t.Error("should be EOF", err)
48
+	}
49
+}
50
+
51
+func TestWriter(t *testing.T) {
52
+	var buf bytes.Buffer
53
+	w := NewWriter(context.Background(), &buf)
54
+
55
+	// write three
56
+	n, err := w.Write([]byte("abc"))
57
+	if n != 3 {
58
+		t.Error("n should be 3")
59
+	}
60
+	if err != nil {
61
+		t.Error("should have no error")
62
+	}
63
+	if string(buf.Bytes()) != string("abc") {
64
+		t.Error("incorrect contents")
65
+	}
66
+
67
+	// write three more
68
+	n, err = w.Write([]byte("def"))
69
+	if n != 3 {
70
+		t.Error("n should be 3")
71
+	}
72
+	if err != nil {
73
+		t.Error("should have no error")
74
+	}
75
+	if string(buf.Bytes()) != string("abcdef") {
76
+		t.Error("incorrect contents")
77
+	}
78
+}
79
+
80
+func TestReaderCancel(t *testing.T) {
81
+	ctx, cancel := context.WithCancel(context.Background())
82
+	piper, pipew := io.Pipe()
83
+	r := NewReader(ctx, piper)
84
+
85
+	buf := make([]byte, 10)
86
+	done := make(chan ioret)
87
+
88
+	go func() {
89
+		n, err := r.Read(buf)
90
+		done <- ioret{n, err}
91
+	}()
92
+
93
+	pipew.Write([]byte("abcdefghij"))
94
+
95
+	select {
96
+	case ret := <-done:
97
+		if ret.n != 10 {
98
+			t.Error("ret.n should be 10", ret.n)
99
+		}
100
+		if ret.err != nil {
101
+			t.Error("ret.err should be nil", ret.err)
102
+		}
103
+		if string(buf) != "abcdefghij" {
104
+			t.Error("read contents differ")
105
+		}
106
+	case <-time.After(20 * time.Millisecond):
107
+		t.Fatal("failed to read")
108
+	}
109
+
110
+	go func() {
111
+		n, err := r.Read(buf)
112
+		done <- ioret{n, err}
113
+	}()
114
+
115
+	cancel()
116
+
117
+	select {
118
+	case ret := <-done:
119
+		if ret.n != 0 {
120
+			t.Error("ret.n should be 0", ret.n)
121
+		}
122
+		if ret.err == nil {
123
+			t.Error("ret.err should be ctx error", ret.err)
124
+		}
125
+	case <-time.After(20 * time.Millisecond):
126
+		t.Fatal("failed to stop reading after cancel")
127
+	}
128
+}
129
+
130
+func TestWriterCancel(t *testing.T) {
131
+	ctx, cancel := context.WithCancel(context.Background())
132
+	piper, pipew := io.Pipe()
133
+	w := NewWriter(ctx, pipew)
134
+
135
+	buf := make([]byte, 10)
136
+	done := make(chan ioret)
137
+
138
+	go func() {
139
+		n, err := w.Write([]byte("abcdefghij"))
140
+		done <- ioret{n, err}
141
+	}()
142
+
143
+	piper.Read(buf)
144
+
145
+	select {
146
+	case ret := <-done:
147
+		if ret.n != 10 {
148
+			t.Error("ret.n should be 10", ret.n)
149
+		}
150
+		if ret.err != nil {
151
+			t.Error("ret.err should be nil", ret.err)
152
+		}
153
+		if string(buf) != "abcdefghij" {
154
+			t.Error("write contents differ")
155
+		}
156
+	case <-time.After(20 * time.Millisecond):
157
+		t.Fatal("failed to write")
158
+	}
159
+
160
+	go func() {
161
+		n, err := w.Write([]byte("abcdefghij"))
162
+		done <- ioret{n, err}
163
+	}()
164
+
165
+	cancel()
166
+
167
+	select {
168
+	case ret := <-done:
169
+		if ret.n != 0 {
170
+			t.Error("ret.n should be 0", ret.n)
171
+		}
172
+		if ret.err == nil {
173
+			t.Error("ret.err should be ctx error", ret.err)
174
+		}
175
+	case <-time.After(20 * time.Millisecond):
176
+		t.Fatal("failed to stop writing after cancel")
177
+	}
178
+}
179
+
180
+func TestReadPostCancel(t *testing.T) {
181
+	ctx, cancel := context.WithCancel(context.Background())
182
+	piper, pipew := io.Pipe()
183
+	r := NewReader(ctx, piper)
184
+
185
+	buf := make([]byte, 10)
186
+	done := make(chan ioret)
187
+
188
+	go func() {
189
+		n, err := r.Read(buf)
190
+		done <- ioret{n, err}
191
+	}()
192
+
193
+	cancel()
194
+
195
+	select {
196
+	case ret := <-done:
197
+		if ret.n != 0 {
198
+			t.Error("ret.n should be 0", ret.n)
199
+		}
200
+		if ret.err == nil {
201
+			t.Error("ret.err should be ctx error", ret.err)
202
+		}
203
+	case <-time.After(20 * time.Millisecond):
204
+		t.Fatal("failed to stop reading after cancel")
205
+	}
206
+
207
+	pipew.Write([]byte("abcdefghij"))
208
+
209
+	if !bytes.Equal(buf, make([]byte, len(buf))) {
210
+		t.Fatal("buffer should have not been written to")
211
+	}
212
+}
213
+
214
+func TestWritePostCancel(t *testing.T) {
215
+	ctx, cancel := context.WithCancel(context.Background())
216
+	piper, pipew := io.Pipe()
217
+	w := NewWriter(ctx, pipew)
218
+
219
+	buf := []byte("abcdefghij")
220
+	buf2 := make([]byte, 10)
221
+	done := make(chan ioret)
222
+
223
+	go func() {
224
+		n, err := w.Write(buf)
225
+		done <- ioret{n, err}
226
+	}()
227
+
228
+	piper.Read(buf2)
229
+
230
+	select {
231
+	case ret := <-done:
232
+		if ret.n != 10 {
233
+			t.Error("ret.n should be 10", ret.n)
234
+		}
235
+		if ret.err != nil {
236
+			t.Error("ret.err should be nil", ret.err)
237
+		}
238
+		if string(buf2) != "abcdefghij" {
239
+			t.Error("write contents differ")
240
+		}
241
+	case <-time.After(20 * time.Millisecond):
242
+		t.Fatal("failed to write")
243
+	}
244
+
245
+	go func() {
246
+		n, err := w.Write(buf)
247
+		done <- ioret{n, err}
248
+	}()
249
+
250
+	cancel()
251
+
252
+	select {
253
+	case ret := <-done:
254
+		if ret.n != 0 {
255
+			t.Error("ret.n should be 0", ret.n)
256
+		}
257
+		if ret.err == nil {
258
+			t.Error("ret.err should be ctx error", ret.err)
259
+		}
260
+	case <-time.After(20 * time.Millisecond):
261
+		t.Fatal("failed to stop writing after cancel")
262
+	}
263
+
264
+	copy(buf, []byte("aaaaaaaaaa"))
265
+
266
+	piper.Read(buf2)
267
+
268
+	if string(buf2) == "aaaaaaaaaa" {
269
+		t.Error("buffer was read from after ctx cancel")
270
+	} else if string(buf2) != "abcdefghij" {
271
+		t.Error("write contents differ from expected")
272
+	}
273
+}

+ 26
- 0
vendor/src/github.com/jessevdk/go-flags/LICENSE Datei anzeigen

@@ -0,0 +1,26 @@
1
+Copyright (c) 2012 Jesse van den Kieboom. All rights reserved.
2
+Redistribution and use in source and binary forms, with or without
3
+modification, are permitted provided that the following conditions are
4
+met:
5
+
6
+   * Redistributions of source code must retain the above copyright
7
+     notice, this list of conditions and the following disclaimer.
8
+   * Redistributions in binary form must reproduce the above
9
+     copyright notice, this list of conditions and the following disclaimer
10
+     in the documentation and/or other materials provided with the
11
+     distribution.
12
+   * Neither the name of Google Inc. nor the names of its
13
+     contributors may be used to endorse or promote products derived from
14
+     this software without specific prior written permission.
15
+
16
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 134
- 0
vendor/src/github.com/jessevdk/go-flags/README.md Datei anzeigen

@@ -0,0 +1,134 @@
1
+go-flags: a go library for parsing command line arguments
2
+=========================================================
3
+
4
+[![GoDoc](https://godoc.org/github.com/jessevdk/go-flags?status.png)](https://godoc.org/github.com/jessevdk/go-flags) [![Build Status](https://travis-ci.org/jessevdk/go-flags.svg?branch=master)](https://travis-ci.org/jessevdk/go-flags) [![Coverage Status](https://img.shields.io/coveralls/jessevdk/go-flags.svg)](https://coveralls.io/r/jessevdk/go-flags?branch=master)
5
+
6
+This library provides similar functionality to the builtin flag library of
7
+go, but provides much more functionality and nicer formatting. From the
8
+documentation:
9
+
10
+Package flags provides an extensive command line option parser.
11
+The flags package is similar in functionality to the go builtin flag package
12
+but provides more options and uses reflection to provide a convenient and
13
+succinct way of specifying command line options.
14
+
15
+Supported features:
16
+* Options with short names (-v)
17
+* Options with long names (--verbose)
18
+* Options with and without arguments (bool v.s. other type)
19
+* Options with optional arguments and default values
20
+* Multiple option groups each containing a set of options
21
+* Generate and print well-formatted help message
22
+* Passing remaining command line arguments after -- (optional)
23
+* Ignoring unknown command line options (optional)
24
+* Supports -I/usr/include -I=/usr/include -I /usr/include option argument specification
25
+* Supports multiple short options -aux
26
+* Supports all primitive go types (string, int{8..64}, uint{8..64}, float)
27
+* Supports same option multiple times (can store in slice or last option counts)
28
+* Supports maps
29
+* Supports function callbacks
30
+* Supports namespaces for (nested) option groups
31
+
32
+The flags package uses structs, reflection and struct field tags
33
+to allow users to specify command line options. This results in very simple
34
+and concise specification of your application options. For example:
35
+
36
+```go
37
+type Options struct {
38
+	Verbose []bool `short:"v" long:"verbose" description:"Show verbose debug information"`
39
+}
40
+```
41
+
42
+This specifies one option with a short name -v and a long name --verbose.
43
+When either -v or --verbose is found on the command line, a 'true' value
44
+will be appended to the Verbose field. e.g. when specifying -vvv, the
45
+resulting value of Verbose will be {[true, true, true]}.
46
+
47
+Example:
48
+--------
49
+```go
50
+var opts struct {
51
+	// Slice of bool will append 'true' each time the option
52
+	// is encountered (can be set multiple times, like -vvv)
53
+	Verbose []bool `short:"v" long:"verbose" description:"Show verbose debug information"`
54
+
55
+	// Example of automatic marshalling to desired type (uint)
56
+	Offset uint `long:"offset" description:"Offset"`
57
+
58
+	// Example of a callback, called each time the option is found.
59
+	Call func(string) `short:"c" description:"Call phone number"`
60
+
61
+	// Example of a required flag
62
+	Name string `short:"n" long:"name" description:"A name" required:"true"`
63
+
64
+	// Example of a value name
65
+	File string `short:"f" long:"file" description:"A file" value-name:"FILE"`
66
+
67
+	// Example of a pointer
68
+	Ptr *int `short:"p" description:"A pointer to an integer"`
69
+
70
+	// Example of a slice of strings
71
+	StringSlice []string `short:"s" description:"A slice of strings"`
72
+
73
+	// Example of a slice of pointers
74
+	PtrSlice []*string `long:"ptrslice" description:"A slice of pointers to string"`
75
+
76
+	// Example of a map
77
+	IntMap map[string]int `long:"intmap" description:"A map from string to int"`
78
+}
79
+
80
+// Callback which will invoke callto:<argument> to call a number.
81
+// Note that this works just on OS X (and probably only with
82
+// Skype) but it shows the idea.
83
+opts.Call = func(num string) {
84
+	cmd := exec.Command("open", "callto:"+num)
85
+	cmd.Start()
86
+	cmd.Process.Release()
87
+}
88
+
89
+// Make some fake arguments to parse.
90
+args := []string{
91
+	"-vv",
92
+	"--offset=5",
93
+	"-n", "Me",
94
+	"-p", "3",
95
+	"-s", "hello",
96
+	"-s", "world",
97
+	"--ptrslice", "hello",
98
+	"--ptrslice", "world",
99
+	"--intmap", "a:1",
100
+	"--intmap", "b:5",
101
+	"arg1",
102
+	"arg2",
103
+	"arg3",
104
+}
105
+
106
+// Parse flags from `args'. Note that here we use flags.ParseArgs for
107
+// the sake of making a working example. Normally, you would simply use
108
+// flags.Parse(&opts) which uses os.Args
109
+args, err := flags.ParseArgs(&opts, args)
110
+
111
+if err != nil {
112
+	panic(err)
113
+}
114
+
115
+fmt.Printf("Verbosity: %v\n", opts.Verbose)
116
+fmt.Printf("Offset: %d\n", opts.Offset)
117
+fmt.Printf("Name: %s\n", opts.Name)
118
+fmt.Printf("Ptr: %d\n", *opts.Ptr)
119
+fmt.Printf("StringSlice: %v\n", opts.StringSlice)
120
+fmt.Printf("PtrSlice: [%v %v]\n", *opts.PtrSlice[0], *opts.PtrSlice[1])
121
+fmt.Printf("IntMap: [a:%v b:%v]\n", opts.IntMap["a"], opts.IntMap["b"])
122
+fmt.Printf("Remaining args: %s\n", strings.Join(args, " "))
123
+
124
+// Output: Verbosity: [true true]
125
+// Offset: 5
126
+// Name: Me
127
+// Ptr: 3
128
+// StringSlice: [hello world]
129
+// PtrSlice: [hello world]
130
+// IntMap: [a:1 b:5]
131
+// Remaining args: arg1 arg2 arg3
132
+```
133
+
134
+More information can be found in the godocs: <http://godoc.org/github.com/jessevdk/go-flags>

+ 27
- 0
vendor/src/github.com/jessevdk/go-flags/arg.go Datei anzeigen

@@ -0,0 +1,27 @@
1
+package flags
2
+
3
+import (
4
+	"reflect"
5
+)
6
+
7
+// Arg represents a positional argument on the command line.
8
+type Arg struct {
9
+	// The name of the positional argument (used in the help)
10
+	Name string
11
+
12
+	// A description of the positional argument (used in the help)
13
+	Description string
14
+
15
+	// The minimal number of required positional arguments
16
+	Required int
17
+
18
+	// The maximum number of required positional arguments
19
+	RequiredMaximum int
20
+
21
+	value reflect.Value
22
+	tag   multiTag
23
+}
24
+
25
+func (a *Arg) isRemaining() bool {
26
+	return a.value.Type().Kind() == reflect.Slice
27
+}

+ 163
- 0
vendor/src/github.com/jessevdk/go-flags/arg_test.go Datei anzeigen

@@ -0,0 +1,163 @@
1
+package flags
2
+
3
+import (
4
+	"testing"
5
+)
6
+
7
+func TestPositional(t *testing.T) {
8
+	var opts = struct {
9
+		Value bool `short:"v"`
10
+
11
+		Positional struct {
12
+			Command  int
13
+			Filename string
14
+			Rest     []string
15
+		} `positional-args:"yes" required:"yes"`
16
+	}{}
17
+
18
+	p := NewParser(&opts, Default)
19
+	ret, err := p.ParseArgs([]string{"10", "arg_test.go", "a", "b"})
20
+
21
+	if err != nil {
22
+		t.Fatalf("Unexpected error: %v", err)
23
+		return
24
+	}
25
+
26
+	if opts.Positional.Command != 10 {
27
+		t.Fatalf("Expected opts.Positional.Command to be 10, but got %v", opts.Positional.Command)
28
+	}
29
+
30
+	if opts.Positional.Filename != "arg_test.go" {
31
+		t.Fatalf("Expected opts.Positional.Filename to be \"arg_test.go\", but got %v", opts.Positional.Filename)
32
+	}
33
+
34
+	assertStringArray(t, opts.Positional.Rest, []string{"a", "b"})
35
+	assertStringArray(t, ret, []string{})
36
+}
37
+
38
+func TestPositionalRequired(t *testing.T) {
39
+	var opts = struct {
40
+		Value bool `short:"v"`
41
+
42
+		Positional struct {
43
+			Command  int
44
+			Filename string
45
+			Rest     []string
46
+		} `positional-args:"yes" required:"yes"`
47
+	}{}
48
+
49
+	p := NewParser(&opts, None)
50
+	_, err := p.ParseArgs([]string{"10"})
51
+
52
+	assertError(t, err, ErrRequired, "the required argument `Filename` was not provided")
53
+}
54
+
55
+func TestPositionalRequiredRest1Fail(t *testing.T) {
56
+	var opts = struct {
57
+		Value bool `short:"v"`
58
+
59
+		Positional struct {
60
+			Rest []string `required:"yes"`
61
+		} `positional-args:"yes"`
62
+	}{}
63
+
64
+	p := NewParser(&opts, None)
65
+	_, err := p.ParseArgs([]string{})
66
+
67
+	assertError(t, err, ErrRequired, "the required argument `Rest (at least 1 argument)` was not provided")
68
+}
69
+
70
+func TestPositionalRequiredRest1Pass(t *testing.T) {
71
+	var opts = struct {
72
+		Value bool `short:"v"`
73
+
74
+		Positional struct {
75
+			Rest []string `required:"yes"`
76
+		} `positional-args:"yes"`
77
+	}{}
78
+
79
+	p := NewParser(&opts, None)
80
+	_, err := p.ParseArgs([]string{"rest1"})
81
+
82
+	if err != nil {
83
+		t.Fatalf("Unexpected error: %v", err)
84
+		return
85
+	}
86
+
87
+	if len(opts.Positional.Rest) != 1 {
88
+		t.Fatalf("Expected 1 positional rest argument")
89
+	}
90
+
91
+	assertString(t, opts.Positional.Rest[0], "rest1")
92
+}
93
+
94
+func TestPositionalRequiredRest2Fail(t *testing.T) {
95
+	var opts = struct {
96
+		Value bool `short:"v"`
97
+
98
+		Positional struct {
99
+			Rest []string `required:"2"`
100
+		} `positional-args:"yes"`
101
+	}{}
102
+
103
+	p := NewParser(&opts, None)
104
+	_, err := p.ParseArgs([]string{"rest1"})
105
+
106
+	assertError(t, err, ErrRequired, "the required argument `Rest (at least 2 arguments, but got only 1)` was not provided")
107
+}
108
+
109
+func TestPositionalRequiredRest2Pass(t *testing.T) {
110
+	var opts = struct {
111
+		Value bool `short:"v"`
112
+
113
+		Positional struct {
114
+			Rest []string `required:"2"`
115
+		} `positional-args:"yes"`
116
+	}{}
117
+
118
+	p := NewParser(&opts, None)
119
+	_, err := p.ParseArgs([]string{"rest1", "rest2", "rest3"})
120
+
121
+	if err != nil {
122
+		t.Fatalf("Unexpected error: %v", err)
123
+		return
124
+	}
125
+
126
+	if len(opts.Positional.Rest) != 3 {
127
+		t.Fatalf("Expected 3 positional rest argument")
128
+	}
129
+
130
+	assertString(t, opts.Positional.Rest[0], "rest1")
131
+	assertString(t, opts.Positional.Rest[1], "rest2")
132
+	assertString(t, opts.Positional.Rest[2], "rest3")
133
+}
134
+
135
+func TestPositionalRequiredRestRangeFail(t *testing.T) {
136
+	var opts = struct {
137
+		Value bool `short:"v"`
138
+
139
+		Positional struct {
140
+			Rest []string `required:"1-2"`
141
+		} `positional-args:"yes"`
142
+	}{}
143
+
144
+	p := NewParser(&opts, None)
145
+	_, err := p.ParseArgs([]string{"rest1", "rest2", "rest3"})
146
+
147
+	assertError(t, err, ErrRequired, "the required argument `Rest (at most 2 arguments, but got 3)` was not provided")
148
+}
149
+
150
+func TestPositionalRequiredRestRangeEmptyFail(t *testing.T) {
151
+	var opts = struct {
152
+		Value bool `short:"v"`
153
+
154
+		Positional struct {
155
+			Rest []string `required:"0-0"`
156
+		} `positional-args:"yes"`
157
+	}{}
158
+
159
+	p := NewParser(&opts, None)
160
+	_, err := p.ParseArgs([]string{"some", "thing"})
161
+
162
+	assertError(t, err, ErrRequired, "the required argument `Rest (zero arguments)` was not provided")
163
+}

+ 177
- 0
vendor/src/github.com/jessevdk/go-flags/assert_test.go Datei anzeigen

@@ -0,0 +1,177 @@
1
+package flags
2
+
3
+import (
4
+	"fmt"
5
+	"io"
6
+	"io/ioutil"
7
+	"os"
8
+	"os/exec"
9
+	"path"
10
+	"runtime"
11
+	"testing"
12
+)
13
+
14
+func assertCallerInfo() (string, int) {
15
+	ptr := make([]uintptr, 15)
16
+	n := runtime.Callers(1, ptr)
17
+
18
+	if n == 0 {
19
+		return "", 0
20
+	}
21
+
22
+	mef := runtime.FuncForPC(ptr[0])
23
+	mefile, meline := mef.FileLine(ptr[0])
24
+
25
+	for i := 2; i < n; i++ {
26
+		f := runtime.FuncForPC(ptr[i])
27
+		file, line := f.FileLine(ptr[i])
28
+
29
+		if file != mefile {
30
+			return file, line
31
+		}
32
+	}
33
+
34
+	return mefile, meline
35
+}
36
+
37
+func assertErrorf(t *testing.T, format string, args ...interface{}) {
38
+	msg := fmt.Sprintf(format, args...)
39
+
40
+	file, line := assertCallerInfo()
41
+
42
+	t.Errorf("%s:%d: %s", path.Base(file), line, msg)
43
+}
44
+
45
+func assertFatalf(t *testing.T, format string, args ...interface{}) {
46
+	msg := fmt.Sprintf(format, args...)
47
+
48
+	file, line := assertCallerInfo()
49
+
50
+	t.Fatalf("%s:%d: %s", path.Base(file), line, msg)
51
+}
52
+
53
+func assertString(t *testing.T, a string, b string) {
54
+	if a != b {
55
+		assertErrorf(t, "Expected %#v, but got %#v", b, a)
56
+	}
57
+}
58
+
59
+func assertStringArray(t *testing.T, a []string, b []string) {
60
+	if len(a) != len(b) {
61
+		assertErrorf(t, "Expected %#v, but got %#v", b, a)
62
+		return
63
+	}
64
+
65
+	for i, v := range a {
66
+		if b[i] != v {
67
+			assertErrorf(t, "Expected %#v, but got %#v", b, a)
68
+			return
69
+		}
70
+	}
71
+}
72
+
73
+func assertBoolArray(t *testing.T, a []bool, b []bool) {
74
+	if len(a) != len(b) {
75
+		assertErrorf(t, "Expected %#v, but got %#v", b, a)
76
+		return
77
+	}
78
+
79
+	for i, v := range a {
80
+		if b[i] != v {
81
+			assertErrorf(t, "Expected %#v, but got %#v", b, a)
82
+			return
83
+		}
84
+	}
85
+}
86
+
87
+func assertParserSuccess(t *testing.T, data interface{}, args ...string) (*Parser, []string) {
88
+	parser := NewParser(data, Default&^PrintErrors)
89
+	ret, err := parser.ParseArgs(args)
90
+
91
+	if err != nil {
92
+		t.Fatalf("Unexpected parse error: %s", err)
93
+		return nil, nil
94
+	}
95
+
96
+	return parser, ret
97
+}
98
+
99
+func assertParseSuccess(t *testing.T, data interface{}, args ...string) []string {
100
+	_, ret := assertParserSuccess(t, data, args...)
101
+	return ret
102
+}
103
+
104
+func assertError(t *testing.T, err error, typ ErrorType, msg string) {
105
+	if err == nil {
106
+		assertFatalf(t, "Expected error: %s", msg)
107
+		return
108
+	}
109
+
110
+	if e, ok := err.(*Error); !ok {
111
+		assertFatalf(t, "Expected Error type, but got %#v", err)
112
+	} else {
113
+		if e.Type != typ {
114
+			assertErrorf(t, "Expected error type {%s}, but got {%s}", typ, e.Type)
115
+		}
116
+
117
+		if e.Message != msg {
118
+			assertErrorf(t, "Expected error message %#v, but got %#v", msg, e.Message)
119
+		}
120
+	}
121
+}
122
+
123
+func assertParseFail(t *testing.T, typ ErrorType, msg string, data interface{}, args ...string) []string {
124
+	parser := NewParser(data, Default&^PrintErrors)
125
+	ret, err := parser.ParseArgs(args)
126
+
127
+	assertError(t, err, typ, msg)
128
+	return ret
129
+}
130
+
131
+func diff(a, b string) (string, error) {
132
+	atmp, err := ioutil.TempFile("", "help-diff")
133
+
134
+	if err != nil {
135
+		return "", err
136
+	}
137
+
138
+	btmp, err := ioutil.TempFile("", "help-diff")
139
+
140
+	if err != nil {
141
+		return "", err
142
+	}
143
+
144
+	if _, err := io.WriteString(atmp, a); err != nil {
145
+		return "", err
146
+	}
147
+
148
+	if _, err := io.WriteString(btmp, b); err != nil {
149
+		return "", err
150
+	}
151
+
152
+	ret, err := exec.Command("diff", "-u", "-d", "--label", "got", atmp.Name(), "--label", "expected", btmp.Name()).Output()
153
+
154
+	os.Remove(atmp.Name())
155
+	os.Remove(btmp.Name())
156
+
157
+	if err.Error() == "exit status 1" {
158
+		return string(ret), nil
159
+	}
160
+
161
+	return string(ret), err
162
+}
163
+
164
+func assertDiff(t *testing.T, actual, expected, msg string) {
165
+	if actual == expected {
166
+		return
167
+	}
168
+
169
+	ret, err := diff(actual, expected)
170
+
171
+	if err != nil {
172
+		assertErrorf(t, "Unexpected diff error: %s", err)
173
+		assertErrorf(t, "Unexpected %s, expected:\n\n%s\n\nbut got\n\n%s", msg, expected, actual)
174
+	} else {
175
+		assertErrorf(t, "Unexpected %s:\n\n%s", msg, ret)
176
+	}
177
+}

+ 16
- 0
vendor/src/github.com/jessevdk/go-flags/check_crosscompile.sh Datei anzeigen

@@ -0,0 +1,16 @@
1
+#!/bin/bash
2
+
3
+set -e
4
+
5
+echo '# linux arm7'
6
+GOARM=7 GOARCH=arm GOOS=linux go build
7
+echo '# linux arm5'
8
+GOARM=5 GOARCH=arm GOOS=linux go build
9
+echo '# windows 386'
10
+GOARCH=386 GOOS=windows go build
11
+echo '# windows amd64'
12
+GOARCH=amd64 GOOS=windows go build
13
+echo '# darwin'
14
+GOARCH=amd64 GOOS=darwin go build
15
+echo '# freebsd'
16
+GOARCH=amd64 GOOS=freebsd go build

+ 59
- 0
vendor/src/github.com/jessevdk/go-flags/closest.go Datei anzeigen

@@ -0,0 +1,59 @@
1
+package flags
2
+
3
+func levenshtein(s string, t string) int {
4
+	if len(s) == 0 {
5
+		return len(t)
6
+	}
7
+
8
+	if len(t) == 0 {
9
+		return len(s)
10
+	}
11
+
12
+	dists := make([][]int, len(s)+1)
13
+	for i := range dists {
14
+		dists[i] = make([]int, len(t)+1)
15
+		dists[i][0] = i
16
+	}
17
+
18
+	for j := range t {
19
+		dists[0][j] = j
20
+	}
21
+
22
+	for i, sc := range s {
23
+		for j, tc := range t {
24
+			if sc == tc {
25
+				dists[i+1][j+1] = dists[i][j]
26
+			} else {
27
+				dists[i+1][j+1] = dists[i][j] + 1
28
+				if dists[i+1][j] < dists[i+1][j+1] {
29
+					dists[i+1][j+1] = dists[i+1][j] + 1
30
+				}
31
+				if dists[i][j+1] < dists[i+1][j+1] {
32
+					dists[i+1][j+1] = dists[i][j+1] + 1
33
+				}
34
+			}
35
+		}
36
+	}
37
+
38
+	return dists[len(s)][len(t)]
39
+}
40
+
41
+func closestChoice(cmd string, choices []string) (string, int) {
42
+	if len(choices) == 0 {
43
+		return "", 0
44
+	}
45
+
46
+	mincmd := -1
47
+	mindist := -1
48
+
49
+	for i, c := range choices {
50
+		l := levenshtein(cmd, c)
51
+
52
+		if mincmd < 0 || l < mindist {
53
+			mindist = l
54
+			mincmd = i
55
+		}
56
+	}
57
+
58
+	return choices[mincmd], mindist
59
+}

+ 465
- 0
vendor/src/github.com/jessevdk/go-flags/command.go Datei anzeigen

@@ -0,0 +1,465 @@
1
+package flags
2
+
3
+import (
4
+	"reflect"
5
+	"sort"
6
+	"strconv"
7
+	"strings"
8
+)
9
+
10
+// Command represents an application command. Commands can be added to the
11
+// parser (which itself is a command) and are selected/executed when its name
12
+// is specified on the command line. The Command type embeds a Group and
13
+// therefore also carries a set of command specific options.
14
+type Command struct {
15
+	// Embedded, see Group for more information
16
+	*Group
17
+
18
+	// The name by which the command can be invoked
19
+	Name string
20
+
21
+	// The active sub command (set by parsing) or nil
22
+	Active *Command
23
+
24
+	// Whether subcommands are optional
25
+	SubcommandsOptional bool
26
+
27
+	// Aliases for the command
28
+	Aliases []string
29
+
30
+	// Whether positional arguments are required
31
+	ArgsRequired bool
32
+
33
+	commands            []*Command
34
+	hasBuiltinHelpGroup bool
35
+	args                []*Arg
36
+}
37
+
38
+// Commander is an interface which can be implemented by any command added in
39
+// the options. When implemented, the Execute method will be called for the last
40
+// specified (sub)command providing the remaining command line arguments.
41
+type Commander interface {
42
+	// Execute will be called for the last active (sub)command. The
43
+	// args argument contains the remaining command line arguments. The
44
+	// error that Execute returns will be eventually passed out of the
45
+	// Parse method of the Parser.
46
+	Execute(args []string) error
47
+}
48
+
49
+// Usage is an interface which can be implemented to show a custom usage string
50
+// in the help message shown for a command.
51
+type Usage interface {
52
+	// Usage is called for commands to allow customized printing of command
53
+	// usage in the generated help message.
54
+	Usage() string
55
+}
56
+
57
+type lookup struct {
58
+	shortNames map[string]*Option
59
+	longNames  map[string]*Option
60
+
61
+	commands map[string]*Command
62
+}
63
+
64
+// AddCommand adds a new command to the parser with the given name and data. The
65
+// data needs to be a pointer to a struct from which the fields indicate which
66
+// options are in the command. The provided data can implement the Command and
67
+// Usage interfaces.
68
+func (c *Command) AddCommand(command string, shortDescription string, longDescription string, data interface{}) (*Command, error) {
69
+	cmd := newCommand(command, shortDescription, longDescription, data)
70
+
71
+	cmd.parent = c
72
+
73
+	if err := cmd.scan(); err != nil {
74
+		return nil, err
75
+	}
76
+
77
+	c.commands = append(c.commands, cmd)
78
+	return cmd, nil
79
+}
80
+
81
+// AddGroup adds a new group to the command with the given name and data. The
82
+// data needs to be a pointer to a struct from which the fields indicate which
83
+// options are in the group.
84
+func (c *Command) AddGroup(shortDescription string, longDescription string, data interface{}) (*Group, error) {
85
+	group := newGroup(shortDescription, longDescription, data)
86
+
87
+	group.parent = c
88
+
89
+	if err := group.scanType(c.scanSubcommandHandler(group)); err != nil {
90
+		return nil, err
91
+	}
92
+
93
+	c.groups = append(c.groups, group)
94
+	return group, nil
95
+}
96
+
97
+// Commands returns a list of subcommands of this command.
98
+func (c *Command) Commands() []*Command {
99
+	return c.commands
100
+}
101
+
102
+// Find locates the subcommand with the given name and returns it. If no such
103
+// command can be found Find will return nil.
104
+func (c *Command) Find(name string) *Command {
105
+	for _, cc := range c.commands {
106
+		if cc.match(name) {
107
+			return cc
108
+		}
109
+	}
110
+
111
+	return nil
112
+}
113
+
114
+// FindOptionByLongName finds an option that is part of the command, or any of
115
+// its parent commands, by matching its long name (including the option
116
+// namespace).
117
+func (c *Command) FindOptionByLongName(longName string) (option *Option) {
118
+	for option == nil && c != nil {
119
+		option = c.Group.FindOptionByLongName(longName)
120
+
121
+		c, _ = c.parent.(*Command)
122
+	}
123
+
124
+	return option
125
+}
126
+
127
+// FindOptionByShortName finds an option that is part of the command, or any of
128
+// its parent commands, by matching its long name (including the option
129
+// namespace).
130
+func (c *Command) FindOptionByShortName(shortName rune) (option *Option) {
131
+	for option == nil && c != nil {
132
+		option = c.Group.FindOptionByShortName(shortName)
133
+
134
+		c, _ = c.parent.(*Command)
135
+	}
136
+
137
+	return option
138
+}
139
+
140
+// Args returns a list of positional arguments associated with this command.
141
+func (c *Command) Args() []*Arg {
142
+	ret := make([]*Arg, len(c.args))
143
+	copy(ret, c.args)
144
+
145
+	return ret
146
+}
147
+
148
+func newCommand(name string, shortDescription string, longDescription string, data interface{}) *Command {
149
+	return &Command{
150
+		Group: newGroup(shortDescription, longDescription, data),
151
+		Name:  name,
152
+	}
153
+}
154
+
155
+func (c *Command) scanSubcommandHandler(parentg *Group) scanHandler {
156
+	f := func(realval reflect.Value, sfield *reflect.StructField) (bool, error) {
157
+		mtag := newMultiTag(string(sfield.Tag))
158
+
159
+		if err := mtag.Parse(); err != nil {
160
+			return true, err
161
+		}
162
+
163
+		positional := mtag.Get("positional-args")
164
+
165
+		if len(positional) != 0 {
166
+			stype := realval.Type()
167
+
168
+			for i := 0; i < stype.NumField(); i++ {
169
+				field := stype.Field(i)
170
+
171
+				m := newMultiTag((string(field.Tag)))
172
+
173
+				if err := m.Parse(); err != nil {
174
+					return true, err
175
+				}
176
+
177
+				name := m.Get("positional-arg-name")
178
+
179
+				if len(name) == 0 {
180
+					name = field.Name
181
+				}
182
+
183
+				required := -1
184
+				requiredMaximum := -1
185
+
186
+				sreq := m.Get("required")
187
+
188
+				if sreq != "" {
189
+					required = 1
190
+
191
+					rng := strings.SplitN(sreq, "-", 2)
192
+
193
+					if len(rng) > 1 {
194
+						if preq, err := strconv.ParseInt(rng[0], 10, 32); err == nil {
195
+							required = int(preq)
196
+						}
197
+
198
+						if preq, err := strconv.ParseInt(rng[1], 10, 32); err == nil {
199
+							requiredMaximum = int(preq)
200
+						}
201
+					} else {
202
+						if preq, err := strconv.ParseInt(sreq, 10, 32); err == nil {
203
+							required = int(preq)
204
+						}
205
+					}
206
+				}
207
+
208
+				arg := &Arg{
209
+					Name:            name,
210
+					Description:     m.Get("description"),
211
+					Required:        required,
212
+					RequiredMaximum: requiredMaximum,
213
+
214
+					value: realval.Field(i),
215
+					tag:   m,
216
+				}
217
+
218
+				c.args = append(c.args, arg)
219
+
220
+				if len(mtag.Get("required")) != 0 {
221
+					c.ArgsRequired = true
222
+				}
223
+			}
224
+
225
+			return true, nil
226
+		}
227
+
228
+		subcommand := mtag.Get("command")
229
+
230
+		if len(subcommand) != 0 {
231
+			var ptrval reflect.Value
232
+
233
+			if realval.Kind() == reflect.Ptr {
234
+				ptrval = realval
235
+
236
+				if ptrval.IsNil() {
237
+					ptrval.Set(reflect.New(ptrval.Type().Elem()))
238
+				}
239
+			} else {
240
+				ptrval = realval.Addr()
241
+			}
242
+
243
+			shortDescription := mtag.Get("description")
244
+			longDescription := mtag.Get("long-description")
245
+			subcommandsOptional := mtag.Get("subcommands-optional")
246
+			aliases := mtag.GetMany("alias")
247
+
248
+			subc, err := c.AddCommand(subcommand, shortDescription, longDescription, ptrval.Interface())
249
+
250
+			if err != nil {
251
+				return true, err
252
+			}
253
+
254
+			subc.Hidden = mtag.Get("hidden") != ""
255
+
256
+			if len(subcommandsOptional) > 0 {
257
+				subc.SubcommandsOptional = true
258
+			}
259
+
260
+			if len(aliases) > 0 {
261
+				subc.Aliases = aliases
262
+			}
263
+
264
+			return true, nil
265
+		}
266
+
267
+		return parentg.scanSubGroupHandler(realval, sfield)
268
+	}
269
+
270
+	return f
271
+}
272
+
273
+func (c *Command) scan() error {
274
+	return c.scanType(c.scanSubcommandHandler(c.Group))
275
+}
276
+
277
+func (c *Command) eachOption(f func(*Command, *Group, *Option)) {
278
+	c.eachCommand(func(c *Command) {
279
+		c.eachGroup(func(g *Group) {
280
+			for _, option := range g.options {
281
+				f(c, g, option)
282
+			}
283
+		})
284
+	}, true)
285
+}
286
+
287
+func (c *Command) eachCommand(f func(*Command), recurse bool) {
288
+	f(c)
289
+
290
+	for _, cc := range c.commands {
291
+		if recurse {
292
+			cc.eachCommand(f, true)
293
+		} else {
294
+			f(cc)
295
+		}
296
+	}
297
+}
298
+
299
+func (c *Command) eachActiveGroup(f func(cc *Command, g *Group)) {
300
+	c.eachGroup(func(g *Group) {
301
+		f(c, g)
302
+	})
303
+
304
+	if c.Active != nil {
305
+		c.Active.eachActiveGroup(f)
306
+	}
307
+}
308
+
309
+func (c *Command) addHelpGroups(showHelp func() error) {
310
+	if !c.hasBuiltinHelpGroup {
311
+		c.addHelpGroup(showHelp)
312
+		c.hasBuiltinHelpGroup = true
313
+	}
314
+
315
+	for _, cc := range c.commands {
316
+		cc.addHelpGroups(showHelp)
317
+	}
318
+}
319
+
320
+func (c *Command) makeLookup() lookup {
321
+	ret := lookup{
322
+		shortNames: make(map[string]*Option),
323
+		longNames:  make(map[string]*Option),
324
+		commands:   make(map[string]*Command),
325
+	}
326
+
327
+	parent := c.parent
328
+
329
+	var parents []*Command
330
+
331
+	for parent != nil {
332
+		if cmd, ok := parent.(*Command); ok {
333
+			parents = append(parents, cmd)
334
+			parent = cmd.parent
335
+		} else {
336
+			parent = nil
337
+		}
338
+	}
339
+
340
+	for i := len(parents) - 1; i >= 0; i-- {
341
+		parents[i].fillLookup(&ret, true)
342
+	}
343
+
344
+	c.fillLookup(&ret, false)
345
+	return ret
346
+}
347
+
348
+func (c *Command) fillLookup(ret *lookup, onlyOptions bool) {
349
+	c.eachGroup(func(g *Group) {
350
+		for _, option := range g.options {
351
+			if option.ShortName != 0 {
352
+				ret.shortNames[string(option.ShortName)] = option
353
+			}
354
+
355
+			if len(option.LongName) > 0 {
356
+				ret.longNames[option.LongNameWithNamespace()] = option
357
+			}
358
+		}
359
+	})
360
+
361
+	if onlyOptions {
362
+		return
363
+	}
364
+
365
+	for _, subcommand := range c.commands {
366
+		ret.commands[subcommand.Name] = subcommand
367
+
368
+		for _, a := range subcommand.Aliases {
369
+			ret.commands[a] = subcommand
370
+		}
371
+	}
372
+}
373
+
374
+func (c *Command) groupByName(name string) *Group {
375
+	if grp := c.Group.groupByName(name); grp != nil {
376
+		return grp
377
+	}
378
+
379
+	for _, subc := range c.commands {
380
+		prefix := subc.Name + "."
381
+
382
+		if strings.HasPrefix(name, prefix) {
383
+			if grp := subc.groupByName(name[len(prefix):]); grp != nil {
384
+				return grp
385
+			}
386
+		} else if name == subc.Name {
387
+			return subc.Group
388
+		}
389
+	}
390
+
391
+	return nil
392
+}
393
+
394
+type commandList []*Command
395
+
396
+func (c commandList) Less(i, j int) bool {
397
+	return c[i].Name < c[j].Name
398
+}
399
+
400
+func (c commandList) Len() int {
401
+	return len(c)
402
+}
403
+
404
+func (c commandList) Swap(i, j int) {
405
+	c[i], c[j] = c[j], c[i]
406
+}
407
+
408
+func (c *Command) sortedVisibleCommands() []*Command {
409
+	ret := commandList(c.visibleCommands())
410
+	sort.Sort(ret)
411
+
412
+	return []*Command(ret)
413
+}
414
+
415
+func (c *Command) visibleCommands() []*Command {
416
+	ret := make([]*Command, 0, len(c.commands))
417
+
418
+	for _, cmd := range c.commands {
419
+		if !cmd.Hidden {
420
+			ret = append(ret, cmd)
421
+		}
422
+	}
423
+
424
+	return ret
425
+}
426
+
427
+func (c *Command) match(name string) bool {
428
+	if c.Name == name {
429
+		return true
430
+	}
431
+
432
+	for _, v := range c.Aliases {
433
+		if v == name {
434
+			return true
435
+		}
436
+	}
437
+
438
+	return false
439
+}
440
+
441
+func (c *Command) hasCliOptions() bool {
442
+	ret := false
443
+
444
+	c.eachGroup(func(g *Group) {
445
+		if g.isBuiltinHelp {
446
+			return
447
+		}
448
+
449
+		for _, opt := range g.options {
450
+			if opt.canCli() {
451
+				ret = true
452
+			}
453
+		}
454
+	})
455
+
456
+	return ret
457
+}
458
+
459
+func (c *Command) fillParseState(s *parseState) {
460
+	s.positional = make([]*Arg, len(c.args))
461
+	copy(s.positional, c.args)
462
+
463
+	s.lookup = c.makeLookup()
464
+	s.command = c
465
+}

+ 582
- 0
vendor/src/github.com/jessevdk/go-flags/command_test.go Datei anzeigen

@@ -0,0 +1,582 @@
1
+package flags
2
+
3
+import (
4
+	"fmt"
5
+	"testing"
6
+)
7
+
8
+func TestCommandInline(t *testing.T) {
9
+	var opts = struct {
10
+		Value bool `short:"v"`
11
+
12
+		Command struct {
13
+			G bool `short:"g"`
14
+		} `command:"cmd"`
15
+	}{}
16
+
17
+	p, ret := assertParserSuccess(t, &opts, "-v", "cmd", "-g")
18
+
19
+	assertStringArray(t, ret, []string{})
20
+
21
+	if p.Active == nil {
22
+		t.Errorf("Expected active command")
23
+	}
24
+
25
+	if !opts.Value {
26
+		t.Errorf("Expected Value to be true")
27
+	}
28
+
29
+	if !opts.Command.G {
30
+		t.Errorf("Expected Command.G to be true")
31
+	}
32
+
33
+	if p.Command.Find("cmd") != p.Active {
34
+		t.Errorf("Expected to find command `cmd' to be active")
35
+	}
36
+}
37
+
38
+func TestCommandInlineMulti(t *testing.T) {
39
+	var opts = struct {
40
+		Value bool `short:"v"`
41
+
42
+		C1 struct {
43
+		} `command:"c1"`
44
+
45
+		C2 struct {
46
+			G bool `short:"g"`
47
+		} `command:"c2"`
48
+	}{}
49
+
50
+	p, ret := assertParserSuccess(t, &opts, "-v", "c2", "-g")
51
+
52
+	assertStringArray(t, ret, []string{})
53
+
54
+	if p.Active == nil {
55
+		t.Errorf("Expected active command")
56
+	}
57
+
58
+	if !opts.Value {
59
+		t.Errorf("Expected Value to be true")
60
+	}
61
+
62
+	if !opts.C2.G {
63
+		t.Errorf("Expected C2.G to be true")
64
+	}
65
+
66
+	if p.Command.Find("c1") == nil {
67
+		t.Errorf("Expected to find command `c1'")
68
+	}
69
+
70
+	if c2 := p.Command.Find("c2"); c2 == nil {
71
+		t.Errorf("Expected to find command `c2'")
72
+	} else if c2 != p.Active {
73
+		t.Errorf("Expected to find command `c2' to be active")
74
+	}
75
+}
76
+
77
+func TestCommandFlagOrder1(t *testing.T) {
78
+	var opts = struct {
79
+		Value bool `short:"v"`
80
+
81
+		Command struct {
82
+			G bool `short:"g"`
83
+		} `command:"cmd"`
84
+	}{}
85
+
86
+	assertParseFail(t, ErrUnknownFlag, "unknown flag `g'", &opts, "-v", "-g", "cmd")
87
+}
88
+
89
+func TestCommandFlagOrder2(t *testing.T) {
90
+	var opts = struct {
91
+		Value bool `short:"v"`
92
+
93
+		Command struct {
94
+			G bool `short:"g"`
95
+		} `command:"cmd"`
96
+	}{}
97
+
98
+	assertParseSuccess(t, &opts, "cmd", "-v", "-g")
99
+
100
+	if !opts.Value {
101
+		t.Errorf("Expected Value to be true")
102
+	}
103
+
104
+	if !opts.Command.G {
105
+		t.Errorf("Expected Command.G to be true")
106
+	}
107
+}
108
+
109
+func TestCommandFlagOrderSub(t *testing.T) {
110
+	var opts = struct {
111
+		Value bool `short:"v"`
112
+
113
+		Command struct {
114
+			G bool `short:"g"`
115
+
116
+			SubCommand struct {
117
+				B bool `short:"b"`
118
+			} `command:"sub"`
119
+		} `command:"cmd"`
120
+	}{}
121
+
122
+	assertParseSuccess(t, &opts, "cmd", "sub", "-v", "-g", "-b")
123
+
124
+	if !opts.Value {
125
+		t.Errorf("Expected Value to be true")
126
+	}
127
+
128
+	if !opts.Command.G {
129
+		t.Errorf("Expected Command.G to be true")
130
+	}
131
+
132
+	if !opts.Command.SubCommand.B {
133
+		t.Errorf("Expected Command.SubCommand.B to be true")
134
+	}
135
+}
136
+
137
+func TestCommandFlagOverride1(t *testing.T) {
138
+	var opts = struct {
139
+		Value bool `short:"v"`
140
+
141
+		Command struct {
142
+			Value bool `short:"v"`
143
+		} `command:"cmd"`
144
+	}{}
145
+
146
+	assertParseSuccess(t, &opts, "-v", "cmd")
147
+
148
+	if !opts.Value {
149
+		t.Errorf("Expected Value to be true")
150
+	}
151
+
152
+	if opts.Command.Value {
153
+		t.Errorf("Expected Command.Value to be false")
154
+	}
155
+}
156
+
157
+func TestCommandFlagOverride2(t *testing.T) {
158
+	var opts = struct {
159
+		Value bool `short:"v"`
160
+
161
+		Command struct {
162
+			Value bool `short:"v"`
163
+		} `command:"cmd"`
164
+	}{}
165
+
166
+	assertParseSuccess(t, &opts, "cmd", "-v")
167
+
168
+	if opts.Value {
169
+		t.Errorf("Expected Value to be false")
170
+	}
171
+
172
+	if !opts.Command.Value {
173
+		t.Errorf("Expected Command.Value to be true")
174
+	}
175
+}
176
+
177
+func TestCommandFlagOverrideSub(t *testing.T) {
178
+	var opts = struct {
179
+		Value bool `short:"v"`
180
+
181
+		Command struct {
182
+			Value bool `short:"v"`
183
+
184
+			SubCommand struct {
185
+				Value bool `short:"v"`
186
+			} `command:"sub"`
187
+		} `command:"cmd"`
188
+	}{}
189
+
190
+	assertParseSuccess(t, &opts, "cmd", "sub", "-v")
191
+
192
+	if opts.Value {
193
+		t.Errorf("Expected Value to be false")
194
+	}
195
+
196
+	if opts.Command.Value {
197
+		t.Errorf("Expected Command.Value to be false")
198
+	}
199
+
200
+	if !opts.Command.SubCommand.Value {
201
+		t.Errorf("Expected Command.Value to be true")
202
+	}
203
+}
204
+
205
+func TestCommandFlagOverrideSub2(t *testing.T) {
206
+	var opts = struct {
207
+		Value bool `short:"v"`
208
+
209
+		Command struct {
210
+			Value bool `short:"v"`
211
+
212
+			SubCommand struct {
213
+				G bool `short:"g"`
214
+			} `command:"sub"`
215
+		} `command:"cmd"`
216
+	}{}
217
+
218
+	assertParseSuccess(t, &opts, "cmd", "sub", "-v")
219
+
220
+	if opts.Value {
221
+		t.Errorf("Expected Value to be false")
222
+	}
223
+
224
+	if !opts.Command.Value {
225
+		t.Errorf("Expected Command.Value to be true")
226
+	}
227
+}
228
+
229
+func TestCommandEstimate(t *testing.T) {
230
+	var opts = struct {
231
+		Value bool `short:"v"`
232
+
233
+		Cmd1 struct {
234
+		} `command:"remove"`
235
+
236
+		Cmd2 struct {
237
+		} `command:"add"`
238
+	}{}
239
+
240
+	p := NewParser(&opts, None)
241
+	_, err := p.ParseArgs([]string{})
242
+
243
+	assertError(t, err, ErrCommandRequired, "Please specify one command of: add or remove")
244
+}
245
+
246
+func TestCommandEstimate2(t *testing.T) {
247
+	var opts = struct {
248
+		Value bool `short:"v"`
249
+
250
+		Cmd1 struct {
251
+		} `command:"remove"`
252
+
253
+		Cmd2 struct {
254
+		} `command:"add"`
255
+	}{}
256
+
257
+	p := NewParser(&opts, None)
258
+	_, err := p.ParseArgs([]string{"rmive"})
259
+
260
+	assertError(t, err, ErrUnknownCommand, "Unknown command `rmive', did you mean `remove'?")
261
+}
262
+
263
+type testCommand struct {
264
+	G        bool `short:"g"`
265
+	Executed bool
266
+	EArgs    []string
267
+}
268
+
269
+func (c *testCommand) Execute(args []string) error {
270
+	c.Executed = true
271
+	c.EArgs = args
272
+
273
+	return nil
274
+}
275
+
276
+func TestCommandExecute(t *testing.T) {
277
+	var opts = struct {
278
+		Value bool `short:"v"`
279
+
280
+		Command testCommand `command:"cmd"`
281
+	}{}
282
+
283
+	assertParseSuccess(t, &opts, "-v", "cmd", "-g", "a", "b")
284
+
285
+	if !opts.Value {
286
+		t.Errorf("Expected Value to be true")
287
+	}
288
+
289
+	if !opts.Command.Executed {
290
+		t.Errorf("Did not execute command")
291
+	}
292
+
293
+	if !opts.Command.G {
294
+		t.Errorf("Expected Command.C to be true")
295
+	}
296
+
297
+	assertStringArray(t, opts.Command.EArgs, []string{"a", "b"})
298
+}
299
+
300
+func TestCommandClosest(t *testing.T) {
301
+	var opts = struct {
302
+		Value bool `short:"v"`
303
+
304
+		Cmd1 struct {
305
+		} `command:"remove"`
306
+
307
+		Cmd2 struct {
308
+		} `command:"add"`
309
+	}{}
310
+
311
+	args := assertParseFail(t, ErrUnknownCommand, "Unknown command `addd', did you mean `add'?", &opts, "-v", "addd")
312
+
313
+	assertStringArray(t, args, []string{"addd"})
314
+}
315
+
316
+func TestCommandAdd(t *testing.T) {
317
+	var opts = struct {
318
+		Value bool `short:"v"`
319
+	}{}
320
+
321
+	var cmd = struct {
322
+		G bool `short:"g"`
323
+	}{}
324
+
325
+	p := NewParser(&opts, Default)
326
+	c, err := p.AddCommand("cmd", "", "", &cmd)
327
+
328
+	if err != nil {
329
+		t.Fatalf("Unexpected error: %v", err)
330
+		return
331
+	}
332
+
333
+	ret, err := p.ParseArgs([]string{"-v", "cmd", "-g", "rest"})
334
+
335
+	if err != nil {
336
+		t.Fatalf("Unexpected error: %v", err)
337
+		return
338
+	}
339
+
340
+	assertStringArray(t, ret, []string{"rest"})
341
+
342
+	if !opts.Value {
343
+		t.Errorf("Expected Value to be true")
344
+	}
345
+
346
+	if !cmd.G {
347
+		t.Errorf("Expected Command.G to be true")
348
+	}
349
+
350
+	if p.Command.Find("cmd") != c {
351
+		t.Errorf("Expected to find command `cmd'")
352
+	}
353
+
354
+	if p.Commands()[0] != c {
355
+		t.Errorf("Expected command %#v, but got %#v", c, p.Commands()[0])
356
+	}
357
+
358
+	if c.Options()[0].ShortName != 'g' {
359
+		t.Errorf("Expected short name `g' but got %v", c.Options()[0].ShortName)
360
+	}
361
+}
362
+
363
+func TestCommandNestedInline(t *testing.T) {
364
+	var opts = struct {
365
+		Value bool `short:"v"`
366
+
367
+		Command struct {
368
+			G bool `short:"g"`
369
+
370
+			Nested struct {
371
+				N string `long:"n"`
372
+			} `command:"nested"`
373
+		} `command:"cmd"`
374
+	}{}
375
+
376
+	p, ret := assertParserSuccess(t, &opts, "-v", "cmd", "-g", "nested", "--n", "n", "rest")
377
+
378
+	assertStringArray(t, ret, []string{"rest"})
379
+
380
+	if !opts.Value {
381
+		t.Errorf("Expected Value to be true")
382
+	}
383
+
384
+	if !opts.Command.G {
385
+		t.Errorf("Expected Command.G to be true")
386
+	}
387
+
388
+	assertString(t, opts.Command.Nested.N, "n")
389
+
390
+	if c := p.Command.Find("cmd"); c == nil {
391
+		t.Errorf("Expected to find command `cmd'")
392
+	} else {
393
+		if c != p.Active {
394
+			t.Errorf("Expected `cmd' to be the active parser command")
395
+		}
396
+
397
+		if nested := c.Find("nested"); nested == nil {
398
+			t.Errorf("Expected to find command `nested'")
399
+		} else if nested != c.Active {
400
+			t.Errorf("Expected to find command `nested' to be the active `cmd' command")
401
+		}
402
+	}
403
+}
404
+
405
+func TestRequiredOnCommand(t *testing.T) {
406
+	var opts = struct {
407
+		Value bool `short:"v" required:"true"`
408
+
409
+		Command struct {
410
+			G bool `short:"g"`
411
+		} `command:"cmd"`
412
+	}{}
413
+
414
+	assertParseFail(t, ErrRequired, fmt.Sprintf("the required flag `%cv' was not specified", defaultShortOptDelimiter), &opts, "cmd")
415
+}
416
+
417
+func TestRequiredAllOnCommand(t *testing.T) {
418
+	var opts = struct {
419
+		Value   bool `short:"v" required:"true"`
420
+		Missing bool `long:"missing" required:"true"`
421
+
422
+		Command struct {
423
+			G bool `short:"g"`
424
+		} `command:"cmd"`
425
+	}{}
426
+
427
+	assertParseFail(t, ErrRequired, fmt.Sprintf("the required flags `%smissing' and `%cv' were not specified", defaultLongOptDelimiter, defaultShortOptDelimiter), &opts, "cmd")
428
+}
429
+
430
+func TestDefaultOnCommand(t *testing.T) {
431
+	var opts = struct {
432
+		Command struct {
433
+			G string `short:"g" default:"value"`
434
+		} `command:"cmd"`
435
+	}{}
436
+
437
+	assertParseSuccess(t, &opts, "cmd")
438
+
439
+	if opts.Command.G != "value" {
440
+		t.Errorf("Expected G to be \"value\"")
441
+	}
442
+}
443
+
444
+func TestAfterNonCommand(t *testing.T) {
445
+	var opts = struct {
446
+		Value bool `short:"v"`
447
+
448
+		Cmd1 struct {
449
+		} `command:"remove"`
450
+
451
+		Cmd2 struct {
452
+		} `command:"add"`
453
+	}{}
454
+
455
+	assertParseFail(t, ErrUnknownCommand, "Unknown command `nocmd'. Please specify one command of: add or remove", &opts, "nocmd", "remove")
456
+}
457
+
458
+func TestSubcommandsOptional(t *testing.T) {
459
+	var opts = struct {
460
+		Value bool `short:"v"`
461
+
462
+		Cmd1 struct {
463
+		} `command:"remove"`
464
+
465
+		Cmd2 struct {
466
+		} `command:"add"`
467
+	}{}
468
+
469
+	p := NewParser(&opts, None)
470
+	p.SubcommandsOptional = true
471
+
472
+	_, err := p.ParseArgs([]string{"-v"})
473
+
474
+	if err != nil {
475
+		t.Fatalf("Unexpected error: %v", err)
476
+		return
477
+	}
478
+
479
+	if !opts.Value {
480
+		t.Errorf("Expected Value to be true")
481
+	}
482
+}
483
+
484
+func TestSubcommandsOptionalAfterNonCommand(t *testing.T) {
485
+	var opts = struct {
486
+		Value bool `short:"v"`
487
+
488
+		Cmd1 struct {
489
+		} `command:"remove"`
490
+
491
+		Cmd2 struct {
492
+		} `command:"add"`
493
+	}{}
494
+
495
+	p := NewParser(&opts, None)
496
+	p.SubcommandsOptional = true
497
+
498
+	retargs, err := p.ParseArgs([]string{"nocmd", "remove"})
499
+
500
+	if err != nil {
501
+		t.Fatalf("Unexpected error: %v", err)
502
+		return
503
+	}
504
+
505
+	assertStringArray(t, retargs, []string{"nocmd", "remove"})
506
+}
507
+
508
+func TestCommandAlias(t *testing.T) {
509
+	var opts = struct {
510
+		Command struct {
511
+			G string `short:"g" default:"value"`
512
+		} `command:"cmd" alias:"cm"`
513
+	}{}
514
+
515
+	assertParseSuccess(t, &opts, "cm")
516
+
517
+	if opts.Command.G != "value" {
518
+		t.Errorf("Expected G to be \"value\"")
519
+	}
520
+}
521
+
522
+func TestSubCommandFindOptionByLongFlag(t *testing.T) {
523
+	var opts struct {
524
+		Testing bool `long:"testing" description:"Testing"`
525
+	}
526
+
527
+	var cmd struct {
528
+		Other bool `long:"other" description:"Other"`
529
+	}
530
+
531
+	p := NewParser(&opts, Default)
532
+	c, _ := p.AddCommand("command", "Short", "Long", &cmd)
533
+
534
+	opt := c.FindOptionByLongName("other")
535
+
536
+	if opt == nil {
537
+		t.Errorf("Expected option, but found none")
538
+	}
539
+
540
+	assertString(t, opt.LongName, "other")
541
+
542
+	opt = c.FindOptionByLongName("testing")
543
+
544
+	if opt == nil {
545
+		t.Errorf("Expected option, but found none")
546
+	}
547
+
548
+	assertString(t, opt.LongName, "testing")
549
+}
550
+
551
+func TestSubCommandFindOptionByShortFlag(t *testing.T) {
552
+	var opts struct {
553
+		Testing bool `short:"t" description:"Testing"`
554
+	}
555
+
556
+	var cmd struct {
557
+		Other bool `short:"o" description:"Other"`
558
+	}
559
+
560
+	p := NewParser(&opts, Default)
561
+	c, _ := p.AddCommand("command", "Short", "Long", &cmd)
562
+
563
+	opt := c.FindOptionByShortName('o')
564
+
565
+	if opt == nil {
566
+		t.Errorf("Expected option, but found none")
567
+	}
568
+
569
+	if opt.ShortName != 'o' {
570
+		t.Errorf("Expected 'o', but got %v", opt.ShortName)
571
+	}
572
+
573
+	opt = c.FindOptionByShortName('t')
574
+
575
+	if opt == nil {
576
+		t.Errorf("Expected option, but found none")
577
+	}
578
+
579
+	if opt.ShortName != 't' {
580
+		t.Errorf("Expected 'o', but got %v", opt.ShortName)
581
+	}
582
+}

+ 309
- 0
vendor/src/github.com/jessevdk/go-flags/completion.go Datei anzeigen

@@ -0,0 +1,309 @@
1
+package flags
2
+
3
+import (
4
+	"fmt"
5
+	"path/filepath"
6
+	"reflect"
7
+	"sort"
8
+	"strings"
9
+	"unicode/utf8"
10
+)
11
+
12
+// Completion is a type containing information of a completion.
13
+type Completion struct {
14
+	// The completed item
15
+	Item string
16
+
17
+	// A description of the completed item (optional)
18
+	Description string
19
+}
20
+
21
+type completions []Completion
22
+
23
+func (c completions) Len() int {
24
+	return len(c)
25
+}
26
+
27
+func (c completions) Less(i, j int) bool {
28
+	return c[i].Item < c[j].Item
29
+}
30
+
31
+func (c completions) Swap(i, j int) {
32
+	c[i], c[j] = c[j], c[i]
33
+}
34
+
35
+// Completer is an interface which can be implemented by types
36
+// to provide custom command line argument completion.
37
+type Completer interface {
38
+	// Complete receives a prefix representing a (partial) value
39
+	// for its type and should provide a list of possible valid
40
+	// completions.
41
+	Complete(match string) []Completion
42
+}
43
+
44
+type completion struct {
45
+	parser *Parser
46
+}
47
+
48
+// Filename is a string alias which provides filename completion.
49
+type Filename string
50
+
51
+func completionsWithoutDescriptions(items []string) []Completion {
52
+	ret := make([]Completion, len(items))
53
+
54
+	for i, v := range items {
55
+		ret[i].Item = v
56
+	}
57
+
58
+	return ret
59
+}
60
+
61
+// Complete returns a list of existing files with the given
62
+// prefix.
63
+func (f *Filename) Complete(match string) []Completion {
64
+	ret, _ := filepath.Glob(match + "*")
65
+	return completionsWithoutDescriptions(ret)
66
+}
67
+
68
+func (c *completion) skipPositional(s *parseState, n int) {
69
+	if n >= len(s.positional) {
70
+		s.positional = nil
71
+	} else {
72
+		s.positional = s.positional[n:]
73
+	}
74
+}
75
+
76
+func (c *completion) completeOptionNames(s *parseState, prefix string, match string, short bool) []Completion {
77
+	if short && len(match) != 0 {
78
+		return []Completion{
79
+			Completion{
80
+				Item: prefix + match,
81
+			},
82
+		}
83
+	}
84
+
85
+	var results []Completion
86
+	repeats := map[string]bool{}
87
+
88
+	for name, opt := range s.lookup.longNames {
89
+		if strings.HasPrefix(name, match) && !opt.Hidden {
90
+			results = append(results, Completion{
91
+				Item:        defaultLongOptDelimiter + name,
92
+				Description: opt.Description,
93
+			})
94
+
95
+			if short {
96
+				repeats[string(opt.ShortName)] = true
97
+			}
98
+		}
99
+	}
100
+
101
+	if short {
102
+		for name, opt := range s.lookup.shortNames {
103
+			if _, exist := repeats[name]; !exist && strings.HasPrefix(name, match) && !opt.Hidden {
104
+				results = append(results, Completion{
105
+					Item:        string(defaultShortOptDelimiter) + name,
106
+					Description: opt.Description,
107
+				})
108
+			}
109
+		}
110
+	}
111
+
112
+	return results
113
+}
114
+
115
+func (c *completion) completeNamesForLongPrefix(s *parseState, prefix string, match string) []Completion {
116
+	return c.completeOptionNames(s, prefix, match, false)
117
+}
118
+
119
+func (c *completion) completeNamesForShortPrefix(s *parseState, prefix string, match string) []Completion {
120
+	return c.completeOptionNames(s, prefix, match, true)
121
+}
122
+
123
+func (c *completion) completeCommands(s *parseState, match string) []Completion {
124
+	n := make([]Completion, 0, len(s.command.commands))
125
+
126
+	for _, cmd := range s.command.commands {
127
+		if cmd.data != c && strings.HasPrefix(cmd.Name, match) {
128
+			n = append(n, Completion{
129
+				Item:        cmd.Name,
130
+				Description: cmd.ShortDescription,
131
+			})
132
+		}
133
+	}
134
+
135
+	return n
136
+}
137
+
138
+func (c *completion) completeValue(value reflect.Value, prefix string, match string) []Completion {
139
+	if value.Kind() == reflect.Slice {
140
+		value = reflect.New(value.Type().Elem())
141
+	}
142
+	i := value.Interface()
143
+
144
+	var ret []Completion
145
+
146
+	if cmp, ok := i.(Completer); ok {
147
+		ret = cmp.Complete(match)
148
+	} else if value.CanAddr() {
149
+		if cmp, ok = value.Addr().Interface().(Completer); ok {
150
+			ret = cmp.Complete(match)
151
+		}
152
+	}
153
+
154
+	for i, v := range ret {
155
+		ret[i].Item = prefix + v.Item
156
+	}
157
+
158
+	return ret
159
+}
160
+
161
+func (c *completion) complete(args []string) []Completion {
162
+	if len(args) == 0 {
163
+		args = []string{""}
164
+	}
165
+
166
+	s := &parseState{
167
+		args: args,
168
+	}
169
+
170
+	c.parser.fillParseState(s)
171
+
172
+	var opt *Option
173
+
174
+	for len(s.args) > 1 {
175
+		arg := s.pop()
176
+
177
+		if (c.parser.Options&PassDoubleDash) != None && arg == "--" {
178
+			opt = nil
179
+			c.skipPositional(s, len(s.args)-1)
180
+
181
+			break
182
+		}
183
+
184
+		if argumentIsOption(arg) {
185
+			prefix, optname, islong := stripOptionPrefix(arg)
186
+			optname, _, argument := splitOption(prefix, optname, islong)
187
+
188
+			if argument == nil {
189
+				var o *Option
190
+				canarg := true
191
+
192
+				if islong {
193
+					o = s.lookup.longNames[optname]
194
+				} else {
195
+					for i, r := range optname {
196
+						sname := string(r)
197
+						o = s.lookup.shortNames[sname]
198
+
199
+						if o == nil {
200
+							break
201
+						}
202
+
203
+						if i == 0 && o.canArgument() && len(optname) != len(sname) {
204
+							canarg = false
205
+							break
206
+						}
207
+					}
208
+				}
209
+
210
+				if o == nil && (c.parser.Options&PassAfterNonOption) != None {
211
+					opt = nil
212
+					c.skipPositional(s, len(s.args)-1)
213
+
214
+					break
215
+				} else if o != nil && o.canArgument() && !o.OptionalArgument && canarg {
216
+					if len(s.args) > 1 {
217
+						s.pop()
218
+					} else {
219
+						opt = o
220
+					}
221
+				}
222
+			}
223
+		} else {
224
+			if len(s.positional) > 0 {
225
+				if !s.positional[0].isRemaining() {
226
+					// Don't advance beyond a remaining positional arg (because
227
+					// it consumes all subsequent args).
228
+					s.positional = s.positional[1:]
229
+				}
230
+			} else if cmd, ok := s.lookup.commands[arg]; ok {
231
+				cmd.fillParseState(s)
232
+			}
233
+
234
+			opt = nil
235
+		}
236
+	}
237
+
238
+	lastarg := s.args[len(s.args)-1]
239
+	var ret []Completion
240
+
241
+	if opt != nil {
242
+		// Completion for the argument of 'opt'
243
+		ret = c.completeValue(opt.value, "", lastarg)
244
+	} else if argumentStartsOption(lastarg) {
245
+		// Complete the option
246
+		prefix, optname, islong := stripOptionPrefix(lastarg)
247
+		optname, split, argument := splitOption(prefix, optname, islong)
248
+
249
+		if argument == nil && !islong {
250
+			rname, n := utf8.DecodeRuneInString(optname)
251
+			sname := string(rname)
252
+
253
+			if opt := s.lookup.shortNames[sname]; opt != nil && opt.canArgument() {
254
+				ret = c.completeValue(opt.value, prefix+sname, optname[n:])
255
+			} else {
256
+				ret = c.completeNamesForShortPrefix(s, prefix, optname)
257
+			}
258
+		} else if argument != nil {
259
+			if islong {
260
+				opt = s.lookup.longNames[optname]
261
+			} else {
262
+				opt = s.lookup.shortNames[optname]
263
+			}
264
+
265
+			if opt != nil {
266
+				ret = c.completeValue(opt.value, prefix+optname+split, *argument)
267
+			}
268
+		} else if islong {
269
+			ret = c.completeNamesForLongPrefix(s, prefix, optname)
270
+		} else {
271
+			ret = c.completeNamesForShortPrefix(s, prefix, optname)
272
+		}
273
+	} else if len(s.positional) > 0 {
274
+		// Complete for positional argument
275
+		ret = c.completeValue(s.positional[0].value, "", lastarg)
276
+	} else if len(s.command.commands) > 0 {
277
+		// Complete for command
278
+		ret = c.completeCommands(s, lastarg)
279
+	}
280
+
281
+	sort.Sort(completions(ret))
282
+	return ret
283
+}
284
+
285
+func (c *completion) print(items []Completion, showDescriptions bool) {
286
+	if showDescriptions && len(items) > 1 {
287
+		maxl := 0
288
+
289
+		for _, v := range items {
290
+			if len(v.Item) > maxl {
291
+				maxl = len(v.Item)
292
+			}
293
+		}
294
+
295
+		for _, v := range items {
296
+			fmt.Printf("%s", v.Item)
297
+
298
+			if len(v.Description) > 0 {
299
+				fmt.Printf("%s  # %s", strings.Repeat(" ", maxl-len(v.Item)), v.Description)
300
+			}
301
+
302
+			fmt.Printf("\n")
303
+		}
304
+	} else {
305
+		for _, v := range items {
306
+			fmt.Println(v.Item)
307
+		}
308
+	}
309
+}

+ 315
- 0
vendor/src/github.com/jessevdk/go-flags/completion_test.go Datei anzeigen

@@ -0,0 +1,315 @@
1
+package flags
2
+
3
+import (
4
+	"bytes"
5
+	"io"
6
+	"os"
7
+	"path"
8
+	"path/filepath"
9
+	"reflect"
10
+	"runtime"
11
+	"strings"
12
+	"testing"
13
+)
14
+
15
+type TestComplete struct {
16
+}
17
+
18
+func (t *TestComplete) Complete(match string) []Completion {
19
+	options := []string{
20
+		"hello world",
21
+		"hello universe",
22
+		"hello multiverse",
23
+	}
24
+
25
+	ret := make([]Completion, 0, len(options))
26
+
27
+	for _, o := range options {
28
+		if strings.HasPrefix(o, match) {
29
+			ret = append(ret, Completion{
30
+				Item: o,
31
+			})
32
+		}
33
+	}
34
+
35
+	return ret
36
+}
37
+
38
+var completionTestOptions struct {
39
+	Verbose  bool `short:"v" long:"verbose" description:"Verbose messages"`
40
+	Debug    bool `short:"d" long:"debug" description:"Enable debug"`
41
+	Info     bool `short:"i" description:"Display info"`
42
+	Version  bool `long:"version" description:"Show version"`
43
+	Required bool `long:"required" required:"true" description:"This is required"`
44
+	Hidden   bool `long:"hidden" hidden:"true" description:"This is hidden"`
45
+
46
+	AddCommand struct {
47
+		Positional struct {
48
+			Filename Filename
49
+		} `positional-args:"yes"`
50
+	} `command:"add" description:"add an item"`
51
+
52
+	AddMultiCommand struct {
53
+		Positional struct {
54
+			Filename []Filename
55
+		} `positional-args:"yes"`
56
+		Extra []Filename `short:"f"`
57
+	} `command:"add-multi" description:"add multiple items"`
58
+
59
+	AddMultiCommandFlag struct {
60
+		Files []Filename `short:"f"`
61
+	} `command:"add-multi-flag" description:"add multiple items via flags"`
62
+
63
+	RemoveCommand struct {
64
+		Other bool     `short:"o"`
65
+		File  Filename `short:"f" long:"filename"`
66
+	} `command:"rm" description:"remove an item"`
67
+
68
+	RenameCommand struct {
69
+		Completed TestComplete `short:"c" long:"completed"`
70
+	} `command:"rename" description:"rename an item"`
71
+}
72
+
73
+type completionTest struct {
74
+	Args             []string
75
+	Completed        []string
76
+	ShowDescriptions bool
77
+}
78
+
79
+var completionTests []completionTest
80
+
81
+func init() {
82
+	_, sourcefile, _, _ := runtime.Caller(0)
83
+	completionTestSourcedir := filepath.Join(filepath.SplitList(path.Dir(sourcefile))...)
84
+
85
+	completionTestFilename := []string{filepath.Join(completionTestSourcedir, "completion.go"), filepath.Join(completionTestSourcedir, "completion_test.go")}
86
+
87
+	completionTests = []completionTest{
88
+		{
89
+			// Short names
90
+			[]string{"-"},
91
+			[]string{"--debug", "--required", "--verbose", "--version", "-i"},
92
+			false,
93
+		},
94
+
95
+		{
96
+			// Short names full
97
+			[]string{"-i"},
98
+			[]string{"-i"},
99
+			false,
100
+		},
101
+
102
+		{
103
+			// Short names concatenated
104
+			[]string{"-dv"},
105
+			[]string{"-dv"},
106
+			false,
107
+		},
108
+
109
+		{
110
+			// Long names
111
+			[]string{"--"},
112
+			[]string{"--debug", "--required", "--verbose", "--version"},
113
+			false,
114
+		},
115
+
116
+		{
117
+			// Long names with descriptions
118
+			[]string{"--"},
119
+			[]string{
120
+				"--debug     # Enable debug",
121
+				"--required  # This is required",
122
+				"--verbose   # Verbose messages",
123
+				"--version   # Show version",
124
+			},
125
+			true,
126
+		},
127
+
128
+		{
129
+			// Long names partial
130
+			[]string{"--ver"},
131
+			[]string{"--verbose", "--version"},
132
+			false,
133
+		},
134
+
135
+		{
136
+			// Commands
137
+			[]string{""},
138
+			[]string{"add", "add-multi", "add-multi-flag", "rename", "rm"},
139
+			false,
140
+		},
141
+
142
+		{
143
+			// Commands with descriptions
144
+			[]string{""},
145
+			[]string{
146
+				"add             # add an item",
147
+				"add-multi       # add multiple items",
148
+				"add-multi-flag  # add multiple items via flags",
149
+				"rename          # rename an item",
150
+				"rm              # remove an item",
151
+			},
152
+			true,
153
+		},
154
+
155
+		{
156
+			// Commands partial
157
+			[]string{"r"},
158
+			[]string{"rename", "rm"},
159
+			false,
160
+		},
161
+
162
+		{
163
+			// Positional filename
164
+			[]string{"add", filepath.Join(completionTestSourcedir, "completion")},
165
+			completionTestFilename,
166
+			false,
167
+		},
168
+
169
+		{
170
+			// Multiple positional filename (1 arg)
171
+			[]string{"add-multi", filepath.Join(completionTestSourcedir, "completion")},
172
+			completionTestFilename,
173
+			false,
174
+		},
175
+		{
176
+			// Multiple positional filename (2 args)
177
+			[]string{"add-multi", filepath.Join(completionTestSourcedir, "completion.go"), filepath.Join(completionTestSourcedir, "completion")},
178
+			completionTestFilename,
179
+			false,
180
+		},
181
+		{
182
+			// Multiple positional filename (3 args)
183
+			[]string{"add-multi", filepath.Join(completionTestSourcedir, "completion.go"), filepath.Join(completionTestSourcedir, "completion.go"), filepath.Join(completionTestSourcedir, "completion")},
184
+			completionTestFilename,
185
+			false,
186
+		},
187
+
188
+		{
189
+			// Flag filename
190
+			[]string{"rm", "-f", path.Join(completionTestSourcedir, "completion")},
191
+			completionTestFilename,
192
+			false,
193
+		},
194
+
195
+		{
196
+			// Flag short concat last filename
197
+			[]string{"rm", "-of", path.Join(completionTestSourcedir, "completion")},
198
+			completionTestFilename,
199
+			false,
200
+		},
201
+
202
+		{
203
+			// Flag concat filename
204
+			[]string{"rm", "-f" + path.Join(completionTestSourcedir, "completion")},
205
+			[]string{"-f" + completionTestFilename[0], "-f" + completionTestFilename[1]},
206
+			false,
207
+		},
208
+
209
+		{
210
+			// Flag equal concat filename
211
+			[]string{"rm", "-f=" + path.Join(completionTestSourcedir, "completion")},
212
+			[]string{"-f=" + completionTestFilename[0], "-f=" + completionTestFilename[1]},
213
+			false,
214
+		},
215
+
216
+		{
217
+			// Flag concat long filename
218
+			[]string{"rm", "--filename=" + path.Join(completionTestSourcedir, "completion")},
219
+			[]string{"--filename=" + completionTestFilename[0], "--filename=" + completionTestFilename[1]},
220
+			false,
221
+		},
222
+
223
+		{
224
+			// Flag long filename
225
+			[]string{"rm", "--filename", path.Join(completionTestSourcedir, "completion")},
226
+			completionTestFilename,
227
+			false,
228
+		},
229
+
230
+		{
231
+			// Custom completed
232
+			[]string{"rename", "-c", "hello un"},
233
+			[]string{"hello universe"},
234
+			false,
235
+		},
236
+		{
237
+			// Multiple flag filename
238
+			[]string{"add-multi-flag", "-f", filepath.Join(completionTestSourcedir, "completion")},
239
+			completionTestFilename,
240
+			false,
241
+		},
242
+	}
243
+}
244
+
245
+func TestCompletion(t *testing.T) {
246
+	p := NewParser(&completionTestOptions, Default)
247
+	c := &completion{parser: p}
248
+
249
+	for _, test := range completionTests {
250
+		if test.ShowDescriptions {
251
+			continue
252
+		}
253
+
254
+		ret := c.complete(test.Args)
255
+		items := make([]string, len(ret))
256
+
257
+		for i, v := range ret {
258
+			items[i] = v.Item
259
+		}
260
+
261
+		if !reflect.DeepEqual(items, test.Completed) {
262
+			t.Errorf("Args: %#v, %#v\n  Expected: %#v\n  Got:     %#v", test.Args, test.ShowDescriptions, test.Completed, items)
263
+		}
264
+	}
265
+}
266
+
267
+func TestParserCompletion(t *testing.T) {
268
+	for _, test := range completionTests {
269
+		if test.ShowDescriptions {
270
+			os.Setenv("GO_FLAGS_COMPLETION", "verbose")
271
+		} else {
272
+			os.Setenv("GO_FLAGS_COMPLETION", "1")
273
+		}
274
+
275
+		tmp := os.Stdout
276
+
277
+		r, w, _ := os.Pipe()
278
+		os.Stdout = w
279
+
280
+		out := make(chan string)
281
+
282
+		go func() {
283
+			var buf bytes.Buffer
284
+
285
+			io.Copy(&buf, r)
286
+
287
+			out <- buf.String()
288
+		}()
289
+
290
+		p := NewParser(&completionTestOptions, None)
291
+
292
+		p.CompletionHandler = func(items []Completion) {
293
+			comp := &completion{parser: p}
294
+			comp.print(items, test.ShowDescriptions)
295
+		}
296
+
297
+		_, err := p.ParseArgs(test.Args)
298
+
299
+		w.Close()
300
+
301
+		os.Stdout = tmp
302
+
303
+		if err != nil {
304
+			t.Fatalf("Unexpected error: %s", err)
305
+		}
306
+
307
+		got := strings.Split(strings.Trim(<-out, "\n"), "\n")
308
+
309
+		if !reflect.DeepEqual(got, test.Completed) {
310
+			t.Errorf("Expected: %#v\nGot: %#v", test.Completed, got)
311
+		}
312
+	}
313
+
314
+	os.Setenv("GO_FLAGS_COMPLETION", "")
315
+}

+ 348
- 0
vendor/src/github.com/jessevdk/go-flags/convert.go Datei anzeigen

@@ -0,0 +1,348 @@
1
+// Copyright 2012 Jesse van den Kieboom. 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 flags
6
+
7
+import (
8
+	"fmt"
9
+	"reflect"
10
+	"strconv"
11
+	"strings"
12
+	"time"
13
+)
14
+
15
+// Marshaler is the interface implemented by types that can marshal themselves
16
+// to a string representation of the flag.
17
+type Marshaler interface {
18
+	// MarshalFlag marshals a flag value to its string representation.
19
+	MarshalFlag() (string, error)
20
+}
21
+
22
+// Unmarshaler is the interface implemented by types that can unmarshal a flag
23
+// argument to themselves. The provided value is directly passed from the
24
+// command line.
25
+type Unmarshaler interface {
26
+	// UnmarshalFlag unmarshals a string value representation to the flag
27
+	// value (which therefore needs to be a pointer receiver).
28
+	UnmarshalFlag(value string) error
29
+}
30
+
31
+func getBase(options multiTag, base int) (int, error) {
32
+	sbase := options.Get("base")
33
+
34
+	var err error
35
+	var ivbase int64
36
+
37
+	if sbase != "" {
38
+		ivbase, err = strconv.ParseInt(sbase, 10, 32)
39
+		base = int(ivbase)
40
+	}
41
+
42
+	return base, err
43
+}
44
+
45
+func convertMarshal(val reflect.Value) (bool, string, error) {
46
+	// Check first for the Marshaler interface
47
+	if val.Type().NumMethod() > 0 && val.CanInterface() {
48
+		if marshaler, ok := val.Interface().(Marshaler); ok {
49
+			ret, err := marshaler.MarshalFlag()
50
+			return true, ret, err
51
+		}
52
+	}
53
+
54
+	return false, "", nil
55
+}
56
+
57
+func convertToString(val reflect.Value, options multiTag) (string, error) {
58
+	if ok, ret, err := convertMarshal(val); ok {
59
+		return ret, err
60
+	}
61
+
62
+	tp := val.Type()
63
+
64
+	// Support for time.Duration
65
+	if tp == reflect.TypeOf((*time.Duration)(nil)).Elem() {
66
+		stringer := val.Interface().(fmt.Stringer)
67
+		return stringer.String(), nil
68
+	}
69
+
70
+	switch tp.Kind() {
71
+	case reflect.String:
72
+		return val.String(), nil
73
+	case reflect.Bool:
74
+		if val.Bool() {
75
+			return "true", nil
76
+		}
77
+
78
+		return "false", nil
79
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
80
+		base, err := getBase(options, 10)
81
+
82
+		if err != nil {
83
+			return "", err
84
+		}
85
+
86
+		return strconv.FormatInt(val.Int(), base), nil
87
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
88
+		base, err := getBase(options, 10)
89
+
90
+		if err != nil {
91
+			return "", err
92
+		}
93
+
94
+		return strconv.FormatUint(val.Uint(), base), nil
95
+	case reflect.Float32, reflect.Float64:
96
+		return strconv.FormatFloat(val.Float(), 'g', -1, tp.Bits()), nil
97
+	case reflect.Slice:
98
+		if val.Len() == 0 {
99
+			return "", nil
100
+		}
101
+
102
+		ret := "["
103
+
104
+		for i := 0; i < val.Len(); i++ {
105
+			if i != 0 {
106
+				ret += ", "
107
+			}
108
+
109
+			item, err := convertToString(val.Index(i), options)
110
+
111
+			if err != nil {
112
+				return "", err
113
+			}
114
+
115
+			ret += item
116
+		}
117
+
118
+		return ret + "]", nil
119
+	case reflect.Map:
120
+		ret := "{"
121
+
122
+		for i, key := range val.MapKeys() {
123
+			if i != 0 {
124
+				ret += ", "
125
+			}
126
+
127
+			keyitem, err := convertToString(key, options)
128
+
129
+			if err != nil {
130
+				return "", err
131
+			}
132
+
133
+			item, err := convertToString(val.MapIndex(key), options)
134
+
135
+			if err != nil {
136
+				return "", err
137
+			}
138
+
139
+			ret += keyitem + ":" + item
140
+		}
141
+
142
+		return ret + "}", nil
143
+	case reflect.Ptr:
144
+		return convertToString(reflect.Indirect(val), options)
145
+	case reflect.Interface:
146
+		if !val.IsNil() {
147
+			return convertToString(val.Elem(), options)
148
+		}
149
+	}
150
+
151
+	return "", nil
152
+}
153
+
154
+func convertUnmarshal(val string, retval reflect.Value) (bool, error) {
155
+	if retval.Type().NumMethod() > 0 && retval.CanInterface() {
156
+		if unmarshaler, ok := retval.Interface().(Unmarshaler); ok {
157
+			if retval.IsNil() {
158
+				retval.Set(reflect.New(retval.Type().Elem()))
159
+
160
+				// Re-assign from the new value
161
+				unmarshaler = retval.Interface().(Unmarshaler)
162
+			}
163
+
164
+			return true, unmarshaler.UnmarshalFlag(val)
165
+		}
166
+	}
167
+
168
+	if retval.Type().Kind() != reflect.Ptr && retval.CanAddr() {
169
+		return convertUnmarshal(val, retval.Addr())
170
+	}
171
+
172
+	if retval.Type().Kind() == reflect.Interface && !retval.IsNil() {
173
+		return convertUnmarshal(val, retval.Elem())
174
+	}
175
+
176
+	return false, nil
177
+}
178
+
179
+func convert(val string, retval reflect.Value, options multiTag) error {
180
+	if ok, err := convertUnmarshal(val, retval); ok {
181
+		return err
182
+	}
183
+
184
+	tp := retval.Type()
185
+
186
+	// Support for time.Duration
187
+	if tp == reflect.TypeOf((*time.Duration)(nil)).Elem() {
188
+		parsed, err := time.ParseDuration(val)
189
+
190
+		if err != nil {
191
+			return err
192
+		}
193
+
194
+		retval.SetInt(int64(parsed))
195
+		return nil
196
+	}
197
+
198
+	switch tp.Kind() {
199
+	case reflect.String:
200
+		retval.SetString(val)
201
+	case reflect.Bool:
202
+		if val == "" {
203
+			retval.SetBool(true)
204
+		} else {
205
+			b, err := strconv.ParseBool(val)
206
+
207
+			if err != nil {
208
+				return err
209
+			}
210
+
211
+			retval.SetBool(b)
212
+		}
213
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
214
+		base, err := getBase(options, 10)
215
+
216
+		if err != nil {
217
+			return err
218
+		}
219
+
220
+		parsed, err := strconv.ParseInt(val, base, tp.Bits())
221
+
222
+		if err != nil {
223
+			return err
224
+		}
225
+
226
+		retval.SetInt(parsed)
227
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
228
+		base, err := getBase(options, 10)
229
+
230
+		if err != nil {
231
+			return err
232
+		}
233
+
234
+		parsed, err := strconv.ParseUint(val, base, tp.Bits())
235
+
236
+		if err != nil {
237
+			return err
238
+		}
239
+
240
+		retval.SetUint(parsed)
241
+	case reflect.Float32, reflect.Float64:
242
+		parsed, err := strconv.ParseFloat(val, tp.Bits())
243
+
244
+		if err != nil {
245
+			return err
246
+		}
247
+
248
+		retval.SetFloat(parsed)
249
+	case reflect.Slice:
250
+		elemtp := tp.Elem()
251
+
252
+		elemvalptr := reflect.New(elemtp)
253
+		elemval := reflect.Indirect(elemvalptr)
254
+
255
+		if err := convert(val, elemval, options); err != nil {
256
+			return err
257
+		}
258
+
259
+		retval.Set(reflect.Append(retval, elemval))
260
+	case reflect.Map:
261
+		parts := strings.SplitN(val, ":", 2)
262
+
263
+		key := parts[0]
264
+		var value string
265
+
266
+		if len(parts) == 2 {
267
+			value = parts[1]
268
+		}
269
+
270
+		keytp := tp.Key()
271
+		keyval := reflect.New(keytp)
272
+
273
+		if err := convert(key, keyval, options); err != nil {
274
+			return err
275
+		}
276
+
277
+		valuetp := tp.Elem()
278
+		valueval := reflect.New(valuetp)
279
+
280
+		if err := convert(value, valueval, options); err != nil {
281
+			return err
282
+		}
283
+
284
+		if retval.IsNil() {
285
+			retval.Set(reflect.MakeMap(tp))
286
+		}
287
+
288
+		retval.SetMapIndex(reflect.Indirect(keyval), reflect.Indirect(valueval))
289
+	case reflect.Ptr:
290
+		if retval.IsNil() {
291
+			retval.Set(reflect.New(retval.Type().Elem()))
292
+		}
293
+
294
+		return convert(val, reflect.Indirect(retval), options)
295
+	case reflect.Interface:
296
+		if !retval.IsNil() {
297
+			return convert(val, retval.Elem(), options)
298
+		}
299
+	}
300
+
301
+	return nil
302
+}
303
+
304
+func isPrint(s string) bool {
305
+	for _, c := range s {
306
+		if !strconv.IsPrint(c) {
307
+			return false
308
+		}
309
+	}
310
+
311
+	return true
312
+}
313
+
314
+func quoteIfNeeded(s string) string {
315
+	if !isPrint(s) {
316
+		return strconv.Quote(s)
317
+	}
318
+
319
+	return s
320
+}
321
+
322
+func quoteIfNeededV(s []string) []string {
323
+	ret := make([]string, len(s))
324
+
325
+	for i, v := range s {
326
+		ret[i] = quoteIfNeeded(v)
327
+	}
328
+
329
+	return ret
330
+}
331
+
332
+func quoteV(s []string) []string {
333
+	ret := make([]string, len(s))
334
+
335
+	for i, v := range s {
336
+		ret[i] = strconv.Quote(v)
337
+	}
338
+
339
+	return ret
340
+}
341
+
342
+func unquoteIfPossible(s string) (string, error) {
343
+	if len(s) == 0 || s[0] != '"' {
344
+		return s, nil
345
+	}
346
+
347
+	return strconv.Unquote(s)
348
+}

+ 159
- 0
vendor/src/github.com/jessevdk/go-flags/convert_test.go Datei anzeigen

@@ -0,0 +1,159 @@
1
+package flags
2
+
3
+import (
4
+	"testing"
5
+	"time"
6
+)
7
+
8
+func expectConvert(t *testing.T, o *Option, expected string) {
9
+	s, err := convertToString(o.value, o.tag)
10
+
11
+	if err != nil {
12
+		t.Errorf("Unexpected error: %v", err)
13
+		return
14
+	}
15
+
16
+	assertString(t, s, expected)
17
+}
18
+
19
+func TestConvertToString(t *testing.T) {
20
+	d, _ := time.ParseDuration("1h2m4s")
21
+
22
+	var opts = struct {
23
+		String string `long:"string"`
24
+
25
+		Int   int   `long:"int"`
26
+		Int8  int8  `long:"int8"`
27
+		Int16 int16 `long:"int16"`
28
+		Int32 int32 `long:"int32"`
29
+		Int64 int64 `long:"int64"`
30
+
31
+		Uint   uint   `long:"uint"`
32
+		Uint8  uint8  `long:"uint8"`
33
+		Uint16 uint16 `long:"uint16"`
34
+		Uint32 uint32 `long:"uint32"`
35
+		Uint64 uint64 `long:"uint64"`
36
+
37
+		Float32 float32 `long:"float32"`
38
+		Float64 float64 `long:"float64"`
39
+
40
+		Duration time.Duration `long:"duration"`
41
+
42
+		Bool bool `long:"bool"`
43
+
44
+		IntSlice    []int           `long:"int-slice"`
45
+		IntFloatMap map[int]float64 `long:"int-float-map"`
46
+
47
+		PtrBool   *bool       `long:"ptr-bool"`
48
+		Interface interface{} `long:"interface"`
49
+
50
+		Int32Base  int32  `long:"int32-base" base:"16"`
51
+		Uint32Base uint32 `long:"uint32-base" base:"16"`
52
+	}{
53
+		"string",
54
+
55
+		-2,
56
+		-1,
57
+		0,
58
+		1,
59
+		2,
60
+
61
+		1,
62
+		2,
63
+		3,
64
+		4,
65
+		5,
66
+
67
+		1.2,
68
+		-3.4,
69
+
70
+		d,
71
+		true,
72
+
73
+		[]int{-3, 4, -2},
74
+		map[int]float64{-2: 4.5},
75
+
76
+		new(bool),
77
+		float32(5.2),
78
+
79
+		-5823,
80
+		4232,
81
+	}
82
+
83
+	p := NewNamedParser("test", Default)
84
+	grp, _ := p.AddGroup("test group", "", &opts)
85
+
86
+	expects := []string{
87
+		"string",
88
+		"-2",
89
+		"-1",
90
+		"0",
91
+		"1",
92
+		"2",
93
+
94
+		"1",
95
+		"2",
96
+		"3",
97
+		"4",
98
+		"5",
99
+
100
+		"1.2",
101
+		"-3.4",
102
+
103
+		"1h2m4s",
104
+		"true",
105
+
106
+		"[-3, 4, -2]",
107
+		"{-2:4.5}",
108
+
109
+		"false",
110
+		"5.2",
111
+
112
+		"-16bf",
113
+		"1088",
114
+	}
115
+
116
+	for i, v := range grp.Options() {
117
+		expectConvert(t, v, expects[i])
118
+	}
119
+}
120
+
121
+func TestConvertToStringInvalidIntBase(t *testing.T) {
122
+	var opts = struct {
123
+		Int int `long:"int" base:"no"`
124
+	}{
125
+		2,
126
+	}
127
+
128
+	p := NewNamedParser("test", Default)
129
+	grp, _ := p.AddGroup("test group", "", &opts)
130
+	o := grp.Options()[0]
131
+
132
+	_, err := convertToString(o.value, o.tag)
133
+
134
+	if err != nil {
135
+		err = newErrorf(ErrMarshal, "%v", err)
136
+	}
137
+
138
+	assertError(t, err, ErrMarshal, "strconv.ParseInt: parsing \"no\": invalid syntax")
139
+}
140
+
141
+func TestConvertToStringInvalidUintBase(t *testing.T) {
142
+	var opts = struct {
143
+		Uint uint `long:"uint" base:"no"`
144
+	}{
145
+		2,
146
+	}
147
+
148
+	p := NewNamedParser("test", Default)
149
+	grp, _ := p.AddGroup("test group", "", &opts)
150
+	o := grp.Options()[0]
151
+
152
+	_, err := convertToString(o.value, o.tag)
153
+
154
+	if err != nil {
155
+		err = newErrorf(ErrMarshal, "%v", err)
156
+	}
157
+
158
+	assertError(t, err, ErrMarshal, "strconv.ParseInt: parsing \"no\": invalid syntax")
159
+}

+ 134
- 0
vendor/src/github.com/jessevdk/go-flags/error.go Datei anzeigen

@@ -0,0 +1,134 @@
1
+package flags
2
+
3
+import (
4
+	"fmt"
5
+)
6
+
7
+// ErrorType represents the type of error.
8
+type ErrorType uint
9
+
10
+const (
11
+	// ErrUnknown indicates a generic error.
12
+	ErrUnknown ErrorType = iota
13
+
14
+	// ErrExpectedArgument indicates that an argument was expected.
15
+	ErrExpectedArgument
16
+
17
+	// ErrUnknownFlag indicates an unknown flag.
18
+	ErrUnknownFlag
19
+
20
+	// ErrUnknownGroup indicates an unknown group.
21
+	ErrUnknownGroup
22
+
23
+	// ErrMarshal indicates a marshalling error while converting values.
24
+	ErrMarshal
25
+
26
+	// ErrHelp indicates that the built-in help was shown (the error
27
+	// contains the help message).
28
+	ErrHelp
29
+
30
+	// ErrNoArgumentForBool indicates that an argument was given for a
31
+	// boolean flag (which don't not take any arguments).
32
+	ErrNoArgumentForBool
33
+
34
+	// ErrRequired indicates that a required flag was not provided.
35
+	ErrRequired
36
+
37
+	// ErrShortNameTooLong indicates that a short flag name was specified,
38
+	// longer than one character.
39
+	ErrShortNameTooLong
40
+
41
+	// ErrDuplicatedFlag indicates that a short or long flag has been
42
+	// defined more than once
43
+	ErrDuplicatedFlag
44
+
45
+	// ErrTag indicates an error while parsing flag tags.
46
+	ErrTag
47
+
48
+	// ErrCommandRequired indicates that a command was required but not
49
+	// specified
50
+	ErrCommandRequired
51
+
52
+	// ErrUnknownCommand indicates that an unknown command was specified.
53
+	ErrUnknownCommand
54
+
55
+	// ErrInvalidChoice indicates an invalid option value which only allows
56
+	// a certain number of choices.
57
+	ErrInvalidChoice
58
+
59
+	// ErrInvalidTag indicates an invalid tag or invalid use of an existing tag
60
+	ErrInvalidTag
61
+)
62
+
63
+func (e ErrorType) String() string {
64
+	switch e {
65
+	case ErrUnknown:
66
+		return "unknown"
67
+	case ErrExpectedArgument:
68
+		return "expected argument"
69
+	case ErrUnknownFlag:
70
+		return "unknown flag"
71
+	case ErrUnknownGroup:
72
+		return "unknown group"
73
+	case ErrMarshal:
74
+		return "marshal"
75
+	case ErrHelp:
76
+		return "help"
77
+	case ErrNoArgumentForBool:
78
+		return "no argument for bool"
79
+	case ErrRequired:
80
+		return "required"
81
+	case ErrShortNameTooLong:
82
+		return "short name too long"
83
+	case ErrDuplicatedFlag:
84
+		return "duplicated flag"
85
+	case ErrTag:
86
+		return "tag"
87
+	case ErrCommandRequired:
88
+		return "command required"
89
+	case ErrUnknownCommand:
90
+		return "unknown command"
91
+	case ErrInvalidChoice:
92
+		return "invalid choice"
93
+	case ErrInvalidTag:
94
+		return "invalid tag"
95
+	}
96
+
97
+	return "unrecognized error type"
98
+}
99
+
100
+// Error represents a parser error. The error returned from Parse is of this
101
+// type. The error contains both a Type and Message.
102
+type Error struct {
103
+	// The type of error
104
+	Type ErrorType
105
+
106
+	// The error message
107
+	Message string
108
+}
109
+
110
+// Error returns the error's message
111
+func (e *Error) Error() string {
112
+	return e.Message
113
+}
114
+
115
+func newError(tp ErrorType, message string) *Error {
116
+	return &Error{
117
+		Type:    tp,
118
+		Message: message,
119
+	}
120
+}
121
+
122
+func newErrorf(tp ErrorType, format string, args ...interface{}) *Error {
123
+	return newError(tp, fmt.Sprintf(format, args...))
124
+}
125
+
126
+func wrapError(err error) *Error {
127
+	ret, ok := err.(*Error)
128
+
129
+	if !ok {
130
+		return newError(ErrUnknown, err.Error())
131
+	}
132
+
133
+	return ret
134
+}

+ 110
- 0
vendor/src/github.com/jessevdk/go-flags/example_test.go Datei anzeigen

@@ -0,0 +1,110 @@
1
+// Example of use of the flags package.
2
+package flags
3
+
4
+import (
5
+	"fmt"
6
+	"os/exec"
7
+)
8
+
9
+func Example() {
10
+	var opts struct {
11
+		// Slice of bool will append 'true' each time the option
12
+		// is encountered (can be set multiple times, like -vvv)
13
+		Verbose []bool `short:"v" long:"verbose" description:"Show verbose debug information"`
14
+
15
+		// Example of automatic marshalling to desired type (uint)
16
+		Offset uint `long:"offset" description:"Offset"`
17
+
18
+		// Example of a callback, called each time the option is found.
19
+		Call func(string) `short:"c" description:"Call phone number"`
20
+
21
+		// Example of a required flag
22
+		Name string `short:"n" long:"name" description:"A name" required:"true"`
23
+
24
+		// Example of a value name
25
+		File string `short:"f" long:"file" description:"A file" value-name:"FILE"`
26
+
27
+		// Example of a pointer
28
+		Ptr *int `short:"p" description:"A pointer to an integer"`
29
+
30
+		// Example of a slice of strings
31
+		StringSlice []string `short:"s" description:"A slice of strings"`
32
+
33
+		// Example of a slice of pointers
34
+		PtrSlice []*string `long:"ptrslice" description:"A slice of pointers to string"`
35
+
36
+		// Example of a map
37
+		IntMap map[string]int `long:"intmap" description:"A map from string to int"`
38
+
39
+		// Example of a filename (useful for completion)
40
+		Filename Filename `long:"filename" description:"A filename"`
41
+
42
+		// Example of positional arguments
43
+		Args struct {
44
+			ID   string
45
+			Num  int
46
+			Rest []string
47
+		} `positional-args:"yes" required:"yes"`
48
+	}
49
+
50
+	// Callback which will invoke callto:<argument> to call a number.
51
+	// Note that this works just on OS X (and probably only with
52
+	// Skype) but it shows the idea.
53
+	opts.Call = func(num string) {
54
+		cmd := exec.Command("open", "callto:"+num)
55
+		cmd.Start()
56
+		cmd.Process.Release()
57
+	}
58
+
59
+	// Make some fake arguments to parse.
60
+	args := []string{
61
+		"-vv",
62
+		"--offset=5",
63
+		"-n", "Me",
64
+		"-p", "3",
65
+		"-s", "hello",
66
+		"-s", "world",
67
+		"--ptrslice", "hello",
68
+		"--ptrslice", "world",
69
+		"--intmap", "a:1",
70
+		"--intmap", "b:5",
71
+		"--filename", "hello.go",
72
+		"id",
73
+		"10",
74
+		"remaining1",
75
+		"remaining2",
76
+	}
77
+
78
+	// Parse flags from `args'. Note that here we use flags.ParseArgs for
79
+	// the sake of making a working example. Normally, you would simply use
80
+	// flags.Parse(&opts) which uses os.Args
81
+	_, err := ParseArgs(&opts, args)
82
+
83
+	if err != nil {
84
+		panic(err)
85
+	}
86
+
87
+	fmt.Printf("Verbosity: %v\n", opts.Verbose)
88
+	fmt.Printf("Offset: %d\n", opts.Offset)
89
+	fmt.Printf("Name: %s\n", opts.Name)
90
+	fmt.Printf("Ptr: %d\n", *opts.Ptr)
91
+	fmt.Printf("StringSlice: %v\n", opts.StringSlice)
92
+	fmt.Printf("PtrSlice: [%v %v]\n", *opts.PtrSlice[0], *opts.PtrSlice[1])
93
+	fmt.Printf("IntMap: [a:%v b:%v]\n", opts.IntMap["a"], opts.IntMap["b"])
94
+	fmt.Printf("Filename: %v\n", opts.Filename)
95
+	fmt.Printf("Args.ID: %s\n", opts.Args.ID)
96
+	fmt.Printf("Args.Num: %d\n", opts.Args.Num)
97
+	fmt.Printf("Args.Rest: %v\n", opts.Args.Rest)
98
+
99
+	// Output: Verbosity: [true true]
100
+	// Offset: 5
101
+	// Name: Me
102
+	// Ptr: 3
103
+	// StringSlice: [hello world]
104
+	// PtrSlice: [hello world]
105
+	// IntMap: [a:1 b:5]
106
+	// Filename: hello.go
107
+	// Args.ID: id
108
+	// Args.Num: 10
109
+	// Args.Rest: [remaining1 remaining2]
110
+}

+ 23
- 0
vendor/src/github.com/jessevdk/go-flags/examples/add.go Datei anzeigen

@@ -0,0 +1,23 @@
1
+package main
2
+
3
+import (
4
+	"fmt"
5
+)
6
+
7
+type AddCommand struct {
8
+	All bool `short:"a" long:"all" description:"Add all files"`
9
+}
10
+
11
+var addCommand AddCommand
12
+
13
+func (x *AddCommand) Execute(args []string) error {
14
+	fmt.Printf("Adding (all=%v): %#v\n", x.All, args)
15
+	return nil
16
+}
17
+
18
+func init() {
19
+	parser.AddCommand("add",
20
+		"Add a file",
21
+		"The add command adds a file to the repository. Use -a to add all files.",
22
+		&addCommand)
23
+}

+ 9
- 0
vendor/src/github.com/jessevdk/go-flags/examples/bash-completion Datei anzeigen

@@ -0,0 +1,9 @@
1
+_examples() {
2
+	args=("${COMP_WORDS[@]:1:$COMP_CWORD}")
3
+
4
+	local IFS=$'\n'
5
+	COMPREPLY=($(GO_FLAGS_COMPLETION=1 ${COMP_WORDS[0]} "${args[@]}"))
6
+	return 1
7
+}
8
+
9
+complete -F _examples examples

+ 79
- 0
vendor/src/github.com/jessevdk/go-flags/examples/main.go Datei anzeigen

@@ -0,0 +1,79 @@
1
+package main
2
+
3
+import (
4
+	"errors"
5
+	"fmt"
6
+	"github.com/jessevdk/go-flags"
7
+	"os"
8
+	"strconv"
9
+	"strings"
10
+)
11
+
12
+type EditorOptions struct {
13
+	Input  flags.Filename `short:"i" long:"input" description:"Input file" default:"-"`
14
+	Output flags.Filename `short:"o" long:"output" description:"Output file" default:"-"`
15
+}
16
+
17
+type Point struct {
18
+	X, Y int
19
+}
20
+
21
+func (p *Point) UnmarshalFlag(value string) error {
22
+	parts := strings.Split(value, ",")
23
+
24
+	if len(parts) != 2 {
25
+		return errors.New("expected two numbers separated by a ,")
26
+	}
27
+
28
+	x, err := strconv.ParseInt(parts[0], 10, 32)
29
+
30
+	if err != nil {
31
+		return err
32
+	}
33
+
34
+	y, err := strconv.ParseInt(parts[1], 10, 32)
35
+
36
+	if err != nil {
37
+		return err
38
+	}
39
+
40
+	p.X = int(x)
41
+	p.Y = int(y)
42
+
43
+	return nil
44
+}
45
+
46
+func (p Point) MarshalFlag() (string, error) {
47
+	return fmt.Sprintf("%d,%d", p.X, p.Y), nil
48
+}
49
+
50
+type Options struct {
51
+	// Example of verbosity with level
52
+	Verbose []bool `short:"v" long:"verbose" description:"Verbose output"`
53
+
54
+	// Example of optional value
55
+	User string `short:"u" long:"user" description:"User name" optional:"yes" optional-value:"pancake"`
56
+
57
+	// Example of map with multiple default values
58
+	Users map[string]string `long:"users" description:"User e-mail map" default:"system:system@example.org" default:"admin:admin@example.org"`
59
+
60
+	// Example of option group
61
+	Editor EditorOptions `group:"Editor Options"`
62
+
63
+	// Example of custom type Marshal/Unmarshal
64
+	Point Point `long:"point" description:"A x,y point" default:"1,2"`
65
+}
66
+
67
+var options Options
68
+
69
+var parser = flags.NewParser(&options, flags.Default)
70
+
71
+func main() {
72
+	if _, err := parser.Parse(); err != nil {
73
+		if flagsErr, ok := err.(*flags.Error); ok && flagsErr.Type == flags.ErrHelp {
74
+			os.Exit(0)
75
+		} else {
76
+			os.Exit(1)
77
+		}
78
+	}
79
+}

+ 23
- 0
vendor/src/github.com/jessevdk/go-flags/examples/rm.go Datei anzeigen

@@ -0,0 +1,23 @@
1
+package main
2
+
3
+import (
4
+	"fmt"
5
+)
6
+
7
+type RmCommand struct {
8
+	Force bool `short:"f" long:"force" description:"Force removal of files"`
9
+}
10
+
11
+var rmCommand RmCommand
12
+
13
+func (x *RmCommand) Execute(args []string) error {
14
+	fmt.Printf("Removing (force=%v): %#v\n", x.Force, args)
15
+	return nil
16
+}
17
+
18
+func init() {
19
+	parser.AddCommand("rm",
20
+		"Remove a file",
21
+		"The rm command removes a file to the repository. Use -f to force removal of files.",
22
+		&rmCommand)
23
+}

+ 258
- 0
vendor/src/github.com/jessevdk/go-flags/flags.go Datei anzeigen

@@ -0,0 +1,258 @@
1
+// Copyright 2012 Jesse van den Kieboom. 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
+/*
6
+Package flags provides an extensive command line option parser.
7
+The flags package is similar in functionality to the go built-in flag package
8
+but provides more options and uses reflection to provide a convenient and
9
+succinct way of specifying command line options.
10
+
11
+
12
+Supported features
13
+
14
+The following features are supported in go-flags:
15
+
16
+    Options with short names (-v)
17
+    Options with long names (--verbose)
18
+    Options with and without arguments (bool v.s. other type)
19
+    Options with optional arguments and default values
20
+    Option default values from ENVIRONMENT_VARIABLES, including slice and map values
21
+    Multiple option groups each containing a set of options
22
+    Generate and print well-formatted help message
23
+    Passing remaining command line arguments after -- (optional)
24
+    Ignoring unknown command line options (optional)
25
+    Supports -I/usr/include -I=/usr/include -I /usr/include option argument specification
26
+    Supports multiple short options -aux
27
+    Supports all primitive go types (string, int{8..64}, uint{8..64}, float)
28
+    Supports same option multiple times (can store in slice or last option counts)
29
+    Supports maps
30
+    Supports function callbacks
31
+    Supports namespaces for (nested) option groups
32
+
33
+Additional features specific to Windows:
34
+    Options with short names (/v)
35
+    Options with long names (/verbose)
36
+    Windows-style options with arguments use a colon as the delimiter
37
+    Modify generated help message with Windows-style / options
38
+    Windows style options can be disabled at build time using the "forceposix"
39
+    build tag
40
+
41
+
42
+Basic usage
43
+
44
+The flags package uses structs, reflection and struct field tags
45
+to allow users to specify command line options. This results in very simple
46
+and concise specification of your application options. For example:
47
+
48
+    type Options struct {
49
+        Verbose []bool `short:"v" long:"verbose" description:"Show verbose debug information"`
50
+    }
51
+
52
+This specifies one option with a short name -v and a long name --verbose.
53
+When either -v or --verbose is found on the command line, a 'true' value
54
+will be appended to the Verbose field. e.g. when specifying -vvv, the
55
+resulting value of Verbose will be {[true, true, true]}.
56
+
57
+Slice options work exactly the same as primitive type options, except that
58
+whenever the option is encountered, a value is appended to the slice.
59
+
60
+Map options from string to primitive type are also supported. On the command
61
+line, you specify the value for such an option as key:value. For example
62
+
63
+    type Options struct {
64
+        AuthorInfo string[string] `short:"a"`
65
+    }
66
+
67
+Then, the AuthorInfo map can be filled with something like
68
+-a name:Jesse -a "surname:van den Kieboom".
69
+
70
+Finally, for full control over the conversion between command line argument
71
+values and options, user defined types can choose to implement the Marshaler
72
+and Unmarshaler interfaces.
73
+
74
+
75
+Available field tags
76
+
77
+The following is a list of tags for struct fields supported by go-flags:
78
+
79
+    short:            the short name of the option (single character)
80
+    long:             the long name of the option
81
+    required:         if non empty, makes the option required to appear on the command
82
+                      line. If a required option is not present, the parser will
83
+                      return ErrRequired (optional)
84
+    description:      the description of the option (optional)
85
+    long-description: the long description of the option. Currently only
86
+                      displayed in generated man pages (optional)
87
+    no-flag:          if non-empty, this field is ignored as an option (optional)
88
+
89
+    optional:       if non-empty, makes the argument of the option optional. When an
90
+                    argument is optional it can only be specified using
91
+                    --option=argument (optional)
92
+    optional-value: the value of an optional option when the option occurs
93
+                    without an argument. This tag can be specified multiple
94
+                    times in the case of maps or slices (optional)
95
+    default:        the default value of an option. This tag can be specified
96
+                    multiple times in the case of slices or maps (optional)
97
+    default-mask:   when specified, this value will be displayed in the help
98
+                    instead of the actual default value. This is useful
99
+                    mostly for hiding otherwise sensitive information from
100
+                    showing up in the help. If default-mask takes the special
101
+                    value "-", then no default value will be shown at all
102
+                    (optional)
103
+    env:            the default value of the option is overridden from the
104
+                    specified environment variable, if one has been defined.
105
+                    (optional)
106
+    env-delim:      the 'env' default value from environment is split into
107
+                    multiple values with the given delimiter string, use with
108
+                    slices and maps (optional)
109
+    value-name:     the name of the argument value (to be shown in the help)
110
+                    (optional)
111
+    choice:         limits the values for an option to a set of values.
112
+                    This tag can be specified multiple times (optional)
113
+    hidden:         if non-empty, the option is not visible in the help or man page.
114
+
115
+    base: a base (radix) used to convert strings to integer values, the
116
+          default base is 10 (i.e. decimal) (optional)
117
+
118
+    ini-name:       the explicit ini option name (optional)
119
+    no-ini:         if non-empty this field is ignored as an ini option
120
+                    (optional)
121
+
122
+    group:                when specified on a struct field, makes the struct
123
+                          field a separate group with the given name (optional)
124
+    namespace:            when specified on a group struct field, the namespace
125
+                          gets prepended to every option's long name and
126
+                          subgroup's namespace of this group, separated by
127
+                          the parser's namespace delimiter (optional)
128
+    command:              when specified on a struct field, makes the struct
129
+                          field a (sub)command with the given name (optional)
130
+    subcommands-optional: when specified on a command struct field, makes
131
+                          any subcommands of that command optional (optional)
132
+    alias:                when specified on a command struct field, adds the
133
+                          specified name as an alias for the command. Can be
134
+                          be specified multiple times to add more than one
135
+                          alias (optional)
136
+    positional-args:      when specified on a field with a struct type,
137
+                          uses the fields of that struct to parse remaining
138
+                          positional command line arguments into (in order
139
+                          of the fields). If a field has a slice type,
140
+                          then all remaining arguments will be added to it.
141
+                          Positional arguments are optional by default,
142
+                          unless the "required" tag is specified together
143
+                          with the "positional-args" tag. The "required" tag
144
+                          can also be set on the individual rest argument
145
+                          fields, to require only the first N positional
146
+                          arguments. If the "required" tag is set on the
147
+                          rest arguments slice, then its value determines
148
+                          the minimum amount of rest arguments that needs to
149
+                          be provided (e.g. `required:"2"`) (optional)
150
+    positional-arg-name:  used on a field in a positional argument struct; name
151
+                          of the positional argument placeholder to be shown in
152
+                          the help (optional)
153
+
154
+Either the `short:` tag or the `long:` must be specified to make the field eligible as an
155
+option.
156
+
157
+
158
+Option groups
159
+
160
+Option groups are a simple way to semantically separate your options. All
161
+options in a particular group are shown together in the help under the name
162
+of the group. Namespaces can be used to specify option long names more
163
+precisely and emphasize the options affiliation to their group.
164
+
165
+There are currently three ways to specify option groups.
166
+
167
+    1. Use NewNamedParser specifying the various option groups.
168
+    2. Use AddGroup to add a group to an existing parser.
169
+    3. Add a struct field to the top-level options annotated with the
170
+       group:"group-name" tag.
171
+
172
+
173
+
174
+Commands
175
+
176
+The flags package also has basic support for commands. Commands are often
177
+used in monolithic applications that support various commands or actions.
178
+Take git for example, all of the add, commit, checkout, etc. are called
179
+commands. Using commands you can easily separate multiple functions of your
180
+application.
181
+
182
+There are currently two ways to specify a command.
183
+
184
+    1. Use AddCommand on an existing parser.
185
+    2. Add a struct field to your options struct annotated with the
186
+       command:"command-name" tag.
187
+
188
+The most common, idiomatic way to implement commands is to define a global
189
+parser instance and implement each command in a separate file. These
190
+command files should define a go init function which calls AddCommand on
191
+the global parser.
192
+
193
+When parsing ends and there is an active command and that command implements
194
+the Commander interface, then its Execute method will be run with the
195
+remaining command line arguments.
196
+
197
+Command structs can have options which become valid to parse after the
198
+command has been specified on the command line, in addition to the options
199
+of all the parent commands. I.e. considering a -v flag on the parser and an
200
+add command, the following are equivalent:
201
+
202
+    ./app -v add
203
+    ./app add -v
204
+
205
+However, if the -v flag is defined on the add command, then the first of
206
+the two examples above would fail since the -v flag is not defined before
207
+the add command.
208
+
209
+
210
+Completion
211
+
212
+go-flags has builtin support to provide bash completion of flags, commands
213
+and argument values. To use completion, the binary which uses go-flags
214
+can be invoked in a special environment to list completion of the current
215
+command line argument. It should be noted that this `executes` your application,
216
+and it is up to the user to make sure there are no negative side effects (for
217
+example from init functions).
218
+
219
+Setting the environment variable `GO_FLAGS_COMPLETION=1` enables completion
220
+by replacing the argument parsing routine with the completion routine which
221
+outputs completions for the passed arguments. The basic invocation to
222
+complete a set of arguments is therefore:
223
+
224
+    GO_FLAGS_COMPLETION=1 ./completion-example arg1 arg2 arg3
225
+
226
+where `completion-example` is the binary, `arg1` and `arg2` are
227
+the current arguments, and `arg3` (the last argument) is the argument
228
+to be completed. If the GO_FLAGS_COMPLETION is set to "verbose", then
229
+descriptions of possible completion items will also be shown, if there
230
+are more than 1 completion items.
231
+
232
+To use this with bash completion, a simple file can be written which
233
+calls the binary which supports go-flags completion:
234
+
235
+    _completion_example() {
236
+        # All arguments except the first one
237
+        args=("${COMP_WORDS[@]:1:$COMP_CWORD}")
238
+
239
+        # Only split on newlines
240
+        local IFS=$'\n'
241
+
242
+        # Call completion (note that the first element of COMP_WORDS is
243
+        # the executable itself)
244
+        COMPREPLY=($(GO_FLAGS_COMPLETION=1 ${COMP_WORDS[0]} "${args[@]}"))
245
+        return 0
246
+    }
247
+
248
+    complete -F _completion_example completion-example
249
+
250
+Completion requires the parser option PassDoubleDash and is therefore enforced if the environment variable GO_FLAGS_COMPLETION is set.
251
+
252
+Customized completion for argument values is supported by implementing
253
+the flags.Completer interface for the argument value type. An example
254
+of a type which does so is the flags.Filename type, an alias of string
255
+allowing simple filename completion. A slice or array argument value
256
+whose element type implements flags.Completer will also be completed.
257
+*/
258
+package flags

+ 406
- 0
vendor/src/github.com/jessevdk/go-flags/group.go Datei anzeigen

@@ -0,0 +1,406 @@
1
+// Copyright 2012 Jesse van den Kieboom. 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 flags
6
+
7
+import (
8
+	"errors"
9
+	"reflect"
10
+	"strings"
11
+	"unicode/utf8"
12
+)
13
+
14
+// ErrNotPointerToStruct indicates that a provided data container is not
15
+// a pointer to a struct. Only pointers to structs are valid data containers
16
+// for options.
17
+var ErrNotPointerToStruct = errors.New("provided data is not a pointer to struct")
18
+
19
+// Group represents an option group. Option groups can be used to logically
20
+// group options together under a description. Groups are only used to provide
21
+// more structure to options both for the user (as displayed in the help message)
22
+// and for you, since groups can be nested.
23
+type Group struct {
24
+	// A short description of the group. The
25
+	// short description is primarily used in the built-in generated help
26
+	// message
27
+	ShortDescription string
28
+
29
+	// A long description of the group. The long
30
+	// description is primarily used to present information on commands
31
+	// (Command embeds Group) in the built-in generated help and man pages.
32
+	LongDescription string
33
+
34
+	// The namespace of the group
35
+	Namespace string
36
+
37
+	// If true, the group is not displayed in the help or man page
38
+	Hidden bool
39
+
40
+	// The parent of the group or nil if it has no parent
41
+	parent interface{}
42
+
43
+	// All the options in the group
44
+	options []*Option
45
+
46
+	// All the subgroups
47
+	groups []*Group
48
+
49
+	// Whether the group represents the built-in help group
50
+	isBuiltinHelp bool
51
+
52
+	data interface{}
53
+}
54
+
55
+type scanHandler func(reflect.Value, *reflect.StructField) (bool, error)
56
+
57
+// AddGroup adds a new group to the command with the given name and data. The
58
+// data needs to be a pointer to a struct from which the fields indicate which
59
+// options are in the group.
60
+func (g *Group) AddGroup(shortDescription string, longDescription string, data interface{}) (*Group, error) {
61
+	group := newGroup(shortDescription, longDescription, data)
62
+
63
+	group.parent = g
64
+
65
+	if err := group.scan(); err != nil {
66
+		return nil, err
67
+	}
68
+
69
+	g.groups = append(g.groups, group)
70
+	return group, nil
71
+}
72
+
73
+// Groups returns the list of groups embedded in this group.
74
+func (g *Group) Groups() []*Group {
75
+	return g.groups
76
+}
77
+
78
+// Options returns the list of options in this group.
79
+func (g *Group) Options() []*Option {
80
+	return g.options
81
+}
82
+
83
+// Find locates the subgroup with the given short description and returns it.
84
+// If no such group can be found Find will return nil. Note that the description
85
+// is matched case insensitively.
86
+func (g *Group) Find(shortDescription string) *Group {
87
+	lshortDescription := strings.ToLower(shortDescription)
88
+
89
+	var ret *Group
90
+
91
+	g.eachGroup(func(gg *Group) {
92
+		if gg != g && strings.ToLower(gg.ShortDescription) == lshortDescription {
93
+			ret = gg
94
+		}
95
+	})
96
+
97
+	return ret
98
+}
99
+
100
+func (g *Group) findOption(matcher func(*Option) bool) (option *Option) {
101
+	g.eachGroup(func(g *Group) {
102
+		for _, opt := range g.options {
103
+			if option == nil && matcher(opt) {
104
+				option = opt
105
+			}
106
+		}
107
+	})
108
+
109
+	return option
110
+}
111
+
112
+// FindOptionByLongName finds an option that is part of the group, or any of its
113
+// subgroups, by matching its long name (including the option namespace).
114
+func (g *Group) FindOptionByLongName(longName string) *Option {
115
+	return g.findOption(func(option *Option) bool {
116
+		return option.LongNameWithNamespace() == longName
117
+	})
118
+}
119
+
120
+// FindOptionByShortName finds an option that is part of the group, or any of
121
+// its subgroups, by matching its short name.
122
+func (g *Group) FindOptionByShortName(shortName rune) *Option {
123
+	return g.findOption(func(option *Option) bool {
124
+		return option.ShortName == shortName
125
+	})
126
+}
127
+
128
+func newGroup(shortDescription string, longDescription string, data interface{}) *Group {
129
+	return &Group{
130
+		ShortDescription: shortDescription,
131
+		LongDescription:  longDescription,
132
+
133
+		data: data,
134
+	}
135
+}
136
+
137
+func (g *Group) optionByName(name string, namematch func(*Option, string) bool) *Option {
138
+	prio := 0
139
+	var retopt *Option
140
+
141
+	g.eachGroup(func(g *Group) {
142
+		for _, opt := range g.options {
143
+			if namematch != nil && namematch(opt, name) && prio < 4 {
144
+				retopt = opt
145
+				prio = 4
146
+			}
147
+
148
+			if name == opt.field.Name && prio < 3 {
149
+				retopt = opt
150
+				prio = 3
151
+			}
152
+
153
+			if name == opt.LongNameWithNamespace() && prio < 2 {
154
+				retopt = opt
155
+				prio = 2
156
+			}
157
+
158
+			if opt.ShortName != 0 && name == string(opt.ShortName) && prio < 1 {
159
+				retopt = opt
160
+				prio = 1
161
+			}
162
+		}
163
+	})
164
+
165
+	return retopt
166
+}
167
+
168
+func (g *Group) eachGroup(f func(*Group)) {
169
+	f(g)
170
+
171
+	for _, gg := range g.groups {
172
+		gg.eachGroup(f)
173
+	}
174
+}
175
+
176
+func isStringFalsy(s string) bool {
177
+	return s == "" || s == "false" || s == "no" || s == "0"
178
+}
179
+
180
+func (g *Group) scanStruct(realval reflect.Value, sfield *reflect.StructField, handler scanHandler) error {
181
+	stype := realval.Type()
182
+
183
+	if sfield != nil {
184
+		if ok, err := handler(realval, sfield); err != nil {
185
+			return err
186
+		} else if ok {
187
+			return nil
188
+		}
189
+	}
190
+
191
+	for i := 0; i < stype.NumField(); i++ {
192
+		field := stype.Field(i)
193
+
194
+		// PkgName is set only for non-exported fields, which we ignore
195
+		if field.PkgPath != "" && !field.Anonymous {
196
+			continue
197
+		}
198
+
199
+		mtag := newMultiTag(string(field.Tag))
200
+
201
+		if err := mtag.Parse(); err != nil {
202
+			return err
203
+		}
204
+
205
+		// Skip fields with the no-flag tag
206
+		if mtag.Get("no-flag") != "" {
207
+			continue
208
+		}
209
+
210
+		// Dive deep into structs or pointers to structs
211
+		kind := field.Type.Kind()
212
+		fld := realval.Field(i)
213
+
214
+		if kind == reflect.Struct {
215
+			if err := g.scanStruct(fld, &field, handler); err != nil {
216
+				return err
217
+			}
218
+		} else if kind == reflect.Ptr && field.Type.Elem().Kind() == reflect.Struct {
219
+			flagCountBefore := len(g.options) + len(g.groups)
220
+
221
+			if fld.IsNil() {
222
+				fld = reflect.New(fld.Type().Elem())
223
+			}
224
+
225
+			if err := g.scanStruct(reflect.Indirect(fld), &field, handler); err != nil {
226
+				return err
227
+			}
228
+
229
+			if len(g.options)+len(g.groups) != flagCountBefore {
230
+				realval.Field(i).Set(fld)
231
+			}
232
+		}
233
+
234
+		longname := mtag.Get("long")
235
+		shortname := mtag.Get("short")
236
+
237
+		// Need at least either a short or long name
238
+		if longname == "" && shortname == "" && mtag.Get("ini-name") == "" {
239
+			continue
240
+		}
241
+
242
+		short := rune(0)
243
+		rc := utf8.RuneCountInString(shortname)
244
+
245
+		if rc > 1 {
246
+			return newErrorf(ErrShortNameTooLong,
247
+				"short names can only be 1 character long, not `%s'",
248
+				shortname)
249
+
250
+		} else if rc == 1 {
251
+			short, _ = utf8.DecodeRuneInString(shortname)
252
+		}
253
+
254
+		description := mtag.Get("description")
255
+		def := mtag.GetMany("default")
256
+
257
+		optionalValue := mtag.GetMany("optional-value")
258
+		valueName := mtag.Get("value-name")
259
+		defaultMask := mtag.Get("default-mask")
260
+
261
+		optional := !isStringFalsy(mtag.Get("optional"))
262
+		required := !isStringFalsy(mtag.Get("required"))
263
+		choices := mtag.GetMany("choice")
264
+		hidden := !isStringFalsy(mtag.Get("hidden"))
265
+
266
+		option := &Option{
267
+			Description:      description,
268
+			ShortName:        short,
269
+			LongName:         longname,
270
+			Default:          def,
271
+			EnvDefaultKey:    mtag.Get("env"),
272
+			EnvDefaultDelim:  mtag.Get("env-delim"),
273
+			OptionalArgument: optional,
274
+			OptionalValue:    optionalValue,
275
+			Required:         required,
276
+			ValueName:        valueName,
277
+			DefaultMask:      defaultMask,
278
+			Choices:          choices,
279
+			Hidden:           hidden,
280
+
281
+			group: g,
282
+
283
+			field: field,
284
+			value: realval.Field(i),
285
+			tag:   mtag,
286
+		}
287
+
288
+		if option.isBool() && option.Default != nil {
289
+			return newErrorf(ErrInvalidTag,
290
+				"boolean flag `%s' may not have default values, they always default to `false' and can only be turned on",
291
+				option.shortAndLongName())
292
+		}
293
+
294
+		g.options = append(g.options, option)
295
+	}
296
+
297
+	return nil
298
+}
299
+
300
+func (g *Group) checkForDuplicateFlags() *Error {
301
+	shortNames := make(map[rune]*Option)
302
+	longNames := make(map[string]*Option)
303
+
304
+	var duplicateError *Error
305
+
306
+	g.eachGroup(func(g *Group) {
307
+		for _, option := range g.options {
308
+			if option.LongName != "" {
309
+				longName := option.LongNameWithNamespace()
310
+
311
+				if otherOption, ok := longNames[longName]; ok {
312
+					duplicateError = newErrorf(ErrDuplicatedFlag, "option `%s' uses the same long name as option `%s'", option, otherOption)
313
+					return
314
+				}
315
+				longNames[longName] = option
316
+			}
317
+			if option.ShortName != 0 {
318
+				if otherOption, ok := shortNames[option.ShortName]; ok {
319
+					duplicateError = newErrorf(ErrDuplicatedFlag, "option `%s' uses the same short name as option `%s'", option, otherOption)
320
+					return
321
+				}
322
+				shortNames[option.ShortName] = option
323
+			}
324
+		}
325
+	})
326
+
327
+	return duplicateError
328
+}
329
+
330
+func (g *Group) scanSubGroupHandler(realval reflect.Value, sfield *reflect.StructField) (bool, error) {
331
+	mtag := newMultiTag(string(sfield.Tag))
332
+
333
+	if err := mtag.Parse(); err != nil {
334
+		return true, err
335
+	}
336
+
337
+	subgroup := mtag.Get("group")
338
+
339
+	if len(subgroup) != 0 {
340
+		var ptrval reflect.Value
341
+
342
+		if realval.Kind() == reflect.Ptr {
343
+			ptrval = realval
344
+
345
+			if ptrval.IsNil() {
346
+				ptrval.Set(reflect.New(ptrval.Type()))
347
+			}
348
+		} else {
349
+			ptrval = realval.Addr()
350
+		}
351
+
352
+		description := mtag.Get("description")
353
+
354
+		group, err := g.AddGroup(subgroup, description, ptrval.Interface())
355
+
356
+		if err != nil {
357
+			return true, err
358
+		}
359
+
360
+		group.Namespace = mtag.Get("namespace")
361
+		group.Hidden = mtag.Get("hidden") != ""
362
+
363
+		return true, nil
364
+	}
365
+
366
+	return false, nil
367
+}
368
+
369
+func (g *Group) scanType(handler scanHandler) error {
370
+	// Get all the public fields in the data struct
371
+	ptrval := reflect.ValueOf(g.data)
372
+
373
+	if ptrval.Type().Kind() != reflect.Ptr {
374
+		panic(ErrNotPointerToStruct)
375
+	}
376
+
377
+	stype := ptrval.Type().Elem()
378
+
379
+	if stype.Kind() != reflect.Struct {
380
+		panic(ErrNotPointerToStruct)
381
+	}
382
+
383
+	realval := reflect.Indirect(ptrval)
384
+
385
+	if err := g.scanStruct(realval, nil, handler); err != nil {
386
+		return err
387
+	}
388
+
389
+	if err := g.checkForDuplicateFlags(); err != nil {
390
+		return err
391
+	}
392
+
393
+	return nil
394
+}
395
+
396
+func (g *Group) scan() error {
397
+	return g.scanType(g.scanSubGroupHandler)
398
+}
399
+
400
+func (g *Group) groupByName(name string) *Group {
401
+	if len(name) == 0 {
402
+		return g
403
+	}
404
+
405
+	return g.Find(name)
406
+}

+ 255
- 0
vendor/src/github.com/jessevdk/go-flags/group_test.go Datei anzeigen

@@ -0,0 +1,255 @@
1
+package flags
2
+
3
+import (
4
+	"testing"
5
+)
6
+
7
+func TestGroupInline(t *testing.T) {
8
+	var opts = struct {
9
+		Value bool `short:"v"`
10
+
11
+		Group struct {
12
+			G bool `short:"g"`
13
+		} `group:"Grouped Options"`
14
+	}{}
15
+
16
+	p, ret := assertParserSuccess(t, &opts, "-v", "-g")
17
+
18
+	assertStringArray(t, ret, []string{})
19
+
20
+	if !opts.Value {
21
+		t.Errorf("Expected Value to be true")
22
+	}
23
+
24
+	if !opts.Group.G {
25
+		t.Errorf("Expected Group.G to be true")
26
+	}
27
+
28
+	if p.Command.Group.Find("Grouped Options") == nil {
29
+		t.Errorf("Expected to find group `Grouped Options'")
30
+	}
31
+}
32
+
33
+func TestGroupAdd(t *testing.T) {
34
+	var opts = struct {
35
+		Value bool `short:"v"`
36
+	}{}
37
+
38
+	var grp = struct {
39
+		G bool `short:"g"`
40
+	}{}
41
+
42
+	p := NewParser(&opts, Default)
43
+	g, err := p.AddGroup("Grouped Options", "", &grp)
44
+
45
+	if err != nil {
46
+		t.Fatalf("Unexpected error: %v", err)
47
+		return
48
+	}
49
+
50
+	ret, err := p.ParseArgs([]string{"-v", "-g", "rest"})
51
+
52
+	if err != nil {
53
+		t.Fatalf("Unexpected error: %v", err)
54
+		return
55
+	}
56
+
57
+	assertStringArray(t, ret, []string{"rest"})
58
+
59
+	if !opts.Value {
60
+		t.Errorf("Expected Value to be true")
61
+	}
62
+
63
+	if !grp.G {
64
+		t.Errorf("Expected Group.G to be true")
65
+	}
66
+
67
+	if p.Command.Group.Find("Grouped Options") != g {
68
+		t.Errorf("Expected to find group `Grouped Options'")
69
+	}
70
+
71
+	if p.Groups()[1] != g {
72
+		t.Errorf("Expected group %#v, but got %#v", g, p.Groups()[0])
73
+	}
74
+
75
+	if g.Options()[0].ShortName != 'g' {
76
+		t.Errorf("Expected short name `g' but got %v", g.Options()[0].ShortName)
77
+	}
78
+}
79
+
80
+func TestGroupNestedInline(t *testing.T) {
81
+	var opts = struct {
82
+		Value bool `short:"v"`
83
+
84
+		Group struct {
85
+			G bool `short:"g"`
86
+
87
+			Nested struct {
88
+				N string `long:"n"`
89
+			} `group:"Nested Options"`
90
+		} `group:"Grouped Options"`
91
+	}{}
92
+
93
+	p, ret := assertParserSuccess(t, &opts, "-v", "-g", "--n", "n", "rest")
94
+
95
+	assertStringArray(t, ret, []string{"rest"})
96
+
97
+	if !opts.Value {
98
+		t.Errorf("Expected Value to be true")
99
+	}
100
+
101
+	if !opts.Group.G {
102
+		t.Errorf("Expected Group.G to be true")
103
+	}
104
+
105
+	assertString(t, opts.Group.Nested.N, "n")
106
+
107
+	if p.Command.Group.Find("Grouped Options") == nil {
108
+		t.Errorf("Expected to find group `Grouped Options'")
109
+	}
110
+
111
+	if p.Command.Group.Find("Nested Options") == nil {
112
+		t.Errorf("Expected to find group `Nested Options'")
113
+	}
114
+}
115
+
116
+func TestGroupNestedInlineNamespace(t *testing.T) {
117
+	var opts = struct {
118
+		Opt string `long:"opt"`
119
+
120
+		Group struct {
121
+			Opt   string `long:"opt"`
122
+			Group struct {
123
+				Opt string `long:"opt"`
124
+			} `group:"Subsubgroup" namespace:"sap"`
125
+		} `group:"Subgroup" namespace:"sip"`
126
+	}{}
127
+
128
+	p, ret := assertParserSuccess(t, &opts, "--opt", "a", "--sip.opt", "b", "--sip.sap.opt", "c", "rest")
129
+
130
+	assertStringArray(t, ret, []string{"rest"})
131
+
132
+	assertString(t, opts.Opt, "a")
133
+	assertString(t, opts.Group.Opt, "b")
134
+	assertString(t, opts.Group.Group.Opt, "c")
135
+
136
+	for _, name := range []string{"Subgroup", "Subsubgroup"} {
137
+		if p.Command.Group.Find(name) == nil {
138
+			t.Errorf("Expected to find group '%s'", name)
139
+		}
140
+	}
141
+}
142
+
143
+func TestDuplicateShortFlags(t *testing.T) {
144
+	var opts struct {
145
+		Verbose   []bool   `short:"v" long:"verbose" description:"Show verbose debug information"`
146
+		Variables []string `short:"v" long:"variable" description:"Set a variable value."`
147
+	}
148
+
149
+	args := []string{
150
+		"--verbose",
151
+		"-v", "123",
152
+		"-v", "456",
153
+	}
154
+
155
+	_, err := ParseArgs(&opts, args)
156
+
157
+	if err == nil {
158
+		t.Errorf("Expected an error with type ErrDuplicatedFlag")
159
+	} else {
160
+		err2 := err.(*Error)
161
+		if err2.Type != ErrDuplicatedFlag {
162
+			t.Errorf("Expected an error with type ErrDuplicatedFlag")
163
+		}
164
+	}
165
+}
166
+
167
+func TestDuplicateLongFlags(t *testing.T) {
168
+	var opts struct {
169
+		Test1 []bool   `short:"a" long:"testing" description:"Test 1"`
170
+		Test2 []string `short:"b" long:"testing" description:"Test 2."`
171
+	}
172
+
173
+	args := []string{
174
+		"--testing",
175
+	}
176
+
177
+	_, err := ParseArgs(&opts, args)
178
+
179
+	if err == nil {
180
+		t.Errorf("Expected an error with type ErrDuplicatedFlag")
181
+	} else {
182
+		err2 := err.(*Error)
183
+		if err2.Type != ErrDuplicatedFlag {
184
+			t.Errorf("Expected an error with type ErrDuplicatedFlag")
185
+		}
186
+	}
187
+}
188
+
189
+func TestFindOptionByLongFlag(t *testing.T) {
190
+	var opts struct {
191
+		Testing bool `long:"testing" description:"Testing"`
192
+	}
193
+
194
+	p := NewParser(&opts, Default)
195
+	opt := p.FindOptionByLongName("testing")
196
+
197
+	if opt == nil {
198
+		t.Errorf("Expected option, but found none")
199
+	}
200
+
201
+	assertString(t, opt.LongName, "testing")
202
+}
203
+
204
+func TestFindOptionByShortFlag(t *testing.T) {
205
+	var opts struct {
206
+		Testing bool `short:"t" description:"Testing"`
207
+	}
208
+
209
+	p := NewParser(&opts, Default)
210
+	opt := p.FindOptionByShortName('t')
211
+
212
+	if opt == nil {
213
+		t.Errorf("Expected option, but found none")
214
+	}
215
+
216
+	if opt.ShortName != 't' {
217
+		t.Errorf("Expected 't', but got %v", opt.ShortName)
218
+	}
219
+}
220
+
221
+func TestFindOptionByLongFlagInSubGroup(t *testing.T) {
222
+	var opts struct {
223
+		Group struct {
224
+			Testing bool `long:"testing" description:"Testing"`
225
+		} `group:"sub-group"`
226
+	}
227
+
228
+	p := NewParser(&opts, Default)
229
+	opt := p.FindOptionByLongName("testing")
230
+
231
+	if opt == nil {
232
+		t.Errorf("Expected option, but found none")
233
+	}
234
+
235
+	assertString(t, opt.LongName, "testing")
236
+}
237
+
238
+func TestFindOptionByShortFlagInSubGroup(t *testing.T) {
239
+	var opts struct {
240
+		Group struct {
241
+			Testing bool `short:"t" description:"Testing"`
242
+		} `group:"sub-group"`
243
+	}
244
+
245
+	p := NewParser(&opts, Default)
246
+	opt := p.FindOptionByShortName('t')
247
+
248
+	if opt == nil {
249
+		t.Errorf("Expected option, but found none")
250
+	}
251
+
252
+	if opt.ShortName != 't' {
253
+		t.Errorf("Expected 't', but got %v", opt.ShortName)
254
+	}
255
+}

+ 491
- 0
vendor/src/github.com/jessevdk/go-flags/help.go Datei anzeigen

@@ -0,0 +1,491 @@
1
+// Copyright 2012 Jesse van den Kieboom. 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 flags
6
+
7
+import (
8
+	"bufio"
9
+	"bytes"
10
+	"fmt"
11
+	"io"
12
+	"runtime"
13
+	"strings"
14
+	"unicode/utf8"
15
+)
16
+
17
+type alignmentInfo struct {
18
+	maxLongLen      int
19
+	hasShort        bool
20
+	hasValueName    bool
21
+	terminalColumns int
22
+	indent          bool
23
+}
24
+
25
+const (
26
+	paddingBeforeOption                 = 2
27
+	distanceBetweenOptionAndDescription = 2
28
+)
29
+
30
+func (a *alignmentInfo) descriptionStart() int {
31
+	ret := a.maxLongLen + distanceBetweenOptionAndDescription
32
+
33
+	if a.hasShort {
34
+		ret += 2
35
+	}
36
+
37
+	if a.maxLongLen > 0 {
38
+		ret += 4
39
+	}
40
+
41
+	if a.hasValueName {
42
+		ret += 3
43
+	}
44
+
45
+	return ret
46
+}
47
+
48
+func (a *alignmentInfo) updateLen(name string, indent bool) {
49
+	l := utf8.RuneCountInString(name)
50
+
51
+	if indent {
52
+		l = l + 4
53
+	}
54
+
55
+	if l > a.maxLongLen {
56
+		a.maxLongLen = l
57
+	}
58
+}
59
+
60
+func (p *Parser) getAlignmentInfo() alignmentInfo {
61
+	ret := alignmentInfo{
62
+		maxLongLen:      0,
63
+		hasShort:        false,
64
+		hasValueName:    false,
65
+		terminalColumns: getTerminalColumns(),
66
+	}
67
+
68
+	if ret.terminalColumns <= 0 {
69
+		ret.terminalColumns = 80
70
+	}
71
+
72
+	var prevcmd *Command
73
+
74
+	p.eachActiveGroup(func(c *Command, grp *Group) {
75
+		if c != prevcmd {
76
+			for _, arg := range c.args {
77
+				ret.updateLen(arg.Name, c != p.Command)
78
+			}
79
+		}
80
+
81
+		for _, info := range grp.options {
82
+			if !info.canCli() {
83
+				continue
84
+			}
85
+
86
+			if info.ShortName != 0 {
87
+				ret.hasShort = true
88
+			}
89
+
90
+			if len(info.ValueName) > 0 {
91
+				ret.hasValueName = true
92
+			}
93
+
94
+			l := info.LongNameWithNamespace() + info.ValueName
95
+
96
+			if len(info.Choices) != 0 {
97
+				l += "[" + strings.Join(info.Choices, "|") + "]"
98
+			}
99
+
100
+			ret.updateLen(l, c != p.Command)
101
+		}
102
+	})
103
+
104
+	return ret
105
+}
106
+
107
+func wrapText(s string, l int, prefix string) string {
108
+	var ret string
109
+
110
+	if l < 10 {
111
+		l = 10
112
+	}
113
+
114
+	// Basic text wrapping of s at spaces to fit in l
115
+	lines := strings.Split(s, "\n")
116
+
117
+	for _, line := range lines {
118
+		var retline string
119
+
120
+		line = strings.TrimSpace(line)
121
+
122
+		for len(line) > l {
123
+			// Try to split on space
124
+			suffix := ""
125
+
126
+			pos := strings.LastIndex(line[:l], " ")
127
+
128
+			if pos < 0 {
129
+				pos = l - 1
130
+				suffix = "-\n"
131
+			}
132
+
133
+			if len(retline) != 0 {
134
+				retline += "\n" + prefix
135
+			}
136
+
137
+			retline += strings.TrimSpace(line[:pos]) + suffix
138
+			line = strings.TrimSpace(line[pos:])
139
+		}
140
+
141
+		if len(line) > 0 {
142
+			if len(retline) != 0 {
143
+				retline += "\n" + prefix
144
+			}
145
+
146
+			retline += line
147
+		}
148
+
149
+		if len(ret) > 0 {
150
+			ret += "\n"
151
+
152
+			if len(retline) > 0 {
153
+				ret += prefix
154
+			}
155
+		}
156
+
157
+		ret += retline
158
+	}
159
+
160
+	return ret
161
+}
162
+
163
+func (p *Parser) writeHelpOption(writer *bufio.Writer, option *Option, info alignmentInfo) {
164
+	line := &bytes.Buffer{}
165
+
166
+	prefix := paddingBeforeOption
167
+
168
+	if info.indent {
169
+		prefix += 4
170
+	}
171
+
172
+	if option.Hidden {
173
+		return
174
+	}
175
+
176
+	line.WriteString(strings.Repeat(" ", prefix))
177
+
178
+	if option.ShortName != 0 {
179
+		line.WriteRune(defaultShortOptDelimiter)
180
+		line.WriteRune(option.ShortName)
181
+	} else if info.hasShort {
182
+		line.WriteString("  ")
183
+	}
184
+
185
+	descstart := info.descriptionStart() + paddingBeforeOption
186
+
187
+	if len(option.LongName) > 0 {
188
+		if option.ShortName != 0 {
189
+			line.WriteString(", ")
190
+		} else if info.hasShort {
191
+			line.WriteString("  ")
192
+		}
193
+
194
+		line.WriteString(defaultLongOptDelimiter)
195
+		line.WriteString(option.LongNameWithNamespace())
196
+	}
197
+
198
+	if option.canArgument() {
199
+		line.WriteRune(defaultNameArgDelimiter)
200
+
201
+		if len(option.ValueName) > 0 {
202
+			line.WriteString(option.ValueName)
203
+		}
204
+
205
+		if len(option.Choices) > 0 {
206
+			line.WriteString("[" + strings.Join(option.Choices, "|") + "]")
207
+		}
208
+	}
209
+
210
+	written := line.Len()
211
+	line.WriteTo(writer)
212
+
213
+	if option.Description != "" {
214
+		dw := descstart - written
215
+		writer.WriteString(strings.Repeat(" ", dw))
216
+
217
+		var def string
218
+
219
+		if len(option.DefaultMask) != 0 {
220
+			if option.DefaultMask != "-" {
221
+				def = option.DefaultMask
222
+			}
223
+		} else {
224
+			def = option.defaultLiteral
225
+		}
226
+
227
+		var envDef string
228
+		if option.EnvDefaultKey != "" {
229
+			var envPrintable string
230
+			if runtime.GOOS == "windows" {
231
+				envPrintable = "%" + option.EnvDefaultKey + "%"
232
+			} else {
233
+				envPrintable = "$" + option.EnvDefaultKey
234
+			}
235
+			envDef = fmt.Sprintf(" [%s]", envPrintable)
236
+		}
237
+
238
+		var desc string
239
+
240
+		if def != "" {
241
+			desc = fmt.Sprintf("%s (default: %v)%s", option.Description, def, envDef)
242
+		} else {
243
+			desc = option.Description + envDef
244
+		}
245
+
246
+		writer.WriteString(wrapText(desc,
247
+			info.terminalColumns-descstart,
248
+			strings.Repeat(" ", descstart)))
249
+	}
250
+
251
+	writer.WriteString("\n")
252
+}
253
+
254
+func maxCommandLength(s []*Command) int {
255
+	if len(s) == 0 {
256
+		return 0
257
+	}
258
+
259
+	ret := len(s[0].Name)
260
+
261
+	for _, v := range s[1:] {
262
+		l := len(v.Name)
263
+
264
+		if l > ret {
265
+			ret = l
266
+		}
267
+	}
268
+
269
+	return ret
270
+}
271
+
272
+// WriteHelp writes a help message containing all the possible options and
273
+// their descriptions to the provided writer. Note that the HelpFlag parser
274
+// option provides a convenient way to add a -h/--help option group to the
275
+// command line parser which will automatically show the help messages using
276
+// this method.
277
+func (p *Parser) WriteHelp(writer io.Writer) {
278
+	if writer == nil {
279
+		return
280
+	}
281
+
282
+	wr := bufio.NewWriter(writer)
283
+	aligninfo := p.getAlignmentInfo()
284
+
285
+	cmd := p.Command
286
+
287
+	for cmd.Active != nil {
288
+		cmd = cmd.Active
289
+	}
290
+
291
+	if p.Name != "" {
292
+		wr.WriteString("Usage:\n")
293
+		wr.WriteString(" ")
294
+
295
+		allcmd := p.Command
296
+
297
+		for allcmd != nil {
298
+			var usage string
299
+
300
+			if allcmd == p.Command {
301
+				if len(p.Usage) != 0 {
302
+					usage = p.Usage
303
+				} else if p.Options&HelpFlag != 0 {
304
+					usage = "[OPTIONS]"
305
+				}
306
+			} else if us, ok := allcmd.data.(Usage); ok {
307
+				usage = us.Usage()
308
+			} else if allcmd.hasCliOptions() {
309
+				usage = fmt.Sprintf("[%s-OPTIONS]", allcmd.Name)
310
+			}
311
+
312
+			if len(usage) != 0 {
313
+				fmt.Fprintf(wr, " %s %s", allcmd.Name, usage)
314
+			} else {
315
+				fmt.Fprintf(wr, " %s", allcmd.Name)
316
+			}
317
+
318
+			if len(allcmd.args) > 0 {
319
+				fmt.Fprintf(wr, " ")
320
+			}
321
+
322
+			for i, arg := range allcmd.args {
323
+				if i != 0 {
324
+					fmt.Fprintf(wr, " ")
325
+				}
326
+
327
+				name := arg.Name
328
+
329
+				if arg.isRemaining() {
330
+					name = name + "..."
331
+				}
332
+
333
+				if !allcmd.ArgsRequired {
334
+					fmt.Fprintf(wr, "[%s]", name)
335
+				} else {
336
+					fmt.Fprintf(wr, "%s", name)
337
+				}
338
+			}
339
+
340
+			if allcmd.Active == nil && len(allcmd.commands) > 0 {
341
+				var co, cc string
342
+
343
+				if allcmd.SubcommandsOptional {
344
+					co, cc = "[", "]"
345
+				} else {
346
+					co, cc = "<", ">"
347
+				}
348
+
349
+				visibleCommands := allcmd.visibleCommands()
350
+
351
+				if len(visibleCommands) > 3 {
352
+					fmt.Fprintf(wr, " %scommand%s", co, cc)
353
+				} else {
354
+					subcommands := allcmd.sortedVisibleCommands()
355
+					names := make([]string, len(subcommands))
356
+
357
+					for i, subc := range subcommands {
358
+						names[i] = subc.Name
359
+					}
360
+
361
+					fmt.Fprintf(wr, " %s%s%s", co, strings.Join(names, " | "), cc)
362
+				}
363
+			}
364
+
365
+			allcmd = allcmd.Active
366
+		}
367
+
368
+		fmt.Fprintln(wr)
369
+
370
+		if len(cmd.LongDescription) != 0 {
371
+			fmt.Fprintln(wr)
372
+
373
+			t := wrapText(cmd.LongDescription,
374
+				aligninfo.terminalColumns,
375
+				"")
376
+
377
+			fmt.Fprintln(wr, t)
378
+		}
379
+	}
380
+
381
+	c := p.Command
382
+
383
+	for c != nil {
384
+		printcmd := c != p.Command
385
+
386
+		c.eachGroup(func(grp *Group) {
387
+			first := true
388
+
389
+			// Skip built-in help group for all commands except the top-level
390
+			// parser
391
+			if grp.Hidden || (grp.isBuiltinHelp && c != p.Command) {
392
+				return
393
+			}
394
+
395
+			for _, info := range grp.options {
396
+				if !info.canCli() || info.Hidden {
397
+					continue
398
+				}
399
+
400
+				if printcmd {
401
+					fmt.Fprintf(wr, "\n[%s command options]\n", c.Name)
402
+					aligninfo.indent = true
403
+					printcmd = false
404
+				}
405
+
406
+				if first && cmd.Group != grp {
407
+					fmt.Fprintln(wr)
408
+
409
+					if aligninfo.indent {
410
+						wr.WriteString("    ")
411
+					}
412
+
413
+					fmt.Fprintf(wr, "%s:\n", grp.ShortDescription)
414
+					first = false
415
+				}
416
+
417
+				p.writeHelpOption(wr, info, aligninfo)
418
+			}
419
+		})
420
+
421
+		var args []*Arg
422
+		for _, arg := range c.args {
423
+			if arg.Description != "" {
424
+				args = append(args, arg)
425
+			}
426
+		}
427
+
428
+		if len(args) > 0 {
429
+			if c == p.Command {
430
+				fmt.Fprintf(wr, "\nArguments:\n")
431
+			} else {
432
+				fmt.Fprintf(wr, "\n[%s command arguments]\n", c.Name)
433
+			}
434
+
435
+			descStart := aligninfo.descriptionStart() + paddingBeforeOption
436
+
437
+			for _, arg := range args {
438
+				argPrefix := strings.Repeat(" ", paddingBeforeOption)
439
+				argPrefix += arg.Name
440
+
441
+				if len(arg.Description) > 0 {
442
+					argPrefix += ":"
443
+					wr.WriteString(argPrefix)
444
+
445
+					// Space between "arg:" and the description start
446
+					descPadding := strings.Repeat(" ", descStart-len(argPrefix))
447
+					// How much space the description gets before wrapping
448
+					descWidth := aligninfo.terminalColumns - 1 - descStart
449
+					// Whitespace to which we can indent new description lines
450
+					descPrefix := strings.Repeat(" ", descStart)
451
+
452
+					wr.WriteString(descPadding)
453
+					wr.WriteString(wrapText(arg.Description, descWidth, descPrefix))
454
+				} else {
455
+					wr.WriteString(argPrefix)
456
+				}
457
+
458
+				fmt.Fprintln(wr)
459
+			}
460
+		}
461
+
462
+		c = c.Active
463
+	}
464
+
465
+	scommands := cmd.sortedVisibleCommands()
466
+
467
+	if len(scommands) > 0 {
468
+		maxnamelen := maxCommandLength(scommands)
469
+
470
+		fmt.Fprintln(wr)
471
+		fmt.Fprintln(wr, "Available commands:")
472
+
473
+		for _, c := range scommands {
474
+			fmt.Fprintf(wr, "  %s", c.Name)
475
+
476
+			if len(c.ShortDescription) > 0 {
477
+				pad := strings.Repeat(" ", maxnamelen-len(c.Name))
478
+				fmt.Fprintf(wr, "%s  %s", pad, c.ShortDescription)
479
+
480
+				if len(c.Aliases) > 0 {
481
+					fmt.Fprintf(wr, " (aliases: %s)", strings.Join(c.Aliases, ", "))
482
+				}
483
+
484
+			}
485
+
486
+			fmt.Fprintln(wr)
487
+		}
488
+	}
489
+
490
+	wr.Flush()
491
+}

+ 538
- 0
vendor/src/github.com/jessevdk/go-flags/help_test.go Datei anzeigen

@@ -0,0 +1,538 @@
1
+package flags
2
+
3
+import (
4
+	"bufio"
5
+	"bytes"
6
+	"fmt"
7
+	"os"
8
+	"runtime"
9
+	"strings"
10
+	"testing"
11
+	"time"
12
+)
13
+
14
+type helpOptions struct {
15
+	Verbose          []bool       `short:"v" long:"verbose" description:"Show verbose debug information" ini-name:"verbose"`
16
+	Call             func(string) `short:"c" description:"Call phone number" ini-name:"call"`
17
+	PtrSlice         []*string    `long:"ptrslice" description:"A slice of pointers to string"`
18
+	EmptyDescription bool         `long:"empty-description"`
19
+
20
+	Default           string            `long:"default" default:"Some\nvalue" description:"Test default value"`
21
+	DefaultArray      []string          `long:"default-array" default:"Some value" default:"Other\tvalue" description:"Test default array value"`
22
+	DefaultMap        map[string]string `long:"default-map" default:"some:value" default:"another:value" description:"Testdefault map value"`
23
+	EnvDefault1       string            `long:"env-default1" default:"Some value" env:"ENV_DEFAULT" description:"Test env-default1 value"`
24
+	EnvDefault2       string            `long:"env-default2" env:"ENV_DEFAULT" description:"Test env-default2 value"`
25
+	OptionWithArgName string            `long:"opt-with-arg-name" value-name:"something" description:"Option with named argument"`
26
+	OptionWithChoices string            `long:"opt-with-choices" value-name:"choice" choice:"dog" choice:"cat" description:"Option with choices"`
27
+	Hidden            string            `long:"hidden" description:"Hidden option" hidden:"yes"`
28
+
29
+	OnlyIni string `ini-name:"only-ini" description:"Option only available in ini"`
30
+
31
+	Other struct {
32
+		StringSlice []string       `short:"s" default:"some" default:"value" description:"A slice of strings"`
33
+		IntMap      map[string]int `long:"intmap" default:"a:1" description:"A map from string to int" ini-name:"int-map"`
34
+	} `group:"Other Options"`
35
+
36
+	HiddenGroup struct {
37
+		InsideHiddenGroup string `long:"inside-hidden-group" description:"Inside hidden group"`
38
+	} `group:"Hidden group" hidden:"yes"`
39
+
40
+	Group struct {
41
+		Opt                  string `long:"opt" description:"This is a subgroup option"`
42
+		HiddenInsideGroup    string `long:"hidden-inside-group" description:"Hidden inside group" hidden:"yes"`
43
+		NotHiddenInsideGroup string `long:"not-hidden-inside-group" description:"Not hidden inside group" hidden:"false"`
44
+
45
+		Group struct {
46
+			Opt string `long:"opt" description:"This is a subsubgroup option"`
47
+		} `group:"Subsubgroup" namespace:"sap"`
48
+	} `group:"Subgroup" namespace:"sip"`
49
+
50
+	Command struct {
51
+		ExtraVerbose []bool `long:"extra-verbose" description:"Use for extra verbosity"`
52
+	} `command:"command" alias:"cm" alias:"cmd" description:"A command"`
53
+
54
+	HiddenCommand struct {
55
+		ExtraVerbose []bool `long:"extra-verbose" description:"Use for extra verbosity"`
56
+	} `command:"hidden-command" description:"A hidden command" hidden:"yes"`
57
+
58
+	Args struct {
59
+		Filename     string  `positional-arg-name:"filename" description:"A filename with a long description to trigger line wrapping"`
60
+		Number       int     `positional-arg-name:"num" description:"A number"`
61
+		HiddenInHelp float32 `positional-arg-name:"hidden-in-help" required:"yes"`
62
+	} `positional-args:"yes"`
63
+}
64
+
65
+func TestHelp(t *testing.T) {
66
+	oldEnv := EnvSnapshot()
67
+	defer oldEnv.Restore()
68
+	os.Setenv("ENV_DEFAULT", "env-def")
69
+
70
+	var opts helpOptions
71
+	p := NewNamedParser("TestHelp", HelpFlag)
72
+	p.AddGroup("Application Options", "The application options", &opts)
73
+
74
+	_, err := p.ParseArgs([]string{"--help"})
75
+
76
+	if err == nil {
77
+		t.Fatalf("Expected help error")
78
+	}
79
+
80
+	if e, ok := err.(*Error); !ok {
81
+		t.Fatalf("Expected flags.Error, but got %T", err)
82
+	} else {
83
+		if e.Type != ErrHelp {
84
+			t.Errorf("Expected flags.ErrHelp type, but got %s", e.Type)
85
+		}
86
+
87
+		var expected string
88
+
89
+		if runtime.GOOS == "windows" {
90
+			expected = `Usage:
91
+  TestHelp [OPTIONS] [filename] [num] [hidden-in-help] <command>
92
+
93
+Application Options:
94
+  /v, /verbose                              Show verbose debug information
95
+  /c:                                       Call phone number
96
+      /ptrslice:                            A slice of pointers to string
97
+      /empty-description
98
+      /default:                             Test default value (default:
99
+                                            "Some\nvalue")
100
+      /default-array:                       Test default array value (default:
101
+                                            Some value, "Other\tvalue")
102
+      /default-map:                         Testdefault map value (default:
103
+                                            some:value, another:value)
104
+      /env-default1:                        Test env-default1 value (default:
105
+                                            Some value) [%ENV_DEFAULT%]
106
+      /env-default2:                        Test env-default2 value
107
+                                            [%ENV_DEFAULT%]
108
+      /opt-with-arg-name:something          Option with named argument
109
+      /opt-with-choices:choice[dog|cat]     Option with choices
110
+
111
+Other Options:
112
+  /s:                                       A slice of strings (default: some,
113
+                                            value)
114
+      /intmap:                              A map from string to int (default:
115
+                                            a:1)
116
+
117
+Subgroup:
118
+      /sip.opt:                             This is a subgroup option
119
+      /sip.not-hidden-inside-group:         Not hidden inside group
120
+
121
+Subsubgroup:
122
+      /sip.sap.opt:                         This is a subsubgroup option
123
+
124
+Help Options:
125
+  /?                                        Show this help message
126
+  /h, /help                                 Show this help message
127
+
128
+Arguments:
129
+  filename:                                 A filename with a long description
130
+                                            to trigger line wrapping
131
+  num:                                      A number
132
+
133
+Available commands:
134
+  command  A command (aliases: cm, cmd)
135
+`
136
+		} else {
137
+			expected = `Usage:
138
+  TestHelp [OPTIONS] [filename] [num] [hidden-in-help] <command>
139
+
140
+Application Options:
141
+  -v, --verbose                             Show verbose debug information
142
+  -c=                                       Call phone number
143
+      --ptrslice=                           A slice of pointers to string
144
+      --empty-description
145
+      --default=                            Test default value (default:
146
+                                            "Some\nvalue")
147
+      --default-array=                      Test default array value (default:
148
+                                            Some value, "Other\tvalue")
149
+      --default-map=                        Testdefault map value (default:
150
+                                            some:value, another:value)
151
+      --env-default1=                       Test env-default1 value (default:
152
+                                            Some value) [$ENV_DEFAULT]
153
+      --env-default2=                       Test env-default2 value
154
+                                            [$ENV_DEFAULT]
155
+      --opt-with-arg-name=something         Option with named argument
156
+      --opt-with-choices=choice[dog|cat]    Option with choices
157
+
158
+Other Options:
159
+  -s=                                       A slice of strings (default: some,
160
+                                            value)
161
+      --intmap=                             A map from string to int (default:
162
+                                            a:1)
163
+
164
+Subgroup:
165
+      --sip.opt=                            This is a subgroup option
166
+      --sip.not-hidden-inside-group=        Not hidden inside group
167
+
168
+Subsubgroup:
169
+      --sip.sap.opt=                        This is a subsubgroup option
170
+
171
+Help Options:
172
+  -h, --help                                Show this help message
173
+
174
+Arguments:
175
+  filename:                                 A filename with a long description
176
+                                            to trigger line wrapping
177
+  num:                                      A number
178
+
179
+Available commands:
180
+  command  A command (aliases: cm, cmd)
181
+`
182
+		}
183
+
184
+		assertDiff(t, e.Message, expected, "help message")
185
+	}
186
+}
187
+
188
+func TestMan(t *testing.T) {
189
+	oldEnv := EnvSnapshot()
190
+	defer oldEnv.Restore()
191
+	os.Setenv("ENV_DEFAULT", "env-def")
192
+
193
+	var opts helpOptions
194
+	p := NewNamedParser("TestMan", HelpFlag)
195
+	p.ShortDescription = "Test manpage generation"
196
+	p.LongDescription = "This is a somewhat `longer' description of what this does"
197
+	p.AddGroup("Application Options", "The application options", &opts)
198
+
199
+	p.Commands()[0].LongDescription = "Longer `command' description"
200
+
201
+	var buf bytes.Buffer
202
+	p.WriteManPage(&buf)
203
+
204
+	got := buf.String()
205
+
206
+	tt := time.Now()
207
+
208
+	var envDefaultName string
209
+
210
+	if runtime.GOOS == "windows" {
211
+		envDefaultName = "%ENV_DEFAULT%"
212
+	} else {
213
+		envDefaultName = "$ENV_DEFAULT"
214
+	}
215
+
216
+	expected := fmt.Sprintf(`.TH TestMan 1 "%s"
217
+.SH NAME
218
+TestMan \- Test manpage generation
219
+.SH SYNOPSIS
220
+\fBTestMan\fP [OPTIONS]
221
+.SH DESCRIPTION
222
+This is a somewhat \fBlonger\fP description of what this does
223
+.SH OPTIONS
224
+.SS Application Options
225
+The application options
226
+.TP
227
+\fB\fB\-v\fR, \fB\-\-verbose\fR\fP
228
+Show verbose debug information
229
+.TP
230
+\fB\fB\-c\fR\fP
231
+Call phone number
232
+.TP
233
+\fB\fB\-\-ptrslice\fR\fP
234
+A slice of pointers to string
235
+.TP
236
+\fB\fB\-\-empty-description\fR\fP
237
+.TP
238
+\fB\fB\-\-default\fR <default: \fI"Some\\nvalue"\fR>\fP
239
+Test default value
240
+.TP
241
+\fB\fB\-\-default-array\fR <default: \fI"Some value", "Other\\tvalue"\fR>\fP
242
+Test default array value
243
+.TP
244
+\fB\fB\-\-default-map\fR <default: \fI"some:value", "another:value"\fR>\fP
245
+Testdefault map value
246
+.TP
247
+\fB\fB\-\-env-default1\fR <default: \fI"Some value"\fR>\fP
248
+Test env-default1 value
249
+.TP
250
+\fB\fB\-\-env-default2\fR <default: \fI%s\fR>\fP
251
+Test env-default2 value
252
+.TP
253
+\fB\fB\-\-opt-with-arg-name\fR \fIsomething\fR\fP
254
+Option with named argument
255
+.TP
256
+\fB\fB\-\-opt-with-choices\fR \fIchoice\fR\fP
257
+Option with choices
258
+.SS Other Options
259
+.TP
260
+\fB\fB\-s\fR <default: \fI"some", "value"\fR>\fP
261
+A slice of strings
262
+.TP
263
+\fB\fB\-\-intmap\fR <default: \fI"a:1"\fR>\fP
264
+A map from string to int
265
+.SS Subgroup
266
+.TP
267
+\fB\fB\-\-sip.opt\fR\fP
268
+This is a subgroup option
269
+.TP
270
+\fB\fB\-\-sip.not-hidden-inside-group\fR\fP
271
+Not hidden inside group
272
+.SS Subsubgroup
273
+.TP
274
+\fB\fB\-\-sip.sap.opt\fR\fP
275
+This is a subsubgroup option
276
+.SH COMMANDS
277
+.SS command
278
+A command
279
+
280
+Longer \fBcommand\fP description
281
+
282
+\fBUsage\fP: TestMan [OPTIONS] command [command-OPTIONS]
283
+.TP
284
+
285
+\fBAliases\fP: cm, cmd
286
+
287
+.TP
288
+\fB\fB\-\-extra-verbose\fR\fP
289
+Use for extra verbosity
290
+`, tt.Format("2 January 2006"), envDefaultName)
291
+
292
+	assertDiff(t, got, expected, "man page")
293
+}
294
+
295
+type helpCommandNoOptions struct {
296
+	Command struct {
297
+	} `command:"command" description:"A command"`
298
+}
299
+
300
+func TestHelpCommand(t *testing.T) {
301
+	oldEnv := EnvSnapshot()
302
+	defer oldEnv.Restore()
303
+	os.Setenv("ENV_DEFAULT", "env-def")
304
+
305
+	var opts helpCommandNoOptions
306
+	p := NewNamedParser("TestHelpCommand", HelpFlag)
307
+	p.AddGroup("Application Options", "The application options", &opts)
308
+
309
+	_, err := p.ParseArgs([]string{"command", "--help"})
310
+
311
+	if err == nil {
312
+		t.Fatalf("Expected help error")
313
+	}
314
+
315
+	if e, ok := err.(*Error); !ok {
316
+		t.Fatalf("Expected flags.Error, but got %T", err)
317
+	} else {
318
+		if e.Type != ErrHelp {
319
+			t.Errorf("Expected flags.ErrHelp type, but got %s", e.Type)
320
+		}
321
+
322
+		var expected string
323
+
324
+		if runtime.GOOS == "windows" {
325
+			expected = `Usage:
326
+  TestHelpCommand [OPTIONS] command
327
+
328
+Help Options:
329
+  /?              Show this help message
330
+  /h, /help       Show this help message
331
+`
332
+		} else {
333
+			expected = `Usage:
334
+  TestHelpCommand [OPTIONS] command
335
+
336
+Help Options:
337
+  -h, --help      Show this help message
338
+`
339
+		}
340
+
341
+		assertDiff(t, e.Message, expected, "help message")
342
+	}
343
+}
344
+
345
+func TestHelpDefaults(t *testing.T) {
346
+	var expected string
347
+
348
+	if runtime.GOOS == "windows" {
349
+		expected = `Usage:
350
+  TestHelpDefaults [OPTIONS]
351
+
352
+Application Options:
353
+      /with-default:               With default (default: default-value)
354
+      /without-default:            Without default
355
+      /with-programmatic-default:  With programmatic default (default:
356
+                                   default-value)
357
+
358
+Help Options:
359
+  /?                               Show this help message
360
+  /h, /help                        Show this help message
361
+`
362
+	} else {
363
+		expected = `Usage:
364
+  TestHelpDefaults [OPTIONS]
365
+
366
+Application Options:
367
+      --with-default=              With default (default: default-value)
368
+      --without-default=           Without default
369
+      --with-programmatic-default= With programmatic default (default:
370
+                                   default-value)
371
+
372
+Help Options:
373
+  -h, --help                       Show this help message
374
+`
375
+	}
376
+
377
+	tests := []struct {
378
+		Args   []string
379
+		Output string
380
+	}{
381
+		{
382
+			Args:   []string{"-h"},
383
+			Output: expected,
384
+		},
385
+		{
386
+			Args:   []string{"--with-default", "other-value", "--with-programmatic-default", "other-value", "-h"},
387
+			Output: expected,
388
+		},
389
+	}
390
+
391
+	for _, test := range tests {
392
+		var opts struct {
393
+			WithDefault             string `long:"with-default" default:"default-value" description:"With default"`
394
+			WithoutDefault          string `long:"without-default" description:"Without default"`
395
+			WithProgrammaticDefault string `long:"with-programmatic-default" description:"With programmatic default"`
396
+		}
397
+
398
+		opts.WithProgrammaticDefault = "default-value"
399
+
400
+		p := NewNamedParser("TestHelpDefaults", HelpFlag)
401
+		p.AddGroup("Application Options", "The application options", &opts)
402
+
403
+		_, err := p.ParseArgs(test.Args)
404
+
405
+		if err == nil {
406
+			t.Fatalf("Expected help error")
407
+		}
408
+
409
+		if e, ok := err.(*Error); !ok {
410
+			t.Fatalf("Expected flags.Error, but got %T", err)
411
+		} else {
412
+			if e.Type != ErrHelp {
413
+				t.Errorf("Expected flags.ErrHelp type, but got %s", e.Type)
414
+			}
415
+
416
+			assertDiff(t, e.Message, test.Output, "help message")
417
+		}
418
+	}
419
+}
420
+
421
+func TestHelpRestArgs(t *testing.T) {
422
+	opts := struct {
423
+		Verbose bool `short:"v"`
424
+	}{}
425
+
426
+	p := NewNamedParser("TestHelpDefaults", HelpFlag)
427
+	p.AddGroup("Application Options", "The application options", &opts)
428
+
429
+	retargs, err := p.ParseArgs([]string{"-h", "-v", "rest"})
430
+
431
+	if err == nil {
432
+		t.Fatalf("Expected help error")
433
+	}
434
+
435
+	assertStringArray(t, retargs, []string{"-v", "rest"})
436
+}
437
+
438
+func TestWrapText(t *testing.T) {
439
+	s := "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
440
+
441
+	got := wrapText(s, 60, "      ")
442
+	expected := `Lorem ipsum dolor sit amet, consectetur adipisicing elit,
443
+      sed do eiusmod tempor incididunt ut labore et dolore magna
444
+      aliqua. Ut enim ad minim veniam, quis nostrud exercitation
445
+      ullamco laboris nisi ut aliquip ex ea commodo consequat.
446
+      Duis aute irure dolor in reprehenderit in voluptate velit
447
+      esse cillum dolore eu fugiat nulla pariatur. Excepteur sint
448
+      occaecat cupidatat non proident, sunt in culpa qui officia
449
+      deserunt mollit anim id est laborum.`
450
+
451
+	assertDiff(t, got, expected, "wrapped text")
452
+}
453
+
454
+func TestWrapParagraph(t *testing.T) {
455
+	s := "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\n\n"
456
+	s += "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n\n"
457
+	s += "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.\n\n"
458
+	s += "Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n"
459
+
460
+	got := wrapText(s, 60, "      ")
461
+	expected := `Lorem ipsum dolor sit amet, consectetur adipisicing elit,
462
+      sed do eiusmod tempor incididunt ut labore et dolore magna
463
+      aliqua.
464
+
465
+      Ut enim ad minim veniam, quis nostrud exercitation ullamco
466
+      laboris nisi ut aliquip ex ea commodo consequat.
467
+
468
+      Duis aute irure dolor in reprehenderit in voluptate velit
469
+      esse cillum dolore eu fugiat nulla pariatur.
470
+
471
+      Excepteur sint occaecat cupidatat non proident, sunt in
472
+      culpa qui officia deserunt mollit anim id est laborum.
473
+`
474
+
475
+	assertDiff(t, got, expected, "wrapped paragraph")
476
+}
477
+
478
+func TestHelpDefaultMask(t *testing.T) {
479
+	var tests = []struct {
480
+		opts    interface{}
481
+		present string
482
+	}{
483
+		{
484
+			opts: &struct {
485
+				Value string `short:"v" default:"123" description:"V"`
486
+			}{},
487
+			present: "V (default: 123)\n",
488
+		},
489
+		{
490
+			opts: &struct {
491
+				Value string `short:"v" default:"123" default-mask:"abc" description:"V"`
492
+			}{},
493
+			present: "V (default: abc)\n",
494
+		},
495
+		{
496
+			opts: &struct {
497
+				Value string `short:"v" default:"123" default-mask:"-" description:"V"`
498
+			}{},
499
+			present: "V\n",
500
+		},
501
+		{
502
+			opts: &struct {
503
+				Value string `short:"v" description:"V"`
504
+			}{Value: "123"},
505
+			present: "V (default: 123)\n",
506
+		},
507
+		{
508
+			opts: &struct {
509
+				Value string `short:"v" default-mask:"abc" description:"V"`
510
+			}{Value: "123"},
511
+			present: "V (default: abc)\n",
512
+		},
513
+		{
514
+			opts: &struct {
515
+				Value string `short:"v" default-mask:"-" description:"V"`
516
+			}{Value: "123"},
517
+			present: "V\n",
518
+		},
519
+	}
520
+
521
+	for _, test := range tests {
522
+		p := NewParser(test.opts, HelpFlag)
523
+		_, err := p.ParseArgs([]string{"-h"})
524
+		if flagsErr, ok := err.(*Error); ok && flagsErr.Type == ErrHelp {
525
+			err = nil
526
+		}
527
+		if err != nil {
528
+			t.Fatalf("Unexpected error: %v", err)
529
+		}
530
+		h := &bytes.Buffer{}
531
+		w := bufio.NewWriter(h)
532
+		p.writeHelpOption(w, p.FindOptionByShortName('v'), p.getAlignmentInfo())
533
+		w.Flush()
534
+		if strings.Index(h.String(), test.present) < 0 {
535
+			t.Errorf("Not present %q\n%s", test.present, h.String())
536
+		}
537
+	}
538
+}

+ 597
- 0
vendor/src/github.com/jessevdk/go-flags/ini.go Datei anzeigen

@@ -0,0 +1,597 @@
1
+package flags
2
+
3
+import (
4
+	"bufio"
5
+	"fmt"
6
+	"io"
7
+	"os"
8
+	"reflect"
9
+	"sort"
10
+	"strconv"
11
+	"strings"
12
+)
13
+
14
+// IniError contains location information on where an error occurred.
15
+type IniError struct {
16
+	// The error message.
17
+	Message string
18
+
19
+	// The filename of the file in which the error occurred.
20
+	File string
21
+
22
+	// The line number at which the error occurred.
23
+	LineNumber uint
24
+}
25
+
26
+// Error provides a "file:line: message" formatted message of the ini error.
27
+func (x *IniError) Error() string {
28
+	return fmt.Sprintf(
29
+		"%s:%d: %s",
30
+		x.File,
31
+		x.LineNumber,
32
+		x.Message,
33
+	)
34
+}
35
+
36
+// IniOptions for writing
37
+type IniOptions uint
38
+
39
+const (
40
+	// IniNone indicates no options.
41
+	IniNone IniOptions = 0
42
+
43
+	// IniIncludeDefaults indicates that default values should be written.
44
+	IniIncludeDefaults = 1 << iota
45
+
46
+	// IniCommentDefaults indicates that if IniIncludeDefaults is used
47
+	// options with default values are written but commented out.
48
+	IniCommentDefaults
49
+
50
+	// IniIncludeComments indicates that comments containing the description
51
+	// of an option should be written.
52
+	IniIncludeComments
53
+
54
+	// IniDefault provides a default set of options.
55
+	IniDefault = IniIncludeComments
56
+)
57
+
58
+// IniParser is a utility to read and write flags options from and to ini
59
+// formatted strings.
60
+type IniParser struct {
61
+	ParseAsDefaults bool // override default flags
62
+
63
+	parser *Parser
64
+}
65
+
66
+type iniValue struct {
67
+	Name       string
68
+	Value      string
69
+	Quoted     bool
70
+	LineNumber uint
71
+}
72
+
73
+type iniSection []iniValue
74
+
75
+type ini struct {
76
+	File     string
77
+	Sections map[string]iniSection
78
+}
79
+
80
+// NewIniParser creates a new ini parser for a given Parser.
81
+func NewIniParser(p *Parser) *IniParser {
82
+	return &IniParser{
83
+		parser: p,
84
+	}
85
+}
86
+
87
+// IniParse is a convenience function to parse command line options with default
88
+// settings from an ini formatted file. The provided data is a pointer to a struct
89
+// representing the default option group (named "Application Options"). For
90
+// more control, use flags.NewParser.
91
+func IniParse(filename string, data interface{}) error {
92
+	p := NewParser(data, Default)
93
+
94
+	return NewIniParser(p).ParseFile(filename)
95
+}
96
+
97
+// ParseFile parses flags from an ini formatted file. See Parse for more
98
+// information on the ini file format. The returned errors can be of the type
99
+// flags.Error or flags.IniError.
100
+func (i *IniParser) ParseFile(filename string) error {
101
+	ini, err := readIniFromFile(filename)
102
+
103
+	if err != nil {
104
+		return err
105
+	}
106
+
107
+	return i.parse(ini)
108
+}
109
+
110
+// Parse parses flags from an ini format. You can use ParseFile as a
111
+// convenience function to parse from a filename instead of a general
112
+// io.Reader.
113
+//
114
+// The format of the ini file is as follows:
115
+//
116
+//     [Option group name]
117
+//     option = value
118
+//
119
+// Each section in the ini file represents an option group or command in the
120
+// flags parser. The default flags parser option group (i.e. when using
121
+// flags.Parse) is named 'Application Options'. The ini option name is matched
122
+// in the following order:
123
+//
124
+//     1. Compared to the ini-name tag on the option struct field (if present)
125
+//     2. Compared to the struct field name
126
+//     3. Compared to the option long name (if present)
127
+//     4. Compared to the option short name (if present)
128
+//
129
+// Sections for nested groups and commands can be addressed using a dot `.'
130
+// namespacing notation (i.e [subcommand.Options]). Group section names are
131
+// matched case insensitive.
132
+//
133
+// The returned errors can be of the type flags.Error or flags.IniError.
134
+func (i *IniParser) Parse(reader io.Reader) error {
135
+	ini, err := readIni(reader, "")
136
+
137
+	if err != nil {
138
+		return err
139
+	}
140
+
141
+	return i.parse(ini)
142
+}
143
+
144
+// WriteFile writes the flags as ini format into a file. See Write
145
+// for more information. The returned error occurs when the specified file
146
+// could not be opened for writing.
147
+func (i *IniParser) WriteFile(filename string, options IniOptions) error {
148
+	return writeIniToFile(i, filename, options)
149
+}
150
+
151
+// Write writes the current values of all the flags to an ini format.
152
+// See Parse for more information on the ini file format. You typically
153
+// call this only after settings have been parsed since the default values of each
154
+// option are stored just before parsing the flags (this is only relevant when
155
+// IniIncludeDefaults is _not_ set in options).
156
+func (i *IniParser) Write(writer io.Writer, options IniOptions) {
157
+	writeIni(i, writer, options)
158
+}
159
+
160
+func readFullLine(reader *bufio.Reader) (string, error) {
161
+	var line []byte
162
+
163
+	for {
164
+		l, more, err := reader.ReadLine()
165
+
166
+		if err != nil {
167
+			return "", err
168
+		}
169
+
170
+		if line == nil && !more {
171
+			return string(l), nil
172
+		}
173
+
174
+		line = append(line, l...)
175
+
176
+		if !more {
177
+			break
178
+		}
179
+	}
180
+
181
+	return string(line), nil
182
+}
183
+
184
+func optionIniName(option *Option) string {
185
+	name := option.tag.Get("_read-ini-name")
186
+
187
+	if len(name) != 0 {
188
+		return name
189
+	}
190
+
191
+	name = option.tag.Get("ini-name")
192
+
193
+	if len(name) != 0 {
194
+		return name
195
+	}
196
+
197
+	return option.field.Name
198
+}
199
+
200
+func writeGroupIni(cmd *Command, group *Group, namespace string, writer io.Writer, options IniOptions) {
201
+	var sname string
202
+
203
+	if len(namespace) != 0 {
204
+		sname = namespace
205
+	}
206
+
207
+	if cmd.Group != group && len(group.ShortDescription) != 0 {
208
+		if len(sname) != 0 {
209
+			sname += "."
210
+		}
211
+
212
+		sname += group.ShortDescription
213
+	}
214
+
215
+	sectionwritten := false
216
+	comments := (options & IniIncludeComments) != IniNone
217
+
218
+	for _, option := range group.options {
219
+		if option.isFunc() || option.Hidden {
220
+			continue
221
+		}
222
+
223
+		if len(option.tag.Get("no-ini")) != 0 {
224
+			continue
225
+		}
226
+
227
+		val := option.value
228
+
229
+		if (options&IniIncludeDefaults) == IniNone && option.valueIsDefault() {
230
+			continue
231
+		}
232
+
233
+		if !sectionwritten {
234
+			fmt.Fprintf(writer, "[%s]\n", sname)
235
+			sectionwritten = true
236
+		}
237
+
238
+		if comments && len(option.Description) != 0 {
239
+			fmt.Fprintf(writer, "; %s\n", option.Description)
240
+		}
241
+
242
+		oname := optionIniName(option)
243
+
244
+		commentOption := (options&(IniIncludeDefaults|IniCommentDefaults)) == IniIncludeDefaults|IniCommentDefaults && option.valueIsDefault()
245
+
246
+		kind := val.Type().Kind()
247
+		switch kind {
248
+		case reflect.Slice:
249
+			kind = val.Type().Elem().Kind()
250
+
251
+			if val.Len() == 0 {
252
+				writeOption(writer, oname, kind, "", "", true, option.iniQuote)
253
+			} else {
254
+				for idx := 0; idx < val.Len(); idx++ {
255
+					v, _ := convertToString(val.Index(idx), option.tag)
256
+
257
+					writeOption(writer, oname, kind, "", v, commentOption, option.iniQuote)
258
+				}
259
+			}
260
+		case reflect.Map:
261
+			kind = val.Type().Elem().Kind()
262
+
263
+			if val.Len() == 0 {
264
+				writeOption(writer, oname, kind, "", "", true, option.iniQuote)
265
+			} else {
266
+				mkeys := val.MapKeys()
267
+				keys := make([]string, len(val.MapKeys()))
268
+				kkmap := make(map[string]reflect.Value)
269
+
270
+				for i, k := range mkeys {
271
+					keys[i], _ = convertToString(k, option.tag)
272
+					kkmap[keys[i]] = k
273
+				}
274
+
275
+				sort.Strings(keys)
276
+
277
+				for _, k := range keys {
278
+					v, _ := convertToString(val.MapIndex(kkmap[k]), option.tag)
279
+
280
+					writeOption(writer, oname, kind, k, v, commentOption, option.iniQuote)
281
+				}
282
+			}
283
+		default:
284
+			v, _ := convertToString(val, option.tag)
285
+
286
+			writeOption(writer, oname, kind, "", v, commentOption, option.iniQuote)
287
+		}
288
+
289
+		if comments {
290
+			fmt.Fprintln(writer)
291
+		}
292
+	}
293
+
294
+	if sectionwritten && !comments {
295
+		fmt.Fprintln(writer)
296
+	}
297
+}
298
+
299
+func writeOption(writer io.Writer, optionName string, optionType reflect.Kind, optionKey string, optionValue string, commentOption bool, forceQuote bool) {
300
+	if forceQuote || (optionType == reflect.String && !isPrint(optionValue)) {
301
+		optionValue = strconv.Quote(optionValue)
302
+	}
303
+
304
+	comment := ""
305
+	if commentOption {
306
+		comment = "; "
307
+	}
308
+
309
+	fmt.Fprintf(writer, "%s%s =", comment, optionName)
310
+
311
+	if optionKey != "" {
312
+		fmt.Fprintf(writer, " %s:%s", optionKey, optionValue)
313
+	} else if optionValue != "" {
314
+		fmt.Fprintf(writer, " %s", optionValue)
315
+	}
316
+
317
+	fmt.Fprintln(writer)
318
+}
319
+
320
+func writeCommandIni(command *Command, namespace string, writer io.Writer, options IniOptions) {
321
+	command.eachGroup(func(group *Group) {
322
+		if !group.Hidden {
323
+			writeGroupIni(command, group, namespace, writer, options)
324
+		}
325
+	})
326
+
327
+	for _, c := range command.commands {
328
+		var nns string
329
+
330
+		if c.Hidden {
331
+			continue
332
+		}
333
+
334
+		if len(namespace) != 0 {
335
+			nns = c.Name + "." + nns
336
+		} else {
337
+			nns = c.Name
338
+		}
339
+
340
+		writeCommandIni(c, nns, writer, options)
341
+	}
342
+}
343
+
344
+func writeIni(parser *IniParser, writer io.Writer, options IniOptions) {
345
+	writeCommandIni(parser.parser.Command, "", writer, options)
346
+}
347
+
348
+func writeIniToFile(parser *IniParser, filename string, options IniOptions) error {
349
+	file, err := os.Create(filename)
350
+
351
+	if err != nil {
352
+		return err
353
+	}
354
+
355
+	defer file.Close()
356
+
357
+	writeIni(parser, file, options)
358
+
359
+	return nil
360
+}
361
+
362
+func readIniFromFile(filename string) (*ini, error) {
363
+	file, err := os.Open(filename)
364
+
365
+	if err != nil {
366
+		return nil, err
367
+	}
368
+
369
+	defer file.Close()
370
+
371
+	return readIni(file, filename)
372
+}
373
+
374
+func readIni(contents io.Reader, filename string) (*ini, error) {
375
+	ret := &ini{
376
+		File:     filename,
377
+		Sections: make(map[string]iniSection),
378
+	}
379
+
380
+	reader := bufio.NewReader(contents)
381
+
382
+	// Empty global section
383
+	section := make(iniSection, 0, 10)
384
+	sectionname := ""
385
+
386
+	ret.Sections[sectionname] = section
387
+
388
+	var lineno uint
389
+
390
+	for {
391
+		line, err := readFullLine(reader)
392
+
393
+		if err == io.EOF {
394
+			break
395
+		} else if err != nil {
396
+			return nil, err
397
+		}
398
+
399
+		lineno++
400
+		line = strings.TrimSpace(line)
401
+
402
+		// Skip empty lines and lines starting with ; (comments)
403
+		if len(line) == 0 || line[0] == ';' || line[0] == '#' {
404
+			continue
405
+		}
406
+
407
+		if line[0] == '[' {
408
+			if line[0] != '[' || line[len(line)-1] != ']' {
409
+				return nil, &IniError{
410
+					Message:    "malformed section header",
411
+					File:       filename,
412
+					LineNumber: lineno,
413
+				}
414
+			}
415
+
416
+			name := strings.TrimSpace(line[1 : len(line)-1])
417
+
418
+			if len(name) == 0 {
419
+				return nil, &IniError{
420
+					Message:    "empty section name",
421
+					File:       filename,
422
+					LineNumber: lineno,
423
+				}
424
+			}
425
+
426
+			sectionname = name
427
+			section = ret.Sections[name]
428
+
429
+			if section == nil {
430
+				section = make(iniSection, 0, 10)
431
+				ret.Sections[name] = section
432
+			}
433
+
434
+			continue
435
+		}
436
+
437
+		// Parse option here
438
+		keyval := strings.SplitN(line, "=", 2)
439
+
440
+		if len(keyval) != 2 {
441
+			return nil, &IniError{
442
+				Message:    fmt.Sprintf("malformed key=value (%s)", line),
443
+				File:       filename,
444
+				LineNumber: lineno,
445
+			}
446
+		}
447
+
448
+		name := strings.TrimSpace(keyval[0])
449
+		value := strings.TrimSpace(keyval[1])
450
+		quoted := false
451
+
452
+		if len(value) != 0 && value[0] == '"' {
453
+			if v, err := strconv.Unquote(value); err == nil {
454
+				value = v
455
+
456
+				quoted = true
457
+			} else {
458
+				return nil, &IniError{
459
+					Message:    err.Error(),
460
+					File:       filename,
461
+					LineNumber: lineno,
462
+				}
463
+			}
464
+		}
465
+
466
+		section = append(section, iniValue{
467
+			Name:       name,
468
+			Value:      value,
469
+			Quoted:     quoted,
470
+			LineNumber: lineno,
471
+		})
472
+
473
+		ret.Sections[sectionname] = section
474
+	}
475
+
476
+	return ret, nil
477
+}
478
+
479
+func (i *IniParser) matchingGroups(name string) []*Group {
480
+	if len(name) == 0 {
481
+		var ret []*Group
482
+
483
+		i.parser.eachGroup(func(g *Group) {
484
+			ret = append(ret, g)
485
+		})
486
+
487
+		return ret
488
+	}
489
+
490
+	g := i.parser.groupByName(name)
491
+
492
+	if g != nil {
493
+		return []*Group{g}
494
+	}
495
+
496
+	return nil
497
+}
498
+
499
+func (i *IniParser) parse(ini *ini) error {
500
+	p := i.parser
501
+
502
+	var quotesLookup = make(map[*Option]bool)
503
+
504
+	for name, section := range ini.Sections {
505
+		groups := i.matchingGroups(name)
506
+
507
+		if len(groups) == 0 {
508
+			return newErrorf(ErrUnknownGroup, "could not find option group `%s'", name)
509
+		}
510
+
511
+		for _, inival := range section {
512
+			var opt *Option
513
+
514
+			for _, group := range groups {
515
+				opt = group.optionByName(inival.Name, func(o *Option, n string) bool {
516
+					return strings.ToLower(o.tag.Get("ini-name")) == strings.ToLower(n)
517
+				})
518
+
519
+				if opt != nil && len(opt.tag.Get("no-ini")) != 0 {
520
+					opt = nil
521
+				}
522
+
523
+				if opt != nil {
524
+					break
525
+				}
526
+			}
527
+
528
+			if opt == nil {
529
+				if (p.Options & IgnoreUnknown) == None {
530
+					return &IniError{
531
+						Message:    fmt.Sprintf("unknown option: %s", inival.Name),
532
+						File:       ini.File,
533
+						LineNumber: inival.LineNumber,
534
+					}
535
+				}
536
+
537
+				continue
538
+			}
539
+
540
+			// ini value is ignored if override is set and
541
+			// value was previously set from non default
542
+			if i.ParseAsDefaults && !opt.isSetDefault {
543
+				continue
544
+			}
545
+
546
+			pval := &inival.Value
547
+
548
+			if !opt.canArgument() && len(inival.Value) == 0 {
549
+				pval = nil
550
+			} else {
551
+				if opt.value.Type().Kind() == reflect.Map {
552
+					parts := strings.SplitN(inival.Value, ":", 2)
553
+
554
+					// only handle unquoting
555
+					if len(parts) == 2 && parts[1][0] == '"' {
556
+						if v, err := strconv.Unquote(parts[1]); err == nil {
557
+							parts[1] = v
558
+
559
+							inival.Quoted = true
560
+						} else {
561
+							return &IniError{
562
+								Message:    err.Error(),
563
+								File:       ini.File,
564
+								LineNumber: inival.LineNumber,
565
+							}
566
+						}
567
+
568
+						s := parts[0] + ":" + parts[1]
569
+
570
+						pval = &s
571
+					}
572
+				}
573
+			}
574
+
575
+			if err := opt.set(pval); err != nil {
576
+				return &IniError{
577
+					Message:    err.Error(),
578
+					File:       ini.File,
579
+					LineNumber: inival.LineNumber,
580
+				}
581
+			}
582
+
583
+			// either all INI values are quoted or only values who need quoting
584
+			if _, ok := quotesLookup[opt]; !inival.Quoted || !ok {
585
+				quotesLookup[opt] = inival.Quoted
586
+			}
587
+
588
+			opt.tag.Set("_read-ini-name", inival.Name)
589
+		}
590
+	}
591
+
592
+	for opt, quoted := range quotesLookup {
593
+		opt.iniQuote = quoted
594
+	}
595
+
596
+	return nil
597
+}

+ 1053
- 0
vendor/src/github.com/jessevdk/go-flags/ini_test.go
Datei-Diff unterdrückt, da er zu groß ist
Datei anzeigen


+ 85
- 0
vendor/src/github.com/jessevdk/go-flags/long_test.go Datei anzeigen

@@ -0,0 +1,85 @@
1
+package flags
2
+
3
+import (
4
+	"testing"
5
+)
6
+
7
+func TestLong(t *testing.T) {
8
+	var opts = struct {
9
+		Value bool `long:"value"`
10
+	}{}
11
+
12
+	ret := assertParseSuccess(t, &opts, "--value")
13
+
14
+	assertStringArray(t, ret, []string{})
15
+
16
+	if !opts.Value {
17
+		t.Errorf("Expected Value to be true")
18
+	}
19
+}
20
+
21
+func TestLongArg(t *testing.T) {
22
+	var opts = struct {
23
+		Value string `long:"value"`
24
+	}{}
25
+
26
+	ret := assertParseSuccess(t, &opts, "--value", "value")
27
+
28
+	assertStringArray(t, ret, []string{})
29
+	assertString(t, opts.Value, "value")
30
+}
31
+
32
+func TestLongArgEqual(t *testing.T) {
33
+	var opts = struct {
34
+		Value string `long:"value"`
35
+	}{}
36
+
37
+	ret := assertParseSuccess(t, &opts, "--value=value")
38
+
39
+	assertStringArray(t, ret, []string{})
40
+	assertString(t, opts.Value, "value")
41
+}
42
+
43
+func TestLongDefault(t *testing.T) {
44
+	var opts = struct {
45
+		Value string `long:"value" default:"value"`
46
+	}{}
47
+
48
+	ret := assertParseSuccess(t, &opts)
49
+
50
+	assertStringArray(t, ret, []string{})
51
+	assertString(t, opts.Value, "value")
52
+}
53
+
54
+func TestLongOptional(t *testing.T) {
55
+	var opts = struct {
56
+		Value string `long:"value" optional:"yes" optional-value:"value"`
57
+	}{}
58
+
59
+	ret := assertParseSuccess(t, &opts, "--value")
60
+
61
+	assertStringArray(t, ret, []string{})
62
+	assertString(t, opts.Value, "value")
63
+}
64
+
65
+func TestLongOptionalArg(t *testing.T) {
66
+	var opts = struct {
67
+		Value string `long:"value" optional:"yes" optional-value:"value"`
68
+	}{}
69
+
70
+	ret := assertParseSuccess(t, &opts, "--value", "no")
71
+
72
+	assertStringArray(t, ret, []string{"no"})
73
+	assertString(t, opts.Value, "value")
74
+}
75
+
76
+func TestLongOptionalArgEqual(t *testing.T) {
77
+	var opts = struct {
78
+		Value string `long:"value" optional:"yes" optional-value:"value"`
79
+	}{}
80
+
81
+	ret := assertParseSuccess(t, &opts, "--value=value", "no")
82
+
83
+	assertStringArray(t, ret, []string{"no"})
84
+	assertString(t, opts.Value, "value")
85
+}

+ 205
- 0
vendor/src/github.com/jessevdk/go-flags/man.go Datei anzeigen

@@ -0,0 +1,205 @@
1
+package flags
2
+
3
+import (
4
+	"fmt"
5
+	"io"
6
+	"runtime"
7
+	"strings"
8
+	"time"
9
+)
10
+
11
+func manQuote(s string) string {
12
+	return strings.Replace(s, "\\", "\\\\", -1)
13
+}
14
+
15
+func formatForMan(wr io.Writer, s string) {
16
+	for {
17
+		idx := strings.IndexRune(s, '`')
18
+
19
+		if idx < 0 {
20
+			fmt.Fprintf(wr, "%s", manQuote(s))
21
+			break
22
+		}
23
+
24
+		fmt.Fprintf(wr, "%s", manQuote(s[:idx]))
25
+
26
+		s = s[idx+1:]
27
+		idx = strings.IndexRune(s, '\'')
28
+
29
+		if idx < 0 {
30
+			fmt.Fprintf(wr, "%s", manQuote(s))
31
+			break
32
+		}
33
+
34
+		fmt.Fprintf(wr, "\\fB%s\\fP", manQuote(s[:idx]))
35
+		s = s[idx+1:]
36
+	}
37
+}
38
+
39
+func writeManPageOptions(wr io.Writer, grp *Group) {
40
+	grp.eachGroup(func(group *Group) {
41
+		if group.Hidden || len(group.options) == 0 {
42
+			return
43
+		}
44
+
45
+		// If the parent (grp) has any subgroups, display their descriptions as
46
+		// subsection headers similar to the output of --help.
47
+		if group.ShortDescription != "" && len(grp.groups) > 0 {
48
+			fmt.Fprintf(wr, ".SS %s\n", group.ShortDescription)
49
+
50
+			if group.LongDescription != "" {
51
+				formatForMan(wr, group.LongDescription)
52
+				fmt.Fprintln(wr, "")
53
+			}
54
+		}
55
+
56
+		for _, opt := range group.options {
57
+			if !opt.canCli() || opt.Hidden {
58
+				continue
59
+			}
60
+
61
+			fmt.Fprintln(wr, ".TP")
62
+			fmt.Fprintf(wr, "\\fB")
63
+
64
+			if opt.ShortName != 0 {
65
+				fmt.Fprintf(wr, "\\fB\\-%c\\fR", opt.ShortName)
66
+			}
67
+
68
+			if len(opt.LongName) != 0 {
69
+				if opt.ShortName != 0 {
70
+					fmt.Fprintf(wr, ", ")
71
+				}
72
+
73
+				fmt.Fprintf(wr, "\\fB\\-\\-%s\\fR", manQuote(opt.LongNameWithNamespace()))
74
+			}
75
+
76
+			if len(opt.ValueName) != 0 || opt.OptionalArgument {
77
+				if opt.OptionalArgument {
78
+					fmt.Fprintf(wr, " [\\fI%s=%s\\fR]", manQuote(opt.ValueName), manQuote(strings.Join(quoteV(opt.OptionalValue), ", ")))
79
+				} else {
80
+					fmt.Fprintf(wr, " \\fI%s\\fR", manQuote(opt.ValueName))
81
+				}
82
+			}
83
+
84
+			if len(opt.Default) != 0 {
85
+				fmt.Fprintf(wr, " <default: \\fI%s\\fR>", manQuote(strings.Join(quoteV(opt.Default), ", ")))
86
+			} else if len(opt.EnvDefaultKey) != 0 {
87
+				if runtime.GOOS == "windows" {
88
+					fmt.Fprintf(wr, " <default: \\fI%%%s%%\\fR>", manQuote(opt.EnvDefaultKey))
89
+				} else {
90
+					fmt.Fprintf(wr, " <default: \\fI$%s\\fR>", manQuote(opt.EnvDefaultKey))
91
+				}
92
+			}
93
+
94
+			if opt.Required {
95
+				fmt.Fprintf(wr, " (\\fIrequired\\fR)")
96
+			}
97
+
98
+			fmt.Fprintln(wr, "\\fP")
99
+
100
+			if len(opt.Description) != 0 {
101
+				formatForMan(wr, opt.Description)
102
+				fmt.Fprintln(wr, "")
103
+			}
104
+		}
105
+	})
106
+}
107
+
108
+func writeManPageSubcommands(wr io.Writer, name string, root *Command) {
109
+	commands := root.sortedVisibleCommands()
110
+
111
+	for _, c := range commands {
112
+		var nn string
113
+
114
+		if c.Hidden {
115
+			continue
116
+		}
117
+
118
+		if len(name) != 0 {
119
+			nn = name + " " + c.Name
120
+		} else {
121
+			nn = c.Name
122
+		}
123
+
124
+		writeManPageCommand(wr, nn, root, c)
125
+	}
126
+}
127
+
128
+func writeManPageCommand(wr io.Writer, name string, root *Command, command *Command) {
129
+	fmt.Fprintf(wr, ".SS %s\n", name)
130
+	fmt.Fprintln(wr, command.ShortDescription)
131
+
132
+	if len(command.LongDescription) > 0 {
133
+		fmt.Fprintln(wr, "")
134
+
135
+		cmdstart := fmt.Sprintf("The %s command", manQuote(command.Name))
136
+
137
+		if strings.HasPrefix(command.LongDescription, cmdstart) {
138
+			fmt.Fprintf(wr, "The \\fI%s\\fP command", manQuote(command.Name))
139
+
140
+			formatForMan(wr, command.LongDescription[len(cmdstart):])
141
+			fmt.Fprintln(wr, "")
142
+		} else {
143
+			formatForMan(wr, command.LongDescription)
144
+			fmt.Fprintln(wr, "")
145
+		}
146
+	}
147
+
148
+	var usage string
149
+	if us, ok := command.data.(Usage); ok {
150
+		usage = us.Usage()
151
+	} else if command.hasCliOptions() {
152
+		usage = fmt.Sprintf("[%s-OPTIONS]", command.Name)
153
+	}
154
+
155
+	var pre string
156
+	if root.hasCliOptions() {
157
+		pre = fmt.Sprintf("%s [OPTIONS] %s", root.Name, command.Name)
158
+	} else {
159
+		pre = fmt.Sprintf("%s %s", root.Name, command.Name)
160
+	}
161
+
162
+	if len(usage) > 0 {
163
+		fmt.Fprintf(wr, "\n\\fBUsage\\fP: %s %s\n.TP\n", manQuote(pre), manQuote(usage))
164
+	}
165
+
166
+	if len(command.Aliases) > 0 {
167
+		fmt.Fprintf(wr, "\n\\fBAliases\\fP: %s\n\n", manQuote(strings.Join(command.Aliases, ", ")))
168
+	}
169
+
170
+	writeManPageOptions(wr, command.Group)
171
+	writeManPageSubcommands(wr, name, command)
172
+}
173
+
174
+// WriteManPage writes a basic man page in groff format to the specified
175
+// writer.
176
+func (p *Parser) WriteManPage(wr io.Writer) {
177
+	t := time.Now()
178
+
179
+	fmt.Fprintf(wr, ".TH %s 1 \"%s\"\n", manQuote(p.Name), t.Format("2 January 2006"))
180
+	fmt.Fprintln(wr, ".SH NAME")
181
+	fmt.Fprintf(wr, "%s \\- %s\n", manQuote(p.Name), manQuote(p.ShortDescription))
182
+	fmt.Fprintln(wr, ".SH SYNOPSIS")
183
+
184
+	usage := p.Usage
185
+
186
+	if len(usage) == 0 {
187
+		usage = "[OPTIONS]"
188
+	}
189
+
190
+	fmt.Fprintf(wr, "\\fB%s\\fP %s\n", manQuote(p.Name), manQuote(usage))
191
+	fmt.Fprintln(wr, ".SH DESCRIPTION")
192
+
193
+	formatForMan(wr, p.LongDescription)
194
+	fmt.Fprintln(wr, "")
195
+
196
+	fmt.Fprintln(wr, ".SH OPTIONS")
197
+
198
+	writeManPageOptions(wr, p.Command.Group)
199
+
200
+	if len(p.visibleCommands()) > 0 {
201
+		fmt.Fprintln(wr, ".SH COMMANDS")
202
+
203
+		writeManPageSubcommands(wr, "", p.Command)
204
+	}
205
+}

+ 119
- 0
vendor/src/github.com/jessevdk/go-flags/marshal_test.go Datei anzeigen

@@ -0,0 +1,119 @@
1
+package flags
2
+
3
+import (
4
+	"fmt"
5
+	"testing"
6
+)
7
+
8
+type marshalled string
9
+
10
+func (m *marshalled) UnmarshalFlag(value string) error {
11
+	if value == "yes" {
12
+		*m = "true"
13
+	} else if value == "no" {
14
+		*m = "false"
15
+	} else {
16
+		return fmt.Errorf("`%s' is not a valid value, please specify `yes' or `no'", value)
17
+	}
18
+
19
+	return nil
20
+}
21
+
22
+func (m marshalled) MarshalFlag() (string, error) {
23
+	if m == "true" {
24
+		return "yes", nil
25
+	}
26
+
27
+	return "no", nil
28
+}
29
+
30
+type marshalledError bool
31
+
32
+func (m marshalledError) MarshalFlag() (string, error) {
33
+	return "", newErrorf(ErrMarshal, "Failed to marshal")
34
+}
35
+
36
+func TestUnmarshal(t *testing.T) {
37
+	var opts = struct {
38
+		Value marshalled `short:"v"`
39
+	}{}
40
+
41
+	ret := assertParseSuccess(t, &opts, "-v=yes")
42
+
43
+	assertStringArray(t, ret, []string{})
44
+
45
+	if opts.Value != "true" {
46
+		t.Errorf("Expected Value to be \"true\"")
47
+	}
48
+}
49
+
50
+func TestUnmarshalDefault(t *testing.T) {
51
+	var opts = struct {
52
+		Value marshalled `short:"v" default:"yes"`
53
+	}{}
54
+
55
+	ret := assertParseSuccess(t, &opts)
56
+
57
+	assertStringArray(t, ret, []string{})
58
+
59
+	if opts.Value != "true" {
60
+		t.Errorf("Expected Value to be \"true\"")
61
+	}
62
+}
63
+
64
+func TestUnmarshalOptional(t *testing.T) {
65
+	var opts = struct {
66
+		Value marshalled `short:"v" optional:"yes" optional-value:"yes"`
67
+	}{}
68
+
69
+	ret := assertParseSuccess(t, &opts, "-v")
70
+
71
+	assertStringArray(t, ret, []string{})
72
+
73
+	if opts.Value != "true" {
74
+		t.Errorf("Expected Value to be \"true\"")
75
+	}
76
+}
77
+
78
+func TestUnmarshalError(t *testing.T) {
79
+	var opts = struct {
80
+		Value marshalled `short:"v"`
81
+	}{}
82
+
83
+	assertParseFail(t, ErrMarshal, fmt.Sprintf("invalid argument for flag `%cv' (expected flags.marshalled): `invalid' is not a valid value, please specify `yes' or `no'", defaultShortOptDelimiter), &opts, "-vinvalid")
84
+}
85
+
86
+func TestUnmarshalPositionalError(t *testing.T) {
87
+	var opts = struct {
88
+		Args struct {
89
+			Value marshalled
90
+		} `positional-args:"yes"`
91
+	}{}
92
+
93
+	parser := NewParser(&opts, Default&^PrintErrors)
94
+	_, err := parser.ParseArgs([]string{"invalid"})
95
+
96
+	msg := "`invalid' is not a valid value, please specify `yes' or `no'"
97
+
98
+	if err == nil {
99
+		assertFatalf(t, "Expected error: %s", msg)
100
+		return
101
+	}
102
+
103
+	if err.Error() != msg {
104
+		assertErrorf(t, "Expected error message %#v, but got %#v", msg, err.Error())
105
+	}
106
+}
107
+
108
+func TestMarshalError(t *testing.T) {
109
+	var opts = struct {
110
+		Value marshalledError `short:"v"`
111
+	}{}
112
+
113
+	p := NewParser(&opts, Default)
114
+	o := p.Command.Groups()[0].Options()[0]
115
+
116
+	_, err := convertToString(o.value, o.tag)
117
+
118
+	assertError(t, err, ErrMarshal, "Failed to marshal")
119
+}

+ 140
- 0
vendor/src/github.com/jessevdk/go-flags/multitag.go Datei anzeigen

@@ -0,0 +1,140 @@
1
+package flags
2
+
3
+import (
4
+	"strconv"
5
+)
6
+
7
+type multiTag struct {
8
+	value string
9
+	cache map[string][]string
10
+}
11
+
12
+func newMultiTag(v string) multiTag {
13
+	return multiTag{
14
+		value: v,
15
+	}
16
+}
17
+
18
+func (x *multiTag) scan() (map[string][]string, error) {
19
+	v := x.value
20
+
21
+	ret := make(map[string][]string)
22
+
23
+	// This is mostly copied from reflect.StructTag.Get
24
+	for v != "" {
25
+		i := 0
26
+
27
+		// Skip whitespace
28
+		for i < len(v) && v[i] == ' ' {
29
+			i++
30
+		}
31
+
32
+		v = v[i:]
33
+
34
+		if v == "" {
35
+			break
36
+		}
37
+
38
+		// Scan to colon to find key
39
+		i = 0
40
+
41
+		for i < len(v) && v[i] != ' ' && v[i] != ':' && v[i] != '"' {
42
+			i++
43
+		}
44
+
45
+		if i >= len(v) {
46
+			return nil, newErrorf(ErrTag, "expected `:' after key name, but got end of tag (in `%v`)", x.value)
47
+		}
48
+
49
+		if v[i] != ':' {
50
+			return nil, newErrorf(ErrTag, "expected `:' after key name, but got `%v' (in `%v`)", v[i], x.value)
51
+		}
52
+
53
+		if i+1 >= len(v) {
54
+			return nil, newErrorf(ErrTag, "expected `\"' to start tag value at end of tag (in `%v`)", x.value)
55
+		}
56
+
57
+		if v[i+1] != '"' {
58
+			return nil, newErrorf(ErrTag, "expected `\"' to start tag value, but got `%v' (in `%v`)", v[i+1], x.value)
59
+		}
60
+
61
+		name := v[:i]
62
+		v = v[i+1:]
63
+
64
+		// Scan quoted string to find value
65
+		i = 1
66
+
67
+		for i < len(v) && v[i] != '"' {
68
+			if v[i] == '\n' {
69
+				return nil, newErrorf(ErrTag, "unexpected newline in tag value `%v' (in `%v`)", name, x.value)
70
+			}
71
+
72
+			if v[i] == '\\' {
73
+				i++
74
+			}
75
+			i++
76
+		}
77
+
78
+		if i >= len(v) {
79
+			return nil, newErrorf(ErrTag, "expected end of tag value `\"' at end of tag (in `%v`)", x.value)
80
+		}
81
+
82
+		val, err := strconv.Unquote(v[:i+1])
83
+
84
+		if err != nil {
85
+			return nil, newErrorf(ErrTag, "Malformed value of tag `%v:%v` => %v (in `%v`)", name, v[:i+1], err, x.value)
86
+		}
87
+
88
+		v = v[i+1:]
89
+
90
+		ret[name] = append(ret[name], val)
91
+	}
92
+
93
+	return ret, nil
94
+}
95
+
96
+func (x *multiTag) Parse() error {
97
+	vals, err := x.scan()
98
+	x.cache = vals
99
+
100
+	return err
101
+}
102
+
103
+func (x *multiTag) cached() map[string][]string {
104
+	if x.cache == nil {
105
+		cache, _ := x.scan()
106
+
107
+		if cache == nil {
108
+			cache = make(map[string][]string)
109
+		}
110
+
111
+		x.cache = cache
112
+	}
113
+
114
+	return x.cache
115
+}
116
+
117
+func (x *multiTag) Get(key string) string {
118
+	c := x.cached()
119
+
120
+	if v, ok := c[key]; ok {
121
+		return v[len(v)-1]
122
+	}
123
+
124
+	return ""
125
+}
126
+
127
+func (x *multiTag) GetMany(key string) []string {
128
+	c := x.cached()
129
+	return c[key]
130
+}
131
+
132
+func (x *multiTag) Set(key string, value string) {
133
+	c := x.cached()
134
+	c[key] = []string{value}
135
+}
136
+
137
+func (x *multiTag) SetMany(key string, value []string) {
138
+	c := x.cached()
139
+	c[key] = value
140
+}

+ 461
- 0
vendor/src/github.com/jessevdk/go-flags/option.go Datei anzeigen

@@ -0,0 +1,461 @@
1
+package flags
2
+
3
+import (
4
+	"bytes"
5
+	"fmt"
6
+	"reflect"
7
+	"strings"
8
+	"syscall"
9
+	"unicode/utf8"
10
+)
11
+
12
+// Option flag information. Contains a description of the option, short and
13
+// long name as well as a default value and whether an argument for this
14
+// flag is optional.
15
+type Option struct {
16
+	// The description of the option flag. This description is shown
17
+	// automatically in the built-in help.
18
+	Description string
19
+
20
+	// The short name of the option (a single character). If not 0, the
21
+	// option flag can be 'activated' using -<ShortName>. Either ShortName
22
+	// or LongName needs to be non-empty.
23
+	ShortName rune
24
+
25
+	// The long name of the option. If not "", the option flag can be
26
+	// activated using --<LongName>. Either ShortName or LongName needs
27
+	// to be non-empty.
28
+	LongName string
29
+
30
+	// The default value of the option.
31
+	Default []string
32
+
33
+	// The optional environment default value key name.
34
+	EnvDefaultKey string
35
+
36
+	// The optional delimiter string for EnvDefaultKey values.
37
+	EnvDefaultDelim string
38
+
39
+	// If true, specifies that the argument to an option flag is optional.
40
+	// When no argument to the flag is specified on the command line, the
41
+	// value of OptionalValue will be set in the field this option represents.
42
+	// This is only valid for non-boolean options.
43
+	OptionalArgument bool
44
+
45
+	// The optional value of the option. The optional value is used when
46
+	// the option flag is marked as having an OptionalArgument. This means
47
+	// that when the flag is specified, but no option argument is given,
48
+	// the value of the field this option represents will be set to
49
+	// OptionalValue. This is only valid for non-boolean options.
50
+	OptionalValue []string
51
+
52
+	// If true, the option _must_ be specified on the command line. If the
53
+	// option is not specified, the parser will generate an ErrRequired type
54
+	// error.
55
+	Required bool
56
+
57
+	// A name for the value of an option shown in the Help as --flag [ValueName]
58
+	ValueName string
59
+
60
+	// A mask value to show in the help instead of the default value. This
61
+	// is useful for hiding sensitive information in the help, such as
62
+	// passwords.
63
+	DefaultMask string
64
+
65
+	// If non empty, only a certain set of values is allowed for an option.
66
+	Choices []string
67
+
68
+	// If true, the option is not displayed in the help or man page
69
+	Hidden bool
70
+
71
+	// The group which the option belongs to
72
+	group *Group
73
+
74
+	// The struct field which the option represents.
75
+	field reflect.StructField
76
+
77
+	// The struct field value which the option represents.
78
+	value reflect.Value
79
+
80
+	// Determines if the option will be always quoted in the INI output
81
+	iniQuote bool
82
+
83
+	tag            multiTag
84
+	isSet          bool
85
+	isSetDefault   bool
86
+	preventDefault bool
87
+
88
+	defaultLiteral string
89
+}
90
+
91
+// LongNameWithNamespace returns the option's long name with the group namespaces
92
+// prepended by walking up the option's group tree. Namespaces and the long name
93
+// itself are separated by the parser's namespace delimiter. If the long name is
94
+// empty an empty string is returned.
95
+func (option *Option) LongNameWithNamespace() string {
96
+	if len(option.LongName) == 0 {
97
+		return ""
98
+	}
99
+
100
+	// fetch the namespace delimiter from the parser which is always at the
101
+	// end of the group hierarchy
102
+	namespaceDelimiter := ""
103
+	g := option.group
104
+
105
+	for {
106
+		if p, ok := g.parent.(*Parser); ok {
107
+			namespaceDelimiter = p.NamespaceDelimiter
108
+
109
+			break
110
+		}
111
+
112
+		switch i := g.parent.(type) {
113
+		case *Command:
114
+			g = i.Group
115
+		case *Group:
116
+			g = i
117
+		}
118
+	}
119
+
120
+	// concatenate long name with namespace
121
+	longName := option.LongName
122
+	g = option.group
123
+
124
+	for g != nil {
125
+		if g.Namespace != "" {
126
+			longName = g.Namespace + namespaceDelimiter + longName
127
+		}
128
+
129
+		switch i := g.parent.(type) {
130
+		case *Command:
131
+			g = i.Group
132
+		case *Group:
133
+			g = i
134
+		case *Parser:
135
+			g = nil
136
+		}
137
+	}
138
+
139
+	return longName
140
+}
141
+
142
+// String converts an option to a human friendly readable string describing the
143
+// option.
144
+func (option *Option) String() string {
145
+	var s string
146
+	var short string
147
+
148
+	if option.ShortName != 0 {
149
+		data := make([]byte, utf8.RuneLen(option.ShortName))
150
+		utf8.EncodeRune(data, option.ShortName)
151
+		short = string(data)
152
+
153
+		if len(option.LongName) != 0 {
154
+			s = fmt.Sprintf("%s%s, %s%s",
155
+				string(defaultShortOptDelimiter), short,
156
+				defaultLongOptDelimiter, option.LongNameWithNamespace())
157
+		} else {
158
+			s = fmt.Sprintf("%s%s", string(defaultShortOptDelimiter), short)
159
+		}
160
+	} else if len(option.LongName) != 0 {
161
+		s = fmt.Sprintf("%s%s", defaultLongOptDelimiter, option.LongNameWithNamespace())
162
+	}
163
+
164
+	return s
165
+}
166
+
167
+// Value returns the option value as an interface{}.
168
+func (option *Option) Value() interface{} {
169
+	return option.value.Interface()
170
+}
171
+
172
+// Field returns the reflect struct field of the option.
173
+func (option *Option) Field() reflect.StructField {
174
+	return option.field
175
+}
176
+
177
+// IsSet returns true if option has been set
178
+func (option *Option) IsSet() bool {
179
+	return option.isSet
180
+}
181
+
182
+// IsSetDefault returns true if option has been set via the default option tag
183
+func (option *Option) IsSetDefault() bool {
184
+	return option.isSetDefault
185
+}
186
+
187
+// Set the value of an option to the specified value. An error will be returned
188
+// if the specified value could not be converted to the corresponding option
189
+// value type.
190
+func (option *Option) set(value *string) error {
191
+	kind := option.value.Type().Kind()
192
+
193
+	if (kind == reflect.Map || kind == reflect.Slice) && !option.isSet {
194
+		option.empty()
195
+	}
196
+
197
+	option.isSet = true
198
+	option.preventDefault = true
199
+
200
+	if len(option.Choices) != 0 {
201
+		found := false
202
+
203
+		for _, choice := range option.Choices {
204
+			if choice == *value {
205
+				found = true
206
+				break
207
+			}
208
+		}
209
+
210
+		if !found {
211
+			allowed := strings.Join(option.Choices[0:len(option.Choices)-1], ", ")
212
+
213
+			if len(option.Choices) > 1 {
214
+				allowed += " or " + option.Choices[len(option.Choices)-1]
215
+			}
216
+
217
+			return newErrorf(ErrInvalidChoice,
218
+				"Invalid value `%s' for option `%s'. Allowed values are: %s",
219
+				*value, option, allowed)
220
+		}
221
+	}
222
+
223
+	if option.isFunc() {
224
+		return option.call(value)
225
+	} else if value != nil {
226
+		return convert(*value, option.value, option.tag)
227
+	}
228
+
229
+	return convert("", option.value, option.tag)
230
+}
231
+
232
+func (option *Option) canCli() bool {
233
+	return option.ShortName != 0 || len(option.LongName) != 0
234
+}
235
+
236
+func (option *Option) canArgument() bool {
237
+	if u := option.isUnmarshaler(); u != nil {
238
+		return true
239
+	}
240
+
241
+	return !option.isBool()
242
+}
243
+
244
+func (option *Option) emptyValue() reflect.Value {
245
+	tp := option.value.Type()
246
+
247
+	if tp.Kind() == reflect.Map {
248
+		return reflect.MakeMap(tp)
249
+	}
250
+
251
+	return reflect.Zero(tp)
252
+}
253
+
254
+func (option *Option) empty() {
255
+	if !option.isFunc() {
256
+		option.value.Set(option.emptyValue())
257
+	}
258
+}
259
+
260
+func (option *Option) clearDefault() {
261
+	usedDefault := option.Default
262
+
263
+	if envKey := option.EnvDefaultKey; envKey != "" {
264
+		// os.Getenv() makes no distinction between undefined and
265
+		// empty values, so we use syscall.Getenv()
266
+		if value, ok := syscall.Getenv(envKey); ok {
267
+			if option.EnvDefaultDelim != "" {
268
+				usedDefault = strings.Split(value,
269
+					option.EnvDefaultDelim)
270
+			} else {
271
+				usedDefault = []string{value}
272
+			}
273
+		}
274
+	}
275
+
276
+	option.isSetDefault = true
277
+
278
+	if len(usedDefault) > 0 {
279
+		option.empty()
280
+
281
+		for _, d := range usedDefault {
282
+			option.set(&d)
283
+			option.isSetDefault = true
284
+		}
285
+	} else {
286
+		tp := option.value.Type()
287
+
288
+		switch tp.Kind() {
289
+		case reflect.Map:
290
+			if option.value.IsNil() {
291
+				option.empty()
292
+			}
293
+		case reflect.Slice:
294
+			if option.value.IsNil() {
295
+				option.empty()
296
+			}
297
+		}
298
+	}
299
+}
300
+
301
+func (option *Option) valueIsDefault() bool {
302
+	// Check if the value of the option corresponds to its
303
+	// default value
304
+	emptyval := option.emptyValue()
305
+
306
+	checkvalptr := reflect.New(emptyval.Type())
307
+	checkval := reflect.Indirect(checkvalptr)
308
+
309
+	checkval.Set(emptyval)
310
+
311
+	if len(option.Default) != 0 {
312
+		for _, v := range option.Default {
313
+			convert(v, checkval, option.tag)
314
+		}
315
+	}
316
+
317
+	return reflect.DeepEqual(option.value.Interface(), checkval.Interface())
318
+}
319
+
320
+func (option *Option) isUnmarshaler() Unmarshaler {
321
+	v := option.value
322
+
323
+	for {
324
+		if !v.CanInterface() {
325
+			break
326
+		}
327
+
328
+		i := v.Interface()
329
+
330
+		if u, ok := i.(Unmarshaler); ok {
331
+			return u
332
+		}
333
+
334
+		if !v.CanAddr() {
335
+			break
336
+		}
337
+
338
+		v = v.Addr()
339
+	}
340
+
341
+	return nil
342
+}
343
+
344
+func (option *Option) isBool() bool {
345
+	tp := option.value.Type()
346
+
347
+	for {
348
+		switch tp.Kind() {
349
+		case reflect.Slice, reflect.Ptr:
350
+			tp = tp.Elem()
351
+		case reflect.Bool:
352
+			return true
353
+		case reflect.Func:
354
+			return tp.NumIn() == 0
355
+		default:
356
+			return false
357
+		}
358
+	}
359
+}
360
+
361
+func (option *Option) isSignedNumber() bool {
362
+	tp := option.value.Type()
363
+
364
+	for {
365
+		switch tp.Kind() {
366
+		case reflect.Slice, reflect.Ptr:
367
+			tp = tp.Elem()
368
+		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Float32, reflect.Float64:
369
+			return true
370
+		default:
371
+			return false
372
+		}
373
+	}
374
+}
375
+
376
+func (option *Option) isFunc() bool {
377
+	return option.value.Type().Kind() == reflect.Func
378
+}
379
+
380
+func (option *Option) call(value *string) error {
381
+	var retval []reflect.Value
382
+
383
+	if value == nil {
384
+		retval = option.value.Call(nil)
385
+	} else {
386
+		tp := option.value.Type().In(0)
387
+
388
+		val := reflect.New(tp)
389
+		val = reflect.Indirect(val)
390
+
391
+		if err := convert(*value, val, option.tag); err != nil {
392
+			return err
393
+		}
394
+
395
+		retval = option.value.Call([]reflect.Value{val})
396
+	}
397
+
398
+	if len(retval) == 1 && retval[0].Type() == reflect.TypeOf((*error)(nil)).Elem() {
399
+		if retval[0].Interface() == nil {
400
+			return nil
401
+		}
402
+
403
+		return retval[0].Interface().(error)
404
+	}
405
+
406
+	return nil
407
+}
408
+
409
+func (option *Option) updateDefaultLiteral() {
410
+	defs := option.Default
411
+	def := ""
412
+
413
+	if len(defs) == 0 && option.canArgument() {
414
+		var showdef bool
415
+
416
+		switch option.field.Type.Kind() {
417
+		case reflect.Func, reflect.Ptr:
418
+			showdef = !option.value.IsNil()
419
+		case reflect.Slice, reflect.String, reflect.Array:
420
+			showdef = option.value.Len() > 0
421
+		case reflect.Map:
422
+			showdef = !option.value.IsNil() && option.value.Len() > 0
423
+		default:
424
+			zeroval := reflect.Zero(option.field.Type)
425
+			showdef = !reflect.DeepEqual(zeroval.Interface(), option.value.Interface())
426
+		}
427
+
428
+		if showdef {
429
+			def, _ = convertToString(option.value, option.tag)
430
+		}
431
+	} else if len(defs) != 0 {
432
+		l := len(defs) - 1
433
+
434
+		for i := 0; i < l; i++ {
435
+			def += quoteIfNeeded(defs[i]) + ", "
436
+		}
437
+
438
+		def += quoteIfNeeded(defs[l])
439
+	}
440
+
441
+	option.defaultLiteral = def
442
+}
443
+
444
+func (option *Option) shortAndLongName() string {
445
+	ret := &bytes.Buffer{}
446
+
447
+	if option.ShortName != 0 {
448
+		ret.WriteRune(defaultShortOptDelimiter)
449
+		ret.WriteRune(option.ShortName)
450
+	}
451
+
452
+	if len(option.LongName) != 0 {
453
+		if option.ShortName != 0 {
454
+			ret.WriteRune('/')
455
+		}
456
+
457
+		ret.WriteString(option.LongName)
458
+	}
459
+
460
+	return ret.String()
461
+}

+ 45
- 0
vendor/src/github.com/jessevdk/go-flags/options_test.go Datei anzeigen

@@ -0,0 +1,45 @@
1
+package flags
2
+
3
+import (
4
+	"testing"
5
+)
6
+
7
+func TestPassDoubleDash(t *testing.T) {
8
+	var opts = struct {
9
+		Value bool `short:"v"`
10
+	}{}
11
+
12
+	p := NewParser(&opts, PassDoubleDash)
13
+	ret, err := p.ParseArgs([]string{"-v", "--", "-v", "-g"})
14
+
15
+	if err != nil {
16
+		t.Fatalf("Unexpected error: %v", err)
17
+		return
18
+	}
19
+
20
+	if !opts.Value {
21
+		t.Errorf("Expected Value to be true")
22
+	}
23
+
24
+	assertStringArray(t, ret, []string{"-v", "-g"})
25
+}
26
+
27
+func TestPassAfterNonOption(t *testing.T) {
28
+	var opts = struct {
29
+		Value bool `short:"v"`
30
+	}{}
31
+
32
+	p := NewParser(&opts, PassAfterNonOption)
33
+	ret, err := p.ParseArgs([]string{"-v", "arg", "-v", "-g"})
34
+
35
+	if err != nil {
36
+		t.Fatalf("Unexpected error: %v", err)
37
+		return
38
+	}
39
+
40
+	if !opts.Value {
41
+		t.Errorf("Expected Value to be true")
42
+	}
43
+
44
+	assertStringArray(t, ret, []string{"arg", "-v", "-g"})
45
+}

+ 67
- 0
vendor/src/github.com/jessevdk/go-flags/optstyle_other.go Datei anzeigen

@@ -0,0 +1,67 @@
1
+// +build !windows forceposix
2
+
3
+package flags
4
+
5
+import (
6
+	"strings"
7
+)
8
+
9
+const (
10
+	defaultShortOptDelimiter = '-'
11
+	defaultLongOptDelimiter  = "--"
12
+	defaultNameArgDelimiter  = '='
13
+)
14
+
15
+func argumentStartsOption(arg string) bool {
16
+	return len(arg) > 0 && arg[0] == '-'
17
+}
18
+
19
+func argumentIsOption(arg string) bool {
20
+	if len(arg) > 1 && arg[0] == '-' && arg[1] != '-' {
21
+		return true
22
+	}
23
+
24
+	if len(arg) > 2 && arg[0] == '-' && arg[1] == '-' && arg[2] != '-' {
25
+		return true
26
+	}
27
+
28
+	return false
29
+}
30
+
31
+// stripOptionPrefix returns the option without the prefix and whether or
32
+// not the option is a long option or not.
33
+func stripOptionPrefix(optname string) (prefix string, name string, islong bool) {
34
+	if strings.HasPrefix(optname, "--") {
35
+		return "--", optname[2:], true
36
+	} else if strings.HasPrefix(optname, "-") {
37
+		return "-", optname[1:], false
38
+	}
39
+
40
+	return "", optname, false
41
+}
42
+
43
+// splitOption attempts to split the passed option into a name and an argument.
44
+// When there is no argument specified, nil will be returned for it.
45
+func splitOption(prefix string, option string, islong bool) (string, string, *string) {
46
+	pos := strings.Index(option, "=")
47
+
48
+	if (islong && pos >= 0) || (!islong && pos == 1) {
49
+		rest := option[pos+1:]
50
+		return option[:pos], "=", &rest
51
+	}
52
+
53
+	return option, "", nil
54
+}
55
+
56
+// addHelpGroup adds a new group that contains default help parameters.
57
+func (c *Command) addHelpGroup(showHelp func() error) *Group {
58
+	var help struct {
59
+		ShowHelp func() error `short:"h" long:"help" description:"Show this help message"`
60
+	}
61
+
62
+	help.ShowHelp = showHelp
63
+	ret, _ := c.AddGroup("Help Options", "", &help)
64
+	ret.isBuiltinHelp = true
65
+
66
+	return ret
67
+}

+ 108
- 0
vendor/src/github.com/jessevdk/go-flags/optstyle_windows.go Datei anzeigen

@@ -0,0 +1,108 @@
1
+// +build !forceposix
2
+
3
+package flags
4
+
5
+import (
6
+	"strings"
7
+)
8
+
9
+// Windows uses a front slash for both short and long options.  Also it uses
10
+// a colon for name/argument delimter.
11
+const (
12
+	defaultShortOptDelimiter = '/'
13
+	defaultLongOptDelimiter  = "/"
14
+	defaultNameArgDelimiter  = ':'
15
+)
16
+
17
+func argumentStartsOption(arg string) bool {
18
+	return len(arg) > 0 && (arg[0] == '-' || arg[0] == '/')
19
+}
20
+
21
+func argumentIsOption(arg string) bool {
22
+	// Windows-style options allow front slash for the option
23
+	// delimiter.
24
+	if len(arg) > 1 && arg[0] == '/' {
25
+		return true
26
+	}
27
+
28
+	if len(arg) > 1 && arg[0] == '-' && arg[1] != '-' {
29
+		return true
30
+	}
31
+
32
+	if len(arg) > 2 && arg[0] == '-' && arg[1] == '-' && arg[2] != '-' {
33
+		return true
34
+	}
35
+
36
+	return false
37
+}
38
+
39
+// stripOptionPrefix returns the option without the prefix and whether or
40
+// not the option is a long option or not.
41
+func stripOptionPrefix(optname string) (prefix string, name string, islong bool) {
42
+	// Determine if the argument is a long option or not.  Windows
43
+	// typically supports both long and short options with a single
44
+	// front slash as the option delimiter, so handle this situation
45
+	// nicely.
46
+	possplit := 0
47
+
48
+	if strings.HasPrefix(optname, "--") {
49
+		possplit = 2
50
+		islong = true
51
+	} else if strings.HasPrefix(optname, "-") {
52
+		possplit = 1
53
+		islong = false
54
+	} else if strings.HasPrefix(optname, "/") {
55
+		possplit = 1
56
+		islong = len(optname) > 2
57
+	}
58
+
59
+	return optname[:possplit], optname[possplit:], islong
60
+}
61
+
62
+// splitOption attempts to split the passed option into a name and an argument.
63
+// When there is no argument specified, nil will be returned for it.
64
+func splitOption(prefix string, option string, islong bool) (string, string, *string) {
65
+	if len(option) == 0 {
66
+		return option, "", nil
67
+	}
68
+
69
+	// Windows typically uses a colon for the option name and argument
70
+	// delimiter while POSIX typically uses an equals.  Support both styles,
71
+	// but don't allow the two to be mixed.  That is to say /foo:bar and
72
+	// --foo=bar are acceptable, but /foo=bar and --foo:bar are not.
73
+	var pos int
74
+	var sp string
75
+
76
+	if prefix == "/" {
77
+		sp = ":"
78
+		pos = strings.Index(option, sp)
79
+	} else if len(prefix) > 0 {
80
+		sp = "="
81
+		pos = strings.Index(option, sp)
82
+	}
83
+
84
+	if (islong && pos >= 0) || (!islong && pos == 1) {
85
+		rest := option[pos+1:]
86
+		return option[:pos], sp, &rest
87
+	}
88
+
89
+	return option, "", nil
90
+}
91
+
92
+// addHelpGroup adds a new group that contains default help parameters.
93
+func (c *Command) addHelpGroup(showHelp func() error) *Group {
94
+	// Windows CLI applications typically use /? for help, so make both
95
+	// that available as well as the POSIX style h and help.
96
+	var help struct {
97
+		ShowHelpWindows func() error `short:"?" description:"Show this help message"`
98
+		ShowHelpPosix   func() error `short:"h" long:"help" description:"Show this help message"`
99
+	}
100
+
101
+	help.ShowHelpWindows = showHelp
102
+	help.ShowHelpPosix = showHelp
103
+
104
+	ret, _ := c.AddGroup("Help Options", "", &help)
105
+	ret.isBuiltinHelp = true
106
+
107
+	return ret
108
+}

+ 700
- 0
vendor/src/github.com/jessevdk/go-flags/parser.go Datei anzeigen

@@ -0,0 +1,700 @@
1
+// Copyright 2012 Jesse van den Kieboom. 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 flags
6
+
7
+import (
8
+	"bytes"
9
+	"fmt"
10
+	"os"
11
+	"path"
12
+	"sort"
13
+	"strings"
14
+	"unicode/utf8"
15
+)
16
+
17
+// A Parser provides command line option parsing. It can contain several
18
+// option groups each with their own set of options.
19
+type Parser struct {
20
+	// Embedded, see Command for more information
21
+	*Command
22
+
23
+	// A usage string to be displayed in the help message.
24
+	Usage string
25
+
26
+	// Option flags changing the behavior of the parser.
27
+	Options Options
28
+
29
+	// NamespaceDelimiter separates group namespaces and option long names
30
+	NamespaceDelimiter string
31
+
32
+	// UnknownOptionsHandler is a function which gets called when the parser
33
+	// encounters an unknown option. The function receives the unknown option
34
+	// name, a SplitArgument which specifies its value if set with an argument
35
+	// separator, and the remaining command line arguments.
36
+	// It should return a new list of remaining arguments to continue parsing,
37
+	// or an error to indicate a parse failure.
38
+	UnknownOptionHandler func(option string, arg SplitArgument, args []string) ([]string, error)
39
+
40
+	// CompletionHandler is a function gets called to handle the completion of
41
+	// items. By default, the items are printed and the application is exited.
42
+	// You can override this default behavior by specifying a custom CompletionHandler.
43
+	CompletionHandler func(items []Completion)
44
+
45
+	// CommandHandler is a function that gets called to handle execution of a
46
+	// command. By default, the command will simply be executed. This can be
47
+	// overridden to perform certain actions (such as applying global flags)
48
+	// just before the command is executed. Note that if you override the
49
+	// handler it is your responsibility to call the command.Execute function.
50
+	//
51
+	// The command passed into CommandHandler may be nil in case there is no
52
+	// command to be executed when parsing has finished.
53
+	CommandHandler func(command Commander, args []string) error
54
+
55
+	internalError error
56
+}
57
+
58
+// SplitArgument represents the argument value of an option that was passed using
59
+// an argument separator.
60
+type SplitArgument interface {
61
+	// String returns the option's value as a string, and a boolean indicating
62
+	// if the option was present.
63
+	Value() (string, bool)
64
+}
65
+
66
+type strArgument struct {
67
+	value *string
68
+}
69
+
70
+func (s strArgument) Value() (string, bool) {
71
+	if s.value == nil {
72
+		return "", false
73
+	}
74
+
75
+	return *s.value, true
76
+}
77
+
78
+// Options provides parser options that change the behavior of the option
79
+// parser.
80
+type Options uint
81
+
82
+const (
83
+	// None indicates no options.
84
+	None Options = 0
85
+
86
+	// HelpFlag adds a default Help Options group to the parser containing
87
+	// -h and --help options. When either -h or --help is specified on the
88
+	// command line, the parser will return the special error of type
89
+	// ErrHelp. When PrintErrors is also specified, then the help message
90
+	// will also be automatically printed to os.Stdout.
91
+	HelpFlag = 1 << iota
92
+
93
+	// PassDoubleDash passes all arguments after a double dash, --, as
94
+	// remaining command line arguments (i.e. they will not be parsed for
95
+	// flags).
96
+	PassDoubleDash
97
+
98
+	// IgnoreUnknown ignores any unknown options and passes them as
99
+	// remaining command line arguments instead of generating an error.
100
+	IgnoreUnknown
101
+
102
+	// PrintErrors prints any errors which occurred during parsing to
103
+	// os.Stderr. In the special case of ErrHelp, the message will be printed
104
+	// to os.Stdout.
105
+	PrintErrors
106
+
107
+	// PassAfterNonOption passes all arguments after the first non option
108
+	// as remaining command line arguments. This is equivalent to strict
109
+	// POSIX processing.
110
+	PassAfterNonOption
111
+
112
+	// Default is a convenient default set of options which should cover
113
+	// most of the uses of the flags package.
114
+	Default = HelpFlag | PrintErrors | PassDoubleDash
115
+)
116
+
117
+type parseState struct {
118
+	arg        string
119
+	args       []string
120
+	retargs    []string
121
+	positional []*Arg
122
+	err        error
123
+
124
+	command *Command
125
+	lookup  lookup
126
+}
127
+
128
+// Parse is a convenience function to parse command line options with default
129
+// settings. The provided data is a pointer to a struct representing the
130
+// default option group (named "Application Options"). For more control, use
131
+// flags.NewParser.
132
+func Parse(data interface{}) ([]string, error) {
133
+	return NewParser(data, Default).Parse()
134
+}
135
+
136
+// ParseArgs is a convenience function to parse command line options with default
137
+// settings. The provided data is a pointer to a struct representing the
138
+// default option group (named "Application Options"). The args argument is
139
+// the list of command line arguments to parse. If you just want to parse the
140
+// default program command line arguments (i.e. os.Args), then use flags.Parse
141
+// instead. For more control, use flags.NewParser.
142
+func ParseArgs(data interface{}, args []string) ([]string, error) {
143
+	return NewParser(data, Default).ParseArgs(args)
144
+}
145
+
146
+// NewParser creates a new parser. It uses os.Args[0] as the application
147
+// name and then calls Parser.NewNamedParser (see Parser.NewNamedParser for
148
+// more details). The provided data is a pointer to a struct representing the
149
+// default option group (named "Application Options"), or nil if the default
150
+// group should not be added. The options parameter specifies a set of options
151
+// for the parser.
152
+func NewParser(data interface{}, options Options) *Parser {
153
+	p := NewNamedParser(path.Base(os.Args[0]), options)
154
+
155
+	if data != nil {
156
+		g, err := p.AddGroup("Application Options", "", data)
157
+
158
+		if err == nil {
159
+			g.parent = p
160
+		}
161
+
162
+		p.internalError = err
163
+	}
164
+
165
+	return p
166
+}
167
+
168
+// NewNamedParser creates a new parser. The appname is used to display the
169
+// executable name in the built-in help message. Option groups and commands can
170
+// be added to this parser by using AddGroup and AddCommand.
171
+func NewNamedParser(appname string, options Options) *Parser {
172
+	p := &Parser{
173
+		Command:            newCommand(appname, "", "", nil),
174
+		Options:            options,
175
+		NamespaceDelimiter: ".",
176
+	}
177
+
178
+	p.Command.parent = p
179
+
180
+	return p
181
+}
182
+
183
+// Parse parses the command line arguments from os.Args using Parser.ParseArgs.
184
+// For more detailed information see ParseArgs.
185
+func (p *Parser) Parse() ([]string, error) {
186
+	return p.ParseArgs(os.Args[1:])
187
+}
188
+
189
+// ParseArgs parses the command line arguments according to the option groups that
190
+// were added to the parser. On successful parsing of the arguments, the
191
+// remaining, non-option, arguments (if any) are returned. The returned error
192
+// indicates a parsing error and can be used with PrintError to display
193
+// contextual information on where the error occurred exactly.
194
+//
195
+// When the common help group has been added (AddHelp) and either -h or --help
196
+// was specified in the command line arguments, a help message will be
197
+// automatically printed if the PrintErrors option is enabled.
198
+// Furthermore, the special error type ErrHelp is returned.
199
+// It is up to the caller to exit the program if so desired.
200
+func (p *Parser) ParseArgs(args []string) ([]string, error) {
201
+	if p.internalError != nil {
202
+		return nil, p.internalError
203
+	}
204
+
205
+	p.eachOption(func(c *Command, g *Group, option *Option) {
206
+		option.isSet = false
207
+		option.isSetDefault = false
208
+		option.updateDefaultLiteral()
209
+	})
210
+
211
+	// Add built-in help group to all commands if necessary
212
+	if (p.Options & HelpFlag) != None {
213
+		p.addHelpGroups(p.showBuiltinHelp)
214
+	}
215
+
216
+	compval := os.Getenv("GO_FLAGS_COMPLETION")
217
+
218
+	if len(compval) != 0 {
219
+		comp := &completion{parser: p}
220
+		items := comp.complete(args)
221
+
222
+		if p.CompletionHandler != nil {
223
+			p.CompletionHandler(items)
224
+		} else {
225
+			comp.print(items, compval == "verbose")
226
+			os.Exit(0)
227
+		}
228
+
229
+		return nil, nil
230
+	}
231
+
232
+	s := &parseState{
233
+		args:    args,
234
+		retargs: make([]string, 0, len(args)),
235
+	}
236
+
237
+	p.fillParseState(s)
238
+
239
+	for !s.eof() {
240
+		arg := s.pop()
241
+
242
+		// When PassDoubleDash is set and we encounter a --, then
243
+		// simply append all the rest as arguments and break out
244
+		if (p.Options&PassDoubleDash) != None && arg == "--" {
245
+			s.addArgs(s.args...)
246
+			break
247
+		}
248
+
249
+		if !argumentIsOption(arg) {
250
+			// Note: this also sets s.err, so we can just check for
251
+			// nil here and use s.err later
252
+			if p.parseNonOption(s) != nil {
253
+				break
254
+			}
255
+
256
+			continue
257
+		}
258
+
259
+		var err error
260
+
261
+		prefix, optname, islong := stripOptionPrefix(arg)
262
+		optname, _, argument := splitOption(prefix, optname, islong)
263
+
264
+		if islong {
265
+			err = p.parseLong(s, optname, argument)
266
+		} else {
267
+			err = p.parseShort(s, optname, argument)
268
+		}
269
+
270
+		if err != nil {
271
+			ignoreUnknown := (p.Options & IgnoreUnknown) != None
272
+			parseErr := wrapError(err)
273
+
274
+			if parseErr.Type != ErrUnknownFlag || (!ignoreUnknown && p.UnknownOptionHandler == nil) {
275
+				s.err = parseErr
276
+				break
277
+			}
278
+
279
+			if ignoreUnknown {
280
+				s.addArgs(arg)
281
+			} else if p.UnknownOptionHandler != nil {
282
+				modifiedArgs, err := p.UnknownOptionHandler(optname, strArgument{argument}, s.args)
283
+
284
+				if err != nil {
285
+					s.err = err
286
+					break
287
+				}
288
+
289
+				s.args = modifiedArgs
290
+			}
291
+		}
292
+	}
293
+
294
+	if s.err == nil {
295
+		p.eachOption(func(c *Command, g *Group, option *Option) {
296
+			if option.preventDefault {
297
+				return
298
+			}
299
+
300
+			option.clearDefault()
301
+		})
302
+
303
+		s.checkRequired(p)
304
+	}
305
+
306
+	var reterr error
307
+
308
+	if s.err != nil {
309
+		reterr = s.err
310
+	} else if len(s.command.commands) != 0 && !s.command.SubcommandsOptional {
311
+		reterr = s.estimateCommand()
312
+	} else if cmd, ok := s.command.data.(Commander); ok {
313
+		if p.CommandHandler != nil {
314
+			reterr = p.CommandHandler(cmd, s.retargs)
315
+		} else {
316
+			reterr = cmd.Execute(s.retargs)
317
+		}
318
+	} else if p.CommandHandler != nil {
319
+		reterr = p.CommandHandler(nil, s.retargs)
320
+	}
321
+
322
+	if reterr != nil {
323
+		var retargs []string
324
+
325
+		if ourErr, ok := reterr.(*Error); !ok || ourErr.Type != ErrHelp {
326
+			retargs = append([]string{s.arg}, s.args...)
327
+		} else {
328
+			retargs = s.args
329
+		}
330
+
331
+		return retargs, p.printError(reterr)
332
+	}
333
+
334
+	return s.retargs, nil
335
+}
336
+
337
+func (p *parseState) eof() bool {
338
+	return len(p.args) == 0
339
+}
340
+
341
+func (p *parseState) pop() string {
342
+	if p.eof() {
343
+		return ""
344
+	}
345
+
346
+	p.arg = p.args[0]
347
+	p.args = p.args[1:]
348
+
349
+	return p.arg
350
+}
351
+
352
+func (p *parseState) peek() string {
353
+	if p.eof() {
354
+		return ""
355
+	}
356
+
357
+	return p.args[0]
358
+}
359
+
360
+func (p *parseState) checkRequired(parser *Parser) error {
361
+	c := parser.Command
362
+
363
+	var required []*Option
364
+
365
+	for c != nil {
366
+		c.eachGroup(func(g *Group) {
367
+			for _, option := range g.options {
368
+				if !option.isSet && option.Required {
369
+					required = append(required, option)
370
+				}
371
+			}
372
+		})
373
+
374
+		c = c.Active
375
+	}
376
+
377
+	if len(required) == 0 {
378
+		if len(p.positional) > 0 {
379
+			var reqnames []string
380
+
381
+			for _, arg := range p.positional {
382
+				argRequired := (!arg.isRemaining() && p.command.ArgsRequired) || arg.Required != -1 || arg.RequiredMaximum != -1
383
+
384
+				if !argRequired {
385
+					continue
386
+				}
387
+
388
+				if arg.isRemaining() {
389
+					if arg.value.Len() < arg.Required {
390
+						var arguments string
391
+
392
+						if arg.Required > 1 {
393
+							arguments = "arguments, but got only " + fmt.Sprintf("%d", arg.value.Len())
394
+						} else {
395
+							arguments = "argument"
396
+						}
397
+
398
+						reqnames = append(reqnames, "`"+arg.Name+" (at least "+fmt.Sprintf("%d", arg.Required)+" "+arguments+")`")
399
+					} else if arg.RequiredMaximum != -1 && arg.value.Len() > arg.RequiredMaximum {
400
+						if arg.RequiredMaximum == 0 {
401
+							reqnames = append(reqnames, "`"+arg.Name+" (zero arguments)`")
402
+						} else {
403
+							var arguments string
404
+
405
+							if arg.RequiredMaximum > 1 {
406
+								arguments = "arguments, but got " + fmt.Sprintf("%d", arg.value.Len())
407
+							} else {
408
+								arguments = "argument"
409
+							}
410
+
411
+							reqnames = append(reqnames, "`"+arg.Name+" (at most "+fmt.Sprintf("%d", arg.RequiredMaximum)+" "+arguments+")`")
412
+						}
413
+					}
414
+				} else {
415
+					reqnames = append(reqnames, "`"+arg.Name+"`")
416
+				}
417
+			}
418
+
419
+			if len(reqnames) == 0 {
420
+				return nil
421
+			}
422
+
423
+			var msg string
424
+
425
+			if len(reqnames) == 1 {
426
+				msg = fmt.Sprintf("the required argument %s was not provided", reqnames[0])
427
+			} else {
428
+				msg = fmt.Sprintf("the required arguments %s and %s were not provided",
429
+					strings.Join(reqnames[:len(reqnames)-1], ", "), reqnames[len(reqnames)-1])
430
+			}
431
+
432
+			p.err = newError(ErrRequired, msg)
433
+			return p.err
434
+		}
435
+
436
+		return nil
437
+	}
438
+
439
+	names := make([]string, 0, len(required))
440
+
441
+	for _, k := range required {
442
+		names = append(names, "`"+k.String()+"'")
443
+	}
444
+
445
+	sort.Strings(names)
446
+
447
+	var msg string
448
+
449
+	if len(names) == 1 {
450
+		msg = fmt.Sprintf("the required flag %s was not specified", names[0])
451
+	} else {
452
+		msg = fmt.Sprintf("the required flags %s and %s were not specified",
453
+			strings.Join(names[:len(names)-1], ", "), names[len(names)-1])
454
+	}
455
+
456
+	p.err = newError(ErrRequired, msg)
457
+	return p.err
458
+}
459
+
460
+func (p *parseState) estimateCommand() error {
461
+	commands := p.command.sortedVisibleCommands()
462
+	cmdnames := make([]string, len(commands))
463
+
464
+	for i, v := range commands {
465
+		cmdnames[i] = v.Name
466
+	}
467
+
468
+	var msg string
469
+	var errtype ErrorType
470
+
471
+	if len(p.retargs) != 0 {
472
+		c, l := closestChoice(p.retargs[0], cmdnames)
473
+		msg = fmt.Sprintf("Unknown command `%s'", p.retargs[0])
474
+		errtype = ErrUnknownCommand
475
+
476
+		if float32(l)/float32(len(c)) < 0.5 {
477
+			msg = fmt.Sprintf("%s, did you mean `%s'?", msg, c)
478
+		} else if len(cmdnames) == 1 {
479
+			msg = fmt.Sprintf("%s. You should use the %s command",
480
+				msg,
481
+				cmdnames[0])
482
+		} else if len(cmdnames) > 1 {
483
+			msg = fmt.Sprintf("%s. Please specify one command of: %s or %s",
484
+				msg,
485
+				strings.Join(cmdnames[:len(cmdnames)-1], ", "),
486
+				cmdnames[len(cmdnames)-1])
487
+		}
488
+	} else {
489
+		errtype = ErrCommandRequired
490
+
491
+		if len(cmdnames) == 1 {
492
+			msg = fmt.Sprintf("Please specify the %s command", cmdnames[0])
493
+		} else if len(cmdnames) > 1 {
494
+			msg = fmt.Sprintf("Please specify one command of: %s or %s",
495
+				strings.Join(cmdnames[:len(cmdnames)-1], ", "),
496
+				cmdnames[len(cmdnames)-1])
497
+		}
498
+	}
499
+
500
+	return newError(errtype, msg)
501
+}
502
+
503
+func (p *Parser) parseOption(s *parseState, name string, option *Option, canarg bool, argument *string) (err error) {
504
+	if !option.canArgument() {
505
+		if argument != nil {
506
+			return newErrorf(ErrNoArgumentForBool, "bool flag `%s' cannot have an argument", option)
507
+		}
508
+
509
+		err = option.set(nil)
510
+	} else if argument != nil || (canarg && !s.eof()) {
511
+		var arg string
512
+
513
+		if argument != nil {
514
+			arg = *argument
515
+		} else {
516
+			arg = s.pop()
517
+
518
+			if argumentIsOption(arg) && !(option.isSignedNumber() && len(arg) > 1 && arg[0] == '-' && arg[1] >= '0' && arg[1] <= '9') {
519
+				return newErrorf(ErrExpectedArgument, "expected argument for flag `%s', but got option `%s'", option, arg)
520
+			} else if p.Options&PassDoubleDash != 0 && arg == "--" {
521
+				return newErrorf(ErrExpectedArgument, "expected argument for flag `%s', but got double dash `--'", option)
522
+			}
523
+		}
524
+
525
+		if option.tag.Get("unquote") != "false" {
526
+			arg, err = unquoteIfPossible(arg)
527
+		}
528
+
529
+		if err == nil {
530
+			err = option.set(&arg)
531
+		}
532
+	} else if option.OptionalArgument {
533
+		option.empty()
534
+
535
+		for _, v := range option.OptionalValue {
536
+			err = option.set(&v)
537
+
538
+			if err != nil {
539
+				break
540
+			}
541
+		}
542
+	} else {
543
+		err = newErrorf(ErrExpectedArgument, "expected argument for flag `%s'", option)
544
+	}
545
+
546
+	if err != nil {
547
+		if _, ok := err.(*Error); !ok {
548
+			err = newErrorf(ErrMarshal, "invalid argument for flag `%s' (expected %s): %s",
549
+				option,
550
+				option.value.Type(),
551
+				err.Error())
552
+		}
553
+	}
554
+
555
+	return err
556
+}
557
+
558
+func (p *Parser) parseLong(s *parseState, name string, argument *string) error {
559
+	if option := s.lookup.longNames[name]; option != nil {
560
+		// Only long options that are required can consume an argument
561
+		// from the argument list
562
+		canarg := !option.OptionalArgument
563
+
564
+		return p.parseOption(s, name, option, canarg, argument)
565
+	}
566
+
567
+	return newErrorf(ErrUnknownFlag, "unknown flag `%s'", name)
568
+}
569
+
570
+func (p *Parser) splitShortConcatArg(s *parseState, optname string) (string, *string) {
571
+	c, n := utf8.DecodeRuneInString(optname)
572
+
573
+	if n == len(optname) {
574
+		return optname, nil
575
+	}
576
+
577
+	first := string(c)
578
+
579
+	if option := s.lookup.shortNames[first]; option != nil && option.canArgument() {
580
+		arg := optname[n:]
581
+		return first, &arg
582
+	}
583
+
584
+	return optname, nil
585
+}
586
+
587
+func (p *Parser) parseShort(s *parseState, optname string, argument *string) error {
588
+	if argument == nil {
589
+		optname, argument = p.splitShortConcatArg(s, optname)
590
+	}
591
+
592
+	for i, c := range optname {
593
+		shortname := string(c)
594
+
595
+		if option := s.lookup.shortNames[shortname]; option != nil {
596
+			// Only the last short argument can consume an argument from
597
+			// the arguments list, and only if it's non optional
598
+			canarg := (i+utf8.RuneLen(c) == len(optname)) && !option.OptionalArgument
599
+
600
+			if err := p.parseOption(s, shortname, option, canarg, argument); err != nil {
601
+				return err
602
+			}
603
+		} else {
604
+			return newErrorf(ErrUnknownFlag, "unknown flag `%s'", shortname)
605
+		}
606
+
607
+		// Only the first option can have a concatted argument, so just
608
+		// clear argument here
609
+		argument = nil
610
+	}
611
+
612
+	return nil
613
+}
614
+
615
+func (p *parseState) addArgs(args ...string) error {
616
+	for len(p.positional) > 0 && len(args) > 0 {
617
+		arg := p.positional[0]
618
+
619
+		if err := convert(args[0], arg.value, arg.tag); err != nil {
620
+			p.err = err
621
+			return err
622
+		}
623
+
624
+		if !arg.isRemaining() {
625
+			p.positional = p.positional[1:]
626
+		}
627
+
628
+		args = args[1:]
629
+	}
630
+
631
+	p.retargs = append(p.retargs, args...)
632
+	return nil
633
+}
634
+
635
+func (p *Parser) parseNonOption(s *parseState) error {
636
+	if len(s.positional) > 0 {
637
+		return s.addArgs(s.arg)
638
+	}
639
+
640
+	if len(s.command.commands) > 0 && len(s.retargs) == 0 {
641
+		if cmd := s.lookup.commands[s.arg]; cmd != nil {
642
+			s.command.Active = cmd
643
+			cmd.fillParseState(s)
644
+
645
+			return nil
646
+		} else if !s.command.SubcommandsOptional {
647
+			s.addArgs(s.arg)
648
+			return newErrorf(ErrUnknownCommand, "Unknown command `%s'", s.arg)
649
+		}
650
+	}
651
+
652
+	if (p.Options & PassAfterNonOption) != None {
653
+		// If PassAfterNonOption is set then all remaining arguments
654
+		// are considered positional
655
+		if err := s.addArgs(s.arg); err != nil {
656
+			return err
657
+		}
658
+
659
+		if err := s.addArgs(s.args...); err != nil {
660
+			return err
661
+		}
662
+
663
+		s.args = []string{}
664
+	} else {
665
+		return s.addArgs(s.arg)
666
+	}
667
+
668
+	return nil
669
+}
670
+
671
+func (p *Parser) showBuiltinHelp() error {
672
+	var b bytes.Buffer
673
+
674
+	p.WriteHelp(&b)
675
+	return newError(ErrHelp, b.String())
676
+}
677
+
678
+func (p *Parser) printError(err error) error {
679
+	if err != nil && (p.Options&PrintErrors) != None {
680
+		flagsErr, ok := err.(*Error)
681
+
682
+		if ok && flagsErr.Type == ErrHelp {
683
+			fmt.Fprintln(os.Stdout, err)
684
+		} else {
685
+			fmt.Fprintln(os.Stderr, err)
686
+		}
687
+	}
688
+
689
+	return err
690
+}
691
+
692
+func (p *Parser) clearIsSet() {
693
+	p.eachCommand(func(c *Command) {
694
+		c.eachGroup(func(g *Group) {
695
+			for _, option := range g.options {
696
+				option.isSet = false
697
+			}
698
+		})
699
+	}, true)
700
+}

+ 612
- 0
vendor/src/github.com/jessevdk/go-flags/parser_test.go Datei anzeigen

@@ -0,0 +1,612 @@
1
+package flags
2
+
3
+import (
4
+	"fmt"
5
+	"os"
6
+	"reflect"
7
+	"runtime"
8
+	"strconv"
9
+	"strings"
10
+	"testing"
11
+	"time"
12
+)
13
+
14
+type defaultOptions struct {
15
+	Int        int `long:"i"`
16
+	IntDefault int `long:"id" default:"1"`
17
+
18
+	Float64        float64 `long:"f"`
19
+	Float64Default float64 `long:"fd" default:"-3.14"`
20
+
21
+	NumericFlag bool `short:"3"`
22
+
23
+	String            string `long:"str"`
24
+	StringDefault     string `long:"strd" default:"abc"`
25
+	StringNotUnquoted string `long:"strnot" unquote:"false"`
26
+
27
+	Time        time.Duration `long:"t"`
28
+	TimeDefault time.Duration `long:"td" default:"1m"`
29
+
30
+	Map        map[string]int `long:"m"`
31
+	MapDefault map[string]int `long:"md" default:"a:1"`
32
+
33
+	Slice        []int `long:"s"`
34
+	SliceDefault []int `long:"sd" default:"1" default:"2"`
35
+}
36
+
37
+func TestDefaults(t *testing.T) {
38
+	var tests = []struct {
39
+		msg      string
40
+		args     []string
41
+		expected defaultOptions
42
+	}{
43
+		{
44
+			msg:  "no arguments, expecting default values",
45
+			args: []string{},
46
+			expected: defaultOptions{
47
+				Int:        0,
48
+				IntDefault: 1,
49
+
50
+				Float64:        0.0,
51
+				Float64Default: -3.14,
52
+
53
+				NumericFlag: false,
54
+
55
+				String:        "",
56
+				StringDefault: "abc",
57
+
58
+				Time:        0,
59
+				TimeDefault: time.Minute,
60
+
61
+				Map:        map[string]int{},
62
+				MapDefault: map[string]int{"a": 1},
63
+
64
+				Slice:        []int{},
65
+				SliceDefault: []int{1, 2},
66
+			},
67
+		},
68
+		{
69
+			msg:  "non-zero value arguments, expecting overwritten arguments",
70
+			args: []string{"--i=3", "--id=3", "--f=-2.71", "--fd=2.71", "-3", "--str=def", "--strd=def", "--t=3ms", "--td=3ms", "--m=c:3", "--md=c:3", "--s=3", "--sd=3"},
71
+			expected: defaultOptions{
72
+				Int:        3,
73
+				IntDefault: 3,
74
+
75
+				Float64:        -2.71,
76
+				Float64Default: 2.71,
77
+
78
+				NumericFlag: true,
79
+
80
+				String:        "def",
81
+				StringDefault: "def",
82
+
83
+				Time:        3 * time.Millisecond,
84
+				TimeDefault: 3 * time.Millisecond,
85
+
86
+				Map:        map[string]int{"c": 3},
87
+				MapDefault: map[string]int{"c": 3},
88
+
89
+				Slice:        []int{3},
90
+				SliceDefault: []int{3},
91
+			},
92
+		},
93
+		{
94
+			msg:  "zero value arguments, expecting overwritten arguments",
95
+			args: []string{"--i=0", "--id=0", "--f=0", "--fd=0", "--str", "", "--strd=\"\"", "--t=0ms", "--td=0s", "--m=:0", "--md=:0", "--s=0", "--sd=0"},
96
+			expected: defaultOptions{
97
+				Int:        0,
98
+				IntDefault: 0,
99
+
100
+				Float64:        0,
101
+				Float64Default: 0,
102
+
103
+				String:        "",
104
+				StringDefault: "",
105
+
106
+				Time:        0,
107
+				TimeDefault: 0,
108
+
109
+				Map:        map[string]int{"": 0},
110
+				MapDefault: map[string]int{"": 0},
111
+
112
+				Slice:        []int{0},
113
+				SliceDefault: []int{0},
114
+			},
115
+		},
116
+	}
117
+
118
+	for _, test := range tests {
119
+		var opts defaultOptions
120
+
121
+		_, err := ParseArgs(&opts, test.args)
122
+		if err != nil {
123
+			t.Fatalf("%s:\nUnexpected error: %v", test.msg, err)
124
+		}
125
+
126
+		if opts.Slice == nil {
127
+			opts.Slice = []int{}
128
+		}
129
+
130
+		if !reflect.DeepEqual(opts, test.expected) {
131
+			t.Errorf("%s:\nUnexpected options with arguments %+v\nexpected\n%+v\nbut got\n%+v\n", test.msg, test.args, test.expected, opts)
132
+		}
133
+	}
134
+}
135
+
136
+func TestNoDefaultsForBools(t *testing.T) {
137
+	var opts struct {
138
+		DefaultBool bool `short:"d" default:"true"`
139
+	}
140
+
141
+	if runtime.GOOS == "windows" {
142
+		assertParseFail(t, ErrInvalidTag, "boolean flag `/d' may not have default values, they always default to `false' and can only be turned on", &opts)
143
+	} else {
144
+		assertParseFail(t, ErrInvalidTag, "boolean flag `-d' may not have default values, they always default to `false' and can only be turned on", &opts)
145
+	}
146
+}
147
+
148
+func TestUnquoting(t *testing.T) {
149
+	var tests = []struct {
150
+		arg   string
151
+		err   error
152
+		value string
153
+	}{
154
+		{
155
+			arg:   "\"abc",
156
+			err:   strconv.ErrSyntax,
157
+			value: "",
158
+		},
159
+		{
160
+			arg:   "\"\"abc\"",
161
+			err:   strconv.ErrSyntax,
162
+			value: "",
163
+		},
164
+		{
165
+			arg:   "\"abc\"",
166
+			err:   nil,
167
+			value: "abc",
168
+		},
169
+		{
170
+			arg:   "\"\\\"abc\\\"\"",
171
+			err:   nil,
172
+			value: "\"abc\"",
173
+		},
174
+		{
175
+			arg:   "\"\\\"abc\"",
176
+			err:   nil,
177
+			value: "\"abc",
178
+		},
179
+	}
180
+
181
+	for _, test := range tests {
182
+		var opts defaultOptions
183
+
184
+		for _, delimiter := range []bool{false, true} {
185
+			p := NewParser(&opts, None)
186
+
187
+			var err error
188
+			if delimiter {
189
+				_, err = p.ParseArgs([]string{"--str=" + test.arg, "--strnot=" + test.arg})
190
+			} else {
191
+				_, err = p.ParseArgs([]string{"--str", test.arg, "--strnot", test.arg})
192
+			}
193
+
194
+			if test.err == nil {
195
+				if err != nil {
196
+					t.Fatalf("Expected no error but got: %v", err)
197
+				}
198
+
199
+				if test.value != opts.String {
200
+					t.Fatalf("Expected String to be %q but got %q", test.value, opts.String)
201
+				}
202
+				if q := strconv.Quote(test.value); q != opts.StringNotUnquoted {
203
+					t.Fatalf("Expected StringDefault to be %q but got %q", q, opts.StringNotUnquoted)
204
+				}
205
+			} else {
206
+				if err == nil {
207
+					t.Fatalf("Expected error")
208
+				} else if e, ok := err.(*Error); ok {
209
+					if strings.HasPrefix(e.Message, test.err.Error()) {
210
+						t.Fatalf("Expected error message to end with %q but got %v", test.err.Error(), e.Message)
211
+					}
212
+				}
213
+			}
214
+		}
215
+	}
216
+}
217
+
218
+// EnvRestorer keeps a copy of a set of env variables and can restore the env from them
219
+type EnvRestorer struct {
220
+	env map[string]string
221
+}
222
+
223
+func (r *EnvRestorer) Restore() {
224
+	os.Clearenv()
225
+
226
+	for k, v := range r.env {
227
+		os.Setenv(k, v)
228
+	}
229
+}
230
+
231
+// EnvSnapshot returns a snapshot of the currently set env variables
232
+func EnvSnapshot() *EnvRestorer {
233
+	r := EnvRestorer{make(map[string]string)}
234
+
235
+	for _, kv := range os.Environ() {
236
+		parts := strings.SplitN(kv, "=", 2)
237
+
238
+		if len(parts) != 2 {
239
+			panic("got a weird env variable: " + kv)
240
+		}
241
+
242
+		r.env[parts[0]] = parts[1]
243
+	}
244
+
245
+	return &r
246
+}
247
+
248
+type envDefaultOptions struct {
249
+	Int   int            `long:"i" default:"1" env:"TEST_I"`
250
+	Time  time.Duration  `long:"t" default:"1m" env:"TEST_T"`
251
+	Map   map[string]int `long:"m" default:"a:1" env:"TEST_M" env-delim:";"`
252
+	Slice []int          `long:"s" default:"1" default:"2" env:"TEST_S"  env-delim:","`
253
+}
254
+
255
+func TestEnvDefaults(t *testing.T) {
256
+	var tests = []struct {
257
+		msg      string
258
+		args     []string
259
+		expected envDefaultOptions
260
+		env      map[string]string
261
+	}{
262
+		{
263
+			msg:  "no arguments, no env, expecting default values",
264
+			args: []string{},
265
+			expected: envDefaultOptions{
266
+				Int:   1,
267
+				Time:  time.Minute,
268
+				Map:   map[string]int{"a": 1},
269
+				Slice: []int{1, 2},
270
+			},
271
+		},
272
+		{
273
+			msg:  "no arguments, env defaults, expecting env default values",
274
+			args: []string{},
275
+			expected: envDefaultOptions{
276
+				Int:   2,
277
+				Time:  2 * time.Minute,
278
+				Map:   map[string]int{"a": 2, "b": 3},
279
+				Slice: []int{4, 5, 6},
280
+			},
281
+			env: map[string]string{
282
+				"TEST_I": "2",
283
+				"TEST_T": "2m",
284
+				"TEST_M": "a:2;b:3",
285
+				"TEST_S": "4,5,6",
286
+			},
287
+		},
288
+		{
289
+			msg:  "non-zero value arguments, expecting overwritten arguments",
290
+			args: []string{"--i=3", "--t=3ms", "--m=c:3", "--s=3"},
291
+			expected: envDefaultOptions{
292
+				Int:   3,
293
+				Time:  3 * time.Millisecond,
294
+				Map:   map[string]int{"c": 3},
295
+				Slice: []int{3},
296
+			},
297
+			env: map[string]string{
298
+				"TEST_I": "2",
299
+				"TEST_T": "2m",
300
+				"TEST_M": "a:2;b:3",
301
+				"TEST_S": "4,5,6",
302
+			},
303
+		},
304
+		{
305
+			msg:  "zero value arguments, expecting overwritten arguments",
306
+			args: []string{"--i=0", "--t=0ms", "--m=:0", "--s=0"},
307
+			expected: envDefaultOptions{
308
+				Int:   0,
309
+				Time:  0,
310
+				Map:   map[string]int{"": 0},
311
+				Slice: []int{0},
312
+			},
313
+			env: map[string]string{
314
+				"TEST_I": "2",
315
+				"TEST_T": "2m",
316
+				"TEST_M": "a:2;b:3",
317
+				"TEST_S": "4,5,6",
318
+			},
319
+		},
320
+	}
321
+
322
+	oldEnv := EnvSnapshot()
323
+	defer oldEnv.Restore()
324
+
325
+	for _, test := range tests {
326
+		var opts envDefaultOptions
327
+		oldEnv.Restore()
328
+		for envKey, envValue := range test.env {
329
+			os.Setenv(envKey, envValue)
330
+		}
331
+		_, err := ParseArgs(&opts, test.args)
332
+		if err != nil {
333
+			t.Fatalf("%s:\nUnexpected error: %v", test.msg, err)
334
+		}
335
+
336
+		if opts.Slice == nil {
337
+			opts.Slice = []int{}
338
+		}
339
+
340
+		if !reflect.DeepEqual(opts, test.expected) {
341
+			t.Errorf("%s:\nUnexpected options with arguments %+v\nexpected\n%+v\nbut got\n%+v\n", test.msg, test.args, test.expected, opts)
342
+		}
343
+	}
344
+}
345
+
346
+func TestOptionAsArgument(t *testing.T) {
347
+	var tests = []struct {
348
+		args        []string
349
+		expectError bool
350
+		errType     ErrorType
351
+		errMsg      string
352
+		rest        []string
353
+	}{
354
+		{
355
+			// short option must not be accepted as argument
356
+			args:        []string{"--string-slice", "foobar", "--string-slice", "-o"},
357
+			expectError: true,
358
+			errType:     ErrExpectedArgument,
359
+			errMsg:      "expected argument for flag `" + defaultLongOptDelimiter + "string-slice', but got option `-o'",
360
+		},
361
+		{
362
+			// long option must not be accepted as argument
363
+			args:        []string{"--string-slice", "foobar", "--string-slice", "--other-option"},
364
+			expectError: true,
365
+			errType:     ErrExpectedArgument,
366
+			errMsg:      "expected argument for flag `" + defaultLongOptDelimiter + "string-slice', but got option `--other-option'",
367
+		},
368
+		{
369
+			// long option must not be accepted as argument
370
+			args:        []string{"--string-slice", "--"},
371
+			expectError: true,
372
+			errType:     ErrExpectedArgument,
373
+			errMsg:      "expected argument for flag `" + defaultLongOptDelimiter + "string-slice', but got double dash `--'",
374
+		},
375
+		{
376
+			// quoted and appended option should be accepted as argument (even if it looks like an option)
377
+			args: []string{"--string-slice", "foobar", "--string-slice=\"--other-option\""},
378
+		},
379
+		{
380
+			// Accept any single character arguments including '-'
381
+			args: []string{"--string-slice", "-"},
382
+		},
383
+		{
384
+			// Do not accept arguments which start with '-' even if the next character is a digit
385
+			args:        []string{"--string-slice", "-3.14"},
386
+			expectError: true,
387
+			errType:     ErrExpectedArgument,
388
+			errMsg:      "expected argument for flag `" + defaultLongOptDelimiter + "string-slice', but got option `-3.14'",
389
+		},
390
+		{
391
+			// Do not accept arguments which start with '-' if the next character is not a digit
392
+			args:        []string{"--string-slice", "-character"},
393
+			expectError: true,
394
+			errType:     ErrExpectedArgument,
395
+			errMsg:      "expected argument for flag `" + defaultLongOptDelimiter + "string-slice', but got option `-character'",
396
+		},
397
+		{
398
+			args: []string{"-o", "-", "-"},
399
+			rest: []string{"-", "-"},
400
+		},
401
+		{
402
+			// Accept arguments which start with '-' if the next character is a digit, for number options only
403
+			args: []string{"--int-slice", "-3"},
404
+		},
405
+		{
406
+			// Accept arguments which start with '-' if the next character is a digit, for number options only
407
+			args: []string{"--int16", "-3"},
408
+		},
409
+		{
410
+			// Accept arguments which start with '-' if the next character is a digit, for number options only
411
+			args: []string{"--float32", "-3.2"},
412
+		},
413
+		{
414
+			// Accept arguments which start with '-' if the next character is a digit, for number options only
415
+			args: []string{"--float32ptr", "-3.2"},
416
+		},
417
+	}
418
+
419
+	var opts struct {
420
+		StringSlice []string `long:"string-slice"`
421
+		IntSlice    []int    `long:"int-slice"`
422
+		Int16       int16    `long:"int16"`
423
+		Float32     float32  `long:"float32"`
424
+		Float32Ptr  *float32 `long:"float32ptr"`
425
+		OtherOption bool     `long:"other-option" short:"o"`
426
+	}
427
+
428
+	for _, test := range tests {
429
+		if test.expectError {
430
+			assertParseFail(t, test.errType, test.errMsg, &opts, test.args...)
431
+		} else {
432
+			args := assertParseSuccess(t, &opts, test.args...)
433
+
434
+			assertStringArray(t, args, test.rest)
435
+		}
436
+	}
437
+}
438
+
439
+func TestUnknownFlagHandler(t *testing.T) {
440
+
441
+	var opts struct {
442
+		Flag1 string `long:"flag1"`
443
+		Flag2 string `long:"flag2"`
444
+	}
445
+
446
+	p := NewParser(&opts, None)
447
+
448
+	var unknownFlag1 string
449
+	var unknownFlag2 bool
450
+	var unknownFlag3 string
451
+
452
+	// Set up a callback to intercept unknown options during parsing
453
+	p.UnknownOptionHandler = func(option string, arg SplitArgument, args []string) ([]string, error) {
454
+		if option == "unknownFlag1" {
455
+			if argValue, ok := arg.Value(); ok {
456
+				unknownFlag1 = argValue
457
+				return args, nil
458
+			}
459
+			// consume a value from remaining args list
460
+			unknownFlag1 = args[0]
461
+			return args[1:], nil
462
+		} else if option == "unknownFlag2" {
463
+			// treat this one as a bool switch, don't consume any args
464
+			unknownFlag2 = true
465
+			return args, nil
466
+		} else if option == "unknownFlag3" {
467
+			if argValue, ok := arg.Value(); ok {
468
+				unknownFlag3 = argValue
469
+				return args, nil
470
+			}
471
+			// consume a value from remaining args list
472
+			unknownFlag3 = args[0]
473
+			return args[1:], nil
474
+		}
475
+
476
+		return args, fmt.Errorf("Unknown flag: %v", option)
477
+	}
478
+
479
+	// Parse args containing some unknown flags, verify that
480
+	// our callback can handle all of them
481
+	_, err := p.ParseArgs([]string{"--flag1=stuff", "--unknownFlag1", "blah", "--unknownFlag2", "--unknownFlag3=baz", "--flag2=foo"})
482
+
483
+	if err != nil {
484
+		assertErrorf(t, "Parser returned unexpected error %v", err)
485
+	}
486
+
487
+	assertString(t, opts.Flag1, "stuff")
488
+	assertString(t, opts.Flag2, "foo")
489
+	assertString(t, unknownFlag1, "blah")
490
+	assertString(t, unknownFlag3, "baz")
491
+
492
+	if !unknownFlag2 {
493
+		assertErrorf(t, "Flag should have been set by unknown handler, but had value: %v", unknownFlag2)
494
+	}
495
+
496
+	// Parse args with unknown flags that callback doesn't handle, verify it returns error
497
+	_, err = p.ParseArgs([]string{"--flag1=stuff", "--unknownFlagX", "blah", "--flag2=foo"})
498
+
499
+	if err == nil {
500
+		assertErrorf(t, "Parser should have returned error, but returned nil")
501
+	}
502
+}
503
+
504
+func TestChoices(t *testing.T) {
505
+	var opts struct {
506
+		Choice string `long:"choose" choice:"v1" choice:"v2"`
507
+	}
508
+
509
+	assertParseFail(t, ErrInvalidChoice, "Invalid value `invalid' for option `"+defaultLongOptDelimiter+"choose'. Allowed values are: v1 or v2", &opts, "--choose", "invalid")
510
+	assertParseSuccess(t, &opts, "--choose", "v2")
511
+	assertString(t, opts.Choice, "v2")
512
+}
513
+
514
+func TestEmbedded(t *testing.T) {
515
+	type embedded struct {
516
+		V bool `short:"v"`
517
+	}
518
+	var opts struct {
519
+		embedded
520
+	}
521
+
522
+	assertParseSuccess(t, &opts, "-v")
523
+
524
+	if !opts.V {
525
+		t.Errorf("Expected V to be true")
526
+	}
527
+}
528
+
529
+type command struct {
530
+}
531
+
532
+func (c *command) Execute(args []string) error {
533
+	return nil
534
+}
535
+
536
+func TestCommandHandlerNoCommand(t *testing.T) {
537
+	var opts = struct {
538
+		Value bool `short:"v"`
539
+	}{}
540
+
541
+	parser := NewParser(&opts, Default&^PrintErrors)
542
+
543
+	var executedCommand Commander
544
+	var executedArgs []string
545
+
546
+	executed := false
547
+
548
+	parser.CommandHandler = func(command Commander, args []string) error {
549
+		executed = true
550
+
551
+		executedCommand = command
552
+		executedArgs = args
553
+
554
+		return nil
555
+	}
556
+
557
+	_, err := parser.ParseArgs([]string{"arg1", "arg2"})
558
+
559
+	if err != nil {
560
+		t.Fatalf("Unexpected parse error: %s", err)
561
+	}
562
+
563
+	if !executed {
564
+		t.Errorf("Expected command handler to be executed")
565
+	}
566
+
567
+	if executedCommand != nil {
568
+		t.Errorf("Did not exect an executed command")
569
+	}
570
+
571
+	assertStringArray(t, executedArgs, []string{"arg1", "arg2"})
572
+}
573
+
574
+func TestCommandHandler(t *testing.T) {
575
+	var opts = struct {
576
+		Value bool `short:"v"`
577
+
578
+		Command command `command:"cmd"`
579
+	}{}
580
+
581
+	parser := NewParser(&opts, Default&^PrintErrors)
582
+
583
+	var executedCommand Commander
584
+	var executedArgs []string
585
+
586
+	executed := false
587
+
588
+	parser.CommandHandler = func(command Commander, args []string) error {
589
+		executed = true
590
+
591
+		executedCommand = command
592
+		executedArgs = args
593
+
594
+		return nil
595
+	}
596
+
597
+	_, err := parser.ParseArgs([]string{"cmd", "arg1", "arg2"})
598
+
599
+	if err != nil {
600
+		t.Fatalf("Unexpected parse error: %s", err)
601
+	}
602
+
603
+	if !executed {
604
+		t.Errorf("Expected command handler to be executed")
605
+	}
606
+
607
+	if executedCommand == nil {
608
+		t.Errorf("Expected command handler to be executed")
609
+	}
610
+
611
+	assertStringArray(t, executedArgs, []string{"arg1", "arg2"})
612
+}

+ 164
- 0
vendor/src/github.com/jessevdk/go-flags/pointer_test.go Datei anzeigen

@@ -0,0 +1,164 @@
1
+package flags
2
+
3
+import (
4
+	"testing"
5
+)
6
+
7
+func TestPointerBool(t *testing.T) {
8
+	var opts = struct {
9
+		Value *bool `short:"v"`
10
+	}{}
11
+
12
+	ret := assertParseSuccess(t, &opts, "-v")
13
+
14
+	assertStringArray(t, ret, []string{})
15
+
16
+	if !*opts.Value {
17
+		t.Errorf("Expected Value to be true")
18
+	}
19
+}
20
+
21
+func TestPointerString(t *testing.T) {
22
+	var opts = struct {
23
+		Value *string `short:"v"`
24
+	}{}
25
+
26
+	ret := assertParseSuccess(t, &opts, "-v", "value")
27
+
28
+	assertStringArray(t, ret, []string{})
29
+	assertString(t, *opts.Value, "value")
30
+}
31
+
32
+func TestPointerSlice(t *testing.T) {
33
+	var opts = struct {
34
+		Value *[]string `short:"v"`
35
+	}{}
36
+
37
+	ret := assertParseSuccess(t, &opts, "-v", "value1", "-v", "value2")
38
+
39
+	assertStringArray(t, ret, []string{})
40
+	assertStringArray(t, *opts.Value, []string{"value1", "value2"})
41
+}
42
+
43
+func TestPointerMap(t *testing.T) {
44
+	var opts = struct {
45
+		Value *map[string]int `short:"v"`
46
+	}{}
47
+
48
+	ret := assertParseSuccess(t, &opts, "-v", "k1:2", "-v", "k2:-5")
49
+
50
+	assertStringArray(t, ret, []string{})
51
+
52
+	if v, ok := (*opts.Value)["k1"]; !ok {
53
+		t.Errorf("Expected key \"k1\" to exist")
54
+	} else if v != 2 {
55
+		t.Errorf("Expected \"k1\" to be 2, but got %#v", v)
56
+	}
57
+
58
+	if v, ok := (*opts.Value)["k2"]; !ok {
59
+		t.Errorf("Expected key \"k2\" to exist")
60
+	} else if v != -5 {
61
+		t.Errorf("Expected \"k2\" to be -5, but got %#v", v)
62
+	}
63
+}
64
+
65
+type marshalledString string
66
+
67
+func (m *marshalledString) UnmarshalFlag(value string) error {
68
+	*m = marshalledString(value)
69
+	return nil
70
+}
71
+
72
+func (m marshalledString) MarshalFlag() (string, error) {
73
+	return string(m), nil
74
+}
75
+
76
+func TestPointerStringMarshalled(t *testing.T) {
77
+	var opts = struct {
78
+		Value *marshalledString `short:"v"`
79
+	}{}
80
+
81
+	ret := assertParseSuccess(t, &opts, "-v", "value")
82
+
83
+	assertStringArray(t, ret, []string{})
84
+
85
+	if opts.Value == nil {
86
+		t.Error("Expected value not to be nil")
87
+		return
88
+	}
89
+
90
+	assertString(t, string(*opts.Value), "value")
91
+}
92
+
93
+type marshalledStruct struct {
94
+	Value string
95
+}
96
+
97
+func (m *marshalledStruct) UnmarshalFlag(value string) error {
98
+	m.Value = value
99
+	return nil
100
+}
101
+
102
+func (m marshalledStruct) MarshalFlag() (string, error) {
103
+	return m.Value, nil
104
+}
105
+
106
+func TestPointerStructMarshalled(t *testing.T) {
107
+	var opts = struct {
108
+		Value *marshalledStruct `short:"v"`
109
+	}{}
110
+
111
+	ret := assertParseSuccess(t, &opts, "-v", "value")
112
+
113
+	assertStringArray(t, ret, []string{})
114
+
115
+	if opts.Value == nil {
116
+		t.Error("Expected value not to be nil")
117
+		return
118
+	}
119
+
120
+	assertString(t, opts.Value.Value, "value")
121
+}
122
+
123
+type PointerGroup struct {
124
+	Value bool `short:"v"`
125
+}
126
+
127
+func TestPointerGroup(t *testing.T) {
128
+	var opts = struct {
129
+		Group *PointerGroup `group:"Group Options"`
130
+	}{}
131
+
132
+	ret := assertParseSuccess(t, &opts, "-v")
133
+
134
+	assertStringArray(t, ret, []string{})
135
+
136
+	if !opts.Group.Value {
137
+		t.Errorf("Expected Group.Value to be true")
138
+	}
139
+}
140
+
141
+func TestDoNotChangeNonTaggedFields(t *testing.T) {
142
+	var opts struct {
143
+		A struct {
144
+			Pointer *int
145
+		}
146
+		B *struct {
147
+			Pointer *int
148
+		}
149
+	}
150
+
151
+	ret := assertParseSuccess(t, &opts)
152
+
153
+	assertStringArray(t, ret, []string{})
154
+
155
+	if opts.A.Pointer != nil {
156
+		t.Error("Expected A.Pointer to be nil")
157
+	}
158
+	if opts.B != nil {
159
+		t.Error("Expected B to be nil")
160
+	}
161
+	if opts.B != nil && opts.B.Pointer != nil {
162
+		t.Error("Expected B.Pointer to be nil")
163
+	}
164
+}

+ 234
- 0
vendor/src/github.com/jessevdk/go-flags/short_test.go Datei anzeigen

@@ -0,0 +1,234 @@
1
+package flags
2
+
3
+import (
4
+	"fmt"
5
+	"testing"
6
+)
7
+
8
+func TestShort(t *testing.T) {
9
+	var opts = struct {
10
+		Value bool `short:"v"`
11
+	}{}
12
+
13
+	ret := assertParseSuccess(t, &opts, "-v")
14
+
15
+	assertStringArray(t, ret, []string{})
16
+
17
+	if !opts.Value {
18
+		t.Errorf("Expected Value to be true")
19
+	}
20
+}
21
+
22
+func TestShortTooLong(t *testing.T) {
23
+	var opts = struct {
24
+		Value bool `short:"vv"`
25
+	}{}
26
+
27
+	assertParseFail(t, ErrShortNameTooLong, "short names can only be 1 character long, not `vv'", &opts)
28
+}
29
+
30
+func TestShortRequired(t *testing.T) {
31
+	var opts = struct {
32
+		Value bool `short:"v" required:"true"`
33
+	}{}
34
+
35
+	assertParseFail(t, ErrRequired, fmt.Sprintf("the required flag `%cv' was not specified", defaultShortOptDelimiter), &opts)
36
+}
37
+
38
+func TestShortRequiredFalsy1(t *testing.T) {
39
+	var opts = struct {
40
+		Value bool `short:"v" required:"false"`
41
+	}{}
42
+
43
+	assertParseSuccess(t, &opts)
44
+}
45
+
46
+func TestShortRequiredFalsy2(t *testing.T) {
47
+	var opts = struct {
48
+		Value bool `short:"v" required:"no"`
49
+	}{}
50
+
51
+	assertParseSuccess(t, &opts)
52
+}
53
+
54
+func TestShortMultiConcat(t *testing.T) {
55
+	var opts = struct {
56
+		V bool `short:"v"`
57
+		O bool `short:"o"`
58
+		F bool `short:"f"`
59
+	}{}
60
+
61
+	ret := assertParseSuccess(t, &opts, "-vo", "-f")
62
+
63
+	assertStringArray(t, ret, []string{})
64
+
65
+	if !opts.V {
66
+		t.Errorf("Expected V to be true")
67
+	}
68
+
69
+	if !opts.O {
70
+		t.Errorf("Expected O to be true")
71
+	}
72
+
73
+	if !opts.F {
74
+		t.Errorf("Expected F to be true")
75
+	}
76
+}
77
+
78
+func TestShortMultiRequiredConcat(t *testing.T) {
79
+	var opts = struct {
80
+		V bool `short:"v" required:"true"`
81
+		O bool `short:"o" required:"true"`
82
+		F bool `short:"f" required:"true"`
83
+	}{}
84
+
85
+	ret := assertParseSuccess(t, &opts, "-vo", "-f")
86
+
87
+	assertStringArray(t, ret, []string{})
88
+
89
+	if !opts.V {
90
+		t.Errorf("Expected V to be true")
91
+	}
92
+
93
+	if !opts.O {
94
+		t.Errorf("Expected O to be true")
95
+	}
96
+
97
+	if !opts.F {
98
+		t.Errorf("Expected F to be true")
99
+	}
100
+}
101
+
102
+func TestShortMultiSlice(t *testing.T) {
103
+	var opts = struct {
104
+		Values []bool `short:"v"`
105
+	}{}
106
+
107
+	ret := assertParseSuccess(t, &opts, "-v", "-v")
108
+
109
+	assertStringArray(t, ret, []string{})
110
+	assertBoolArray(t, opts.Values, []bool{true, true})
111
+}
112
+
113
+func TestShortMultiSliceConcat(t *testing.T) {
114
+	var opts = struct {
115
+		Values []bool `short:"v"`
116
+	}{}
117
+
118
+	ret := assertParseSuccess(t, &opts, "-vvv")
119
+
120
+	assertStringArray(t, ret, []string{})
121
+	assertBoolArray(t, opts.Values, []bool{true, true, true})
122
+}
123
+
124
+func TestShortWithEqualArg(t *testing.T) {
125
+	var opts = struct {
126
+		Value string `short:"v"`
127
+	}{}
128
+
129
+	ret := assertParseSuccess(t, &opts, "-v=value")
130
+
131
+	assertStringArray(t, ret, []string{})
132
+	assertString(t, opts.Value, "value")
133
+}
134
+
135
+func TestShortWithArg(t *testing.T) {
136
+	var opts = struct {
137
+		Value string `short:"v"`
138
+	}{}
139
+
140
+	ret := assertParseSuccess(t, &opts, "-vvalue")
141
+
142
+	assertStringArray(t, ret, []string{})
143
+	assertString(t, opts.Value, "value")
144
+}
145
+
146
+func TestShortArg(t *testing.T) {
147
+	var opts = struct {
148
+		Value string `short:"v"`
149
+	}{}
150
+
151
+	ret := assertParseSuccess(t, &opts, "-v", "value")
152
+
153
+	assertStringArray(t, ret, []string{})
154
+	assertString(t, opts.Value, "value")
155
+}
156
+
157
+func TestShortMultiWithEqualArg(t *testing.T) {
158
+	var opts = struct {
159
+		F     []bool `short:"f"`
160
+		Value string `short:"v"`
161
+	}{}
162
+
163
+	assertParseFail(t, ErrExpectedArgument, fmt.Sprintf("expected argument for flag `%cv'", defaultShortOptDelimiter), &opts, "-ffv=value")
164
+}
165
+
166
+func TestShortMultiArg(t *testing.T) {
167
+	var opts = struct {
168
+		F     []bool `short:"f"`
169
+		Value string `short:"v"`
170
+	}{}
171
+
172
+	ret := assertParseSuccess(t, &opts, "-ffv", "value")
173
+
174
+	assertStringArray(t, ret, []string{})
175
+	assertBoolArray(t, opts.F, []bool{true, true})
176
+	assertString(t, opts.Value, "value")
177
+}
178
+
179
+func TestShortMultiArgConcatFail(t *testing.T) {
180
+	var opts = struct {
181
+		F     []bool `short:"f"`
182
+		Value string `short:"v"`
183
+	}{}
184
+
185
+	assertParseFail(t, ErrExpectedArgument, fmt.Sprintf("expected argument for flag `%cv'", defaultShortOptDelimiter), &opts, "-ffvvalue")
186
+}
187
+
188
+func TestShortMultiArgConcat(t *testing.T) {
189
+	var opts = struct {
190
+		F     []bool `short:"f"`
191
+		Value string `short:"v"`
192
+	}{}
193
+
194
+	ret := assertParseSuccess(t, &opts, "-vff")
195
+
196
+	assertStringArray(t, ret, []string{})
197
+	assertString(t, opts.Value, "ff")
198
+}
199
+
200
+func TestShortOptional(t *testing.T) {
201
+	var opts = struct {
202
+		F     []bool `short:"f"`
203
+		Value string `short:"v" optional:"yes" optional-value:"value"`
204
+	}{}
205
+
206
+	ret := assertParseSuccess(t, &opts, "-fv", "f")
207
+
208
+	assertStringArray(t, ret, []string{"f"})
209
+	assertString(t, opts.Value, "value")
210
+}
211
+
212
+func TestShortOptionalFalsy1(t *testing.T) {
213
+	var opts = struct {
214
+		F     []bool `short:"f"`
215
+		Value string `short:"v" optional:"false" optional-value:"value"`
216
+	}{}
217
+
218
+	ret := assertParseSuccess(t, &opts, "-fv", "f")
219
+
220
+	assertStringArray(t, ret, []string{})
221
+	assertString(t, opts.Value, "f")
222
+}
223
+
224
+func TestShortOptionalFalsy2(t *testing.T) {
225
+	var opts = struct {
226
+		F     []bool `short:"f"`
227
+		Value string `short:"v" optional:"no" optional-value:"value"`
228
+	}{}
229
+
230
+	ret := assertParseSuccess(t, &opts, "-fv", "f")
231
+
232
+	assertStringArray(t, ret, []string{})
233
+	assertString(t, opts.Value, "f")
234
+}

+ 38
- 0
vendor/src/github.com/jessevdk/go-flags/tag_test.go Datei anzeigen

@@ -0,0 +1,38 @@
1
+package flags
2
+
3
+import (
4
+	"testing"
5
+)
6
+
7
+func TestTagMissingColon(t *testing.T) {
8
+	var opts = struct {
9
+		Value bool `short`
10
+	}{}
11
+
12
+	assertParseFail(t, ErrTag, "expected `:' after key name, but got end of tag (in `short`)", &opts, "")
13
+}
14
+
15
+func TestTagMissingValue(t *testing.T) {
16
+	var opts = struct {
17
+		Value bool `short:`
18
+	}{}
19
+
20
+	assertParseFail(t, ErrTag, "expected `\"' to start tag value at end of tag (in `short:`)", &opts, "")
21
+}
22
+
23
+func TestTagMissingQuote(t *testing.T) {
24
+	var opts = struct {
25
+		Value bool `short:"v`
26
+	}{}
27
+
28
+	assertParseFail(t, ErrTag, "expected end of tag value `\"' at end of tag (in `short:\"v`)", &opts, "")
29
+}
30
+
31
+func TestTagNewline(t *testing.T) {
32
+	var opts = struct {
33
+		Value bool `long:"verbose" description:"verbose
34
+something"`
35
+	}{}
36
+
37
+	assertParseFail(t, ErrTag, "unexpected newline in tag value `description' (in `long:\"verbose\" description:\"verbose\nsomething\"`)", &opts, "")
38
+}

+ 28
- 0
vendor/src/github.com/jessevdk/go-flags/termsize.go Datei anzeigen

@@ -0,0 +1,28 @@
1
+// +build !windows,!plan9,!solaris,!appengine
2
+
3
+package flags
4
+
5
+import (
6
+	"syscall"
7
+	"unsafe"
8
+)
9
+
10
+type winsize struct {
11
+	row, col       uint16
12
+	xpixel, ypixel uint16
13
+}
14
+
15
+func getTerminalColumns() int {
16
+	ws := winsize{}
17
+
18
+	if tIOCGWINSZ != 0 {
19
+		syscall.Syscall(syscall.SYS_IOCTL,
20
+			uintptr(0),
21
+			uintptr(tIOCGWINSZ),
22
+			uintptr(unsafe.Pointer(&ws)))
23
+
24
+		return int(ws.col)
25
+	}
26
+
27
+	return 80
28
+}

+ 7
- 0
vendor/src/github.com/jessevdk/go-flags/termsize_nosysioctl.go Datei anzeigen

@@ -0,0 +1,7 @@
1
+// +build windows plan9 solaris appengine
2
+
3
+package flags
4
+
5
+func getTerminalColumns() int {
6
+	return 80
7
+}

+ 7
- 0
vendor/src/github.com/jessevdk/go-flags/tiocgwinsz_bsdish.go Datei anzeigen

@@ -0,0 +1,7 @@
1
+// +build darwin freebsd netbsd openbsd
2
+
3
+package flags
4
+
5
+const (
6
+	tIOCGWINSZ = 0x40087468
7
+)

+ 7
- 0
vendor/src/github.com/jessevdk/go-flags/tiocgwinsz_linux.go Datei anzeigen

@@ -0,0 +1,7 @@
1
+// +build linux
2
+
3
+package flags
4
+
5
+const (
6
+	tIOCGWINSZ = 0x5413
7
+)

+ 7
- 0
vendor/src/github.com/jessevdk/go-flags/tiocgwinsz_other.go Datei anzeigen

@@ -0,0 +1,7 @@
1
+// +build !darwin,!freebsd,!netbsd,!openbsd,!linux
2
+
3
+package flags
4
+
5
+const (
6
+	tIOCGWINSZ = 0
7
+)

+ 66
- 0
vendor/src/github.com/jessevdk/go-flags/unknown_test.go Datei anzeigen

@@ -0,0 +1,66 @@
1
+package flags
2
+
3
+import (
4
+	"testing"
5
+)
6
+
7
+func TestUnknownFlags(t *testing.T) {
8
+	var opts = struct {
9
+		Verbose []bool `short:"v" long:"verbose" description:"Verbose output"`
10
+	}{}
11
+
12
+	args := []string{
13
+		"-f",
14
+	}
15
+
16
+	p := NewParser(&opts, 0)
17
+	args, err := p.ParseArgs(args)
18
+
19
+	if err == nil {
20
+		t.Fatal("Expected error for unknown argument")
21
+	}
22
+}
23
+
24
+func TestIgnoreUnknownFlags(t *testing.T) {
25
+	var opts = struct {
26
+		Verbose []bool `short:"v" long:"verbose" description:"Verbose output"`
27
+	}{}
28
+
29
+	args := []string{
30
+		"hello",
31
+		"world",
32
+		"-v",
33
+		"--foo=bar",
34
+		"--verbose",
35
+		"-f",
36
+	}
37
+
38
+	p := NewParser(&opts, IgnoreUnknown)
39
+	args, err := p.ParseArgs(args)
40
+
41
+	if err != nil {
42
+		t.Fatal(err)
43
+	}
44
+
45
+	exargs := []string{
46
+		"hello",
47
+		"world",
48
+		"--foo=bar",
49
+		"-f",
50
+	}
51
+
52
+	issame := (len(args) == len(exargs))
53
+
54
+	if issame {
55
+		for i := 0; i < len(args); i++ {
56
+			if args[i] != exargs[i] {
57
+				issame = false
58
+				break
59
+			}
60
+		}
61
+	}
62
+
63
+	if !issame {
64
+		t.Fatalf("Expected %v but got %v", exargs, args)
65
+	}
66
+}

+ 21
- 0
vendor/src/github.com/mitchellh/go-homedir/LICENSE Datei anzeigen

@@ -0,0 +1,21 @@
1
+The MIT License (MIT)
2
+
3
+Copyright (c) 2013 Mitchell Hashimoto
4
+
5
+Permission is hereby granted, free of charge, to any person obtaining a copy
6
+of this software and associated documentation files (the "Software"), to deal
7
+in the Software without restriction, including without limitation the rights
8
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+copies of the Software, and to permit persons to whom the Software is
10
+furnished to do so, subject to the following conditions:
11
+
12
+The above copyright notice and this permission notice shall be included in
13
+all copies or substantial portions of the Software.
14
+
15
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+THE SOFTWARE.

+ 14
- 0
vendor/src/github.com/mitchellh/go-homedir/README.md Datei anzeigen

@@ -0,0 +1,14 @@
1
+# go-homedir
2
+
3
+This is a Go library for detecting the user's home directory without
4
+the use of cgo, so the library can be used in cross-compilation environments.
5
+
6
+Usage is incredibly simple, just call `homedir.Dir()` to get the home directory
7
+for a user, and `homedir.Expand()` to expand the `~` in a path to the home
8
+directory.
9
+
10
+**Why not just use `os/user`?** The built-in `os/user` package requires
11
+cgo on Darwin systems. This means that any Go code that uses that package
12
+cannot cross compile. But 99% of the time the use for `os/user` is just to
13
+retrieve the home directory, which we can do for the current user without
14
+cgo. This library does that, enabling cross-compilation.

+ 137
- 0
vendor/src/github.com/mitchellh/go-homedir/homedir.go Datei anzeigen

@@ -0,0 +1,137 @@
1
+package homedir
2
+
3
+import (
4
+	"bytes"
5
+	"errors"
6
+	"os"
7
+	"os/exec"
8
+	"path/filepath"
9
+	"runtime"
10
+	"strconv"
11
+	"strings"
12
+	"sync"
13
+)
14
+
15
+// DisableCache will disable caching of the home directory. Caching is enabled
16
+// by default.
17
+var DisableCache bool
18
+
19
+var homedirCache string
20
+var cacheLock sync.RWMutex
21
+
22
+// Dir returns the home directory for the executing user.
23
+//
24
+// This uses an OS-specific method for discovering the home directory.
25
+// An error is returned if a home directory cannot be detected.
26
+func Dir() (string, error) {
27
+	if !DisableCache {
28
+		cacheLock.RLock()
29
+		cached := homedirCache
30
+		cacheLock.RUnlock()
31
+		if cached != "" {
32
+			return cached, nil
33
+		}
34
+	}
35
+
36
+	cacheLock.Lock()
37
+	defer cacheLock.Unlock()
38
+
39
+	var result string
40
+	var err error
41
+	if runtime.GOOS == "windows" {
42
+		result, err = dirWindows()
43
+	} else {
44
+		// Unix-like system, so just assume Unix
45
+		result, err = dirUnix()
46
+	}
47
+
48
+	if err != nil {
49
+		return "", err
50
+	}
51
+	homedirCache = result
52
+	return result, nil
53
+}
54
+
55
+// Expand expands the path to include the home directory if the path
56
+// is prefixed with `~`. If it isn't prefixed with `~`, the path is
57
+// returned as-is.
58
+func Expand(path string) (string, error) {
59
+	if len(path) == 0 {
60
+		return path, nil
61
+	}
62
+
63
+	if path[0] != '~' {
64
+		return path, nil
65
+	}
66
+
67
+	if len(path) > 1 && path[1] != '/' && path[1] != '\\' {
68
+		return "", errors.New("cannot expand user-specific home dir")
69
+	}
70
+
71
+	dir, err := Dir()
72
+	if err != nil {
73
+		return "", err
74
+	}
75
+
76
+	return filepath.Join(dir, path[1:]), nil
77
+}
78
+
79
+func dirUnix() (string, error) {
80
+	// First prefer the HOME environmental variable
81
+	if home := os.Getenv("HOME"); home != "" {
82
+		return home, nil
83
+	}
84
+
85
+	// If that fails, try getent
86
+	var stdout bytes.Buffer
87
+	cmd := exec.Command("getent", "passwd", strconv.Itoa(os.Getuid()))
88
+	cmd.Stdout = &stdout
89
+	if err := cmd.Run(); err != nil {
90
+		// If the error is ErrNotFound, we ignore it. Otherwise, return it.
91
+		if err != exec.ErrNotFound {
92
+			return "", err
93
+		}
94
+	} else {
95
+		if passwd := strings.TrimSpace(stdout.String()); passwd != "" {
96
+			// username:password:uid:gid:gecos:home:shell
97
+			passwdParts := strings.SplitN(passwd, ":", 7)
98
+			if len(passwdParts) > 5 {
99
+				return passwdParts[5], nil
100
+			}
101
+		}
102
+	}
103
+
104
+	// If all else fails, try the shell
105
+	stdout.Reset()
106
+	cmd = exec.Command("sh", "-c", "cd && pwd")
107
+	cmd.Stdout = &stdout
108
+	if err := cmd.Run(); err != nil {
109
+		return "", err
110
+	}
111
+
112
+	result := strings.TrimSpace(stdout.String())
113
+	if result == "" {
114
+		return "", errors.New("blank output when reading home directory")
115
+	}
116
+
117
+	return result, nil
118
+}
119
+
120
+func dirWindows() (string, error) {
121
+	// First prefer the HOME environmental variable
122
+	if home := os.Getenv("HOME"); home != "" {
123
+		return home, nil
124
+	}
125
+
126
+	drive := os.Getenv("HOMEDRIVE")
127
+	path := os.Getenv("HOMEPATH")
128
+	home := drive + path
129
+	if drive == "" || path == "" {
130
+		home = os.Getenv("USERPROFILE")
131
+	}
132
+	if home == "" {
133
+		return "", errors.New("HOMEDRIVE, HOMEPATH, and USERPROFILE are blank")
134
+	}
135
+
136
+	return home, nil
137
+}

+ 112
- 0
vendor/src/github.com/mitchellh/go-homedir/homedir_test.go Datei anzeigen

@@ -0,0 +1,112 @@
1
+package homedir
2
+
3
+import (
4
+	"os"
5
+	"os/user"
6
+	"path/filepath"
7
+	"testing"
8
+)
9
+
10
+func patchEnv(key, value string) func() {
11
+	bck := os.Getenv(key)
12
+	deferFunc := func() {
13
+		os.Setenv(key, bck)
14
+	}
15
+
16
+	os.Setenv(key, value)
17
+	return deferFunc
18
+}
19
+
20
+func BenchmarkDir(b *testing.B) {
21
+	// We do this for any "warmups"
22
+	for i := 0; i < 10; i++ {
23
+		Dir()
24
+	}
25
+
26
+	b.ResetTimer()
27
+	for i := 0; i < b.N; i++ {
28
+		Dir()
29
+	}
30
+}
31
+
32
+func TestDir(t *testing.T) {
33
+	u, err := user.Current()
34
+	if err != nil {
35
+		t.Fatalf("err: %s", err)
36
+	}
37
+
38
+	dir, err := Dir()
39
+	if err != nil {
40
+		t.Fatalf("err: %s", err)
41
+	}
42
+
43
+	if u.HomeDir != dir {
44
+		t.Fatalf("%#v != %#v", u.HomeDir, dir)
45
+	}
46
+}
47
+
48
+func TestExpand(t *testing.T) {
49
+	u, err := user.Current()
50
+	if err != nil {
51
+		t.Fatalf("err: %s", err)
52
+	}
53
+
54
+	cases := []struct {
55
+		Input  string
56
+		Output string
57
+		Err    bool
58
+	}{
59
+		{
60
+			"/foo",
61
+			"/foo",
62
+			false,
63
+		},
64
+
65
+		{
66
+			"~/foo",
67
+			filepath.Join(u.HomeDir, "foo"),
68
+			false,
69
+		},
70
+
71
+		{
72
+			"",
73
+			"",
74
+			false,
75
+		},
76
+
77
+		{
78
+			"~",
79
+			u.HomeDir,
80
+			false,
81
+		},
82
+
83
+		{
84
+			"~foo/foo",
85
+			"",
86
+			true,
87
+		},
88
+	}
89
+
90
+	for _, tc := range cases {
91
+		actual, err := Expand(tc.Input)
92
+		if (err != nil) != tc.Err {
93
+			t.Fatalf("Input: %#v\n\nErr: %s", tc.Input, err)
94
+		}
95
+
96
+		if actual != tc.Output {
97
+			t.Fatalf("Input: %#v\n\nOutput: %#v", tc.Input, actual)
98
+		}
99
+	}
100
+
101
+	DisableCache = true
102
+	defer func() { DisableCache = false }()
103
+	defer patchEnv("HOME", "/custom/path/")()
104
+	expected := filepath.Join("/", "custom", "path", "foo/bar")
105
+	actual, err := Expand("~/foo/bar")
106
+
107
+	if err != nil {
108
+		t.Errorf("No error is expected, got: %v", err)
109
+	} else if actual != expected {
110
+		t.Errorf("Expected: %v; actual: %v", expected, actual)
111
+	}
112
+}

+ 28
- 0
vendor/src/github.com/sergi/go-diff/diffmatchpatch/benchutil_test.go Datei anzeigen

@@ -0,0 +1,28 @@
1
+// Copyright (c) 2012-2016 The go-diff authors. All rights reserved.
2
+// https://github.com/sergi/go-diff
3
+// See the included LICENSE file for license details.
4
+//
5
+// go-diff is a Go implementation of Google's Diff, Match, and Patch library
6
+// Original library is Copyright (c) 2006 Google Inc.
7
+// http://code.google.com/p/google-diff-match-patch/
8
+
9
+package diffmatchpatch
10
+
11
+import (
12
+	"io/ioutil"
13
+)
14
+
15
+const testdataPath = "../testdata/"
16
+
17
+func speedtestTexts() (s1 string, s2 string) {
18
+	d1, err := ioutil.ReadFile(testdataPath + "speedtest1.txt")
19
+	if err != nil {
20
+		panic(err)
21
+	}
22
+	d2, err := ioutil.ReadFile(testdataPath + "speedtest2.txt")
23
+	if err != nil {
24
+		panic(err)
25
+	}
26
+
27
+	return string(d1), string(d2)
28
+}

+ 1344
- 0
vendor/src/github.com/sergi/go-diff/diffmatchpatch/diff.go
Datei-Diff unterdrückt, da er zu groß ist
Datei anzeigen


+ 1427
- 0
vendor/src/github.com/sergi/go-diff/diffmatchpatch/diff_test.go
Datei-Diff unterdrückt, da er zu groß ist
Datei anzeigen


+ 46
- 0
vendor/src/github.com/sergi/go-diff/diffmatchpatch/diffmatchpatch.go Datei anzeigen

@@ -0,0 +1,46 @@
1
+// Copyright (c) 2012-2016 The go-diff authors. All rights reserved.
2
+// https://github.com/sergi/go-diff
3
+// See the included LICENSE file for license details.
4
+//
5
+// go-diff is a Go implementation of Google's Diff, Match, and Patch library
6
+// Original library is Copyright (c) 2006 Google Inc.
7
+// http://code.google.com/p/google-diff-match-patch/
8
+
9
+// Package diffmatchpatch offers robust algorithms to perform the operations required for synchronizing plain text.
10
+package diffmatchpatch
11
+
12
+import (
13
+	"time"
14
+)
15
+
16
+// DiffMatchPatch holds the configuration for diff-match-patch operations.
17
+type DiffMatchPatch struct {
18
+	// Number of seconds to map a diff before giving up (0 for infinity).
19
+	DiffTimeout time.Duration
20
+	// Cost of an empty edit operation in terms of edit characters.
21
+	DiffEditCost int
22
+	// How far to search for a match (0 = exact location, 1000+ = broad match). A match this many characters away from the expected location will add 1.0 to the score (0.0 is a perfect match).
23
+	MatchDistance int
24
+	// When deleting a large block of text (over ~64 characters), how close do the contents have to be to match the expected contents. (0.0 = perfection, 1.0 = very loose).  Note that MatchThreshold controls how closely the end points of a delete need to match.
25
+	PatchDeleteThreshold float64
26
+	// Chunk size for context length.
27
+	PatchMargin int
28
+	// The number of bits in an int.
29
+	MatchMaxBits int
30
+	// At what point is no match declared (0.0 = perfection, 1.0 = very loose).
31
+	MatchThreshold float64
32
+}
33
+
34
+// New creates a new DiffMatchPatch object with default parameters.
35
+func New() *DiffMatchPatch {
36
+	// Defaults.
37
+	return &DiffMatchPatch{
38
+		DiffTimeout:          time.Second,
39
+		DiffEditCost:         4,
40
+		MatchThreshold:       0.5,
41
+		MatchDistance:        1000,
42
+		PatchDeleteThreshold: 0.5,
43
+		PatchMargin:          4,
44
+		MatchMaxBits:         32,
45
+	}
46
+}

+ 160
- 0
vendor/src/github.com/sergi/go-diff/diffmatchpatch/match.go Datei anzeigen

@@ -0,0 +1,160 @@
1
+// Copyright (c) 2012-2016 The go-diff authors. All rights reserved.
2
+// https://github.com/sergi/go-diff
3
+// See the included LICENSE file for license details.
4
+//
5
+// go-diff is a Go implementation of Google's Diff, Match, and Patch library
6
+// Original library is Copyright (c) 2006 Google Inc.
7
+// http://code.google.com/p/google-diff-match-patch/
8
+
9
+package diffmatchpatch
10
+
11
+import (
12
+	"math"
13
+)
14
+
15
+// MatchMain locates the best instance of 'pattern' in 'text' near 'loc'.
16
+// Returns -1 if no match found.
17
+func (dmp *DiffMatchPatch) MatchMain(text, pattern string, loc int) int {
18
+	// Check for null inputs not needed since null can't be passed in C#.
19
+
20
+	loc = int(math.Max(0, math.Min(float64(loc), float64(len(text)))))
21
+	if text == pattern {
22
+		// Shortcut (potentially not guaranteed by the algorithm)
23
+		return 0
24
+	} else if len(text) == 0 {
25
+		// Nothing to match.
26
+		return -1
27
+	} else if loc+len(pattern) <= len(text) && text[loc:loc+len(pattern)] == pattern {
28
+		// Perfect match at the perfect spot!  (Includes case of null pattern)
29
+		return loc
30
+	}
31
+	// Do a fuzzy compare.
32
+	return dmp.MatchBitap(text, pattern, loc)
33
+}
34
+
35
+// MatchBitap locates the best instance of 'pattern' in 'text' near 'loc' using the Bitap algorithm.
36
+// Returns -1 if no match was found.
37
+func (dmp *DiffMatchPatch) MatchBitap(text, pattern string, loc int) int {
38
+	// Initialise the alphabet.
39
+	s := dmp.MatchAlphabet(pattern)
40
+
41
+	// Highest score beyond which we give up.
42
+	scoreThreshold := dmp.MatchThreshold
43
+	// Is there a nearby exact match? (speedup)
44
+	bestLoc := indexOf(text, pattern, loc)
45
+	if bestLoc != -1 {
46
+		scoreThreshold = math.Min(dmp.matchBitapScore(0, bestLoc, loc,
47
+			pattern), scoreThreshold)
48
+		// What about in the other direction? (speedup)
49
+		bestLoc = lastIndexOf(text, pattern, loc+len(pattern))
50
+		if bestLoc != -1 {
51
+			scoreThreshold = math.Min(dmp.matchBitapScore(0, bestLoc, loc,
52
+				pattern), scoreThreshold)
53
+		}
54
+	}
55
+
56
+	// Initialise the bit arrays.
57
+	matchmask := 1 << uint((len(pattern) - 1))
58
+	bestLoc = -1
59
+
60
+	var binMin, binMid int
61
+	binMax := len(pattern) + len(text)
62
+	lastRd := []int{}
63
+	for d := 0; d < len(pattern); d++ {
64
+		// Scan for the best match; each iteration allows for one more error. Run a binary search to determine how far from 'loc' we can stray at this error level.
65
+		binMin = 0
66
+		binMid = binMax
67
+		for binMin < binMid {
68
+			if dmp.matchBitapScore(d, loc+binMid, loc, pattern) <= scoreThreshold {
69
+				binMin = binMid
70
+			} else {
71
+				binMax = binMid
72
+			}
73
+			binMid = (binMax-binMin)/2 + binMin
74
+		}
75
+		// Use the result from this iteration as the maximum for the next.
76
+		binMax = binMid
77
+		start := int(math.Max(1, float64(loc-binMid+1)))
78
+		finish := int(math.Min(float64(loc+binMid), float64(len(text))) + float64(len(pattern)))
79
+
80
+		rd := make([]int, finish+2)
81
+		rd[finish+1] = (1 << uint(d)) - 1
82
+
83
+		for j := finish; j >= start; j-- {
84
+			var charMatch int
85
+			if len(text) <= j-1 {
86
+				// Out of range.
87
+				charMatch = 0
88
+			} else if _, ok := s[text[j-1]]; !ok {
89
+				charMatch = 0
90
+			} else {
91
+				charMatch = s[text[j-1]]
92
+			}
93
+
94
+			if d == 0 {
95
+				// First pass: exact match.
96
+				rd[j] = ((rd[j+1] << 1) | 1) & charMatch
97
+			} else {
98
+				// Subsequent passes: fuzzy match.
99
+				rd[j] = ((rd[j+1]<<1)|1)&charMatch | (((lastRd[j+1] | lastRd[j]) << 1) | 1) | lastRd[j+1]
100
+			}
101
+			if (rd[j] & matchmask) != 0 {
102
+				score := dmp.matchBitapScore(d, j-1, loc, pattern)
103
+				// This match will almost certainly be better than any existing match.  But check anyway.
104
+				if score <= scoreThreshold {
105
+					// Told you so.
106
+					scoreThreshold = score
107
+					bestLoc = j - 1
108
+					if bestLoc > loc {
109
+						// When passing loc, don't exceed our current distance from loc.
110
+						start = int(math.Max(1, float64(2*loc-bestLoc)))
111
+					} else {
112
+						// Already passed loc, downhill from here on in.
113
+						break
114
+					}
115
+				}
116
+			}
117
+		}
118
+		if dmp.matchBitapScore(d+1, loc, loc, pattern) > scoreThreshold {
119
+			// No hope for a (better) match at greater error levels.
120
+			break
121
+		}
122
+		lastRd = rd
123
+	}
124
+	return bestLoc
125
+}
126
+
127
+// matchBitapScore computes and returns the score for a match with e errors and x location.
128
+func (dmp *DiffMatchPatch) matchBitapScore(e, x, loc int, pattern string) float64 {
129
+	accuracy := float64(e) / float64(len(pattern))
130
+	proximity := math.Abs(float64(loc - x))
131
+	if dmp.MatchDistance == 0 {
132
+		// Dodge divide by zero error.
133
+		if proximity == 0 {
134
+			return accuracy
135
+		}
136
+
137
+		return 1.0
138
+	}
139
+	return accuracy + (proximity / float64(dmp.MatchDistance))
140
+}
141
+
142
+// MatchAlphabet initialises the alphabet for the Bitap algorithm.
143
+func (dmp *DiffMatchPatch) MatchAlphabet(pattern string) map[byte]int {
144
+	s := map[byte]int{}
145
+	charPattern := []byte(pattern)
146
+	for _, c := range charPattern {
147
+		_, ok := s[c]
148
+		if !ok {
149
+			s[c] = 0
150
+		}
151
+	}
152
+	i := 0
153
+
154
+	for _, c := range charPattern {
155
+		value := s[c] | int(uint(1)<<uint((len(pattern)-i-1)))
156
+		s[c] = value
157
+		i++
158
+	}
159
+	return s
160
+}

+ 174
- 0
vendor/src/github.com/sergi/go-diff/diffmatchpatch/match_test.go Datei anzeigen

@@ -0,0 +1,174 @@
1
+// Copyright (c) 2012-2016 The go-diff authors. All rights reserved.
2
+// https://github.com/sergi/go-diff
3
+// See the included LICENSE file for license details.
4
+//
5
+// go-diff is a Go implementation of Google's Diff, Match, and Patch library
6
+// Original library is Copyright (c) 2006 Google Inc.
7
+// http://code.google.com/p/google-diff-match-patch/
8
+
9
+package diffmatchpatch
10
+
11
+import (
12
+	"fmt"
13
+	"testing"
14
+
15
+	"github.com/stretchr/testify/assert"
16
+)
17
+
18
+func TestMatchAlphabet(t *testing.T) {
19
+	type TestCase struct {
20
+		Pattern string
21
+
22
+		Expected map[byte]int
23
+	}
24
+
25
+	dmp := New()
26
+
27
+	for i, tc := range []TestCase{
28
+		{
29
+			Pattern: "abc",
30
+
31
+			Expected: map[byte]int{
32
+				'a': 4,
33
+				'b': 2,
34
+				'c': 1,
35
+			},
36
+		},
37
+		{
38
+			Pattern: "abcaba",
39
+
40
+			Expected: map[byte]int{
41
+				'a': 37,
42
+				'b': 18,
43
+				'c': 8,
44
+			},
45
+		},
46
+	} {
47
+		actual := dmp.MatchAlphabet(tc.Pattern)
48
+		assert.Equal(t, tc.Expected, actual, fmt.Sprintf("Test case #%d, %#v", i, tc))
49
+	}
50
+}
51
+
52
+func TestMatchBitap(t *testing.T) {
53
+	type TestCase struct {
54
+		Name string
55
+
56
+		Text     string
57
+		Pattern  string
58
+		Location int
59
+
60
+		Expected int
61
+	}
62
+
63
+	dmp := New()
64
+	dmp.MatchDistance = 100
65
+	dmp.MatchThreshold = 0.5
66
+
67
+	for i, tc := range []TestCase{
68
+		{"Exact match #1", "abcdefghijk", "fgh", 5, 5},
69
+		{"Exact match #2", "abcdefghijk", "fgh", 0, 5},
70
+		{"Fuzzy match #1", "abcdefghijk", "efxhi", 0, 4},
71
+		{"Fuzzy match #2", "abcdefghijk", "cdefxyhijk", 5, 2},
72
+		{"Fuzzy match #3", "abcdefghijk", "bxy", 1, -1},
73
+		{"Overflow", "123456789xx0", "3456789x0", 2, 2},
74
+		{"Before start match", "abcdef", "xxabc", 4, 0},
75
+		{"Beyond end match", "abcdef", "defyy", 4, 3},
76
+		{"Oversized pattern", "abcdef", "xabcdefy", 0, 0},
77
+	} {
78
+		actual := dmp.MatchBitap(tc.Text, tc.Pattern, tc.Location)
79
+		assert.Equal(t, tc.Expected, actual, fmt.Sprintf("Test case #%d, %s", i, tc.Name))
80
+	}
81
+
82
+	dmp.MatchThreshold = 0.4
83
+
84
+	for i, tc := range []TestCase{
85
+		{"Threshold #1", "abcdefghijk", "efxyhi", 1, 4},
86
+	} {
87
+		actual := dmp.MatchBitap(tc.Text, tc.Pattern, tc.Location)
88
+		assert.Equal(t, tc.Expected, actual, fmt.Sprintf("Test case #%d, %s", i, tc.Name))
89
+	}
90
+
91
+	dmp.MatchThreshold = 0.3
92
+
93
+	for i, tc := range []TestCase{
94
+		{"Threshold #2", "abcdefghijk", "efxyhi", 1, -1},
95
+	} {
96
+		actual := dmp.MatchBitap(tc.Text, tc.Pattern, tc.Location)
97
+		assert.Equal(t, tc.Expected, actual, fmt.Sprintf("Test case #%d, %s", i, tc.Name))
98
+	}
99
+
100
+	dmp.MatchThreshold = 0.0
101
+
102
+	for i, tc := range []TestCase{
103
+		{"Threshold #3", "abcdefghijk", "bcdef", 1, 1},
104
+	} {
105
+		actual := dmp.MatchBitap(tc.Text, tc.Pattern, tc.Location)
106
+		assert.Equal(t, tc.Expected, actual, fmt.Sprintf("Test case #%d, %s", i, tc.Name))
107
+	}
108
+
109
+	dmp.MatchThreshold = 0.5
110
+
111
+	for i, tc := range []TestCase{
112
+		{"Multiple select #1", "abcdexyzabcde", "abccde", 3, 0},
113
+		{"Multiple select #2", "abcdexyzabcde", "abccde", 5, 8},
114
+	} {
115
+		actual := dmp.MatchBitap(tc.Text, tc.Pattern, tc.Location)
116
+		assert.Equal(t, tc.Expected, actual, fmt.Sprintf("Test case #%d, %s", i, tc.Name))
117
+	}
118
+
119
+	// Strict location.
120
+	dmp.MatchDistance = 10
121
+
122
+	for i, tc := range []TestCase{
123
+		{"Distance test #1", "abcdefghijklmnopqrstuvwxyz", "abcdefg", 24, -1},
124
+		{"Distance test #2", "abcdefghijklmnopqrstuvwxyz", "abcdxxefg", 1, 0},
125
+	} {
126
+		actual := dmp.MatchBitap(tc.Text, tc.Pattern, tc.Location)
127
+		assert.Equal(t, tc.Expected, actual, fmt.Sprintf("Test case #%d, %s", i, tc.Name))
128
+	}
129
+
130
+	// Loose location.
131
+	dmp.MatchDistance = 1000
132
+
133
+	for i, tc := range []TestCase{
134
+		{"Distance test #3", "abcdefghijklmnopqrstuvwxyz", "abcdefg", 24, 0},
135
+	} {
136
+		actual := dmp.MatchBitap(tc.Text, tc.Pattern, tc.Location)
137
+		assert.Equal(t, tc.Expected, actual, fmt.Sprintf("Test case #%d, %s", i, tc.Name))
138
+	}
139
+}
140
+
141
+func TestMatchMain(t *testing.T) {
142
+	type TestCase struct {
143
+		Name string
144
+
145
+		Text1    string
146
+		Text2    string
147
+		Location int
148
+
149
+		Expected int
150
+	}
151
+
152
+	dmp := New()
153
+
154
+	for i, tc := range []TestCase{
155
+		{"Equality", "abcdef", "abcdef", 1000, 0},
156
+		{"Null text", "", "abcdef", 1, -1},
157
+		{"Null pattern", "abcdef", "", 3, 3},
158
+		{"Exact match", "abcdef", "de", 3, 3},
159
+		{"Beyond end match", "abcdef", "defy", 4, 3},
160
+		{"Oversized pattern", "abcdef", "abcdefy", 0, 0},
161
+	} {
162
+		actual := dmp.MatchMain(tc.Text1, tc.Text2, tc.Location)
163
+		assert.Equal(t, tc.Expected, actual, fmt.Sprintf("Test case #%d, %s", i, tc.Name))
164
+	}
165
+
166
+	dmp.MatchThreshold = 0.7
167
+
168
+	for i, tc := range []TestCase{
169
+		{"Complex match", "I am the very model of a modern major general.", " that berry ", 5, 4},
170
+	} {
171
+		actual := dmp.MatchMain(tc.Text1, tc.Text2, tc.Location)
172
+		assert.Equal(t, tc.Expected, actual, fmt.Sprintf("Test case #%d, %#v", i, tc))
173
+	}
174
+}

+ 23
- 0
vendor/src/github.com/sergi/go-diff/diffmatchpatch/mathutil.go Datei anzeigen

@@ -0,0 +1,23 @@
1
+// Copyright (c) 2012-2016 The go-diff authors. All rights reserved.
2
+// https://github.com/sergi/go-diff
3
+// See the included LICENSE file for license details.
4
+//
5
+// go-diff is a Go implementation of Google's Diff, Match, and Patch library
6
+// Original library is Copyright (c) 2006 Google Inc.
7
+// http://code.google.com/p/google-diff-match-patch/
8
+
9
+package diffmatchpatch
10
+
11
+func min(x, y int) int {
12
+	if x < y {
13
+		return x
14
+	}
15
+	return y
16
+}
17
+
18
+func max(x, y int) int {
19
+	if x > y {
20
+		return x
21
+	}
22
+	return y
23
+}

+ 556
- 0
vendor/src/github.com/sergi/go-diff/diffmatchpatch/patch.go Datei anzeigen

@@ -0,0 +1,556 @@
1
+// Copyright (c) 2012-2016 The go-diff authors. All rights reserved.
2
+// https://github.com/sergi/go-diff
3
+// See the included LICENSE file for license details.
4
+//
5
+// go-diff is a Go implementation of Google's Diff, Match, and Patch library
6
+// Original library is Copyright (c) 2006 Google Inc.
7
+// http://code.google.com/p/google-diff-match-patch/
8
+
9
+package diffmatchpatch
10
+
11
+import (
12
+	"bytes"
13
+	"errors"
14
+	"math"
15
+	"net/url"
16
+	"regexp"
17
+	"strconv"
18
+	"strings"
19
+)
20
+
21
+// Patch represents one patch operation.
22
+type Patch struct {
23
+	diffs   []Diff
24
+	Start1  int
25
+	Start2  int
26
+	Length1 int
27
+	Length2 int
28
+}
29
+
30
+// String emulates GNU diff's format.
31
+// Header: @@ -382,8 +481,9 @@
32
+// Indices are printed as 1-based, not 0-based.
33
+func (p *Patch) String() string {
34
+	var coords1, coords2 string
35
+
36
+	if p.Length1 == 0 {
37
+		coords1 = strconv.Itoa(p.Start1) + ",0"
38
+	} else if p.Length1 == 1 {
39
+		coords1 = strconv.Itoa(p.Start1 + 1)
40
+	} else {
41
+		coords1 = strconv.Itoa(p.Start1+1) + "," + strconv.Itoa(p.Length1)
42
+	}
43
+
44
+	if p.Length2 == 0 {
45
+		coords2 = strconv.Itoa(p.Start2) + ",0"
46
+	} else if p.Length2 == 1 {
47
+		coords2 = strconv.Itoa(p.Start2 + 1)
48
+	} else {
49
+		coords2 = strconv.Itoa(p.Start2+1) + "," + strconv.Itoa(p.Length2)
50
+	}
51
+
52
+	var text bytes.Buffer
53
+	_, _ = text.WriteString("@@ -" + coords1 + " +" + coords2 + " @@\n")
54
+
55
+	// Escape the body of the patch with %xx notation.
56
+	for _, aDiff := range p.diffs {
57
+		switch aDiff.Type {
58
+		case DiffInsert:
59
+			_, _ = text.WriteString("+")
60
+		case DiffDelete:
61
+			_, _ = text.WriteString("-")
62
+		case DiffEqual:
63
+			_, _ = text.WriteString(" ")
64
+		}
65
+
66
+		_, _ = text.WriteString(strings.Replace(url.QueryEscape(aDiff.Text), "+", " ", -1))
67
+		_, _ = text.WriteString("\n")
68
+	}
69
+
70
+	return unescaper.Replace(text.String())
71
+}
72
+
73
+// PatchAddContext increases the context until it is unique, but doesn't let the pattern expand beyond MatchMaxBits.
74
+func (dmp *DiffMatchPatch) PatchAddContext(patch Patch, text string) Patch {
75
+	if len(text) == 0 {
76
+		return patch
77
+	}
78
+
79
+	pattern := text[patch.Start2 : patch.Start2+patch.Length1]
80
+	padding := 0
81
+
82
+	// Look for the first and last matches of pattern in text.  If two different matches are found, increase the pattern length.
83
+	for strings.Index(text, pattern) != strings.LastIndex(text, pattern) &&
84
+		len(pattern) < dmp.MatchMaxBits-2*dmp.PatchMargin {
85
+		padding += dmp.PatchMargin
86
+		maxStart := max(0, patch.Start2-padding)
87
+		minEnd := min(len(text), patch.Start2+patch.Length1+padding)
88
+		pattern = text[maxStart:minEnd]
89
+	}
90
+	// Add one chunk for good luck.
91
+	padding += dmp.PatchMargin
92
+
93
+	// Add the prefix.
94
+	prefix := text[max(0, patch.Start2-padding):patch.Start2]
95
+	if len(prefix) != 0 {
96
+		patch.diffs = append([]Diff{Diff{DiffEqual, prefix}}, patch.diffs...)
97
+	}
98
+	// Add the suffix.
99
+	suffix := text[patch.Start2+patch.Length1 : min(len(text), patch.Start2+patch.Length1+padding)]
100
+	if len(suffix) != 0 {
101
+		patch.diffs = append(patch.diffs, Diff{DiffEqual, suffix})
102
+	}
103
+
104
+	// Roll back the start points.
105
+	patch.Start1 -= len(prefix)
106
+	patch.Start2 -= len(prefix)
107
+	// Extend the lengths.
108
+	patch.Length1 += len(prefix) + len(suffix)
109
+	patch.Length2 += len(prefix) + len(suffix)
110
+
111
+	return patch
112
+}
113
+
114
+// PatchMake computes a list of patches.
115
+func (dmp *DiffMatchPatch) PatchMake(opt ...interface{}) []Patch {
116
+	if len(opt) == 1 {
117
+		diffs, _ := opt[0].([]Diff)
118
+		text1 := dmp.DiffText1(diffs)
119
+		return dmp.PatchMake(text1, diffs)
120
+	} else if len(opt) == 2 {
121
+		text1 := opt[0].(string)
122
+		switch t := opt[1].(type) {
123
+		case string:
124
+			diffs := dmp.DiffMain(text1, t, true)
125
+			if len(diffs) > 2 {
126
+				diffs = dmp.DiffCleanupSemantic(diffs)
127
+				diffs = dmp.DiffCleanupEfficiency(diffs)
128
+			}
129
+			return dmp.PatchMake(text1, diffs)
130
+		case []Diff:
131
+			return dmp.patchMake2(text1, t)
132
+		}
133
+	} else if len(opt) == 3 {
134
+		return dmp.PatchMake(opt[0], opt[2])
135
+	}
136
+	return []Patch{}
137
+}
138
+
139
+// patchMake2 computes a list of patches to turn text1 into text2.
140
+// text2 is not provided, diffs are the delta between text1 and text2.
141
+func (dmp *DiffMatchPatch) patchMake2(text1 string, diffs []Diff) []Patch {
142
+	// Check for null inputs not needed since null can't be passed in C#.
143
+	patches := []Patch{}
144
+	if len(diffs) == 0 {
145
+		return patches // Get rid of the null case.
146
+	}
147
+
148
+	patch := Patch{}
149
+	charCount1 := 0 // Number of characters into the text1 string.
150
+	charCount2 := 0 // Number of characters into the text2 string.
151
+	// Start with text1 (prepatchText) and apply the diffs until we arrive at text2 (postpatchText). We recreate the patches one by one to determine context info.
152
+	prepatchText := text1
153
+	postpatchText := text1
154
+
155
+	for i, aDiff := range diffs {
156
+		if len(patch.diffs) == 0 && aDiff.Type != DiffEqual {
157
+			// A new patch starts here.
158
+			patch.Start1 = charCount1
159
+			patch.Start2 = charCount2
160
+		}
161
+
162
+		switch aDiff.Type {
163
+		case DiffInsert:
164
+			patch.diffs = append(patch.diffs, aDiff)
165
+			patch.Length2 += len(aDiff.Text)
166
+			postpatchText = postpatchText[:charCount2] +
167
+				aDiff.Text + postpatchText[charCount2:]
168
+		case DiffDelete:
169
+			patch.Length1 += len(aDiff.Text)
170
+			patch.diffs = append(patch.diffs, aDiff)
171
+			postpatchText = postpatchText[:charCount2] + postpatchText[charCount2+len(aDiff.Text):]
172
+		case DiffEqual:
173
+			if len(aDiff.Text) <= 2*dmp.PatchMargin &&
174
+				len(patch.diffs) != 0 && i != len(diffs)-1 {
175
+				// Small equality inside a patch.
176
+				patch.diffs = append(patch.diffs, aDiff)
177
+				patch.Length1 += len(aDiff.Text)
178
+				patch.Length2 += len(aDiff.Text)
179
+			}
180
+			if len(aDiff.Text) >= 2*dmp.PatchMargin {
181
+				// Time for a new patch.
182
+				if len(patch.diffs) != 0 {
183
+					patch = dmp.PatchAddContext(patch, prepatchText)
184
+					patches = append(patches, patch)
185
+					patch = Patch{}
186
+					// Unlike Unidiff, our patch lists have a rolling context. http://code.google.com/p/google-diff-match-patch/wiki/Unidiff Update prepatch text & pos to reflect the application of the just completed patch.
187
+					prepatchText = postpatchText
188
+					charCount1 = charCount2
189
+				}
190
+			}
191
+		}
192
+
193
+		// Update the current character count.
194
+		if aDiff.Type != DiffInsert {
195
+			charCount1 += len(aDiff.Text)
196
+		}
197
+		if aDiff.Type != DiffDelete {
198
+			charCount2 += len(aDiff.Text)
199
+		}
200
+	}
201
+
202
+	// Pick up the leftover patch if not empty.
203
+	if len(patch.diffs) != 0 {
204
+		patch = dmp.PatchAddContext(patch, prepatchText)
205
+		patches = append(patches, patch)
206
+	}
207
+
208
+	return patches
209
+}
210
+
211
+// PatchDeepCopy returns an array that is identical to a given an array of patches.
212
+func (dmp *DiffMatchPatch) PatchDeepCopy(patches []Patch) []Patch {
213
+	patchesCopy := []Patch{}
214
+	for _, aPatch := range patches {
215
+		patchCopy := Patch{}
216
+		for _, aDiff := range aPatch.diffs {
217
+			patchCopy.diffs = append(patchCopy.diffs, Diff{
218
+				aDiff.Type,
219
+				aDiff.Text,
220
+			})
221
+		}
222
+		patchCopy.Start1 = aPatch.Start1
223
+		patchCopy.Start2 = aPatch.Start2
224
+		patchCopy.Length1 = aPatch.Length1
225
+		patchCopy.Length2 = aPatch.Length2
226
+		patchesCopy = append(patchesCopy, patchCopy)
227
+	}
228
+	return patchesCopy
229
+}
230
+
231
+// PatchApply merges a set of patches onto the text.  Returns a patched text, as well as an array of true/false values indicating which patches were applied.
232
+func (dmp *DiffMatchPatch) PatchApply(patches []Patch, text string) (string, []bool) {
233
+	if len(patches) == 0 {
234
+		return text, []bool{}
235
+	}
236
+
237
+	// Deep copy the patches so that no changes are made to originals.
238
+	patches = dmp.PatchDeepCopy(patches)
239
+
240
+	nullPadding := dmp.PatchAddPadding(patches)
241
+	text = nullPadding + text + nullPadding
242
+	patches = dmp.PatchSplitMax(patches)
243
+
244
+	x := 0
245
+	// delta keeps track of the offset between the expected and actual location of the previous patch.  If there are patches expected at positions 10 and 20, but the first patch was found at 12, delta is 2 and the second patch has an effective expected position of 22.
246
+	delta := 0
247
+	results := make([]bool, len(patches))
248
+	for _, aPatch := range patches {
249
+		expectedLoc := aPatch.Start2 + delta
250
+		text1 := dmp.DiffText1(aPatch.diffs)
251
+		var startLoc int
252
+		endLoc := -1
253
+		if len(text1) > dmp.MatchMaxBits {
254
+			// PatchSplitMax will only provide an oversized pattern in the case of a monster delete.
255
+			startLoc = dmp.MatchMain(text, text1[:dmp.MatchMaxBits], expectedLoc)
256
+			if startLoc != -1 {
257
+				endLoc = dmp.MatchMain(text,
258
+					text1[len(text1)-dmp.MatchMaxBits:], expectedLoc+len(text1)-dmp.MatchMaxBits)
259
+				if endLoc == -1 || startLoc >= endLoc {
260
+					// Can't find valid trailing context.  Drop this patch.
261
+					startLoc = -1
262
+				}
263
+			}
264
+		} else {
265
+			startLoc = dmp.MatchMain(text, text1, expectedLoc)
266
+		}
267
+		if startLoc == -1 {
268
+			// No match found.  :(
269
+			results[x] = false
270
+			// Subtract the delta for this failed patch from subsequent patches.
271
+			delta -= aPatch.Length2 - aPatch.Length1
272
+		} else {
273
+			// Found a match.  :)
274
+			results[x] = true
275
+			delta = startLoc - expectedLoc
276
+			var text2 string
277
+			if endLoc == -1 {
278
+				text2 = text[startLoc:int(math.Min(float64(startLoc+len(text1)), float64(len(text))))]
279
+			} else {
280
+				text2 = text[startLoc:int(math.Min(float64(endLoc+dmp.MatchMaxBits), float64(len(text))))]
281
+			}
282
+			if text1 == text2 {
283
+				// Perfect match, just shove the Replacement text in.
284
+				text = text[:startLoc] + dmp.DiffText2(aPatch.diffs) + text[startLoc+len(text1):]
285
+			} else {
286
+				// Imperfect match.  Run a diff to get a framework of equivalent indices.
287
+				diffs := dmp.DiffMain(text1, text2, false)
288
+				if len(text1) > dmp.MatchMaxBits && float64(dmp.DiffLevenshtein(diffs))/float64(len(text1)) > dmp.PatchDeleteThreshold {
289
+					// The end points match, but the content is unacceptably bad.
290
+					results[x] = false
291
+				} else {
292
+					diffs = dmp.DiffCleanupSemanticLossless(diffs)
293
+					index1 := 0
294
+					for _, aDiff := range aPatch.diffs {
295
+						if aDiff.Type != DiffEqual {
296
+							index2 := dmp.DiffXIndex(diffs, index1)
297
+							if aDiff.Type == DiffInsert {
298
+								// Insertion
299
+								text = text[:startLoc+index2] + aDiff.Text + text[startLoc+index2:]
300
+							} else if aDiff.Type == DiffDelete {
301
+								// Deletion
302
+								startIndex := startLoc + index2
303
+								text = text[:startIndex] +
304
+									text[startIndex+dmp.DiffXIndex(diffs, index1+len(aDiff.Text))-index2:]
305
+							}
306
+						}
307
+						if aDiff.Type != DiffDelete {
308
+							index1 += len(aDiff.Text)
309
+						}
310
+					}
311
+				}
312
+			}
313
+		}
314
+		x++
315
+	}
316
+	// Strip the padding off.
317
+	text = text[len(nullPadding) : len(nullPadding)+(len(text)-2*len(nullPadding))]
318
+	return text, results
319
+}
320
+
321
+// PatchAddPadding adds some padding on text start and end so that edges can match something.
322
+// Intended to be called only from within patchApply.
323
+func (dmp *DiffMatchPatch) PatchAddPadding(patches []Patch) string {
324
+	paddingLength := dmp.PatchMargin
325
+	nullPadding := ""
326
+	for x := 1; x <= paddingLength; x++ {
327
+		nullPadding += string(x)
328
+	}
329
+
330
+	// Bump all the patches forward.
331
+	for i := range patches {
332
+		patches[i].Start1 += paddingLength
333
+		patches[i].Start2 += paddingLength
334
+	}
335
+
336
+	// Add some padding on start of first diff.
337
+	if len(patches[0].diffs) == 0 || patches[0].diffs[0].Type != DiffEqual {
338
+		// Add nullPadding equality.
339
+		patches[0].diffs = append([]Diff{Diff{DiffEqual, nullPadding}}, patches[0].diffs...)
340
+		patches[0].Start1 -= paddingLength // Should be 0.
341
+		patches[0].Start2 -= paddingLength // Should be 0.
342
+		patches[0].Length1 += paddingLength
343
+		patches[0].Length2 += paddingLength
344
+	} else if paddingLength > len(patches[0].diffs[0].Text) {
345
+		// Grow first equality.
346
+		extraLength := paddingLength - len(patches[0].diffs[0].Text)
347
+		patches[0].diffs[0].Text = nullPadding[len(patches[0].diffs[0].Text):] + patches[0].diffs[0].Text
348
+		patches[0].Start1 -= extraLength
349
+		patches[0].Start2 -= extraLength
350
+		patches[0].Length1 += extraLength
351
+		patches[0].Length2 += extraLength
352
+	}
353
+
354
+	// Add some padding on end of last diff.
355
+	last := len(patches) - 1
356
+	if len(patches[last].diffs) == 0 || patches[last].diffs[len(patches[last].diffs)-1].Type != DiffEqual {
357
+		// Add nullPadding equality.
358
+		patches[last].diffs = append(patches[last].diffs, Diff{DiffEqual, nullPadding})
359
+		patches[last].Length1 += paddingLength
360
+		patches[last].Length2 += paddingLength
361
+	} else if paddingLength > len(patches[last].diffs[len(patches[last].diffs)-1].Text) {
362
+		// Grow last equality.
363
+		lastDiff := patches[last].diffs[len(patches[last].diffs)-1]
364
+		extraLength := paddingLength - len(lastDiff.Text)
365
+		patches[last].diffs[len(patches[last].diffs)-1].Text += nullPadding[:extraLength]
366
+		patches[last].Length1 += extraLength
367
+		patches[last].Length2 += extraLength
368
+	}
369
+
370
+	return nullPadding
371
+}
372
+
373
+// PatchSplitMax looks through the patches and breaks up any which are longer than the maximum limit of the match algorithm.
374
+// Intended to be called only from within patchApply.
375
+func (dmp *DiffMatchPatch) PatchSplitMax(patches []Patch) []Patch {
376
+	patchSize := dmp.MatchMaxBits
377
+	for x := 0; x < len(patches); x++ {
378
+		if patches[x].Length1 <= patchSize {
379
+			continue
380
+		}
381
+		bigpatch := patches[x]
382
+		// Remove the big old patch.
383
+		patches = append(patches[:x], patches[x+1:]...)
384
+		x--
385
+
386
+		Start1 := bigpatch.Start1
387
+		Start2 := bigpatch.Start2
388
+		precontext := ""
389
+		for len(bigpatch.diffs) != 0 {
390
+			// Create one of several smaller patches.
391
+			patch := Patch{}
392
+			empty := true
393
+			patch.Start1 = Start1 - len(precontext)
394
+			patch.Start2 = Start2 - len(precontext)
395
+			if len(precontext) != 0 {
396
+				patch.Length1 = len(precontext)
397
+				patch.Length2 = len(precontext)
398
+				patch.diffs = append(patch.diffs, Diff{DiffEqual, precontext})
399
+			}
400
+			for len(bigpatch.diffs) != 0 && patch.Length1 < patchSize-dmp.PatchMargin {
401
+				diffType := bigpatch.diffs[0].Type
402
+				diffText := bigpatch.diffs[0].Text
403
+				if diffType == DiffInsert {
404
+					// Insertions are harmless.
405
+					patch.Length2 += len(diffText)
406
+					Start2 += len(diffText)
407
+					patch.diffs = append(patch.diffs, bigpatch.diffs[0])
408
+					bigpatch.diffs = bigpatch.diffs[1:]
409
+					empty = false
410
+				} else if diffType == DiffDelete && len(patch.diffs) == 1 && patch.diffs[0].Type == DiffEqual && len(diffText) > 2*patchSize {
411
+					// This is a large deletion.  Let it pass in one chunk.
412
+					patch.Length1 += len(diffText)
413
+					Start1 += len(diffText)
414
+					empty = false
415
+					patch.diffs = append(patch.diffs, Diff{diffType, diffText})
416
+					bigpatch.diffs = bigpatch.diffs[1:]
417
+				} else {
418
+					// Deletion or equality.  Only take as much as we can stomach.
419
+					diffText = diffText[:min(len(diffText), patchSize-patch.Length1-dmp.PatchMargin)]
420
+
421
+					patch.Length1 += len(diffText)
422
+					Start1 += len(diffText)
423
+					if diffType == DiffEqual {
424
+						patch.Length2 += len(diffText)
425
+						Start2 += len(diffText)
426
+					} else {
427
+						empty = false
428
+					}
429
+					patch.diffs = append(patch.diffs, Diff{diffType, diffText})
430
+					if diffText == bigpatch.diffs[0].Text {
431
+						bigpatch.diffs = bigpatch.diffs[1:]
432
+					} else {
433
+						bigpatch.diffs[0].Text =
434
+							bigpatch.diffs[0].Text[len(diffText):]
435
+					}
436
+				}
437
+			}
438
+			// Compute the head context for the next patch.
439
+			precontext = dmp.DiffText2(patch.diffs)
440
+			precontext = precontext[max(0, len(precontext)-dmp.PatchMargin):]
441
+
442
+			postcontext := ""
443
+			// Append the end context for this patch.
444
+			if len(dmp.DiffText1(bigpatch.diffs)) > dmp.PatchMargin {
445
+				postcontext = dmp.DiffText1(bigpatch.diffs)[:dmp.PatchMargin]
446
+			} else {
447
+				postcontext = dmp.DiffText1(bigpatch.diffs)
448
+			}
449
+
450
+			if len(postcontext) != 0 {
451
+				patch.Length1 += len(postcontext)
452
+				patch.Length2 += len(postcontext)
453
+				if len(patch.diffs) != 0 && patch.diffs[len(patch.diffs)-1].Type == DiffEqual {
454
+					patch.diffs[len(patch.diffs)-1].Text += postcontext
455
+				} else {
456
+					patch.diffs = append(patch.diffs, Diff{DiffEqual, postcontext})
457
+				}
458
+			}
459
+			if !empty {
460
+				x++
461
+				patches = append(patches[:x], append([]Patch{patch}, patches[x:]...)...)
462
+			}
463
+		}
464
+	}
465
+	return patches
466
+}
467
+
468
+// PatchToText takes a list of patches and returns a textual representation.
469
+func (dmp *DiffMatchPatch) PatchToText(patches []Patch) string {
470
+	var text bytes.Buffer
471
+	for _, aPatch := range patches {
472
+		_, _ = text.WriteString(aPatch.String())
473
+	}
474
+	return text.String()
475
+}
476
+
477
+// PatchFromText parses a textual representation of patches and returns a List of Patch objects.
478
+func (dmp *DiffMatchPatch) PatchFromText(textline string) ([]Patch, error) {
479
+	patches := []Patch{}
480
+	if len(textline) == 0 {
481
+		return patches, nil
482
+	}
483
+	text := strings.Split(textline, "\n")
484
+	textPointer := 0
485
+	patchHeader := regexp.MustCompile("^@@ -(\\d+),?(\\d*) \\+(\\d+),?(\\d*) @@$")
486
+
487
+	var patch Patch
488
+	var sign uint8
489
+	var line string
490
+	for textPointer < len(text) {
491
+
492
+		if !patchHeader.MatchString(text[textPointer]) {
493
+			return patches, errors.New("Invalid patch string: " + text[textPointer])
494
+		}
495
+
496
+		patch = Patch{}
497
+		m := patchHeader.FindStringSubmatch(text[textPointer])
498
+
499
+		patch.Start1, _ = strconv.Atoi(m[1])
500
+		if len(m[2]) == 0 {
501
+			patch.Start1--
502
+			patch.Length1 = 1
503
+		} else if m[2] == "0" {
504
+			patch.Length1 = 0
505
+		} else {
506
+			patch.Start1--
507
+			patch.Length1, _ = strconv.Atoi(m[2])
508
+		}
509
+
510
+		patch.Start2, _ = strconv.Atoi(m[3])
511
+
512
+		if len(m[4]) == 0 {
513
+			patch.Start2--
514
+			patch.Length2 = 1
515
+		} else if m[4] == "0" {
516
+			patch.Length2 = 0
517
+		} else {
518
+			patch.Start2--
519
+			patch.Length2, _ = strconv.Atoi(m[4])
520
+		}
521
+		textPointer++
522
+
523
+		for textPointer < len(text) {
524
+			if len(text[textPointer]) > 0 {
525
+				sign = text[textPointer][0]
526
+			} else {
527
+				textPointer++
528
+				continue
529
+			}
530
+
531
+			line = text[textPointer][1:]
532
+			line = strings.Replace(line, "+", "%2b", -1)
533
+			line, _ = url.QueryUnescape(line)
534
+			if sign == '-' {
535
+				// Deletion.
536
+				patch.diffs = append(patch.diffs, Diff{DiffDelete, line})
537
+			} else if sign == '+' {
538
+				// Insertion.
539
+				patch.diffs = append(patch.diffs, Diff{DiffInsert, line})
540
+			} else if sign == ' ' {
541
+				// Minor equality.
542
+				patch.diffs = append(patch.diffs, Diff{DiffEqual, line})
543
+			} else if sign == '@' {
544
+				// Start of next patch.
545
+				break
546
+			} else {
547
+				// WTF?
548
+				return patches, errors.New("Invalid patch mode '" + string(sign) + "' in: " + string(line))
549
+			}
550
+			textPointer++
551
+		}
552
+
553
+		patches = append(patches, patch)
554
+	}
555
+	return patches, nil
556
+}

+ 339
- 0
vendor/src/github.com/sergi/go-diff/diffmatchpatch/patch_test.go Datei anzeigen

@@ -0,0 +1,339 @@
1
+// Copyright (c) 2012-2016 The go-diff authors. All rights reserved.
2
+// https://github.com/sergi/go-diff
3
+// See the included LICENSE file for license details.
4
+//
5
+// go-diff is a Go implementation of Google's Diff, Match, and Patch library
6
+// Original library is Copyright (c) 2006 Google Inc.
7
+// http://code.google.com/p/google-diff-match-patch/
8
+
9
+package diffmatchpatch
10
+
11
+import (
12
+	"fmt"
13
+	"strings"
14
+	"testing"
15
+
16
+	"github.com/stretchr/testify/assert"
17
+)
18
+
19
+func TestPatchString(t *testing.T) {
20
+	type TestCase struct {
21
+		Patch Patch
22
+
23
+		Expected string
24
+	}
25
+
26
+	for i, tc := range []TestCase{
27
+		{
28
+			Patch: Patch{
29
+				Start1:  20,
30
+				Start2:  21,
31
+				Length1: 18,
32
+				Length2: 17,
33
+
34
+				diffs: []Diff{
35
+					{DiffEqual, "jump"},
36
+					{DiffDelete, "s"},
37
+					{DiffInsert, "ed"},
38
+					{DiffEqual, " over "},
39
+					{DiffDelete, "the"},
40
+					{DiffInsert, "a"},
41
+					{DiffEqual, "\nlaz"},
42
+				},
43
+			},
44
+
45
+			Expected: "@@ -21,18 +22,17 @@\n jump\n-s\n+ed\n  over \n-the\n+a\n %0Alaz\n",
46
+		},
47
+	} {
48
+		actual := tc.Patch.String()
49
+		assert.Equal(t, tc.Expected, actual, fmt.Sprintf("Test case #%d, %#v", i, tc))
50
+	}
51
+}
52
+
53
+func TestPatchFromText(t *testing.T) {
54
+	type TestCase struct {
55
+		Patch string
56
+
57
+		ErrorMessagePrefix string
58
+	}
59
+
60
+	dmp := New()
61
+
62
+	for i, tc := range []TestCase{
63
+		{"", ""},
64
+		{"@@ -21,18 +22,17 @@\n jump\n-s\n+ed\n  over \n-the\n+a\n %0Alaz\n", ""},
65
+		{"@@ -1 +1 @@\n-a\n+b\n", ""},
66
+		{"@@ -1,3 +0,0 @@\n-abc\n", ""},
67
+		{"@@ -0,0 +1,3 @@\n+abc\n", ""},
68
+		{"@@ _0,0 +0,0 @@\n+abc\n", "Invalid patch string: @@ _0,0 +0,0 @@"},
69
+		{"Bad\nPatch\n", "Invalid patch string"},
70
+	} {
71
+		patches, err := dmp.PatchFromText(tc.Patch)
72
+		if tc.ErrorMessagePrefix == "" {
73
+			assert.Nil(t, err)
74
+
75
+			if tc.Patch == "" {
76
+				assert.Equal(t, []Patch{}, patches, fmt.Sprintf("Test case #%d, %#v", i, tc))
77
+			} else {
78
+				assert.Equal(t, tc.Patch, patches[0].String(), fmt.Sprintf("Test case #%d, %#v", i, tc))
79
+			}
80
+		} else {
81
+			e := err.Error()
82
+			if strings.HasPrefix(e, tc.ErrorMessagePrefix) {
83
+				e = tc.ErrorMessagePrefix
84
+			}
85
+			assert.Equal(t, tc.ErrorMessagePrefix, e)
86
+		}
87
+	}
88
+
89
+	diffs := []Diff{
90
+		{DiffDelete, "`1234567890-=[]\\;',./"},
91
+		{DiffInsert, "~!@#$%^&*()_+{}|:\"<>?"},
92
+	}
93
+
94
+	patches, err := dmp.PatchFromText("@@ -1,21 +1,21 @@\n-%601234567890-=%5B%5D%5C;',./\n+~!@#$%25%5E&*()_+%7B%7D%7C:%22%3C%3E?\n")
95
+	assert.Len(t, patches, 1)
96
+	assert.Equal(t, diffs,
97
+		patches[0].diffs,
98
+	)
99
+	assert.Nil(t, err)
100
+}
101
+
102
+func TestPatchToText(t *testing.T) {
103
+	type TestCase struct {
104
+		Patch string
105
+	}
106
+
107
+	dmp := New()
108
+
109
+	for i, tc := range []TestCase{
110
+		{"@@ -21,18 +22,17 @@\n jump\n-s\n+ed\n  over \n-the\n+a\n  laz\n"},
111
+		{"@@ -1,9 +1,9 @@\n-f\n+F\n oo+fooba\n@@ -7,9 +7,9 @@\n obar\n-,\n+.\n  tes\n"},
112
+	} {
113
+		patches, err := dmp.PatchFromText(tc.Patch)
114
+		assert.Nil(t, err)
115
+
116
+		actual := dmp.PatchToText(patches)
117
+		assert.Equal(t, tc.Patch, actual, fmt.Sprintf("Test case #%d, %#v", i, tc))
118
+	}
119
+}
120
+
121
+func TestPatchAddContext(t *testing.T) {
122
+	type TestCase struct {
123
+		Name string
124
+
125
+		Patch string
126
+		Text  string
127
+
128
+		Expected string
129
+	}
130
+
131
+	dmp := New()
132
+	dmp.PatchMargin = 4
133
+
134
+	for i, tc := range []TestCase{
135
+		{"Simple case", "@@ -21,4 +21,10 @@\n-jump\n+somersault\n", "The quick brown fox jumps over the lazy dog.", "@@ -17,12 +17,18 @@\n fox \n-jump\n+somersault\n s ov\n"},
136
+		{"Not enough trailing context", "@@ -21,4 +21,10 @@\n-jump\n+somersault\n", "The quick brown fox jumps.", "@@ -17,10 +17,16 @@\n fox \n-jump\n+somersault\n s.\n"},
137
+		{"Not enough leading context", "@@ -3 +3,2 @@\n-e\n+at\n", "The quick brown fox jumps.", "@@ -1,7 +1,8 @@\n Th\n-e\n+at\n  qui\n"},
138
+		{"Ambiguity", "@@ -3 +3,2 @@\n-e\n+at\n", "The quick brown fox jumps.  The quick brown fox crashes.", "@@ -1,27 +1,28 @@\n Th\n-e\n+at\n  quick brown fox jumps. \n"},
139
+	} {
140
+		patches, err := dmp.PatchFromText(tc.Patch)
141
+		assert.Nil(t, err)
142
+
143
+		actual := dmp.PatchAddContext(patches[0], tc.Text)
144
+		assert.Equal(t, tc.Expected, actual.String(), fmt.Sprintf("Test case #%d, %s", i, tc.Name))
145
+	}
146
+}
147
+
148
+func TestPatchMakeAndPatchToText(t *testing.T) {
149
+	type TestCase struct {
150
+		Name string
151
+
152
+		Input1 interface{}
153
+		Input2 interface{}
154
+		Input3 interface{}
155
+
156
+		Expected string
157
+	}
158
+
159
+	dmp := New()
160
+
161
+	text1 := "The quick brown fox jumps over the lazy dog."
162
+	text2 := "That quick brown fox jumped over a lazy dog."
163
+
164
+	for i, tc := range []TestCase{
165
+		{"Null case", "", "", nil, ""},
166
+		{"Text2+Text1 inputs", text2, text1, nil, "@@ -1,8 +1,7 @@\n Th\n-at\n+e\n  qui\n@@ -21,17 +21,18 @@\n jump\n-ed\n+s\n  over \n-a\n+the\n  laz\n"},
167
+		{"Text1+Text2 inputs", text1, text2, nil, "@@ -1,11 +1,12 @@\n Th\n-e\n+at\n  quick b\n@@ -22,18 +22,17 @@\n jump\n-s\n+ed\n  over \n-the\n+a\n  laz\n"},
168
+		{"Diff input", dmp.DiffMain(text1, text2, false), nil, nil, "@@ -1,11 +1,12 @@\n Th\n-e\n+at\n  quick b\n@@ -22,18 +22,17 @@\n jump\n-s\n+ed\n  over \n-the\n+a\n  laz\n"},
169
+		{"Text1+Diff inputs", text1, dmp.DiffMain(text1, text2, false), nil, "@@ -1,11 +1,12 @@\n Th\n-e\n+at\n  quick b\n@@ -22,18 +22,17 @@\n jump\n-s\n+ed\n  over \n-the\n+a\n  laz\n"},
170
+		{"Text1+Text2+Diff inputs (deprecated)", text1, text2, dmp.DiffMain(text1, text2, false), "@@ -1,11 +1,12 @@\n Th\n-e\n+at\n  quick b\n@@ -22,18 +22,17 @@\n jump\n-s\n+ed\n  over \n-the\n+a\n  laz\n"},
171
+		{"Character encoding", "`1234567890-=[]\\;',./", "~!@#$%^&*()_+{}|:\"<>?", nil, "@@ -1,21 +1,21 @@\n-%601234567890-=%5B%5D%5C;',./\n+~!@#$%25%5E&*()_+%7B%7D%7C:%22%3C%3E?\n"},
172
+		{"Long string with repeats", strings.Repeat("abcdef", 100), strings.Repeat("abcdef", 100) + "123", nil, "@@ -573,28 +573,31 @@\n cdefabcdefabcdefabcdefabcdef\n+123\n"},
173
+		{"Corner case of #31 fixed by #32", "2016-09-01T03:07:14.807830741Z", "2016-09-01T03:07:15.154800781Z", nil, "@@ -15,16 +15,16 @@\n 07:1\n+5.15\n 4\n-.\n 80\n+0\n 78\n-3074\n 1Z\n"},
174
+	} {
175
+		var patches []Patch
176
+		if tc.Input3 != nil {
177
+			patches = dmp.PatchMake(tc.Input1, tc.Input2, tc.Input3)
178
+		} else if tc.Input2 != nil {
179
+			patches = dmp.PatchMake(tc.Input1, tc.Input2)
180
+		} else if ps, ok := tc.Input1.([]Patch); ok {
181
+			patches = ps
182
+		} else {
183
+			patches = dmp.PatchMake(tc.Input1)
184
+		}
185
+
186
+		actual := dmp.PatchToText(patches)
187
+		assert.Equal(t, tc.Expected, actual, fmt.Sprintf("Test case #%d, %s", i, tc.Name))
188
+	}
189
+
190
+	// Corner case of #28 wrong patch with timeout of 0
191
+	dmp.DiffTimeout = 0
192
+
193
+	text1 = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus ut risus et enim consectetur convallis a non ipsum. Sed nec nibh cursus, interdum libero vel."
194
+	text2 = "Lorem a ipsum dolor sit amet, consectetur adipiscing elit. Vivamus ut risus et enim consectetur convallis a non ipsum. Sed nec nibh cursus, interdum liberovel."
195
+
196
+	diffs := dmp.DiffMain(text1, text2, true)
197
+	// Additional check that the diff texts are equal to the originals even if we are using DiffMain with checklines=true #29
198
+	assert.Equal(t, text1, dmp.DiffText1(diffs))
199
+	assert.Equal(t, text2, dmp.DiffText2(diffs))
200
+
201
+	patches := dmp.PatchMake(text1, diffs)
202
+
203
+	actual := dmp.PatchToText(patches)
204
+	assert.Equal(t, "@@ -1,14 +1,16 @@\n Lorem \n+a \n ipsum do\n@@ -148,13 +148,12 @@\n m libero\n- \n vel.\n", actual)
205
+
206
+	// Check that empty Patch array is returned for no parameter call
207
+	patches = dmp.PatchMake()
208
+	assert.Equal(t, []Patch{}, patches)
209
+}
210
+
211
+func TestPatchSplitMax(t *testing.T) {
212
+	type TestCase struct {
213
+		Text1 string
214
+		Text2 string
215
+
216
+		Expected string
217
+	}
218
+
219
+	dmp := New()
220
+
221
+	for i, tc := range []TestCase{
222
+		{"abcdefghijklmnopqrstuvwxyz01234567890", "XabXcdXefXghXijXklXmnXopXqrXstXuvXwxXyzX01X23X45X67X89X0", "@@ -1,32 +1,46 @@\n+X\n ab\n+X\n cd\n+X\n ef\n+X\n gh\n+X\n ij\n+X\n kl\n+X\n mn\n+X\n op\n+X\n qr\n+X\n st\n+X\n uv\n+X\n wx\n+X\n yz\n+X\n 012345\n@@ -25,13 +39,18 @@\n zX01\n+X\n 23\n+X\n 45\n+X\n 67\n+X\n 89\n+X\n 0\n"},
223
+		{"abcdef1234567890123456789012345678901234567890123456789012345678901234567890uvwxyz", "abcdefuvwxyz", "@@ -3,78 +3,8 @@\n cdef\n-1234567890123456789012345678901234567890123456789012345678901234567890\n uvwx\n"},
224
+		{"1234567890123456789012345678901234567890123456789012345678901234567890", "abc", "@@ -1,32 +1,4 @@\n-1234567890123456789012345678\n 9012\n@@ -29,32 +1,4 @@\n-9012345678901234567890123456\n 7890\n@@ -57,14 +1,3 @@\n-78901234567890\n+abc\n"},
225
+		{"abcdefghij , h : 0 , t : 1 abcdefghij , h : 0 , t : 1 abcdefghij , h : 0 , t : 1", "abcdefghij , h : 1 , t : 1 abcdefghij , h : 1 , t : 1 abcdefghij , h : 0 , t : 1", "@@ -2,32 +2,32 @@\n bcdefghij , h : \n-0\n+1\n  , t : 1 abcdef\n@@ -29,32 +29,32 @@\n bcdefghij , h : \n-0\n+1\n  , t : 1 abcdef\n"},
226
+	} {
227
+		patches := dmp.PatchMake(tc.Text1, tc.Text2)
228
+		patches = dmp.PatchSplitMax(patches)
229
+
230
+		actual := dmp.PatchToText(patches)
231
+		assert.Equal(t, tc.Expected, actual, fmt.Sprintf("Test case #%d, %#v", i, tc))
232
+	}
233
+}
234
+
235
+func TestPatchAddPadding(t *testing.T) {
236
+	type TestCase struct {
237
+		Name string
238
+
239
+		Text1 string
240
+		Text2 string
241
+
242
+		Expected            string
243
+		ExpectedWithPadding string
244
+	}
245
+
246
+	dmp := New()
247
+
248
+	for i, tc := range []TestCase{
249
+		{"Both edges full", "", "test", "@@ -0,0 +1,4 @@\n+test\n", "@@ -1,8 +1,12 @@\n %01%02%03%04\n+test\n %01%02%03%04\n"},
250
+		{"Both edges partial", "XY", "XtestY", "@@ -1,2 +1,6 @@\n X\n+test\n Y\n", "@@ -2,8 +2,12 @@\n %02%03%04X\n+test\n Y%01%02%03\n"},
251
+		{"Both edges none", "XXXXYYYY", "XXXXtestYYYY", "@@ -1,8 +1,12 @@\n XXXX\n+test\n YYYY\n", "@@ -5,8 +5,12 @@\n XXXX\n+test\n YYYY\n"},
252
+	} {
253
+		patches := dmp.PatchMake(tc.Text1, tc.Text2)
254
+
255
+		actual := dmp.PatchToText(patches)
256
+		assert.Equal(t, tc.Expected, actual, fmt.Sprintf("Test case #%d, %s", i, tc.Name))
257
+
258
+		dmp.PatchAddPadding(patches)
259
+
260
+		actualWithPadding := dmp.PatchToText(patches)
261
+		assert.Equal(t, tc.ExpectedWithPadding, actualWithPadding, fmt.Sprintf("Test case #%d, %s", i, tc.Name))
262
+	}
263
+}
264
+
265
+func TestPatchApply(t *testing.T) {
266
+	type TestCase struct {
267
+		Name string
268
+
269
+		Text1    string
270
+		Text2    string
271
+		TextBase string
272
+
273
+		Expected        string
274
+		ExpectedApplies []bool
275
+	}
276
+
277
+	dmp := New()
278
+	dmp.MatchDistance = 1000
279
+	dmp.MatchThreshold = 0.5
280
+	dmp.PatchDeleteThreshold = 0.5
281
+
282
+	for i, tc := range []TestCase{
283
+		{"Null case", "", "", "Hello world.", "Hello world.", []bool{}},
284
+		{"Exact match", "The quick brown fox jumps over the lazy dog.", "That quick brown fox jumped over a lazy dog.", "The quick brown fox jumps over the lazy dog.", "That quick brown fox jumped over a lazy dog.", []bool{true, true}},
285
+		{"Partial match", "The quick brown fox jumps over the lazy dog.", "That quick brown fox jumped over a lazy dog.", "The quick red rabbit jumps over the tired tiger.", "That quick red rabbit jumped over a tired tiger.", []bool{true, true}},
286
+		{"Failed match", "The quick brown fox jumps over the lazy dog.", "That quick brown fox jumped over a lazy dog.", "I am the very model of a modern major general.", "I am the very model of a modern major general.", []bool{false, false}},
287
+		{"Big delete, small Diff", "x1234567890123456789012345678901234567890123456789012345678901234567890y", "xabcy", "x123456789012345678901234567890-----++++++++++-----123456789012345678901234567890y", "xabcy", []bool{true, true}},
288
+		{"Big delete, big Diff 1", "x1234567890123456789012345678901234567890123456789012345678901234567890y", "xabcy", "x12345678901234567890---------------++++++++++---------------12345678901234567890y", "xabc12345678901234567890---------------++++++++++---------------12345678901234567890y", []bool{false, true}},
289
+	} {
290
+		patches := dmp.PatchMake(tc.Text1, tc.Text2)
291
+
292
+		actual, actualApplies := dmp.PatchApply(patches, tc.TextBase)
293
+		assert.Equal(t, tc.Expected, actual, fmt.Sprintf("Test case #%d, %s", i, tc.Name))
294
+		assert.Equal(t, tc.ExpectedApplies, actualApplies, fmt.Sprintf("Test case #%d, %s", i, tc.Name))
295
+	}
296
+
297
+	dmp.PatchDeleteThreshold = 0.6
298
+
299
+	for i, tc := range []TestCase{
300
+		{"Big delete, big Diff 2", "x1234567890123456789012345678901234567890123456789012345678901234567890y", "xabcy", "x12345678901234567890---------------++++++++++---------------12345678901234567890y", "xabcy", []bool{true, true}},
301
+	} {
302
+		patches := dmp.PatchMake(tc.Text1, tc.Text2)
303
+
304
+		actual, actualApplies := dmp.PatchApply(patches, tc.TextBase)
305
+		assert.Equal(t, tc.Expected, actual, fmt.Sprintf("Test case #%d, %s", i, tc.Name))
306
+		assert.Equal(t, tc.ExpectedApplies, actualApplies, fmt.Sprintf("Test case #%d, %s", i, tc.Name))
307
+	}
308
+
309
+	dmp.MatchDistance = 0
310
+	dmp.MatchThreshold = 0.0
311
+	dmp.PatchDeleteThreshold = 0.5
312
+
313
+	for i, tc := range []TestCase{
314
+		{"Compensate for failed patch", "abcdefghijklmnopqrstuvwxyz--------------------1234567890", "abcXXXXXXXXXXdefghijklmnopqrstuvwxyz--------------------1234567YYYYYYYYYY890", "ABCDEFGHIJKLMNOPQRSTUVWXYZ--------------------1234567890", "ABCDEFGHIJKLMNOPQRSTUVWXYZ--------------------1234567YYYYYYYYYY890", []bool{false, true}},
315
+	} {
316
+		patches := dmp.PatchMake(tc.Text1, tc.Text2)
317
+
318
+		actual, actualApplies := dmp.PatchApply(patches, tc.TextBase)
319
+		assert.Equal(t, tc.Expected, actual, fmt.Sprintf("Test case #%d, %s", i, tc.Name))
320
+		assert.Equal(t, tc.ExpectedApplies, actualApplies, fmt.Sprintf("Test case #%d, %s", i, tc.Name))
321
+	}
322
+
323
+	dmp.MatchThreshold = 0.5
324
+	dmp.MatchDistance = 1000
325
+
326
+	for i, tc := range []TestCase{
327
+		{"No side effects", "", "test", "", "test", []bool{true}},
328
+		{"No side effects with major delete", "The quick brown fox jumps over the lazy dog.", "Woof", "The quick brown fox jumps over the lazy dog.", "Woof", []bool{true, true}},
329
+		{"Edge exact match", "", "test", "", "test", []bool{true}},
330
+		{"Near edge exact match", "XY", "XtestY", "XY", "XtestY", []bool{true}},
331
+		{"Edge partial match", "y", "y123", "x", "x123", []bool{true}},
332
+	} {
333
+		patches := dmp.PatchMake(tc.Text1, tc.Text2)
334
+
335
+		actual, actualApplies := dmp.PatchApply(patches, tc.TextBase)
336
+		assert.Equal(t, tc.Expected, actual, fmt.Sprintf("Test case #%d, %s", i, tc.Name))
337
+		assert.Equal(t, tc.ExpectedApplies, actualApplies, fmt.Sprintf("Test case #%d, %s", i, tc.Name))
338
+	}
339
+}

+ 88
- 0
vendor/src/github.com/sergi/go-diff/diffmatchpatch/stringutil.go Datei anzeigen

@@ -0,0 +1,88 @@
1
+// Copyright (c) 2012-2016 The go-diff authors. All rights reserved.
2
+// https://github.com/sergi/go-diff
3
+// See the included LICENSE file for license details.
4
+//
5
+// go-diff is a Go implementation of Google's Diff, Match, and Patch library
6
+// Original library is Copyright (c) 2006 Google Inc.
7
+// http://code.google.com/p/google-diff-match-patch/
8
+
9
+package diffmatchpatch
10
+
11
+import (
12
+	"strings"
13
+	"unicode/utf8"
14
+)
15
+
16
+// unescaper unescapes selected chars for compatibility with JavaScript's encodeURI.
17
+// In speed critical applications this could be dropped since the receiving application will certainly decode these fine. Note that this function is case-sensitive.  Thus "%3F" would not be unescaped.  But this is ok because it is only called with the output of HttpUtility.UrlEncode which returns lowercase hex. Example: "%3f" -> "?", "%24" -> "$", etc.
18
+var unescaper = strings.NewReplacer(
19
+	"%21", "!", "%7E", "~", "%27", "'",
20
+	"%28", "(", "%29", ")", "%3B", ";",
21
+	"%2F", "/", "%3F", "?", "%3A", ":",
22
+	"%40", "@", "%26", "&", "%3D", "=",
23
+	"%2B", "+", "%24", "$", "%2C", ",", "%23", "#", "%2A", "*")
24
+
25
+// indexOf returns the first index of pattern in str, starting at str[i].
26
+func indexOf(str string, pattern string, i int) int {
27
+	if i > len(str)-1 {
28
+		return -1
29
+	}
30
+	if i <= 0 {
31
+		return strings.Index(str, pattern)
32
+	}
33
+	ind := strings.Index(str[i:], pattern)
34
+	if ind == -1 {
35
+		return -1
36
+	}
37
+	return ind + i
38
+}
39
+
40
+// lastIndexOf returns the last index of pattern in str, starting at str[i].
41
+func lastIndexOf(str string, pattern string, i int) int {
42
+	if i < 0 {
43
+		return -1
44
+	}
45
+	if i >= len(str) {
46
+		return strings.LastIndex(str, pattern)
47
+	}
48
+	_, size := utf8.DecodeRuneInString(str[i:])
49
+	return strings.LastIndex(str[:i+size], pattern)
50
+}
51
+
52
+// runesIndexOf returns the index of pattern in target, starting at target[i].
53
+func runesIndexOf(target, pattern []rune, i int) int {
54
+	if i > len(target)-1 {
55
+		return -1
56
+	}
57
+	if i <= 0 {
58
+		return runesIndex(target, pattern)
59
+	}
60
+	ind := runesIndex(target[i:], pattern)
61
+	if ind == -1 {
62
+		return -1
63
+	}
64
+	return ind + i
65
+}
66
+
67
+func runesEqual(r1, r2 []rune) bool {
68
+	if len(r1) != len(r2) {
69
+		return false
70
+	}
71
+	for i, c := range r1 {
72
+		if c != r2[i] {
73
+			return false
74
+		}
75
+	}
76
+	return true
77
+}
78
+
79
+// runesIndex is the equivalent of strings.Index for rune slices.
80
+func runesIndex(r1, r2 []rune) int {
81
+	last := len(r1) - len(r2)
82
+	for i := 0; i <= last; i++ {
83
+		if runesEqual(r1[i:i+len(r2)], r2) {
84
+			return i
85
+		}
86
+	}
87
+	return -1
88
+}

+ 116
- 0
vendor/src/github.com/sergi/go-diff/diffmatchpatch/stringutil_test.go Datei anzeigen

@@ -0,0 +1,116 @@
1
+// Copyright (c) 2012-2016 The go-diff authors. All rights reserved.
2
+// https://github.com/sergi/go-diff
3
+// See the included LICENSE file for license details.
4
+//
5
+// go-diff is a Go implementation of Google's Diff, Match, and Patch library
6
+// Original library is Copyright (c) 2006 Google Inc.
7
+// http://code.google.com/p/google-diff-match-patch/
8
+
9
+package diffmatchpatch
10
+
11
+import (
12
+	"fmt"
13
+	"testing"
14
+
15
+	"github.com/stretchr/testify/assert"
16
+)
17
+
18
+func TestRunesIndexOf(t *testing.T) {
19
+	type TestCase struct {
20
+		Pattern string
21
+		Start   int
22
+
23
+		Expected int
24
+	}
25
+
26
+	for i, tc := range []TestCase{
27
+		{"abc", 0, 0},
28
+		{"cde", 0, 2},
29
+		{"e", 0, 4},
30
+		{"cdef", 0, -1},
31
+		{"abcdef", 0, -1},
32
+		{"abc", 2, -1},
33
+		{"cde", 2, 2},
34
+		{"e", 2, 4},
35
+		{"cdef", 2, -1},
36
+		{"abcdef", 2, -1},
37
+		{"e", 6, -1},
38
+	} {
39
+		actual := runesIndexOf([]rune("abcde"), []rune(tc.Pattern), tc.Start)
40
+		assert.Equal(t, tc.Expected, actual, fmt.Sprintf("Test case #%d, %#v", i, tc))
41
+	}
42
+}
43
+
44
+func TestIndexOf(t *testing.T) {
45
+	type TestCase struct {
46
+		String   string
47
+		Pattern  string
48
+		Position int
49
+
50
+		Expected int
51
+	}
52
+
53
+	for i, tc := range []TestCase{
54
+		{"hi world", "world", -1, 3},
55
+		{"hi world", "world", 0, 3},
56
+		{"hi world", "world", 1, 3},
57
+		{"hi world", "world", 2, 3},
58
+		{"hi world", "world", 3, 3},
59
+		{"hi world", "world", 4, -1},
60
+		{"abbc", "b", -1, 1},
61
+		{"abbc", "b", 0, 1},
62
+		{"abbc", "b", 1, 1},
63
+		{"abbc", "b", 2, 2},
64
+		{"abbc", "b", 3, -1},
65
+		{"abbc", "b", 4, -1},
66
+		// The greek letter beta is the two-byte sequence of "\u03b2".
67
+		{"a\u03b2\u03b2c", "\u03b2", -1, 1},
68
+		{"a\u03b2\u03b2c", "\u03b2", 0, 1},
69
+		{"a\u03b2\u03b2c", "\u03b2", 1, 1},
70
+		{"a\u03b2\u03b2c", "\u03b2", 3, 3},
71
+		{"a\u03b2\u03b2c", "\u03b2", 5, -1},
72
+		{"a\u03b2\u03b2c", "\u03b2", 6, -1},
73
+	} {
74
+		actual := indexOf(tc.String, tc.Pattern, tc.Position)
75
+		assert.Equal(t, tc.Expected, actual, fmt.Sprintf("Test case #%d, %#v", i, tc))
76
+	}
77
+}
78
+
79
+func TestLastIndexOf(t *testing.T) {
80
+	type TestCase struct {
81
+		String   string
82
+		Pattern  string
83
+		Position int
84
+
85
+		Expected int
86
+	}
87
+
88
+	for i, tc := range []TestCase{
89
+		{"hi world", "world", -1, -1},
90
+		{"hi world", "world", 0, -1},
91
+		{"hi world", "world", 1, -1},
92
+		{"hi world", "world", 2, -1},
93
+		{"hi world", "world", 3, -1},
94
+		{"hi world", "world", 4, -1},
95
+		{"hi world", "world", 5, -1},
96
+		{"hi world", "world", 6, -1},
97
+		{"hi world", "world", 7, 3},
98
+		{"hi world", "world", 8, 3},
99
+		{"abbc", "b", -1, -1},
100
+		{"abbc", "b", 0, -1},
101
+		{"abbc", "b", 1, 1},
102
+		{"abbc", "b", 2, 2},
103
+		{"abbc", "b", 3, 2},
104
+		{"abbc", "b", 4, 2},
105
+		// The greek letter beta is the two-byte sequence of "\u03b2".
106
+		{"a\u03b2\u03b2c", "\u03b2", -1, -1},
107
+		{"a\u03b2\u03b2c", "\u03b2", 0, -1},
108
+		{"a\u03b2\u03b2c", "\u03b2", 1, 1},
109
+		{"a\u03b2\u03b2c", "\u03b2", 3, 3},
110
+		{"a\u03b2\u03b2c", "\u03b2", 5, 3},
111
+		{"a\u03b2\u03b2c", "\u03b2", 6, 3},
112
+	} {
113
+		actual := lastIndexOf(tc.String, tc.Pattern, tc.Position)
114
+		assert.Equal(t, tc.Expected, actual, fmt.Sprintf("Test case #%d, %#v", i, tc))
115
+	}
116
+}

+ 28
- 0
vendor/src/github.com/src-d/gcfg/LICENSE Datei anzeigen

@@ -0,0 +1,28 @@
1
+Copyright (c) 2012 Péter Surányi. Portions Copyright (c) 2009 The Go
2
+Authors. All rights reserved.
3
+
4
+Redistribution and use in source and binary forms, with or without
5
+modification, are permitted provided that the following conditions are
6
+met:
7
+
8
+   * Redistributions of source code must retain the above copyright
9
+notice, this list of conditions and the following disclaimer.
10
+   * Redistributions in binary form must reproduce the above
11
+copyright notice, this list of conditions and the following disclaimer
12
+in the documentation and/or other materials provided with the
13
+distribution.
14
+   * Neither the name of Google Inc. nor the names of its
15
+contributors may be used to endorse or promote products derived from
16
+this software without specific prior written permission.
17
+
18
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 4
- 0
vendor/src/github.com/src-d/gcfg/README Datei anzeigen

@@ -0,0 +1,4 @@
1
+Gcfg reads INI-style configuration files into Go structs;
2
+supports user-defined types and subsections.
3
+
4
+Package docs: https://godoc.org/gopkg.in/gcfg.v1

+ 145
- 0
vendor/src/github.com/src-d/gcfg/doc.go Datei anzeigen

@@ -0,0 +1,145 @@
1
+// Package gcfg reads "INI-style" text-based configuration files with
2
+// "name=value" pairs grouped into sections (gcfg files).
3
+//
4
+// This package is still a work in progress; see the sections below for planned
5
+// changes.
6
+//
7
+// Syntax
8
+//
9
+// The syntax is based on that used by git config:
10
+// http://git-scm.com/docs/git-config#_syntax .
11
+// There are some (planned) differences compared to the git config format:
12
+//  - improve data portability:
13
+//    - must be encoded in UTF-8 (for now) and must not contain the 0 byte
14
+//    - include and "path" type is not supported
15
+//      (path type may be implementable as a user-defined type)
16
+//  - internationalization
17
+//    - section and variable names can contain unicode letters, unicode digits
18
+//      (as defined in http://golang.org/ref/spec#Characters ) and hyphens
19
+//      (U+002D), starting with a unicode letter
20
+//  - disallow potentially ambiguous or misleading definitions:
21
+//    - `[sec.sub]` format is not allowed (deprecated in gitconfig)
22
+//    - `[sec ""]` is not allowed
23
+//      - use `[sec]` for section name "sec" and empty subsection name
24
+//    - (planned) within a single file, definitions must be contiguous for each:
25
+//      - section: '[secA]' -> '[secB]' -> '[secA]' is an error
26
+//      - subsection: '[sec "A"]' -> '[sec "B"]' -> '[sec "A"]' is an error
27
+//      - multivalued variable: 'multi=a' -> 'other=x' -> 'multi=b' is an error
28
+//
29
+// Data structure
30
+//
31
+// The functions in this package read values into a user-defined struct.
32
+// Each section corresponds to a struct field in the config struct, and each
33
+// variable in a section corresponds to a data field in the section struct.
34
+// The mapping of each section or variable name to fields is done either based
35
+// on the "gcfg" struct tag or by matching the name of the section or variable,
36
+// ignoring case. In the latter case, hyphens '-' in section and variable names
37
+// correspond to underscores '_' in field names.
38
+// Fields must be exported; to use a section or variable name starting with a
39
+// letter that is neither upper- or lower-case, prefix the field name with 'X'.
40
+// (See https://code.google.com/p/go/issues/detail?id=5763#c4 .)
41
+//
42
+// For sections with subsections, the corresponding field in config must be a
43
+// map, rather than a struct, with string keys and pointer-to-struct values.
44
+// Values for subsection variables are stored in the map with the subsection
45
+// name used as the map key.
46
+// (Note that unlike section and variable names, subsection names are case
47
+// sensitive.)
48
+// When using a map, and there is a section with the same section name but
49
+// without a subsection name, its values are stored with the empty string used
50
+// as the key.
51
+// It is possible to provide default values for subsections in the section
52
+// "default-<sectionname>" (or by setting values in the corresponding struct
53
+// field "Default_<sectionname>").
54
+//
55
+// The functions in this package panic if config is not a pointer to a struct,
56
+// or when a field is not of a suitable type (either a struct or a map with
57
+// string keys and pointer-to-struct values).
58
+//
59
+// Parsing of values
60
+//
61
+// The section structs in the config struct may contain single-valued or
62
+// multi-valued variables. Variables of unnamed slice type (that is, a type
63
+// starting with `[]`) are treated as multi-value; all others (including named
64
+// slice types) are treated as single-valued variables.
65
+//
66
+// Single-valued variables are handled based on the type as follows.
67
+// Unnamed pointer types (that is, types starting with `*`) are dereferenced,
68
+// and if necessary, a new instance is allocated.
69
+//
70
+// For types implementing the encoding.TextUnmarshaler interface, the
71
+// UnmarshalText method is used to set the value. Implementing this method is
72
+// the recommended way for parsing user-defined types.
73
+//
74
+// For fields of string kind, the value string is assigned to the field, after
75
+// unquoting and unescaping as needed.
76
+// For fields of bool kind, the field is set to true if the value is "true",
77
+// "yes", "on" or "1", and set to false if the value is "false", "no", "off" or
78
+// "0", ignoring case. In addition, single-valued bool fields can be specified
79
+// with a "blank" value (variable name without equals sign and value); in such
80
+// case the value is set to true.
81
+//
82
+// Predefined integer types [u]int(|8|16|32|64) and big.Int are parsed as
83
+// decimal or hexadecimal (if having '0x' prefix). (This is to prevent
84
+// unintuitively handling zero-padded numbers as octal.) Other types having
85
+// [u]int* as the underlying type, such as os.FileMode and uintptr allow
86
+// decimal, hexadecimal, or octal values.
87
+// Parsing mode for integer types can be overridden using the struct tag option
88
+// ",int=mode" where mode is a combination of the 'd', 'h', and 'o' characters
89
+// (each standing for decimal, hexadecimal, and octal, respectively.)
90
+//
91
+// All other types are parsed using fmt.Sscanf with the "%v" verb.
92
+//
93
+// For multi-valued variables, each individual value is parsed as above and
94
+// appended to the slice. If the first value is specified as a "blank" value
95
+// (variable name without equals sign and value), a new slice is allocated;
96
+// that is any values previously set in the slice will be ignored.
97
+//
98
+// The types subpackage for provides helpers for parsing "enum-like" and integer
99
+// types.
100
+//
101
+// Error handling
102
+//
103
+// There are 3 types of errors:
104
+//
105
+//  - programmer errors / panics:
106
+//    - invalid configuration structure
107
+//  - data errors:
108
+//    - fatal errors:
109
+//      - invalid configuration syntax
110
+//    - warnings:
111
+//      - data that doesn't belong to any part of the config structure
112
+//
113
+// Programmer errors trigger panics. These are should be fixed by the programmer
114
+// before releasing code that uses gcfg.
115
+//
116
+// Data errors cause gcfg to return a non-nil error value. This includes the
117
+// case when there are extra unknown key-value definitions in the configuration
118
+// data (extra data).
119
+// However, in some occasions it is desirable to be able to proceed in
120
+// situations when the only data error is that of extra data.
121
+// These errors are handled at a different (warning) priority and can be
122
+// filtered out programmatically. To ignore extra data warnings, wrap the
123
+// gcfg.Read*Into invocation into a call to gcfg.FatalOnly.
124
+//
125
+// TODO
126
+//
127
+// The following is a list of changes under consideration:
128
+//  - documentation
129
+//    - self-contained syntax documentation
130
+//    - more practical examples
131
+//    - move TODOs to issue tracker (eventually)
132
+//  - syntax
133
+//    - reconsider valid escape sequences
134
+//      (gitconfig doesn't support \r in value, \t in subsection name, etc.)
135
+//  - reading / parsing gcfg files
136
+//    - define internal representation structure
137
+//    - support multiple inputs (readers, strings, files)
138
+//    - support declaring encoding (?)
139
+//    - support varying fields sets for subsections (?)
140
+//  - writing gcfg files
141
+//  - error handling
142
+//    - make error context accessible programmatically?
143
+//    - limit input size?
144
+//
145
+package gcfg // import "github.com/src-d/gcfg"

+ 41
- 0
vendor/src/github.com/src-d/gcfg/errors.go Datei anzeigen

@@ -0,0 +1,41 @@
1
+package gcfg
2
+
3
+import (
4
+	"gopkg.in/warnings.v0"
5
+)
6
+
7
+// FatalOnly filters the results of a Read*Into invocation and returns only
8
+// fatal errors. That is, errors (warnings) indicating data for unknown
9
+// sections / variables is ignored. Example invocation:
10
+//
11
+//  err := gcfg.FatalOnly(gcfg.ReadFileInto(&cfg, configFile))
12
+//  if err != nil {
13
+//      ...
14
+//
15
+func FatalOnly(err error) error {
16
+	return warnings.FatalOnly(err)
17
+}
18
+
19
+func isFatal(err error) bool {
20
+	_, ok := err.(extraData)
21
+	return !ok
22
+}
23
+
24
+type extraData struct {
25
+	section    string
26
+	subsection *string
27
+	variable   *string
28
+}
29
+
30
+func (e extraData) Error() string {
31
+	s := "can't store data at section \"" + e.section + "\""
32
+	if e.subsection != nil {
33
+		s += ", subsection \"" + *e.subsection + "\""
34
+	}
35
+	if e.variable != nil {
36
+		s += ", variable \"" + *e.variable + "\""
37
+	}
38
+	return s
39
+}
40
+
41
+var _ error = extraData{}

+ 132
- 0
vendor/src/github.com/src-d/gcfg/example_test.go Datei anzeigen

@@ -0,0 +1,132 @@
1
+package gcfg_test
2
+
3
+import (
4
+	"fmt"
5
+	"log"
6
+)
7
+
8
+import "github.com/src-d/gcfg"
9
+
10
+func ExampleReadStringInto() {
11
+	cfgStr := `; Comment line
12
+[section]
13
+name=value # comment`
14
+	cfg := struct {
15
+		Section struct {
16
+			Name string
17
+		}
18
+	}{}
19
+	err := gcfg.ReadStringInto(&cfg, cfgStr)
20
+	if err != nil {
21
+		log.Fatalf("Failed to parse gcfg data: %s", err)
22
+	}
23
+	fmt.Println(cfg.Section.Name)
24
+	// Output: value
25
+}
26
+
27
+func ExampleReadStringInto_bool() {
28
+	cfgStr := `; Comment line
29
+[section]
30
+switch=on`
31
+	cfg := struct {
32
+		Section struct {
33
+			Switch bool
34
+		}
35
+	}{}
36
+	err := gcfg.ReadStringInto(&cfg, cfgStr)
37
+	if err != nil {
38
+		log.Fatalf("Failed to parse gcfg data: %s", err)
39
+	}
40
+	fmt.Println(cfg.Section.Switch)
41
+	// Output: true
42
+}
43
+
44
+func ExampleReadStringInto_hyphens() {
45
+	cfgStr := `; Comment line
46
+[section-name]
47
+variable-name=value # comment`
48
+	cfg := struct {
49
+		Section_Name struct {
50
+			Variable_Name string
51
+		}
52
+	}{}
53
+	err := gcfg.ReadStringInto(&cfg, cfgStr)
54
+	if err != nil {
55
+		log.Fatalf("Failed to parse gcfg data: %s", err)
56
+	}
57
+	fmt.Println(cfg.Section_Name.Variable_Name)
58
+	// Output: value
59
+}
60
+
61
+func ExampleReadStringInto_tags() {
62
+	cfgStr := `; Comment line
63
+[section]
64
+var-name=value # comment`
65
+	cfg := struct {
66
+		Section struct {
67
+			FieldName string `gcfg:"var-name"`
68
+		}
69
+	}{}
70
+	err := gcfg.ReadStringInto(&cfg, cfgStr)
71
+	if err != nil {
72
+		log.Fatalf("Failed to parse gcfg data: %s", err)
73
+	}
74
+	fmt.Println(cfg.Section.FieldName)
75
+	// Output: value
76
+}
77
+
78
+func ExampleReadStringInto_subsections() {
79
+	cfgStr := `; Comment line
80
+[profile "A"]
81
+color = white
82
+
83
+[profile "B"]
84
+color = black
85
+`
86
+	cfg := struct {
87
+		Profile map[string]*struct {
88
+			Color string
89
+		}
90
+	}{}
91
+	err := gcfg.ReadStringInto(&cfg, cfgStr)
92
+	if err != nil {
93
+		log.Fatalf("Failed to parse gcfg data: %s", err)
94
+	}
95
+	fmt.Printf("%s %s\n", cfg.Profile["A"].Color, cfg.Profile["B"].Color)
96
+	// Output: white black
97
+}
98
+
99
+func ExampleReadStringInto_multivalue() {
100
+	cfgStr := `; Comment line
101
+[section]
102
+multi=value1
103
+multi=value2`
104
+	cfg := struct {
105
+		Section struct {
106
+			Multi []string
107
+		}
108
+	}{}
109
+	err := gcfg.ReadStringInto(&cfg, cfgStr)
110
+	if err != nil {
111
+		log.Fatalf("Failed to parse gcfg data: %s", err)
112
+	}
113
+	fmt.Println(cfg.Section.Multi)
114
+	// Output: [value1 value2]
115
+}
116
+
117
+func ExampleReadStringInto_unicode() {
118
+	cfgStr := `; Comment line
119
+[甲]
120
+乙=丙 # comment`
121
+	cfg := struct {
122
+		X甲 struct {
123
+			X乙 string
124
+		}
125
+	}{}
126
+	err := gcfg.ReadStringInto(&cfg, cfgStr)
127
+	if err != nil {
128
+		log.Fatalf("Failed to parse gcfg data: %s", err)
129
+	}
130
+	fmt.Println(cfg.X甲.X乙)
131
+	// Output: 丙
132
+}

+ 7
- 0
vendor/src/github.com/src-d/gcfg/go1_0.go Datei anzeigen

@@ -0,0 +1,7 @@
1
+// +build !go1.2
2
+
3
+package gcfg
4
+
5
+type textUnmarshaler interface {
6
+	UnmarshalText(text []byte) error
7
+}

+ 9
- 0
vendor/src/github.com/src-d/gcfg/go1_2.go Datei anzeigen

@@ -0,0 +1,9 @@
1
+// +build go1.2
2
+
3
+package gcfg
4
+
5
+import (
6
+	"encoding"
7
+)
8
+
9
+type textUnmarshaler encoding.TextUnmarshaler

+ 63
- 0
vendor/src/github.com/src-d/gcfg/issues_test.go Datei anzeigen

@@ -0,0 +1,63 @@
1
+package gcfg
2
+
3
+import (
4
+	"fmt"
5
+	"math/big"
6
+	"strings"
7
+	"testing"
8
+)
9
+
10
+type Config1 struct {
11
+	Section struct {
12
+		Int    int
13
+		BigInt big.Int
14
+	}
15
+}
16
+
17
+var testsIssue1 = []struct {
18
+	cfg      string
19
+	typename string
20
+}{
21
+	{"[section]\nint=X", "int"},
22
+	{"[section]\nint=", "int"},
23
+	{"[section]\nint=1A", "int"},
24
+	{"[section]\nbigint=X", "big.Int"},
25
+	{"[section]\nbigint=", "big.Int"},
26
+	{"[section]\nbigint=1A", "big.Int"},
27
+}
28
+
29
+// Value parse error should:
30
+//  - include plain type name
31
+//  - not include reflect internals
32
+func TestIssue1(t *testing.T) {
33
+	for i, tt := range testsIssue1 {
34
+		var c Config1
35
+		err := ReadStringInto(&c, tt.cfg)
36
+		switch {
37
+		case err == nil:
38
+			t.Errorf("%d fail: got ok; wanted error", i)
39
+		case !strings.Contains(err.Error(), tt.typename):
40
+			t.Errorf("%d fail: error message doesn't contain type name %q: %v",
41
+				i, tt.typename, err)
42
+		case strings.Contains(err.Error(), "reflect"):
43
+			t.Errorf("%d fail: error message includes reflect internals: %v",
44
+				i, err)
45
+		default:
46
+			t.Logf("%d pass: %v", i, err)
47
+		}
48
+	}
49
+}
50
+
51
+type confIssue2 struct{ Main struct{ Foo string } }
52
+
53
+var testsIssue2 = []readtest{
54
+	{"[main]\n;\nfoo = bar\n", &confIssue2{struct{ Foo string }{"bar"}}, true},
55
+	{"[main]\r\n;\r\nfoo = bar\r\n", &confIssue2{struct{ Foo string }{"bar"}}, true},
56
+}
57
+
58
+func TestIssue2(t *testing.T) {
59
+	for i, tt := range testsIssue2 {
60
+		id := fmt.Sprintf("issue2:%d", i)
61
+		testRead(t, id, tt)
62
+	}
63
+}

+ 273
- 0
vendor/src/github.com/src-d/gcfg/read.go Datei anzeigen

@@ -0,0 +1,273 @@
1
+package gcfg
2
+
3
+import (
4
+	"fmt"
5
+	"io"
6
+	"io/ioutil"
7
+	"os"
8
+	"strings"
9
+
10
+	"github.com/src-d/gcfg/scanner"
11
+	"github.com/src-d/gcfg/token"
12
+	"gopkg.in/warnings.v0"
13
+)
14
+
15
+var unescape = map[rune]rune{'\\': '\\', '"': '"', 'n': '\n', 't': '\t'}
16
+
17
+// no error: invalid literals should be caught by scanner
18
+func unquote(s string) string {
19
+	u, q, esc := make([]rune, 0, len(s)), false, false
20
+	for _, c := range s {
21
+		if esc {
22
+			uc, ok := unescape[c]
23
+			switch {
24
+			case ok:
25
+				u = append(u, uc)
26
+				fallthrough
27
+			case !q && c == '\n':
28
+				esc = false
29
+				continue
30
+			}
31
+			panic("invalid escape sequence")
32
+		}
33
+		switch c {
34
+		case '"':
35
+			q = !q
36
+		case '\\':
37
+			esc = true
38
+		default:
39
+			u = append(u, c)
40
+		}
41
+	}
42
+	if q {
43
+		panic("missing end quote")
44
+	}
45
+	if esc {
46
+		panic("invalid escape sequence")
47
+	}
48
+	return string(u)
49
+}
50
+
51
+func read(c *warnings.Collector, callback func(string,string,string,string,bool)error,
52
+	fset *token.FileSet, file *token.File, src []byte) error {
53
+	//
54
+	var s scanner.Scanner
55
+	var errs scanner.ErrorList
56
+	s.Init(file, src, func(p token.Position, m string) { errs.Add(p, m) }, 0)
57
+	sect, sectsub := "", ""
58
+	pos, tok, lit := s.Scan()
59
+	errfn := func(msg string) error {
60
+		return fmt.Errorf("%s: %s", fset.Position(pos), msg)
61
+	}
62
+	for {
63
+		if errs.Len() > 0 {
64
+			if err := c.Collect(errs.Err()); err != nil {
65
+				return err
66
+			}
67
+		}
68
+		switch tok {
69
+		case token.EOF:
70
+			return nil
71
+		case token.EOL, token.COMMENT:
72
+			pos, tok, lit = s.Scan()
73
+		case token.LBRACK:
74
+			pos, tok, lit = s.Scan()
75
+			if errs.Len() > 0 {
76
+				if err := c.Collect(errs.Err()); err != nil {
77
+					return err
78
+				}
79
+			}
80
+			if tok != token.IDENT {
81
+				if err := c.Collect(errfn("expected section name")); err != nil {
82
+					return err
83
+				}
84
+			}
85
+			sect, sectsub = lit, ""
86
+			pos, tok, lit = s.Scan()
87
+			if errs.Len() > 0 {
88
+				if err := c.Collect(errs.Err()); err != nil {
89
+					return err
90
+				}
91
+			}
92
+			if tok == token.STRING {
93
+				sectsub = unquote(lit)
94
+				if sectsub == "" {
95
+					if err := c.Collect(errfn("empty subsection name")); err != nil {
96
+						return err
97
+					}
98
+				}
99
+				pos, tok, lit = s.Scan()
100
+				if errs.Len() > 0 {
101
+					if err := c.Collect(errs.Err()); err != nil {
102
+						return err
103
+					}
104
+				}
105
+			}
106
+			if tok != token.RBRACK {
107
+				if sectsub == "" {
108
+					if err := c.Collect(errfn("expected subsection name or right bracket")); err != nil {
109
+						return err
110
+					}
111
+				}
112
+				if err := c.Collect(errfn("expected right bracket")); err != nil {
113
+					return err
114
+				}
115
+			}
116
+			pos, tok, lit = s.Scan()
117
+			if tok != token.EOL && tok != token.EOF && tok != token.COMMENT {
118
+				if err := c.Collect(errfn("expected EOL, EOF, or comment")); err != nil {
119
+					return err
120
+				}
121
+			}
122
+			// If a section/subsection header was found, ensure a
123
+			// container object is created, even if there are no
124
+			// variables further down.
125
+			err := c.Collect(callback(sect, sectsub, "", "", true))
126
+			if err != nil {
127
+				return err
128
+			}
129
+		case token.IDENT:
130
+			if sect == "" {
131
+				if err := c.Collect(errfn("expected section header")); err != nil {
132
+					return err
133
+				}
134
+			}
135
+			n := lit
136
+			pos, tok, lit = s.Scan()
137
+			if errs.Len() > 0 {
138
+				return errs.Err()
139
+			}
140
+			blank, v := tok == token.EOF || tok == token.EOL || tok == token.COMMENT, ""
141
+			if !blank {
142
+				if tok != token.ASSIGN {
143
+					if err := c.Collect(errfn("expected '='")); err != nil {
144
+						return err
145
+					}
146
+				}
147
+				pos, tok, lit = s.Scan()
148
+				if errs.Len() > 0 {
149
+					if err := c.Collect(errs.Err()); err != nil {
150
+						return err
151
+					}
152
+				}
153
+				if tok != token.STRING {
154
+					if err := c.Collect(errfn("expected value")); err != nil {
155
+						return err
156
+					}
157
+				}
158
+				v = unquote(lit)
159
+				pos, tok, lit = s.Scan()
160
+				if errs.Len() > 0 {
161
+					if err := c.Collect(errs.Err()); err != nil {
162
+						return err
163
+					}
164
+				}
165
+				if tok != token.EOL && tok != token.EOF && tok != token.COMMENT {
166
+					if err := c.Collect(errfn("expected EOL, EOF, or comment")); err != nil {
167
+						return err
168
+					}
169
+				}
170
+			}
171
+			err := c.Collect(callback(sect, sectsub, n, v, blank))
172
+			if err != nil {
173
+				return err
174
+			}
175
+		default:
176
+			if sect == "" {
177
+				if err := c.Collect(errfn("expected section header")); err != nil {
178
+					return err
179
+				}
180
+			}
181
+			if err := c.Collect(errfn("expected section header or variable declaration")); err != nil {
182
+				return err
183
+			}
184
+		}
185
+	}
186
+	panic("never reached")
187
+}
188
+
189
+func readInto(config interface{}, fset *token.FileSet, file *token.File,
190
+	src []byte) error {
191
+	//
192
+	c := warnings.NewCollector(isFatal)
193
+	firstPassCallback := func(s string, ss string, k string, v string, bv bool) error {
194
+		return set(c, config, s, ss, k, v, bv, false)
195
+	}
196
+	err := read(c, firstPassCallback, fset, file, src)
197
+	if err != nil {
198
+		return err
199
+	}
200
+	secondPassCallback := func(s string, ss string, k string, v string, bv bool) error {
201
+		return set(c, config, s, ss, k, v, bv, true)
202
+	}
203
+	err = read(c, secondPassCallback, fset, file, src)
204
+	if err != nil {
205
+		return err
206
+	}
207
+	return c.Done()
208
+}
209
+
210
+// ReadWithCallback reads gcfg formatted data from reader and calls
211
+// callback with each section and option found.
212
+//
213
+// Callback is called with section, subsection, option key, option value
214
+// and blank value flag as arguments.
215
+//
216
+// When a section is found, callback is called with nil subsection, option key
217
+// and option value.
218
+//
219
+// When a subsection is found, callback is called with nil option key and
220
+// option value.
221
+//
222
+// If blank value flag is true, it means that the value was not set for an option
223
+// (as opposed to set to empty string).
224
+//
225
+// If callback returns an error, ReadWithCallback terminates with an error too.
226
+func ReadWithCallback(reader io.Reader, callback func(string,string,string,string,bool)error) error {
227
+	src, err := ioutil.ReadAll(reader)
228
+	if err != nil {
229
+		return err
230
+	}
231
+
232
+	fset := token.NewFileSet()
233
+	file := fset.AddFile("", fset.Base(), len(src))
234
+	c := warnings.NewCollector(isFatal)
235
+
236
+	return read(c, callback, fset, file, src)
237
+}
238
+
239
+// ReadInto reads gcfg formatted data from reader and sets the values into the
240
+// corresponding fields in config.
241
+func ReadInto(config interface{}, reader io.Reader) error {
242
+	src, err := ioutil.ReadAll(reader)
243
+	if err != nil {
244
+		return err
245
+	}
246
+	fset := token.NewFileSet()
247
+	file := fset.AddFile("", fset.Base(), len(src))
248
+	return readInto(config, fset, file, src)
249
+}
250
+
251
+// ReadStringInto reads gcfg formatted data from str and sets the values into
252
+// the corresponding fields in config.
253
+func ReadStringInto(config interface{}, str string) error {
254
+	r := strings.NewReader(str)
255
+	return ReadInto(config, r)
256
+}
257
+
258
+// ReadFileInto reads gcfg formatted data from the file filename and sets the
259
+// values into the corresponding fields in config.
260
+func ReadFileInto(config interface{}, filename string) error {
261
+	f, err := os.Open(filename)
262
+	if err != nil {
263
+		return err
264
+	}
265
+	defer f.Close()
266
+	src, err := ioutil.ReadAll(f)
267
+	if err != nil {
268
+		return err
269
+	}
270
+	fset := token.NewFileSet()
271
+	file := fset.AddFile(filename, fset.Base(), len(src))
272
+	return readInto(config, fset, file, src)
273
+}

+ 474
- 0
vendor/src/github.com/src-d/gcfg/read_test.go Datei anzeigen

@@ -0,0 +1,474 @@
1
+package gcfg
2
+
3
+import (
4
+	"fmt"
5
+	"math/big"
6
+	"os"
7
+	"reflect"
8
+	"testing"
9
+	"bytes"
10
+	"strconv"
11
+	"github.com/pkg/errors"
12
+)
13
+
14
+const (
15
+	// 64 spaces
16
+	sp64 = "                                                                "
17
+	// 512 spaces
18
+	sp512 = sp64 + sp64 + sp64 + sp64 + sp64 + sp64 + sp64 + sp64
19
+	// 4096 spaces
20
+	sp4096 = sp512 + sp512 + sp512 + sp512 + sp512 + sp512 + sp512 + sp512
21
+)
22
+
23
+type cBasic struct {
24
+	Section           cBasicS1
25
+	Hyphen_In_Section cBasicS2
26
+	unexported        cBasicS1
27
+	Exported          cBasicS3
28
+	TagName           cBasicS1 `gcfg:"tag-name"`
29
+}
30
+type cBasicS1 struct {
31
+	Name  string
32
+	Int   int
33
+	PName *string
34
+}
35
+type cBasicS2 struct {
36
+	Hyphen_In_Name string
37
+}
38
+type cBasicS3 struct {
39
+	unexported string
40
+}
41
+
42
+type nonMulti []string
43
+
44
+type unmarshalable string
45
+
46
+func (u *unmarshalable) UnmarshalText(text []byte) error {
47
+	s := string(text)
48
+	if s == "error" {
49
+		return fmt.Errorf("%s", s)
50
+	}
51
+	*u = unmarshalable(s)
52
+	return nil
53
+}
54
+
55
+var _ textUnmarshaler = new(unmarshalable)
56
+
57
+type cUni struct {
58
+	X甲       cUniS1
59
+	XSection cUniS2
60
+}
61
+type cUniS1 struct {
62
+	X乙 string
63
+}
64
+type cUniS2 struct {
65
+	XName string
66
+}
67
+
68
+type cMulti struct {
69
+	M1 cMultiS1
70
+	M2 cMultiS2
71
+	M3 cMultiS3
72
+}
73
+type cMultiS1 struct{ Multi []string }
74
+type cMultiS2 struct{ NonMulti nonMulti }
75
+type cMultiS3 struct{ PMulti *[]string }
76
+
77
+type cSubs struct{ Sub map[string]*cSubsS1 }
78
+type cSubsS1 struct{ Name string }
79
+
80
+type cBool struct{ Section cBoolS1 }
81
+type cBoolS1 struct{ Bool bool }
82
+
83
+type cTxUnm struct{ Section cTxUnmS1 }
84
+type cTxUnmS1 struct{ Name unmarshalable }
85
+
86
+type cNum struct {
87
+	N1 cNumS1
88
+	N2 cNumS2
89
+	N3 cNumS3
90
+}
91
+type cNumS1 struct {
92
+	Int    int
93
+	IntDHO int `gcfg:",int=dho"`
94
+	Big    *big.Int
95
+}
96
+type cNumS2 struct {
97
+	MultiInt []int
98
+	MultiBig []*big.Int
99
+}
100
+type cNumS3 struct{ FileMode os.FileMode }
101
+type readtest struct {
102
+	gcfg string
103
+	exp  interface{}
104
+	ok   bool
105
+}
106
+
107
+func newString(s string) *string           { return &s }
108
+func newStringSlice(s ...string) *[]string { return &s }
109
+
110
+var readtests = []struct {
111
+	group string
112
+	tests []readtest
113
+}{{"scanning", []readtest{
114
+	{"[section]\nname=value", &cBasic{Section: cBasicS1{Name: "value"}}, true},
115
+	// hyphen in name
116
+	{"[hyphen-in-section]\nhyphen-in-name=value", &cBasic{Hyphen_In_Section: cBasicS2{Hyphen_In_Name: "value"}}, true},
117
+	// quoted string value
118
+	{"[section]\nname=\"\"", &cBasic{Section: cBasicS1{Name: ""}}, true},
119
+	{"[section]\nname=\" \"", &cBasic{Section: cBasicS1{Name: " "}}, true},
120
+	{"[section]\nname=\"value\"", &cBasic{Section: cBasicS1{Name: "value"}}, true},
121
+	{"[section]\nname=\" value \"", &cBasic{Section: cBasicS1{Name: " value "}}, true},
122
+	{"\n[section]\nname=\"va ; lue\"", &cBasic{Section: cBasicS1{Name: "va ; lue"}}, true},
123
+	{"[section]\nname=\"val\" \"ue\"", &cBasic{Section: cBasicS1{Name: "val ue"}}, true},
124
+	{"[section]\nname=\"value", &cBasic{}, false},
125
+	// escape sequences
126
+	{"[section]\nname=\"va\\\\lue\"", &cBasic{Section: cBasicS1{Name: "va\\lue"}}, true},
127
+	{"[section]\nname=\"va\\\"lue\"", &cBasic{Section: cBasicS1{Name: "va\"lue"}}, true},
128
+	{"[section]\nname=\"va\\nlue\"", &cBasic{Section: cBasicS1{Name: "va\nlue"}}, true},
129
+	{"[section]\nname=\"va\\tlue\"", &cBasic{Section: cBasicS1{Name: "va\tlue"}}, true},
130
+	{"\n[section]\nname=\\", &cBasic{}, false},
131
+	{"\n[section]\nname=\\a", &cBasic{}, false},
132
+	{"\n[section]\nname=\"val\\a\"", &cBasic{}, false},
133
+	{"\n[section]\nname=val\\", &cBasic{}, false},
134
+	{"\n[sub \"A\\\n\"]\nname=value", &cSubs{}, false},
135
+	{"\n[sub \"A\\\t\"]\nname=value", &cSubs{}, false},
136
+	// broken line
137
+	{"[section]\nname=value \\\n value", &cBasic{Section: cBasicS1{Name: "value  value"}}, true},
138
+	{"[section]\nname=\"value \\\n value\"", &cBasic{}, false},
139
+}}, {"scanning:whitespace", []readtest{
140
+	{" \n[section]\nname=value", &cBasic{Section: cBasicS1{Name: "value"}}, true},
141
+	{" [section]\nname=value", &cBasic{Section: cBasicS1{Name: "value"}}, true},
142
+	{"\t[section]\nname=value", &cBasic{Section: cBasicS1{Name: "value"}}, true},
143
+	{"[ section]\nname=value", &cBasic{Section: cBasicS1{Name: "value"}}, true},
144
+	{"[section ]\nname=value", &cBasic{Section: cBasicS1{Name: "value"}}, true},
145
+	{"[section]\n name=value", &cBasic{Section: cBasicS1{Name: "value"}}, true},
146
+	{"[section]\nname =value", &cBasic{Section: cBasicS1{Name: "value"}}, true},
147
+	{"[section]\nname= value", &cBasic{Section: cBasicS1{Name: "value"}}, true},
148
+	{"[section]\nname=value ", &cBasic{Section: cBasicS1{Name: "value"}}, true},
149
+	{"[section]\r\nname=value", &cBasic{Section: cBasicS1{Name: "value"}}, true},
150
+	{"[section]\r\nname=value\r\n", &cBasic{Section: cBasicS1{Name: "value"}}, true},
151
+	{";cmnt\r\n[section]\r\nname=value\r\n", &cBasic{Section: cBasicS1{Name: "value"}}, true},
152
+	// long lines
153
+	{sp4096 + "[section]\nname=value\n", &cBasic{Section: cBasicS1{Name: "value"}}, true},
154
+	{"[" + sp4096 + "section]\nname=value\n", &cBasic{Section: cBasicS1{Name: "value"}}, true},
155
+	{"[section" + sp4096 + "]\nname=value\n", &cBasic{Section: cBasicS1{Name: "value"}}, true},
156
+	{"[section]" + sp4096 + "\nname=value\n", &cBasic{Section: cBasicS1{Name: "value"}}, true},
157
+	{"[section]\n" + sp4096 + "name=value\n", &cBasic{Section: cBasicS1{Name: "value"}}, true},
158
+	{"[section]\nname" + sp4096 + "=value\n", &cBasic{Section: cBasicS1{Name: "value"}}, true},
159
+	{"[section]\nname=" + sp4096 + "value\n", &cBasic{Section: cBasicS1{Name: "value"}}, true},
160
+	{"[section]\nname=value\n" + sp4096, &cBasic{Section: cBasicS1{Name: "value"}}, true},
161
+}}, {"scanning:comments", []readtest{
162
+	{"; cmnt\n[section]\nname=value", &cBasic{Section: cBasicS1{Name: "value"}}, true},
163
+	{"# cmnt\n[section]\nname=value", &cBasic{Section: cBasicS1{Name: "value"}}, true},
164
+	{" ; cmnt\n[section]\nname=value", &cBasic{Section: cBasicS1{Name: "value"}}, true},
165
+	{"\t; cmnt\n[section]\nname=value", &cBasic{Section: cBasicS1{Name: "value"}}, true},
166
+	{"\n[section]; cmnt\nname=value", &cBasic{Section: cBasicS1{Name: "value"}}, true},
167
+	{"\n[section] ; cmnt\nname=value", &cBasic{Section: cBasicS1{Name: "value"}}, true},
168
+	{"\n[section]\nname=value; cmnt", &cBasic{Section: cBasicS1{Name: "value"}}, true},
169
+	{"\n[section]\nname=value ; cmnt", &cBasic{Section: cBasicS1{Name: "value"}}, true},
170
+	{"\n[section]\nname=\"value\" ; cmnt", &cBasic{Section: cBasicS1{Name: "value"}}, true},
171
+	{"\n[section]\nname=value ; \"cmnt", &cBasic{Section: cBasicS1{Name: "value"}}, true},
172
+	{"\n[section]\nname=\"va ; lue\" ; cmnt", &cBasic{Section: cBasicS1{Name: "va ; lue"}}, true},
173
+	{"\n[section]\nname=; cmnt", &cBasic{Section: cBasicS1{Name: ""}}, true},
174
+}}, {"scanning:subsections", []readtest{
175
+	{"\n[sub \"A\"]\nname=value", &cSubs{map[string]*cSubsS1{"A": &cSubsS1{"value"}}}, true},
176
+	{"\n[sub \"b\"]\nname=value", &cSubs{map[string]*cSubsS1{"b": &cSubsS1{"value"}}}, true},
177
+	{"\n[sub \"A\\\\\"]\nname=value", &cSubs{map[string]*cSubsS1{"A\\": &cSubsS1{"value"}}}, true},
178
+	{"\n[sub \"A\\\"\"]\nname=value", &cSubs{map[string]*cSubsS1{"A\"": &cSubsS1{"value"}}}, true},
179
+}}, {"syntax", []readtest{
180
+	// invalid line
181
+	{"\n[section]\n=", &cBasic{}, false},
182
+	// no section
183
+	{"name=value", &cBasic{}, false},
184
+	// empty section
185
+	{"\n[]\nname=value", &cBasic{}, false},
186
+	// empty subsection
187
+	{"\n[sub \"\"]\nname=value", &cSubs{}, false},
188
+}}, {"setting", []readtest{
189
+	{"[section]\nname=value", &cBasic{Section: cBasicS1{Name: "value"}}, true},
190
+	// pointer
191
+	{"[section]", &cBasic{Section: cBasicS1{PName: nil}}, true},
192
+	{"[section]\npname=value", &cBasic{Section: cBasicS1{PName: newString("value")}}, true},
193
+	{"[m3]", &cMulti{M3: cMultiS3{PMulti: nil}}, true},
194
+	{"[m3]\npmulti", &cMulti{M3: cMultiS3{PMulti: newStringSlice()}}, true},
195
+	{"[m3]\npmulti=value", &cMulti{M3: cMultiS3{PMulti: newStringSlice("value")}}, true},
196
+	{"[m3]\npmulti=value1\npmulti=value2", &cMulti{M3: cMultiS3{PMulti: newStringSlice("value1", "value2")}}, true},
197
+	// section name not matched
198
+	{"\n[nonexistent]\nname=value", &cBasic{}, false},
199
+	// subsection name not matched
200
+	{"\n[section \"nonexistent\"]\nname=value", &cBasic{}, false},
201
+	// variable name not matched
202
+	{"\n[section]\nnonexistent=value", &cBasic{}, false},
203
+	// hyphen in name
204
+	{"[hyphen-in-section]\nhyphen-in-name=value", &cBasic{Hyphen_In_Section: cBasicS2{Hyphen_In_Name: "value"}}, true},
205
+	// ignore unexported fields
206
+	{"[unexported]\nname=value", &cBasic{}, false},
207
+	{"[exported]\nunexported=value", &cBasic{}, false},
208
+	// 'X' prefix for non-upper/lower-case letters
209
+	{"[甲]\n乙=丙", &cUni{X甲: cUniS1{X乙: "丙"}}, true},
210
+	//{"[section]\nxname=value", &cBasic{XSection: cBasicS4{XName: "value"}}, false},
211
+	//{"[xsection]\nname=value", &cBasic{XSection: cBasicS4{XName: "value"}}, false},
212
+	// name specified as struct tag
213
+	{"[tag-name]\nname=value", &cBasic{TagName: cBasicS1{Name: "value"}}, true},
214
+	// empty subsections
215
+	{"\n[sub \"A\"]\n[sub \"B\"]", &cSubs{map[string]*cSubsS1{"A": &cSubsS1{}, "B": &cSubsS1{}}}, true},
216
+}}, {"multivalue", []readtest{
217
+	// unnamed slice type: treat as multi-value
218
+	{"\n[m1]", &cMulti{M1: cMultiS1{}}, true},
219
+	{"\n[m1]\nmulti=value", &cMulti{M1: cMultiS1{[]string{"value"}}}, true},
220
+	{"\n[m1]\nmulti=value1\nmulti=value2", &cMulti{M1: cMultiS1{[]string{"value1", "value2"}}}, true},
221
+	// "blank" empties multi-valued slice -- here same result as above
222
+	{"\n[m1]\nmulti\nmulti=value1\nmulti=value2", &cMulti{M1: cMultiS1{[]string{"value1", "value2"}}}, true},
223
+	// named slice type: do not treat as multi-value
224
+	{"\n[m2]", &cMulti{}, true},
225
+	{"\n[m2]\nmulti=value", &cMulti{}, false},
226
+	{"\n[m2]\nmulti=value1\nmulti=value2", &cMulti{}, false},
227
+}}, {"type:string", []readtest{
228
+	{"[section]\nname=value", &cBasic{Section: cBasicS1{Name: "value"}}, true},
229
+	{"[section]\nname=", &cBasic{Section: cBasicS1{Name: ""}}, true},
230
+}}, {"type:bool", []readtest{
231
+	// explicit values
232
+	{"[section]\nbool=true", &cBool{cBoolS1{true}}, true},
233
+	{"[section]\nbool=yes", &cBool{cBoolS1{true}}, true},
234
+	{"[section]\nbool=on", &cBool{cBoolS1{true}}, true},
235
+	{"[section]\nbool=1", &cBool{cBoolS1{true}}, true},
236
+	{"[section]\nbool=tRuE", &cBool{cBoolS1{true}}, true},
237
+	{"[section]\nbool=false", &cBool{cBoolS1{false}}, true},
238
+	{"[section]\nbool=no", &cBool{cBoolS1{false}}, true},
239
+	{"[section]\nbool=off", &cBool{cBoolS1{false}}, true},
240
+	{"[section]\nbool=0", &cBool{cBoolS1{false}}, true},
241
+	{"[section]\nbool=NO", &cBool{cBoolS1{false}}, true},
242
+	// "blank" value handled as true
243
+	{"[section]\nbool", &cBool{cBoolS1{true}}, true},
244
+	// bool parse errors
245
+	{"[section]\nbool=maybe", &cBool{}, false},
246
+	{"[section]\nbool=t", &cBool{}, false},
247
+	{"[section]\nbool=truer", &cBool{}, false},
248
+	{"[section]\nbool=2", &cBool{}, false},
249
+	{"[section]\nbool=-1", &cBool{}, false},
250
+}}, {"type:numeric", []readtest{
251
+	{"[section]\nint=0", &cBasic{Section: cBasicS1{Int: 0}}, true},
252
+	{"[section]\nint=1", &cBasic{Section: cBasicS1{Int: 1}}, true},
253
+	{"[section]\nint=-1", &cBasic{Section: cBasicS1{Int: -1}}, true},
254
+	{"[section]\nint=0.2", &cBasic{}, false},
255
+	{"[section]\nint=1e3", &cBasic{}, false},
256
+	// primitive [u]int(|8|16|32|64) and big.Int is parsed as dec or hex (not octal)
257
+	{"[n1]\nint=010", &cNum{N1: cNumS1{Int: 10}}, true},
258
+	{"[n1]\nint=0x10", &cNum{N1: cNumS1{Int: 0x10}}, true},
259
+	{"[n1]\nbig=1", &cNum{N1: cNumS1{Big: big.NewInt(1)}}, true},
260
+	{"[n1]\nbig=0x10", &cNum{N1: cNumS1{Big: big.NewInt(0x10)}}, true},
261
+	{"[n1]\nbig=010", &cNum{N1: cNumS1{Big: big.NewInt(10)}}, true},
262
+	{"[n2]\nmultiint=010", &cNum{N2: cNumS2{MultiInt: []int{10}}}, true},
263
+	{"[n2]\nmultibig=010", &cNum{N2: cNumS2{MultiBig: []*big.Int{big.NewInt(10)}}}, true},
264
+	// set parse mode for int types via struct tag
265
+	{"[n1]\nintdho=010", &cNum{N1: cNumS1{IntDHO: 010}}, true},
266
+	// octal allowed for named type
267
+	{"[n3]\nfilemode=0777", &cNum{N3: cNumS3{FileMode: 0777}}, true},
268
+}}, {"type:textUnmarshaler", []readtest{
269
+	{"[section]\nname=value", &cTxUnm{Section: cTxUnmS1{Name: "value"}}, true},
270
+	{"[section]\nname=error", &cTxUnm{}, false},
271
+}},
272
+}
273
+
274
+func TestReadStringInto(t *testing.T) {
275
+	for _, tg := range readtests {
276
+		for i, tt := range tg.tests {
277
+			id := fmt.Sprintf("%s:%d", tg.group, i)
278
+			testRead(t, id, tt)
279
+		}
280
+	}
281
+}
282
+
283
+func TestReadStringIntoMultiBlankPreset(t *testing.T) {
284
+	tt := readtest{"\n[m1]\nmulti\nmulti=value1\nmulti=value2", &cMulti{M1: cMultiS1{[]string{"value1", "value2"}}}, true}
285
+	cfg := &cMulti{M1: cMultiS1{[]string{"preset1", "preset2"}}}
286
+	testReadInto(t, "multi:blank", tt, cfg)
287
+}
288
+
289
+func testRead(t *testing.T, id string, tt readtest) {
290
+	// get the type of the expected result
291
+	restyp := reflect.TypeOf(tt.exp).Elem()
292
+	// create a new instance to hold the actual result
293
+	res := reflect.New(restyp).Interface()
294
+	testReadInto(t, id, tt, res)
295
+}
296
+
297
+func testReadInto(t *testing.T, id string, tt readtest, res interface{}) {
298
+	err := ReadStringInto(res, tt.gcfg)
299
+	if tt.ok {
300
+		if err != nil {
301
+			t.Errorf("%s fail: got error %v, wanted ok", id, err)
302
+			return
303
+		} else if !reflect.DeepEqual(res, tt.exp) {
304
+			t.Errorf("%s fail: got value %#v, wanted value %#v", id, res, tt.exp)
305
+			return
306
+		}
307
+		if !testing.Short() {
308
+			t.Logf("%s pass: got value %#v", id, res)
309
+		}
310
+	} else { // !tt.ok
311
+		if err == nil {
312
+			t.Errorf("%s fail: got value %#v, wanted error", id, res)
313
+			return
314
+		}
315
+		if !testing.Short() {
316
+			t.Logf("%s pass: got error %v", id, err)
317
+		}
318
+	}
319
+}
320
+
321
+func TestReadFileInto(t *testing.T) {
322
+	res := &struct{ Section struct{ Name string } }{}
323
+	err := ReadFileInto(res, "testdata/gcfg_test.gcfg")
324
+	if err != nil {
325
+		t.Error(err)
326
+	}
327
+	if "value" != res.Section.Name {
328
+		t.Errorf("got %q, wanted %q", res.Section.Name, "value")
329
+	}
330
+}
331
+
332
+func TestReadFileIntoUnicode(t *testing.T) {
333
+	res := &struct{ X甲 struct{ X乙 string } }{}
334
+	err := ReadFileInto(res, "testdata/gcfg_unicode_test.gcfg")
335
+	if err != nil {
336
+		t.Error(err)
337
+	}
338
+	if "丙" != res.X甲.X乙 {
339
+		t.Errorf("got %q, wanted %q", res.X甲.X乙, "丙")
340
+	}
341
+}
342
+
343
+func TestReadStringIntoSubsectDefaults(t *testing.T) {
344
+	type subsect struct {
345
+		Color       string
346
+		Orientation string
347
+	}
348
+	res := &struct {
349
+		Default_Profile subsect
350
+		Profile         map[string]*subsect
351
+	}{Default_Profile: subsect{Color: "green"}}
352
+	cfg := `
353
+	[profile "one"]
354
+	orientation = left`
355
+	err := ReadStringInto(res, cfg)
356
+	if err != nil {
357
+		t.Error(err)
358
+	}
359
+	if res.Profile["one"].Color != "green" {
360
+		t.Errorf("got %q; want %q", res.Profile["one"].Color, "green")
361
+	}
362
+}
363
+
364
+func TestReadStringIntoExtraData(t *testing.T) {
365
+	res := &struct {
366
+		Section struct {
367
+			Name string
368
+		}
369
+	}{}
370
+	cfg := `
371
+	[section]
372
+	name = value
373
+	name2 = value2`
374
+	err := FatalOnly(ReadStringInto(res, cfg))
375
+	if err != nil {
376
+		t.Error(err)
377
+	}
378
+	if res.Section.Name != "value" {
379
+		t.Errorf("res.Section.Name=%q; want %q", res.Section.Name, "value")
380
+	}
381
+}
382
+
383
+func TestReadWithCallback(t *testing.T) {
384
+	results := [][]string{}
385
+	cb := func(s string, ss string, k string, v string, bv bool) error {
386
+		results = append(results, []string{s, ss, k, v, strconv.FormatBool(bv)})
387
+		return nil
388
+	}
389
+	text := `
390
+	[sect1]
391
+	key1=value1
392
+	[sect1 "subsect1"]
393
+	key2=value2
394
+	key3=value3
395
+	key4
396
+	key5=
397
+	[sect1 "subsect2"]
398
+	[sect2]
399
+	`
400
+	expected := [][]string{
401
+		[]string{"sect1", "", "", "", "true"},
402
+		[]string{"sect1", "", "key1", "value1", "false"},
403
+		[]string{"sect1", "subsect1", "", "", "true"},
404
+		[]string{"sect1", "subsect1", "key2", "value2", "false"},
405
+		[]string{"sect1", "subsect1", "key3", "value3", "false"},
406
+		[]string{"sect1", "subsect1", "key4", "", "true"},
407
+		[]string{"sect1", "subsect1", "key5", "", "false"},
408
+		[]string{"sect1", "subsect2", "", "", "true"},
409
+		[]string{"sect2", "", "", "", "true"},
410
+	}
411
+	err := ReadWithCallback(bytes.NewReader([]byte(text)), cb)
412
+	if err != nil {
413
+		t.Error(err)
414
+	}
415
+	if !reflect.DeepEqual(results, expected) {
416
+		t.Errorf("expected %+v, got %+v", expected, results)
417
+	}
418
+
419
+	i := 0
420
+	expectedErr := errors.New("FATAL ERROR")
421
+	results = [][]string{}
422
+	cbWithError := func(s string, ss string, k string, v string, bv bool) error {
423
+		results = append(results, []string{s, ss, k, v, strconv.FormatBool(bv)})
424
+		i += 1
425
+		if i == 3 {
426
+			return expectedErr
427
+		}
428
+		return nil
429
+	}
430
+	err = ReadWithCallback(bytes.NewReader([]byte(text)), cbWithError)
431
+	if err != expectedErr {
432
+		t.Errorf("expected error: %+v", err)
433
+	}
434
+	if !reflect.DeepEqual(results, expected[:3]) {
435
+		t.Errorf("expected %+v, got %+v", expected, results[:3])
436
+	}
437
+}
438
+
439
+func TestReadWithCallback_WithError(t *testing.T) {
440
+	results := [][]string{}
441
+	cb := func(s string, ss string, k string, v string, bv bool) error {
442
+		results = append(results, []string{s, ss, k, v, strconv.FormatBool(bv)})
443
+		return nil
444
+	}
445
+	text := `
446
+	[sect1]
447
+	key1=value1
448
+	[sect1 "subsect1"]
449
+	key2=value2
450
+	key3=value3
451
+	key4
452
+	key5=
453
+	[sect1 "subsect2"]
454
+	[sect2]
455
+	`
456
+	expected := [][]string{
457
+		[]string{"sect1", "", "", "", "true"},
458
+		[]string{"sect1", "", "key1", "value1", "false"},
459
+		[]string{"sect1", "subsect1", "", "", "true"},
460
+		[]string{"sect1", "subsect1", "key2", "value2", "false"},
461
+		[]string{"sect1", "subsect1", "key3", "value3", "false"},
462
+		[]string{"sect1", "subsect1", "key4", "", "true"},
463
+		[]string{"sect1", "subsect1", "key5", "", "false"},
464
+		[]string{"sect1", "subsect2", "", "", "true"},
465
+		[]string{"sect2", "", "", "", "true"},
466
+	}
467
+	err := ReadWithCallback(bytes.NewReader([]byte(text)), cb)
468
+	if err != nil {
469
+		t.Error(err)
470
+	}
471
+	if !reflect.DeepEqual(results, expected) {
472
+		t.Errorf("expected %+v, got %+v", expected, results)
473
+	}
474
+}

+ 121
- 0
vendor/src/github.com/src-d/gcfg/scanner/errors.go Datei anzeigen

@@ -0,0 +1,121 @@
1
+// Copyright 2009 The Go Authors. 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 scanner
6
+
7
+import (
8
+	"fmt"
9
+	"io"
10
+	"sort"
11
+)
12
+
13
+import (
14
+	"github.com/src-d/gcfg/token"
15
+)
16
+
17
+// In an ErrorList, an error is represented by an *Error.
18
+// The position Pos, if valid, points to the beginning of
19
+// the offending token, and the error condition is described
20
+// by Msg.
21
+//
22
+type Error struct {
23
+	Pos token.Position
24
+	Msg string
25
+}
26
+
27
+// Error implements the error interface.
28
+func (e Error) Error() string {
29
+	if e.Pos.Filename != "" || e.Pos.IsValid() {
30
+		// don't print "<unknown position>"
31
+		// TODO(gri) reconsider the semantics of Position.IsValid
32
+		return e.Pos.String() + ": " + e.Msg
33
+	}
34
+	return e.Msg
35
+}
36
+
37
+// ErrorList is a list of *Errors.
38
+// The zero value for an ErrorList is an empty ErrorList ready to use.
39
+//
40
+type ErrorList []*Error
41
+
42
+// Add adds an Error with given position and error message to an ErrorList.
43
+func (p *ErrorList) Add(pos token.Position, msg string) {
44
+	*p = append(*p, &Error{pos, msg})
45
+}
46
+
47
+// Reset resets an ErrorList to no errors.
48
+func (p *ErrorList) Reset() { *p = (*p)[0:0] }
49
+
50
+// ErrorList implements the sort Interface.
51
+func (p ErrorList) Len() int      { return len(p) }
52
+func (p ErrorList) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
53
+
54
+func (p ErrorList) Less(i, j int) bool {
55
+	e := &p[i].Pos
56
+	f := &p[j].Pos
57
+	if e.Filename < f.Filename {
58
+		return true
59
+	}
60
+	if e.Filename == f.Filename {
61
+		return e.Offset < f.Offset
62
+	}
63
+	return false
64
+}
65
+
66
+// Sort sorts an ErrorList. *Error entries are sorted by position,
67
+// other errors are sorted by error message, and before any *Error
68
+// entry.
69
+//
70
+func (p ErrorList) Sort() {
71
+	sort.Sort(p)
72
+}
73
+
74
+// RemoveMultiples sorts an ErrorList and removes all but the first error per line.
75
+func (p *ErrorList) RemoveMultiples() {
76
+	sort.Sort(p)
77
+	var last token.Position // initial last.Line is != any legal error line
78
+	i := 0
79
+	for _, e := range *p {
80
+		if e.Pos.Filename != last.Filename || e.Pos.Line != last.Line {
81
+			last = e.Pos
82
+			(*p)[i] = e
83
+			i++
84
+		}
85
+	}
86
+	(*p) = (*p)[0:i]
87
+}
88
+
89
+// An ErrorList implements the error interface.
90
+func (p ErrorList) Error() string {
91
+	switch len(p) {
92
+	case 0:
93
+		return "no errors"
94
+	case 1:
95
+		return p[0].Error()
96
+	}
97
+	return fmt.Sprintf("%s (and %d more errors)", p[0], len(p)-1)
98
+}
99
+
100
+// Err returns an error equivalent to this error list.
101
+// If the list is empty, Err returns nil.
102
+func (p ErrorList) Err() error {
103
+	if len(p) == 0 {
104
+		return nil
105
+	}
106
+	return p
107
+}
108
+
109
+// PrintError is a utility function that prints a list of errors to w,
110
+// one error per line, if the err parameter is an ErrorList. Otherwise
111
+// it prints the err string.
112
+//
113
+func PrintError(w io.Writer, err error) {
114
+	if list, ok := err.(ErrorList); ok {
115
+		for _, e := range list {
116
+			fmt.Fprintf(w, "%s\n", e)
117
+		}
118
+	} else if err != nil {
119
+		fmt.Fprintf(w, "%s\n", err)
120
+	}
121
+}

+ 46
- 0
vendor/src/github.com/src-d/gcfg/scanner/example_test.go Datei anzeigen

@@ -0,0 +1,46 @@
1
+// Copyright 2012 The Go Authors. 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 scanner_test
6
+
7
+import (
8
+	"fmt"
9
+)
10
+
11
+import (
12
+	"github.com/src-d/gcfg/scanner"
13
+	"github.com/src-d/gcfg/token"
14
+)
15
+
16
+func ExampleScanner_Scan() {
17
+	// src is the input that we want to tokenize.
18
+	src := []byte(`[profile "A"]
19
+color = blue ; Comment`)
20
+
21
+	// Initialize the scanner.
22
+	var s scanner.Scanner
23
+	fset := token.NewFileSet()                      // positions are relative to fset
24
+	file := fset.AddFile("", fset.Base(), len(src)) // register input "file"
25
+	s.Init(file, src, nil /* no error handler */, scanner.ScanComments)
26
+
27
+	// Repeated calls to Scan yield the token sequence found in the input.
28
+	for {
29
+		pos, tok, lit := s.Scan()
30
+		if tok == token.EOF {
31
+			break
32
+		}
33
+		fmt.Printf("%s\t%q\t%q\n", fset.Position(pos), tok, lit)
34
+	}
35
+
36
+	// output:
37
+	// 1:1	"["	""
38
+	// 1:2	"IDENT"	"profile"
39
+	// 1:10	"STRING"	"\"A\""
40
+	// 1:13	"]"	""
41
+	// 1:14	"\n"	""
42
+	// 2:1	"IDENT"	"color"
43
+	// 2:7	"="	""
44
+	// 2:9	"STRING"	"blue"
45
+	// 2:14	"COMMENT"	"; Comment"
46
+}

+ 342
- 0
vendor/src/github.com/src-d/gcfg/scanner/scanner.go Datei anzeigen

@@ -0,0 +1,342 @@
1
+// Copyright 2009 The Go Authors. 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 scanner implements a scanner for gcfg configuration text.
6
+// It takes a []byte as source which can then be tokenized
7
+// through repeated calls to the Scan method.
8
+//
9
+// Note that the API for the scanner package may change to accommodate new
10
+// features or implementation changes in gcfg.
11
+//
12
+package scanner
13
+
14
+import (
15
+	"fmt"
16
+	"path/filepath"
17
+	"unicode"
18
+	"unicode/utf8"
19
+)
20
+
21
+import (
22
+	"github.com/src-d/gcfg/token"
23
+)
24
+
25
+// An ErrorHandler may be provided to Scanner.Init. If a syntax error is
26
+// encountered and a handler was installed, the handler is called with a
27
+// position and an error message. The position points to the beginning of
28
+// the offending token.
29
+//
30
+type ErrorHandler func(pos token.Position, msg string)
31
+
32
+// A Scanner holds the scanner's internal state while processing
33
+// a given text.  It can be allocated as part of another data
34
+// structure but must be initialized via Init before use.
35
+//
36
+type Scanner struct {
37
+	// immutable state
38
+	file *token.File  // source file handle
39
+	dir  string       // directory portion of file.Name()
40
+	src  []byte       // source
41
+	err  ErrorHandler // error reporting; or nil
42
+	mode Mode         // scanning mode
43
+
44
+	// scanning state
45
+	ch         rune // current character
46
+	offset     int  // character offset
47
+	rdOffset   int  // reading offset (position after current character)
48
+	lineOffset int  // current line offset
49
+	nextVal    bool // next token is expected to be a value
50
+
51
+	// public state - ok to modify
52
+	ErrorCount int // number of errors encountered
53
+}
54
+
55
+// Read the next Unicode char into s.ch.
56
+// s.ch < 0 means end-of-file.
57
+//
58
+func (s *Scanner) next() {
59
+	if s.rdOffset < len(s.src) {
60
+		s.offset = s.rdOffset
61
+		if s.ch == '\n' {
62
+			s.lineOffset = s.offset
63
+			s.file.AddLine(s.offset)
64
+		}
65
+		r, w := rune(s.src[s.rdOffset]), 1
66
+		switch {
67
+		case r == 0:
68
+			s.error(s.offset, "illegal character NUL")
69
+		case r >= 0x80:
70
+			// not ASCII
71
+			r, w = utf8.DecodeRune(s.src[s.rdOffset:])
72
+			if r == utf8.RuneError && w == 1 {
73
+				s.error(s.offset, "illegal UTF-8 encoding")
74
+			}
75
+		}
76
+		s.rdOffset += w
77
+		s.ch = r
78
+	} else {
79
+		s.offset = len(s.src)
80
+		if s.ch == '\n' {
81
+			s.lineOffset = s.offset
82
+			s.file.AddLine(s.offset)
83
+		}
84
+		s.ch = -1 // eof
85
+	}
86
+}
87
+
88
+// A mode value is a set of flags (or 0).
89
+// They control scanner behavior.
90
+//
91
+type Mode uint
92
+
93
+const (
94
+	ScanComments Mode = 1 << iota // return comments as COMMENT tokens
95
+)
96
+
97
+// Init prepares the scanner s to tokenize the text src by setting the
98
+// scanner at the beginning of src. The scanner uses the file set file
99
+// for position information and it adds line information for each line.
100
+// It is ok to re-use the same file when re-scanning the same file as
101
+// line information which is already present is ignored. Init causes a
102
+// panic if the file size does not match the src size.
103
+//
104
+// Calls to Scan will invoke the error handler err if they encounter a
105
+// syntax error and err is not nil. Also, for each error encountered,
106
+// the Scanner field ErrorCount is incremented by one. The mode parameter
107
+// determines how comments are handled.
108
+//
109
+// Note that Init may call err if there is an error in the first character
110
+// of the file.
111
+//
112
+func (s *Scanner) Init(file *token.File, src []byte, err ErrorHandler, mode Mode) {
113
+	// Explicitly initialize all fields since a scanner may be reused.
114
+	if file.Size() != len(src) {
115
+		panic(fmt.Sprintf("file size (%d) does not match src len (%d)", file.Size(), len(src)))
116
+	}
117
+	s.file = file
118
+	s.dir, _ = filepath.Split(file.Name())
119
+	s.src = src
120
+	s.err = err
121
+	s.mode = mode
122
+
123
+	s.ch = ' '
124
+	s.offset = 0
125
+	s.rdOffset = 0
126
+	s.lineOffset = 0
127
+	s.ErrorCount = 0
128
+	s.nextVal = false
129
+
130
+	s.next()
131
+}
132
+
133
+func (s *Scanner) error(offs int, msg string) {
134
+	if s.err != nil {
135
+		s.err(s.file.Position(s.file.Pos(offs)), msg)
136
+	}
137
+	s.ErrorCount++
138
+}
139
+
140
+func (s *Scanner) scanComment() string {
141
+	// initial [;#] already consumed
142
+	offs := s.offset - 1 // position of initial [;#]
143
+
144
+	for s.ch != '\n' && s.ch >= 0 {
145
+		s.next()
146
+	}
147
+	return string(s.src[offs:s.offset])
148
+}
149
+
150
+func isLetter(ch rune) bool {
151
+	return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch >= 0x80 && unicode.IsLetter(ch)
152
+}
153
+
154
+func isDigit(ch rune) bool {
155
+	return '0' <= ch && ch <= '9' || ch >= 0x80 && unicode.IsDigit(ch)
156
+}
157
+
158
+func (s *Scanner) scanIdentifier() string {
159
+	offs := s.offset
160
+	for isLetter(s.ch) || isDigit(s.ch) || s.ch == '-' {
161
+		s.next()
162
+	}
163
+	return string(s.src[offs:s.offset])
164
+}
165
+
166
+func (s *Scanner) scanEscape(val bool) {
167
+	offs := s.offset
168
+	ch := s.ch
169
+	s.next() // always make progress
170
+	switch ch {
171
+	case '\\', '"':
172
+		// ok
173
+	case 'n', 't':
174
+		if val {
175
+			break // ok
176
+		}
177
+		fallthrough
178
+	default:
179
+		s.error(offs, "unknown escape sequence")
180
+	}
181
+}
182
+
183
+func (s *Scanner) scanString() string {
184
+	// '"' opening already consumed
185
+	offs := s.offset - 1
186
+
187
+	for s.ch != '"' {
188
+		ch := s.ch
189
+		s.next()
190
+		if ch == '\n' || ch < 0 {
191
+			s.error(offs, "string not terminated")
192
+			break
193
+		}
194
+		if ch == '\\' {
195
+			s.scanEscape(false)
196
+		}
197
+	}
198
+
199
+	s.next()
200
+
201
+	return string(s.src[offs:s.offset])
202
+}
203
+
204
+func stripCR(b []byte) []byte {
205
+	c := make([]byte, len(b))
206
+	i := 0
207
+	for _, ch := range b {
208
+		if ch != '\r' {
209
+			c[i] = ch
210
+			i++
211
+		}
212
+	}
213
+	return c[:i]
214
+}
215
+
216
+func (s *Scanner) scanValString() string {
217
+	offs := s.offset
218
+
219
+	hasCR := false
220
+	end := offs
221
+	inQuote := false
222
+loop:
223
+	for inQuote || s.ch >= 0 && s.ch != '\n' && s.ch != ';' && s.ch != '#' {
224
+		ch := s.ch
225
+		s.next()
226
+		switch {
227
+		case inQuote && ch == '\\':
228
+			s.scanEscape(true)
229
+		case !inQuote && ch == '\\':
230
+			if s.ch == '\r' {
231
+				hasCR = true
232
+				s.next()
233
+			}
234
+			if s.ch != '\n' {
235
+				s.error(offs, "unquoted '\\' must be followed by new line")
236
+				break loop
237
+			}
238
+			s.next()
239
+		case ch == '"':
240
+			inQuote = !inQuote
241
+		case ch == '\r':
242
+			hasCR = true
243
+		case ch < 0 || inQuote && ch == '\n':
244
+			s.error(offs, "string not terminated")
245
+			break loop
246
+		}
247
+		if inQuote || !isWhiteSpace(ch) {
248
+			end = s.offset
249
+		}
250
+	}
251
+
252
+	lit := s.src[offs:end]
253
+	if hasCR {
254
+		lit = stripCR(lit)
255
+	}
256
+
257
+	return string(lit)
258
+}
259
+
260
+func isWhiteSpace(ch rune) bool {
261
+	return ch == ' ' || ch == '\t' || ch == '\r'
262
+}
263
+
264
+func (s *Scanner) skipWhitespace() {
265
+	for isWhiteSpace(s.ch) {
266
+		s.next()
267
+	}
268
+}
269
+
270
+// Scan scans the next token and returns the token position, the token,
271
+// and its literal string if applicable. The source end is indicated by
272
+// token.EOF.
273
+//
274
+// If the returned token is a literal (token.IDENT, token.STRING) or
275
+// token.COMMENT, the literal string has the corresponding value.
276
+//
277
+// If the returned token is token.ILLEGAL, the literal string is the
278
+// offending character.
279
+//
280
+// In all other cases, Scan returns an empty literal string.
281
+//
282
+// For more tolerant parsing, Scan will return a valid token if
283
+// possible even if a syntax error was encountered. Thus, even
284
+// if the resulting token sequence contains no illegal tokens,
285
+// a client may not assume that no error occurred. Instead it
286
+// must check the scanner's ErrorCount or the number of calls
287
+// of the error handler, if there was one installed.
288
+//
289
+// Scan adds line information to the file added to the file
290
+// set with Init. Token positions are relative to that file
291
+// and thus relative to the file set.
292
+//
293
+func (s *Scanner) Scan() (pos token.Pos, tok token.Token, lit string) {
294
+scanAgain:
295
+	s.skipWhitespace()
296
+
297
+	// current token start
298
+	pos = s.file.Pos(s.offset)
299
+
300
+	// determine token value
301
+	switch ch := s.ch; {
302
+	case s.nextVal:
303
+		lit = s.scanValString()
304
+		tok = token.STRING
305
+		s.nextVal = false
306
+	case isLetter(ch):
307
+		lit = s.scanIdentifier()
308
+		tok = token.IDENT
309
+	default:
310
+		s.next() // always make progress
311
+		switch ch {
312
+		case -1:
313
+			tok = token.EOF
314
+		case '\n':
315
+			tok = token.EOL
316
+		case '"':
317
+			tok = token.STRING
318
+			lit = s.scanString()
319
+		case '[':
320
+			tok = token.LBRACK
321
+		case ']':
322
+			tok = token.RBRACK
323
+		case ';', '#':
324
+			// comment
325
+			lit = s.scanComment()
326
+			if s.mode&ScanComments == 0 {
327
+				// skip comment
328
+				goto scanAgain
329
+			}
330
+			tok = token.COMMENT
331
+		case '=':
332
+			tok = token.ASSIGN
333
+			s.nextVal = true
334
+		default:
335
+			s.error(s.file.Offset(pos), fmt.Sprintf("illegal character %#U", ch))
336
+			tok = token.ILLEGAL
337
+			lit = string(ch)
338
+		}
339
+	}
340
+
341
+	return
342
+}

+ 417
- 0
vendor/src/github.com/src-d/gcfg/scanner/scanner_test.go Datei anzeigen

@@ -0,0 +1,417 @@
1
+// Copyright 2009 The Go Authors. 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 scanner
6
+
7
+import (
8
+	"os"
9
+	"strings"
10
+	"testing"
11
+)
12
+
13
+import (
14
+	"github.com/src-d/gcfg/token"
15
+)
16
+
17
+var fset = token.NewFileSet()
18
+
19
+const /* class */ (
20
+	special = iota
21
+	literal
22
+	operator
23
+)
24
+
25
+func tokenclass(tok token.Token) int {
26
+	switch {
27
+	case tok.IsLiteral():
28
+		return literal
29
+	case tok.IsOperator():
30
+		return operator
31
+	}
32
+	return special
33
+}
34
+
35
+type elt struct {
36
+	tok   token.Token
37
+	lit   string
38
+	class int
39
+	pre   string
40
+	suf   string
41
+}
42
+
43
+var tokens = [...]elt{
44
+	// Special tokens
45
+	{token.COMMENT, "; a comment", special, "", "\n"},
46
+	{token.COMMENT, "# a comment", special, "", "\n"},
47
+
48
+	// Operators and delimiters
49
+	{token.ASSIGN, "=", operator, "", "value"},
50
+	{token.LBRACK, "[", operator, "", ""},
51
+	{token.RBRACK, "]", operator, "", ""},
52
+	{token.EOL, "\n", operator, "", ""},
53
+
54
+	// Identifiers
55
+	{token.IDENT, "foobar", literal, "", ""},
56
+	{token.IDENT, "a۰۱۸", literal, "", ""},
57
+	{token.IDENT, "foo६४", literal, "", ""},
58
+	{token.IDENT, "bar9876", literal, "", ""},
59
+	{token.IDENT, "foo-bar", literal, "", ""},
60
+	{token.IDENT, "foo", literal, ";\n", ""},
61
+	// String literals (subsection names)
62
+	{token.STRING, `"foobar"`, literal, "", ""},
63
+	{token.STRING, `"\""`, literal, "", ""},
64
+	// String literals (values)
65
+	{token.STRING, `"\n"`, literal, "=", ""},
66
+	{token.STRING, `"foobar"`, literal, "=", ""},
67
+	{token.STRING, `"foo\nbar"`, literal, "=", ""},
68
+	{token.STRING, `"foo\"bar"`, literal, "=", ""},
69
+	{token.STRING, `"foo\\bar"`, literal, "=", ""},
70
+	{token.STRING, `"foobar"`, literal, "=", ""},
71
+	{token.STRING, `"foobar"`, literal, "= ", ""},
72
+	{token.STRING, `"foobar"`, literal, "=", "\n"},
73
+	{token.STRING, `"foobar"`, literal, "=", ";"},
74
+	{token.STRING, `"foobar"`, literal, "=", " ;"},
75
+	{token.STRING, `"foobar"`, literal, "=", "#"},
76
+	{token.STRING, `"foobar"`, literal, "=", " #"},
77
+	{token.STRING, "foobar", literal, "=", ""},
78
+	{token.STRING, "foobar", literal, "= ", ""},
79
+	{token.STRING, "foobar", literal, "=", " "},
80
+	{token.STRING, `"foo" "bar"`, literal, "=", " "},
81
+	{token.STRING, "foo\\\nbar", literal, "=", ""},
82
+	{token.STRING, "foo\\\r\nbar", literal, "=", ""},
83
+}
84
+
85
+const whitespace = "  \t  \n\n\n" // to separate tokens
86
+
87
+var source = func() []byte {
88
+	var src []byte
89
+	for _, t := range tokens {
90
+		src = append(src, t.pre...)
91
+		src = append(src, t.lit...)
92
+		src = append(src, t.suf...)
93
+		src = append(src, whitespace...)
94
+	}
95
+	return src
96
+}()
97
+
98
+func newlineCount(s string) int {
99
+	n := 0
100
+	for i := 0; i < len(s); i++ {
101
+		if s[i] == '\n' {
102
+			n++
103
+		}
104
+	}
105
+	return n
106
+}
107
+
108
+func checkPos(t *testing.T, lit string, p token.Pos, expected token.Position) {
109
+	pos := fset.Position(p)
110
+	if pos.Filename != expected.Filename {
111
+		t.Errorf("bad filename for %q: got %s, expected %s", lit, pos.Filename, expected.Filename)
112
+	}
113
+	if pos.Offset != expected.Offset {
114
+		t.Errorf("bad position for %q: got %d, expected %d", lit, pos.Offset, expected.Offset)
115
+	}
116
+	if pos.Line != expected.Line {
117
+		t.Errorf("bad line for %q: got %d, expected %d", lit, pos.Line, expected.Line)
118
+	}
119
+	if pos.Column != expected.Column {
120
+		t.Errorf("bad column for %q: got %d, expected %d", lit, pos.Column, expected.Column)
121
+	}
122
+}
123
+
124
+// Verify that calling Scan() provides the correct results.
125
+func TestScan(t *testing.T) {
126
+	// make source
127
+	src_linecount := newlineCount(string(source))
128
+	whitespace_linecount := newlineCount(whitespace)
129
+
130
+	index := 0
131
+
132
+	// error handler
133
+	eh := func(_ token.Position, msg string) {
134
+		t.Errorf("%d: error handler called (msg = %s)", index, msg)
135
+	}
136
+
137
+	// verify scan
138
+	var s Scanner
139
+	s.Init(fset.AddFile("", fset.Base(), len(source)), source, eh, ScanComments)
140
+	// epos is the expected position
141
+	epos := token.Position{
142
+		Filename: "",
143
+		Offset:   0,
144
+		Line:     1,
145
+		Column:   1,
146
+	}
147
+	for {
148
+		pos, tok, lit := s.Scan()
149
+		if lit == "" {
150
+			// no literal value for non-literal tokens
151
+			lit = tok.String()
152
+		}
153
+		e := elt{token.EOF, "", special, "", ""}
154
+		if index < len(tokens) {
155
+			e = tokens[index]
156
+		}
157
+		if tok == token.EOF {
158
+			lit = "<EOF>"
159
+			epos.Line = src_linecount
160
+			epos.Column = 2
161
+		}
162
+		if e.pre != "" && strings.ContainsRune("=;#", rune(e.pre[0])) {
163
+			epos.Column = 1
164
+			checkPos(t, lit, pos, epos)
165
+			var etok token.Token
166
+			if e.pre[0] == '=' {
167
+				etok = token.ASSIGN
168
+			} else {
169
+				etok = token.COMMENT
170
+			}
171
+			if tok != etok {
172
+				t.Errorf("bad token for %q: got %q, expected %q", lit, tok, etok)
173
+			}
174
+			pos, tok, lit = s.Scan()
175
+		}
176
+		epos.Offset += len(e.pre)
177
+		if tok != token.EOF {
178
+			epos.Column = 1 + len(e.pre)
179
+		}
180
+		if e.pre != "" && e.pre[len(e.pre)-1] == '\n' {
181
+			epos.Offset--
182
+			epos.Column--
183
+			checkPos(t, lit, pos, epos)
184
+			if tok != token.EOL {
185
+				t.Errorf("bad token for %q: got %q, expected %q", lit, tok, token.EOL)
186
+			}
187
+			epos.Line++
188
+			epos.Offset++
189
+			epos.Column = 1
190
+			pos, tok, lit = s.Scan()
191
+		}
192
+		checkPos(t, lit, pos, epos)
193
+		if tok != e.tok {
194
+			t.Errorf("bad token for %q: got %q, expected %q", lit, tok, e.tok)
195
+		}
196
+		if e.tok.IsLiteral() {
197
+			// no CRs in value string literals
198
+			elit := e.lit
199
+			if strings.ContainsRune(e.pre, '=') {
200
+				elit = string(stripCR([]byte(elit)))
201
+				epos.Offset += len(e.lit) - len(lit) // correct position
202
+			}
203
+			if lit != elit {
204
+				t.Errorf("bad literal for %q: got %q, expected %q", lit, lit, elit)
205
+			}
206
+		}
207
+		if tokenclass(tok) != e.class {
208
+			t.Errorf("bad class for %q: got %d, expected %d", lit, tokenclass(tok), e.class)
209
+		}
210
+		epos.Offset += len(lit) + len(e.suf) + len(whitespace)
211
+		epos.Line += newlineCount(lit) + newlineCount(e.suf) + whitespace_linecount
212
+		index++
213
+		if tok == token.EOF {
214
+			break
215
+		}
216
+		if e.suf == "value" {
217
+			pos, tok, lit = s.Scan()
218
+			if tok != token.STRING {
219
+				t.Errorf("bad token for %q: got %q, expected %q", lit, tok, token.STRING)
220
+			}
221
+		} else if strings.ContainsRune(e.suf, ';') || strings.ContainsRune(e.suf, '#') {
222
+			pos, tok, lit = s.Scan()
223
+			if tok != token.COMMENT {
224
+				t.Errorf("bad token for %q: got %q, expected %q", lit, tok, token.COMMENT)
225
+			}
226
+		}
227
+		// skip EOLs
228
+		for i := 0; i < whitespace_linecount+newlineCount(e.suf); i++ {
229
+			pos, tok, lit = s.Scan()
230
+			if tok != token.EOL {
231
+				t.Errorf("bad token for %q: got %q, expected %q", lit, tok, token.EOL)
232
+			}
233
+		}
234
+	}
235
+	if s.ErrorCount != 0 {
236
+		t.Errorf("found %d errors", s.ErrorCount)
237
+	}
238
+}
239
+
240
+func TestScanValStringEOF(t *testing.T) {
241
+	var s Scanner
242
+	src := "= value"
243
+	f := fset.AddFile("src", fset.Base(), len(src))
244
+	s.Init(f, []byte(src), nil, 0)
245
+	s.Scan()              // =
246
+	s.Scan()              // value
247
+	_, tok, _ := s.Scan() // EOF
248
+	if tok != token.EOF {
249
+		t.Errorf("bad token: got %s, expected %s", tok, token.EOF)
250
+	}
251
+	if s.ErrorCount > 0 {
252
+		t.Error("scanning error")
253
+	}
254
+}
255
+
256
+// Verify that initializing the same scanner more then once works correctly.
257
+func TestInit(t *testing.T) {
258
+	var s Scanner
259
+
260
+	// 1st init
261
+	src1 := "\nname = value"
262
+	f1 := fset.AddFile("src1", fset.Base(), len(src1))
263
+	s.Init(f1, []byte(src1), nil, 0)
264
+	if f1.Size() != len(src1) {
265
+		t.Errorf("bad file size: got %d, expected %d", f1.Size(), len(src1))
266
+	}
267
+	s.Scan()              // \n
268
+	s.Scan()              // name
269
+	_, tok, _ := s.Scan() // =
270
+	if tok != token.ASSIGN {
271
+		t.Errorf("bad token: got %s, expected %s", tok, token.ASSIGN)
272
+	}
273
+
274
+	// 2nd init
275
+	src2 := "[section]"
276
+	f2 := fset.AddFile("src2", fset.Base(), len(src2))
277
+	s.Init(f2, []byte(src2), nil, 0)
278
+	if f2.Size() != len(src2) {
279
+		t.Errorf("bad file size: got %d, expected %d", f2.Size(), len(src2))
280
+	}
281
+	_, tok, _ = s.Scan() // [
282
+	if tok != token.LBRACK {
283
+		t.Errorf("bad token: got %s, expected %s", tok, token.LBRACK)
284
+	}
285
+
286
+	if s.ErrorCount != 0 {
287
+		t.Errorf("found %d errors", s.ErrorCount)
288
+	}
289
+}
290
+
291
+func TestStdErrorHandler(t *testing.T) {
292
+	const src = "@\n" + // illegal character, cause an error
293
+		"@ @\n" // two errors on the same line
294
+
295
+	var list ErrorList
296
+	eh := func(pos token.Position, msg string) { list.Add(pos, msg) }
297
+
298
+	var s Scanner
299
+	s.Init(fset.AddFile("File1", fset.Base(), len(src)), []byte(src), eh, 0)
300
+	for {
301
+		if _, tok, _ := s.Scan(); tok == token.EOF {
302
+			break
303
+		}
304
+	}
305
+
306
+	if len(list) != s.ErrorCount {
307
+		t.Errorf("found %d errors, expected %d", len(list), s.ErrorCount)
308
+	}
309
+
310
+	if len(list) != 3 {
311
+		t.Errorf("found %d raw errors, expected 3", len(list))
312
+		PrintError(os.Stderr, list)
313
+	}
314
+
315
+	list.Sort()
316
+	if len(list) != 3 {
317
+		t.Errorf("found %d sorted errors, expected 3", len(list))
318
+		PrintError(os.Stderr, list)
319
+	}
320
+
321
+	list.RemoveMultiples()
322
+	if len(list) != 2 {
323
+		t.Errorf("found %d one-per-line errors, expected 2", len(list))
324
+		PrintError(os.Stderr, list)
325
+	}
326
+}
327
+
328
+type errorCollector struct {
329
+	cnt int            // number of errors encountered
330
+	msg string         // last error message encountered
331
+	pos token.Position // last error position encountered
332
+}
333
+
334
+func checkError(t *testing.T, src string, tok token.Token, pos int, err string) {
335
+	var s Scanner
336
+	var h errorCollector
337
+	eh := func(pos token.Position, msg string) {
338
+		h.cnt++
339
+		h.msg = msg
340
+		h.pos = pos
341
+	}
342
+	s.Init(fset.AddFile("", fset.Base(), len(src)), []byte(src), eh, ScanComments)
343
+	if src[0] == '=' {
344
+		_, _, _ = s.Scan()
345
+	}
346
+	_, tok0, _ := s.Scan()
347
+	_, tok1, _ := s.Scan()
348
+	if tok0 != tok {
349
+		t.Errorf("%q: got %s, expected %s", src, tok0, tok)
350
+	}
351
+	if tok1 != token.EOF {
352
+		t.Errorf("%q: got %s, expected EOF", src, tok1)
353
+	}
354
+	cnt := 0
355
+	if err != "" {
356
+		cnt = 1
357
+	}
358
+	if h.cnt != cnt {
359
+		t.Errorf("%q: got cnt %d, expected %d", src, h.cnt, cnt)
360
+	}
361
+	if h.msg != err {
362
+		t.Errorf("%q: got msg %q, expected %q", src, h.msg, err)
363
+	}
364
+	if h.pos.Offset != pos {
365
+		t.Errorf("%q: got offset %d, expected %d", src, h.pos.Offset, pos)
366
+	}
367
+}
368
+
369
+var errors = []struct {
370
+	src string
371
+	tok token.Token
372
+	pos int
373
+	err string
374
+}{
375
+	{"\a", token.ILLEGAL, 0, "illegal character U+0007"},
376
+	{"/", token.ILLEGAL, 0, "illegal character U+002F '/'"},
377
+	{"_", token.ILLEGAL, 0, "illegal character U+005F '_'"},
378
+	{`…`, token.ILLEGAL, 0, "illegal character U+2026 '…'"},
379
+	{`""`, token.STRING, 0, ""},
380
+	{`"`, token.STRING, 0, "string not terminated"},
381
+	{"\"\n", token.STRING, 0, "string not terminated"},
382
+	{`="`, token.STRING, 1, "string not terminated"},
383
+	{"=\"\n", token.STRING, 1, "string not terminated"},
384
+	{"=\\", token.STRING, 1, "unquoted '\\' must be followed by new line"},
385
+	{"=\\\r", token.STRING, 1, "unquoted '\\' must be followed by new line"},
386
+	{`"\z"`, token.STRING, 2, "unknown escape sequence"},
387
+	{`"\a"`, token.STRING, 2, "unknown escape sequence"},
388
+	{`"\b"`, token.STRING, 2, "unknown escape sequence"},
389
+	{`"\f"`, token.STRING, 2, "unknown escape sequence"},
390
+	{`"\r"`, token.STRING, 2, "unknown escape sequence"},
391
+	{`"\t"`, token.STRING, 2, "unknown escape sequence"},
392
+	{`"\v"`, token.STRING, 2, "unknown escape sequence"},
393
+	{`"\0"`, token.STRING, 2, "unknown escape sequence"},
394
+}
395
+
396
+func TestScanErrors(t *testing.T) {
397
+	for _, e := range errors {
398
+		checkError(t, e.src, e.tok, e.pos, e.err)
399
+	}
400
+}
401
+
402
+func BenchmarkScan(b *testing.B) {
403
+	b.StopTimer()
404
+	fset := token.NewFileSet()
405
+	file := fset.AddFile("", fset.Base(), len(source))
406
+	var s Scanner
407
+	b.StartTimer()
408
+	for i := b.N - 1; i >= 0; i-- {
409
+		s.Init(file, source, nil, ScanComments)
410
+		for {
411
+			_, tok, _ := s.Scan()
412
+			if tok == token.EOF {
413
+				break
414
+			}
415
+		}
416
+	}
417
+}

+ 332
- 0
vendor/src/github.com/src-d/gcfg/set.go Datei anzeigen

@@ -0,0 +1,332 @@
1
+package gcfg
2
+
3
+import (
4
+	"bytes"
5
+	"encoding/gob"
6
+	"fmt"
7
+	"math/big"
8
+	"reflect"
9
+	"strings"
10
+	"unicode"
11
+	"unicode/utf8"
12
+
13
+	"github.com/src-d/gcfg/types"
14
+	"gopkg.in/warnings.v0"
15
+)
16
+
17
+type tag struct {
18
+	ident   string
19
+	intMode string
20
+}
21
+
22
+func newTag(ts string) tag {
23
+	t := tag{}
24
+	s := strings.Split(ts, ",")
25
+	t.ident = s[0]
26
+	for _, tse := range s[1:] {
27
+		if strings.HasPrefix(tse, "int=") {
28
+			t.intMode = tse[len("int="):]
29
+		}
30
+	}
31
+	return t
32
+}
33
+
34
+func fieldFold(v reflect.Value, name string) (reflect.Value, tag) {
35
+	var n string
36
+	r0, _ := utf8.DecodeRuneInString(name)
37
+	if unicode.IsLetter(r0) && !unicode.IsLower(r0) && !unicode.IsUpper(r0) {
38
+		n = "X"
39
+	}
40
+	n += strings.Replace(name, "-", "_", -1)
41
+	f, ok := v.Type().FieldByNameFunc(func(fieldName string) bool {
42
+		if !v.FieldByName(fieldName).CanSet() {
43
+			return false
44
+		}
45
+		f, _ := v.Type().FieldByName(fieldName)
46
+		t := newTag(f.Tag.Get("gcfg"))
47
+		if t.ident != "" {
48
+			return strings.EqualFold(t.ident, name)
49
+		}
50
+		return strings.EqualFold(n, fieldName)
51
+	})
52
+	if !ok {
53
+		return reflect.Value{}, tag{}
54
+	}
55
+	return v.FieldByName(f.Name), newTag(f.Tag.Get("gcfg"))
56
+}
57
+
58
+type setter func(destp interface{}, blank bool, val string, t tag) error
59
+
60
+var errUnsupportedType = fmt.Errorf("unsupported type")
61
+var errBlankUnsupported = fmt.Errorf("blank value not supported for type")
62
+
63
+var setters = []setter{
64
+	typeSetter, textUnmarshalerSetter, kindSetter, scanSetter,
65
+}
66
+
67
+func textUnmarshalerSetter(d interface{}, blank bool, val string, t tag) error {
68
+	dtu, ok := d.(textUnmarshaler)
69
+	if !ok {
70
+		return errUnsupportedType
71
+	}
72
+	if blank {
73
+		return errBlankUnsupported
74
+	}
75
+	return dtu.UnmarshalText([]byte(val))
76
+}
77
+
78
+func boolSetter(d interface{}, blank bool, val string, t tag) error {
79
+	if blank {
80
+		reflect.ValueOf(d).Elem().Set(reflect.ValueOf(true))
81
+		return nil
82
+	}
83
+	b, err := types.ParseBool(val)
84
+	if err == nil {
85
+		reflect.ValueOf(d).Elem().Set(reflect.ValueOf(b))
86
+	}
87
+	return err
88
+}
89
+
90
+func intMode(mode string) types.IntMode {
91
+	var m types.IntMode
92
+	if strings.ContainsAny(mode, "dD") {
93
+		m |= types.Dec
94
+	}
95
+	if strings.ContainsAny(mode, "hH") {
96
+		m |= types.Hex
97
+	}
98
+	if strings.ContainsAny(mode, "oO") {
99
+		m |= types.Oct
100
+	}
101
+	return m
102
+}
103
+
104
+var typeModes = map[reflect.Type]types.IntMode{
105
+	reflect.TypeOf(int(0)):    types.Dec | types.Hex,
106
+	reflect.TypeOf(int8(0)):   types.Dec | types.Hex,
107
+	reflect.TypeOf(int16(0)):  types.Dec | types.Hex,
108
+	reflect.TypeOf(int32(0)):  types.Dec | types.Hex,
109
+	reflect.TypeOf(int64(0)):  types.Dec | types.Hex,
110
+	reflect.TypeOf(uint(0)):   types.Dec | types.Hex,
111
+	reflect.TypeOf(uint8(0)):  types.Dec | types.Hex,
112
+	reflect.TypeOf(uint16(0)): types.Dec | types.Hex,
113
+	reflect.TypeOf(uint32(0)): types.Dec | types.Hex,
114
+	reflect.TypeOf(uint64(0)): types.Dec | types.Hex,
115
+	// use default mode (allow dec/hex/oct) for uintptr type
116
+	reflect.TypeOf(big.Int{}): types.Dec | types.Hex,
117
+}
118
+
119
+func intModeDefault(t reflect.Type) types.IntMode {
120
+	m, ok := typeModes[t]
121
+	if !ok {
122
+		m = types.Dec | types.Hex | types.Oct
123
+	}
124
+	return m
125
+}
126
+
127
+func intSetter(d interface{}, blank bool, val string, t tag) error {
128
+	if blank {
129
+		return errBlankUnsupported
130
+	}
131
+	mode := intMode(t.intMode)
132
+	if mode == 0 {
133
+		mode = intModeDefault(reflect.TypeOf(d).Elem())
134
+	}
135
+	return types.ParseInt(d, val, mode)
136
+}
137
+
138
+func stringSetter(d interface{}, blank bool, val string, t tag) error {
139
+	if blank {
140
+		return errBlankUnsupported
141
+	}
142
+	dsp, ok := d.(*string)
143
+	if !ok {
144
+		return errUnsupportedType
145
+	}
146
+	*dsp = val
147
+	return nil
148
+}
149
+
150
+var kindSetters = map[reflect.Kind]setter{
151
+	reflect.String:  stringSetter,
152
+	reflect.Bool:    boolSetter,
153
+	reflect.Int:     intSetter,
154
+	reflect.Int8:    intSetter,
155
+	reflect.Int16:   intSetter,
156
+	reflect.Int32:   intSetter,
157
+	reflect.Int64:   intSetter,
158
+	reflect.Uint:    intSetter,
159
+	reflect.Uint8:   intSetter,
160
+	reflect.Uint16:  intSetter,
161
+	reflect.Uint32:  intSetter,
162
+	reflect.Uint64:  intSetter,
163
+	reflect.Uintptr: intSetter,
164
+}
165
+
166
+var typeSetters = map[reflect.Type]setter{
167
+	reflect.TypeOf(big.Int{}): intSetter,
168
+}
169
+
170
+func typeSetter(d interface{}, blank bool, val string, tt tag) error {
171
+	t := reflect.ValueOf(d).Type().Elem()
172
+	setter, ok := typeSetters[t]
173
+	if !ok {
174
+		return errUnsupportedType
175
+	}
176
+	return setter(d, blank, val, tt)
177
+}
178
+
179
+func kindSetter(d interface{}, blank bool, val string, tt tag) error {
180
+	k := reflect.ValueOf(d).Type().Elem().Kind()
181
+	setter, ok := kindSetters[k]
182
+	if !ok {
183
+		return errUnsupportedType
184
+	}
185
+	return setter(d, blank, val, tt)
186
+}
187
+
188
+func scanSetter(d interface{}, blank bool, val string, tt tag) error {
189
+	if blank {
190
+		return errBlankUnsupported
191
+	}
192
+	return types.ScanFully(d, val, 'v')
193
+}
194
+
195
+func newValue(c *warnings.Collector, sect string, vCfg reflect.Value,
196
+	vType reflect.Type) (reflect.Value, error) {
197
+	//
198
+	pv := reflect.New(vType)
199
+	dfltName := "default-" + sect
200
+	dfltField, _ := fieldFold(vCfg, dfltName)
201
+	var err error
202
+	if dfltField.IsValid() {
203
+		b := bytes.NewBuffer(nil)
204
+		ge := gob.NewEncoder(b)
205
+		if err = c.Collect(ge.EncodeValue(dfltField)); err != nil {
206
+			return pv, err
207
+		}
208
+		gd := gob.NewDecoder(bytes.NewReader(b.Bytes()))
209
+		if err = c.Collect(gd.DecodeValue(pv.Elem())); err != nil {
210
+			return pv, err
211
+		}
212
+	}
213
+	return pv, nil
214
+}
215
+
216
+func set(c *warnings.Collector, cfg interface{}, sect, sub, name string,
217
+	 value string, blankValue bool, subsectPass bool) error {
218
+	//
219
+	vPCfg := reflect.ValueOf(cfg)
220
+	if vPCfg.Kind() != reflect.Ptr || vPCfg.Elem().Kind() != reflect.Struct {
221
+		panic(fmt.Errorf("config must be a pointer to a struct"))
222
+	}
223
+	vCfg := vPCfg.Elem()
224
+	vSect, _ := fieldFold(vCfg, sect)
225
+	if !vSect.IsValid() {
226
+		err := extraData{section: sect}
227
+		return c.Collect(err)
228
+	}
229
+	isSubsect := vSect.Kind() == reflect.Map
230
+	if subsectPass != isSubsect {
231
+		return nil
232
+	}
233
+	if isSubsect {
234
+		vst := vSect.Type()
235
+		if vst.Key().Kind() != reflect.String ||
236
+			vst.Elem().Kind() != reflect.Ptr ||
237
+			vst.Elem().Elem().Kind() != reflect.Struct {
238
+			panic(fmt.Errorf("map field for section must have string keys and "+
239
+				" pointer-to-struct values: section %q", sect))
240
+		}
241
+		if vSect.IsNil() {
242
+			vSect.Set(reflect.MakeMap(vst))
243
+		}
244
+		k := reflect.ValueOf(sub)
245
+		pv := vSect.MapIndex(k)
246
+		if !pv.IsValid() {
247
+			vType := vSect.Type().Elem().Elem()
248
+			var err error
249
+			if pv, err = newValue(c, sect, vCfg, vType); err != nil {
250
+				return err
251
+			}
252
+			vSect.SetMapIndex(k, pv)
253
+		}
254
+		vSect = pv.Elem()
255
+	} else if vSect.Kind() != reflect.Struct {
256
+		panic(fmt.Errorf("field for section must be a map or a struct: "+
257
+			"section %q", sect))
258
+	} else if sub != "" {
259
+		err := extraData{section: sect, subsection: &sub}
260
+		return c.Collect(err)
261
+	}
262
+	// Empty name is a special value, meaning that only the
263
+	// section/subsection object is to be created, with no values set.
264
+	if name == "" {
265
+		return nil
266
+	}
267
+	vVar, t := fieldFold(vSect, name)
268
+	if !vVar.IsValid() {
269
+		var err error
270
+		if isSubsect {
271
+			err = extraData{section: sect, subsection: &sub, variable: &name}
272
+		} else {
273
+			err = extraData{section: sect, variable: &name}
274
+		}
275
+		return c.Collect(err)
276
+	}
277
+	// vVal is either single-valued var, or newly allocated value within multi-valued var
278
+	var vVal reflect.Value
279
+	// multi-value if unnamed slice type
280
+	isMulti := vVar.Type().Name() == "" && vVar.Kind() == reflect.Slice ||
281
+		vVar.Type().Name() == "" && vVar.Kind() == reflect.Ptr && vVar.Type().Elem().Name() == "" && vVar.Type().Elem().Kind() == reflect.Slice
282
+	if isMulti && vVar.Kind() == reflect.Ptr {
283
+		if vVar.IsNil() {
284
+			vVar.Set(reflect.New(vVar.Type().Elem()))
285
+		}
286
+		vVar = vVar.Elem()
287
+	}
288
+	if isMulti && blankValue {
289
+		vVar.Set(reflect.Zero(vVar.Type()))
290
+		return nil
291
+	}
292
+	if isMulti {
293
+		vVal = reflect.New(vVar.Type().Elem()).Elem()
294
+	} else {
295
+		vVal = vVar
296
+	}
297
+	isDeref := vVal.Type().Name() == "" && vVal.Type().Kind() == reflect.Ptr
298
+	isNew := isDeref && vVal.IsNil()
299
+	// vAddr is address of value to set (dereferenced & allocated as needed)
300
+	var vAddr reflect.Value
301
+	switch {
302
+	case isNew:
303
+		vAddr = reflect.New(vVal.Type().Elem())
304
+	case isDeref && !isNew:
305
+		vAddr = vVal
306
+	default:
307
+		vAddr = vVal.Addr()
308
+	}
309
+	vAddrI := vAddr.Interface()
310
+	err, ok := error(nil), false
311
+	for _, s := range setters {
312
+		err = s(vAddrI, blankValue, value, t)
313
+		if err == nil {
314
+			ok = true
315
+			break
316
+		}
317
+		if err != errUnsupportedType {
318
+			return err
319
+		}
320
+	}
321
+	if !ok {
322
+		// in case all setters returned errUnsupportedType
323
+		return err
324
+	}
325
+	if isNew { // set reference if it was dereferenced and newly allocated
326
+		vVal.Set(vAddr)
327
+	}
328
+	if isMulti { // append if multi-valued
329
+		vVar.Set(reflect.Append(vVar, vVal))
330
+	}
331
+	return nil
332
+}

+ 3
- 0
vendor/src/github.com/src-d/gcfg/testdata/gcfg_test.gcfg Datei anzeigen

@@ -0,0 +1,3 @@
1
+; Comment line
2
+[section]
3
+name=value # comment

+ 3
- 0
vendor/src/github.com/src-d/gcfg/testdata/gcfg_unicode_test.gcfg Datei anzeigen

@@ -0,0 +1,3 @@
1
+; Comment line
2
+[甲]
3
+乙=丙 # comment

+ 435
- 0
vendor/src/github.com/src-d/gcfg/token/position.go Datei anzeigen

@@ -0,0 +1,435 @@
1
+// Copyright 2010 The Go Authors. 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
+// TODO(gri) consider making this a separate package outside the go directory.
6
+
7
+package token
8
+
9
+import (
10
+	"fmt"
11
+	"sort"
12
+	"sync"
13
+)
14
+
15
+// -----------------------------------------------------------------------------
16
+// Positions
17
+
18
+// Position describes an arbitrary source position
19
+// including the file, line, and column location.
20
+// A Position is valid if the line number is > 0.
21
+//
22
+type Position struct {
23
+	Filename string // filename, if any
24
+	Offset   int    // offset, starting at 0
25
+	Line     int    // line number, starting at 1
26
+	Column   int    // column number, starting at 1 (character count)
27
+}
28
+
29
+// IsValid returns true if the position is valid.
30
+func (pos *Position) IsValid() bool { return pos.Line > 0 }
31
+
32
+// String returns a string in one of several forms:
33
+//
34
+//	file:line:column    valid position with file name
35
+//	line:column         valid position without file name
36
+//	file                invalid position with file name
37
+//	-                   invalid position without file name
38
+//
39
+func (pos Position) String() string {
40
+	s := pos.Filename
41
+	if pos.IsValid() {
42
+		if s != "" {
43
+			s += ":"
44
+		}
45
+		s += fmt.Sprintf("%d:%d", pos.Line, pos.Column)
46
+	}
47
+	if s == "" {
48
+		s = "-"
49
+	}
50
+	return s
51
+}
52
+
53
+// Pos is a compact encoding of a source position within a file set.
54
+// It can be converted into a Position for a more convenient, but much
55
+// larger, representation.
56
+//
57
+// The Pos value for a given file is a number in the range [base, base+size],
58
+// where base and size are specified when adding the file to the file set via
59
+// AddFile.
60
+//
61
+// To create the Pos value for a specific source offset, first add
62
+// the respective file to the current file set (via FileSet.AddFile)
63
+// and then call File.Pos(offset) for that file. Given a Pos value p
64
+// for a specific file set fset, the corresponding Position value is
65
+// obtained by calling fset.Position(p).
66
+//
67
+// Pos values can be compared directly with the usual comparison operators:
68
+// If two Pos values p and q are in the same file, comparing p and q is
69
+// equivalent to comparing the respective source file offsets. If p and q
70
+// are in different files, p < q is true if the file implied by p was added
71
+// to the respective file set before the file implied by q.
72
+//
73
+type Pos int
74
+
75
+// The zero value for Pos is NoPos; there is no file and line information
76
+// associated with it, and NoPos().IsValid() is false. NoPos is always
77
+// smaller than any other Pos value. The corresponding Position value
78
+// for NoPos is the zero value for Position.
79
+//
80
+const NoPos Pos = 0
81
+
82
+// IsValid returns true if the position is valid.
83
+func (p Pos) IsValid() bool {
84
+	return p != NoPos
85
+}
86
+
87
+// -----------------------------------------------------------------------------
88
+// File
89
+
90
+// A File is a handle for a file belonging to a FileSet.
91
+// A File has a name, size, and line offset table.
92
+//
93
+type File struct {
94
+	set  *FileSet
95
+	name string // file name as provided to AddFile
96
+	base int    // Pos value range for this file is [base...base+size]
97
+	size int    // file size as provided to AddFile
98
+
99
+	// lines and infos are protected by set.mutex
100
+	lines []int
101
+	infos []lineInfo
102
+}
103
+
104
+// Name returns the file name of file f as registered with AddFile.
105
+func (f *File) Name() string {
106
+	return f.name
107
+}
108
+
109
+// Base returns the base offset of file f as registered with AddFile.
110
+func (f *File) Base() int {
111
+	return f.base
112
+}
113
+
114
+// Size returns the size of file f as registered with AddFile.
115
+func (f *File) Size() int {
116
+	return f.size
117
+}
118
+
119
+// LineCount returns the number of lines in file f.
120
+func (f *File) LineCount() int {
121
+	f.set.mutex.RLock()
122
+	n := len(f.lines)
123
+	f.set.mutex.RUnlock()
124
+	return n
125
+}
126
+
127
+// AddLine adds the line offset for a new line.
128
+// The line offset must be larger than the offset for the previous line
129
+// and smaller than the file size; otherwise the line offset is ignored.
130
+//
131
+func (f *File) AddLine(offset int) {
132
+	f.set.mutex.Lock()
133
+	if i := len(f.lines); (i == 0 || f.lines[i-1] < offset) && offset < f.size {
134
+		f.lines = append(f.lines, offset)
135
+	}
136
+	f.set.mutex.Unlock()
137
+}
138
+
139
+// SetLines sets the line offsets for a file and returns true if successful.
140
+// The line offsets are the offsets of the first character of each line;
141
+// for instance for the content "ab\nc\n" the line offsets are {0, 3}.
142
+// An empty file has an empty line offset table.
143
+// Each line offset must be larger than the offset for the previous line
144
+// and smaller than the file size; otherwise SetLines fails and returns
145
+// false.
146
+//
147
+func (f *File) SetLines(lines []int) bool {
148
+	// verify validity of lines table
149
+	size := f.size
150
+	for i, offset := range lines {
151
+		if i > 0 && offset <= lines[i-1] || size <= offset {
152
+			return false
153
+		}
154
+	}
155
+
156
+	// set lines table
157
+	f.set.mutex.Lock()
158
+	f.lines = lines
159
+	f.set.mutex.Unlock()
160
+	return true
161
+}
162
+
163
+// SetLinesForContent sets the line offsets for the given file content.
164
+func (f *File) SetLinesForContent(content []byte) {
165
+	var lines []int
166
+	line := 0
167
+	for offset, b := range content {
168
+		if line >= 0 {
169
+			lines = append(lines, line)
170
+		}
171
+		line = -1
172
+		if b == '\n' {
173
+			line = offset + 1
174
+		}
175
+	}
176
+
177
+	// set lines table
178
+	f.set.mutex.Lock()
179
+	f.lines = lines
180
+	f.set.mutex.Unlock()
181
+}
182
+
183
+// A lineInfo object describes alternative file and line number
184
+// information (such as provided via a //line comment in a .go
185
+// file) for a given file offset.
186
+type lineInfo struct {
187
+	// fields are exported to make them accessible to gob
188
+	Offset   int
189
+	Filename string
190
+	Line     int
191
+}
192
+
193
+// AddLineInfo adds alternative file and line number information for
194
+// a given file offset. The offset must be larger than the offset for
195
+// the previously added alternative line info and smaller than the
196
+// file size; otherwise the information is ignored.
197
+//
198
+// AddLineInfo is typically used to register alternative position
199
+// information for //line filename:line comments in source files.
200
+//
201
+func (f *File) AddLineInfo(offset int, filename string, line int) {
202
+	f.set.mutex.Lock()
203
+	if i := len(f.infos); i == 0 || f.infos[i-1].Offset < offset && offset < f.size {
204
+		f.infos = append(f.infos, lineInfo{offset, filename, line})
205
+	}
206
+	f.set.mutex.Unlock()
207
+}
208
+
209
+// Pos returns the Pos value for the given file offset;
210
+// the offset must be <= f.Size().
211
+// f.Pos(f.Offset(p)) == p.
212
+//
213
+func (f *File) Pos(offset int) Pos {
214
+	if offset > f.size {
215
+		panic("illegal file offset")
216
+	}
217
+	return Pos(f.base + offset)
218
+}
219
+
220
+// Offset returns the offset for the given file position p;
221
+// p must be a valid Pos value in that file.
222
+// f.Offset(f.Pos(offset)) == offset.
223
+//
224
+func (f *File) Offset(p Pos) int {
225
+	if int(p) < f.base || int(p) > f.base+f.size {
226
+		panic("illegal Pos value")
227
+	}
228
+	return int(p) - f.base
229
+}
230
+
231
+// Line returns the line number for the given file position p;
232
+// p must be a Pos value in that file or NoPos.
233
+//
234
+func (f *File) Line(p Pos) int {
235
+	// TODO(gri) this can be implemented much more efficiently
236
+	return f.Position(p).Line
237
+}
238
+
239
+func searchLineInfos(a []lineInfo, x int) int {
240
+	return sort.Search(len(a), func(i int) bool { return a[i].Offset > x }) - 1
241
+}
242
+
243
+// info returns the file name, line, and column number for a file offset.
244
+func (f *File) info(offset int) (filename string, line, column int) {
245
+	filename = f.name
246
+	if i := searchInts(f.lines, offset); i >= 0 {
247
+		line, column = i+1, offset-f.lines[i]+1
248
+	}
249
+	if len(f.infos) > 0 {
250
+		// almost no files have extra line infos
251
+		if i := searchLineInfos(f.infos, offset); i >= 0 {
252
+			alt := &f.infos[i]
253
+			filename = alt.Filename
254
+			if i := searchInts(f.lines, alt.Offset); i >= 0 {
255
+				line += alt.Line - i - 1
256
+			}
257
+		}
258
+	}
259
+	return
260
+}
261
+
262
+func (f *File) position(p Pos) (pos Position) {
263
+	offset := int(p) - f.base
264
+	pos.Offset = offset
265
+	pos.Filename, pos.Line, pos.Column = f.info(offset)
266
+	return
267
+}
268
+
269
+// Position returns the Position value for the given file position p;
270
+// p must be a Pos value in that file or NoPos.
271
+//
272
+func (f *File) Position(p Pos) (pos Position) {
273
+	if p != NoPos {
274
+		if int(p) < f.base || int(p) > f.base+f.size {
275
+			panic("illegal Pos value")
276
+		}
277
+		pos = f.position(p)
278
+	}
279
+	return
280
+}
281
+
282
+// -----------------------------------------------------------------------------
283
+// FileSet
284
+
285
+// A FileSet represents a set of source files.
286
+// Methods of file sets are synchronized; multiple goroutines
287
+// may invoke them concurrently.
288
+//
289
+type FileSet struct {
290
+	mutex sync.RWMutex // protects the file set
291
+	base  int          // base offset for the next file
292
+	files []*File      // list of files in the order added to the set
293
+	last  *File        // cache of last file looked up
294
+}
295
+
296
+// NewFileSet creates a new file set.
297
+func NewFileSet() *FileSet {
298
+	s := new(FileSet)
299
+	s.base = 1 // 0 == NoPos
300
+	return s
301
+}
302
+
303
+// Base returns the minimum base offset that must be provided to
304
+// AddFile when adding the next file.
305
+//
306
+func (s *FileSet) Base() int {
307
+	s.mutex.RLock()
308
+	b := s.base
309
+	s.mutex.RUnlock()
310
+	return b
311
+
312
+}
313
+
314
+// AddFile adds a new file with a given filename, base offset, and file size
315
+// to the file set s and returns the file. Multiple files may have the same
316
+// name. The base offset must not be smaller than the FileSet's Base(), and
317
+// size must not be negative.
318
+//
319
+// Adding the file will set the file set's Base() value to base + size + 1
320
+// as the minimum base value for the next file. The following relationship
321
+// exists between a Pos value p for a given file offset offs:
322
+//
323
+//	int(p) = base + offs
324
+//
325
+// with offs in the range [0, size] and thus p in the range [base, base+size].
326
+// For convenience, File.Pos may be used to create file-specific position
327
+// values from a file offset.
328
+//
329
+func (s *FileSet) AddFile(filename string, base, size int) *File {
330
+	s.mutex.Lock()
331
+	defer s.mutex.Unlock()
332
+	if base < s.base || size < 0 {
333
+		panic("illegal base or size")
334
+	}
335
+	// base >= s.base && size >= 0
336
+	f := &File{s, filename, base, size, []int{0}, nil}
337
+	base += size + 1 // +1 because EOF also has a position
338
+	if base < 0 {
339
+		panic("token.Pos offset overflow (> 2G of source code in file set)")
340
+	}
341
+	// add the file to the file set
342
+	s.base = base
343
+	s.files = append(s.files, f)
344
+	s.last = f
345
+	return f
346
+}
347
+
348
+// Iterate calls f for the files in the file set in the order they were added
349
+// until f returns false.
350
+//
351
+func (s *FileSet) Iterate(f func(*File) bool) {
352
+	for i := 0; ; i++ {
353
+		var file *File
354
+		s.mutex.RLock()
355
+		if i < len(s.files) {
356
+			file = s.files[i]
357
+		}
358
+		s.mutex.RUnlock()
359
+		if file == nil || !f(file) {
360
+			break
361
+		}
362
+	}
363
+}
364
+
365
+func searchFiles(a []*File, x int) int {
366
+	return sort.Search(len(a), func(i int) bool { return a[i].base > x }) - 1
367
+}
368
+
369
+func (s *FileSet) file(p Pos) *File {
370
+	// common case: p is in last file
371
+	if f := s.last; f != nil && f.base <= int(p) && int(p) <= f.base+f.size {
372
+		return f
373
+	}
374
+	// p is not in last file - search all files
375
+	if i := searchFiles(s.files, int(p)); i >= 0 {
376
+		f := s.files[i]
377
+		// f.base <= int(p) by definition of searchFiles
378
+		if int(p) <= f.base+f.size {
379
+			s.last = f
380
+			return f
381
+		}
382
+	}
383
+	return nil
384
+}
385
+
386
+// File returns the file that contains the position p.
387
+// If no such file is found (for instance for p == NoPos),
388
+// the result is nil.
389
+//
390
+func (s *FileSet) File(p Pos) (f *File) {
391
+	if p != NoPos {
392
+		s.mutex.RLock()
393
+		f = s.file(p)
394
+		s.mutex.RUnlock()
395
+	}
396
+	return
397
+}
398
+
399
+// Position converts a Pos in the fileset into a general Position.
400
+func (s *FileSet) Position(p Pos) (pos Position) {
401
+	if p != NoPos {
402
+		s.mutex.RLock()
403
+		if f := s.file(p); f != nil {
404
+			pos = f.position(p)
405
+		}
406
+		s.mutex.RUnlock()
407
+	}
408
+	return
409
+}
410
+
411
+// -----------------------------------------------------------------------------
412
+// Helper functions
413
+
414
+func searchInts(a []int, x int) int {
415
+	// This function body is a manually inlined version of:
416
+	//
417
+	//   return sort.Search(len(a), func(i int) bool { return a[i] > x }) - 1
418
+	//
419
+	// With better compiler optimizations, this may not be needed in the
420
+	// future, but at the moment this change improves the go/printer
421
+	// benchmark performance by ~30%. This has a direct impact on the
422
+	// speed of gofmt and thus seems worthwhile (2011-04-29).
423
+	// TODO(gri): Remove this when compilers have caught up.
424
+	i, j := 0, len(a)
425
+	for i < j {
426
+		h := i + (j-i)/2 // avoid overflow when computing h
427
+		// i ≤ h < j
428
+		if a[h] <= x {
429
+			i = h + 1
430
+		} else {
431
+			j = h
432
+		}
433
+	}
434
+	return i - 1
435
+}

+ 181
- 0
vendor/src/github.com/src-d/gcfg/token/position_test.go Datei anzeigen

@@ -0,0 +1,181 @@
1
+// Copyright 2010 The Go Authors. 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 token
6
+
7
+import (
8
+	"fmt"
9
+	"testing"
10
+)
11
+
12
+func checkPos(t *testing.T, msg string, p, q Position) {
13
+	if p.Filename != q.Filename {
14
+		t.Errorf("%s: expected filename = %q; got %q", msg, q.Filename, p.Filename)
15
+	}
16
+	if p.Offset != q.Offset {
17
+		t.Errorf("%s: expected offset = %d; got %d", msg, q.Offset, p.Offset)
18
+	}
19
+	if p.Line != q.Line {
20
+		t.Errorf("%s: expected line = %d; got %d", msg, q.Line, p.Line)
21
+	}
22
+	if p.Column != q.Column {
23
+		t.Errorf("%s: expected column = %d; got %d", msg, q.Column, p.Column)
24
+	}
25
+}
26
+
27
+func TestNoPos(t *testing.T) {
28
+	if NoPos.IsValid() {
29
+		t.Errorf("NoPos should not be valid")
30
+	}
31
+	var fset *FileSet
32
+	checkPos(t, "nil NoPos", fset.Position(NoPos), Position{})
33
+	fset = NewFileSet()
34
+	checkPos(t, "fset NoPos", fset.Position(NoPos), Position{})
35
+}
36
+
37
+var tests = []struct {
38
+	filename string
39
+	source   []byte // may be nil
40
+	size     int
41
+	lines    []int
42
+}{
43
+	{"a", []byte{}, 0, []int{}},
44
+	{"b", []byte("01234"), 5, []int{0}},
45
+	{"c", []byte("\n\n\n\n\n\n\n\n\n"), 9, []int{0, 1, 2, 3, 4, 5, 6, 7, 8}},
46
+	{"d", nil, 100, []int{0, 5, 10, 20, 30, 70, 71, 72, 80, 85, 90, 99}},
47
+	{"e", nil, 777, []int{0, 80, 100, 120, 130, 180, 267, 455, 500, 567, 620}},
48
+	{"f", []byte("package p\n\nimport \"fmt\""), 23, []int{0, 10, 11}},
49
+	{"g", []byte("package p\n\nimport \"fmt\"\n"), 24, []int{0, 10, 11}},
50
+	{"h", []byte("package p\n\nimport \"fmt\"\n "), 25, []int{0, 10, 11, 24}},
51
+}
52
+
53
+func linecol(lines []int, offs int) (int, int) {
54
+	prevLineOffs := 0
55
+	for line, lineOffs := range lines {
56
+		if offs < lineOffs {
57
+			return line, offs - prevLineOffs + 1
58
+		}
59
+		prevLineOffs = lineOffs
60
+	}
61
+	return len(lines), offs - prevLineOffs + 1
62
+}
63
+
64
+func verifyPositions(t *testing.T, fset *FileSet, f *File, lines []int) {
65
+	for offs := 0; offs < f.Size(); offs++ {
66
+		p := f.Pos(offs)
67
+		offs2 := f.Offset(p)
68
+		if offs2 != offs {
69
+			t.Errorf("%s, Offset: expected offset %d; got %d", f.Name(), offs, offs2)
70
+		}
71
+		line, col := linecol(lines, offs)
72
+		msg := fmt.Sprintf("%s (offs = %d, p = %d)", f.Name(), offs, p)
73
+		checkPos(t, msg, f.Position(f.Pos(offs)), Position{f.Name(), offs, line, col})
74
+		checkPos(t, msg, fset.Position(p), Position{f.Name(), offs, line, col})
75
+	}
76
+}
77
+
78
+func makeTestSource(size int, lines []int) []byte {
79
+	src := make([]byte, size)
80
+	for _, offs := range lines {
81
+		if offs > 0 {
82
+			src[offs-1] = '\n'
83
+		}
84
+	}
85
+	return src
86
+}
87
+
88
+func TestPositions(t *testing.T) {
89
+	const delta = 7 // a non-zero base offset increment
90
+	fset := NewFileSet()
91
+	for _, test := range tests {
92
+		// verify consistency of test case
93
+		if test.source != nil && len(test.source) != test.size {
94
+			t.Errorf("%s: inconsistent test case: expected file size %d; got %d", test.filename, test.size, len(test.source))
95
+		}
96
+
97
+		// add file and verify name and size
98
+		f := fset.AddFile(test.filename, fset.Base()+delta, test.size)
99
+		if f.Name() != test.filename {
100
+			t.Errorf("expected filename %q; got %q", test.filename, f.Name())
101
+		}
102
+		if f.Size() != test.size {
103
+			t.Errorf("%s: expected file size %d; got %d", f.Name(), test.size, f.Size())
104
+		}
105
+		if fset.File(f.Pos(0)) != f {
106
+			t.Errorf("%s: f.Pos(0) was not found in f", f.Name())
107
+		}
108
+
109
+		// add lines individually and verify all positions
110
+		for i, offset := range test.lines {
111
+			f.AddLine(offset)
112
+			if f.LineCount() != i+1 {
113
+				t.Errorf("%s, AddLine: expected line count %d; got %d", f.Name(), i+1, f.LineCount())
114
+			}
115
+			// adding the same offset again should be ignored
116
+			f.AddLine(offset)
117
+			if f.LineCount() != i+1 {
118
+				t.Errorf("%s, AddLine: expected unchanged line count %d; got %d", f.Name(), i+1, f.LineCount())
119
+			}
120
+			verifyPositions(t, fset, f, test.lines[0:i+1])
121
+		}
122
+
123
+		// add lines with SetLines and verify all positions
124
+		if ok := f.SetLines(test.lines); !ok {
125
+			t.Errorf("%s: SetLines failed", f.Name())
126
+		}
127
+		if f.LineCount() != len(test.lines) {
128
+			t.Errorf("%s, SetLines: expected line count %d; got %d", f.Name(), len(test.lines), f.LineCount())
129
+		}
130
+		verifyPositions(t, fset, f, test.lines)
131
+
132
+		// add lines with SetLinesForContent and verify all positions
133
+		src := test.source
134
+		if src == nil {
135
+			// no test source available - create one from scratch
136
+			src = makeTestSource(test.size, test.lines)
137
+		}
138
+		f.SetLinesForContent(src)
139
+		if f.LineCount() != len(test.lines) {
140
+			t.Errorf("%s, SetLinesForContent: expected line count %d; got %d", f.Name(), len(test.lines), f.LineCount())
141
+		}
142
+		verifyPositions(t, fset, f, test.lines)
143
+	}
144
+}
145
+
146
+func TestLineInfo(t *testing.T) {
147
+	fset := NewFileSet()
148
+	f := fset.AddFile("foo", fset.Base(), 500)
149
+	lines := []int{0, 42, 77, 100, 210, 220, 277, 300, 333, 401}
150
+	// add lines individually and provide alternative line information
151
+	for _, offs := range lines {
152
+		f.AddLine(offs)
153
+		f.AddLineInfo(offs, "bar", 42)
154
+	}
155
+	// verify positions for all offsets
156
+	for offs := 0; offs <= f.Size(); offs++ {
157
+		p := f.Pos(offs)
158
+		_, col := linecol(lines, offs)
159
+		msg := fmt.Sprintf("%s (offs = %d, p = %d)", f.Name(), offs, p)
160
+		checkPos(t, msg, f.Position(f.Pos(offs)), Position{"bar", offs, 42, col})
161
+		checkPos(t, msg, fset.Position(p), Position{"bar", offs, 42, col})
162
+	}
163
+}
164
+
165
+func TestFiles(t *testing.T) {
166
+	fset := NewFileSet()
167
+	for i, test := range tests {
168
+		fset.AddFile(test.filename, fset.Base(), test.size)
169
+		j := 0
170
+		fset.Iterate(func(f *File) bool {
171
+			if f.Name() != tests[j].filename {
172
+				t.Errorf("expected filename = %s; got %s", tests[j].filename, f.Name())
173
+			}
174
+			j++
175
+			return true
176
+		})
177
+		if j != i+1 {
178
+			t.Errorf("expected %d files; got %d", i+1, j)
179
+		}
180
+	}
181
+}

+ 56
- 0
vendor/src/github.com/src-d/gcfg/token/serialize.go Datei anzeigen

@@ -0,0 +1,56 @@
1
+// Copyright 2011 The Go Authors. 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 token
6
+
7
+type serializedFile struct {
8
+	// fields correspond 1:1 to fields with same (lower-case) name in File
9
+	Name  string
10
+	Base  int
11
+	Size  int
12
+	Lines []int
13
+	Infos []lineInfo
14
+}
15
+
16
+type serializedFileSet struct {
17
+	Base  int
18
+	Files []serializedFile
19
+}
20
+
21
+// Read calls decode to deserialize a file set into s; s must not be nil.
22
+func (s *FileSet) Read(decode func(interface{}) error) error {
23
+	var ss serializedFileSet
24
+	if err := decode(&ss); err != nil {
25
+		return err
26
+	}
27
+
28
+	s.mutex.Lock()
29
+	s.base = ss.Base
30
+	files := make([]*File, len(ss.Files))
31
+	for i := 0; i < len(ss.Files); i++ {
32
+		f := &ss.Files[i]
33
+		files[i] = &File{s, f.Name, f.Base, f.Size, f.Lines, f.Infos}
34
+	}
35
+	s.files = files
36
+	s.last = nil
37
+	s.mutex.Unlock()
38
+
39
+	return nil
40
+}
41
+
42
+// Write calls encode to serialize the file set s.
43
+func (s *FileSet) Write(encode func(interface{}) error) error {
44
+	var ss serializedFileSet
45
+
46
+	s.mutex.Lock()
47
+	ss.Base = s.base
48
+	files := make([]serializedFile, len(s.files))
49
+	for i, f := range s.files {
50
+		files[i] = serializedFile{f.name, f.base, f.size, f.lines, f.infos}
51
+	}
52
+	ss.Files = files
53
+	s.mutex.Unlock()
54
+
55
+	return encode(ss)
56
+}

+ 111
- 0
vendor/src/github.com/src-d/gcfg/token/serialize_test.go Datei anzeigen

@@ -0,0 +1,111 @@
1
+// Copyright 2011 The Go Authors. 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 token
6
+
7
+import (
8
+	"bytes"
9
+	"encoding/gob"
10
+	"fmt"
11
+	"testing"
12
+)
13
+
14
+// equal returns nil if p and q describe the same file set;
15
+// otherwise it returns an error describing the discrepancy.
16
+func equal(p, q *FileSet) error {
17
+	if p == q {
18
+		// avoid deadlock if p == q
19
+		return nil
20
+	}
21
+
22
+	// not strictly needed for the test
23
+	p.mutex.Lock()
24
+	q.mutex.Lock()
25
+	defer q.mutex.Unlock()
26
+	defer p.mutex.Unlock()
27
+
28
+	if p.base != q.base {
29
+		return fmt.Errorf("different bases: %d != %d", p.base, q.base)
30
+	}
31
+
32
+	if len(p.files) != len(q.files) {
33
+		return fmt.Errorf("different number of files: %d != %d", len(p.files), len(q.files))
34
+	}
35
+
36
+	for i, f := range p.files {
37
+		g := q.files[i]
38
+		if f.set != p {
39
+			return fmt.Errorf("wrong fileset for %q", f.name)
40
+		}
41
+		if g.set != q {
42
+			return fmt.Errorf("wrong fileset for %q", g.name)
43
+		}
44
+		if f.name != g.name {
45
+			return fmt.Errorf("different filenames: %q != %q", f.name, g.name)
46
+		}
47
+		if f.base != g.base {
48
+			return fmt.Errorf("different base for %q: %d != %d", f.name, f.base, g.base)
49
+		}
50
+		if f.size != g.size {
51
+			return fmt.Errorf("different size for %q: %d != %d", f.name, f.size, g.size)
52
+		}
53
+		for j, l := range f.lines {
54
+			m := g.lines[j]
55
+			if l != m {
56
+				return fmt.Errorf("different offsets for %q", f.name)
57
+			}
58
+		}
59
+		for j, l := range f.infos {
60
+			m := g.infos[j]
61
+			if l.Offset != m.Offset || l.Filename != m.Filename || l.Line != m.Line {
62
+				return fmt.Errorf("different infos for %q", f.name)
63
+			}
64
+		}
65
+	}
66
+
67
+	// we don't care about .last - it's just a cache
68
+	return nil
69
+}
70
+
71
+func checkSerialize(t *testing.T, p *FileSet) {
72
+	var buf bytes.Buffer
73
+	encode := func(x interface{}) error {
74
+		return gob.NewEncoder(&buf).Encode(x)
75
+	}
76
+	if err := p.Write(encode); err != nil {
77
+		t.Errorf("writing fileset failed: %s", err)
78
+		return
79
+	}
80
+	q := NewFileSet()
81
+	decode := func(x interface{}) error {
82
+		return gob.NewDecoder(&buf).Decode(x)
83
+	}
84
+	if err := q.Read(decode); err != nil {
85
+		t.Errorf("reading fileset failed: %s", err)
86
+		return
87
+	}
88
+	if err := equal(p, q); err != nil {
89
+		t.Errorf("filesets not identical: %s", err)
90
+	}
91
+}
92
+
93
+func TestSerialization(t *testing.T) {
94
+	p := NewFileSet()
95
+	checkSerialize(t, p)
96
+	// add some files
97
+	for i := 0; i < 10; i++ {
98
+		f := p.AddFile(fmt.Sprintf("file%d", i), p.Base()+i, i*100)
99
+		checkSerialize(t, p)
100
+		// add some lines and alternative file infos
101
+		line := 1000
102
+		for offs := 0; offs < f.Size(); offs += 40 + i {
103
+			f.AddLine(offs)
104
+			if offs%7 == 0 {
105
+				f.AddLineInfo(offs, fmt.Sprintf("file%d", offs), line)
106
+				line += 33
107
+			}
108
+		}
109
+		checkSerialize(t, p)
110
+	}
111
+}

+ 83
- 0
vendor/src/github.com/src-d/gcfg/token/token.go Datei anzeigen

@@ -0,0 +1,83 @@
1
+// Copyright 2009 The Go Authors. 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 token defines constants representing the lexical tokens of the gcfg
6
+// configuration syntax and basic operations on tokens (printing, predicates).
7
+//
8
+// Note that the API for the token package may change to accommodate new
9
+// features or implementation changes in gcfg.
10
+//
11
+package token
12
+
13
+import "strconv"
14
+
15
+// Token is the set of lexical tokens of the gcfg configuration syntax.
16
+type Token int
17
+
18
+// The list of tokens.
19
+const (
20
+	// Special tokens
21
+	ILLEGAL Token = iota
22
+	EOF
23
+	COMMENT
24
+
25
+	literal_beg
26
+	// Identifiers and basic type literals
27
+	// (these tokens stand for classes of literals)
28
+	IDENT  // section-name, variable-name
29
+	STRING // "subsection-name", variable value
30
+	literal_end
31
+
32
+	operator_beg
33
+	// Operators and delimiters
34
+	ASSIGN // =
35
+	LBRACK // [
36
+	RBRACK // ]
37
+	EOL    // \n
38
+	operator_end
39
+)
40
+
41
+var tokens = [...]string{
42
+	ILLEGAL: "ILLEGAL",
43
+
44
+	EOF:     "EOF",
45
+	COMMENT: "COMMENT",
46
+
47
+	IDENT:  "IDENT",
48
+	STRING: "STRING",
49
+
50
+	ASSIGN: "=",
51
+	LBRACK: "[",
52
+	RBRACK: "]",
53
+	EOL:    "\n",
54
+}
55
+
56
+// String returns the string corresponding to the token tok.
57
+// For operators and delimiters, the string is the actual token character
58
+// sequence (e.g., for the token ASSIGN, the string is "="). For all other
59
+// tokens the string corresponds to the token constant name (e.g. for the
60
+// token IDENT, the string is "IDENT").
61
+//
62
+func (tok Token) String() string {
63
+	s := ""
64
+	if 0 <= tok && tok < Token(len(tokens)) {
65
+		s = tokens[tok]
66
+	}
67
+	if s == "" {
68
+		s = "token(" + strconv.Itoa(int(tok)) + ")"
69
+	}
70
+	return s
71
+}
72
+
73
+// Predicates
74
+
75
+// IsLiteral returns true for tokens corresponding to identifiers
76
+// and basic type literals; it returns false otherwise.
77
+//
78
+func (tok Token) IsLiteral() bool { return literal_beg < tok && tok < literal_end }
79
+
80
+// IsOperator returns true for tokens corresponding to operators and
81
+// delimiters; it returns false otherwise.
82
+//
83
+func (tok Token) IsOperator() bool { return operator_beg < tok && tok < operator_end }

+ 0
- 0
vendor/src/github.com/src-d/gcfg/types/bool.go Datei anzeigen


Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden.