mirror of
				https://github.com/taigrr/wtf
				synced 2025-01-18 04:03:14 -08:00 
			
		
		
		
	Merge branch 'master' of github.com:davidsbond/wtf into davidsbond-master
This commit is contained in:
		
						commit
						ac39734f6d
					
				| @ -35,10 +35,21 @@ func (widget *Widget) getInstance() (*clientInstance, error) { | |||||||
| 
 | 
 | ||||||
| // getKubeClient returns a kubernetes clientset for the kubeconfig provided | // getKubeClient returns a kubernetes clientset for the kubeconfig provided | ||||||
| func (widget *Widget) getKubeClient() (kubernetes.Interface, error) { | func (widget *Widget) getKubeClient() (kubernetes.Interface, error) { | ||||||
| 	config, err := clientcmd.BuildConfigFromFlags("", widget.kubeconfig) | 	var overrides *clientcmd.ConfigOverrides | ||||||
|  | 	if widget.context != "" { | ||||||
|  | 		overrides = &clientcmd.ConfigOverrides{ | ||||||
|  | 			CurrentContext: widget.context, | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	config, err := clientcmd.NewNonInteractiveDeferredLoadingClientConfig( | ||||||
|  | 		&clientcmd.ClientConfigLoadingRules{ExplicitPath: widget.kubeconfig}, | ||||||
|  | 		overrides).ClientConfig() | ||||||
|  | 
 | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
| 	clientset, err := kubernetes.NewForConfig(config) | 	clientset, err := kubernetes.NewForConfig(config) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
|  | |||||||
| @ -18,6 +18,7 @@ type Settings struct { | |||||||
| 	title      string   `help:"Override the title of widget."` | 	title      string   `help:"Override the title of widget."` | ||||||
| 	kubeconfig string   `help:"Location of a kubeconfig file."` | 	kubeconfig string   `help:"Location of a kubeconfig file."` | ||||||
| 	namespaces []string `help:"List of namespaces to watch. If blank, defaults to all namespaces."` | 	namespaces []string `help:"List of namespaces to watch. If blank, defaults to all namespaces."` | ||||||
|  | 	context    string   `help:"Kubernetes context to use. If blank, uses default context"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func NewSettingsFromYAML(name string, moduleConfig *config.Config, globalConfig *config.Config) *Settings { | func NewSettingsFromYAML(name string, moduleConfig *config.Config, globalConfig *config.Config) *Settings { | ||||||
| @ -29,6 +30,7 @@ func NewSettingsFromYAML(name string, moduleConfig *config.Config, globalConfig | |||||||
| 		title:      moduleConfig.UString("title"), | 		title:      moduleConfig.UString("title"), | ||||||
| 		kubeconfig: moduleConfig.UString("kubeconfig"), | 		kubeconfig: moduleConfig.UString("kubeconfig"), | ||||||
| 		namespaces: utils.ToStrs(moduleConfig.UList("namespaces")), | 		namespaces: utils.ToStrs(moduleConfig.UList("namespaces")), | ||||||
|  | 		context:    moduleConfig.UString("context"), | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return &settings | 	return &settings | ||||||
|  | |||||||
| @ -18,6 +18,7 @@ type Widget struct { | |||||||
| 	title      string | 	title      string | ||||||
| 	kubeconfig string | 	kubeconfig string | ||||||
| 	namespaces []string | 	namespaces []string | ||||||
|  | 	context    string | ||||||
| 	settings   *Settings | 	settings   *Settings | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -31,6 +32,7 @@ func NewWidget(app *tview.Application, settings *Settings) *Widget { | |||||||
| 		kubeconfig: settings.kubeconfig, | 		kubeconfig: settings.kubeconfig, | ||||||
| 		namespaces: settings.namespaces, | 		namespaces: settings.namespaces, | ||||||
| 		settings:   settings, | 		settings:   settings, | ||||||
|  | 		context:    settings.context, | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	widget.View.SetWrap(true) | 	widget.View.SetWrap(true) | ||||||
| @ -101,6 +103,10 @@ func (widget *Widget) generateTitle() string { | |||||||
| 	} | 	} | ||||||
| 	title := "Kube" | 	title := "Kube" | ||||||
| 
 | 
 | ||||||
|  | 	if widget.context != "" { | ||||||
|  | 		title = fmt.Sprintf("%s (%s)", title, widget.context) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	if len(widget.namespaces) == 1 { | 	if len(widget.namespaces) == 1 { | ||||||
| 		title += fmt.Sprintf(" - Namespace: %s", widget.namespaces[0]) | 		title += fmt.Sprintf(" - Namespace: %s", widget.namespaces[0]) | ||||||
| 	} else if len(widget.namespaces) > 1 { | 	} else if len(widget.namespaces) > 1 { | ||||||
|  | |||||||
| @ -10,6 +10,7 @@ func Test_generateTitle(t *testing.T) { | |||||||
| 	type fields struct { | 	type fields struct { | ||||||
| 		title      string | 		title      string | ||||||
| 		namespaces []string | 		namespaces []string | ||||||
|  | 		context    string | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	testCases := []struct { | 	testCases := []struct { | ||||||
| @ -46,6 +47,14 @@ func Test_generateTitle(t *testing.T) { | |||||||
| 			}, | 			}, | ||||||
| 			want: "Test Explicit Title", | 			want: "Test Explicit Title", | ||||||
| 		}, | 		}, | ||||||
|  | 		{ | ||||||
|  | 			name: "Context set", | ||||||
|  | 			fields: fields{ | ||||||
|  | 				namespaces: []string{}, | ||||||
|  | 				context:    "test-context", | ||||||
|  | 			}, | ||||||
|  | 			want: "Kube (test-context)", | ||||||
|  | 		}, | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	for _, tt := range testCases { | 	for _, tt := range testCases { | ||||||
| @ -53,6 +62,7 @@ func Test_generateTitle(t *testing.T) { | |||||||
| 			widget := &Widget{ | 			widget := &Widget{ | ||||||
| 				title:      tt.fields.title, | 				title:      tt.fields.title, | ||||||
| 				namespaces: tt.fields.namespaces, | 				namespaces: tt.fields.namespaces, | ||||||
|  | 				context:    tt.fields.context, | ||||||
| 			} | 			} | ||||||
| 			assert.Equal(t, tt.want, widget.generateTitle()) | 			assert.Equal(t, tt.want, widget.generateTitle()) | ||||||
| 		}) | 		}) | ||||||
|  | |||||||
							
								
								
									
										4
									
								
								vendor/github.com/alecthomas/chroma/.golangci.yml
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/alecthomas/chroma/.golangci.yml
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -18,6 +18,8 @@ linters: | |||||||
|     - funlen |     - funlen | ||||||
|     - godox |     - godox | ||||||
|     - wsl |     - wsl | ||||||
|  |     - gomnd | ||||||
|  |     - gocognit | ||||||
| 
 | 
 | ||||||
| linters-settings: | linters-settings: | ||||||
|   govet: |   govet: | ||||||
| @ -49,3 +51,5 @@ issues: | |||||||
|     - 'at least one file in a package should have a package comment' |     - 'at least one file in a package should have a package comment' | ||||||
|     - 'string literal contains the Unicode' |     - 'string literal contains the Unicode' | ||||||
|     - 'methods on the same type should have the same receiver name' |     - 'methods on the same type should have the same receiver name' | ||||||
|  |     - '_TokenType_name should be _TokenTypeName' | ||||||
|  |     - '`_TokenType_map` should be `_TokenTypeMap`' | ||||||
|  | |||||||
							
								
								
									
										4
									
								
								vendor/github.com/alecthomas/chroma/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/alecthomas/chroma/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -1,8 +1,10 @@ | |||||||
| sudo: false | sudo: false | ||||||
| language: go | language: go | ||||||
|  | go: | ||||||
|  |   - "1.13.x" | ||||||
| script: | script: | ||||||
|   - go test -v ./... |   - go test -v ./... | ||||||
|   - curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | bash -s v1.20.0 |   - curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | bash -s v1.22.2 | ||||||
|   - ./bin/golangci-lint run |   - ./bin/golangci-lint run | ||||||
|   - git clean -fdx . |   - git clean -fdx . | ||||||
| after_success: | after_success: | ||||||
|  | |||||||
							
								
								
									
										19
									
								
								vendor/github.com/alecthomas/chroma/Makefile
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								vendor/github.com/alecthomas/chroma/Makefile
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | |||||||
|  | .PHONY: chromad upload all | ||||||
|  | 
 | ||||||
|  | all: README.md tokentype_string.go | ||||||
|  | 
 | ||||||
|  | README.md: lexers/*/*.go | ||||||
|  | 	./table.py | ||||||
|  | 
 | ||||||
|  | tokentype_string.go: types.go | ||||||
|  | 	go generate | ||||||
|  | 
 | ||||||
|  | chromad: | ||||||
|  | 	(cd ./cmd/chromad && go get github.com/GeertJohan/go.rice/rice@master && go install github.com/GeertJohan/go.rice/rice) | ||||||
|  | 	rm -f chromad | ||||||
|  | 	(export CGOENABLED=0 GOOS=linux ; cd ./cmd/chromad && go build -o ../../chromad .) | ||||||
|  | 	rice append -i ./cmd/chromad --exec=./chromad | ||||||
|  | 
 | ||||||
|  | upload: chromad | ||||||
|  | 	scp chromad root@swapoff.org: && \
 | ||||||
|  | 		ssh root@swapoff.org 'install -m755 ./chromad /srv/http/swapoff.org/bin && service chromad restart' | ||||||
							
								
								
									
										7
									
								
								vendor/github.com/alecthomas/chroma/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								vendor/github.com/alecthomas/chroma/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -47,14 +47,14 @@ I | Idris, INI, Io | |||||||
| J | J, Java, JavaScript, JSON, Julia, Jungle | J | J, Java, JavaScript, JSON, Julia, Jungle | ||||||
| K | Kotlin | K | Kotlin | ||||||
| L | Lighttpd configuration file, LLVM, Lua | L | Lighttpd configuration file, LLVM, Lua | ||||||
| M | Mako, markdown, Mason, Mathematica, Matlab, MiniZinc, Modula-2, MonkeyC, MorrowindScript, Myghty, MySQL | M | Mako, markdown, Mason, Mathematica, Matlab, MiniZinc, MLIR, Modula-2, MonkeyC, MorrowindScript, Myghty, MySQL | ||||||
| N | NASM, Newspeak, Nginx configuration file, Nim, Nix | N | NASM, Newspeak, Nginx configuration file, Nim, Nix | ||||||
| O | Objective-C, OCaml, Octave, OpenSCAD, Org Mode | O | Objective-C, OCaml, Octave, OpenSCAD, Org Mode | ||||||
| P | PacmanConf, Perl, PHP, Pig, PkgConfig, PL/pgSQL, plaintext, PostgreSQL SQL dialect, PostScript, POVRay, PowerShell, Prolog, Protocol Buffer, Puppet, Python, Python 3 | P | PacmanConf, Perl, PHP, Pig, PkgConfig, PL/pgSQL, plaintext, PostgreSQL SQL dialect, PostScript, POVRay, PowerShell, Prolog, Protocol Buffer, Puppet, Python, Python 3 | ||||||
| Q | QBasic | Q | QBasic | ||||||
| R | R, Racket, Ragel, react, reg, reStructuredText, Rexx, Ruby, Rust | R | R, Racket, Ragel, react, reg, reStructuredText, Rexx, Ruby, Rust | ||||||
| S | Sass, Scala, Scheme, Scilab, SCSS, Smalltalk, Smarty, Snobol, Solidity, SPARQL, SQL, SquidConf, Swift, SYSTEMD, systemverilog | S | Sass, Scala, Scheme, Scilab, SCSS, Smalltalk, Smarty, SML, Snobol, Solidity, SPARQL, SQL, SquidConf, Swift, SYSTEMD, systemverilog | ||||||
| T | TASM, Tcl, Tcsh, Termcap, Terminfo, Terraform, TeX, Thrift, TOML, TradingView, Transact-SQL, Turing, Turtle, Twig, TypeScript, TypoScript, TypoScriptCssData, TypoScriptHtmlData | T | TableGen, TASM, Tcl, Tcsh, Termcap, Terminfo, Terraform, TeX, Thrift, TOML, TradingView, Transact-SQL, Turing, Turtle, Twig, TypeScript, TypoScript, TypoScriptCssData, TypoScriptHtmlData | ||||||
| V | VB.net, verilog, VHDL, VimL, vue | V | VB.net, verilog, VHDL, VimL, vue | ||||||
| W | WDTE | W | WDTE | ||||||
| X | XML, Xorg | X | XML, Xorg | ||||||
| @ -183,6 +183,7 @@ following constructor options: | |||||||
| - `ClassPrefix(prefix)` - prefix each generated CSS class. | - `ClassPrefix(prefix)` - prefix each generated CSS class. | ||||||
| - `TabWidth(width)` - Set the rendered tab width, in characters. | - `TabWidth(width)` - Set the rendered tab width, in characters. | ||||||
| - `WithLineNumbers()` - Render line numbers (style with `LineNumbers`). | - `WithLineNumbers()` - Render line numbers (style with `LineNumbers`). | ||||||
|  | - `LinkableLineNumbers()` - Make the line numbers linkable. | ||||||
| - `HighlightLines(ranges)` - Highlight lines in these ranges (style with `LineHighlight`). | - `HighlightLines(ranges)` - Highlight lines in these ranges (style with `LineHighlight`). | ||||||
| - `LineNumbersInTable()` - Use a table for formatting line numbers and code, rather than spans. | - `LineNumbersInTable()` - Use a table for formatting line numbers and code, rather than spans. | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										29
									
								
								vendor/github.com/alecthomas/chroma/formatters/html/html.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										29
									
								
								vendor/github.com/alecthomas/chroma/formatters/html/html.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -58,6 +58,15 @@ func LineNumbersInTable(b bool) Option { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // LinkableLineNumbers decorates the line numbers HTML elements with an "id" | ||||||
|  | // attribute so they can be linked. | ||||||
|  | func LinkableLineNumbers(b bool, prefix string) Option { | ||||||
|  | 	return func(f *Formatter) { | ||||||
|  | 		f.linkableLineNumbers = b | ||||||
|  | 		f.lineNumbersIDPrefix = prefix | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // HighlightLines higlights the given line ranges with the Highlight style. | // HighlightLines higlights the given line ranges with the Highlight style. | ||||||
| // | // | ||||||
| // A range is the beginning and ending of a range as 1-based line numbers, inclusive. | // A range is the beginning and ending of a range as 1-based line numbers, inclusive. | ||||||
| @ -136,6 +145,8 @@ type Formatter struct { | |||||||
| 	tabWidth            int | 	tabWidth            int | ||||||
| 	lineNumbers         bool | 	lineNumbers         bool | ||||||
| 	lineNumbersInTable  bool | 	lineNumbersInTable  bool | ||||||
|  | 	linkableLineNumbers bool | ||||||
|  | 	lineNumbersIDPrefix string | ||||||
| 	highlightRanges     highlightRanges | 	highlightRanges     highlightRanges | ||||||
| 	baseLineNumber      int | 	baseLineNumber      int | ||||||
| } | } | ||||||
| @ -196,7 +207,7 @@ func (f *Formatter) writeHTML(w io.Writer, style *chroma.Style, tokens []chroma. | |||||||
| 				fmt.Fprintf(w, "<span%s>", f.styleAttr(css, chroma.LineHighlight)) | 				fmt.Fprintf(w, "<span%s>", f.styleAttr(css, chroma.LineHighlight)) | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			fmt.Fprintf(w, "<span%s>%*d\n</span>", f.styleAttr(css, chroma.LineNumbersTable), lineDigits, line) | 			fmt.Fprintf(w, "<span%s%s>%*d\n</span>", f.styleAttr(css, chroma.LineNumbersTable), f.lineIDAttribute(line), lineDigits, line) | ||||||
| 
 | 
 | ||||||
| 			if highlight { | 			if highlight { | ||||||
| 				fmt.Fprintf(w, "</span>") | 				fmt.Fprintf(w, "</span>") | ||||||
| @ -222,7 +233,7 @@ func (f *Formatter) writeHTML(w io.Writer, style *chroma.Style, tokens []chroma. | |||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if f.lineNumbers && !wrapInTable { | 		if f.lineNumbers && !wrapInTable { | ||||||
| 			fmt.Fprintf(w, "<span%s>%*d</span>", f.styleAttr(css, chroma.LineNumbers), lineDigits, line) | 			fmt.Fprintf(w, "<span%s%s>%*d</span>", f.styleAttr(css, chroma.LineNumbers), f.lineIDAttribute(line), lineDigits, line) | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		for _, token := range tokens { | 		for _, token := range tokens { | ||||||
| @ -253,6 +264,13 @@ func (f *Formatter) writeHTML(w io.Writer, style *chroma.Style, tokens []chroma. | |||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func (f *Formatter) lineIDAttribute(line int) string { | ||||||
|  | 	if !f.linkableLineNumbers { | ||||||
|  | 		return "" | ||||||
|  | 	} | ||||||
|  | 	return fmt.Sprintf(" id=\"%s%d\"", f.lineNumbersIDPrefix, line) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func (f *Formatter) shouldHighlight(highlightIndex, line int) (bool, bool) { | func (f *Formatter) shouldHighlight(highlightIndex, line int) (bool, bool) { | ||||||
| 	next := false | 	next := false | ||||||
| 	for highlightIndex < len(f.highlightRanges) && line > f.highlightRanges[highlightIndex][1] { | 	for highlightIndex < len(f.highlightRanges) && line > f.highlightRanges[highlightIndex][1] { | ||||||
| @ -327,6 +345,13 @@ func (f *Formatter) WriteCSS(w io.Writer, style *chroma.Style) error { | |||||||
| 			return err | 			return err | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | 	// Special-case line number highlighting when targeted. | ||||||
|  | 	if f.lineNumbers || f.lineNumbersInTable { | ||||||
|  | 		targetedLineCSS := StyleEntryToCSS(style.Get(chroma.LineHighlight)) | ||||||
|  | 		for _, tt := range []chroma.TokenType{chroma.LineNumbers, chroma.LineNumbersTable} { | ||||||
|  | 			fmt.Fprintf(w, "/* %s targeted by URL anchor */ .%schroma .%s:target { %s }\n", tt, f.prefix, f.class(tt), targetedLineCSS) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
| 	tts := []int{} | 	tts := []int{} | ||||||
| 	for tt := range css { | 	for tt := range css { | ||||||
| 		tts = append(tts, int(tt)) | 		tts = append(tts, int(tt)) | ||||||
|  | |||||||
							
								
								
									
										5
									
								
								vendor/github.com/alecthomas/chroma/go.mod
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								vendor/github.com/alecthomas/chroma/go.mod
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -1,17 +1,12 @@ | |||||||
| module github.com/alecthomas/chroma | module github.com/alecthomas/chroma | ||||||
| 
 | 
 | ||||||
| require ( | require ( | ||||||
| 	github.com/GeertJohan/go.rice v1.0.0 |  | ||||||
| 	github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38 | 	github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38 | ||||||
| 	github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721 // indirect | 	github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721 // indirect | ||||||
| 	github.com/alecthomas/kong v0.2.1-0.20190708041108-0548c6b1afae | 	github.com/alecthomas/kong v0.2.1-0.20190708041108-0548c6b1afae | ||||||
| 	github.com/alecthomas/kong-hcl v0.1.8-0.20190615233001-b21fea9723c8 |  | ||||||
| 	github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897 // indirect | 	github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897 // indirect | ||||||
| 	github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 | 	github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 | ||||||
| 	github.com/dlclark/regexp2 v1.1.6 | 	github.com/dlclark/regexp2 v1.1.6 | ||||||
| 	github.com/gorilla/csrf v1.6.0 |  | ||||||
| 	github.com/gorilla/handlers v1.4.1 |  | ||||||
| 	github.com/gorilla/mux v1.7.3 |  | ||||||
| 	github.com/mattn/go-colorable v0.0.9 | 	github.com/mattn/go-colorable v0.0.9 | ||||||
| 	github.com/mattn/go-isatty v0.0.4 | 	github.com/mattn/go-isatty v0.0.4 | ||||||
| 	github.com/sergi/go-diff v1.0.0 // indirect | 	github.com/sergi/go-diff v1.0.0 // indirect | ||||||
|  | |||||||
							
								
								
									
										25
									
								
								vendor/github.com/alecthomas/chroma/go.sum
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										25
									
								
								vendor/github.com/alecthomas/chroma/go.sum
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -1,20 +1,11 @@ | |||||||
| github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0= |  | ||||||
| github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= |  | ||||||
| github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38 h1:smF2tmSOzy2Mm+0dGI2AIUHY+w0BUc+4tn40djz7+6U= | github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38 h1:smF2tmSOzy2Mm+0dGI2AIUHY+w0BUc+4tn40djz7+6U= | ||||||
| github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38/go.mod h1:r7bzyVFMNntcxPZXK3/+KdruV1H5KSlyVY0gc+NgInI= | github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38/go.mod h1:r7bzyVFMNntcxPZXK3/+KdruV1H5KSlyVY0gc+NgInI= | ||||||
| github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721 h1:JHZL0hZKJ1VENNfmXvHbgYlbUOvpzYzvy2aZU5gXVeo= | github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721 h1:JHZL0hZKJ1VENNfmXvHbgYlbUOvpzYzvy2aZU5gXVeo= | ||||||
| github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721/go.mod h1:QO9JBoKquHd+jz9nshCh40fOfO+JzsoXy8qTHF68zU0= | github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721/go.mod h1:QO9JBoKquHd+jz9nshCh40fOfO+JzsoXy8qTHF68zU0= | ||||||
| github.com/alecthomas/go.rice v1.0.1-0.20190719113735-961b99d742e7 h1:0cMlP9evwgTzs5JUe2C/3rLttYjmRm0kbz9fdGBIV1E= |  | ||||||
| github.com/alecthomas/go.rice v1.0.1-0.20190719113735-961b99d742e7/go.mod h1:af5vUNlDNkCjOZeSGFgIJxDje9qdjsO6hshx0gTmZt4= |  | ||||||
| github.com/alecthomas/kong v0.1.17-0.20190424132513-439c674f7ae0/go.mod h1:+inYUSluD+p4L8KdviBSgzcqEjUQOfC5fQDRFuc36lI= |  | ||||||
| github.com/alecthomas/kong v0.2.1-0.20190708041108-0548c6b1afae h1:C4Q9m+oXOxcSWwYk9XzzafY2xAVAaeubZbUHJkw3PlY= | github.com/alecthomas/kong v0.2.1-0.20190708041108-0548c6b1afae h1:C4Q9m+oXOxcSWwYk9XzzafY2xAVAaeubZbUHJkw3PlY= | ||||||
| github.com/alecthomas/kong v0.2.1-0.20190708041108-0548c6b1afae/go.mod h1:+inYUSluD+p4L8KdviBSgzcqEjUQOfC5fQDRFuc36lI= | github.com/alecthomas/kong v0.2.1-0.20190708041108-0548c6b1afae/go.mod h1:+inYUSluD+p4L8KdviBSgzcqEjUQOfC5fQDRFuc36lI= | ||||||
| github.com/alecthomas/kong-hcl v0.1.8-0.20190615233001-b21fea9723c8 h1:atLL+K8Hg0e8863K2X+k7qu+xz3M2a/mWFIACAPf55M= |  | ||||||
| github.com/alecthomas/kong-hcl v0.1.8-0.20190615233001-b21fea9723c8/go.mod h1:MRgZdU3vrFd05IQ89AxUZ0aYdF39BYoNFa324SodPCA= |  | ||||||
| github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897 h1:p9Sln00KOTlrYkxI1zYWl1QLnEqAqEARBEYa8FQnQcY= | github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897 h1:p9Sln00KOTlrYkxI1zYWl1QLnEqAqEARBEYa8FQnQcY= | ||||||
| github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897/go.mod h1:xTS7Pm1pD1mvyM075QCDSRqH6qRLXylzS24ZTpRiSzQ= | github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897/go.mod h1:xTS7Pm1pD1mvyM075QCDSRqH6qRLXylzS24ZTpRiSzQ= | ||||||
| github.com/daaku/go.zipexe v1.0.0 h1:VSOgZtH418pH9L16hC/JrgSNJbbAL26pj7lmD1+CGdY= |  | ||||||
| github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E= |  | ||||||
| github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 h1:y5HC9v93H5EPKqaS1UYVg1uYah5Xf51mBfIoWehClUQ= | github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 h1:y5HC9v93H5EPKqaS1UYVg1uYah5Xf51mBfIoWehClUQ= | ||||||
| github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964/go.mod h1:Xd9hchkHSWYkEqJwUGisez3G1QY8Ryz0sdWrLPMGjLk= | github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964/go.mod h1:Xd9hchkHSWYkEqJwUGisez3G1QY8Ryz0sdWrLPMGjLk= | ||||||
| github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||||||
| @ -22,25 +13,11 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c | |||||||
| github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||||||
| github.com/dlclark/regexp2 v1.1.6 h1:CqB4MjHw0MFCDj+PHHjiESmHX+N7t0tJzKvC6M97BRg= | github.com/dlclark/regexp2 v1.1.6 h1:CqB4MjHw0MFCDj+PHHjiESmHX+N7t0tJzKvC6M97BRg= | ||||||
| github.com/dlclark/regexp2 v1.1.6/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= | github.com/dlclark/regexp2 v1.1.6/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= | ||||||
| github.com/gorilla/csrf v1.6.0 h1:60oN1cFdncCE8tjwQ3QEkFND5k37lQPcRjnlvm7CIJ0= |  | ||||||
| github.com/gorilla/csrf v1.6.0/go.mod h1:7tSf8kmjNYr7IWDCYhd3U8Ck34iQ/Yw5CJu7bAkHEGI= |  | ||||||
| github.com/gorilla/handlers v1.4.1 h1:BHvcRGJe/TrL+OqFxoKQGddTgeibiOjaBssV5a/N9sw= |  | ||||||
| github.com/gorilla/handlers v1.4.1/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= |  | ||||||
| github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw= |  | ||||||
| github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= |  | ||||||
| github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= |  | ||||||
| github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= |  | ||||||
| github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= |  | ||||||
| github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= |  | ||||||
| github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= |  | ||||||
| github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4= | github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4= | ||||||
| github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= | github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= | ||||||
| github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs= | github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs= | ||||||
| github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= | github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= | ||||||
| github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= | github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= | ||||||
| github.com/nkovacs/streamquote v1.0.0/go.mod h1:BN+NaZ2CmdKqUuTUXUEm9j95B2TRbpOWpxbJYzzgUsc= |  | ||||||
| github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw= |  | ||||||
| github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= |  | ||||||
| github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= | github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= | ||||||
| github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= | ||||||
| github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||||||
| @ -52,7 +29,5 @@ github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1 | |||||||
| github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= | ||||||
| github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= | github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= | ||||||
| github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= | ||||||
| github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= |  | ||||||
| github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= |  | ||||||
| golang.org/x/sys v0.0.0-20181128092732-4ed8d59d0b35 h1:YAFjXN64LMvktoUZH9zgY4lGc/msGN7HQfoSuKCgaDU= | golang.org/x/sys v0.0.0-20181128092732-4ed8d59d0b35 h1:YAFjXN64LMvktoUZH9zgY4lGc/msGN7HQfoSuKCgaDU= | ||||||
| golang.org/x/sys v0.0.0-20181128092732-4ed8d59d0b35/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | golang.org/x/sys v0.0.0-20181128092732-4ed8d59d0b35/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||||
|  | |||||||
							
								
								
									
										43
									
								
								vendor/github.com/alecthomas/chroma/lexers/m/mlir.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								vendor/github.com/alecthomas/chroma/lexers/m/mlir.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,43 @@ | |||||||
|  | package m | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	. "github.com/alecthomas/chroma" // nolint | ||||||
|  | 	"github.com/alecthomas/chroma/lexers/internal" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // MLIR lexer. | ||||||
|  | var Mlir = internal.Register(MustNewLexer( | ||||||
|  | 	&Config{ | ||||||
|  | 		Name:      "MLIR", | ||||||
|  | 		Aliases:   []string{"mlir"}, | ||||||
|  | 		Filenames: []string{"*.mlir"}, | ||||||
|  | 		MimeTypes: []string{"text/x-mlir"}, | ||||||
|  | 	}, | ||||||
|  | 	Rules{ | ||||||
|  | 		"root": { | ||||||
|  | 			Include("whitespace"), | ||||||
|  | 			{`c?"[^"]*?"`, LiteralString, nil}, | ||||||
|  | 			{`\^([-a-zA-Z$._][\w\-$.0-9]*)\s*`, NameLabel, nil}, | ||||||
|  | 			{`([\w\d_$.]+)\s*=`, NameLabel, nil}, | ||||||
|  | 			Include("keyword"), | ||||||
|  | 			{`->`, Punctuation, nil}, | ||||||
|  | 			{`@([\w_][\w\d_$.]*)`, NameFunction, nil}, | ||||||
|  | 			{`[%#][\w\d_$.]+`, NameVariable, nil}, | ||||||
|  | 			{`([1-9?][\d?]*\s*x)+`, LiteralNumber, nil}, | ||||||
|  | 			{`0[xX][a-fA-F0-9]+`, LiteralNumber, nil}, | ||||||
|  | 			{`-?\d+(?:[.]\d+)?(?:[eE][-+]?\d+(?:[.]\d+)?)?`, LiteralNumber, nil}, | ||||||
|  | 			{`[=<>{}\[\]()*.,!:]|x\b`, Punctuation, nil}, | ||||||
|  | 			{`[\w\d]+`, Text, nil}, | ||||||
|  | 		}, | ||||||
|  | 		"whitespace": { | ||||||
|  | 			{`(\n|\s)+`, Text, nil}, | ||||||
|  | 			{`//.*?\n`, Comment, nil}, | ||||||
|  | 		}, | ||||||
|  | 		"keyword": { | ||||||
|  | 			{Words(``, ``, `constant`, `return`), KeywordType, nil}, | ||||||
|  | 			{Words(``, ``, `func`, `loc`, `memref`, `tensor`, `vector`), KeywordType, nil}, | ||||||
|  | 			{`bf16|f16|f32|f64|index`, Keyword, nil}, | ||||||
|  | 			{`i[1-9]\d*`, Keyword, nil}, | ||||||
|  | 		}, | ||||||
|  | 	}, | ||||||
|  | )) | ||||||
							
								
								
									
										4
									
								
								vendor/github.com/alecthomas/chroma/lexers/p/powershell.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/alecthomas/chroma/lexers/p/powershell.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -22,6 +22,7 @@ var Powershell = internal.Register(MustNewLexer( | |||||||
| 			{`^(\s*#[#\s]*)(\.(?:component|description|example|externalhelp|forwardhelpcategory|forwardhelptargetname|functionality|inputs|link|notes|outputs|parameter|remotehelprunspace|role|synopsis))([^\n]*$)`, ByGroups(Comment, LiteralStringDoc, Comment), nil}, | 			{`^(\s*#[#\s]*)(\.(?:component|description|example|externalhelp|forwardhelpcategory|forwardhelptargetname|functionality|inputs|link|notes|outputs|parameter|remotehelprunspace|role|synopsis))([^\n]*$)`, ByGroups(Comment, LiteralStringDoc, Comment), nil}, | ||||||
| 			{`#[^\n]*?$`, Comment, nil}, | 			{`#[^\n]*?$`, Comment, nil}, | ||||||
| 			{`(<|<)#`, CommentMultiline, Push("multline")}, | 			{`(<|<)#`, CommentMultiline, Push("multline")}, | ||||||
|  | 			{`(?i)([A-Z]:)`, Name, nil}, | ||||||
| 			{`@"\n`, LiteralStringHeredoc, Push("heredoc-double")}, | 			{`@"\n`, LiteralStringHeredoc, Push("heredoc-double")}, | ||||||
| 			{`@'\n.*?\n'@`, LiteralStringHeredoc, nil}, | 			{`@'\n.*?\n'@`, LiteralStringHeredoc, nil}, | ||||||
| 			{"`[\\'\"$@-]", Punctuation, nil}, | 			{"`[\\'\"$@-]", Punctuation, nil}, | ||||||
| @ -30,7 +31,8 @@ var Powershell = internal.Register(MustNewLexer( | |||||||
| 			{`(\$|@@|@)((global|script|private|env):)?\w+`, NameVariable, nil}, | 			{`(\$|@@|@)((global|script|private|env):)?\w+`, NameVariable, nil}, | ||||||
| 			{`(while|validateset|validaterange|validatepattern|validatelength|validatecount|until|trap|switch|return|ref|process|param|parameter|in|if|global:|function|foreach|for|finally|filter|end|elseif|else|dynamicparam|do|default|continue|cmdletbinding|break|begin|alias|\?|%|#script|#private|#local|#global|mandatory|parametersetname|position|valuefrompipeline|valuefrompipelinebypropertyname|valuefromremainingarguments|helpmessage|try|catch|throw)\b`, Keyword, nil}, | 			{`(while|validateset|validaterange|validatepattern|validatelength|validatecount|until|trap|switch|return|ref|process|param|parameter|in|if|global:|function|foreach|for|finally|filter|end|elseif|else|dynamicparam|do|default|continue|cmdletbinding|break|begin|alias|\?|%|#script|#private|#local|#global|mandatory|parametersetname|position|valuefrompipeline|valuefrompipelinebypropertyname|valuefromremainingarguments|helpmessage|try|catch|throw)\b`, Keyword, nil}, | ||||||
| 			{`-(and|as|band|bnot|bor|bxor|casesensitive|ccontains|ceq|cge|cgt|cle|clike|clt|cmatch|cne|cnotcontains|cnotlike|cnotmatch|contains|creplace|eq|exact|f|file|ge|gt|icontains|ieq|ige|igt|ile|ilike|ilt|imatch|ine|inotcontains|inotlike|inotmatch|ireplace|is|isnot|le|like|lt|match|ne|not|notcontains|notlike|notmatch|or|regex|replace|wildcard)\b`, Operator, nil}, | 			{`-(and|as|band|bnot|bor|bxor|casesensitive|ccontains|ceq|cge|cgt|cle|clike|clt|cmatch|cne|cnotcontains|cnotlike|cnotmatch|contains|creplace|eq|exact|f|file|ge|gt|icontains|ieq|ige|igt|ile|ilike|ilt|imatch|ine|inotcontains|inotlike|inotmatch|ireplace|is|isnot|le|like|lt|match|ne|not|notcontains|notlike|notmatch|or|regex|replace|wildcard)\b`, Operator, nil}, | ||||||
| 			{`(write|where|wait|use|update|unregister|undo|trace|test|tee|take|suspend|stop|start|split|sort|skip|show|set|send|select|scroll|resume|restore|restart|resolve|resize|reset|rename|remove|register|receive|read|push|pop|ping|out|new|move|measure|limit|join|invoke|import|group|get|format|foreach|export|expand|exit|enter|enable|disconnect|disable|debug|cxnew|copy|convertto|convertfrom|convert|connect|complete|compare|clear|checkpoint|aggregate|add)-[a-z_]\w*\b`, NameBuiltin, nil}, | 			{`(write|where|watch|wait|use|update|unregister|unpublish|unprotect|unlock|uninstall|undo|unblock|trace|test|tee|take|sync|switch|suspend|submit|stop|step|start|split|sort|skip|show|set|send|select|search|scroll|save|revoke|resume|restore|restart|resolve|resize|reset|request|repair|rename|remove|register|redo|receive|read|push|publish|protect|pop|ping|out|optimize|open|new|move|mount|merge|measure|lock|limit|join|invoke|install|initialize|import|hide|group|grant|get|format|foreach|find|export|expand|exit|enter|enable|edit|dismount|disconnect|disable|deny|debug|cxnew|copy|convertto|convertfrom|convert|connect|confirm|compress|complete|compare|close|clear|checkpoint|block|backup|assert|approve|aggregate|add)-[a-z_]\w*\b`, NameBuiltin, nil}, | ||||||
|  | 			{`(ac|asnp|cat|cd|cfs|chdir|clc|clear|clhy|cli|clp|cls|clv|cnsn|compare|copy|cp|cpi|cpp|curl|cvpa|dbp|del|diff|dir|dnsn|ebp|echo|epal|epcsv|epsn|erase|etsn|exsn|fc|fhx|fl|foreach|ft|fw|gal|gbp|gc|gci|gcm|gcs|gdr|ghy|gi|gjb|gl|gm|gmo|gp|gps|gpv|group|gsn|gsnp|gsv|gu|gv|gwmi|h|history|icm|iex|ihy|ii|ipal|ipcsv|ipmo|ipsn|irm|ise|iwmi|iwr|kill|lp|ls|man|md|measure|mi|mount|move|mp|mv|nal|ndr|ni|nmo|npssc|nsn|nv|ogv|oh|popd|ps|pushd|pwd|r|rbp|rcjb|rcsn|rd|rdr|ren|ri|rjb|rm|rmdir|rmo|rni|rnp|rp|rsn|rsnp|rujb|rv|rvpa|rwmi|sajb|sal|saps|sasv|sbp|sc|select|set|shcm|si|sl|sleep|sls|sort|sp|spjb|spps|spsv|start|sujb|sv|swmi|tee|trcm|type|wget|where|wjb|write)\s`, NameBuiltin, nil}, | ||||||
| 			{"\\[[a-z_\\[][\\w. `,\\[\\]]*\\]", NameConstant, nil}, | 			{"\\[[a-z_\\[][\\w. `,\\[\\]]*\\]", NameConstant, nil}, | ||||||
| 			{`-[a-z_]\w*`, Name, nil}, | 			{`-[a-z_]\w*`, Name, nil}, | ||||||
| 			{`\w+`, Name, nil}, | 			{`\w+`, Name, nil}, | ||||||
|  | |||||||
							
								
								
									
										200
									
								
								vendor/github.com/alecthomas/chroma/lexers/s/sml.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										200
									
								
								vendor/github.com/alecthomas/chroma/lexers/s/sml.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,200 @@ | |||||||
|  | package s | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	. "github.com/alecthomas/chroma" // nolint | ||||||
|  | 	"github.com/alecthomas/chroma/lexers/internal" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // Standard ML lexer. | ||||||
|  | var StandardML = internal.Register(MustNewLexer( | ||||||
|  | 	&Config{ | ||||||
|  | 		Name:      "Standard ML", | ||||||
|  | 		Aliases:   []string{"sml"}, | ||||||
|  | 		Filenames: []string{"*.sml", "*.sig", "*.fun"}, | ||||||
|  | 		MimeTypes: []string{"text/x-standardml", "application/x-standardml"}, | ||||||
|  | 	}, | ||||||
|  | 	Rules{ | ||||||
|  | 		"whitespace": { | ||||||
|  | 			{`\s+`, Text, nil}, | ||||||
|  | 			{`\(\*`, CommentMultiline, Push("comment")}, | ||||||
|  | 		}, | ||||||
|  | 		"delimiters": { | ||||||
|  | 			{`\(|\[|\{`, Punctuation, Push("main")}, | ||||||
|  | 			{`\)|\]|\}`, Punctuation, Pop(1)}, | ||||||
|  | 			{`\b(let|if|local)\b(?!\')`, KeywordReserved, Push("main", "main")}, | ||||||
|  | 			{`\b(struct|sig|while)\b(?!\')`, KeywordReserved, Push("main")}, | ||||||
|  | 			{`\b(do|else|end|in|then)\b(?!\')`, KeywordReserved, Pop(1)}, | ||||||
|  | 		}, | ||||||
|  | 		"core": { | ||||||
|  | 			{`(_|\}|\{|\)|;|,|\[|\(|\]|\.\.\.)`, Punctuation, nil}, | ||||||
|  | 			{`#"`, LiteralStringChar, Push("char")}, | ||||||
|  | 			{`"`, LiteralStringDouble, Push("string")}, | ||||||
|  | 			{`~?0x[0-9a-fA-F]+`, LiteralNumberHex, nil}, | ||||||
|  | 			{`0wx[0-9a-fA-F]+`, LiteralNumberHex, nil}, | ||||||
|  | 			{`0w\d+`, LiteralNumberInteger, nil}, | ||||||
|  | 			{`~?\d+\.\d+[eE]~?\d+`, LiteralNumberFloat, nil}, | ||||||
|  | 			{`~?\d+\.\d+`, LiteralNumberFloat, nil}, | ||||||
|  | 			{`~?\d+[eE]~?\d+`, LiteralNumberFloat, nil}, | ||||||
|  | 			{`~?\d+`, LiteralNumberInteger, nil}, | ||||||
|  | 			{`#\s*[1-9][0-9]*`, NameLabel, nil}, | ||||||
|  | 			{`#\s*([a-zA-Z][\w']*)`, NameLabel, nil}, | ||||||
|  | 			{"#\\s+([!%&$#+\\-/:<=>?@\\\\~`^|*]+)", NameLabel, nil}, | ||||||
|  | 			{`\b(datatype|abstype)\b(?!\')`, KeywordReserved, Push("dname")}, | ||||||
|  | 			{`(?=\b(exception)\b(?!\'))`, Text, Push("ename")}, | ||||||
|  | 			{`\b(functor|include|open|signature|structure)\b(?!\')`, KeywordReserved, Push("sname")}, | ||||||
|  | 			{`\b(type|eqtype)\b(?!\')`, KeywordReserved, Push("tname")}, | ||||||
|  | 			{`\'[\w\']*`, NameDecorator, nil}, | ||||||
|  | 			{`([a-zA-Z][\w']*)(\.)`, NameNamespace, Push("dotted")}, | ||||||
|  | 			{`\b(abstype|and|andalso|as|case|datatype|do|else|end|exception|fn|fun|handle|if|in|infix|infixr|let|local|nonfix|of|op|open|orelse|raise|rec|then|type|val|with|withtype|while|eqtype|functor|include|sharing|sig|signature|struct|structure|where)\b`, KeywordReserved, nil}, | ||||||
|  | 			{`([a-zA-Z][\w']*)`, Name, nil}, | ||||||
|  | 			{`\b(:|\|,=|=>|->|#|:>)\b`, KeywordReserved, nil}, | ||||||
|  | 			{"([!%&$#+\\-/:<=>?@\\\\~`^|*]+)", Name, nil}, | ||||||
|  | 		}, | ||||||
|  | 		"dotted": { | ||||||
|  | 			{`([a-zA-Z][\w']*)(\.)`, NameNamespace, nil}, | ||||||
|  | 			// ignoring reserved words | ||||||
|  | 			{`([a-zA-Z][\w']*)`, Name, Pop(1)}, | ||||||
|  | 			// ignoring reserved words | ||||||
|  | 			{"([!%&$#+\\-/:<=>?@\\\\~`^|*]+)", Name, Pop(1)}, | ||||||
|  | 			{`\s+`, Error, nil}, | ||||||
|  | 			{`\S+`, Error, nil}, | ||||||
|  | 		}, | ||||||
|  | 		"root": { | ||||||
|  | 			Default(Push("main")), | ||||||
|  | 		}, | ||||||
|  | 		"main": { | ||||||
|  | 			Include("whitespace"), | ||||||
|  | 			{`\b(val|and)\b(?!\')`, KeywordReserved, Push("vname")}, | ||||||
|  | 			{`\b(fun)\b(?!\')`, KeywordReserved, Push("#pop", "main-fun", "fname")}, | ||||||
|  | 			Include("delimiters"), | ||||||
|  | 			Include("core"), | ||||||
|  | 			{`\S+`, Error, nil}, | ||||||
|  | 		}, | ||||||
|  | 		"main-fun": { | ||||||
|  | 			Include("whitespace"), | ||||||
|  | 			{`\s`, Text, nil}, | ||||||
|  | 			{`\(\*`, CommentMultiline, Push("comment")}, | ||||||
|  | 			{`\b(fun|and)\b(?!\')`, KeywordReserved, Push("fname")}, | ||||||
|  | 			{`\b(val)\b(?!\')`, KeywordReserved, Push("#pop", "main", "vname")}, | ||||||
|  | 			{`\|`, Punctuation, Push("fname")}, | ||||||
|  | 			{`\b(case|handle)\b(?!\')`, KeywordReserved, Push("#pop", "main")}, | ||||||
|  | 			Include("delimiters"), | ||||||
|  | 			Include("core"), | ||||||
|  | 			{`\S+`, Error, nil}, | ||||||
|  | 		}, | ||||||
|  | 		"char": { | ||||||
|  | 			{`[^"\\]`, LiteralStringChar, nil}, | ||||||
|  | 			{`\\[\\"abtnvfr]`, LiteralStringEscape, nil}, | ||||||
|  | 			{`\\\^[\x40-\x5e]`, LiteralStringEscape, nil}, | ||||||
|  | 			{`\\[0-9]{3}`, LiteralStringEscape, nil}, | ||||||
|  | 			{`\\u[0-9a-fA-F]{4}`, LiteralStringEscape, nil}, | ||||||
|  | 			{`\\\s+\\`, LiteralStringInterpol, nil}, | ||||||
|  | 			{`"`, LiteralStringChar, Pop(1)}, | ||||||
|  | 		}, | ||||||
|  | 		"string": { | ||||||
|  | 			{`[^"\\]`, LiteralStringDouble, nil}, | ||||||
|  | 			{`\\[\\"abtnvfr]`, LiteralStringEscape, nil}, | ||||||
|  | 			{`\\\^[\x40-\x5e]`, LiteralStringEscape, nil}, | ||||||
|  | 			{`\\[0-9]{3}`, LiteralStringEscape, nil}, | ||||||
|  | 			{`\\u[0-9a-fA-F]{4}`, LiteralStringEscape, nil}, | ||||||
|  | 			{`\\\s+\\`, LiteralStringInterpol, nil}, | ||||||
|  | 			{`"`, LiteralStringDouble, Pop(1)}, | ||||||
|  | 		}, | ||||||
|  | 		"breakout": { | ||||||
|  | 			{`(?=\b(where|do|handle|if|sig|op|while|case|as|else|signature|andalso|struct|infixr|functor|in|structure|then|local|rec|end|fun|of|orelse|val|include|fn|with|exception|let|and|infix|sharing|datatype|type|abstype|withtype|eqtype|nonfix|raise|open)\b(?!\'))`, Text, Pop(1)}, | ||||||
|  | 		}, | ||||||
|  | 		"sname": { | ||||||
|  | 			Include("whitespace"), | ||||||
|  | 			Include("breakout"), | ||||||
|  | 			{`([a-zA-Z][\w']*)`, NameNamespace, nil}, | ||||||
|  | 			Default(Pop(1)), | ||||||
|  | 		}, | ||||||
|  | 		"fname": { | ||||||
|  | 			Include("whitespace"), | ||||||
|  | 			{`\'[\w\']*`, NameDecorator, nil}, | ||||||
|  | 			{`\(`, Punctuation, Push("tyvarseq")}, | ||||||
|  | 			{`([a-zA-Z][\w']*)`, NameFunction, Pop(1)}, | ||||||
|  | 			{"([!%&$#+\\-/:<=>?@\\\\~`^|*]+)", NameFunction, Pop(1)}, | ||||||
|  | 			Default(Pop(1)), | ||||||
|  | 		}, | ||||||
|  | 		"vname": { | ||||||
|  | 			Include("whitespace"), | ||||||
|  | 			{`\'[\w\']*`, NameDecorator, nil}, | ||||||
|  | 			{`\(`, Punctuation, Push("tyvarseq")}, | ||||||
|  | 			{"([a-zA-Z][\\w']*)(\\s*)(=(?![!%&$#+\\-/:<=>?@\\\\~`^|*]+))", ByGroups(NameVariable, Text, Punctuation), Pop(1)}, | ||||||
|  | 			{"([!%&$#+\\-/:<=>?@\\\\~`^|*]+)(\\s*)(=(?![!%&$#+\\-/:<=>?@\\\\~`^|*]+))", ByGroups(NameVariable, Text, Punctuation), Pop(1)}, | ||||||
|  | 			{`([a-zA-Z][\w']*)`, NameVariable, Pop(1)}, | ||||||
|  | 			{"([!%&$#+\\-/:<=>?@\\\\~`^|*]+)", NameVariable, Pop(1)}, | ||||||
|  | 			Default(Pop(1)), | ||||||
|  | 		}, | ||||||
|  | 		"tname": { | ||||||
|  | 			Include("whitespace"), | ||||||
|  | 			Include("breakout"), | ||||||
|  | 			{`\'[\w\']*`, NameDecorator, nil}, | ||||||
|  | 			{`\(`, Punctuation, Push("tyvarseq")}, | ||||||
|  | 			{"=(?![!%&$#+\\-/:<=>?@\\\\~`^|*]+)", Punctuation, Push("#pop", "typbind")}, | ||||||
|  | 			{`([a-zA-Z][\w']*)`, KeywordType, nil}, | ||||||
|  | 			{"([!%&$#+\\-/:<=>?@\\\\~`^|*]+)", KeywordType, nil}, | ||||||
|  | 			{`\S+`, Error, Pop(1)}, | ||||||
|  | 		}, | ||||||
|  | 		"typbind": { | ||||||
|  | 			Include("whitespace"), | ||||||
|  | 			{`\b(and)\b(?!\')`, KeywordReserved, Push("#pop", "tname")}, | ||||||
|  | 			Include("breakout"), | ||||||
|  | 			Include("core"), | ||||||
|  | 			{`\S+`, Error, Pop(1)}, | ||||||
|  | 		}, | ||||||
|  | 		"dname": { | ||||||
|  | 			Include("whitespace"), | ||||||
|  | 			Include("breakout"), | ||||||
|  | 			{`\'[\w\']*`, NameDecorator, nil}, | ||||||
|  | 			{`\(`, Punctuation, Push("tyvarseq")}, | ||||||
|  | 			{`(=)(\s*)(datatype)`, ByGroups(Punctuation, Text, KeywordReserved), Pop(1)}, | ||||||
|  | 			{"=(?![!%&$#+\\-/:<=>?@\\\\~`^|*]+)", Punctuation, Push("#pop", "datbind", "datcon")}, | ||||||
|  | 			{`([a-zA-Z][\w']*)`, KeywordType, nil}, | ||||||
|  | 			{"([!%&$#+\\-/:<=>?@\\\\~`^|*]+)", KeywordType, nil}, | ||||||
|  | 			{`\S+`, Error, Pop(1)}, | ||||||
|  | 		}, | ||||||
|  | 		"datbind": { | ||||||
|  | 			Include("whitespace"), | ||||||
|  | 			{`\b(and)\b(?!\')`, KeywordReserved, Push("#pop", "dname")}, | ||||||
|  | 			{`\b(withtype)\b(?!\')`, KeywordReserved, Push("#pop", "tname")}, | ||||||
|  | 			{`\b(of)\b(?!\')`, KeywordReserved, nil}, | ||||||
|  | 			{`(\|)(\s*)([a-zA-Z][\w']*)`, ByGroups(Punctuation, Text, NameClass), nil}, | ||||||
|  | 			{"(\\|)(\\s+)([!%&$#+\\-/:<=>?@\\\\~`^|*]+)", ByGroups(Punctuation, Text, NameClass), nil}, | ||||||
|  | 			Include("breakout"), | ||||||
|  | 			Include("core"), | ||||||
|  | 			{`\S+`, Error, nil}, | ||||||
|  | 		}, | ||||||
|  | 		"ename": { | ||||||
|  | 			Include("whitespace"), | ||||||
|  | 			{`(exception|and)\b(\s+)([a-zA-Z][\w']*)`, ByGroups(KeywordReserved, Text, NameClass), nil}, | ||||||
|  | 			{"(exception|and)\\b(\\s*)([!%&$#+\\-/:<=>?@\\\\~`^|*]+)", ByGroups(KeywordReserved, Text, NameClass), nil}, | ||||||
|  | 			{`\b(of)\b(?!\')`, KeywordReserved, nil}, | ||||||
|  | 			Include("breakout"), | ||||||
|  | 			Include("core"), | ||||||
|  | 			{`\S+`, Error, nil}, | ||||||
|  | 		}, | ||||||
|  | 		"datcon": { | ||||||
|  | 			Include("whitespace"), | ||||||
|  | 			{`([a-zA-Z][\w']*)`, NameClass, Pop(1)}, | ||||||
|  | 			{"([!%&$#+\\-/:<=>?@\\\\~`^|*]+)", NameClass, Pop(1)}, | ||||||
|  | 			{`\S+`, Error, Pop(1)}, | ||||||
|  | 		}, | ||||||
|  | 		"tyvarseq": { | ||||||
|  | 			{`\s`, Text, nil}, | ||||||
|  | 			{`\(\*`, CommentMultiline, Push("comment")}, | ||||||
|  | 			{`\'[\w\']*`, NameDecorator, nil}, | ||||||
|  | 			{`[a-zA-Z][\w']*`, Name, nil}, | ||||||
|  | 			{`,`, Punctuation, nil}, | ||||||
|  | 			{`\)`, Punctuation, Pop(1)}, | ||||||
|  | 			{"[!%&$#+\\-/:<=>?@\\\\~`^|*]+", Name, nil}, | ||||||
|  | 		}, | ||||||
|  | 		"comment": { | ||||||
|  | 			{`[^(*)]`, CommentMultiline, nil}, | ||||||
|  | 			{`\(\*`, CommentMultiline, Push()}, | ||||||
|  | 			{`\*\)`, CommentMultiline, Pop(1)}, | ||||||
|  | 			{`[(*)]`, CommentMultiline, nil}, | ||||||
|  | 		}, | ||||||
|  | 	}, | ||||||
|  | )) | ||||||
							
								
								
									
										42
									
								
								vendor/github.com/alecthomas/chroma/lexers/t/tablegen.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								vendor/github.com/alecthomas/chroma/lexers/t/tablegen.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,42 @@ | |||||||
|  | package t | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	. "github.com/alecthomas/chroma" // nolint | ||||||
|  | 	"github.com/alecthomas/chroma/lexers/internal" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // TableGen lexer. | ||||||
|  | var Tablegen = internal.Register(MustNewLexer( | ||||||
|  | 	&Config{ | ||||||
|  | 		Name:      "TableGen", | ||||||
|  | 		Aliases:   []string{"tablegen"}, | ||||||
|  | 		Filenames: []string{"*.td"}, | ||||||
|  | 		MimeTypes: []string{"text/x-tablegen"}, | ||||||
|  | 	}, | ||||||
|  | 	Rules{ | ||||||
|  | 		"root": { | ||||||
|  | 			Include("macro"), | ||||||
|  | 			Include("whitespace"), | ||||||
|  | 			{`c?"[^"]*?"`, LiteralString, nil}, | ||||||
|  | 			Include("keyword"), | ||||||
|  | 			{`\$[_a-zA-Z][_\w]*`, NameVariable, nil}, | ||||||
|  | 			{`\d*[_a-zA-Z][_\w]*`, NameVariable, nil}, | ||||||
|  | 			{`\[\{[\w\W]*?\}\]`, LiteralString, nil}, | ||||||
|  | 			{`[+-]?\d+|0x[\da-fA-F]+|0b[01]+`, LiteralNumber, nil}, | ||||||
|  | 			{`[=<>{}\[\]()*.,!:;]`, Punctuation, nil}, | ||||||
|  | 		}, | ||||||
|  | 		"macro": { | ||||||
|  | 			{`(#include\s+)("[^"]*")`, ByGroups(CommentPreproc, LiteralString), nil}, | ||||||
|  | 			{`^\s*#(ifdef|ifndef)\s+[_\w][_\w\d]*`, CommentPreproc, nil}, | ||||||
|  | 			{`^\s*#define\s+[_\w][_\w\d]*`, CommentPreproc, nil}, | ||||||
|  | 			{`^\s*#endif`, CommentPreproc, nil}, | ||||||
|  | 		}, | ||||||
|  | 		"whitespace": { | ||||||
|  | 			{`(\n|\s)+`, Text, nil}, | ||||||
|  | 			{`//.*?\n`, Comment, nil}, | ||||||
|  | 		}, | ||||||
|  | 		"keyword": { | ||||||
|  | 			{Words(``, `\b`, `bit`, `bits`, `class`, `code`, `dag`, `def`, `defm`, `field`, `foreach`, `in`, `int`, `let`, `list`, `multiclass`, `string`), Keyword, nil}, | ||||||
|  | 		}, | ||||||
|  | 	}, | ||||||
|  | )) | ||||||
							
								
								
									
										12
									
								
								vendor/github.com/alecthomas/chroma/lexers/y/yaml.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										12
									
								
								vendor/github.com/alecthomas/chroma/lexers/y/yaml.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -15,12 +15,15 @@ var YAML = internal.Register(MustNewLexer( | |||||||
| 	Rules{ | 	Rules{ | ||||||
| 		"root": { | 		"root": { | ||||||
| 			Include("whitespace"), | 			Include("whitespace"), | ||||||
| 			{`#.*`, Comment, nil}, | 			{`^---`, Text, nil}, | ||||||
|  | 			{`[\n?]?\s*- `, Text, nil}, | ||||||
|  | 			{`#.*$`, Comment, nil}, | ||||||
| 			{`!![^\s]+`, CommentPreproc, nil}, | 			{`!![^\s]+`, CommentPreproc, nil}, | ||||||
| 			{`&[^\s]+`, CommentPreproc, nil}, | 			{`&[^\s]+`, CommentPreproc, nil}, | ||||||
| 			{`\*[^\s]+`, CommentPreproc, nil}, | 			{`\*[^\s]+`, CommentPreproc, nil}, | ||||||
| 			{`^%include\s+[^\n\r]+`, CommentPreproc, nil}, | 			{`^%include\s+[^\n\r]+`, CommentPreproc, nil}, | ||||||
| 			{`([>|+-]\s+)(\s+)((?:(?:.*?$)(?:[\n\r]*?)?)*)`, ByGroups(StringDoc, StringDoc, StringDoc), nil}, | 			{`([>|+-]\s+)(\s+)((?:(?:.*?$)(?:[\n\r]*?)?)*)`, ByGroups(StringDoc, StringDoc, StringDoc), nil}, | ||||||
|  | 			Include("key"), | ||||||
| 			Include("value"), | 			Include("value"), | ||||||
| 			{`[?:,\[\]]`, Punctuation, nil}, | 			{`[?:,\[\]]`, Punctuation, nil}, | ||||||
| 			{`.`, Text, nil}, | 			{`.`, Text, nil}, | ||||||
| @ -33,8 +36,15 @@ var YAML = internal.Register(MustNewLexer( | |||||||
| 			{`\b[+\-]?(0x[\da-f]+|0o[0-7]+|(\d+\.?\d*|\.?\d+)(e[\+\-]?\d+)?|\.inf|\.nan)\b`, Number, nil}, | 			{`\b[+\-]?(0x[\da-f]+|0o[0-7]+|(\d+\.?\d*|\.?\d+)(e[\+\-]?\d+)?|\.inf|\.nan)\b`, Number, nil}, | ||||||
| 			{`\b[\w]+\b`, Text, nil}, | 			{`\b[\w]+\b`, Text, nil}, | ||||||
| 		}, | 		}, | ||||||
|  | 		"key": { | ||||||
|  | 			{`"[^"\n].*": `, Keyword, nil}, | ||||||
|  | 			{`(-)( )([^"\n{]*)(:)( )`, ByGroups(Punctuation, Whitespace, Keyword, Punctuation, Whitespace), nil}, | ||||||
|  | 			{`([^"\n{]*)(:)( )`, ByGroups(Keyword, Punctuation, Whitespace), nil}, | ||||||
|  | 			{`([^"\n{]*)(:)(\n)`, ByGroups(Keyword, Punctuation, Whitespace), nil}, | ||||||
|  | 		}, | ||||||
| 		"whitespace": { | 		"whitespace": { | ||||||
| 			{`\s+`, Whitespace, nil}, | 			{`\s+`, Whitespace, nil}, | ||||||
|  | 			{`\n+`, Whitespace, nil}, | ||||||
| 		}, | 		}, | ||||||
| 	}, | 	}, | ||||||
| )) | )) | ||||||
|  | |||||||
							
								
								
									
										41
									
								
								vendor/github.com/digitalocean/godo/CHANGELOG.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										41
									
								
								vendor/github.com/digitalocean/godo/CHANGELOG.md
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -1,5 +1,46 @@ | |||||||
| # Change Log | # Change Log | ||||||
| 
 | 
 | ||||||
|  | ## unreleased | ||||||
|  | 
 | ||||||
|  | ## [v1.29.0] - 2019-12-13 | ||||||
|  | 
 | ||||||
|  | - #288 Add Balance Get method - @rbutler | ||||||
|  | - #286,#289 Deserialize meta field - @timoreimann | ||||||
|  | 
 | ||||||
|  | ## [v1.28.0] - 2019-12-04 | ||||||
|  | 
 | ||||||
|  | - #282 Add valid Redis eviction policy constants - @bentranter | ||||||
|  | - #281 Remove databases info from top-level godoc string - @bentranter | ||||||
|  | - #280 Fix VolumeSnapshotResourceType value volumesnapshot -> volume_snapshot - @aqche | ||||||
|  | 
 | ||||||
|  | ## [v1.27.0] - 2019-11-18 | ||||||
|  | 
 | ||||||
|  | - #278 add mysql user auth settings for database users - @gregmankes | ||||||
|  | 
 | ||||||
|  | ## [v1.26.0] - 2019-11-13 | ||||||
|  | 
 | ||||||
|  | - #272 dbaas: get and set mysql sql mode - @mikejholly | ||||||
|  | 
 | ||||||
|  | ## [v1.25.0] - 2019-11-13 | ||||||
|  | 
 | ||||||
|  | - #275 registry/docker-credentials: add support for the read/write parameter - @kamaln7 | ||||||
|  | - #273 implement the registry/docker-credentials endpoint - @kamaln7 | ||||||
|  | - #271 Add registry resource - @snormore | ||||||
|  | 
 | ||||||
|  | ## [v1.24.1] - 2019-11-04 | ||||||
|  | 
 | ||||||
|  | - #264 Update isLast to check p.Next - @aqche | ||||||
|  | 
 | ||||||
|  | ## [v1.24.0] - 2019-10-30 | ||||||
|  | 
 | ||||||
|  | - #267 Return []DatabaseFirewallRule in addition to raw response. - @andrewsomething | ||||||
|  | 
 | ||||||
|  | ## [v1.23.1] - 2019-10-30 | ||||||
|  | 
 | ||||||
|  | - #265 add support for getting/setting firewall rules - @gregmankes | ||||||
|  | - #262 remove ResolveReference call - @mdanzinger | ||||||
|  | - #261 Update CONTRIBUTING.md - @mdanzinger | ||||||
|  | 
 | ||||||
| ## [v1.22.0] - 2019-09-24 | ## [v1.22.0] - 2019-09-24 | ||||||
| 
 | 
 | ||||||
| - #259 Add Kubernetes GetCredentials method - @snormore | - #259 Add Kubernetes GetCredentials method - @snormore | ||||||
|  | |||||||
							
								
								
									
										2
									
								
								vendor/github.com/digitalocean/godo/CONTRIBUTING.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/digitalocean/godo/CONTRIBUTING.md
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -18,7 +18,7 @@ go get -u github.com/stretchr/testify/assert | |||||||
| If outside `$GOPATH`, just clone the repository: | If outside `$GOPATH`, just clone the repository: | ||||||
| 
 | 
 | ||||||
| ```sh | ```sh | ||||||
| git clone github.com/digitalocean/godo | git clone https://github.com/digitalocean/godo | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| ## Running tests | ## Running tests | ||||||
|  | |||||||
							
								
								
									
										4
									
								
								vendor/github.com/digitalocean/godo/action.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/digitalocean/godo/action.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -34,6 +34,7 @@ var _ ActionsService = &ActionsServiceOp{} | |||||||
| type actionsRoot struct { | type actionsRoot struct { | ||||||
| 	Actions []Action `json:"actions"` | 	Actions []Action `json:"actions"` | ||||||
| 	Links   *Links   `json:"links"` | 	Links   *Links   `json:"links"` | ||||||
|  | 	Meta    *Meta    `json:"meta"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type actionRoot struct { | type actionRoot struct { | ||||||
| @ -74,6 +75,9 @@ func (s *ActionsServiceOp) List(ctx context.Context, opt *ListOptions) ([]Action | |||||||
| 	if l := root.Links; l != nil { | 	if l := root.Links; l != nil { | ||||||
| 		resp.Links = l | 		resp.Links = l | ||||||
| 	} | 	} | ||||||
|  | 	if m := root.Meta; m != nil { | ||||||
|  | 		resp.Meta = m | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	return root.Actions, resp, err | 	return root.Actions, resp, err | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										52
									
								
								vendor/github.com/digitalocean/godo/balance.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								vendor/github.com/digitalocean/godo/balance.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,52 @@ | |||||||
|  | package godo | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"context" | ||||||
|  | 	"net/http" | ||||||
|  | 	"time" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // BalanceService is an interface for interfacing with the Balance | ||||||
|  | // endpoints of the DigitalOcean API | ||||||
|  | // See: https://developers.digitalocean.com/documentation/v2/#balance | ||||||
|  | type BalanceService interface { | ||||||
|  | 	Get(context.Context) (*Balance, *Response, error) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // BalanceServiceOp handles communication with the Balance related methods of | ||||||
|  | // the DigitalOcean API. | ||||||
|  | type BalanceServiceOp struct { | ||||||
|  | 	client *Client | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | var _ BalanceService = &BalanceServiceOp{} | ||||||
|  | 
 | ||||||
|  | // Balance represents a DigitalOcean Balance | ||||||
|  | type Balance struct { | ||||||
|  | 	MonthToDateBalance string    `json:"month_to_date_balance"` | ||||||
|  | 	AccountBalance     string    `json:"account_balance"` | ||||||
|  | 	MonthToDateUsage   string    `json:"month_to_date_usage"` | ||||||
|  | 	GeneratedAt        time.Time `json:"generated_at"` | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (r Balance) String() string { | ||||||
|  | 	return Stringify(r) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Get DigitalOcean balance info | ||||||
|  | func (s *BalanceServiceOp) Get(ctx context.Context) (*Balance, *Response, error) { | ||||||
|  | 	path := "v2/customers/my/balance" | ||||||
|  | 
 | ||||||
|  | 	req, err := s.client.NewRequest(ctx, http.MethodGet, path, nil) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, nil, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	root := new(Balance) | ||||||
|  | 	resp, err := s.client.Do(ctx, req, root) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, resp, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return root, resp, err | ||||||
|  | } | ||||||
							
								
								
									
										4
									
								
								vendor/github.com/digitalocean/godo/cdn.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/digitalocean/godo/cdn.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -47,6 +47,7 @@ type cdnRoot struct { | |||||||
| type cdnsRoot struct { | type cdnsRoot struct { | ||||||
| 	Endpoints []CDN  `json:"endpoints"` | 	Endpoints []CDN  `json:"endpoints"` | ||||||
| 	Links     *Links `json:"links"` | 	Links     *Links `json:"links"` | ||||||
|  | 	Meta      *Meta  `json:"meta"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // CDNCreateRequest represents a request to create a CDN. | // CDNCreateRequest represents a request to create a CDN. | ||||||
| @ -93,6 +94,9 @@ func (c CDNServiceOp) List(ctx context.Context, opt *ListOptions) ([]CDN, *Respo | |||||||
| 	if l := root.Links; l != nil { | 	if l := root.Links; l != nil { | ||||||
| 		resp.Links = l | 		resp.Links = l | ||||||
| 	} | 	} | ||||||
|  | 	if m := root.Meta; m != nil { | ||||||
|  | 		resp.Meta = m | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	return root.Endpoints, resp, err | 	return root.Endpoints, resp, err | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										4
									
								
								vendor/github.com/digitalocean/godo/certificates.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/digitalocean/godo/certificates.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -46,6 +46,7 @@ type certificateRoot struct { | |||||||
| type certificatesRoot struct { | type certificatesRoot struct { | ||||||
| 	Certificates []Certificate `json:"certificates"` | 	Certificates []Certificate `json:"certificates"` | ||||||
| 	Links        *Links        `json:"links"` | 	Links        *Links        `json:"links"` | ||||||
|  | 	Meta         *Meta         `json:"meta"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // CertificatesServiceOp handles communication with certificates methods of the DigitalOcean API. | // CertificatesServiceOp handles communication with certificates methods of the DigitalOcean API. | ||||||
| @ -93,6 +94,9 @@ func (c *CertificatesServiceOp) List(ctx context.Context, opt *ListOptions) ([]C | |||||||
| 	if l := root.Links; l != nil { | 	if l := root.Links; l != nil { | ||||||
| 		resp.Links = l | 		resp.Links = l | ||||||
| 	} | 	} | ||||||
|  | 	if m := root.Meta; m != nil { | ||||||
|  | 		resp.Meta = m | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	return root.Certificates, resp, nil | 	return root.Certificates, resp, nil | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										163
									
								
								vendor/github.com/digitalocean/godo/databases.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										163
									
								
								vendor/github.com/digitalocean/godo/databases.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -4,6 +4,7 @@ import ( | |||||||
| 	"context" | 	"context" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"net/http" | 	"net/http" | ||||||
|  | 	"strings" | ||||||
| 	"time" | 	"time" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| @ -22,11 +23,69 @@ const ( | |||||||
| 	databasePoolsPath          = databaseBasePath + "/%s/pools" | 	databasePoolsPath          = databaseBasePath + "/%s/pools" | ||||||
| 	databaseReplicaPath        = databaseBasePath + "/%s/replicas/%s" | 	databaseReplicaPath        = databaseBasePath + "/%s/replicas/%s" | ||||||
| 	databaseReplicasPath       = databaseBasePath + "/%s/replicas" | 	databaseReplicasPath       = databaseBasePath + "/%s/replicas" | ||||||
| 	evictionPolicyPath      = databaseBasePath + "/%s/eviction_policy" | 	databaseEvictionPolicyPath = databaseBasePath + "/%s/eviction_policy" | ||||||
|  | 	databaseSQLModePath        = databaseBasePath + "/%s/sql_mode" | ||||||
|  | 	databaseFirewallRulesPath  = databaseBasePath + "/%s/firewall" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // DatabasesService is an interface for interfacing with the databases endpoints | // SQL Mode constants allow for MySQL-specific SQL flavor configuration. | ||||||
| // of the DigitalOcean API. | const ( | ||||||
|  | 	SQLModeAllowInvalidDates     = "ALLOW_INVALID_DATES" | ||||||
|  | 	SQLModeANSIQuotes            = "ANSI_QUOTES" | ||||||
|  | 	SQLModeHighNotPrecedence     = "HIGH_NOT_PRECEDENCE" | ||||||
|  | 	SQLModeIgnoreSpace           = "IGNORE_SPACE" | ||||||
|  | 	SQLModeNoAuthCreateUser      = "NO_AUTO_CREATE_USER" | ||||||
|  | 	SQLModeNoAutoValueOnZero     = "NO_AUTO_VALUE_ON_ZERO" | ||||||
|  | 	SQLModeNoBackslashEscapes    = "NO_BACKSLASH_ESCAPES" | ||||||
|  | 	SQLModeNoDirInCreate         = "NO_DIR_IN_CREATE" | ||||||
|  | 	SQLModeNoEngineSubstitution  = "NO_ENGINE_SUBSTITUTION" | ||||||
|  | 	SQLModeNoFieldOptions        = "NO_FIELD_OPTIONS" | ||||||
|  | 	SQLModeNoKeyOptions          = "NO_KEY_OPTIONS" | ||||||
|  | 	SQLModeNoTableOptions        = "NO_TABLE_OPTIONS" | ||||||
|  | 	SQLModeNoUnsignedSubtraction = "NO_UNSIGNED_SUBTRACTION" | ||||||
|  | 	SQLModeNoZeroDate            = "NO_ZERO_DATE" | ||||||
|  | 	SQLModeNoZeroInDate          = "NO_ZERO_IN_DATE" | ||||||
|  | 	SQLModeOnlyFullGroupBy       = "ONLY_FULL_GROUP_BY" | ||||||
|  | 	SQLModePadCharToFullLength   = "PAD_CHAR_TO_FULL_LENGTH" | ||||||
|  | 	SQLModePipesAsConcat         = "PIPES_AS_CONCAT" | ||||||
|  | 	SQLModeRealAsFloat           = "REAL_AS_FLOAT" | ||||||
|  | 	SQLModeStrictAllTables       = "STRICT_ALL_TABLES" | ||||||
|  | 	SQLModeStrictTransTables     = "STRICT_TRANS_TABLES" | ||||||
|  | 	SQLModeANSI                  = "ANSI" | ||||||
|  | 	SQLModeDB2                   = "DB2" | ||||||
|  | 	SQLModeMaxDB                 = "MAXDB" | ||||||
|  | 	SQLModeMSSQL                 = "MSSQL" | ||||||
|  | 	SQLModeMYSQL323              = "MYSQL323" | ||||||
|  | 	SQLModeMYSQL40               = "MYSQL40" | ||||||
|  | 	SQLModeOracle                = "ORACLE" | ||||||
|  | 	SQLModePostgreSQL            = "POSTGRESQL" | ||||||
|  | 	SQLModeTraditional           = "TRADITIONAL" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // SQL Auth constants allow for MySQL-specific user auth plugins | ||||||
|  | const ( | ||||||
|  | 	SQLAuthPluginNative      = "mysql_native_password" | ||||||
|  | 	SQLAuthPluginCachingSHA2 = "caching_sha2_password" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // Redis eviction policies supported by the managed Redis product. | ||||||
|  | const ( | ||||||
|  | 	EvictionPolicyNoEviction     = "noeviction" | ||||||
|  | 	EvictionPolicyAllKeysLRU     = "allkeys_lru" | ||||||
|  | 	EvictionPolicyAllKeysRandom  = "allkeys_random" | ||||||
|  | 	EvictionPolicyVolatileLRU    = "volatile_lru" | ||||||
|  | 	EvictionPolicyVolatileRandom = "volatile_random" | ||||||
|  | 	EvictionPolicyVolatileTTL    = "volatile_ttl" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // The DatabasesService provides access to the DigitalOcean managed database | ||||||
|  | // suite of products through the public API. Customers can create new database | ||||||
|  | // clusters, migrate them  between regions, create replicas and interact with | ||||||
|  | // their configurations. Each database service is refered to as a Database. A | ||||||
|  | // SQL database service can have multiple databases residing in the system. To | ||||||
|  | // help make these entities distinct from Databases in godo, we refer to them | ||||||
|  | // here as DatabaseDBs. | ||||||
|  | // | ||||||
| // See: https://developers.digitalocean.com/documentation/v2#databases | // See: https://developers.digitalocean.com/documentation/v2#databases | ||||||
| type DatabasesService interface { | type DatabasesService interface { | ||||||
| 	List(context.Context, *ListOptions) ([]Database, *Response, error) | 	List(context.Context, *ListOptions) ([]Database, *Response, error) | ||||||
| @ -55,6 +114,10 @@ type DatabasesService interface { | |||||||
| 	DeleteReplica(context.Context, string, string) (*Response, error) | 	DeleteReplica(context.Context, string, string) (*Response, error) | ||||||
| 	GetEvictionPolicy(context.Context, string) (string, *Response, error) | 	GetEvictionPolicy(context.Context, string) (string, *Response, error) | ||||||
| 	SetEvictionPolicy(context.Context, string, string) (*Response, error) | 	SetEvictionPolicy(context.Context, string, string) (*Response, error) | ||||||
|  | 	GetSQLMode(context.Context, string) (string, *Response, error) | ||||||
|  | 	SetSQLMode(context.Context, string, ...string) (*Response, error) | ||||||
|  | 	GetFirewallRules(context.Context, string) ([]DatabaseFirewallRule, *Response, error) | ||||||
|  | 	UpdateFirewallRules(context.Context, string, *DatabaseUpdateFirewallRulesRequest) (*Response, error) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // DatabasesServiceOp handles communication with the Databases related methods | // DatabasesServiceOp handles communication with the Databases related methods | ||||||
| @ -105,6 +168,12 @@ type DatabaseUser struct { | |||||||
| 	Name          string                     `json:"name,omitempty"` | 	Name          string                     `json:"name,omitempty"` | ||||||
| 	Role          string                     `json:"role,omitempty"` | 	Role          string                     `json:"role,omitempty"` | ||||||
| 	Password      string                     `json:"password,omitempty"` | 	Password      string                     `json:"password,omitempty"` | ||||||
|  | 	MySQLSettings *DatabaseMySQLUserSettings `json:"mysql_settings,omitempty"` | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // DatabaseMySQLUserSettings contains MySQL-specific user settings | ||||||
|  | type DatabaseMySQLUserSettings struct { | ||||||
|  | 	AuthPlugin string `json:"auth_plugin"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // DatabaseMaintenanceWindow represents the maintenance_window of a database | // DatabaseMaintenanceWindow represents the maintenance_window of a database | ||||||
| @ -195,6 +264,7 @@ type DatabaseCreatePoolRequest struct { | |||||||
| // DatabaseCreateUserRequest is used to create a new database user | // DatabaseCreateUserRequest is used to create a new database user | ||||||
| type DatabaseCreateUserRequest struct { | type DatabaseCreateUserRequest struct { | ||||||
| 	Name          string                     `json:"name"` | 	Name          string                     `json:"name"` | ||||||
|  | 	MySQLSettings *DatabaseMySQLUserSettings `json:"mysql_settings,omitempty"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // DatabaseCreateDBRequest is used to create a new engine-specific database within the cluster | // DatabaseCreateDBRequest is used to create a new engine-specific database within the cluster | ||||||
| @ -211,6 +281,20 @@ type DatabaseCreateReplicaRequest struct { | |||||||
| 	Tags               []string `json:"tags,omitempty"` | 	Tags               []string `json:"tags,omitempty"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // DatabaseUpdateFirewallRulesRequest is used to set the firewall rules for a database | ||||||
|  | type DatabaseUpdateFirewallRulesRequest struct { | ||||||
|  | 	Rules []*DatabaseFirewallRule `json:"rules"` | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // DatabaseFirewallRule is a rule describing an inbound source to a database | ||||||
|  | type DatabaseFirewallRule struct { | ||||||
|  | 	UUID        string    `json:"uuid"` | ||||||
|  | 	ClusterUUID string    `json:"cluster_uuid"` | ||||||
|  | 	Type        string    `json:"type"` | ||||||
|  | 	Value       string    `json:"value"` | ||||||
|  | 	CreatedAt   time.Time `json:"created_at"` | ||||||
|  | } | ||||||
|  | 
 | ||||||
| type databaseUserRoot struct { | type databaseUserRoot struct { | ||||||
| 	User *DatabaseUser `json:"user"` | 	User *DatabaseUser `json:"user"` | ||||||
| } | } | ||||||
| @ -259,6 +343,15 @@ type evictionPolicyRoot struct { | |||||||
| 	EvictionPolicy string `json:"eviction_policy"` | 	EvictionPolicy string `json:"eviction_policy"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | type sqlModeRoot struct { | ||||||
|  | 	SQLMode string `json:"sql_mode"` | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type databaseFirewallRuleRoot struct { | ||||||
|  | 	Rules []DatabaseFirewallRule `json:"rules"` | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // URN returns a URN identifier for the database | ||||||
| func (d Database) URN() string { | func (d Database) URN() string { | ||||||
| 	return ToURN("dbaas", d.ID) | 	return ToURN("dbaas", d.ID) | ||||||
| } | } | ||||||
| @ -642,7 +735,7 @@ func (svc *DatabasesServiceOp) DeleteReplica(ctx context.Context, databaseID, na | |||||||
| 
 | 
 | ||||||
| // GetEvictionPolicy loads the eviction policy for a given Redis cluster. | // GetEvictionPolicy loads the eviction policy for a given Redis cluster. | ||||||
| func (svc *DatabasesServiceOp) GetEvictionPolicy(ctx context.Context, databaseID string) (string, *Response, error) { | func (svc *DatabasesServiceOp) GetEvictionPolicy(ctx context.Context, databaseID string) (string, *Response, error) { | ||||||
| 	path := fmt.Sprintf(evictionPolicyPath, databaseID) | 	path := fmt.Sprintf(databaseEvictionPolicyPath, databaseID) | ||||||
| 	req, err := svc.client.NewRequest(ctx, http.MethodGet, path, nil) | 	req, err := svc.client.NewRequest(ctx, http.MethodGet, path, nil) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return "", nil, err | 		return "", nil, err | ||||||
| @ -656,8 +749,11 @@ func (svc *DatabasesServiceOp) GetEvictionPolicy(ctx context.Context, databaseID | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // SetEvictionPolicy updates the eviction policy for a given Redis cluster. | // SetEvictionPolicy updates the eviction policy for a given Redis cluster. | ||||||
|  | // | ||||||
|  | // The valid eviction policies are documented by the exported string constants | ||||||
|  | // with the prefix `EvictionPolicy`. | ||||||
| func (svc *DatabasesServiceOp) SetEvictionPolicy(ctx context.Context, databaseID, policy string) (*Response, error) { | func (svc *DatabasesServiceOp) SetEvictionPolicy(ctx context.Context, databaseID, policy string) (*Response, error) { | ||||||
| 	path := fmt.Sprintf(evictionPolicyPath, databaseID) | 	path := fmt.Sprintf(databaseEvictionPolicyPath, databaseID) | ||||||
| 	root := &evictionPolicyRoot{EvictionPolicy: policy} | 	root := &evictionPolicyRoot{EvictionPolicy: policy} | ||||||
| 	req, err := svc.client.NewRequest(ctx, http.MethodPut, path, root) | 	req, err := svc.client.NewRequest(ctx, http.MethodPut, path, root) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| @ -669,3 +765,60 @@ func (svc *DatabasesServiceOp) SetEvictionPolicy(ctx context.Context, databaseID | |||||||
| 	} | 	} | ||||||
| 	return resp, nil | 	return resp, nil | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | // GetSQLMode loads the SQL Mode settings for a given MySQL cluster. | ||||||
|  | func (svc *DatabasesServiceOp) GetSQLMode(ctx context.Context, databaseID string) (string, *Response, error) { | ||||||
|  | 	path := fmt.Sprintf(databaseSQLModePath, databaseID) | ||||||
|  | 	req, err := svc.client.NewRequest(ctx, http.MethodGet, path, nil) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return "", nil, err | ||||||
|  | 	} | ||||||
|  | 	root := &sqlModeRoot{} | ||||||
|  | 	resp, err := svc.client.Do(ctx, req, root) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return "", resp, err | ||||||
|  | 	} | ||||||
|  | 	return root.SQLMode, resp, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // SetSQLMode updates the SQL Mode settings for a given MySQL cluster. | ||||||
|  | func (svc *DatabasesServiceOp) SetSQLMode(ctx context.Context, databaseID string, sqlModes ...string) (*Response, error) { | ||||||
|  | 	path := fmt.Sprintf(databaseSQLModePath, databaseID) | ||||||
|  | 	root := &sqlModeRoot{SQLMode: strings.Join(sqlModes, ",")} | ||||||
|  | 	req, err := svc.client.NewRequest(ctx, http.MethodPut, path, root) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	resp, err := svc.client.Do(ctx, req, nil) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return resp, err | ||||||
|  | 	} | ||||||
|  | 	return resp, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // GetFirewallRules loads the inbound sources for a given cluster. | ||||||
|  | func (svc *DatabasesServiceOp) GetFirewallRules(ctx context.Context, databaseID string) ([]DatabaseFirewallRule, *Response, error) { | ||||||
|  | 	path := fmt.Sprintf(databaseFirewallRulesPath, databaseID) | ||||||
|  | 	root := new(databaseFirewallRuleRoot) | ||||||
|  | 	req, err := svc.client.NewRequest(ctx, http.MethodGet, path, nil) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, nil, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	resp, err := svc.client.Do(ctx, req, root) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, resp, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return root.Rules, resp, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // UpdateFirewallRules sets the inbound sources for a given cluster. | ||||||
|  | func (svc *DatabasesServiceOp) UpdateFirewallRules(ctx context.Context, databaseID string, firewallRulesReq *DatabaseUpdateFirewallRulesRequest) (*Response, error) { | ||||||
|  | 	path := fmt.Sprintf(databaseFirewallRulesPath, databaseID) | ||||||
|  | 	req, err := svc.client.NewRequest(ctx, http.MethodPut, path, firewallRulesReq) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	return svc.client.Do(ctx, req, nil) | ||||||
|  | } | ||||||
|  | |||||||
							
								
								
									
										11
									
								
								vendor/github.com/digitalocean/godo/doc.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										11
									
								
								vendor/github.com/digitalocean/godo/doc.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -1,11 +1,2 @@ | |||||||
| // Package godo is the DigtalOcean API v2 client for Go | // Package godo is the DigtalOcean API v2 client for Go. | ||||||
| // |  | ||||||
| // Databases |  | ||||||
| // |  | ||||||
| // The Databases service provides access to the DigitalOcean managed database |  | ||||||
| // suite of products. Customers can create new database clusters, migrate them |  | ||||||
| // between regions, create replicas and interact with their configurations. |  | ||||||
| // Each database service is refered to as a Database. A SQL database service |  | ||||||
| // can have multiple databases residing in the system. To help make these |  | ||||||
| // entities distinct from Databases in godo, we refer to them here as DatabaseDBs. |  | ||||||
| package godo | package godo | ||||||
|  | |||||||
							
								
								
									
										4
									
								
								vendor/github.com/digitalocean/godo/domains.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/digitalocean/godo/domains.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -47,6 +47,7 @@ type domainRoot struct { | |||||||
| type domainsRoot struct { | type domainsRoot struct { | ||||||
| 	Domains []Domain `json:"domains"` | 	Domains []Domain `json:"domains"` | ||||||
| 	Links   *Links   `json:"links"` | 	Links   *Links   `json:"links"` | ||||||
|  | 	Meta    *Meta    `json:"meta"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // DomainCreateRequest respresents a request to create a domain. | // DomainCreateRequest respresents a request to create a domain. | ||||||
| @ -122,6 +123,9 @@ func (s DomainsServiceOp) List(ctx context.Context, opt *ListOptions) ([]Domain, | |||||||
| 	if l := root.Links; l != nil { | 	if l := root.Links; l != nil { | ||||||
| 		resp.Links = l | 		resp.Links = l | ||||||
| 	} | 	} | ||||||
|  | 	if m := root.Meta; m != nil { | ||||||
|  | 		resp.Meta = m | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	return root.Domains, resp, err | 	return root.Domains, resp, err | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										19
									
								
								vendor/github.com/digitalocean/godo/droplets.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										19
									
								
								vendor/github.com/digitalocean/godo/droplets.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -139,21 +139,25 @@ type dropletRoot struct { | |||||||
| type dropletsRoot struct { | type dropletsRoot struct { | ||||||
| 	Droplets []Droplet `json:"droplets"` | 	Droplets []Droplet `json:"droplets"` | ||||||
| 	Links    *Links    `json:"links"` | 	Links    *Links    `json:"links"` | ||||||
|  | 	Meta     *Meta     `json:"meta"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type kernelsRoot struct { | type kernelsRoot struct { | ||||||
| 	Kernels []Kernel `json:"kernels,omitempty"` | 	Kernels []Kernel `json:"kernels,omitempty"` | ||||||
| 	Links   *Links   `json:"links"` | 	Links   *Links   `json:"links"` | ||||||
|  | 	Meta    *Meta    `json:"meta"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type dropletSnapshotsRoot struct { | type dropletSnapshotsRoot struct { | ||||||
| 	Snapshots []Image `json:"snapshots,omitempty"` | 	Snapshots []Image `json:"snapshots,omitempty"` | ||||||
| 	Links     *Links  `json:"links"` | 	Links     *Links  `json:"links"` | ||||||
|  | 	Meta      *Meta   `json:"meta"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type backupsRoot struct { | type backupsRoot struct { | ||||||
| 	Backups []Image `json:"backups,omitempty"` | 	Backups []Image `json:"backups,omitempty"` | ||||||
| 	Links   *Links  `json:"links"` | 	Links   *Links  `json:"links"` | ||||||
|  | 	Meta    *Meta   `json:"meta"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // DropletCreateImage identifies an image for the create request. It prefers slug over ID. | // DropletCreateImage identifies an image for the create request. It prefers slug over ID. | ||||||
| @ -295,6 +299,9 @@ func (s *DropletsServiceOp) list(ctx context.Context, path string) ([]Droplet, * | |||||||
| 	if l := root.Links; l != nil { | 	if l := root.Links; l != nil { | ||||||
| 		resp.Links = l | 		resp.Links = l | ||||||
| 	} | 	} | ||||||
|  | 	if m := root.Meta; m != nil { | ||||||
|  | 		resp.Meta = m | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	return root.Droplets, resp, err | 	return root.Droplets, resp, err | ||||||
| } | } | ||||||
| @ -449,6 +456,9 @@ func (s *DropletsServiceOp) Kernels(ctx context.Context, dropletID int, opt *Lis | |||||||
| 	if l := root.Links; l != nil { | 	if l := root.Links; l != nil { | ||||||
| 		resp.Links = l | 		resp.Links = l | ||||||
| 	} | 	} | ||||||
|  | 	if m := root.Meta; m != nil { | ||||||
|  | 		resp.Meta = m | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	return root.Kernels, resp, err | 	return root.Kernels, resp, err | ||||||
| } | } | ||||||
| @ -478,6 +488,9 @@ func (s *DropletsServiceOp) Actions(ctx context.Context, dropletID int, opt *Lis | |||||||
| 	if l := root.Links; l != nil { | 	if l := root.Links; l != nil { | ||||||
| 		resp.Links = l | 		resp.Links = l | ||||||
| 	} | 	} | ||||||
|  | 	if m := root.Meta; m != nil { | ||||||
|  | 		resp.Meta = m | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	return root.Actions, resp, err | 	return root.Actions, resp, err | ||||||
| } | } | ||||||
| @ -507,6 +520,9 @@ func (s *DropletsServiceOp) Backups(ctx context.Context, dropletID int, opt *Lis | |||||||
| 	if l := root.Links; l != nil { | 	if l := root.Links; l != nil { | ||||||
| 		resp.Links = l | 		resp.Links = l | ||||||
| 	} | 	} | ||||||
|  | 	if m := root.Meta; m != nil { | ||||||
|  | 		resp.Meta = m | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	return root.Backups, resp, err | 	return root.Backups, resp, err | ||||||
| } | } | ||||||
| @ -536,6 +552,9 @@ func (s *DropletsServiceOp) Snapshots(ctx context.Context, dropletID int, opt *L | |||||||
| 	if l := root.Links; l != nil { | 	if l := root.Links; l != nil { | ||||||
| 		resp.Links = l | 		resp.Links = l | ||||||
| 	} | 	} | ||||||
|  | 	if m := root.Meta; m != nil { | ||||||
|  | 		resp.Meta = m | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	return root.Snapshots, resp, err | 	return root.Snapshots, resp, err | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										4
									
								
								vendor/github.com/digitalocean/godo/firewalls.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/digitalocean/godo/firewalls.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -237,6 +237,7 @@ type firewallRoot struct { | |||||||
| type firewallsRoot struct { | type firewallsRoot struct { | ||||||
| 	Firewalls []Firewall `json:"firewalls"` | 	Firewalls []Firewall `json:"firewalls"` | ||||||
| 	Links     *Links     `json:"links"` | 	Links     *Links     `json:"links"` | ||||||
|  | 	Meta      *Meta      `json:"meta"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (fw *FirewallsServiceOp) createAndDoReq(ctx context.Context, method, path string, v interface{}) (*Response, error) { | func (fw *FirewallsServiceOp) createAndDoReq(ctx context.Context, method, path string, v interface{}) (*Response, error) { | ||||||
| @ -262,6 +263,9 @@ func (fw *FirewallsServiceOp) listHelper(ctx context.Context, path string) ([]Fi | |||||||
| 	if l := root.Links; l != nil { | 	if l := root.Links; l != nil { | ||||||
| 		resp.Links = l | 		resp.Links = l | ||||||
| 	} | 	} | ||||||
|  | 	if m := root.Meta; m != nil { | ||||||
|  | 		resp.Meta = m | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	return root.Firewalls, resp, err | 	return root.Firewalls, resp, err | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										4
									
								
								vendor/github.com/digitalocean/godo/floating_ips.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/digitalocean/godo/floating_ips.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -44,6 +44,7 @@ func (f FloatingIP) URN() string { | |||||||
| type floatingIPsRoot struct { | type floatingIPsRoot struct { | ||||||
| 	FloatingIPs []FloatingIP `json:"floating_ips"` | 	FloatingIPs []FloatingIP `json:"floating_ips"` | ||||||
| 	Links       *Links       `json:"links"` | 	Links       *Links       `json:"links"` | ||||||
|  | 	Meta        *Meta        `json:"meta"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type floatingIPRoot struct { | type floatingIPRoot struct { | ||||||
| @ -80,6 +81,9 @@ func (f *FloatingIPsServiceOp) List(ctx context.Context, opt *ListOptions) ([]Fl | |||||||
| 	if l := root.Links; l != nil { | 	if l := root.Links; l != nil { | ||||||
| 		resp.Links = l | 		resp.Links = l | ||||||
| 	} | 	} | ||||||
|  | 	if m := root.Meta; m != nil { | ||||||
|  | 		resp.Meta = m | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	return root.FloatingIPs, resp, err | 	return root.FloatingIPs, resp, err | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										13
									
								
								vendor/github.com/digitalocean/godo/godo.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										13
									
								
								vendor/github.com/digitalocean/godo/godo.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -17,7 +17,7 @@ import ( | |||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| const ( | const ( | ||||||
| 	libraryVersion = "1.22.0" | 	libraryVersion = "1.29.0" | ||||||
| 	defaultBaseURL = "https://api.digitalocean.com/" | 	defaultBaseURL = "https://api.digitalocean.com/" | ||||||
| 	userAgent      = "godo/" + libraryVersion | 	userAgent      = "godo/" + libraryVersion | ||||||
| 	mediaType      = "application/json" | 	mediaType      = "application/json" | ||||||
| @ -45,6 +45,7 @@ type Client struct { | |||||||
| 	// Services used for communicating with the API | 	// Services used for communicating with the API | ||||||
| 	Account           AccountService | 	Account           AccountService | ||||||
| 	Actions           ActionsService | 	Actions           ActionsService | ||||||
|  | 	Balance           BalanceService | ||||||
| 	CDNs              CDNService | 	CDNs              CDNService | ||||||
| 	Domains           DomainsService | 	Domains           DomainsService | ||||||
| 	Droplets          DropletsService | 	Droplets          DropletsService | ||||||
| @ -65,6 +66,7 @@ type Client struct { | |||||||
| 	Firewalls         FirewallsService | 	Firewalls         FirewallsService | ||||||
| 	Projects          ProjectsService | 	Projects          ProjectsService | ||||||
| 	Kubernetes        KubernetesService | 	Kubernetes        KubernetesService | ||||||
|  | 	Registry          RegistryService | ||||||
| 	Databases         DatabasesService | 	Databases         DatabasesService | ||||||
| 	VPCs              VPCsService | 	VPCs              VPCsService | ||||||
| 
 | 
 | ||||||
| @ -93,6 +95,9 @@ type Response struct { | |||||||
| 	// request body and not the header. | 	// request body and not the header. | ||||||
| 	Links *Links | 	Links *Links | ||||||
| 
 | 
 | ||||||
|  | 	// Meta describes generic information about the response. | ||||||
|  | 	Meta *Meta | ||||||
|  | 
 | ||||||
| 	// Monitoring URI | 	// Monitoring URI | ||||||
| 	Monitor string | 	Monitor string | ||||||
| 
 | 
 | ||||||
| @ -161,6 +166,7 @@ func NewClient(httpClient *http.Client) *Client { | |||||||
| 	c := &Client{client: httpClient, BaseURL: baseURL, UserAgent: userAgent} | 	c := &Client{client: httpClient, BaseURL: baseURL, UserAgent: userAgent} | ||||||
| 	c.Account = &AccountServiceOp{client: c} | 	c.Account = &AccountServiceOp{client: c} | ||||||
| 	c.Actions = &ActionsServiceOp{client: c} | 	c.Actions = &ActionsServiceOp{client: c} | ||||||
|  | 	c.Balance = &BalanceServiceOp{client: c} | ||||||
| 	c.CDNs = &CDNServiceOp{client: c} | 	c.CDNs = &CDNServiceOp{client: c} | ||||||
| 	c.Certificates = &CertificatesServiceOp{client: c} | 	c.Certificates = &CertificatesServiceOp{client: c} | ||||||
| 	c.Domains = &DomainsServiceOp{client: c} | 	c.Domains = &DomainsServiceOp{client: c} | ||||||
| @ -181,6 +187,7 @@ func NewClient(httpClient *http.Client) *Client { | |||||||
| 	c.StorageActions = &StorageActionsServiceOp{client: c} | 	c.StorageActions = &StorageActionsServiceOp{client: c} | ||||||
| 	c.Tags = &TagsServiceOp{client: c} | 	c.Tags = &TagsServiceOp{client: c} | ||||||
| 	c.Kubernetes = &KubernetesServiceOp{client: c} | 	c.Kubernetes = &KubernetesServiceOp{client: c} | ||||||
|  | 	c.Registry = &RegistryServiceOp{client: c} | ||||||
| 	c.Databases = &DatabasesServiceOp{client: c} | 	c.Databases = &DatabasesServiceOp{client: c} | ||||||
| 	c.VPCs = &VPCsServiceOp{client: c} | 	c.VPCs = &VPCsServiceOp{client: c} | ||||||
| 
 | 
 | ||||||
| @ -227,13 +234,11 @@ func SetUserAgent(ua string) ClientOpt { | |||||||
| // BaseURL of the Client. Relative URLS should always be specified without a preceding slash. If specified, the | // BaseURL of the Client. Relative URLS should always be specified without a preceding slash. If specified, the | ||||||
| // value pointed to by body is JSON encoded and included in as the request body. | // value pointed to by body is JSON encoded and included in as the request body. | ||||||
| func (c *Client) NewRequest(ctx context.Context, method, urlStr string, body interface{}) (*http.Request, error) { | func (c *Client) NewRequest(ctx context.Context, method, urlStr string, body interface{}) (*http.Request, error) { | ||||||
| 	rel, err := url.Parse(urlStr) | 	u, err := c.BaseURL.Parse(urlStr) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	u := c.BaseURL.ResolveReference(rel) |  | ||||||
| 
 |  | ||||||
| 	buf := new(bytes.Buffer) | 	buf := new(bytes.Buffer) | ||||||
| 	if body != nil { | 	if body != nil { | ||||||
| 		err = json.NewEncoder(buf).Encode(body) | 		err = json.NewEncoder(buf).Encode(body) | ||||||
|  | |||||||
							
								
								
									
										4
									
								
								vendor/github.com/digitalocean/godo/images.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/digitalocean/godo/images.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -72,6 +72,7 @@ type imageRoot struct { | |||||||
| type imagesRoot struct { | type imagesRoot struct { | ||||||
| 	Images []Image | 	Images []Image | ||||||
| 	Links  *Links `json:"links"` | 	Links  *Links `json:"links"` | ||||||
|  | 	Meta   *Meta  `json:"meta"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type listImageOptions struct { | type listImageOptions struct { | ||||||
| @ -236,6 +237,9 @@ func (s *ImagesServiceOp) list(ctx context.Context, opt *ListOptions, listOpt *l | |||||||
| 	if l := root.Links; l != nil { | 	if l := root.Links; l != nil { | ||||||
| 		resp.Links = l | 		resp.Links = l | ||||||
| 	} | 	} | ||||||
|  | 	if m := root.Meta; m != nil { | ||||||
|  | 		resp.Meta = m | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	return root.Images, resp, err | 	return root.Images, resp, err | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										4
									
								
								vendor/github.com/digitalocean/godo/keys.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/digitalocean/godo/keys.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -46,6 +46,7 @@ type KeyUpdateRequest struct { | |||||||
| type keysRoot struct { | type keysRoot struct { | ||||||
| 	SSHKeys []Key  `json:"ssh_keys"` | 	SSHKeys []Key  `json:"ssh_keys"` | ||||||
| 	Links   *Links `json:"links"` | 	Links   *Links `json:"links"` | ||||||
|  | 	Meta    *Meta  `json:"meta"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type keyRoot struct { | type keyRoot struct { | ||||||
| @ -83,6 +84,9 @@ func (s *KeysServiceOp) List(ctx context.Context, opt *ListOptions) ([]Key, *Res | |||||||
| 	if l := root.Links; l != nil { | 	if l := root.Links; l != nil { | ||||||
| 		resp.Links = l | 		resp.Links = l | ||||||
| 	} | 	} | ||||||
|  | 	if m := root.Meta; m != nil { | ||||||
|  | 		resp.Meta = m | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	return root.SSHKeys, resp, err | 	return root.SSHKeys, resp, err | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										9
									
								
								vendor/github.com/digitalocean/godo/kubernetes.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										9
									
								
								vendor/github.com/digitalocean/godo/kubernetes.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -354,6 +354,7 @@ type KubernetesRegion struct { | |||||||
| type kubernetesClustersRoot struct { | type kubernetesClustersRoot struct { | ||||||
| 	Clusters []*KubernetesCluster `json:"kubernetes_clusters,omitempty"` | 	Clusters []*KubernetesCluster `json:"kubernetes_clusters,omitempty"` | ||||||
| 	Links    *Links               `json:"links,omitempty"` | 	Links    *Links               `json:"links,omitempty"` | ||||||
|  | 	Meta     *Meta                `json:"meta"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type kubernetesClusterRoot struct { | type kubernetesClusterRoot struct { | ||||||
| @ -469,6 +470,14 @@ func (svc *KubernetesServiceOp) List(ctx context.Context, opts *ListOptions) ([] | |||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, resp, err | 		return nil, resp, err | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
|  | 	if l := root.Links; l != nil { | ||||||
|  | 		resp.Links = l | ||||||
|  | 	} | ||||||
|  | 	if m := root.Meta; m != nil { | ||||||
|  | 		resp.Meta = m | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	return root.Clusters, resp, nil | 	return root.Clusters, resp, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										2
									
								
								vendor/github.com/digitalocean/godo/links.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/digitalocean/godo/links.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -59,7 +59,7 @@ func (l *Links) IsLastPage() bool { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (p *Pages) isLast() bool { | func (p *Pages) isLast() bool { | ||||||
| 	return p.Last == "" | 	return p.Next == "" | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func pageForURL(urlText string) (int, error) { | func pageForURL(urlText string) (int, error) { | ||||||
|  | |||||||
							
								
								
									
										4
									
								
								vendor/github.com/digitalocean/godo/load_balancers.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/digitalocean/godo/load_balancers.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -167,6 +167,7 @@ func (l dropletIDsRequest) String() string { | |||||||
| type loadBalancersRoot struct { | type loadBalancersRoot struct { | ||||||
| 	LoadBalancers []LoadBalancer `json:"load_balancers"` | 	LoadBalancers []LoadBalancer `json:"load_balancers"` | ||||||
| 	Links         *Links         `json:"links"` | 	Links         *Links         `json:"links"` | ||||||
|  | 	Meta          *Meta          `json:"meta"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type loadBalancerRoot struct { | type loadBalancerRoot struct { | ||||||
| @ -218,6 +219,9 @@ func (l *LoadBalancersServiceOp) List(ctx context.Context, opt *ListOptions) ([] | |||||||
| 	if l := root.Links; l != nil { | 	if l := root.Links; l != nil { | ||||||
| 		resp.Links = l | 		resp.Links = l | ||||||
| 	} | 	} | ||||||
|  | 	if m := root.Meta; m != nil { | ||||||
|  | 		resp.Meta = m | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	return root.LoadBalancers, resp, err | 	return root.LoadBalancers, resp, err | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										6
									
								
								vendor/github.com/digitalocean/godo/meta.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								vendor/github.com/digitalocean/godo/meta.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | |||||||
|  | package godo | ||||||
|  | 
 | ||||||
|  | // Meta describes generic information about a response. | ||||||
|  | type Meta struct { | ||||||
|  | 	Total int `json:"total"` | ||||||
|  | } | ||||||
							
								
								
									
										8
									
								
								vendor/github.com/digitalocean/godo/projects.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								vendor/github.com/digitalocean/godo/projects.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -125,6 +125,7 @@ type ProjectResourceLinks struct { | |||||||
| type projectsRoot struct { | type projectsRoot struct { | ||||||
| 	Projects []Project `json:"projects"` | 	Projects []Project `json:"projects"` | ||||||
| 	Links    *Links    `json:"links"` | 	Links    *Links    `json:"links"` | ||||||
|  | 	Meta     *Meta     `json:"meta"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type projectRoot struct { | type projectRoot struct { | ||||||
| @ -134,6 +135,7 @@ type projectRoot struct { | |||||||
| type projectResourcesRoot struct { | type projectResourcesRoot struct { | ||||||
| 	Resources []ProjectResource `json:"resources"` | 	Resources []ProjectResource `json:"resources"` | ||||||
| 	Links     *Links            `json:"links,omitempty"` | 	Links     *Links            `json:"links,omitempty"` | ||||||
|  | 	Meta      *Meta             `json:"meta"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| var _ ProjectsService = &ProjectsServiceOp{} | var _ ProjectsService = &ProjectsServiceOp{} | ||||||
| @ -158,6 +160,9 @@ func (p *ProjectsServiceOp) List(ctx context.Context, opts *ListOptions) ([]Proj | |||||||
| 	if l := root.Links; l != nil { | 	if l := root.Links; l != nil { | ||||||
| 		resp.Links = l | 		resp.Links = l | ||||||
| 	} | 	} | ||||||
|  | 	if m := root.Meta; m != nil { | ||||||
|  | 		resp.Meta = m | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	return root.Projects, resp, err | 	return root.Projects, resp, err | ||||||
| } | } | ||||||
| @ -238,6 +243,9 @@ func (p *ProjectsServiceOp) ListResources(ctx context.Context, projectID string, | |||||||
| 	if l := root.Links; l != nil { | 	if l := root.Links; l != nil { | ||||||
| 		resp.Links = l | 		resp.Links = l | ||||||
| 	} | 	} | ||||||
|  | 	if m := root.Meta; m != nil { | ||||||
|  | 		resp.Meta = m | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	return root.Resources, resp, err | 	return root.Resources, resp, err | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										4
									
								
								vendor/github.com/digitalocean/godo/regions.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/digitalocean/godo/regions.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -32,6 +32,7 @@ type Region struct { | |||||||
| type regionsRoot struct { | type regionsRoot struct { | ||||||
| 	Regions []Region | 	Regions []Region | ||||||
| 	Links   *Links `json:"links"` | 	Links   *Links `json:"links"` | ||||||
|  | 	Meta    *Meta  `json:"meta"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (r Region) String() string { | func (r Region) String() string { | ||||||
| @ -59,6 +60,9 @@ func (s *RegionsServiceOp) List(ctx context.Context, opt *ListOptions) ([]Region | |||||||
| 	if l := root.Links; l != nil { | 	if l := root.Links; l != nil { | ||||||
| 		resp.Links = l | 		resp.Links = l | ||||||
| 	} | 	} | ||||||
|  | 	if m := root.Meta; m != nil { | ||||||
|  | 		resp.Meta = m | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	return root.Regions, resp, err | 	return root.Regions, resp, err | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										119
									
								
								vendor/github.com/digitalocean/godo/registry.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								vendor/github.com/digitalocean/godo/registry.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,119 @@ | |||||||
|  | package godo | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"bytes" | ||||||
|  | 	"context" | ||||||
|  | 	"fmt" | ||||||
|  | 	"net/http" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | const ( | ||||||
|  | 	registryPath = "/v2/registry" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // RegistryService is an interface for interfacing with the Registry endpoints | ||||||
|  | // of the DigitalOcean API. | ||||||
|  | // See: https://developers.digitalocean.com/documentation/v2#registry | ||||||
|  | type RegistryService interface { | ||||||
|  | 	Create(context.Context, *RegistryCreateRequest) (*Registry, *Response, error) | ||||||
|  | 	Get(context.Context) (*Registry, *Response, error) | ||||||
|  | 	Delete(context.Context) (*Response, error) | ||||||
|  | 	DockerCredentials(context.Context, *RegistryDockerCredentialsRequest) (*DockerCredentials, *Response, error) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | var _ RegistryService = &RegistryServiceOp{} | ||||||
|  | 
 | ||||||
|  | // RegistryServiceOp handles communication with Registry methods of the DigitalOcean API. | ||||||
|  | type RegistryServiceOp struct { | ||||||
|  | 	client *Client | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // RegistryCreateRequest represents a request to create a registry. | ||||||
|  | type RegistryCreateRequest struct { | ||||||
|  | 	Name string `json:"name,omitempty"` | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // RegistryDockerCredentialsRequest represents a request to retrieve docker | ||||||
|  | // credentials for a registry. | ||||||
|  | type RegistryDockerCredentialsRequest struct { | ||||||
|  | 	ReadWrite bool `json:"read_write"` | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Registry represents a registry. | ||||||
|  | type Registry struct { | ||||||
|  | 	Name string `json:"name,omitempty"` | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type registryRoot struct { | ||||||
|  | 	Registry *Registry `json:"registry,omitempty"` | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Get retrieves the details of a Registry. | ||||||
|  | func (svc *RegistryServiceOp) Get(ctx context.Context) (*Registry, *Response, error) { | ||||||
|  | 	req, err := svc.client.NewRequest(ctx, http.MethodGet, registryPath, nil) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, nil, err | ||||||
|  | 	} | ||||||
|  | 	root := new(registryRoot) | ||||||
|  | 	resp, err := svc.client.Do(ctx, req, root) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, resp, err | ||||||
|  | 	} | ||||||
|  | 	return root.Registry, resp, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Create creates a registry. | ||||||
|  | func (svc *RegistryServiceOp) Create(ctx context.Context, create *RegistryCreateRequest) (*Registry, *Response, error) { | ||||||
|  | 	req, err := svc.client.NewRequest(ctx, http.MethodPost, registryPath, create) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, nil, err | ||||||
|  | 	} | ||||||
|  | 	root := new(registryRoot) | ||||||
|  | 	resp, err := svc.client.Do(ctx, req, root) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, resp, err | ||||||
|  | 	} | ||||||
|  | 	return root.Registry, resp, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Delete deletes a registry. There is no way to recover a registry once it has | ||||||
|  | // been destroyed. | ||||||
|  | func (svc *RegistryServiceOp) Delete(ctx context.Context) (*Response, error) { | ||||||
|  | 	req, err := svc.client.NewRequest(ctx, http.MethodDelete, registryPath, nil) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	resp, err := svc.client.Do(ctx, req, nil) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return resp, err | ||||||
|  | 	} | ||||||
|  | 	return resp, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // DockerCredentials is the content of a Docker config file | ||||||
|  | // that is used by the docker CLI | ||||||
|  | // See: https://docs.docker.com/engine/reference/commandline/cli/#configjson-properties | ||||||
|  | type DockerCredentials struct { | ||||||
|  | 	DockerConfigJSON []byte | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // DockerCredentials retrieves a Docker config file containing the registry's credentials. | ||||||
|  | func (svc *RegistryServiceOp) DockerCredentials(ctx context.Context, request *RegistryDockerCredentialsRequest) (*DockerCredentials, *Response, error) { | ||||||
|  | 	path := fmt.Sprintf("%s/%s?read_write=%t", registryPath, "docker-credentials", request.ReadWrite) | ||||||
|  | 
 | ||||||
|  | 	req, err := svc.client.NewRequest(ctx, http.MethodGet, path, nil) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, nil, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	var buf bytes.Buffer | ||||||
|  | 	resp, err := svc.client.Do(ctx, req, &buf) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, resp, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	dc := &DockerCredentials{ | ||||||
|  | 		DockerConfigJSON: buf.Bytes(), | ||||||
|  | 	} | ||||||
|  | 	return dc, resp, nil | ||||||
|  | } | ||||||
							
								
								
									
										4
									
								
								vendor/github.com/digitalocean/godo/sizes.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/digitalocean/godo/sizes.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -40,6 +40,7 @@ func (s Size) String() string { | |||||||
| type sizesRoot struct { | type sizesRoot struct { | ||||||
| 	Sizes []Size | 	Sizes []Size | ||||||
| 	Links *Links `json:"links"` | 	Links *Links `json:"links"` | ||||||
|  | 	Meta  *Meta  `json:"meta"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // List all images | // List all images | ||||||
| @ -63,6 +64,9 @@ func (s *SizesServiceOp) List(ctx context.Context, opt *ListOptions) ([]Size, *R | |||||||
| 	if l := root.Links; l != nil { | 	if l := root.Links; l != nil { | ||||||
| 		resp.Links = l | 		resp.Links = l | ||||||
| 	} | 	} | ||||||
|  | 	if m := root.Meta; m != nil { | ||||||
|  | 		resp.Meta = m | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	return root.Sizes, resp, err | 	return root.Sizes, resp, err | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										1
									
								
								vendor/github.com/digitalocean/godo/snapshots.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								vendor/github.com/digitalocean/godo/snapshots.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -47,6 +47,7 @@ type snapshotRoot struct { | |||||||
| type snapshotsRoot struct { | type snapshotsRoot struct { | ||||||
| 	Snapshots []Snapshot `json:"snapshots"` | 	Snapshots []Snapshot `json:"snapshots"` | ||||||
| 	Links     *Links     `json:"links,omitempty"` | 	Links     *Links     `json:"links,omitempty"` | ||||||
|  | 	Meta      *Meta      `json:"meta,omitempty"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type listSnapshotOptions struct { | type listSnapshotOptions struct { | ||||||
|  | |||||||
							
								
								
									
										9
									
								
								vendor/github.com/digitalocean/godo/storage.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										9
									
								
								vendor/github.com/digitalocean/godo/storage.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -15,7 +15,7 @@ const ( | |||||||
| 
 | 
 | ||||||
| // StorageService is an interface for interfacing with the storage | // StorageService is an interface for interfacing with the storage | ||||||
| // endpoints of the Digital Ocean API. | // endpoints of the Digital Ocean API. | ||||||
| // See: https://developers.digitalocean.com/documentation/v2#storage | // See: https://developers.digitalocean.com/documentation/v2/#block-storage | ||||||
| type StorageService interface { | type StorageService interface { | ||||||
| 	ListVolumes(context.Context, *ListVolumeParams) ([]Volume, *Response, error) | 	ListVolumes(context.Context, *ListVolumeParams) ([]Volume, *Response, error) | ||||||
| 	GetVolume(context.Context, string) (*Volume, *Response, error) | 	GetVolume(context.Context, string) (*Volume, *Response, error) | ||||||
| @ -67,6 +67,7 @@ func (f Volume) URN() string { | |||||||
| type storageVolumesRoot struct { | type storageVolumesRoot struct { | ||||||
| 	Volumes []Volume `json:"volumes"` | 	Volumes []Volume `json:"volumes"` | ||||||
| 	Links   *Links   `json:"links"` | 	Links   *Links   `json:"links"` | ||||||
|  | 	Meta    *Meta    `json:"meta"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type storageVolumeRoot struct { | type storageVolumeRoot struct { | ||||||
| @ -122,6 +123,9 @@ func (svc *StorageServiceOp) ListVolumes(ctx context.Context, params *ListVolume | |||||||
| 	if l := root.Links; l != nil { | 	if l := root.Links; l != nil { | ||||||
| 		resp.Links = l | 		resp.Links = l | ||||||
| 	} | 	} | ||||||
|  | 	if m := root.Meta; m != nil { | ||||||
|  | 		resp.Meta = m | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	return root.Volumes, resp, nil | 	return root.Volumes, resp, nil | ||||||
| } | } | ||||||
| @ -203,6 +207,9 @@ func (svc *StorageServiceOp) ListSnapshots(ctx context.Context, volumeID string, | |||||||
| 	if l := root.Links; l != nil { | 	if l := root.Links; l != nil { | ||||||
| 		resp.Links = l | 		resp.Links = l | ||||||
| 	} | 	} | ||||||
|  | 	if m := root.Meta; m != nil { | ||||||
|  | 		resp.Meta = m | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	return root.Snapshots, resp, nil | 	return root.Snapshots, resp, nil | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										3
									
								
								vendor/github.com/digitalocean/godo/storage_actions.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								vendor/github.com/digitalocean/godo/storage_actions.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -120,6 +120,9 @@ func (s *StorageActionsServiceOp) list(ctx context.Context, path string) ([]Acti | |||||||
| 	if l := root.Links; l != nil { | 	if l := root.Links; l != nil { | ||||||
| 		resp.Links = l | 		resp.Links = l | ||||||
| 	} | 	} | ||||||
|  | 	if m := root.Meta; m != nil { | ||||||
|  | 		resp.Meta = m | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	return root.Actions, resp, err | 	return root.Actions, resp, err | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										16
									
								
								vendor/github.com/digitalocean/godo/tags.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										16
									
								
								vendor/github.com/digitalocean/godo/tags.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -42,7 +42,9 @@ const ( | |||||||
| 	// LoadBalancerResourceType holds the string representing our ResourceType of LoadBalancer. | 	// LoadBalancerResourceType holds the string representing our ResourceType of LoadBalancer. | ||||||
| 	LoadBalancerResourceType ResourceType = "load_balancer" | 	LoadBalancerResourceType ResourceType = "load_balancer" | ||||||
| 	// VolumeSnapshotResourceType holds the string representing our ResourceType for storage Snapshots. | 	// VolumeSnapshotResourceType holds the string representing our ResourceType for storage Snapshots. | ||||||
| 	VolumeSnapshotResourceType ResourceType = "volumesnapshot" | 	VolumeSnapshotResourceType ResourceType = "volume_snapshot" | ||||||
|  | 	// DatabaseResourceType holds the string representing our ResourceType of Database. | ||||||
|  | 	DatabaseResourceType ResourceType = "database" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // Resource represent a single resource for associating/disassociating with tags | // Resource represent a single resource for associating/disassociating with tags | ||||||
| @ -58,6 +60,8 @@ type TaggedResources struct { | |||||||
| 	Droplets        *TaggedDropletsResources        `json:"droplets,omitempty"` | 	Droplets        *TaggedDropletsResources        `json:"droplets,omitempty"` | ||||||
| 	Images          *TaggedImagesResources          `json:"images"` | 	Images          *TaggedImagesResources          `json:"images"` | ||||||
| 	Volumes         *TaggedVolumesResources         `json:"volumes"` | 	Volumes         *TaggedVolumesResources         `json:"volumes"` | ||||||
|  | 	VolumeSnapshots *TaggedVolumeSnapshotsResources `json:"volume_snapshots"` | ||||||
|  | 	Databases       *TaggedDatabasesResources       `json:"databases"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // TaggedDropletsResources represent the droplet resources a tag is attached to | // TaggedDropletsResources represent the droplet resources a tag is attached to | ||||||
| @ -79,6 +83,12 @@ type TaggedImagesResources TaggedResourcesData | |||||||
| // TaggedVolumesResources represent the volume resources a tag is attached to | // TaggedVolumesResources represent the volume resources a tag is attached to | ||||||
| type TaggedVolumesResources TaggedResourcesData | type TaggedVolumesResources TaggedResourcesData | ||||||
| 
 | 
 | ||||||
|  | // TaggedVolumeSnapshotsResources represent the volume snapshot resources a tag is attached to | ||||||
|  | type TaggedVolumeSnapshotsResources TaggedResourcesData | ||||||
|  | 
 | ||||||
|  | // TaggedDatabasesResources represent the database resources a tag is attached to | ||||||
|  | type TaggedDatabasesResources TaggedResourcesData | ||||||
|  | 
 | ||||||
| // Tag represent DigitalOcean tag | // Tag represent DigitalOcean tag | ||||||
| type Tag struct { | type Tag struct { | ||||||
| 	Name      string           `json:"name,omitempty"` | 	Name      string           `json:"name,omitempty"` | ||||||
| @ -103,6 +113,7 @@ type UntagResourcesRequest struct { | |||||||
| type tagsRoot struct { | type tagsRoot struct { | ||||||
| 	Tags  []Tag  `json:"tags"` | 	Tags  []Tag  `json:"tags"` | ||||||
| 	Links *Links `json:"links"` | 	Links *Links `json:"links"` | ||||||
|  | 	Meta  *Meta  `json:"meta"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type tagRoot struct { | type tagRoot struct { | ||||||
| @ -131,6 +142,9 @@ func (s *TagsServiceOp) List(ctx context.Context, opt *ListOptions) ([]Tag, *Res | |||||||
| 	if l := root.Links; l != nil { | 	if l := root.Links; l != nil { | ||||||
| 		resp.Links = l | 		resp.Links = l | ||||||
| 	} | 	} | ||||||
|  | 	if m := root.Meta; m != nil { | ||||||
|  | 		resp.Meta = m | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	return root.Tags, resp, err | 	return root.Tags, resp, err | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										4
									
								
								vendor/github.com/digitalocean/godo/vpcs.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/digitalocean/godo/vpcs.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -63,6 +63,7 @@ type vpcRoot struct { | |||||||
| type vpcsRoot struct { | type vpcsRoot struct { | ||||||
| 	VPCs  []*VPC `json:"vpcs"` | 	VPCs  []*VPC `json:"vpcs"` | ||||||
| 	Links *Links `json:"links"` | 	Links *Links `json:"links"` | ||||||
|  | 	Meta  *Meta  `json:"meta"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Get returns the details of a Virtual Private Cloud. | // Get returns the details of a Virtual Private Cloud. | ||||||
| @ -118,6 +119,9 @@ func (v *VPCsServiceOp) List(ctx context.Context, opt *ListOptions) ([]*VPC, *Re | |||||||
| 	if l := root.Links; l != nil { | 	if l := root.Links; l != nil { | ||||||
| 		resp.Links = l | 		resp.Links = l | ||||||
| 	} | 	} | ||||||
|  | 	if m := root.Meta; m != nil { | ||||||
|  | 		resp.Meta = m | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	return root.VPCs, resp, nil | 	return root.VPCs, resp, nil | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										5
									
								
								vendor/github.com/golang/protobuf/proto/properties.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								vendor/github.com/golang/protobuf/proto/properties.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -38,7 +38,6 @@ package proto | |||||||
| import ( | import ( | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"log" | 	"log" | ||||||
| 	"os" |  | ||||||
| 	"reflect" | 	"reflect" | ||||||
| 	"sort" | 	"sort" | ||||||
| 	"strconv" | 	"strconv" | ||||||
| @ -194,7 +193,7 @@ func (p *Properties) Parse(s string) { | |||||||
| 	// "bytes,49,opt,name=foo,def=hello!" | 	// "bytes,49,opt,name=foo,def=hello!" | ||||||
| 	fields := strings.Split(s, ",") // breaks def=, but handled below. | 	fields := strings.Split(s, ",") // breaks def=, but handled below. | ||||||
| 	if len(fields) < 2 { | 	if len(fields) < 2 { | ||||||
| 		fmt.Fprintf(os.Stderr, "proto: tag has too few fields: %q\n", s) | 		log.Printf("proto: tag has too few fields: %q", s) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @ -214,7 +213,7 @@ func (p *Properties) Parse(s string) { | |||||||
| 		p.WireType = WireBytes | 		p.WireType = WireBytes | ||||||
| 		// no numeric converter for non-numeric types | 		// no numeric converter for non-numeric types | ||||||
| 	default: | 	default: | ||||||
| 		fmt.Fprintf(os.Stderr, "proto: tag has unknown wire type: %q\n", s) | 		log.Printf("proto: tag has unknown wire type: %q", s) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										27
									
								
								vendor/github.com/google/go-cmp/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								vendor/github.com/google/go-cmp/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,27 @@ | |||||||
|  | Copyright (c) 2017 The Go Authors. All rights reserved. | ||||||
|  | 
 | ||||||
|  | Redistribution and use in source and binary forms, with or without | ||||||
|  | modification, are permitted provided that the following conditions are | ||||||
|  | met: | ||||||
|  | 
 | ||||||
|  |    * Redistributions of source code must retain the above copyright | ||||||
|  | notice, this list of conditions and the following disclaimer. | ||||||
|  |    * Redistributions in binary form must reproduce the above | ||||||
|  | copyright notice, this list of conditions and the following disclaimer | ||||||
|  | in the documentation and/or other materials provided with the | ||||||
|  | distribution. | ||||||
|  |    * Neither the name of Google Inc. nor the names of its | ||||||
|  | contributors may be used to endorse or promote products derived from | ||||||
|  | this software without specific prior written permission. | ||||||
|  | 
 | ||||||
|  | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||||||
|  | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||||||
|  | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||||||
|  | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||||||
|  | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||||||
|  | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||||||
|  | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||||||
|  | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||||||
|  | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||||
|  | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||||
|  | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||||
							
								
								
									
										616
									
								
								vendor/github.com/google/go-cmp/cmp/compare.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										616
									
								
								vendor/github.com/google/go-cmp/cmp/compare.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,616 @@ | |||||||
|  | // Copyright 2017, The Go Authors. All rights reserved. | ||||||
|  | // Use of this source code is governed by a BSD-style | ||||||
|  | // license that can be found in the LICENSE.md file. | ||||||
|  | 
 | ||||||
|  | // Package cmp determines equality of values. | ||||||
|  | // | ||||||
|  | // This package is intended to be a more powerful and safer alternative to | ||||||
|  | // reflect.DeepEqual for comparing whether two values are semantically equal. | ||||||
|  | // | ||||||
|  | // The primary features of cmp are: | ||||||
|  | // | ||||||
|  | // • When the default behavior of equality does not suit the needs of the test, | ||||||
|  | // custom equality functions can override the equality operation. | ||||||
|  | // For example, an equality function may report floats as equal so long as they | ||||||
|  | // are within some tolerance of each other. | ||||||
|  | // | ||||||
|  | // • Types that have an Equal method may use that method to determine equality. | ||||||
|  | // This allows package authors to determine the equality operation for the types | ||||||
|  | // that they define. | ||||||
|  | // | ||||||
|  | // • If no custom equality functions are used and no Equal method is defined, | ||||||
|  | // equality is determined by recursively comparing the primitive kinds on both | ||||||
|  | // values, much like reflect.DeepEqual. Unlike reflect.DeepEqual, unexported | ||||||
|  | // fields are not compared by default; they result in panics unless suppressed | ||||||
|  | // by using an Ignore option (see cmpopts.IgnoreUnexported) or explicitly compared | ||||||
|  | // using the AllowUnexported option. | ||||||
|  | package cmp | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"reflect" | ||||||
|  | 	"strings" | ||||||
|  | 
 | ||||||
|  | 	"github.com/google/go-cmp/cmp/internal/diff" | ||||||
|  | 	"github.com/google/go-cmp/cmp/internal/flags" | ||||||
|  | 	"github.com/google/go-cmp/cmp/internal/function" | ||||||
|  | 	"github.com/google/go-cmp/cmp/internal/value" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // Equal reports whether x and y are equal by recursively applying the | ||||||
|  | // following rules in the given order to x and y and all of their sub-values: | ||||||
|  | // | ||||||
|  | // • Let S be the set of all Ignore, Transformer, and Comparer options that | ||||||
|  | // remain after applying all path filters, value filters, and type filters. | ||||||
|  | // If at least one Ignore exists in S, then the comparison is ignored. | ||||||
|  | // If the number of Transformer and Comparer options in S is greater than one, | ||||||
|  | // then Equal panics because it is ambiguous which option to use. | ||||||
|  | // If S contains a single Transformer, then use that to transform the current | ||||||
|  | // values and recursively call Equal on the output values. | ||||||
|  | // If S contains a single Comparer, then use that to compare the current values. | ||||||
|  | // Otherwise, evaluation proceeds to the next rule. | ||||||
|  | // | ||||||
|  | // • If the values have an Equal method of the form "(T) Equal(T) bool" or | ||||||
|  | // "(T) Equal(I) bool" where T is assignable to I, then use the result of | ||||||
|  | // x.Equal(y) even if x or y is nil. Otherwise, no such method exists and | ||||||
|  | // evaluation proceeds to the next rule. | ||||||
|  | // | ||||||
|  | // • Lastly, try to compare x and y based on their basic kinds. | ||||||
|  | // Simple kinds like booleans, integers, floats, complex numbers, strings, and | ||||||
|  | // channels are compared using the equivalent of the == operator in Go. | ||||||
|  | // Functions are only equal if they are both nil, otherwise they are unequal. | ||||||
|  | // | ||||||
|  | // Structs are equal if recursively calling Equal on all fields report equal. | ||||||
|  | // If a struct contains unexported fields, Equal panics unless an Ignore option | ||||||
|  | // (e.g., cmpopts.IgnoreUnexported) ignores that field or the AllowUnexported | ||||||
|  | // option explicitly permits comparing the unexported field. | ||||||
|  | // | ||||||
|  | // Slices are equal if they are both nil or both non-nil, where recursively | ||||||
|  | // calling Equal on all non-ignored slice or array elements report equal. | ||||||
|  | // Empty non-nil slices and nil slices are not equal; to equate empty slices, | ||||||
|  | // consider using cmpopts.EquateEmpty. | ||||||
|  | // | ||||||
|  | // Maps are equal if they are both nil or both non-nil, where recursively | ||||||
|  | // calling Equal on all non-ignored map entries report equal. | ||||||
|  | // Map keys are equal according to the == operator. | ||||||
|  | // To use custom comparisons for map keys, consider using cmpopts.SortMaps. | ||||||
|  | // Empty non-nil maps and nil maps are not equal; to equate empty maps, | ||||||
|  | // consider using cmpopts.EquateEmpty. | ||||||
|  | // | ||||||
|  | // Pointers and interfaces are equal if they are both nil or both non-nil, | ||||||
|  | // where they have the same underlying concrete type and recursively | ||||||
|  | // calling Equal on the underlying values reports equal. | ||||||
|  | func Equal(x, y interface{}, opts ...Option) bool { | ||||||
|  | 	vx := reflect.ValueOf(x) | ||||||
|  | 	vy := reflect.ValueOf(y) | ||||||
|  | 
 | ||||||
|  | 	// If the inputs are different types, auto-wrap them in an empty interface | ||||||
|  | 	// so that they have the same parent type. | ||||||
|  | 	var t reflect.Type | ||||||
|  | 	if !vx.IsValid() || !vy.IsValid() || vx.Type() != vy.Type() { | ||||||
|  | 		t = reflect.TypeOf((*interface{})(nil)).Elem() | ||||||
|  | 		if vx.IsValid() { | ||||||
|  | 			vvx := reflect.New(t).Elem() | ||||||
|  | 			vvx.Set(vx) | ||||||
|  | 			vx = vvx | ||||||
|  | 		} | ||||||
|  | 		if vy.IsValid() { | ||||||
|  | 			vvy := reflect.New(t).Elem() | ||||||
|  | 			vvy.Set(vy) | ||||||
|  | 			vy = vvy | ||||||
|  | 		} | ||||||
|  | 	} else { | ||||||
|  | 		t = vx.Type() | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	s := newState(opts) | ||||||
|  | 	s.compareAny(&pathStep{t, vx, vy}) | ||||||
|  | 	return s.result.Equal() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Diff returns a human-readable report of the differences between two values. | ||||||
|  | // It returns an empty string if and only if Equal returns true for the same | ||||||
|  | // input values and options. | ||||||
|  | // | ||||||
|  | // The output is displayed as a literal in pseudo-Go syntax. | ||||||
|  | // At the start of each line, a "-" prefix indicates an element removed from x, | ||||||
|  | // a "+" prefix to indicates an element added to y, and the lack of a prefix | ||||||
|  | // indicates an element common to both x and y. If possible, the output | ||||||
|  | // uses fmt.Stringer.String or error.Error methods to produce more humanly | ||||||
|  | // readable outputs. In such cases, the string is prefixed with either an | ||||||
|  | // 's' or 'e' character, respectively, to indicate that the method was called. | ||||||
|  | // | ||||||
|  | // Do not depend on this output being stable. If you need the ability to | ||||||
|  | // programmatically interpret the difference, consider using a custom Reporter. | ||||||
|  | func Diff(x, y interface{}, opts ...Option) string { | ||||||
|  | 	r := new(defaultReporter) | ||||||
|  | 	eq := Equal(x, y, Options(opts), Reporter(r)) | ||||||
|  | 	d := r.String() | ||||||
|  | 	if (d == "") != eq { | ||||||
|  | 		panic("inconsistent difference and equality results") | ||||||
|  | 	} | ||||||
|  | 	return d | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type state struct { | ||||||
|  | 	// These fields represent the "comparison state". | ||||||
|  | 	// Calling statelessCompare must not result in observable changes to these. | ||||||
|  | 	result    diff.Result // The current result of comparison | ||||||
|  | 	curPath   Path        // The current path in the value tree | ||||||
|  | 	reporters []reporter  // Optional reporters | ||||||
|  | 
 | ||||||
|  | 	// recChecker checks for infinite cycles applying the same set of | ||||||
|  | 	// transformers upon the output of itself. | ||||||
|  | 	recChecker recChecker | ||||||
|  | 
 | ||||||
|  | 	// dynChecker triggers pseudo-random checks for option correctness. | ||||||
|  | 	// It is safe for statelessCompare to mutate this value. | ||||||
|  | 	dynChecker dynChecker | ||||||
|  | 
 | ||||||
|  | 	// These fields, once set by processOption, will not change. | ||||||
|  | 	exporters map[reflect.Type]bool // Set of structs with unexported field visibility | ||||||
|  | 	opts      Options               // List of all fundamental and filter options | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func newState(opts []Option) *state { | ||||||
|  | 	// Always ensure a validator option exists to validate the inputs. | ||||||
|  | 	s := &state{opts: Options{validator{}}} | ||||||
|  | 	s.processOption(Options(opts)) | ||||||
|  | 	return s | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (s *state) processOption(opt Option) { | ||||||
|  | 	switch opt := opt.(type) { | ||||||
|  | 	case nil: | ||||||
|  | 	case Options: | ||||||
|  | 		for _, o := range opt { | ||||||
|  | 			s.processOption(o) | ||||||
|  | 		} | ||||||
|  | 	case coreOption: | ||||||
|  | 		type filtered interface { | ||||||
|  | 			isFiltered() bool | ||||||
|  | 		} | ||||||
|  | 		if fopt, ok := opt.(filtered); ok && !fopt.isFiltered() { | ||||||
|  | 			panic(fmt.Sprintf("cannot use an unfiltered option: %v", opt)) | ||||||
|  | 		} | ||||||
|  | 		s.opts = append(s.opts, opt) | ||||||
|  | 	case visibleStructs: | ||||||
|  | 		if s.exporters == nil { | ||||||
|  | 			s.exporters = make(map[reflect.Type]bool) | ||||||
|  | 		} | ||||||
|  | 		for t := range opt { | ||||||
|  | 			s.exporters[t] = true | ||||||
|  | 		} | ||||||
|  | 	case reporter: | ||||||
|  | 		s.reporters = append(s.reporters, opt) | ||||||
|  | 	default: | ||||||
|  | 		panic(fmt.Sprintf("unknown option %T", opt)) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // statelessCompare compares two values and returns the result. | ||||||
|  | // This function is stateless in that it does not alter the current result, | ||||||
|  | // or output to any registered reporters. | ||||||
|  | func (s *state) statelessCompare(step PathStep) diff.Result { | ||||||
|  | 	// We do not save and restore the curPath because all of the compareX | ||||||
|  | 	// methods should properly push and pop from the path. | ||||||
|  | 	// It is an implementation bug if the contents of curPath differs from | ||||||
|  | 	// when calling this function to when returning from it. | ||||||
|  | 
 | ||||||
|  | 	oldResult, oldReporters := s.result, s.reporters | ||||||
|  | 	s.result = diff.Result{} // Reset result | ||||||
|  | 	s.reporters = nil        // Remove reporters to avoid spurious printouts | ||||||
|  | 	s.compareAny(step) | ||||||
|  | 	res := s.result | ||||||
|  | 	s.result, s.reporters = oldResult, oldReporters | ||||||
|  | 	return res | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (s *state) compareAny(step PathStep) { | ||||||
|  | 	// Update the path stack. | ||||||
|  | 	s.curPath.push(step) | ||||||
|  | 	defer s.curPath.pop() | ||||||
|  | 	for _, r := range s.reporters { | ||||||
|  | 		r.PushStep(step) | ||||||
|  | 		defer r.PopStep() | ||||||
|  | 	} | ||||||
|  | 	s.recChecker.Check(s.curPath) | ||||||
|  | 
 | ||||||
|  | 	// Obtain the current type and values. | ||||||
|  | 	t := step.Type() | ||||||
|  | 	vx, vy := step.Values() | ||||||
|  | 
 | ||||||
|  | 	// Rule 1: Check whether an option applies on this node in the value tree. | ||||||
|  | 	if s.tryOptions(t, vx, vy) { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Rule 2: Check whether the type has a valid Equal method. | ||||||
|  | 	if s.tryMethod(t, vx, vy) { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Rule 3: Compare based on the underlying kind. | ||||||
|  | 	switch t.Kind() { | ||||||
|  | 	case reflect.Bool: | ||||||
|  | 		s.report(vx.Bool() == vy.Bool(), 0) | ||||||
|  | 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | ||||||
|  | 		s.report(vx.Int() == vy.Int(), 0) | ||||||
|  | 	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: | ||||||
|  | 		s.report(vx.Uint() == vy.Uint(), 0) | ||||||
|  | 	case reflect.Float32, reflect.Float64: | ||||||
|  | 		s.report(vx.Float() == vy.Float(), 0) | ||||||
|  | 	case reflect.Complex64, reflect.Complex128: | ||||||
|  | 		s.report(vx.Complex() == vy.Complex(), 0) | ||||||
|  | 	case reflect.String: | ||||||
|  | 		s.report(vx.String() == vy.String(), 0) | ||||||
|  | 	case reflect.Chan, reflect.UnsafePointer: | ||||||
|  | 		s.report(vx.Pointer() == vy.Pointer(), 0) | ||||||
|  | 	case reflect.Func: | ||||||
|  | 		s.report(vx.IsNil() && vy.IsNil(), 0) | ||||||
|  | 	case reflect.Struct: | ||||||
|  | 		s.compareStruct(t, vx, vy) | ||||||
|  | 	case reflect.Slice, reflect.Array: | ||||||
|  | 		s.compareSlice(t, vx, vy) | ||||||
|  | 	case reflect.Map: | ||||||
|  | 		s.compareMap(t, vx, vy) | ||||||
|  | 	case reflect.Ptr: | ||||||
|  | 		s.comparePtr(t, vx, vy) | ||||||
|  | 	case reflect.Interface: | ||||||
|  | 		s.compareInterface(t, vx, vy) | ||||||
|  | 	default: | ||||||
|  | 		panic(fmt.Sprintf("%v kind not handled", t.Kind())) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (s *state) tryOptions(t reflect.Type, vx, vy reflect.Value) bool { | ||||||
|  | 	// Evaluate all filters and apply the remaining options. | ||||||
|  | 	if opt := s.opts.filter(s, t, vx, vy); opt != nil { | ||||||
|  | 		opt.apply(s, vx, vy) | ||||||
|  | 		return true | ||||||
|  | 	} | ||||||
|  | 	return false | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (s *state) tryMethod(t reflect.Type, vx, vy reflect.Value) bool { | ||||||
|  | 	// Check if this type even has an Equal method. | ||||||
|  | 	m, ok := t.MethodByName("Equal") | ||||||
|  | 	if !ok || !function.IsType(m.Type, function.EqualAssignable) { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	eq := s.callTTBFunc(m.Func, vx, vy) | ||||||
|  | 	s.report(eq, reportByMethod) | ||||||
|  | 	return true | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (s *state) callTRFunc(f, v reflect.Value, step Transform) reflect.Value { | ||||||
|  | 	v = sanitizeValue(v, f.Type().In(0)) | ||||||
|  | 	if !s.dynChecker.Next() { | ||||||
|  | 		return f.Call([]reflect.Value{v})[0] | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Run the function twice and ensure that we get the same results back. | ||||||
|  | 	// We run in goroutines so that the race detector (if enabled) can detect | ||||||
|  | 	// unsafe mutations to the input. | ||||||
|  | 	c := make(chan reflect.Value) | ||||||
|  | 	go detectRaces(c, f, v) | ||||||
|  | 	got := <-c | ||||||
|  | 	want := f.Call([]reflect.Value{v})[0] | ||||||
|  | 	if step.vx, step.vy = got, want; !s.statelessCompare(step).Equal() { | ||||||
|  | 		// To avoid false-positives with non-reflexive equality operations, | ||||||
|  | 		// we sanity check whether a value is equal to itself. | ||||||
|  | 		if step.vx, step.vy = want, want; !s.statelessCompare(step).Equal() { | ||||||
|  | 			return want | ||||||
|  | 		} | ||||||
|  | 		panic(fmt.Sprintf("non-deterministic function detected: %s", function.NameOf(f))) | ||||||
|  | 	} | ||||||
|  | 	return want | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (s *state) callTTBFunc(f, x, y reflect.Value) bool { | ||||||
|  | 	x = sanitizeValue(x, f.Type().In(0)) | ||||||
|  | 	y = sanitizeValue(y, f.Type().In(1)) | ||||||
|  | 	if !s.dynChecker.Next() { | ||||||
|  | 		return f.Call([]reflect.Value{x, y})[0].Bool() | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Swapping the input arguments is sufficient to check that | ||||||
|  | 	// f is symmetric and deterministic. | ||||||
|  | 	// We run in goroutines so that the race detector (if enabled) can detect | ||||||
|  | 	// unsafe mutations to the input. | ||||||
|  | 	c := make(chan reflect.Value) | ||||||
|  | 	go detectRaces(c, f, y, x) | ||||||
|  | 	got := <-c | ||||||
|  | 	want := f.Call([]reflect.Value{x, y})[0].Bool() | ||||||
|  | 	if !got.IsValid() || got.Bool() != want { | ||||||
|  | 		panic(fmt.Sprintf("non-deterministic or non-symmetric function detected: %s", function.NameOf(f))) | ||||||
|  | 	} | ||||||
|  | 	return want | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func detectRaces(c chan<- reflect.Value, f reflect.Value, vs ...reflect.Value) { | ||||||
|  | 	var ret reflect.Value | ||||||
|  | 	defer func() { | ||||||
|  | 		recover() // Ignore panics, let the other call to f panic instead | ||||||
|  | 		c <- ret | ||||||
|  | 	}() | ||||||
|  | 	ret = f.Call(vs)[0] | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // sanitizeValue converts nil interfaces of type T to those of type R, | ||||||
|  | // assuming that T is assignable to R. | ||||||
|  | // Otherwise, it returns the input value as is. | ||||||
|  | func sanitizeValue(v reflect.Value, t reflect.Type) reflect.Value { | ||||||
|  | 	// TODO(dsnet): Workaround for reflect bug (https://golang.org/issue/22143). | ||||||
|  | 	if !flags.AtLeastGo110 { | ||||||
|  | 		if v.Kind() == reflect.Interface && v.IsNil() && v.Type() != t { | ||||||
|  | 			return reflect.New(t).Elem() | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return v | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (s *state) compareStruct(t reflect.Type, vx, vy reflect.Value) { | ||||||
|  | 	var vax, vay reflect.Value // Addressable versions of vx and vy | ||||||
|  | 
 | ||||||
|  | 	step := StructField{&structField{}} | ||||||
|  | 	for i := 0; i < t.NumField(); i++ { | ||||||
|  | 		step.typ = t.Field(i).Type | ||||||
|  | 		step.vx = vx.Field(i) | ||||||
|  | 		step.vy = vy.Field(i) | ||||||
|  | 		step.name = t.Field(i).Name | ||||||
|  | 		step.idx = i | ||||||
|  | 		step.unexported = !isExported(step.name) | ||||||
|  | 		if step.unexported { | ||||||
|  | 			if step.name == "_" { | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  | 			// Defer checking of unexported fields until later to give an | ||||||
|  | 			// Ignore a chance to ignore the field. | ||||||
|  | 			if !vax.IsValid() || !vay.IsValid() { | ||||||
|  | 				// For retrieveUnexportedField to work, the parent struct must | ||||||
|  | 				// be addressable. Create a new copy of the values if | ||||||
|  | 				// necessary to make them addressable. | ||||||
|  | 				vax = makeAddressable(vx) | ||||||
|  | 				vay = makeAddressable(vy) | ||||||
|  | 			} | ||||||
|  | 			step.mayForce = s.exporters[t] | ||||||
|  | 			step.pvx = vax | ||||||
|  | 			step.pvy = vay | ||||||
|  | 			step.field = t.Field(i) | ||||||
|  | 		} | ||||||
|  | 		s.compareAny(step) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (s *state) compareSlice(t reflect.Type, vx, vy reflect.Value) { | ||||||
|  | 	isSlice := t.Kind() == reflect.Slice | ||||||
|  | 	if isSlice && (vx.IsNil() || vy.IsNil()) { | ||||||
|  | 		s.report(vx.IsNil() && vy.IsNil(), 0) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// TODO: Support cyclic data structures. | ||||||
|  | 
 | ||||||
|  | 	step := SliceIndex{&sliceIndex{pathStep: pathStep{typ: t.Elem()}}} | ||||||
|  | 	withIndexes := func(ix, iy int) SliceIndex { | ||||||
|  | 		if ix >= 0 { | ||||||
|  | 			step.vx, step.xkey = vx.Index(ix), ix | ||||||
|  | 		} else { | ||||||
|  | 			step.vx, step.xkey = reflect.Value{}, -1 | ||||||
|  | 		} | ||||||
|  | 		if iy >= 0 { | ||||||
|  | 			step.vy, step.ykey = vy.Index(iy), iy | ||||||
|  | 		} else { | ||||||
|  | 			step.vy, step.ykey = reflect.Value{}, -1 | ||||||
|  | 		} | ||||||
|  | 		return step | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Ignore options are able to ignore missing elements in a slice. | ||||||
|  | 	// However, detecting these reliably requires an optimal differencing | ||||||
|  | 	// algorithm, for which diff.Difference is not. | ||||||
|  | 	// | ||||||
|  | 	// Instead, we first iterate through both slices to detect which elements | ||||||
|  | 	// would be ignored if standing alone. The index of non-discarded elements | ||||||
|  | 	// are stored in a separate slice, which diffing is then performed on. | ||||||
|  | 	var indexesX, indexesY []int | ||||||
|  | 	var ignoredX, ignoredY []bool | ||||||
|  | 	for ix := 0; ix < vx.Len(); ix++ { | ||||||
|  | 		ignored := s.statelessCompare(withIndexes(ix, -1)).NumDiff == 0 | ||||||
|  | 		if !ignored { | ||||||
|  | 			indexesX = append(indexesX, ix) | ||||||
|  | 		} | ||||||
|  | 		ignoredX = append(ignoredX, ignored) | ||||||
|  | 	} | ||||||
|  | 	for iy := 0; iy < vy.Len(); iy++ { | ||||||
|  | 		ignored := s.statelessCompare(withIndexes(-1, iy)).NumDiff == 0 | ||||||
|  | 		if !ignored { | ||||||
|  | 			indexesY = append(indexesY, iy) | ||||||
|  | 		} | ||||||
|  | 		ignoredY = append(ignoredY, ignored) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Compute an edit-script for slices vx and vy (excluding ignored elements). | ||||||
|  | 	edits := diff.Difference(len(indexesX), len(indexesY), func(ix, iy int) diff.Result { | ||||||
|  | 		return s.statelessCompare(withIndexes(indexesX[ix], indexesY[iy])) | ||||||
|  | 	}) | ||||||
|  | 
 | ||||||
|  | 	// Replay the ignore-scripts and the edit-script. | ||||||
|  | 	var ix, iy int | ||||||
|  | 	for ix < vx.Len() || iy < vy.Len() { | ||||||
|  | 		var e diff.EditType | ||||||
|  | 		switch { | ||||||
|  | 		case ix < len(ignoredX) && ignoredX[ix]: | ||||||
|  | 			e = diff.UniqueX | ||||||
|  | 		case iy < len(ignoredY) && ignoredY[iy]: | ||||||
|  | 			e = diff.UniqueY | ||||||
|  | 		default: | ||||||
|  | 			e, edits = edits[0], edits[1:] | ||||||
|  | 		} | ||||||
|  | 		switch e { | ||||||
|  | 		case diff.UniqueX: | ||||||
|  | 			s.compareAny(withIndexes(ix, -1)) | ||||||
|  | 			ix++ | ||||||
|  | 		case diff.UniqueY: | ||||||
|  | 			s.compareAny(withIndexes(-1, iy)) | ||||||
|  | 			iy++ | ||||||
|  | 		default: | ||||||
|  | 			s.compareAny(withIndexes(ix, iy)) | ||||||
|  | 			ix++ | ||||||
|  | 			iy++ | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (s *state) compareMap(t reflect.Type, vx, vy reflect.Value) { | ||||||
|  | 	if vx.IsNil() || vy.IsNil() { | ||||||
|  | 		s.report(vx.IsNil() && vy.IsNil(), 0) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// TODO: Support cyclic data structures. | ||||||
|  | 
 | ||||||
|  | 	// We combine and sort the two map keys so that we can perform the | ||||||
|  | 	// comparisons in a deterministic order. | ||||||
|  | 	step := MapIndex{&mapIndex{pathStep: pathStep{typ: t.Elem()}}} | ||||||
|  | 	for _, k := range value.SortKeys(append(vx.MapKeys(), vy.MapKeys()...)) { | ||||||
|  | 		step.vx = vx.MapIndex(k) | ||||||
|  | 		step.vy = vy.MapIndex(k) | ||||||
|  | 		step.key = k | ||||||
|  | 		if !step.vx.IsValid() && !step.vy.IsValid() { | ||||||
|  | 			// It is possible for both vx and vy to be invalid if the | ||||||
|  | 			// key contained a NaN value in it. | ||||||
|  | 			// | ||||||
|  | 			// Even with the ability to retrieve NaN keys in Go 1.12, | ||||||
|  | 			// there still isn't a sensible way to compare the values since | ||||||
|  | 			// a NaN key may map to multiple unordered values. | ||||||
|  | 			// The most reasonable way to compare NaNs would be to compare the | ||||||
|  | 			// set of values. However, this is impossible to do efficiently | ||||||
|  | 			// since set equality is provably an O(n^2) operation given only | ||||||
|  | 			// an Equal function. If we had a Less function or Hash function, | ||||||
|  | 			// this could be done in O(n*log(n)) or O(n), respectively. | ||||||
|  | 			// | ||||||
|  | 			// Rather than adding complex logic to deal with NaNs, make it | ||||||
|  | 			// the user's responsibility to compare such obscure maps. | ||||||
|  | 			const help = "consider providing a Comparer to compare the map" | ||||||
|  | 			panic(fmt.Sprintf("%#v has map key with NaNs\n%s", s.curPath, help)) | ||||||
|  | 		} | ||||||
|  | 		s.compareAny(step) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (s *state) comparePtr(t reflect.Type, vx, vy reflect.Value) { | ||||||
|  | 	if vx.IsNil() || vy.IsNil() { | ||||||
|  | 		s.report(vx.IsNil() && vy.IsNil(), 0) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// TODO: Support cyclic data structures. | ||||||
|  | 
 | ||||||
|  | 	vx, vy = vx.Elem(), vy.Elem() | ||||||
|  | 	s.compareAny(Indirect{&indirect{pathStep{t.Elem(), vx, vy}}}) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (s *state) compareInterface(t reflect.Type, vx, vy reflect.Value) { | ||||||
|  | 	if vx.IsNil() || vy.IsNil() { | ||||||
|  | 		s.report(vx.IsNil() && vy.IsNil(), 0) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	vx, vy = vx.Elem(), vy.Elem() | ||||||
|  | 	if vx.Type() != vy.Type() { | ||||||
|  | 		s.report(false, 0) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	s.compareAny(TypeAssertion{&typeAssertion{pathStep{vx.Type(), vx, vy}}}) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (s *state) report(eq bool, rf resultFlags) { | ||||||
|  | 	if rf&reportByIgnore == 0 { | ||||||
|  | 		if eq { | ||||||
|  | 			s.result.NumSame++ | ||||||
|  | 			rf |= reportEqual | ||||||
|  | 		} else { | ||||||
|  | 			s.result.NumDiff++ | ||||||
|  | 			rf |= reportUnequal | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	for _, r := range s.reporters { | ||||||
|  | 		r.Report(Result{flags: rf}) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // recChecker tracks the state needed to periodically perform checks that | ||||||
|  | // user provided transformers are not stuck in an infinitely recursive cycle. | ||||||
|  | type recChecker struct{ next int } | ||||||
|  | 
 | ||||||
|  | // Check scans the Path for any recursive transformers and panics when any | ||||||
|  | // recursive transformers are detected. Note that the presence of a | ||||||
|  | // recursive Transformer does not necessarily imply an infinite cycle. | ||||||
|  | // As such, this check only activates after some minimal number of path steps. | ||||||
|  | func (rc *recChecker) Check(p Path) { | ||||||
|  | 	const minLen = 1 << 16 | ||||||
|  | 	if rc.next == 0 { | ||||||
|  | 		rc.next = minLen | ||||||
|  | 	} | ||||||
|  | 	if len(p) < rc.next { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	rc.next <<= 1 | ||||||
|  | 
 | ||||||
|  | 	// Check whether the same transformer has appeared at least twice. | ||||||
|  | 	var ss []string | ||||||
|  | 	m := map[Option]int{} | ||||||
|  | 	for _, ps := range p { | ||||||
|  | 		if t, ok := ps.(Transform); ok { | ||||||
|  | 			t := t.Option() | ||||||
|  | 			if m[t] == 1 { // Transformer was used exactly once before | ||||||
|  | 				tf := t.(*transformer).fnc.Type() | ||||||
|  | 				ss = append(ss, fmt.Sprintf("%v: %v => %v", t, tf.In(0), tf.Out(0))) | ||||||
|  | 			} | ||||||
|  | 			m[t]++ | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	if len(ss) > 0 { | ||||||
|  | 		const warning = "recursive set of Transformers detected" | ||||||
|  | 		const help = "consider using cmpopts.AcyclicTransformer" | ||||||
|  | 		set := strings.Join(ss, "\n\t") | ||||||
|  | 		panic(fmt.Sprintf("%s:\n\t%s\n%s", warning, set, help)) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // dynChecker tracks the state needed to periodically perform checks that | ||||||
|  | // user provided functions are symmetric and deterministic. | ||||||
|  | // The zero value is safe for immediate use. | ||||||
|  | type dynChecker struct{ curr, next int } | ||||||
|  | 
 | ||||||
|  | // Next increments the state and reports whether a check should be performed. | ||||||
|  | // | ||||||
|  | // Checks occur every Nth function call, where N is a triangular number: | ||||||
|  | //	0 1 3 6 10 15 21 28 36 45 55 66 78 91 105 120 136 153 171 190 ... | ||||||
|  | // See https://en.wikipedia.org/wiki/Triangular_number | ||||||
|  | // | ||||||
|  | // This sequence ensures that the cost of checks drops significantly as | ||||||
|  | // the number of functions calls grows larger. | ||||||
|  | func (dc *dynChecker) Next() bool { | ||||||
|  | 	ok := dc.curr == dc.next | ||||||
|  | 	if ok { | ||||||
|  | 		dc.curr = 0 | ||||||
|  | 		dc.next++ | ||||||
|  | 	} | ||||||
|  | 	dc.curr++ | ||||||
|  | 	return ok | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // makeAddressable returns a value that is always addressable. | ||||||
|  | // It returns the input verbatim if it is already addressable, | ||||||
|  | // otherwise it creates a new value and returns an addressable copy. | ||||||
|  | func makeAddressable(v reflect.Value) reflect.Value { | ||||||
|  | 	if v.CanAddr() { | ||||||
|  | 		return v | ||||||
|  | 	} | ||||||
|  | 	vc := reflect.New(v.Type()).Elem() | ||||||
|  | 	vc.Set(v) | ||||||
|  | 	return vc | ||||||
|  | } | ||||||
							
								
								
									
										15
									
								
								vendor/github.com/google/go-cmp/cmp/export_panic.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								vendor/github.com/google/go-cmp/cmp/export_panic.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | |||||||
|  | // Copyright 2017, The Go Authors. All rights reserved. | ||||||
|  | // Use of this source code is governed by a BSD-style | ||||||
|  | // license that can be found in the LICENSE.md file. | ||||||
|  | 
 | ||||||
|  | // +build purego | ||||||
|  | 
 | ||||||
|  | package cmp | ||||||
|  | 
 | ||||||
|  | import "reflect" | ||||||
|  | 
 | ||||||
|  | const supportAllowUnexported = false | ||||||
|  | 
 | ||||||
|  | func retrieveUnexportedField(reflect.Value, reflect.StructField) reflect.Value { | ||||||
|  | 	panic("retrieveUnexportedField is not implemented") | ||||||
|  | } | ||||||
							
								
								
									
										23
									
								
								vendor/github.com/google/go-cmp/cmp/export_unsafe.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								vendor/github.com/google/go-cmp/cmp/export_unsafe.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,23 @@ | |||||||
|  | // Copyright 2017, The Go Authors. All rights reserved. | ||||||
|  | // Use of this source code is governed by a BSD-style | ||||||
|  | // license that can be found in the LICENSE.md file. | ||||||
|  | 
 | ||||||
|  | // +build !purego | ||||||
|  | 
 | ||||||
|  | package cmp | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"reflect" | ||||||
|  | 	"unsafe" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | const supportAllowUnexported = true | ||||||
|  | 
 | ||||||
|  | // retrieveUnexportedField uses unsafe to forcibly retrieve any field from | ||||||
|  | // a struct such that the value has read-write permissions. | ||||||
|  | // | ||||||
|  | // The parent struct, v, must be addressable, while f must be a StructField | ||||||
|  | // describing the field to retrieve. | ||||||
|  | func retrieveUnexportedField(v reflect.Value, f reflect.StructField) reflect.Value { | ||||||
|  | 	return reflect.NewAt(f.Type, unsafe.Pointer(v.UnsafeAddr()+f.Offset)).Elem() | ||||||
|  | } | ||||||
							
								
								
									
										17
									
								
								vendor/github.com/google/go-cmp/cmp/internal/diff/debug_disable.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								vendor/github.com/google/go-cmp/cmp/internal/diff/debug_disable.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,17 @@ | |||||||
|  | // Copyright 2017, The Go Authors. All rights reserved. | ||||||
|  | // Use of this source code is governed by a BSD-style | ||||||
|  | // license that can be found in the LICENSE.md file. | ||||||
|  | 
 | ||||||
|  | // +build !cmp_debug | ||||||
|  | 
 | ||||||
|  | package diff | ||||||
|  | 
 | ||||||
|  | var debug debugger | ||||||
|  | 
 | ||||||
|  | type debugger struct{} | ||||||
|  | 
 | ||||||
|  | func (debugger) Begin(_, _ int, f EqualFunc, _, _ *EditScript) EqualFunc { | ||||||
|  | 	return f | ||||||
|  | } | ||||||
|  | func (debugger) Update() {} | ||||||
|  | func (debugger) Finish() {} | ||||||
							
								
								
									
										122
									
								
								vendor/github.com/google/go-cmp/cmp/internal/diff/debug_enable.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								vendor/github.com/google/go-cmp/cmp/internal/diff/debug_enable.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,122 @@ | |||||||
|  | // Copyright 2017, The Go Authors. All rights reserved. | ||||||
|  | // Use of this source code is governed by a BSD-style | ||||||
|  | // license that can be found in the LICENSE.md file. | ||||||
|  | 
 | ||||||
|  | // +build cmp_debug | ||||||
|  | 
 | ||||||
|  | package diff | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"strings" | ||||||
|  | 	"sync" | ||||||
|  | 	"time" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // The algorithm can be seen running in real-time by enabling debugging: | ||||||
|  | //	go test -tags=cmp_debug -v | ||||||
|  | // | ||||||
|  | // Example output: | ||||||
|  | //	=== RUN   TestDifference/#34 | ||||||
|  | //	┌───────────────────────────────┐ | ||||||
|  | //	│ \ · · · · · · · · · · · · · · │ | ||||||
|  | //	│ · # · · · · · · · · · · · · · │ | ||||||
|  | //	│ · \ · · · · · · · · · · · · · │ | ||||||
|  | //	│ · · \ · · · · · · · · · · · · │ | ||||||
|  | //	│ · · · X # · · · · · · · · · · │ | ||||||
|  | //	│ · · · # \ · · · · · · · · · · │ | ||||||
|  | //	│ · · · · · # # · · · · · · · · │ | ||||||
|  | //	│ · · · · · # \ · · · · · · · · │ | ||||||
|  | //	│ · · · · · · · \ · · · · · · · │ | ||||||
|  | //	│ · · · · · · · · \ · · · · · · │ | ||||||
|  | //	│ · · · · · · · · · \ · · · · · │ | ||||||
|  | //	│ · · · · · · · · · · \ · · # · │ | ||||||
|  | //	│ · · · · · · · · · · · \ # # · │ | ||||||
|  | //	│ · · · · · · · · · · · # # # · │ | ||||||
|  | //	│ · · · · · · · · · · # # # # · │ | ||||||
|  | //	│ · · · · · · · · · # # # # # · │ | ||||||
|  | //	│ · · · · · · · · · · · · · · \ │ | ||||||
|  | //	└───────────────────────────────┘ | ||||||
|  | //	[.Y..M.XY......YXYXY.|] | ||||||
|  | // | ||||||
|  | // The grid represents the edit-graph where the horizontal axis represents | ||||||
|  | // list X and the vertical axis represents list Y. The start of the two lists | ||||||
|  | // is the top-left, while the ends are the bottom-right. The '·' represents | ||||||
|  | // an unexplored node in the graph. The '\' indicates that the two symbols | ||||||
|  | // from list X and Y are equal. The 'X' indicates that two symbols are similar | ||||||
|  | // (but not exactly equal) to each other. The '#' indicates that the two symbols | ||||||
|  | // are different (and not similar). The algorithm traverses this graph trying to | ||||||
|  | // make the paths starting in the top-left and the bottom-right connect. | ||||||
|  | // | ||||||
|  | // The series of '.', 'X', 'Y', and 'M' characters at the bottom represents | ||||||
|  | // the currently established path from the forward and reverse searches, | ||||||
|  | // separated by a '|' character. | ||||||
|  | 
 | ||||||
|  | const ( | ||||||
|  | 	updateDelay  = 100 * time.Millisecond | ||||||
|  | 	finishDelay  = 500 * time.Millisecond | ||||||
|  | 	ansiTerminal = true // ANSI escape codes used to move terminal cursor | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | var debug debugger | ||||||
|  | 
 | ||||||
|  | type debugger struct { | ||||||
|  | 	sync.Mutex | ||||||
|  | 	p1, p2           EditScript | ||||||
|  | 	fwdPath, revPath *EditScript | ||||||
|  | 	grid             []byte | ||||||
|  | 	lines            int | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (dbg *debugger) Begin(nx, ny int, f EqualFunc, p1, p2 *EditScript) EqualFunc { | ||||||
|  | 	dbg.Lock() | ||||||
|  | 	dbg.fwdPath, dbg.revPath = p1, p2 | ||||||
|  | 	top := "┌─" + strings.Repeat("──", nx) + "┐\n" | ||||||
|  | 	row := "│ " + strings.Repeat("· ", nx) + "│\n" | ||||||
|  | 	btm := "└─" + strings.Repeat("──", nx) + "┘\n" | ||||||
|  | 	dbg.grid = []byte(top + strings.Repeat(row, ny) + btm) | ||||||
|  | 	dbg.lines = strings.Count(dbg.String(), "\n") | ||||||
|  | 	fmt.Print(dbg) | ||||||
|  | 
 | ||||||
|  | 	// Wrap the EqualFunc so that we can intercept each result. | ||||||
|  | 	return func(ix, iy int) (r Result) { | ||||||
|  | 		cell := dbg.grid[len(top)+iy*len(row):][len("│ ")+len("· ")*ix:][:len("·")] | ||||||
|  | 		for i := range cell { | ||||||
|  | 			cell[i] = 0 // Zero out the multiple bytes of UTF-8 middle-dot | ||||||
|  | 		} | ||||||
|  | 		switch r = f(ix, iy); { | ||||||
|  | 		case r.Equal(): | ||||||
|  | 			cell[0] = '\\' | ||||||
|  | 		case r.Similar(): | ||||||
|  | 			cell[0] = 'X' | ||||||
|  | 		default: | ||||||
|  | 			cell[0] = '#' | ||||||
|  | 		} | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (dbg *debugger) Update() { | ||||||
|  | 	dbg.print(updateDelay) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (dbg *debugger) Finish() { | ||||||
|  | 	dbg.print(finishDelay) | ||||||
|  | 	dbg.Unlock() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (dbg *debugger) String() string { | ||||||
|  | 	dbg.p1, dbg.p2 = *dbg.fwdPath, dbg.p2[:0] | ||||||
|  | 	for i := len(*dbg.revPath) - 1; i >= 0; i-- { | ||||||
|  | 		dbg.p2 = append(dbg.p2, (*dbg.revPath)[i]) | ||||||
|  | 	} | ||||||
|  | 	return fmt.Sprintf("%s[%v|%v]\n\n", dbg.grid, dbg.p1, dbg.p2) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (dbg *debugger) print(d time.Duration) { | ||||||
|  | 	if ansiTerminal { | ||||||
|  | 		fmt.Printf("\x1b[%dA", dbg.lines) // Reset terminal cursor | ||||||
|  | 	} | ||||||
|  | 	fmt.Print(dbg) | ||||||
|  | 	time.Sleep(d) | ||||||
|  | } | ||||||
							
								
								
									
										372
									
								
								vendor/github.com/google/go-cmp/cmp/internal/diff/diff.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										372
									
								
								vendor/github.com/google/go-cmp/cmp/internal/diff/diff.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,372 @@ | |||||||
|  | // Copyright 2017, The Go Authors. All rights reserved. | ||||||
|  | // Use of this source code is governed by a BSD-style | ||||||
|  | // license that can be found in the LICENSE.md file. | ||||||
|  | 
 | ||||||
|  | // Package diff implements an algorithm for producing edit-scripts. | ||||||
|  | // The edit-script is a sequence of operations needed to transform one list | ||||||
|  | // of symbols into another (or vice-versa). The edits allowed are insertions, | ||||||
|  | // deletions, and modifications. The summation of all edits is called the | ||||||
|  | // Levenshtein distance as this problem is well-known in computer science. | ||||||
|  | // | ||||||
|  | // This package prioritizes performance over accuracy. That is, the run time | ||||||
|  | // is more important than obtaining a minimal Levenshtein distance. | ||||||
|  | package diff | ||||||
|  | 
 | ||||||
|  | // EditType represents a single operation within an edit-script. | ||||||
|  | type EditType uint8 | ||||||
|  | 
 | ||||||
|  | const ( | ||||||
|  | 	// Identity indicates that a symbol pair is identical in both list X and Y. | ||||||
|  | 	Identity EditType = iota | ||||||
|  | 	// UniqueX indicates that a symbol only exists in X and not Y. | ||||||
|  | 	UniqueX | ||||||
|  | 	// UniqueY indicates that a symbol only exists in Y and not X. | ||||||
|  | 	UniqueY | ||||||
|  | 	// Modified indicates that a symbol pair is a modification of each other. | ||||||
|  | 	Modified | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // EditScript represents the series of differences between two lists. | ||||||
|  | type EditScript []EditType | ||||||
|  | 
 | ||||||
|  | // String returns a human-readable string representing the edit-script where | ||||||
|  | // Identity, UniqueX, UniqueY, and Modified are represented by the | ||||||
|  | // '.', 'X', 'Y', and 'M' characters, respectively. | ||||||
|  | func (es EditScript) String() string { | ||||||
|  | 	b := make([]byte, len(es)) | ||||||
|  | 	for i, e := range es { | ||||||
|  | 		switch e { | ||||||
|  | 		case Identity: | ||||||
|  | 			b[i] = '.' | ||||||
|  | 		case UniqueX: | ||||||
|  | 			b[i] = 'X' | ||||||
|  | 		case UniqueY: | ||||||
|  | 			b[i] = 'Y' | ||||||
|  | 		case Modified: | ||||||
|  | 			b[i] = 'M' | ||||||
|  | 		default: | ||||||
|  | 			panic("invalid edit-type") | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return string(b) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // stats returns a histogram of the number of each type of edit operation. | ||||||
|  | func (es EditScript) stats() (s struct{ NI, NX, NY, NM int }) { | ||||||
|  | 	for _, e := range es { | ||||||
|  | 		switch e { | ||||||
|  | 		case Identity: | ||||||
|  | 			s.NI++ | ||||||
|  | 		case UniqueX: | ||||||
|  | 			s.NX++ | ||||||
|  | 		case UniqueY: | ||||||
|  | 			s.NY++ | ||||||
|  | 		case Modified: | ||||||
|  | 			s.NM++ | ||||||
|  | 		default: | ||||||
|  | 			panic("invalid edit-type") | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Dist is the Levenshtein distance and is guaranteed to be 0 if and only if | ||||||
|  | // lists X and Y are equal. | ||||||
|  | func (es EditScript) Dist() int { return len(es) - es.stats().NI } | ||||||
|  | 
 | ||||||
|  | // LenX is the length of the X list. | ||||||
|  | func (es EditScript) LenX() int { return len(es) - es.stats().NY } | ||||||
|  | 
 | ||||||
|  | // LenY is the length of the Y list. | ||||||
|  | func (es EditScript) LenY() int { return len(es) - es.stats().NX } | ||||||
|  | 
 | ||||||
|  | // EqualFunc reports whether the symbols at indexes ix and iy are equal. | ||||||
|  | // When called by Difference, the index is guaranteed to be within nx and ny. | ||||||
|  | type EqualFunc func(ix int, iy int) Result | ||||||
|  | 
 | ||||||
|  | // Result is the result of comparison. | ||||||
|  | // NumSame is the number of sub-elements that are equal. | ||||||
|  | // NumDiff is the number of sub-elements that are not equal. | ||||||
|  | type Result struct{ NumSame, NumDiff int } | ||||||
|  | 
 | ||||||
|  | // BoolResult returns a Result that is either Equal or not Equal. | ||||||
|  | func BoolResult(b bool) Result { | ||||||
|  | 	if b { | ||||||
|  | 		return Result{NumSame: 1} // Equal, Similar | ||||||
|  | 	} else { | ||||||
|  | 		return Result{NumDiff: 2} // Not Equal, not Similar | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Equal indicates whether the symbols are equal. Two symbols are equal | ||||||
|  | // if and only if NumDiff == 0. If Equal, then they are also Similar. | ||||||
|  | func (r Result) Equal() bool { return r.NumDiff == 0 } | ||||||
|  | 
 | ||||||
|  | // Similar indicates whether two symbols are similar and may be represented | ||||||
|  | // by using the Modified type. As a special case, we consider binary comparisons | ||||||
|  | // (i.e., those that return Result{1, 0} or Result{0, 1}) to be similar. | ||||||
|  | // | ||||||
|  | // The exact ratio of NumSame to NumDiff to determine similarity may change. | ||||||
|  | func (r Result) Similar() bool { | ||||||
|  | 	// Use NumSame+1 to offset NumSame so that binary comparisons are similar. | ||||||
|  | 	return r.NumSame+1 >= r.NumDiff | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Difference reports whether two lists of lengths nx and ny are equal | ||||||
|  | // given the definition of equality provided as f. | ||||||
|  | // | ||||||
|  | // This function returns an edit-script, which is a sequence of operations | ||||||
|  | // needed to convert one list into the other. The following invariants for | ||||||
|  | // the edit-script are maintained: | ||||||
|  | //	• eq == (es.Dist()==0) | ||||||
|  | //	• nx == es.LenX() | ||||||
|  | //	• ny == es.LenY() | ||||||
|  | // | ||||||
|  | // This algorithm is not guaranteed to be an optimal solution (i.e., one that | ||||||
|  | // produces an edit-script with a minimal Levenshtein distance). This algorithm | ||||||
|  | // favors performance over optimality. The exact output is not guaranteed to | ||||||
|  | // be stable and may change over time. | ||||||
|  | func Difference(nx, ny int, f EqualFunc) (es EditScript) { | ||||||
|  | 	// This algorithm is based on traversing what is known as an "edit-graph". | ||||||
|  | 	// See Figure 1 from "An O(ND) Difference Algorithm and Its Variations" | ||||||
|  | 	// by Eugene W. Myers. Since D can be as large as N itself, this is | ||||||
|  | 	// effectively O(N^2). Unlike the algorithm from that paper, we are not | ||||||
|  | 	// interested in the optimal path, but at least some "decent" path. | ||||||
|  | 	// | ||||||
|  | 	// For example, let X and Y be lists of symbols: | ||||||
|  | 	//	X = [A B C A B B A] | ||||||
|  | 	//	Y = [C B A B A C] | ||||||
|  | 	// | ||||||
|  | 	// The edit-graph can be drawn as the following: | ||||||
|  | 	//	   A B C A B B A | ||||||
|  | 	//	  ┌─────────────┐ | ||||||
|  | 	//	C │_|_|\|_|_|_|_│ 0 | ||||||
|  | 	//	B │_|\|_|_|\|\|_│ 1 | ||||||
|  | 	//	A │\|_|_|\|_|_|\│ 2 | ||||||
|  | 	//	B │_|\|_|_|\|\|_│ 3 | ||||||
|  | 	//	A │\|_|_|\|_|_|\│ 4 | ||||||
|  | 	//	C │ | |\| | | | │ 5 | ||||||
|  | 	//	  └─────────────┘ 6 | ||||||
|  | 	//	   0 1 2 3 4 5 6 7 | ||||||
|  | 	// | ||||||
|  | 	// List X is written along the horizontal axis, while list Y is written | ||||||
|  | 	// along the vertical axis. At any point on this grid, if the symbol in | ||||||
|  | 	// list X matches the corresponding symbol in list Y, then a '\' is drawn. | ||||||
|  | 	// The goal of any minimal edit-script algorithm is to find a path from the | ||||||
|  | 	// top-left corner to the bottom-right corner, while traveling through the | ||||||
|  | 	// fewest horizontal or vertical edges. | ||||||
|  | 	// A horizontal edge is equivalent to inserting a symbol from list X. | ||||||
|  | 	// A vertical edge is equivalent to inserting a symbol from list Y. | ||||||
|  | 	// A diagonal edge is equivalent to a matching symbol between both X and Y. | ||||||
|  | 
 | ||||||
|  | 	// Invariants: | ||||||
|  | 	//	• 0 ≤ fwdPath.X ≤ (fwdFrontier.X, revFrontier.X) ≤ revPath.X ≤ nx | ||||||
|  | 	//	• 0 ≤ fwdPath.Y ≤ (fwdFrontier.Y, revFrontier.Y) ≤ revPath.Y ≤ ny | ||||||
|  | 	// | ||||||
|  | 	// In general: | ||||||
|  | 	//	• fwdFrontier.X < revFrontier.X | ||||||
|  | 	//	• fwdFrontier.Y < revFrontier.Y | ||||||
|  | 	// Unless, it is time for the algorithm to terminate. | ||||||
|  | 	fwdPath := path{+1, point{0, 0}, make(EditScript, 0, (nx+ny)/2)} | ||||||
|  | 	revPath := path{-1, point{nx, ny}, make(EditScript, 0)} | ||||||
|  | 	fwdFrontier := fwdPath.point // Forward search frontier | ||||||
|  | 	revFrontier := revPath.point // Reverse search frontier | ||||||
|  | 
 | ||||||
|  | 	// Search budget bounds the cost of searching for better paths. | ||||||
|  | 	// The longest sequence of non-matching symbols that can be tolerated is | ||||||
|  | 	// approximately the square-root of the search budget. | ||||||
|  | 	searchBudget := 4 * (nx + ny) // O(n) | ||||||
|  | 
 | ||||||
|  | 	// The algorithm below is a greedy, meet-in-the-middle algorithm for | ||||||
|  | 	// computing sub-optimal edit-scripts between two lists. | ||||||
|  | 	// | ||||||
|  | 	// The algorithm is approximately as follows: | ||||||
|  | 	//	• Searching for differences switches back-and-forth between | ||||||
|  | 	//	a search that starts at the beginning (the top-left corner), and | ||||||
|  | 	//	a search that starts at the end (the bottom-right corner). The goal of | ||||||
|  | 	//	the search is connect with the search from the opposite corner. | ||||||
|  | 	//	• As we search, we build a path in a greedy manner, where the first | ||||||
|  | 	//	match seen is added to the path (this is sub-optimal, but provides a | ||||||
|  | 	//	decent result in practice). When matches are found, we try the next pair | ||||||
|  | 	//	of symbols in the lists and follow all matches as far as possible. | ||||||
|  | 	//	• When searching for matches, we search along a diagonal going through | ||||||
|  | 	//	through the "frontier" point. If no matches are found, we advance the | ||||||
|  | 	//	frontier towards the opposite corner. | ||||||
|  | 	//	• This algorithm terminates when either the X coordinates or the | ||||||
|  | 	//	Y coordinates of the forward and reverse frontier points ever intersect. | ||||||
|  | 	// | ||||||
|  | 	// This algorithm is correct even if searching only in the forward direction | ||||||
|  | 	// or in the reverse direction. We do both because it is commonly observed | ||||||
|  | 	// that two lists commonly differ because elements were added to the front | ||||||
|  | 	// or end of the other list. | ||||||
|  | 	// | ||||||
|  | 	// Running the tests with the "cmp_debug" build tag prints a visualization | ||||||
|  | 	// of the algorithm running in real-time. This is educational for | ||||||
|  | 	// understanding how the algorithm works. See debug_enable.go. | ||||||
|  | 	f = debug.Begin(nx, ny, f, &fwdPath.es, &revPath.es) | ||||||
|  | 	for { | ||||||
|  | 		// Forward search from the beginning. | ||||||
|  | 		if fwdFrontier.X >= revFrontier.X || fwdFrontier.Y >= revFrontier.Y || searchBudget == 0 { | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  | 		for stop1, stop2, i := false, false, 0; !(stop1 && stop2) && searchBudget > 0; i++ { | ||||||
|  | 			// Search in a diagonal pattern for a match. | ||||||
|  | 			z := zigzag(i) | ||||||
|  | 			p := point{fwdFrontier.X + z, fwdFrontier.Y - z} | ||||||
|  | 			switch { | ||||||
|  | 			case p.X >= revPath.X || p.Y < fwdPath.Y: | ||||||
|  | 				stop1 = true // Hit top-right corner | ||||||
|  | 			case p.Y >= revPath.Y || p.X < fwdPath.X: | ||||||
|  | 				stop2 = true // Hit bottom-left corner | ||||||
|  | 			case f(p.X, p.Y).Equal(): | ||||||
|  | 				// Match found, so connect the path to this point. | ||||||
|  | 				fwdPath.connect(p, f) | ||||||
|  | 				fwdPath.append(Identity) | ||||||
|  | 				// Follow sequence of matches as far as possible. | ||||||
|  | 				for fwdPath.X < revPath.X && fwdPath.Y < revPath.Y { | ||||||
|  | 					if !f(fwdPath.X, fwdPath.Y).Equal() { | ||||||
|  | 						break | ||||||
|  | 					} | ||||||
|  | 					fwdPath.append(Identity) | ||||||
|  | 				} | ||||||
|  | 				fwdFrontier = fwdPath.point | ||||||
|  | 				stop1, stop2 = true, true | ||||||
|  | 			default: | ||||||
|  | 				searchBudget-- // Match not found | ||||||
|  | 			} | ||||||
|  | 			debug.Update() | ||||||
|  | 		} | ||||||
|  | 		// Advance the frontier towards reverse point. | ||||||
|  | 		if revPath.X-fwdFrontier.X >= revPath.Y-fwdFrontier.Y { | ||||||
|  | 			fwdFrontier.X++ | ||||||
|  | 		} else { | ||||||
|  | 			fwdFrontier.Y++ | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		// Reverse search from the end. | ||||||
|  | 		if fwdFrontier.X >= revFrontier.X || fwdFrontier.Y >= revFrontier.Y || searchBudget == 0 { | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  | 		for stop1, stop2, i := false, false, 0; !(stop1 && stop2) && searchBudget > 0; i++ { | ||||||
|  | 			// Search in a diagonal pattern for a match. | ||||||
|  | 			z := zigzag(i) | ||||||
|  | 			p := point{revFrontier.X - z, revFrontier.Y + z} | ||||||
|  | 			switch { | ||||||
|  | 			case fwdPath.X >= p.X || revPath.Y < p.Y: | ||||||
|  | 				stop1 = true // Hit bottom-left corner | ||||||
|  | 			case fwdPath.Y >= p.Y || revPath.X < p.X: | ||||||
|  | 				stop2 = true // Hit top-right corner | ||||||
|  | 			case f(p.X-1, p.Y-1).Equal(): | ||||||
|  | 				// Match found, so connect the path to this point. | ||||||
|  | 				revPath.connect(p, f) | ||||||
|  | 				revPath.append(Identity) | ||||||
|  | 				// Follow sequence of matches as far as possible. | ||||||
|  | 				for fwdPath.X < revPath.X && fwdPath.Y < revPath.Y { | ||||||
|  | 					if !f(revPath.X-1, revPath.Y-1).Equal() { | ||||||
|  | 						break | ||||||
|  | 					} | ||||||
|  | 					revPath.append(Identity) | ||||||
|  | 				} | ||||||
|  | 				revFrontier = revPath.point | ||||||
|  | 				stop1, stop2 = true, true | ||||||
|  | 			default: | ||||||
|  | 				searchBudget-- // Match not found | ||||||
|  | 			} | ||||||
|  | 			debug.Update() | ||||||
|  | 		} | ||||||
|  | 		// Advance the frontier towards forward point. | ||||||
|  | 		if revFrontier.X-fwdPath.X >= revFrontier.Y-fwdPath.Y { | ||||||
|  | 			revFrontier.X-- | ||||||
|  | 		} else { | ||||||
|  | 			revFrontier.Y-- | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Join the forward and reverse paths and then append the reverse path. | ||||||
|  | 	fwdPath.connect(revPath.point, f) | ||||||
|  | 	for i := len(revPath.es) - 1; i >= 0; i-- { | ||||||
|  | 		t := revPath.es[i] | ||||||
|  | 		revPath.es = revPath.es[:i] | ||||||
|  | 		fwdPath.append(t) | ||||||
|  | 	} | ||||||
|  | 	debug.Finish() | ||||||
|  | 	return fwdPath.es | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type path struct { | ||||||
|  | 	dir   int // +1 if forward, -1 if reverse | ||||||
|  | 	point     // Leading point of the EditScript path | ||||||
|  | 	es    EditScript | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // connect appends any necessary Identity, Modified, UniqueX, or UniqueY types | ||||||
|  | // to the edit-script to connect p.point to dst. | ||||||
|  | func (p *path) connect(dst point, f EqualFunc) { | ||||||
|  | 	if p.dir > 0 { | ||||||
|  | 		// Connect in forward direction. | ||||||
|  | 		for dst.X > p.X && dst.Y > p.Y { | ||||||
|  | 			switch r := f(p.X, p.Y); { | ||||||
|  | 			case r.Equal(): | ||||||
|  | 				p.append(Identity) | ||||||
|  | 			case r.Similar(): | ||||||
|  | 				p.append(Modified) | ||||||
|  | 			case dst.X-p.X >= dst.Y-p.Y: | ||||||
|  | 				p.append(UniqueX) | ||||||
|  | 			default: | ||||||
|  | 				p.append(UniqueY) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		for dst.X > p.X { | ||||||
|  | 			p.append(UniqueX) | ||||||
|  | 		} | ||||||
|  | 		for dst.Y > p.Y { | ||||||
|  | 			p.append(UniqueY) | ||||||
|  | 		} | ||||||
|  | 	} else { | ||||||
|  | 		// Connect in reverse direction. | ||||||
|  | 		for p.X > dst.X && p.Y > dst.Y { | ||||||
|  | 			switch r := f(p.X-1, p.Y-1); { | ||||||
|  | 			case r.Equal(): | ||||||
|  | 				p.append(Identity) | ||||||
|  | 			case r.Similar(): | ||||||
|  | 				p.append(Modified) | ||||||
|  | 			case p.Y-dst.Y >= p.X-dst.X: | ||||||
|  | 				p.append(UniqueY) | ||||||
|  | 			default: | ||||||
|  | 				p.append(UniqueX) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		for p.X > dst.X { | ||||||
|  | 			p.append(UniqueX) | ||||||
|  | 		} | ||||||
|  | 		for p.Y > dst.Y { | ||||||
|  | 			p.append(UniqueY) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (p *path) append(t EditType) { | ||||||
|  | 	p.es = append(p.es, t) | ||||||
|  | 	switch t { | ||||||
|  | 	case Identity, Modified: | ||||||
|  | 		p.add(p.dir, p.dir) | ||||||
|  | 	case UniqueX: | ||||||
|  | 		p.add(p.dir, 0) | ||||||
|  | 	case UniqueY: | ||||||
|  | 		p.add(0, p.dir) | ||||||
|  | 	} | ||||||
|  | 	debug.Update() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type point struct{ X, Y int } | ||||||
|  | 
 | ||||||
|  | func (p *point) add(dx, dy int) { p.X += dx; p.Y += dy } | ||||||
|  | 
 | ||||||
|  | // zigzag maps a consecutive sequence of integers to a zig-zag sequence. | ||||||
|  | //	[0 1 2 3 4 5 ...] => [0 -1 +1 -2 +2 ...] | ||||||
|  | func zigzag(x int) int { | ||||||
|  | 	if x&1 != 0 { | ||||||
|  | 		x = ^x | ||||||
|  | 	} | ||||||
|  | 	return x >> 1 | ||||||
|  | } | ||||||
							
								
								
									
										9
									
								
								vendor/github.com/google/go-cmp/cmp/internal/flags/flags.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								vendor/github.com/google/go-cmp/cmp/internal/flags/flags.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | |||||||
|  | // Copyright 2019, The Go Authors. All rights reserved. | ||||||
|  | // Use of this source code is governed by a BSD-style | ||||||
|  | // license that can be found in the LICENSE.md file. | ||||||
|  | 
 | ||||||
|  | package flags | ||||||
|  | 
 | ||||||
|  | // Deterministic controls whether the output of Diff should be deterministic. | ||||||
|  | // This is only used for testing. | ||||||
|  | var Deterministic bool | ||||||
							
								
								
									
										10
									
								
								vendor/github.com/google/go-cmp/cmp/internal/flags/toolchain_legacy.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								vendor/github.com/google/go-cmp/cmp/internal/flags/toolchain_legacy.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | |||||||
|  | // Copyright 2019, The Go Authors. All rights reserved. | ||||||
|  | // Use of this source code is governed by a BSD-style | ||||||
|  | // license that can be found in the LICENSE.md file. | ||||||
|  | 
 | ||||||
|  | // +build !go1.10 | ||||||
|  | 
 | ||||||
|  | package flags | ||||||
|  | 
 | ||||||
|  | // AtLeastGo110 reports whether the Go toolchain is at least Go 1.10. | ||||||
|  | const AtLeastGo110 = false | ||||||
							
								
								
									
										10
									
								
								vendor/github.com/google/go-cmp/cmp/internal/flags/toolchain_recent.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								vendor/github.com/google/go-cmp/cmp/internal/flags/toolchain_recent.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | |||||||
|  | // Copyright 2019, The Go Authors. All rights reserved. | ||||||
|  | // Use of this source code is governed by a BSD-style | ||||||
|  | // license that can be found in the LICENSE.md file. | ||||||
|  | 
 | ||||||
|  | // +build go1.10 | ||||||
|  | 
 | ||||||
|  | package flags | ||||||
|  | 
 | ||||||
|  | // AtLeastGo110 reports whether the Go toolchain is at least Go 1.10. | ||||||
|  | const AtLeastGo110 = true | ||||||
							
								
								
									
										99
									
								
								vendor/github.com/google/go-cmp/cmp/internal/function/func.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								vendor/github.com/google/go-cmp/cmp/internal/function/func.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,99 @@ | |||||||
|  | // Copyright 2017, The Go Authors. All rights reserved. | ||||||
|  | // Use of this source code is governed by a BSD-style | ||||||
|  | // license that can be found in the LICENSE.md file. | ||||||
|  | 
 | ||||||
|  | // Package function provides functionality for identifying function types. | ||||||
|  | package function | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"reflect" | ||||||
|  | 	"regexp" | ||||||
|  | 	"runtime" | ||||||
|  | 	"strings" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | type funcType int | ||||||
|  | 
 | ||||||
|  | const ( | ||||||
|  | 	_ funcType = iota | ||||||
|  | 
 | ||||||
|  | 	tbFunc  // func(T) bool | ||||||
|  | 	ttbFunc // func(T, T) bool | ||||||
|  | 	trbFunc // func(T, R) bool | ||||||
|  | 	tibFunc // func(T, I) bool | ||||||
|  | 	trFunc  // func(T) R | ||||||
|  | 
 | ||||||
|  | 	Equal             = ttbFunc // func(T, T) bool | ||||||
|  | 	EqualAssignable   = tibFunc // func(T, I) bool; encapsulates func(T, T) bool | ||||||
|  | 	Transformer       = trFunc  // func(T) R | ||||||
|  | 	ValueFilter       = ttbFunc // func(T, T) bool | ||||||
|  | 	Less              = ttbFunc // func(T, T) bool | ||||||
|  | 	ValuePredicate    = tbFunc  // func(T) bool | ||||||
|  | 	KeyValuePredicate = trbFunc // func(T, R) bool | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | var boolType = reflect.TypeOf(true) | ||||||
|  | 
 | ||||||
|  | // IsType reports whether the reflect.Type is of the specified function type. | ||||||
|  | func IsType(t reflect.Type, ft funcType) bool { | ||||||
|  | 	if t == nil || t.Kind() != reflect.Func || t.IsVariadic() { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	ni, no := t.NumIn(), t.NumOut() | ||||||
|  | 	switch ft { | ||||||
|  | 	case tbFunc: // func(T) bool | ||||||
|  | 		if ni == 1 && no == 1 && t.Out(0) == boolType { | ||||||
|  | 			return true | ||||||
|  | 		} | ||||||
|  | 	case ttbFunc: // func(T, T) bool | ||||||
|  | 		if ni == 2 && no == 1 && t.In(0) == t.In(1) && t.Out(0) == boolType { | ||||||
|  | 			return true | ||||||
|  | 		} | ||||||
|  | 	case trbFunc: // func(T, R) bool | ||||||
|  | 		if ni == 2 && no == 1 && t.Out(0) == boolType { | ||||||
|  | 			return true | ||||||
|  | 		} | ||||||
|  | 	case tibFunc: // func(T, I) bool | ||||||
|  | 		if ni == 2 && no == 1 && t.In(0).AssignableTo(t.In(1)) && t.Out(0) == boolType { | ||||||
|  | 			return true | ||||||
|  | 		} | ||||||
|  | 	case trFunc: // func(T) R | ||||||
|  | 		if ni == 1 && no == 1 { | ||||||
|  | 			return true | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return false | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | var lastIdentRx = regexp.MustCompile(`[_\p{L}][_\p{L}\p{N}]*$`) | ||||||
|  | 
 | ||||||
|  | // NameOf returns the name of the function value. | ||||||
|  | func NameOf(v reflect.Value) string { | ||||||
|  | 	fnc := runtime.FuncForPC(v.Pointer()) | ||||||
|  | 	if fnc == nil { | ||||||
|  | 		return "<unknown>" | ||||||
|  | 	} | ||||||
|  | 	fullName := fnc.Name() // e.g., "long/path/name/mypkg.(*MyType).(long/path/name/mypkg.myMethod)-fm" | ||||||
|  | 
 | ||||||
|  | 	// Method closures have a "-fm" suffix. | ||||||
|  | 	fullName = strings.TrimSuffix(fullName, "-fm") | ||||||
|  | 
 | ||||||
|  | 	var name string | ||||||
|  | 	for len(fullName) > 0 { | ||||||
|  | 		inParen := strings.HasSuffix(fullName, ")") | ||||||
|  | 		fullName = strings.TrimSuffix(fullName, ")") | ||||||
|  | 
 | ||||||
|  | 		s := lastIdentRx.FindString(fullName) | ||||||
|  | 		if s == "" { | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  | 		name = s + "." + name | ||||||
|  | 		fullName = strings.TrimSuffix(fullName, s) | ||||||
|  | 
 | ||||||
|  | 		if i := strings.LastIndexByte(fullName, '('); inParen && i >= 0 { | ||||||
|  | 			fullName = fullName[:i] | ||||||
|  | 		} | ||||||
|  | 		fullName = strings.TrimSuffix(fullName, ".") | ||||||
|  | 	} | ||||||
|  | 	return strings.TrimSuffix(name, ".") | ||||||
|  | } | ||||||
							
								
								
									
										23
									
								
								vendor/github.com/google/go-cmp/cmp/internal/value/pointer_purego.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								vendor/github.com/google/go-cmp/cmp/internal/value/pointer_purego.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,23 @@ | |||||||
|  | // Copyright 2018, The Go Authors. All rights reserved. | ||||||
|  | // Use of this source code is governed by a BSD-style | ||||||
|  | // license that can be found in the LICENSE.md file. | ||||||
|  | 
 | ||||||
|  | // +build purego | ||||||
|  | 
 | ||||||
|  | package value | ||||||
|  | 
 | ||||||
|  | import "reflect" | ||||||
|  | 
 | ||||||
|  | // Pointer is an opaque typed pointer and is guaranteed to be comparable. | ||||||
|  | type Pointer struct { | ||||||
|  | 	p uintptr | ||||||
|  | 	t reflect.Type | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // PointerOf returns a Pointer from v, which must be a | ||||||
|  | // reflect.Ptr, reflect.Slice, or reflect.Map. | ||||||
|  | func PointerOf(v reflect.Value) Pointer { | ||||||
|  | 	// NOTE: Storing a pointer as an uintptr is technically incorrect as it | ||||||
|  | 	// assumes that the GC implementation does not use a moving collector. | ||||||
|  | 	return Pointer{v.Pointer(), v.Type()} | ||||||
|  | } | ||||||
							
								
								
									
										26
									
								
								vendor/github.com/google/go-cmp/cmp/internal/value/pointer_unsafe.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								vendor/github.com/google/go-cmp/cmp/internal/value/pointer_unsafe.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,26 @@ | |||||||
|  | // Copyright 2018, The Go Authors. All rights reserved. | ||||||
|  | // Use of this source code is governed by a BSD-style | ||||||
|  | // license that can be found in the LICENSE.md file. | ||||||
|  | 
 | ||||||
|  | // +build !purego | ||||||
|  | 
 | ||||||
|  | package value | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"reflect" | ||||||
|  | 	"unsafe" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // Pointer is an opaque typed pointer and is guaranteed to be comparable. | ||||||
|  | type Pointer struct { | ||||||
|  | 	p unsafe.Pointer | ||||||
|  | 	t reflect.Type | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // PointerOf returns a Pointer from v, which must be a | ||||||
|  | // reflect.Ptr, reflect.Slice, or reflect.Map. | ||||||
|  | func PointerOf(v reflect.Value) Pointer { | ||||||
|  | 	// The proper representation of a pointer is unsafe.Pointer, | ||||||
|  | 	// which is necessary if the GC ever uses a moving collector. | ||||||
|  | 	return Pointer{unsafe.Pointer(v.Pointer()), v.Type()} | ||||||
|  | } | ||||||
							
								
								
									
										104
									
								
								vendor/github.com/google/go-cmp/cmp/internal/value/sort.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								vendor/github.com/google/go-cmp/cmp/internal/value/sort.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,104 @@ | |||||||
|  | // Copyright 2017, The Go Authors. All rights reserved. | ||||||
|  | // Use of this source code is governed by a BSD-style | ||||||
|  | // license that can be found in the LICENSE.md file. | ||||||
|  | 
 | ||||||
|  | package value | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"math" | ||||||
|  | 	"reflect" | ||||||
|  | 	"sort" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // SortKeys sorts a list of map keys, deduplicating keys if necessary. | ||||||
|  | // The type of each value must be comparable. | ||||||
|  | func SortKeys(vs []reflect.Value) []reflect.Value { | ||||||
|  | 	if len(vs) == 0 { | ||||||
|  | 		return vs | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Sort the map keys. | ||||||
|  | 	sort.Slice(vs, func(i, j int) bool { return isLess(vs[i], vs[j]) }) | ||||||
|  | 
 | ||||||
|  | 	// Deduplicate keys (fails for NaNs). | ||||||
|  | 	vs2 := vs[:1] | ||||||
|  | 	for _, v := range vs[1:] { | ||||||
|  | 		if isLess(vs2[len(vs2)-1], v) { | ||||||
|  | 			vs2 = append(vs2, v) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return vs2 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // isLess is a generic function for sorting arbitrary map keys. | ||||||
|  | // The inputs must be of the same type and must be comparable. | ||||||
|  | func isLess(x, y reflect.Value) bool { | ||||||
|  | 	switch x.Type().Kind() { | ||||||
|  | 	case reflect.Bool: | ||||||
|  | 		return !x.Bool() && y.Bool() | ||||||
|  | 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | ||||||
|  | 		return x.Int() < y.Int() | ||||||
|  | 	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: | ||||||
|  | 		return x.Uint() < y.Uint() | ||||||
|  | 	case reflect.Float32, reflect.Float64: | ||||||
|  | 		fx, fy := x.Float(), y.Float() | ||||||
|  | 		return fx < fy || math.IsNaN(fx) && !math.IsNaN(fy) | ||||||
|  | 	case reflect.Complex64, reflect.Complex128: | ||||||
|  | 		cx, cy := x.Complex(), y.Complex() | ||||||
|  | 		rx, ix, ry, iy := real(cx), imag(cx), real(cy), imag(cy) | ||||||
|  | 		if rx == ry || (math.IsNaN(rx) && math.IsNaN(ry)) { | ||||||
|  | 			return ix < iy || math.IsNaN(ix) && !math.IsNaN(iy) | ||||||
|  | 		} | ||||||
|  | 		return rx < ry || math.IsNaN(rx) && !math.IsNaN(ry) | ||||||
|  | 	case reflect.Ptr, reflect.UnsafePointer, reflect.Chan: | ||||||
|  | 		return x.Pointer() < y.Pointer() | ||||||
|  | 	case reflect.String: | ||||||
|  | 		return x.String() < y.String() | ||||||
|  | 	case reflect.Array: | ||||||
|  | 		for i := 0; i < x.Len(); i++ { | ||||||
|  | 			if isLess(x.Index(i), y.Index(i)) { | ||||||
|  | 				return true | ||||||
|  | 			} | ||||||
|  | 			if isLess(y.Index(i), x.Index(i)) { | ||||||
|  | 				return false | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		return false | ||||||
|  | 	case reflect.Struct: | ||||||
|  | 		for i := 0; i < x.NumField(); i++ { | ||||||
|  | 			if isLess(x.Field(i), y.Field(i)) { | ||||||
|  | 				return true | ||||||
|  | 			} | ||||||
|  | 			if isLess(y.Field(i), x.Field(i)) { | ||||||
|  | 				return false | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		return false | ||||||
|  | 	case reflect.Interface: | ||||||
|  | 		vx, vy := x.Elem(), y.Elem() | ||||||
|  | 		if !vx.IsValid() || !vy.IsValid() { | ||||||
|  | 			return !vx.IsValid() && vy.IsValid() | ||||||
|  | 		} | ||||||
|  | 		tx, ty := vx.Type(), vy.Type() | ||||||
|  | 		if tx == ty { | ||||||
|  | 			return isLess(x.Elem(), y.Elem()) | ||||||
|  | 		} | ||||||
|  | 		if tx.Kind() != ty.Kind() { | ||||||
|  | 			return vx.Kind() < vy.Kind() | ||||||
|  | 		} | ||||||
|  | 		if tx.String() != ty.String() { | ||||||
|  | 			return tx.String() < ty.String() | ||||||
|  | 		} | ||||||
|  | 		if tx.PkgPath() != ty.PkgPath() { | ||||||
|  | 			return tx.PkgPath() < ty.PkgPath() | ||||||
|  | 		} | ||||||
|  | 		// This can happen in rare situations, so we fallback to just comparing | ||||||
|  | 		// the unique pointer for a reflect.Type. This guarantees deterministic | ||||||
|  | 		// ordering within a program, but it is obviously not stable. | ||||||
|  | 		return reflect.ValueOf(vx.Type()).Pointer() < reflect.ValueOf(vy.Type()).Pointer() | ||||||
|  | 	default: | ||||||
|  | 		// Must be Func, Map, or Slice; which are not comparable. | ||||||
|  | 		panic(fmt.Sprintf("%T is not comparable", x.Type())) | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										45
									
								
								vendor/github.com/google/go-cmp/cmp/internal/value/zero.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								vendor/github.com/google/go-cmp/cmp/internal/value/zero.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,45 @@ | |||||||
|  | // Copyright 2017, The Go Authors. All rights reserved. | ||||||
|  | // Use of this source code is governed by a BSD-style | ||||||
|  | // license that can be found in the LICENSE.md file. | ||||||
|  | 
 | ||||||
|  | package value | ||||||
|  | 
 | ||||||
|  | import "reflect" | ||||||
|  | 
 | ||||||
|  | // IsZero reports whether v is the zero value. | ||||||
|  | // This does not rely on Interface and so can be used on unexported fields. | ||||||
|  | func IsZero(v reflect.Value) bool { | ||||||
|  | 	switch v.Kind() { | ||||||
|  | 	case reflect.Bool: | ||||||
|  | 		return v.Bool() == false | ||||||
|  | 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | ||||||
|  | 		return v.Int() == 0 | ||||||
|  | 	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: | ||||||
|  | 		return v.Uint() == 0 | ||||||
|  | 	case reflect.Float32, reflect.Float64: | ||||||
|  | 		return v.Float() == 0 | ||||||
|  | 	case reflect.Complex64, reflect.Complex128: | ||||||
|  | 		return v.Complex() == 0 | ||||||
|  | 	case reflect.String: | ||||||
|  | 		return v.String() == "" | ||||||
|  | 	case reflect.UnsafePointer: | ||||||
|  | 		return v.Pointer() == 0 | ||||||
|  | 	case reflect.Chan, reflect.Func, reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice: | ||||||
|  | 		return v.IsNil() | ||||||
|  | 	case reflect.Array: | ||||||
|  | 		for i := 0; i < v.Len(); i++ { | ||||||
|  | 			if !IsZero(v.Index(i)) { | ||||||
|  | 				return false | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		return true | ||||||
|  | 	case reflect.Struct: | ||||||
|  | 		for i := 0; i < v.NumField(); i++ { | ||||||
|  | 			if !IsZero(v.Field(i)) { | ||||||
|  | 				return false | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		return true | ||||||
|  | 	} | ||||||
|  | 	return false | ||||||
|  | } | ||||||
							
								
								
									
										524
									
								
								vendor/github.com/google/go-cmp/cmp/options.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										524
									
								
								vendor/github.com/google/go-cmp/cmp/options.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,524 @@ | |||||||
|  | // Copyright 2017, The Go Authors. All rights reserved. | ||||||
|  | // Use of this source code is governed by a BSD-style | ||||||
|  | // license that can be found in the LICENSE.md file. | ||||||
|  | 
 | ||||||
|  | package cmp | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"reflect" | ||||||
|  | 	"regexp" | ||||||
|  | 	"strings" | ||||||
|  | 
 | ||||||
|  | 	"github.com/google/go-cmp/cmp/internal/function" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // Option configures for specific behavior of Equal and Diff. In particular, | ||||||
|  | // the fundamental Option functions (Ignore, Transformer, and Comparer), | ||||||
|  | // configure how equality is determined. | ||||||
|  | // | ||||||
|  | // The fundamental options may be composed with filters (FilterPath and | ||||||
|  | // FilterValues) to control the scope over which they are applied. | ||||||
|  | // | ||||||
|  | // The cmp/cmpopts package provides helper functions for creating options that | ||||||
|  | // may be used with Equal and Diff. | ||||||
|  | type Option interface { | ||||||
|  | 	// filter applies all filters and returns the option that remains. | ||||||
|  | 	// Each option may only read s.curPath and call s.callTTBFunc. | ||||||
|  | 	// | ||||||
|  | 	// An Options is returned only if multiple comparers or transformers | ||||||
|  | 	// can apply simultaneously and will only contain values of those types | ||||||
|  | 	// or sub-Options containing values of those types. | ||||||
|  | 	filter(s *state, t reflect.Type, vx, vy reflect.Value) applicableOption | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // applicableOption represents the following types: | ||||||
|  | //	Fundamental: ignore | validator | *comparer | *transformer | ||||||
|  | //	Grouping:    Options | ||||||
|  | type applicableOption interface { | ||||||
|  | 	Option | ||||||
|  | 
 | ||||||
|  | 	// apply executes the option, which may mutate s or panic. | ||||||
|  | 	apply(s *state, vx, vy reflect.Value) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // coreOption represents the following types: | ||||||
|  | //	Fundamental: ignore | validator | *comparer | *transformer | ||||||
|  | //	Filters:     *pathFilter | *valuesFilter | ||||||
|  | type coreOption interface { | ||||||
|  | 	Option | ||||||
|  | 	isCore() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type core struct{} | ||||||
|  | 
 | ||||||
|  | func (core) isCore() {} | ||||||
|  | 
 | ||||||
|  | // Options is a list of Option values that also satisfies the Option interface. | ||||||
|  | // Helper comparison packages may return an Options value when packing multiple | ||||||
|  | // Option values into a single Option. When this package processes an Options, | ||||||
|  | // it will be implicitly expanded into a flat list. | ||||||
|  | // | ||||||
|  | // Applying a filter on an Options is equivalent to applying that same filter | ||||||
|  | // on all individual options held within. | ||||||
|  | type Options []Option | ||||||
|  | 
 | ||||||
|  | func (opts Options) filter(s *state, t reflect.Type, vx, vy reflect.Value) (out applicableOption) { | ||||||
|  | 	for _, opt := range opts { | ||||||
|  | 		switch opt := opt.filter(s, t, vx, vy); opt.(type) { | ||||||
|  | 		case ignore: | ||||||
|  | 			return ignore{} // Only ignore can short-circuit evaluation | ||||||
|  | 		case validator: | ||||||
|  | 			out = validator{} // Takes precedence over comparer or transformer | ||||||
|  | 		case *comparer, *transformer, Options: | ||||||
|  | 			switch out.(type) { | ||||||
|  | 			case nil: | ||||||
|  | 				out = opt | ||||||
|  | 			case validator: | ||||||
|  | 				// Keep validator | ||||||
|  | 			case *comparer, *transformer, Options: | ||||||
|  | 				out = Options{out, opt} // Conflicting comparers or transformers | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return out | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (opts Options) apply(s *state, _, _ reflect.Value) { | ||||||
|  | 	const warning = "ambiguous set of applicable options" | ||||||
|  | 	const help = "consider using filters to ensure at most one Comparer or Transformer may apply" | ||||||
|  | 	var ss []string | ||||||
|  | 	for _, opt := range flattenOptions(nil, opts) { | ||||||
|  | 		ss = append(ss, fmt.Sprint(opt)) | ||||||
|  | 	} | ||||||
|  | 	set := strings.Join(ss, "\n\t") | ||||||
|  | 	panic(fmt.Sprintf("%s at %#v:\n\t%s\n%s", warning, s.curPath, set, help)) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (opts Options) String() string { | ||||||
|  | 	var ss []string | ||||||
|  | 	for _, opt := range opts { | ||||||
|  | 		ss = append(ss, fmt.Sprint(opt)) | ||||||
|  | 	} | ||||||
|  | 	return fmt.Sprintf("Options{%s}", strings.Join(ss, ", ")) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // FilterPath returns a new Option where opt is only evaluated if filter f | ||||||
|  | // returns true for the current Path in the value tree. | ||||||
|  | // | ||||||
|  | // This filter is called even if a slice element or map entry is missing and | ||||||
|  | // provides an opportunity to ignore such cases. The filter function must be | ||||||
|  | // symmetric such that the filter result is identical regardless of whether the | ||||||
|  | // missing value is from x or y. | ||||||
|  | // | ||||||
|  | // The option passed in may be an Ignore, Transformer, Comparer, Options, or | ||||||
|  | // a previously filtered Option. | ||||||
|  | func FilterPath(f func(Path) bool, opt Option) Option { | ||||||
|  | 	if f == nil { | ||||||
|  | 		panic("invalid path filter function") | ||||||
|  | 	} | ||||||
|  | 	if opt := normalizeOption(opt); opt != nil { | ||||||
|  | 		return &pathFilter{fnc: f, opt: opt} | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type pathFilter struct { | ||||||
|  | 	core | ||||||
|  | 	fnc func(Path) bool | ||||||
|  | 	opt Option | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (f pathFilter) filter(s *state, t reflect.Type, vx, vy reflect.Value) applicableOption { | ||||||
|  | 	if f.fnc(s.curPath) { | ||||||
|  | 		return f.opt.filter(s, t, vx, vy) | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (f pathFilter) String() string { | ||||||
|  | 	return fmt.Sprintf("FilterPath(%s, %v)", function.NameOf(reflect.ValueOf(f.fnc)), f.opt) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // FilterValues returns a new Option where opt is only evaluated if filter f, | ||||||
|  | // which is a function of the form "func(T, T) bool", returns true for the | ||||||
|  | // current pair of values being compared. If either value is invalid or | ||||||
|  | // the type of the values is not assignable to T, then this filter implicitly | ||||||
|  | // returns false. | ||||||
|  | // | ||||||
|  | // The filter function must be | ||||||
|  | // symmetric (i.e., agnostic to the order of the inputs) and | ||||||
|  | // deterministic (i.e., produces the same result when given the same inputs). | ||||||
|  | // If T is an interface, it is possible that f is called with two values with | ||||||
|  | // different concrete types that both implement T. | ||||||
|  | // | ||||||
|  | // The option passed in may be an Ignore, Transformer, Comparer, Options, or | ||||||
|  | // a previously filtered Option. | ||||||
|  | func FilterValues(f interface{}, opt Option) Option { | ||||||
|  | 	v := reflect.ValueOf(f) | ||||||
|  | 	if !function.IsType(v.Type(), function.ValueFilter) || v.IsNil() { | ||||||
|  | 		panic(fmt.Sprintf("invalid values filter function: %T", f)) | ||||||
|  | 	} | ||||||
|  | 	if opt := normalizeOption(opt); opt != nil { | ||||||
|  | 		vf := &valuesFilter{fnc: v, opt: opt} | ||||||
|  | 		if ti := v.Type().In(0); ti.Kind() != reflect.Interface || ti.NumMethod() > 0 { | ||||||
|  | 			vf.typ = ti | ||||||
|  | 		} | ||||||
|  | 		return vf | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type valuesFilter struct { | ||||||
|  | 	core | ||||||
|  | 	typ reflect.Type  // T | ||||||
|  | 	fnc reflect.Value // func(T, T) bool | ||||||
|  | 	opt Option | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (f valuesFilter) filter(s *state, t reflect.Type, vx, vy reflect.Value) applicableOption { | ||||||
|  | 	if !vx.IsValid() || !vx.CanInterface() || !vy.IsValid() || !vy.CanInterface() { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 	if (f.typ == nil || t.AssignableTo(f.typ)) && s.callTTBFunc(f.fnc, vx, vy) { | ||||||
|  | 		return f.opt.filter(s, t, vx, vy) | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (f valuesFilter) String() string { | ||||||
|  | 	return fmt.Sprintf("FilterValues(%s, %v)", function.NameOf(f.fnc), f.opt) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Ignore is an Option that causes all comparisons to be ignored. | ||||||
|  | // This value is intended to be combined with FilterPath or FilterValues. | ||||||
|  | // It is an error to pass an unfiltered Ignore option to Equal. | ||||||
|  | func Ignore() Option { return ignore{} } | ||||||
|  | 
 | ||||||
|  | type ignore struct{ core } | ||||||
|  | 
 | ||||||
|  | func (ignore) isFiltered() bool                                                     { return false } | ||||||
|  | func (ignore) filter(_ *state, _ reflect.Type, _, _ reflect.Value) applicableOption { return ignore{} } | ||||||
|  | func (ignore) apply(s *state, _, _ reflect.Value)                                   { s.report(true, reportByIgnore) } | ||||||
|  | func (ignore) String() string                                                       { return "Ignore()" } | ||||||
|  | 
 | ||||||
|  | // validator is a sentinel Option type to indicate that some options could not | ||||||
|  | // be evaluated due to unexported fields, missing slice elements, or | ||||||
|  | // missing map entries. Both values are validator only for unexported fields. | ||||||
|  | type validator struct{ core } | ||||||
|  | 
 | ||||||
|  | func (validator) filter(_ *state, _ reflect.Type, vx, vy reflect.Value) applicableOption { | ||||||
|  | 	if !vx.IsValid() || !vy.IsValid() { | ||||||
|  | 		return validator{} | ||||||
|  | 	} | ||||||
|  | 	if !vx.CanInterface() || !vy.CanInterface() { | ||||||
|  | 		return validator{} | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | func (validator) apply(s *state, vx, vy reflect.Value) { | ||||||
|  | 	// Implies missing slice element or map entry. | ||||||
|  | 	if !vx.IsValid() || !vy.IsValid() { | ||||||
|  | 		s.report(vx.IsValid() == vy.IsValid(), 0) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Unable to Interface implies unexported field without visibility access. | ||||||
|  | 	if !vx.CanInterface() || !vy.CanInterface() { | ||||||
|  | 		const help = "consider using a custom Comparer; if you control the implementation of type, you can also consider AllowUnexported or cmpopts.IgnoreUnexported" | ||||||
|  | 		panic(fmt.Sprintf("cannot handle unexported field: %#v\n%s", s.curPath, help)) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	panic("not reachable") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // identRx represents a valid identifier according to the Go specification. | ||||||
|  | const identRx = `[_\p{L}][_\p{L}\p{N}]*` | ||||||
|  | 
 | ||||||
|  | var identsRx = regexp.MustCompile(`^` + identRx + `(\.` + identRx + `)*$`) | ||||||
|  | 
 | ||||||
|  | // Transformer returns an Option that applies a transformation function that | ||||||
|  | // converts values of a certain type into that of another. | ||||||
|  | // | ||||||
|  | // The transformer f must be a function "func(T) R" that converts values of | ||||||
|  | // type T to those of type R and is implicitly filtered to input values | ||||||
|  | // assignable to T. The transformer must not mutate T in any way. | ||||||
|  | // | ||||||
|  | // To help prevent some cases of infinite recursive cycles applying the | ||||||
|  | // same transform to the output of itself (e.g., in the case where the | ||||||
|  | // input and output types are the same), an implicit filter is added such that | ||||||
|  | // a transformer is applicable only if that exact transformer is not already | ||||||
|  | // in the tail of the Path since the last non-Transform step. | ||||||
|  | // For situations where the implicit filter is still insufficient, | ||||||
|  | // consider using cmpopts.AcyclicTransformer, which adds a filter | ||||||
|  | // to prevent the transformer from being recursively applied upon itself. | ||||||
|  | // | ||||||
|  | // The name is a user provided label that is used as the Transform.Name in the | ||||||
|  | // transformation PathStep (and eventually shown in the Diff output). | ||||||
|  | // The name must be a valid identifier or qualified identifier in Go syntax. | ||||||
|  | // If empty, an arbitrary name is used. | ||||||
|  | func Transformer(name string, f interface{}) Option { | ||||||
|  | 	v := reflect.ValueOf(f) | ||||||
|  | 	if !function.IsType(v.Type(), function.Transformer) || v.IsNil() { | ||||||
|  | 		panic(fmt.Sprintf("invalid transformer function: %T", f)) | ||||||
|  | 	} | ||||||
|  | 	if name == "" { | ||||||
|  | 		name = function.NameOf(v) | ||||||
|  | 		if !identsRx.MatchString(name) { | ||||||
|  | 			name = "λ" // Lambda-symbol as placeholder name | ||||||
|  | 		} | ||||||
|  | 	} else if !identsRx.MatchString(name) { | ||||||
|  | 		panic(fmt.Sprintf("invalid name: %q", name)) | ||||||
|  | 	} | ||||||
|  | 	tr := &transformer{name: name, fnc: reflect.ValueOf(f)} | ||||||
|  | 	if ti := v.Type().In(0); ti.Kind() != reflect.Interface || ti.NumMethod() > 0 { | ||||||
|  | 		tr.typ = ti | ||||||
|  | 	} | ||||||
|  | 	return tr | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type transformer struct { | ||||||
|  | 	core | ||||||
|  | 	name string | ||||||
|  | 	typ  reflect.Type  // T | ||||||
|  | 	fnc  reflect.Value // func(T) R | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (tr *transformer) isFiltered() bool { return tr.typ != nil } | ||||||
|  | 
 | ||||||
|  | func (tr *transformer) filter(s *state, t reflect.Type, _, _ reflect.Value) applicableOption { | ||||||
|  | 	for i := len(s.curPath) - 1; i >= 0; i-- { | ||||||
|  | 		if t, ok := s.curPath[i].(Transform); !ok { | ||||||
|  | 			break // Hit most recent non-Transform step | ||||||
|  | 		} else if tr == t.trans { | ||||||
|  | 			return nil // Cannot directly use same Transform | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	if tr.typ == nil || t.AssignableTo(tr.typ) { | ||||||
|  | 		return tr | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (tr *transformer) apply(s *state, vx, vy reflect.Value) { | ||||||
|  | 	step := Transform{&transform{pathStep{typ: tr.fnc.Type().Out(0)}, tr}} | ||||||
|  | 	vvx := s.callTRFunc(tr.fnc, vx, step) | ||||||
|  | 	vvy := s.callTRFunc(tr.fnc, vy, step) | ||||||
|  | 	step.vx, step.vy = vvx, vvy | ||||||
|  | 	s.compareAny(step) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (tr transformer) String() string { | ||||||
|  | 	return fmt.Sprintf("Transformer(%s, %s)", tr.name, function.NameOf(tr.fnc)) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Comparer returns an Option that determines whether two values are equal | ||||||
|  | // to each other. | ||||||
|  | // | ||||||
|  | // The comparer f must be a function "func(T, T) bool" and is implicitly | ||||||
|  | // filtered to input values assignable to T. If T is an interface, it is | ||||||
|  | // possible that f is called with two values of different concrete types that | ||||||
|  | // both implement T. | ||||||
|  | // | ||||||
|  | // The equality function must be: | ||||||
|  | //	• Symmetric: equal(x, y) == equal(y, x) | ||||||
|  | //	• Deterministic: equal(x, y) == equal(x, y) | ||||||
|  | //	• Pure: equal(x, y) does not modify x or y | ||||||
|  | func Comparer(f interface{}) Option { | ||||||
|  | 	v := reflect.ValueOf(f) | ||||||
|  | 	if !function.IsType(v.Type(), function.Equal) || v.IsNil() { | ||||||
|  | 		panic(fmt.Sprintf("invalid comparer function: %T", f)) | ||||||
|  | 	} | ||||||
|  | 	cm := &comparer{fnc: v} | ||||||
|  | 	if ti := v.Type().In(0); ti.Kind() != reflect.Interface || ti.NumMethod() > 0 { | ||||||
|  | 		cm.typ = ti | ||||||
|  | 	} | ||||||
|  | 	return cm | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type comparer struct { | ||||||
|  | 	core | ||||||
|  | 	typ reflect.Type  // T | ||||||
|  | 	fnc reflect.Value // func(T, T) bool | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (cm *comparer) isFiltered() bool { return cm.typ != nil } | ||||||
|  | 
 | ||||||
|  | func (cm *comparer) filter(_ *state, t reflect.Type, _, _ reflect.Value) applicableOption { | ||||||
|  | 	if cm.typ == nil || t.AssignableTo(cm.typ) { | ||||||
|  | 		return cm | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (cm *comparer) apply(s *state, vx, vy reflect.Value) { | ||||||
|  | 	eq := s.callTTBFunc(cm.fnc, vx, vy) | ||||||
|  | 	s.report(eq, reportByFunc) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (cm comparer) String() string { | ||||||
|  | 	return fmt.Sprintf("Comparer(%s)", function.NameOf(cm.fnc)) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // AllowUnexported returns an Option that forcibly allows operations on | ||||||
|  | // unexported fields in certain structs, which are specified by passing in a | ||||||
|  | // value of each struct type. | ||||||
|  | // | ||||||
|  | // Users of this option must understand that comparing on unexported fields | ||||||
|  | // from external packages is not safe since changes in the internal | ||||||
|  | // implementation of some external package may cause the result of Equal | ||||||
|  | // to unexpectedly change. However, it may be valid to use this option on types | ||||||
|  | // defined in an internal package where the semantic meaning of an unexported | ||||||
|  | // field is in the control of the user. | ||||||
|  | // | ||||||
|  | // In many cases, a custom Comparer should be used instead that defines | ||||||
|  | // equality as a function of the public API of a type rather than the underlying | ||||||
|  | // unexported implementation. | ||||||
|  | // | ||||||
|  | // For example, the reflect.Type documentation defines equality to be determined | ||||||
|  | // by the == operator on the interface (essentially performing a shallow pointer | ||||||
|  | // comparison) and most attempts to compare *regexp.Regexp types are interested | ||||||
|  | // in only checking that the regular expression strings are equal. | ||||||
|  | // Both of these are accomplished using Comparers: | ||||||
|  | // | ||||||
|  | //	Comparer(func(x, y reflect.Type) bool { return x == y }) | ||||||
|  | //	Comparer(func(x, y *regexp.Regexp) bool { return x.String() == y.String() }) | ||||||
|  | // | ||||||
|  | // In other cases, the cmpopts.IgnoreUnexported option can be used to ignore | ||||||
|  | // all unexported fields on specified struct types. | ||||||
|  | func AllowUnexported(types ...interface{}) Option { | ||||||
|  | 	if !supportAllowUnexported { | ||||||
|  | 		panic("AllowUnexported is not supported on purego builds, Google App Engine Standard, or GopherJS") | ||||||
|  | 	} | ||||||
|  | 	m := make(map[reflect.Type]bool) | ||||||
|  | 	for _, typ := range types { | ||||||
|  | 		t := reflect.TypeOf(typ) | ||||||
|  | 		if t.Kind() != reflect.Struct { | ||||||
|  | 			panic(fmt.Sprintf("invalid struct type: %T", typ)) | ||||||
|  | 		} | ||||||
|  | 		m[t] = true | ||||||
|  | 	} | ||||||
|  | 	return visibleStructs(m) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type visibleStructs map[reflect.Type]bool | ||||||
|  | 
 | ||||||
|  | func (visibleStructs) filter(_ *state, _ reflect.Type, _, _ reflect.Value) applicableOption { | ||||||
|  | 	panic("not implemented") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Result represents the comparison result for a single node and | ||||||
|  | // is provided by cmp when calling Result (see Reporter). | ||||||
|  | type Result struct { | ||||||
|  | 	_     [0]func() // Make Result incomparable | ||||||
|  | 	flags resultFlags | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Equal reports whether the node was determined to be equal or not. | ||||||
|  | // As a special case, ignored nodes are considered equal. | ||||||
|  | func (r Result) Equal() bool { | ||||||
|  | 	return r.flags&(reportEqual|reportByIgnore) != 0 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // ByIgnore reports whether the node is equal because it was ignored. | ||||||
|  | // This never reports true if Equal reports false. | ||||||
|  | func (r Result) ByIgnore() bool { | ||||||
|  | 	return r.flags&reportByIgnore != 0 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // ByMethod reports whether the Equal method determined equality. | ||||||
|  | func (r Result) ByMethod() bool { | ||||||
|  | 	return r.flags&reportByMethod != 0 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // ByFunc reports whether a Comparer function determined equality. | ||||||
|  | func (r Result) ByFunc() bool { | ||||||
|  | 	return r.flags&reportByFunc != 0 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type resultFlags uint | ||||||
|  | 
 | ||||||
|  | const ( | ||||||
|  | 	_ resultFlags = (1 << iota) / 2 | ||||||
|  | 
 | ||||||
|  | 	reportEqual | ||||||
|  | 	reportUnequal | ||||||
|  | 	reportByIgnore | ||||||
|  | 	reportByMethod | ||||||
|  | 	reportByFunc | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // Reporter is an Option that can be passed to Equal. When Equal traverses | ||||||
|  | // the value trees, it calls PushStep as it descends into each node in the | ||||||
|  | // tree and PopStep as it ascend out of the node. The leaves of the tree are | ||||||
|  | // either compared (determined to be equal or not equal) or ignored and reported | ||||||
|  | // as such by calling the Report method. | ||||||
|  | func Reporter(r interface { | ||||||
|  | 	// PushStep is called when a tree-traversal operation is performed. | ||||||
|  | 	// The PathStep itself is only valid until the step is popped. | ||||||
|  | 	// The PathStep.Values are valid for the duration of the entire traversal | ||||||
|  | 	// and must not be mutated. | ||||||
|  | 	// | ||||||
|  | 	// Equal always calls PushStep at the start to provide an operation-less | ||||||
|  | 	// PathStep used to report the root values. | ||||||
|  | 	// | ||||||
|  | 	// Within a slice, the exact set of inserted, removed, or modified elements | ||||||
|  | 	// is unspecified and may change in future implementations. | ||||||
|  | 	// The entries of a map are iterated through in an unspecified order. | ||||||
|  | 	PushStep(PathStep) | ||||||
|  | 
 | ||||||
|  | 	// Report is called exactly once on leaf nodes to report whether the | ||||||
|  | 	// comparison identified the node as equal, unequal, or ignored. | ||||||
|  | 	// A leaf node is one that is immediately preceded by and followed by | ||||||
|  | 	// a pair of PushStep and PopStep calls. | ||||||
|  | 	Report(Result) | ||||||
|  | 
 | ||||||
|  | 	// PopStep ascends back up the value tree. | ||||||
|  | 	// There is always a matching pop call for every push call. | ||||||
|  | 	PopStep() | ||||||
|  | }) Option { | ||||||
|  | 	return reporter{r} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type reporter struct{ reporterIface } | ||||||
|  | type reporterIface interface { | ||||||
|  | 	PushStep(PathStep) | ||||||
|  | 	Report(Result) | ||||||
|  | 	PopStep() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (reporter) filter(_ *state, _ reflect.Type, _, _ reflect.Value) applicableOption { | ||||||
|  | 	panic("not implemented") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // normalizeOption normalizes the input options such that all Options groups | ||||||
|  | // are flattened and groups with a single element are reduced to that element. | ||||||
|  | // Only coreOptions and Options containing coreOptions are allowed. | ||||||
|  | func normalizeOption(src Option) Option { | ||||||
|  | 	switch opts := flattenOptions(nil, Options{src}); len(opts) { | ||||||
|  | 	case 0: | ||||||
|  | 		return nil | ||||||
|  | 	case 1: | ||||||
|  | 		return opts[0] | ||||||
|  | 	default: | ||||||
|  | 		return opts | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // flattenOptions copies all options in src to dst as a flat list. | ||||||
|  | // Only coreOptions and Options containing coreOptions are allowed. | ||||||
|  | func flattenOptions(dst, src Options) Options { | ||||||
|  | 	for _, opt := range src { | ||||||
|  | 		switch opt := opt.(type) { | ||||||
|  | 		case nil: | ||||||
|  | 			continue | ||||||
|  | 		case Options: | ||||||
|  | 			dst = flattenOptions(dst, opt) | ||||||
|  | 		case coreOption: | ||||||
|  | 			dst = append(dst, opt) | ||||||
|  | 		default: | ||||||
|  | 			panic(fmt.Sprintf("invalid option type: %T", opt)) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return dst | ||||||
|  | } | ||||||
							
								
								
									
										308
									
								
								vendor/github.com/google/go-cmp/cmp/path.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										308
									
								
								vendor/github.com/google/go-cmp/cmp/path.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,308 @@ | |||||||
|  | // Copyright 2017, The Go Authors. All rights reserved. | ||||||
|  | // Use of this source code is governed by a BSD-style | ||||||
|  | // license that can be found in the LICENSE.md file. | ||||||
|  | 
 | ||||||
|  | package cmp | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"reflect" | ||||||
|  | 	"strings" | ||||||
|  | 	"unicode" | ||||||
|  | 	"unicode/utf8" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // Path is a list of PathSteps describing the sequence of operations to get | ||||||
|  | // from some root type to the current position in the value tree. | ||||||
|  | // The first Path element is always an operation-less PathStep that exists | ||||||
|  | // simply to identify the initial type. | ||||||
|  | // | ||||||
|  | // When traversing structs with embedded structs, the embedded struct will | ||||||
|  | // always be accessed as a field before traversing the fields of the | ||||||
|  | // embedded struct themselves. That is, an exported field from the | ||||||
|  | // embedded struct will never be accessed directly from the parent struct. | ||||||
|  | type Path []PathStep | ||||||
|  | 
 | ||||||
|  | // PathStep is a union-type for specific operations to traverse | ||||||
|  | // a value's tree structure. Users of this package never need to implement | ||||||
|  | // these types as values of this type will be returned by this package. | ||||||
|  | // | ||||||
|  | // Implementations of this interface are | ||||||
|  | // StructField, SliceIndex, MapIndex, Indirect, TypeAssertion, and Transform. | ||||||
|  | type PathStep interface { | ||||||
|  | 	String() string | ||||||
|  | 
 | ||||||
|  | 	// Type is the resulting type after performing the path step. | ||||||
|  | 	Type() reflect.Type | ||||||
|  | 
 | ||||||
|  | 	// Values is the resulting values after performing the path step. | ||||||
|  | 	// The type of each valid value is guaranteed to be identical to Type. | ||||||
|  | 	// | ||||||
|  | 	// In some cases, one or both may be invalid or have restrictions: | ||||||
|  | 	//	• For StructField, both are not interface-able if the current field | ||||||
|  | 	//	is unexported and the struct type is not explicitly permitted by | ||||||
|  | 	//	AllowUnexported to traverse unexported fields. | ||||||
|  | 	//	• For SliceIndex, one may be invalid if an element is missing from | ||||||
|  | 	//	either the x or y slice. | ||||||
|  | 	//	• For MapIndex, one may be invalid if an entry is missing from | ||||||
|  | 	//	either the x or y map. | ||||||
|  | 	// | ||||||
|  | 	// The provided values must not be mutated. | ||||||
|  | 	Values() (vx, vy reflect.Value) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | var ( | ||||||
|  | 	_ PathStep = StructField{} | ||||||
|  | 	_ PathStep = SliceIndex{} | ||||||
|  | 	_ PathStep = MapIndex{} | ||||||
|  | 	_ PathStep = Indirect{} | ||||||
|  | 	_ PathStep = TypeAssertion{} | ||||||
|  | 	_ PathStep = Transform{} | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func (pa *Path) push(s PathStep) { | ||||||
|  | 	*pa = append(*pa, s) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (pa *Path) pop() { | ||||||
|  | 	*pa = (*pa)[:len(*pa)-1] | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Last returns the last PathStep in the Path. | ||||||
|  | // If the path is empty, this returns a non-nil PathStep that reports a nil Type. | ||||||
|  | func (pa Path) Last() PathStep { | ||||||
|  | 	return pa.Index(-1) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Index returns the ith step in the Path and supports negative indexing. | ||||||
|  | // A negative index starts counting from the tail of the Path such that -1 | ||||||
|  | // refers to the last step, -2 refers to the second-to-last step, and so on. | ||||||
|  | // If index is invalid, this returns a non-nil PathStep that reports a nil Type. | ||||||
|  | func (pa Path) Index(i int) PathStep { | ||||||
|  | 	if i < 0 { | ||||||
|  | 		i = len(pa) + i | ||||||
|  | 	} | ||||||
|  | 	if i < 0 || i >= len(pa) { | ||||||
|  | 		return pathStep{} | ||||||
|  | 	} | ||||||
|  | 	return pa[i] | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // String returns the simplified path to a node. | ||||||
|  | // The simplified path only contains struct field accesses. | ||||||
|  | // | ||||||
|  | // For example: | ||||||
|  | //	MyMap.MySlices.MyField | ||||||
|  | func (pa Path) String() string { | ||||||
|  | 	var ss []string | ||||||
|  | 	for _, s := range pa { | ||||||
|  | 		if _, ok := s.(StructField); ok { | ||||||
|  | 			ss = append(ss, s.String()) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return strings.TrimPrefix(strings.Join(ss, ""), ".") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // GoString returns the path to a specific node using Go syntax. | ||||||
|  | // | ||||||
|  | // For example: | ||||||
|  | //	(*root.MyMap["key"].(*mypkg.MyStruct).MySlices)[2][3].MyField | ||||||
|  | func (pa Path) GoString() string { | ||||||
|  | 	var ssPre, ssPost []string | ||||||
|  | 	var numIndirect int | ||||||
|  | 	for i, s := range pa { | ||||||
|  | 		var nextStep PathStep | ||||||
|  | 		if i+1 < len(pa) { | ||||||
|  | 			nextStep = pa[i+1] | ||||||
|  | 		} | ||||||
|  | 		switch s := s.(type) { | ||||||
|  | 		case Indirect: | ||||||
|  | 			numIndirect++ | ||||||
|  | 			pPre, pPost := "(", ")" | ||||||
|  | 			switch nextStep.(type) { | ||||||
|  | 			case Indirect: | ||||||
|  | 				continue // Next step is indirection, so let them batch up | ||||||
|  | 			case StructField: | ||||||
|  | 				numIndirect-- // Automatic indirection on struct fields | ||||||
|  | 			case nil: | ||||||
|  | 				pPre, pPost = "", "" // Last step; no need for parenthesis | ||||||
|  | 			} | ||||||
|  | 			if numIndirect > 0 { | ||||||
|  | 				ssPre = append(ssPre, pPre+strings.Repeat("*", numIndirect)) | ||||||
|  | 				ssPost = append(ssPost, pPost) | ||||||
|  | 			} | ||||||
|  | 			numIndirect = 0 | ||||||
|  | 			continue | ||||||
|  | 		case Transform: | ||||||
|  | 			ssPre = append(ssPre, s.trans.name+"(") | ||||||
|  | 			ssPost = append(ssPost, ")") | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		ssPost = append(ssPost, s.String()) | ||||||
|  | 	} | ||||||
|  | 	for i, j := 0, len(ssPre)-1; i < j; i, j = i+1, j-1 { | ||||||
|  | 		ssPre[i], ssPre[j] = ssPre[j], ssPre[i] | ||||||
|  | 	} | ||||||
|  | 	return strings.Join(ssPre, "") + strings.Join(ssPost, "") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type pathStep struct { | ||||||
|  | 	typ    reflect.Type | ||||||
|  | 	vx, vy reflect.Value | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (ps pathStep) Type() reflect.Type             { return ps.typ } | ||||||
|  | func (ps pathStep) Values() (vx, vy reflect.Value) { return ps.vx, ps.vy } | ||||||
|  | func (ps pathStep) String() string { | ||||||
|  | 	if ps.typ == nil { | ||||||
|  | 		return "<nil>" | ||||||
|  | 	} | ||||||
|  | 	s := ps.typ.String() | ||||||
|  | 	if s == "" || strings.ContainsAny(s, "{}\n") { | ||||||
|  | 		return "root" // Type too simple or complex to print | ||||||
|  | 	} | ||||||
|  | 	return fmt.Sprintf("{%s}", s) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // StructField represents a struct field access on a field called Name. | ||||||
|  | type StructField struct{ *structField } | ||||||
|  | type structField struct { | ||||||
|  | 	pathStep | ||||||
|  | 	name string | ||||||
|  | 	idx  int | ||||||
|  | 
 | ||||||
|  | 	// These fields are used for forcibly accessing an unexported field. | ||||||
|  | 	// pvx, pvy, and field are only valid if unexported is true. | ||||||
|  | 	unexported bool | ||||||
|  | 	mayForce   bool                // Forcibly allow visibility | ||||||
|  | 	pvx, pvy   reflect.Value       // Parent values | ||||||
|  | 	field      reflect.StructField // Field information | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (sf StructField) Type() reflect.Type { return sf.typ } | ||||||
|  | func (sf StructField) Values() (vx, vy reflect.Value) { | ||||||
|  | 	if !sf.unexported { | ||||||
|  | 		return sf.vx, sf.vy // CanInterface reports true | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Forcibly obtain read-write access to an unexported struct field. | ||||||
|  | 	if sf.mayForce { | ||||||
|  | 		vx = retrieveUnexportedField(sf.pvx, sf.field) | ||||||
|  | 		vy = retrieveUnexportedField(sf.pvy, sf.field) | ||||||
|  | 		return vx, vy // CanInterface reports true | ||||||
|  | 	} | ||||||
|  | 	return sf.vx, sf.vy // CanInterface reports false | ||||||
|  | } | ||||||
|  | func (sf StructField) String() string { return fmt.Sprintf(".%s", sf.name) } | ||||||
|  | 
 | ||||||
|  | // Name is the field name. | ||||||
|  | func (sf StructField) Name() string { return sf.name } | ||||||
|  | 
 | ||||||
|  | // Index is the index of the field in the parent struct type. | ||||||
|  | // See reflect.Type.Field. | ||||||
|  | func (sf StructField) Index() int { return sf.idx } | ||||||
|  | 
 | ||||||
|  | // SliceIndex is an index operation on a slice or array at some index Key. | ||||||
|  | type SliceIndex struct{ *sliceIndex } | ||||||
|  | type sliceIndex struct { | ||||||
|  | 	pathStep | ||||||
|  | 	xkey, ykey int | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (si SliceIndex) Type() reflect.Type             { return si.typ } | ||||||
|  | func (si SliceIndex) Values() (vx, vy reflect.Value) { return si.vx, si.vy } | ||||||
|  | func (si SliceIndex) String() string { | ||||||
|  | 	switch { | ||||||
|  | 	case si.xkey == si.ykey: | ||||||
|  | 		return fmt.Sprintf("[%d]", si.xkey) | ||||||
|  | 	case si.ykey == -1: | ||||||
|  | 		// [5->?] means "I don't know where X[5] went" | ||||||
|  | 		return fmt.Sprintf("[%d->?]", si.xkey) | ||||||
|  | 	case si.xkey == -1: | ||||||
|  | 		// [?->3] means "I don't know where Y[3] came from" | ||||||
|  | 		return fmt.Sprintf("[?->%d]", si.ykey) | ||||||
|  | 	default: | ||||||
|  | 		// [5->3] means "X[5] moved to Y[3]" | ||||||
|  | 		return fmt.Sprintf("[%d->%d]", si.xkey, si.ykey) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Key is the index key; it may return -1 if in a split state | ||||||
|  | func (si SliceIndex) Key() int { | ||||||
|  | 	if si.xkey != si.ykey { | ||||||
|  | 		return -1 | ||||||
|  | 	} | ||||||
|  | 	return si.xkey | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // SplitKeys are the indexes for indexing into slices in the | ||||||
|  | // x and y values, respectively. These indexes may differ due to the | ||||||
|  | // insertion or removal of an element in one of the slices, causing | ||||||
|  | // all of the indexes to be shifted. If an index is -1, then that | ||||||
|  | // indicates that the element does not exist in the associated slice. | ||||||
|  | // | ||||||
|  | // Key is guaranteed to return -1 if and only if the indexes returned | ||||||
|  | // by SplitKeys are not the same. SplitKeys will never return -1 for | ||||||
|  | // both indexes. | ||||||
|  | func (si SliceIndex) SplitKeys() (ix, iy int) { return si.xkey, si.ykey } | ||||||
|  | 
 | ||||||
|  | // MapIndex is an index operation on a map at some index Key. | ||||||
|  | type MapIndex struct{ *mapIndex } | ||||||
|  | type mapIndex struct { | ||||||
|  | 	pathStep | ||||||
|  | 	key reflect.Value | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (mi MapIndex) Type() reflect.Type             { return mi.typ } | ||||||
|  | func (mi MapIndex) Values() (vx, vy reflect.Value) { return mi.vx, mi.vy } | ||||||
|  | func (mi MapIndex) String() string                 { return fmt.Sprintf("[%#v]", mi.key) } | ||||||
|  | 
 | ||||||
|  | // Key is the value of the map key. | ||||||
|  | func (mi MapIndex) Key() reflect.Value { return mi.key } | ||||||
|  | 
 | ||||||
|  | // Indirect represents pointer indirection on the parent type. | ||||||
|  | type Indirect struct{ *indirect } | ||||||
|  | type indirect struct { | ||||||
|  | 	pathStep | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (in Indirect) Type() reflect.Type             { return in.typ } | ||||||
|  | func (in Indirect) Values() (vx, vy reflect.Value) { return in.vx, in.vy } | ||||||
|  | func (in Indirect) String() string                 { return "*" } | ||||||
|  | 
 | ||||||
|  | // TypeAssertion represents a type assertion on an interface. | ||||||
|  | type TypeAssertion struct{ *typeAssertion } | ||||||
|  | type typeAssertion struct { | ||||||
|  | 	pathStep | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (ta TypeAssertion) Type() reflect.Type             { return ta.typ } | ||||||
|  | func (ta TypeAssertion) Values() (vx, vy reflect.Value) { return ta.vx, ta.vy } | ||||||
|  | func (ta TypeAssertion) String() string                 { return fmt.Sprintf(".(%v)", ta.typ) } | ||||||
|  | 
 | ||||||
|  | // Transform is a transformation from the parent type to the current type. | ||||||
|  | type Transform struct{ *transform } | ||||||
|  | type transform struct { | ||||||
|  | 	pathStep | ||||||
|  | 	trans *transformer | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (tf Transform) Type() reflect.Type             { return tf.typ } | ||||||
|  | func (tf Transform) Values() (vx, vy reflect.Value) { return tf.vx, tf.vy } | ||||||
|  | func (tf Transform) String() string                 { return fmt.Sprintf("%s()", tf.trans.name) } | ||||||
|  | 
 | ||||||
|  | // Name is the name of the Transformer. | ||||||
|  | func (tf Transform) Name() string { return tf.trans.name } | ||||||
|  | 
 | ||||||
|  | // Func is the function pointer to the transformer function. | ||||||
|  | func (tf Transform) Func() reflect.Value { return tf.trans.fnc } | ||||||
|  | 
 | ||||||
|  | // Option returns the originally constructed Transformer option. | ||||||
|  | // The == operator can be used to detect the exact option used. | ||||||
|  | func (tf Transform) Option() Option { return tf.trans } | ||||||
|  | 
 | ||||||
|  | // isExported reports whether the identifier is exported. | ||||||
|  | func isExported(id string) bool { | ||||||
|  | 	r, _ := utf8.DecodeRuneInString(id) | ||||||
|  | 	return unicode.IsUpper(r) | ||||||
|  | } | ||||||
							
								
								
									
										296
									
								
								vendor/github.com/google/go-cmp/cmp/report_compare.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										296
									
								
								vendor/github.com/google/go-cmp/cmp/report_compare.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,296 @@ | |||||||
|  | // Copyright 2019, The Go Authors. All rights reserved. | ||||||
|  | // Use of this source code is governed by a BSD-style | ||||||
|  | // license that can be found in the LICENSE.md file. | ||||||
|  | 
 | ||||||
|  | package cmp | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"reflect" | ||||||
|  | 
 | ||||||
|  | 	"github.com/google/go-cmp/cmp/internal/value" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // TODO: Enforce limits? | ||||||
|  | //	* Enforce maximum number of records to print per node? | ||||||
|  | //	* Enforce maximum size in bytes allowed? | ||||||
|  | //	* As a heuristic, use less verbosity for equal nodes than unequal nodes. | ||||||
|  | // TODO: Enforce unique outputs? | ||||||
|  | //	* Avoid Stringer methods if it results in same output? | ||||||
|  | //	* Print pointer address if outputs still equal? | ||||||
|  | 
 | ||||||
|  | // numContextRecords is the number of surrounding equal records to print. | ||||||
|  | const numContextRecords = 2 | ||||||
|  | 
 | ||||||
|  | type diffMode byte | ||||||
|  | 
 | ||||||
|  | const ( | ||||||
|  | 	diffUnknown   diffMode = 0 | ||||||
|  | 	diffIdentical diffMode = ' ' | ||||||
|  | 	diffRemoved   diffMode = '-' | ||||||
|  | 	diffInserted  diffMode = '+' | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | type typeMode int | ||||||
|  | 
 | ||||||
|  | const ( | ||||||
|  | 	// emitType always prints the type. | ||||||
|  | 	emitType typeMode = iota | ||||||
|  | 	// elideType never prints the type. | ||||||
|  | 	elideType | ||||||
|  | 	// autoType prints the type only for composite kinds | ||||||
|  | 	// (i.e., structs, slices, arrays, and maps). | ||||||
|  | 	autoType | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | type formatOptions struct { | ||||||
|  | 	// DiffMode controls the output mode of FormatDiff. | ||||||
|  | 	// | ||||||
|  | 	// If diffUnknown,   then produce a diff of the x and y values. | ||||||
|  | 	// If diffIdentical, then emit values as if they were equal. | ||||||
|  | 	// If diffRemoved,   then only emit x values (ignoring y values). | ||||||
|  | 	// If diffInserted,  then only emit y values (ignoring x values). | ||||||
|  | 	DiffMode diffMode | ||||||
|  | 
 | ||||||
|  | 	// TypeMode controls whether to print the type for the current node. | ||||||
|  | 	// | ||||||
|  | 	// As a general rule of thumb, we always print the type of the next node | ||||||
|  | 	// after an interface, and always elide the type of the next node after | ||||||
|  | 	// a slice or map node. | ||||||
|  | 	TypeMode typeMode | ||||||
|  | 
 | ||||||
|  | 	// formatValueOptions are options specific to printing reflect.Values. | ||||||
|  | 	formatValueOptions | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (opts formatOptions) WithDiffMode(d diffMode) formatOptions { | ||||||
|  | 	opts.DiffMode = d | ||||||
|  | 	return opts | ||||||
|  | } | ||||||
|  | func (opts formatOptions) WithTypeMode(t typeMode) formatOptions { | ||||||
|  | 	opts.TypeMode = t | ||||||
|  | 	return opts | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // FormatDiff converts a valueNode tree into a textNode tree, where the later | ||||||
|  | // is a textual representation of the differences detected in the former. | ||||||
|  | func (opts formatOptions) FormatDiff(v *valueNode) textNode { | ||||||
|  | 	// Check whether we have specialized formatting for this node. | ||||||
|  | 	// This is not necessary, but helpful for producing more readable outputs. | ||||||
|  | 	if opts.CanFormatDiffSlice(v) { | ||||||
|  | 		return opts.FormatDiffSlice(v) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// For leaf nodes, format the value based on the reflect.Values alone. | ||||||
|  | 	if v.MaxDepth == 0 { | ||||||
|  | 		switch opts.DiffMode { | ||||||
|  | 		case diffUnknown, diffIdentical: | ||||||
|  | 			// Format Equal. | ||||||
|  | 			if v.NumDiff == 0 { | ||||||
|  | 				outx := opts.FormatValue(v.ValueX, visitedPointers{}) | ||||||
|  | 				outy := opts.FormatValue(v.ValueY, visitedPointers{}) | ||||||
|  | 				if v.NumIgnored > 0 && v.NumSame == 0 { | ||||||
|  | 					return textEllipsis | ||||||
|  | 				} else if outx.Len() < outy.Len() { | ||||||
|  | 					return outx | ||||||
|  | 				} else { | ||||||
|  | 					return outy | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			// Format unequal. | ||||||
|  | 			assert(opts.DiffMode == diffUnknown) | ||||||
|  | 			var list textList | ||||||
|  | 			outx := opts.WithTypeMode(elideType).FormatValue(v.ValueX, visitedPointers{}) | ||||||
|  | 			outy := opts.WithTypeMode(elideType).FormatValue(v.ValueY, visitedPointers{}) | ||||||
|  | 			if outx != nil { | ||||||
|  | 				list = append(list, textRecord{Diff: '-', Value: outx}) | ||||||
|  | 			} | ||||||
|  | 			if outy != nil { | ||||||
|  | 				list = append(list, textRecord{Diff: '+', Value: outy}) | ||||||
|  | 			} | ||||||
|  | 			return opts.WithTypeMode(emitType).FormatType(v.Type, list) | ||||||
|  | 		case diffRemoved: | ||||||
|  | 			return opts.FormatValue(v.ValueX, visitedPointers{}) | ||||||
|  | 		case diffInserted: | ||||||
|  | 			return opts.FormatValue(v.ValueY, visitedPointers{}) | ||||||
|  | 		default: | ||||||
|  | 			panic("invalid diff mode") | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Descend into the child value node. | ||||||
|  | 	if v.TransformerName != "" { | ||||||
|  | 		out := opts.WithTypeMode(emitType).FormatDiff(v.Value) | ||||||
|  | 		out = textWrap{"Inverse(" + v.TransformerName + ", ", out, ")"} | ||||||
|  | 		return opts.FormatType(v.Type, out) | ||||||
|  | 	} else { | ||||||
|  | 		switch k := v.Type.Kind(); k { | ||||||
|  | 		case reflect.Struct, reflect.Array, reflect.Slice, reflect.Map: | ||||||
|  | 			return opts.FormatType(v.Type, opts.formatDiffList(v.Records, k)) | ||||||
|  | 		case reflect.Ptr: | ||||||
|  | 			return textWrap{"&", opts.FormatDiff(v.Value), ""} | ||||||
|  | 		case reflect.Interface: | ||||||
|  | 			return opts.WithTypeMode(emitType).FormatDiff(v.Value) | ||||||
|  | 		default: | ||||||
|  | 			panic(fmt.Sprintf("%v cannot have children", k)) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (opts formatOptions) formatDiffList(recs []reportRecord, k reflect.Kind) textNode { | ||||||
|  | 	// Derive record name based on the data structure kind. | ||||||
|  | 	var name string | ||||||
|  | 	var formatKey func(reflect.Value) string | ||||||
|  | 	switch k { | ||||||
|  | 	case reflect.Struct: | ||||||
|  | 		name = "field" | ||||||
|  | 		opts = opts.WithTypeMode(autoType) | ||||||
|  | 		formatKey = func(v reflect.Value) string { return v.String() } | ||||||
|  | 	case reflect.Slice, reflect.Array: | ||||||
|  | 		name = "element" | ||||||
|  | 		opts = opts.WithTypeMode(elideType) | ||||||
|  | 		formatKey = func(reflect.Value) string { return "" } | ||||||
|  | 	case reflect.Map: | ||||||
|  | 		name = "entry" | ||||||
|  | 		opts = opts.WithTypeMode(elideType) | ||||||
|  | 		formatKey = formatMapKey | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Handle unification. | ||||||
|  | 	switch opts.DiffMode { | ||||||
|  | 	case diffIdentical, diffRemoved, diffInserted: | ||||||
|  | 		var list textList | ||||||
|  | 		var deferredEllipsis bool // Add final "..." to indicate records were dropped | ||||||
|  | 		for _, r := range recs { | ||||||
|  | 			// Elide struct fields that are zero value. | ||||||
|  | 			if k == reflect.Struct { | ||||||
|  | 				var isZero bool | ||||||
|  | 				switch opts.DiffMode { | ||||||
|  | 				case diffIdentical: | ||||||
|  | 					isZero = value.IsZero(r.Value.ValueX) || value.IsZero(r.Value.ValueX) | ||||||
|  | 				case diffRemoved: | ||||||
|  | 					isZero = value.IsZero(r.Value.ValueX) | ||||||
|  | 				case diffInserted: | ||||||
|  | 					isZero = value.IsZero(r.Value.ValueY) | ||||||
|  | 				} | ||||||
|  | 				if isZero { | ||||||
|  | 					continue | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			// Elide ignored nodes. | ||||||
|  | 			if r.Value.NumIgnored > 0 && r.Value.NumSame+r.Value.NumDiff == 0 { | ||||||
|  | 				deferredEllipsis = !(k == reflect.Slice || k == reflect.Array) | ||||||
|  | 				if !deferredEllipsis { | ||||||
|  | 					list.AppendEllipsis(diffStats{}) | ||||||
|  | 				} | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  | 			if out := opts.FormatDiff(r.Value); out != nil { | ||||||
|  | 				list = append(list, textRecord{Key: formatKey(r.Key), Value: out}) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		if deferredEllipsis { | ||||||
|  | 			list.AppendEllipsis(diffStats{}) | ||||||
|  | 		} | ||||||
|  | 		return textWrap{"{", list, "}"} | ||||||
|  | 	case diffUnknown: | ||||||
|  | 	default: | ||||||
|  | 		panic("invalid diff mode") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Handle differencing. | ||||||
|  | 	var list textList | ||||||
|  | 	groups := coalesceAdjacentRecords(name, recs) | ||||||
|  | 	for i, ds := range groups { | ||||||
|  | 		// Handle equal records. | ||||||
|  | 		if ds.NumDiff() == 0 { | ||||||
|  | 			// Compute the number of leading and trailing records to print. | ||||||
|  | 			var numLo, numHi int | ||||||
|  | 			numEqual := ds.NumIgnored + ds.NumIdentical | ||||||
|  | 			for numLo < numContextRecords && numLo+numHi < numEqual && i != 0 { | ||||||
|  | 				if r := recs[numLo].Value; r.NumIgnored > 0 && r.NumSame+r.NumDiff == 0 { | ||||||
|  | 					break | ||||||
|  | 				} | ||||||
|  | 				numLo++ | ||||||
|  | 			} | ||||||
|  | 			for numHi < numContextRecords && numLo+numHi < numEqual && i != len(groups)-1 { | ||||||
|  | 				if r := recs[numEqual-numHi-1].Value; r.NumIgnored > 0 && r.NumSame+r.NumDiff == 0 { | ||||||
|  | 					break | ||||||
|  | 				} | ||||||
|  | 				numHi++ | ||||||
|  | 			} | ||||||
|  | 			if numEqual-(numLo+numHi) == 1 && ds.NumIgnored == 0 { | ||||||
|  | 				numHi++ // Avoid pointless coalescing of a single equal record | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			// Format the equal values. | ||||||
|  | 			for _, r := range recs[:numLo] { | ||||||
|  | 				out := opts.WithDiffMode(diffIdentical).FormatDiff(r.Value) | ||||||
|  | 				list = append(list, textRecord{Key: formatKey(r.Key), Value: out}) | ||||||
|  | 			} | ||||||
|  | 			if numEqual > numLo+numHi { | ||||||
|  | 				ds.NumIdentical -= numLo + numHi | ||||||
|  | 				list.AppendEllipsis(ds) | ||||||
|  | 			} | ||||||
|  | 			for _, r := range recs[numEqual-numHi : numEqual] { | ||||||
|  | 				out := opts.WithDiffMode(diffIdentical).FormatDiff(r.Value) | ||||||
|  | 				list = append(list, textRecord{Key: formatKey(r.Key), Value: out}) | ||||||
|  | 			} | ||||||
|  | 			recs = recs[numEqual:] | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		// Handle unequal records. | ||||||
|  | 		for _, r := range recs[:ds.NumDiff()] { | ||||||
|  | 			switch { | ||||||
|  | 			case opts.CanFormatDiffSlice(r.Value): | ||||||
|  | 				out := opts.FormatDiffSlice(r.Value) | ||||||
|  | 				list = append(list, textRecord{Key: formatKey(r.Key), Value: out}) | ||||||
|  | 			case r.Value.NumChildren == r.Value.MaxDepth: | ||||||
|  | 				outx := opts.WithDiffMode(diffRemoved).FormatDiff(r.Value) | ||||||
|  | 				outy := opts.WithDiffMode(diffInserted).FormatDiff(r.Value) | ||||||
|  | 				if outx != nil { | ||||||
|  | 					list = append(list, textRecord{Diff: diffRemoved, Key: formatKey(r.Key), Value: outx}) | ||||||
|  | 				} | ||||||
|  | 				if outy != nil { | ||||||
|  | 					list = append(list, textRecord{Diff: diffInserted, Key: formatKey(r.Key), Value: outy}) | ||||||
|  | 				} | ||||||
|  | 			default: | ||||||
|  | 				out := opts.FormatDiff(r.Value) | ||||||
|  | 				list = append(list, textRecord{Key: formatKey(r.Key), Value: out}) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		recs = recs[ds.NumDiff():] | ||||||
|  | 	} | ||||||
|  | 	assert(len(recs) == 0) | ||||||
|  | 	return textWrap{"{", list, "}"} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // coalesceAdjacentRecords coalesces the list of records into groups of | ||||||
|  | // adjacent equal, or unequal counts. | ||||||
|  | func coalesceAdjacentRecords(name string, recs []reportRecord) (groups []diffStats) { | ||||||
|  | 	var prevCase int // Arbitrary index into which case last occurred | ||||||
|  | 	lastStats := func(i int) *diffStats { | ||||||
|  | 		if prevCase != i { | ||||||
|  | 			groups = append(groups, diffStats{Name: name}) | ||||||
|  | 			prevCase = i | ||||||
|  | 		} | ||||||
|  | 		return &groups[len(groups)-1] | ||||||
|  | 	} | ||||||
|  | 	for _, r := range recs { | ||||||
|  | 		switch rv := r.Value; { | ||||||
|  | 		case rv.NumIgnored > 0 && rv.NumSame+rv.NumDiff == 0: | ||||||
|  | 			lastStats(1).NumIgnored++ | ||||||
|  | 		case rv.NumDiff == 0: | ||||||
|  | 			lastStats(1).NumIdentical++ | ||||||
|  | 		case rv.NumDiff > 0 && !rv.ValueY.IsValid(): | ||||||
|  | 			lastStats(2).NumRemoved++ | ||||||
|  | 		case rv.NumDiff > 0 && !rv.ValueX.IsValid(): | ||||||
|  | 			lastStats(2).NumInserted++ | ||||||
|  | 		default: | ||||||
|  | 			lastStats(2).NumModified++ | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return groups | ||||||
|  | } | ||||||
							
								
								
									
										279
									
								
								vendor/github.com/google/go-cmp/cmp/report_reflect.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										279
									
								
								vendor/github.com/google/go-cmp/cmp/report_reflect.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,279 @@ | |||||||
|  | // Copyright 2019, The Go Authors. All rights reserved. | ||||||
|  | // Use of this source code is governed by a BSD-style | ||||||
|  | // license that can be found in the LICENSE.md file. | ||||||
|  | 
 | ||||||
|  | package cmp | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"reflect" | ||||||
|  | 	"strconv" | ||||||
|  | 	"strings" | ||||||
|  | 	"unicode" | ||||||
|  | 
 | ||||||
|  | 	"github.com/google/go-cmp/cmp/internal/flags" | ||||||
|  | 	"github.com/google/go-cmp/cmp/internal/value" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | type formatValueOptions struct { | ||||||
|  | 	// AvoidStringer controls whether to avoid calling custom stringer | ||||||
|  | 	// methods like error.Error or fmt.Stringer.String. | ||||||
|  | 	AvoidStringer bool | ||||||
|  | 
 | ||||||
|  | 	// ShallowPointers controls whether to avoid descending into pointers. | ||||||
|  | 	// Useful when printing map keys, where pointer comparison is performed | ||||||
|  | 	// on the pointer address rather than the pointed-at value. | ||||||
|  | 	ShallowPointers bool | ||||||
|  | 
 | ||||||
|  | 	// PrintAddresses controls whether to print the address of all pointers, | ||||||
|  | 	// slice elements, and maps. | ||||||
|  | 	PrintAddresses bool | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // FormatType prints the type as if it were wrapping s. | ||||||
|  | // This may return s as-is depending on the current type and TypeMode mode. | ||||||
|  | func (opts formatOptions) FormatType(t reflect.Type, s textNode) textNode { | ||||||
|  | 	// Check whether to emit the type or not. | ||||||
|  | 	switch opts.TypeMode { | ||||||
|  | 	case autoType: | ||||||
|  | 		switch t.Kind() { | ||||||
|  | 		case reflect.Struct, reflect.Slice, reflect.Array, reflect.Map: | ||||||
|  | 			if s.Equal(textNil) { | ||||||
|  | 				return s | ||||||
|  | 			} | ||||||
|  | 		default: | ||||||
|  | 			return s | ||||||
|  | 		} | ||||||
|  | 	case elideType: | ||||||
|  | 		return s | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Determine the type label, applying special handling for unnamed types. | ||||||
|  | 	typeName := t.String() | ||||||
|  | 	if t.Name() == "" { | ||||||
|  | 		// According to Go grammar, certain type literals contain symbols that | ||||||
|  | 		// do not strongly bind to the next lexicographical token (e.g., *T). | ||||||
|  | 		switch t.Kind() { | ||||||
|  | 		case reflect.Chan, reflect.Func, reflect.Ptr: | ||||||
|  | 			typeName = "(" + typeName + ")" | ||||||
|  | 		} | ||||||
|  | 		typeName = strings.Replace(typeName, "struct {", "struct{", -1) | ||||||
|  | 		typeName = strings.Replace(typeName, "interface {", "interface{", -1) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Avoid wrap the value in parenthesis if unnecessary. | ||||||
|  | 	if s, ok := s.(textWrap); ok { | ||||||
|  | 		hasParens := strings.HasPrefix(s.Prefix, "(") && strings.HasSuffix(s.Suffix, ")") | ||||||
|  | 		hasBraces := strings.HasPrefix(s.Prefix, "{") && strings.HasSuffix(s.Suffix, "}") | ||||||
|  | 		if hasParens || hasBraces { | ||||||
|  | 			return textWrap{typeName, s, ""} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return textWrap{typeName + "(", s, ")"} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // FormatValue prints the reflect.Value, taking extra care to avoid descending | ||||||
|  | // into pointers already in m. As pointers are visited, m is also updated. | ||||||
|  | func (opts formatOptions) FormatValue(v reflect.Value, m visitedPointers) (out textNode) { | ||||||
|  | 	if !v.IsValid() { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 	t := v.Type() | ||||||
|  | 
 | ||||||
|  | 	// Check whether there is an Error or String method to call. | ||||||
|  | 	if !opts.AvoidStringer && v.CanInterface() { | ||||||
|  | 		// Avoid calling Error or String methods on nil receivers since many | ||||||
|  | 		// implementations crash when doing so. | ||||||
|  | 		if (t.Kind() != reflect.Ptr && t.Kind() != reflect.Interface) || !v.IsNil() { | ||||||
|  | 			switch v := v.Interface().(type) { | ||||||
|  | 			case error: | ||||||
|  | 				return textLine("e" + formatString(v.Error())) | ||||||
|  | 			case fmt.Stringer: | ||||||
|  | 				return textLine("s" + formatString(v.String())) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Check whether to explicitly wrap the result with the type. | ||||||
|  | 	var skipType bool | ||||||
|  | 	defer func() { | ||||||
|  | 		if !skipType { | ||||||
|  | 			out = opts.FormatType(t, out) | ||||||
|  | 		} | ||||||
|  | 	}() | ||||||
|  | 
 | ||||||
|  | 	var ptr string | ||||||
|  | 	switch t.Kind() { | ||||||
|  | 	case reflect.Bool: | ||||||
|  | 		return textLine(fmt.Sprint(v.Bool())) | ||||||
|  | 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | ||||||
|  | 		return textLine(fmt.Sprint(v.Int())) | ||||||
|  | 	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: | ||||||
|  | 		// Unnamed uints are usually bytes or words, so use hexadecimal. | ||||||
|  | 		if t.PkgPath() == "" || t.Kind() == reflect.Uintptr { | ||||||
|  | 			return textLine(formatHex(v.Uint())) | ||||||
|  | 		} | ||||||
|  | 		return textLine(fmt.Sprint(v.Uint())) | ||||||
|  | 	case reflect.Float32, reflect.Float64: | ||||||
|  | 		return textLine(fmt.Sprint(v.Float())) | ||||||
|  | 	case reflect.Complex64, reflect.Complex128: | ||||||
|  | 		return textLine(fmt.Sprint(v.Complex())) | ||||||
|  | 	case reflect.String: | ||||||
|  | 		return textLine(formatString(v.String())) | ||||||
|  | 	case reflect.UnsafePointer, reflect.Chan, reflect.Func: | ||||||
|  | 		return textLine(formatPointer(v)) | ||||||
|  | 	case reflect.Struct: | ||||||
|  | 		var list textList | ||||||
|  | 		for i := 0; i < v.NumField(); i++ { | ||||||
|  | 			vv := v.Field(i) | ||||||
|  | 			if value.IsZero(vv) { | ||||||
|  | 				continue // Elide fields with zero values | ||||||
|  | 			} | ||||||
|  | 			s := opts.WithTypeMode(autoType).FormatValue(vv, m) | ||||||
|  | 			list = append(list, textRecord{Key: t.Field(i).Name, Value: s}) | ||||||
|  | 		} | ||||||
|  | 		return textWrap{"{", list, "}"} | ||||||
|  | 	case reflect.Slice: | ||||||
|  | 		if v.IsNil() { | ||||||
|  | 			return textNil | ||||||
|  | 		} | ||||||
|  | 		if opts.PrintAddresses { | ||||||
|  | 			ptr = formatPointer(v) | ||||||
|  | 		} | ||||||
|  | 		fallthrough | ||||||
|  | 	case reflect.Array: | ||||||
|  | 		var list textList | ||||||
|  | 		for i := 0; i < v.Len(); i++ { | ||||||
|  | 			vi := v.Index(i) | ||||||
|  | 			if vi.CanAddr() { // Check for cyclic elements | ||||||
|  | 				p := vi.Addr() | ||||||
|  | 				if m.Visit(p) { | ||||||
|  | 					var out textNode | ||||||
|  | 					out = textLine(formatPointer(p)) | ||||||
|  | 					out = opts.WithTypeMode(emitType).FormatType(p.Type(), out) | ||||||
|  | 					out = textWrap{"*", out, ""} | ||||||
|  | 					list = append(list, textRecord{Value: out}) | ||||||
|  | 					continue | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			s := opts.WithTypeMode(elideType).FormatValue(vi, m) | ||||||
|  | 			list = append(list, textRecord{Value: s}) | ||||||
|  | 		} | ||||||
|  | 		return textWrap{ptr + "{", list, "}"} | ||||||
|  | 	case reflect.Map: | ||||||
|  | 		if v.IsNil() { | ||||||
|  | 			return textNil | ||||||
|  | 		} | ||||||
|  | 		if m.Visit(v) { | ||||||
|  | 			return textLine(formatPointer(v)) | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		var list textList | ||||||
|  | 		for _, k := range value.SortKeys(v.MapKeys()) { | ||||||
|  | 			sk := formatMapKey(k) | ||||||
|  | 			sv := opts.WithTypeMode(elideType).FormatValue(v.MapIndex(k), m) | ||||||
|  | 			list = append(list, textRecord{Key: sk, Value: sv}) | ||||||
|  | 		} | ||||||
|  | 		if opts.PrintAddresses { | ||||||
|  | 			ptr = formatPointer(v) | ||||||
|  | 		} | ||||||
|  | 		return textWrap{ptr + "{", list, "}"} | ||||||
|  | 	case reflect.Ptr: | ||||||
|  | 		if v.IsNil() { | ||||||
|  | 			return textNil | ||||||
|  | 		} | ||||||
|  | 		if m.Visit(v) || opts.ShallowPointers { | ||||||
|  | 			return textLine(formatPointer(v)) | ||||||
|  | 		} | ||||||
|  | 		if opts.PrintAddresses { | ||||||
|  | 			ptr = formatPointer(v) | ||||||
|  | 		} | ||||||
|  | 		skipType = true // Let the underlying value print the type instead | ||||||
|  | 		return textWrap{"&" + ptr, opts.FormatValue(v.Elem(), m), ""} | ||||||
|  | 	case reflect.Interface: | ||||||
|  | 		if v.IsNil() { | ||||||
|  | 			return textNil | ||||||
|  | 		} | ||||||
|  | 		// Interfaces accept different concrete types, | ||||||
|  | 		// so configure the underlying value to explicitly print the type. | ||||||
|  | 		skipType = true // Print the concrete type instead | ||||||
|  | 		return opts.WithTypeMode(emitType).FormatValue(v.Elem(), m) | ||||||
|  | 	default: | ||||||
|  | 		panic(fmt.Sprintf("%v kind not handled", v.Kind())) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // formatMapKey formats v as if it were a map key. | ||||||
|  | // The result is guaranteed to be a single line. | ||||||
|  | func formatMapKey(v reflect.Value) string { | ||||||
|  | 	var opts formatOptions | ||||||
|  | 	opts.TypeMode = elideType | ||||||
|  | 	opts.AvoidStringer = true | ||||||
|  | 	opts.ShallowPointers = true | ||||||
|  | 	s := opts.FormatValue(v, visitedPointers{}).String() | ||||||
|  | 	return strings.TrimSpace(s) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // formatString prints s as a double-quoted or backtick-quoted string. | ||||||
|  | func formatString(s string) string { | ||||||
|  | 	// Use quoted string if it the same length as a raw string literal. | ||||||
|  | 	// Otherwise, attempt to use the raw string form. | ||||||
|  | 	qs := strconv.Quote(s) | ||||||
|  | 	if len(qs) == 1+len(s)+1 { | ||||||
|  | 		return qs | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Disallow newlines to ensure output is a single line. | ||||||
|  | 	// Only allow printable runes for readability purposes. | ||||||
|  | 	rawInvalid := func(r rune) bool { | ||||||
|  | 		return r == '`' || r == '\n' || !(unicode.IsPrint(r) || r == '\t') | ||||||
|  | 	} | ||||||
|  | 	if strings.IndexFunc(s, rawInvalid) < 0 { | ||||||
|  | 		return "`" + s + "`" | ||||||
|  | 	} | ||||||
|  | 	return qs | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // formatHex prints u as a hexadecimal integer in Go notation. | ||||||
|  | func formatHex(u uint64) string { | ||||||
|  | 	var f string | ||||||
|  | 	switch { | ||||||
|  | 	case u <= 0xff: | ||||||
|  | 		f = "0x%02x" | ||||||
|  | 	case u <= 0xffff: | ||||||
|  | 		f = "0x%04x" | ||||||
|  | 	case u <= 0xffffff: | ||||||
|  | 		f = "0x%06x" | ||||||
|  | 	case u <= 0xffffffff: | ||||||
|  | 		f = "0x%08x" | ||||||
|  | 	case u <= 0xffffffffff: | ||||||
|  | 		f = "0x%010x" | ||||||
|  | 	case u <= 0xffffffffffff: | ||||||
|  | 		f = "0x%012x" | ||||||
|  | 	case u <= 0xffffffffffffff: | ||||||
|  | 		f = "0x%014x" | ||||||
|  | 	case u <= 0xffffffffffffffff: | ||||||
|  | 		f = "0x%016x" | ||||||
|  | 	} | ||||||
|  | 	return fmt.Sprintf(f, u) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // formatPointer prints the address of the pointer. | ||||||
|  | func formatPointer(v reflect.Value) string { | ||||||
|  | 	p := v.Pointer() | ||||||
|  | 	if flags.Deterministic { | ||||||
|  | 		p = 0xdeadf00f // Only used for stable testing purposes | ||||||
|  | 	} | ||||||
|  | 	return fmt.Sprintf("⟪0x%x⟫", p) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type visitedPointers map[value.Pointer]struct{} | ||||||
|  | 
 | ||||||
|  | // Visit inserts pointer v into the visited map and reports whether it had | ||||||
|  | // already been visited before. | ||||||
|  | func (m visitedPointers) Visit(v reflect.Value) bool { | ||||||
|  | 	p := value.PointerOf(v) | ||||||
|  | 	_, visited := m[p] | ||||||
|  | 	m[p] = struct{}{} | ||||||
|  | 	return visited | ||||||
|  | } | ||||||
							
								
								
									
										333
									
								
								vendor/github.com/google/go-cmp/cmp/report_slices.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										333
									
								
								vendor/github.com/google/go-cmp/cmp/report_slices.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,333 @@ | |||||||
|  | // Copyright 2019, The Go Authors. All rights reserved. | ||||||
|  | // Use of this source code is governed by a BSD-style | ||||||
|  | // license that can be found in the LICENSE.md file. | ||||||
|  | 
 | ||||||
|  | package cmp | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"bytes" | ||||||
|  | 	"fmt" | ||||||
|  | 	"reflect" | ||||||
|  | 	"strings" | ||||||
|  | 	"unicode" | ||||||
|  | 	"unicode/utf8" | ||||||
|  | 
 | ||||||
|  | 	"github.com/google/go-cmp/cmp/internal/diff" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // CanFormatDiffSlice reports whether we support custom formatting for nodes | ||||||
|  | // that are slices of primitive kinds or strings. | ||||||
|  | func (opts formatOptions) CanFormatDiffSlice(v *valueNode) bool { | ||||||
|  | 	switch { | ||||||
|  | 	case opts.DiffMode != diffUnknown: | ||||||
|  | 		return false // Must be formatting in diff mode | ||||||
|  | 	case v.NumDiff == 0: | ||||||
|  | 		return false // No differences detected | ||||||
|  | 	case v.NumIgnored+v.NumCompared+v.NumTransformed > 0: | ||||||
|  | 		// TODO: Handle the case where someone uses bytes.Equal on a large slice. | ||||||
|  | 		return false // Some custom option was used to determined equality | ||||||
|  | 	case !v.ValueX.IsValid() || !v.ValueY.IsValid(): | ||||||
|  | 		return false // Both values must be valid | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	switch t := v.Type; t.Kind() { | ||||||
|  | 	case reflect.String: | ||||||
|  | 	case reflect.Array, reflect.Slice: | ||||||
|  | 		// Only slices of primitive types have specialized handling. | ||||||
|  | 		switch t.Elem().Kind() { | ||||||
|  | 		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, | ||||||
|  | 			reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, | ||||||
|  | 			reflect.Bool, reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128: | ||||||
|  | 		default: | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		// If a sufficient number of elements already differ, | ||||||
|  | 		// use specialized formatting even if length requirement is not met. | ||||||
|  | 		if v.NumDiff > v.NumSame { | ||||||
|  | 			return true | ||||||
|  | 		} | ||||||
|  | 	default: | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Use specialized string diffing for longer slices or strings. | ||||||
|  | 	const minLength = 64 | ||||||
|  | 	return v.ValueX.Len() >= minLength && v.ValueY.Len() >= minLength | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // FormatDiffSlice prints a diff for the slices (or strings) represented by v. | ||||||
|  | // This provides custom-tailored logic to make printing of differences in | ||||||
|  | // textual strings and slices of primitive kinds more readable. | ||||||
|  | func (opts formatOptions) FormatDiffSlice(v *valueNode) textNode { | ||||||
|  | 	assert(opts.DiffMode == diffUnknown) | ||||||
|  | 	t, vx, vy := v.Type, v.ValueX, v.ValueY | ||||||
|  | 
 | ||||||
|  | 	// Auto-detect the type of the data. | ||||||
|  | 	var isLinedText, isText, isBinary bool | ||||||
|  | 	var sx, sy string | ||||||
|  | 	switch { | ||||||
|  | 	case t.Kind() == reflect.String: | ||||||
|  | 		sx, sy = vx.String(), vy.String() | ||||||
|  | 		isText = true // Initial estimate, verify later | ||||||
|  | 	case t.Kind() == reflect.Slice && t.Elem() == reflect.TypeOf(byte(0)): | ||||||
|  | 		sx, sy = string(vx.Bytes()), string(vy.Bytes()) | ||||||
|  | 		isBinary = true // Initial estimate, verify later | ||||||
|  | 	case t.Kind() == reflect.Array: | ||||||
|  | 		// Arrays need to be addressable for slice operations to work. | ||||||
|  | 		vx2, vy2 := reflect.New(t).Elem(), reflect.New(t).Elem() | ||||||
|  | 		vx2.Set(vx) | ||||||
|  | 		vy2.Set(vy) | ||||||
|  | 		vx, vy = vx2, vy2 | ||||||
|  | 	} | ||||||
|  | 	if isText || isBinary { | ||||||
|  | 		var numLines, lastLineIdx, maxLineLen int | ||||||
|  | 		isBinary = false | ||||||
|  | 		for i, r := range sx + sy { | ||||||
|  | 			if !(unicode.IsPrint(r) || unicode.IsSpace(r)) || r == utf8.RuneError { | ||||||
|  | 				isBinary = true | ||||||
|  | 				break | ||||||
|  | 			} | ||||||
|  | 			if r == '\n' { | ||||||
|  | 				if maxLineLen < i-lastLineIdx { | ||||||
|  | 					lastLineIdx = i - lastLineIdx | ||||||
|  | 				} | ||||||
|  | 				lastLineIdx = i + 1 | ||||||
|  | 				numLines++ | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		isText = !isBinary | ||||||
|  | 		isLinedText = isText && numLines >= 4 && maxLineLen <= 256 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Format the string into printable records. | ||||||
|  | 	var list textList | ||||||
|  | 	var delim string | ||||||
|  | 	switch { | ||||||
|  | 	// If the text appears to be multi-lined text, | ||||||
|  | 	// then perform differencing across individual lines. | ||||||
|  | 	case isLinedText: | ||||||
|  | 		ssx := strings.Split(sx, "\n") | ||||||
|  | 		ssy := strings.Split(sy, "\n") | ||||||
|  | 		list = opts.formatDiffSlice( | ||||||
|  | 			reflect.ValueOf(ssx), reflect.ValueOf(ssy), 1, "line", | ||||||
|  | 			func(v reflect.Value, d diffMode) textRecord { | ||||||
|  | 				s := formatString(v.Index(0).String()) | ||||||
|  | 				return textRecord{Diff: d, Value: textLine(s)} | ||||||
|  | 			}, | ||||||
|  | 		) | ||||||
|  | 		delim = "\n" | ||||||
|  | 	// If the text appears to be single-lined text, | ||||||
|  | 	// then perform differencing in approximately fixed-sized chunks. | ||||||
|  | 	// The output is printed as quoted strings. | ||||||
|  | 	case isText: | ||||||
|  | 		list = opts.formatDiffSlice( | ||||||
|  | 			reflect.ValueOf(sx), reflect.ValueOf(sy), 64, "byte", | ||||||
|  | 			func(v reflect.Value, d diffMode) textRecord { | ||||||
|  | 				s := formatString(v.String()) | ||||||
|  | 				return textRecord{Diff: d, Value: textLine(s)} | ||||||
|  | 			}, | ||||||
|  | 		) | ||||||
|  | 		delim = "" | ||||||
|  | 	// If the text appears to be binary data, | ||||||
|  | 	// then perform differencing in approximately fixed-sized chunks. | ||||||
|  | 	// The output is inspired by hexdump. | ||||||
|  | 	case isBinary: | ||||||
|  | 		list = opts.formatDiffSlice( | ||||||
|  | 			reflect.ValueOf(sx), reflect.ValueOf(sy), 16, "byte", | ||||||
|  | 			func(v reflect.Value, d diffMode) textRecord { | ||||||
|  | 				var ss []string | ||||||
|  | 				for i := 0; i < v.Len(); i++ { | ||||||
|  | 					ss = append(ss, formatHex(v.Index(i).Uint())) | ||||||
|  | 				} | ||||||
|  | 				s := strings.Join(ss, ", ") | ||||||
|  | 				comment := commentString(fmt.Sprintf("%c|%v|", d, formatASCII(v.String()))) | ||||||
|  | 				return textRecord{Diff: d, Value: textLine(s), Comment: comment} | ||||||
|  | 			}, | ||||||
|  | 		) | ||||||
|  | 	// For all other slices of primitive types, | ||||||
|  | 	// then perform differencing in approximately fixed-sized chunks. | ||||||
|  | 	// The size of each chunk depends on the width of the element kind. | ||||||
|  | 	default: | ||||||
|  | 		var chunkSize int | ||||||
|  | 		if t.Elem().Kind() == reflect.Bool { | ||||||
|  | 			chunkSize = 16 | ||||||
|  | 		} else { | ||||||
|  | 			switch t.Elem().Bits() { | ||||||
|  | 			case 8: | ||||||
|  | 				chunkSize = 16 | ||||||
|  | 			case 16: | ||||||
|  | 				chunkSize = 12 | ||||||
|  | 			case 32: | ||||||
|  | 				chunkSize = 8 | ||||||
|  | 			default: | ||||||
|  | 				chunkSize = 8 | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		list = opts.formatDiffSlice( | ||||||
|  | 			vx, vy, chunkSize, t.Elem().Kind().String(), | ||||||
|  | 			func(v reflect.Value, d diffMode) textRecord { | ||||||
|  | 				var ss []string | ||||||
|  | 				for i := 0; i < v.Len(); i++ { | ||||||
|  | 					switch t.Elem().Kind() { | ||||||
|  | 					case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | ||||||
|  | 						ss = append(ss, fmt.Sprint(v.Index(i).Int())) | ||||||
|  | 					case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: | ||||||
|  | 						ss = append(ss, formatHex(v.Index(i).Uint())) | ||||||
|  | 					case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128: | ||||||
|  | 						ss = append(ss, fmt.Sprint(v.Index(i).Interface())) | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 				s := strings.Join(ss, ", ") | ||||||
|  | 				return textRecord{Diff: d, Value: textLine(s)} | ||||||
|  | 			}, | ||||||
|  | 		) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Wrap the output with appropriate type information. | ||||||
|  | 	var out textNode = textWrap{"{", list, "}"} | ||||||
|  | 	if !isText { | ||||||
|  | 		// The "{...}" byte-sequence literal is not valid Go syntax for strings. | ||||||
|  | 		// Emit the type for extra clarity (e.g. "string{...}"). | ||||||
|  | 		if t.Kind() == reflect.String { | ||||||
|  | 			opts = opts.WithTypeMode(emitType) | ||||||
|  | 		} | ||||||
|  | 		return opts.FormatType(t, out) | ||||||
|  | 	} | ||||||
|  | 	switch t.Kind() { | ||||||
|  | 	case reflect.String: | ||||||
|  | 		out = textWrap{"strings.Join(", out, fmt.Sprintf(", %q)", delim)} | ||||||
|  | 		if t != reflect.TypeOf(string("")) { | ||||||
|  | 			out = opts.FormatType(t, out) | ||||||
|  | 		} | ||||||
|  | 	case reflect.Slice: | ||||||
|  | 		out = textWrap{"bytes.Join(", out, fmt.Sprintf(", %q)", delim)} | ||||||
|  | 		if t != reflect.TypeOf([]byte(nil)) { | ||||||
|  | 			out = opts.FormatType(t, out) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return out | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // formatASCII formats s as an ASCII string. | ||||||
|  | // This is useful for printing binary strings in a semi-legible way. | ||||||
|  | func formatASCII(s string) string { | ||||||
|  | 	b := bytes.Repeat([]byte{'.'}, len(s)) | ||||||
|  | 	for i := 0; i < len(s); i++ { | ||||||
|  | 		if ' ' <= s[i] && s[i] <= '~' { | ||||||
|  | 			b[i] = s[i] | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return string(b) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (opts formatOptions) formatDiffSlice( | ||||||
|  | 	vx, vy reflect.Value, chunkSize int, name string, | ||||||
|  | 	makeRec func(reflect.Value, diffMode) textRecord, | ||||||
|  | ) (list textList) { | ||||||
|  | 	es := diff.Difference(vx.Len(), vy.Len(), func(ix int, iy int) diff.Result { | ||||||
|  | 		return diff.BoolResult(vx.Index(ix).Interface() == vy.Index(iy).Interface()) | ||||||
|  | 	}) | ||||||
|  | 
 | ||||||
|  | 	appendChunks := func(v reflect.Value, d diffMode) int { | ||||||
|  | 		n0 := v.Len() | ||||||
|  | 		for v.Len() > 0 { | ||||||
|  | 			n := chunkSize | ||||||
|  | 			if n > v.Len() { | ||||||
|  | 				n = v.Len() | ||||||
|  | 			} | ||||||
|  | 			list = append(list, makeRec(v.Slice(0, n), d)) | ||||||
|  | 			v = v.Slice(n, v.Len()) | ||||||
|  | 		} | ||||||
|  | 		return n0 - v.Len() | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	groups := coalesceAdjacentEdits(name, es) | ||||||
|  | 	groups = coalesceInterveningIdentical(groups, chunkSize/4) | ||||||
|  | 	for i, ds := range groups { | ||||||
|  | 		// Print equal. | ||||||
|  | 		if ds.NumDiff() == 0 { | ||||||
|  | 			// Compute the number of leading and trailing equal bytes to print. | ||||||
|  | 			var numLo, numHi int | ||||||
|  | 			numEqual := ds.NumIgnored + ds.NumIdentical | ||||||
|  | 			for numLo < chunkSize*numContextRecords && numLo+numHi < numEqual && i != 0 { | ||||||
|  | 				numLo++ | ||||||
|  | 			} | ||||||
|  | 			for numHi < chunkSize*numContextRecords && numLo+numHi < numEqual && i != len(groups)-1 { | ||||||
|  | 				numHi++ | ||||||
|  | 			} | ||||||
|  | 			if numEqual-(numLo+numHi) <= chunkSize && ds.NumIgnored == 0 { | ||||||
|  | 				numHi = numEqual - numLo // Avoid pointless coalescing of single equal row | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			// Print the equal bytes. | ||||||
|  | 			appendChunks(vx.Slice(0, numLo), diffIdentical) | ||||||
|  | 			if numEqual > numLo+numHi { | ||||||
|  | 				ds.NumIdentical -= numLo + numHi | ||||||
|  | 				list.AppendEllipsis(ds) | ||||||
|  | 			} | ||||||
|  | 			appendChunks(vx.Slice(numEqual-numHi, numEqual), diffIdentical) | ||||||
|  | 			vx = vx.Slice(numEqual, vx.Len()) | ||||||
|  | 			vy = vy.Slice(numEqual, vy.Len()) | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		// Print unequal. | ||||||
|  | 		nx := appendChunks(vx.Slice(0, ds.NumIdentical+ds.NumRemoved+ds.NumModified), diffRemoved) | ||||||
|  | 		vx = vx.Slice(nx, vx.Len()) | ||||||
|  | 		ny := appendChunks(vy.Slice(0, ds.NumIdentical+ds.NumInserted+ds.NumModified), diffInserted) | ||||||
|  | 		vy = vy.Slice(ny, vy.Len()) | ||||||
|  | 	} | ||||||
|  | 	assert(vx.Len() == 0 && vy.Len() == 0) | ||||||
|  | 	return list | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // coalesceAdjacentEdits coalesces the list of edits into groups of adjacent | ||||||
|  | // equal or unequal counts. | ||||||
|  | func coalesceAdjacentEdits(name string, es diff.EditScript) (groups []diffStats) { | ||||||
|  | 	var prevCase int // Arbitrary index into which case last occurred | ||||||
|  | 	lastStats := func(i int) *diffStats { | ||||||
|  | 		if prevCase != i { | ||||||
|  | 			groups = append(groups, diffStats{Name: name}) | ||||||
|  | 			prevCase = i | ||||||
|  | 		} | ||||||
|  | 		return &groups[len(groups)-1] | ||||||
|  | 	} | ||||||
|  | 	for _, e := range es { | ||||||
|  | 		switch e { | ||||||
|  | 		case diff.Identity: | ||||||
|  | 			lastStats(1).NumIdentical++ | ||||||
|  | 		case diff.UniqueX: | ||||||
|  | 			lastStats(2).NumRemoved++ | ||||||
|  | 		case diff.UniqueY: | ||||||
|  | 			lastStats(2).NumInserted++ | ||||||
|  | 		case diff.Modified: | ||||||
|  | 			lastStats(2).NumModified++ | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return groups | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // coalesceInterveningIdentical coalesces sufficiently short (<= windowSize) | ||||||
|  | // equal groups into adjacent unequal groups that currently result in a | ||||||
|  | // dual inserted/removed printout. This acts as a high-pass filter to smooth | ||||||
|  | // out high-frequency changes within the windowSize. | ||||||
|  | func coalesceInterveningIdentical(groups []diffStats, windowSize int) []diffStats { | ||||||
|  | 	groups, groupsOrig := groups[:0], groups | ||||||
|  | 	for i, ds := range groupsOrig { | ||||||
|  | 		if len(groups) >= 2 && ds.NumDiff() > 0 { | ||||||
|  | 			prev := &groups[len(groups)-2] // Unequal group | ||||||
|  | 			curr := &groups[len(groups)-1] // Equal group | ||||||
|  | 			next := &groupsOrig[i]         // Unequal group | ||||||
|  | 			hadX, hadY := prev.NumRemoved > 0, prev.NumInserted > 0 | ||||||
|  | 			hasX, hasY := next.NumRemoved > 0, next.NumInserted > 0 | ||||||
|  | 			if ((hadX || hasX) && (hadY || hasY)) && curr.NumIdentical <= windowSize { | ||||||
|  | 				*prev = (*prev).Append(*curr).Append(*next) | ||||||
|  | 				groups = groups[:len(groups)-1] // Truncate off equal group | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		groups = append(groups, ds) | ||||||
|  | 	} | ||||||
|  | 	return groups | ||||||
|  | } | ||||||
							
								
								
									
										382
									
								
								vendor/github.com/google/go-cmp/cmp/report_text.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										382
									
								
								vendor/github.com/google/go-cmp/cmp/report_text.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,382 @@ | |||||||
|  | // Copyright 2019, The Go Authors. All rights reserved. | ||||||
|  | // Use of this source code is governed by a BSD-style | ||||||
|  | // license that can be found in the LICENSE.md file. | ||||||
|  | 
 | ||||||
|  | package cmp | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"bytes" | ||||||
|  | 	"fmt" | ||||||
|  | 	"math/rand" | ||||||
|  | 	"strings" | ||||||
|  | 	"time" | ||||||
|  | 
 | ||||||
|  | 	"github.com/google/go-cmp/cmp/internal/flags" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | var randBool = rand.New(rand.NewSource(time.Now().Unix())).Intn(2) == 0 | ||||||
|  | 
 | ||||||
|  | type indentMode int | ||||||
|  | 
 | ||||||
|  | func (n indentMode) appendIndent(b []byte, d diffMode) []byte { | ||||||
|  | 	if flags.Deterministic || randBool { | ||||||
|  | 		// Use regular spaces (U+0020). | ||||||
|  | 		switch d { | ||||||
|  | 		case diffUnknown, diffIdentical: | ||||||
|  | 			b = append(b, "  "...) | ||||||
|  | 		case diffRemoved: | ||||||
|  | 			b = append(b, "- "...) | ||||||
|  | 		case diffInserted: | ||||||
|  | 			b = append(b, "+ "...) | ||||||
|  | 		} | ||||||
|  | 	} else { | ||||||
|  | 		// Use non-breaking spaces (U+00a0). | ||||||
|  | 		switch d { | ||||||
|  | 		case diffUnknown, diffIdentical: | ||||||
|  | 			b = append(b, "  "...) | ||||||
|  | 		case diffRemoved: | ||||||
|  | 			b = append(b, "- "...) | ||||||
|  | 		case diffInserted: | ||||||
|  | 			b = append(b, "+ "...) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return repeatCount(n).appendChar(b, '\t') | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type repeatCount int | ||||||
|  | 
 | ||||||
|  | func (n repeatCount) appendChar(b []byte, c byte) []byte { | ||||||
|  | 	for ; n > 0; n-- { | ||||||
|  | 		b = append(b, c) | ||||||
|  | 	} | ||||||
|  | 	return b | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // textNode is a simplified tree-based representation of structured text. | ||||||
|  | // Possible node types are textWrap, textList, or textLine. | ||||||
|  | type textNode interface { | ||||||
|  | 	// Len reports the length in bytes of a single-line version of the tree. | ||||||
|  | 	// Nested textRecord.Diff and textRecord.Comment fields are ignored. | ||||||
|  | 	Len() int | ||||||
|  | 	// Equal reports whether the two trees are structurally identical. | ||||||
|  | 	// Nested textRecord.Diff and textRecord.Comment fields are compared. | ||||||
|  | 	Equal(textNode) bool | ||||||
|  | 	// String returns the string representation of the text tree. | ||||||
|  | 	// It is not guaranteed that len(x.String()) == x.Len(), | ||||||
|  | 	// nor that x.String() == y.String() implies that x.Equal(y). | ||||||
|  | 	String() string | ||||||
|  | 
 | ||||||
|  | 	// formatCompactTo formats the contents of the tree as a single-line string | ||||||
|  | 	// to the provided buffer. Any nested textRecord.Diff and textRecord.Comment | ||||||
|  | 	// fields are ignored. | ||||||
|  | 	// | ||||||
|  | 	// However, not all nodes in the tree should be collapsed as a single-line. | ||||||
|  | 	// If a node can be collapsed as a single-line, it is replaced by a textLine | ||||||
|  | 	// node. Since the top-level node cannot replace itself, this also returns | ||||||
|  | 	// the current node itself. | ||||||
|  | 	// | ||||||
|  | 	// This does not mutate the receiver. | ||||||
|  | 	formatCompactTo([]byte, diffMode) ([]byte, textNode) | ||||||
|  | 	// formatExpandedTo formats the contents of the tree as a multi-line string | ||||||
|  | 	// to the provided buffer. In order for column alignment to operate well, | ||||||
|  | 	// formatCompactTo must be called before calling formatExpandedTo. | ||||||
|  | 	formatExpandedTo([]byte, diffMode, indentMode) []byte | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // textWrap is a wrapper that concatenates a prefix and/or a suffix | ||||||
|  | // to the underlying node. | ||||||
|  | type textWrap struct { | ||||||
|  | 	Prefix string   // e.g., "bytes.Buffer{" | ||||||
|  | 	Value  textNode // textWrap | textList | textLine | ||||||
|  | 	Suffix string   // e.g., "}" | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (s textWrap) Len() int { | ||||||
|  | 	return len(s.Prefix) + s.Value.Len() + len(s.Suffix) | ||||||
|  | } | ||||||
|  | func (s1 textWrap) Equal(s2 textNode) bool { | ||||||
|  | 	if s2, ok := s2.(textWrap); ok { | ||||||
|  | 		return s1.Prefix == s2.Prefix && s1.Value.Equal(s2.Value) && s1.Suffix == s2.Suffix | ||||||
|  | 	} | ||||||
|  | 	return false | ||||||
|  | } | ||||||
|  | func (s textWrap) String() string { | ||||||
|  | 	var d diffMode | ||||||
|  | 	var n indentMode | ||||||
|  | 	_, s2 := s.formatCompactTo(nil, d) | ||||||
|  | 	b := n.appendIndent(nil, d)      // Leading indent | ||||||
|  | 	b = s2.formatExpandedTo(b, d, n) // Main body | ||||||
|  | 	b = append(b, '\n')              // Trailing newline | ||||||
|  | 	return string(b) | ||||||
|  | } | ||||||
|  | func (s textWrap) formatCompactTo(b []byte, d diffMode) ([]byte, textNode) { | ||||||
|  | 	n0 := len(b) // Original buffer length | ||||||
|  | 	b = append(b, s.Prefix...) | ||||||
|  | 	b, s.Value = s.Value.formatCompactTo(b, d) | ||||||
|  | 	b = append(b, s.Suffix...) | ||||||
|  | 	if _, ok := s.Value.(textLine); ok { | ||||||
|  | 		return b, textLine(b[n0:]) | ||||||
|  | 	} | ||||||
|  | 	return b, s | ||||||
|  | } | ||||||
|  | func (s textWrap) formatExpandedTo(b []byte, d diffMode, n indentMode) []byte { | ||||||
|  | 	b = append(b, s.Prefix...) | ||||||
|  | 	b = s.Value.formatExpandedTo(b, d, n) | ||||||
|  | 	b = append(b, s.Suffix...) | ||||||
|  | 	return b | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // textList is a comma-separated list of textWrap or textLine nodes. | ||||||
|  | // The list may be formatted as multi-lines or single-line at the discretion | ||||||
|  | // of the textList.formatCompactTo method. | ||||||
|  | type textList []textRecord | ||||||
|  | type textRecord struct { | ||||||
|  | 	Diff    diffMode     // e.g., 0 or '-' or '+' | ||||||
|  | 	Key     string       // e.g., "MyField" | ||||||
|  | 	Value   textNode     // textWrap | textLine | ||||||
|  | 	Comment fmt.Stringer // e.g., "6 identical fields" | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // AppendEllipsis appends a new ellipsis node to the list if none already | ||||||
|  | // exists at the end. If cs is non-zero it coalesces the statistics with the | ||||||
|  | // previous diffStats. | ||||||
|  | func (s *textList) AppendEllipsis(ds diffStats) { | ||||||
|  | 	hasStats := ds != diffStats{} | ||||||
|  | 	if len(*s) == 0 || !(*s)[len(*s)-1].Value.Equal(textEllipsis) { | ||||||
|  | 		if hasStats { | ||||||
|  | 			*s = append(*s, textRecord{Value: textEllipsis, Comment: ds}) | ||||||
|  | 		} else { | ||||||
|  | 			*s = append(*s, textRecord{Value: textEllipsis}) | ||||||
|  | 		} | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	if hasStats { | ||||||
|  | 		(*s)[len(*s)-1].Comment = (*s)[len(*s)-1].Comment.(diffStats).Append(ds) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (s textList) Len() (n int) { | ||||||
|  | 	for i, r := range s { | ||||||
|  | 		n += len(r.Key) | ||||||
|  | 		if r.Key != "" { | ||||||
|  | 			n += len(": ") | ||||||
|  | 		} | ||||||
|  | 		n += r.Value.Len() | ||||||
|  | 		if i < len(s)-1 { | ||||||
|  | 			n += len(", ") | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return n | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (s1 textList) Equal(s2 textNode) bool { | ||||||
|  | 	if s2, ok := s2.(textList); ok { | ||||||
|  | 		if len(s1) != len(s2) { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 		for i := range s1 { | ||||||
|  | 			r1, r2 := s1[i], s2[i] | ||||||
|  | 			if !(r1.Diff == r2.Diff && r1.Key == r2.Key && r1.Value.Equal(r2.Value) && r1.Comment == r2.Comment) { | ||||||
|  | 				return false | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		return true | ||||||
|  | 	} | ||||||
|  | 	return false | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (s textList) String() string { | ||||||
|  | 	return textWrap{"{", s, "}"}.String() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (s textList) formatCompactTo(b []byte, d diffMode) ([]byte, textNode) { | ||||||
|  | 	s = append(textList(nil), s...) // Avoid mutating original | ||||||
|  | 
 | ||||||
|  | 	// Determine whether we can collapse this list as a single line. | ||||||
|  | 	n0 := len(b) // Original buffer length | ||||||
|  | 	var multiLine bool | ||||||
|  | 	for i, r := range s { | ||||||
|  | 		if r.Diff == diffInserted || r.Diff == diffRemoved { | ||||||
|  | 			multiLine = true | ||||||
|  | 		} | ||||||
|  | 		b = append(b, r.Key...) | ||||||
|  | 		if r.Key != "" { | ||||||
|  | 			b = append(b, ": "...) | ||||||
|  | 		} | ||||||
|  | 		b, s[i].Value = r.Value.formatCompactTo(b, d|r.Diff) | ||||||
|  | 		if _, ok := s[i].Value.(textLine); !ok { | ||||||
|  | 			multiLine = true | ||||||
|  | 		} | ||||||
|  | 		if r.Comment != nil { | ||||||
|  | 			multiLine = true | ||||||
|  | 		} | ||||||
|  | 		if i < len(s)-1 { | ||||||
|  | 			b = append(b, ", "...) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	// Force multi-lined output when printing a removed/inserted node that | ||||||
|  | 	// is sufficiently long. | ||||||
|  | 	if (d == diffInserted || d == diffRemoved) && len(b[n0:]) > 80 { | ||||||
|  | 		multiLine = true | ||||||
|  | 	} | ||||||
|  | 	if !multiLine { | ||||||
|  | 		return b, textLine(b[n0:]) | ||||||
|  | 	} | ||||||
|  | 	return b, s | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (s textList) formatExpandedTo(b []byte, d diffMode, n indentMode) []byte { | ||||||
|  | 	alignKeyLens := s.alignLens( | ||||||
|  | 		func(r textRecord) bool { | ||||||
|  | 			_, isLine := r.Value.(textLine) | ||||||
|  | 			return r.Key == "" || !isLine | ||||||
|  | 		}, | ||||||
|  | 		func(r textRecord) int { return len(r.Key) }, | ||||||
|  | 	) | ||||||
|  | 	alignValueLens := s.alignLens( | ||||||
|  | 		func(r textRecord) bool { | ||||||
|  | 			_, isLine := r.Value.(textLine) | ||||||
|  | 			return !isLine || r.Value.Equal(textEllipsis) || r.Comment == nil | ||||||
|  | 		}, | ||||||
|  | 		func(r textRecord) int { return len(r.Value.(textLine)) }, | ||||||
|  | 	) | ||||||
|  | 
 | ||||||
|  | 	// Format the list as a multi-lined output. | ||||||
|  | 	n++ | ||||||
|  | 	for i, r := range s { | ||||||
|  | 		b = n.appendIndent(append(b, '\n'), d|r.Diff) | ||||||
|  | 		if r.Key != "" { | ||||||
|  | 			b = append(b, r.Key+": "...) | ||||||
|  | 		} | ||||||
|  | 		b = alignKeyLens[i].appendChar(b, ' ') | ||||||
|  | 
 | ||||||
|  | 		b = r.Value.formatExpandedTo(b, d|r.Diff, n) | ||||||
|  | 		if !r.Value.Equal(textEllipsis) { | ||||||
|  | 			b = append(b, ',') | ||||||
|  | 		} | ||||||
|  | 		b = alignValueLens[i].appendChar(b, ' ') | ||||||
|  | 
 | ||||||
|  | 		if r.Comment != nil { | ||||||
|  | 			b = append(b, " // "+r.Comment.String()...) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	n-- | ||||||
|  | 
 | ||||||
|  | 	return n.appendIndent(append(b, '\n'), d) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (s textList) alignLens( | ||||||
|  | 	skipFunc func(textRecord) bool, | ||||||
|  | 	lenFunc func(textRecord) int, | ||||||
|  | ) []repeatCount { | ||||||
|  | 	var startIdx, endIdx, maxLen int | ||||||
|  | 	lens := make([]repeatCount, len(s)) | ||||||
|  | 	for i, r := range s { | ||||||
|  | 		if skipFunc(r) { | ||||||
|  | 			for j := startIdx; j < endIdx && j < len(s); j++ { | ||||||
|  | 				lens[j] = repeatCount(maxLen - lenFunc(s[j])) | ||||||
|  | 			} | ||||||
|  | 			startIdx, endIdx, maxLen = i+1, i+1, 0 | ||||||
|  | 		} else { | ||||||
|  | 			if maxLen < lenFunc(r) { | ||||||
|  | 				maxLen = lenFunc(r) | ||||||
|  | 			} | ||||||
|  | 			endIdx = i + 1 | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	for j := startIdx; j < endIdx && j < len(s); j++ { | ||||||
|  | 		lens[j] = repeatCount(maxLen - lenFunc(s[j])) | ||||||
|  | 	} | ||||||
|  | 	return lens | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // textLine is a single-line segment of text and is always a leaf node | ||||||
|  | // in the textNode tree. | ||||||
|  | type textLine []byte | ||||||
|  | 
 | ||||||
|  | var ( | ||||||
|  | 	textNil      = textLine("nil") | ||||||
|  | 	textEllipsis = textLine("...") | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func (s textLine) Len() int { | ||||||
|  | 	return len(s) | ||||||
|  | } | ||||||
|  | func (s1 textLine) Equal(s2 textNode) bool { | ||||||
|  | 	if s2, ok := s2.(textLine); ok { | ||||||
|  | 		return bytes.Equal([]byte(s1), []byte(s2)) | ||||||
|  | 	} | ||||||
|  | 	return false | ||||||
|  | } | ||||||
|  | func (s textLine) String() string { | ||||||
|  | 	return string(s) | ||||||
|  | } | ||||||
|  | func (s textLine) formatCompactTo(b []byte, d diffMode) ([]byte, textNode) { | ||||||
|  | 	return append(b, s...), s | ||||||
|  | } | ||||||
|  | func (s textLine) formatExpandedTo(b []byte, _ diffMode, _ indentMode) []byte { | ||||||
|  | 	return append(b, s...) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type diffStats struct { | ||||||
|  | 	Name         string | ||||||
|  | 	NumIgnored   int | ||||||
|  | 	NumIdentical int | ||||||
|  | 	NumRemoved   int | ||||||
|  | 	NumInserted  int | ||||||
|  | 	NumModified  int | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (s diffStats) NumDiff() int { | ||||||
|  | 	return s.NumRemoved + s.NumInserted + s.NumModified | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (s diffStats) Append(ds diffStats) diffStats { | ||||||
|  | 	assert(s.Name == ds.Name) | ||||||
|  | 	s.NumIgnored += ds.NumIgnored | ||||||
|  | 	s.NumIdentical += ds.NumIdentical | ||||||
|  | 	s.NumRemoved += ds.NumRemoved | ||||||
|  | 	s.NumInserted += ds.NumInserted | ||||||
|  | 	s.NumModified += ds.NumModified | ||||||
|  | 	return s | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // String prints a humanly-readable summary of coalesced records. | ||||||
|  | // | ||||||
|  | // Example: | ||||||
|  | //	diffStats{Name: "Field", NumIgnored: 5}.String() => "5 ignored fields" | ||||||
|  | func (s diffStats) String() string { | ||||||
|  | 	var ss []string | ||||||
|  | 	var sum int | ||||||
|  | 	labels := [...]string{"ignored", "identical", "removed", "inserted", "modified"} | ||||||
|  | 	counts := [...]int{s.NumIgnored, s.NumIdentical, s.NumRemoved, s.NumInserted, s.NumModified} | ||||||
|  | 	for i, n := range counts { | ||||||
|  | 		if n > 0 { | ||||||
|  | 			ss = append(ss, fmt.Sprintf("%d %v", n, labels[i])) | ||||||
|  | 		} | ||||||
|  | 		sum += n | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Pluralize the name (adjusting for some obscure English grammar rules). | ||||||
|  | 	name := s.Name | ||||||
|  | 	if sum > 1 { | ||||||
|  | 		name = name + "s" | ||||||
|  | 		if strings.HasSuffix(name, "ys") { | ||||||
|  | 			name = name[:len(name)-2] + "ies" // e.g., "entrys" => "entries" | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Format the list according to English grammar (with Oxford comma). | ||||||
|  | 	switch n := len(ss); n { | ||||||
|  | 	case 0: | ||||||
|  | 		return "" | ||||||
|  | 	case 1, 2: | ||||||
|  | 		return strings.Join(ss, " and ") + " " + name | ||||||
|  | 	default: | ||||||
|  | 		return strings.Join(ss[:n-1], ", ") + ", and " + ss[n-1] + " " + name | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type commentString string | ||||||
|  | 
 | ||||||
|  | func (s commentString) String() string { return string(s) } | ||||||
							
								
								
									
										121
									
								
								vendor/github.com/google/go-cmp/cmp/report_value.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								vendor/github.com/google/go-cmp/cmp/report_value.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,121 @@ | |||||||
|  | // Copyright 2019, The Go Authors. All rights reserved. | ||||||
|  | // Use of this source code is governed by a BSD-style | ||||||
|  | // license that can be found in the LICENSE.md file. | ||||||
|  | 
 | ||||||
|  | package cmp | ||||||
|  | 
 | ||||||
|  | import "reflect" | ||||||
|  | 
 | ||||||
|  | // valueNode represents a single node within a report, which is a | ||||||
|  | // structured representation of the value tree, containing information | ||||||
|  | // regarding which nodes are equal or not. | ||||||
|  | type valueNode struct { | ||||||
|  | 	parent *valueNode | ||||||
|  | 
 | ||||||
|  | 	Type   reflect.Type | ||||||
|  | 	ValueX reflect.Value | ||||||
|  | 	ValueY reflect.Value | ||||||
|  | 
 | ||||||
|  | 	// NumSame is the number of leaf nodes that are equal. | ||||||
|  | 	// All descendants are equal only if NumDiff is 0. | ||||||
|  | 	NumSame int | ||||||
|  | 	// NumDiff is the number of leaf nodes that are not equal. | ||||||
|  | 	NumDiff int | ||||||
|  | 	// NumIgnored is the number of leaf nodes that are ignored. | ||||||
|  | 	NumIgnored int | ||||||
|  | 	// NumCompared is the number of leaf nodes that were compared | ||||||
|  | 	// using an Equal method or Comparer function. | ||||||
|  | 	NumCompared int | ||||||
|  | 	// NumTransformed is the number of non-leaf nodes that were transformed. | ||||||
|  | 	NumTransformed int | ||||||
|  | 	// NumChildren is the number of transitive descendants of this node. | ||||||
|  | 	// This counts from zero; thus, leaf nodes have no descendants. | ||||||
|  | 	NumChildren int | ||||||
|  | 	// MaxDepth is the maximum depth of the tree. This counts from zero; | ||||||
|  | 	// thus, leaf nodes have a depth of zero. | ||||||
|  | 	MaxDepth int | ||||||
|  | 
 | ||||||
|  | 	// Records is a list of struct fields, slice elements, or map entries. | ||||||
|  | 	Records []reportRecord // If populated, implies Value is not populated | ||||||
|  | 
 | ||||||
|  | 	// Value is the result of a transformation, pointer indirect, of | ||||||
|  | 	// type assertion. | ||||||
|  | 	Value *valueNode // If populated, implies Records is not populated | ||||||
|  | 
 | ||||||
|  | 	// TransformerName is the name of the transformer. | ||||||
|  | 	TransformerName string // If non-empty, implies Value is populated | ||||||
|  | } | ||||||
|  | type reportRecord struct { | ||||||
|  | 	Key   reflect.Value // Invalid for slice element | ||||||
|  | 	Value *valueNode | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (parent *valueNode) PushStep(ps PathStep) (child *valueNode) { | ||||||
|  | 	vx, vy := ps.Values() | ||||||
|  | 	child = &valueNode{parent: parent, Type: ps.Type(), ValueX: vx, ValueY: vy} | ||||||
|  | 	switch s := ps.(type) { | ||||||
|  | 	case StructField: | ||||||
|  | 		assert(parent.Value == nil) | ||||||
|  | 		parent.Records = append(parent.Records, reportRecord{Key: reflect.ValueOf(s.Name()), Value: child}) | ||||||
|  | 	case SliceIndex: | ||||||
|  | 		assert(parent.Value == nil) | ||||||
|  | 		parent.Records = append(parent.Records, reportRecord{Value: child}) | ||||||
|  | 	case MapIndex: | ||||||
|  | 		assert(parent.Value == nil) | ||||||
|  | 		parent.Records = append(parent.Records, reportRecord{Key: s.Key(), Value: child}) | ||||||
|  | 	case Indirect: | ||||||
|  | 		assert(parent.Value == nil && parent.Records == nil) | ||||||
|  | 		parent.Value = child | ||||||
|  | 	case TypeAssertion: | ||||||
|  | 		assert(parent.Value == nil && parent.Records == nil) | ||||||
|  | 		parent.Value = child | ||||||
|  | 	case Transform: | ||||||
|  | 		assert(parent.Value == nil && parent.Records == nil) | ||||||
|  | 		parent.Value = child | ||||||
|  | 		parent.TransformerName = s.Name() | ||||||
|  | 		parent.NumTransformed++ | ||||||
|  | 	default: | ||||||
|  | 		assert(parent == nil) // Must be the root step | ||||||
|  | 	} | ||||||
|  | 	return child | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (r *valueNode) Report(rs Result) { | ||||||
|  | 	assert(r.MaxDepth == 0) // May only be called on leaf nodes | ||||||
|  | 
 | ||||||
|  | 	if rs.ByIgnore() { | ||||||
|  | 		r.NumIgnored++ | ||||||
|  | 	} else { | ||||||
|  | 		if rs.Equal() { | ||||||
|  | 			r.NumSame++ | ||||||
|  | 		} else { | ||||||
|  | 			r.NumDiff++ | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	assert(r.NumSame+r.NumDiff+r.NumIgnored == 1) | ||||||
|  | 
 | ||||||
|  | 	if rs.ByMethod() { | ||||||
|  | 		r.NumCompared++ | ||||||
|  | 	} | ||||||
|  | 	if rs.ByFunc() { | ||||||
|  | 		r.NumCompared++ | ||||||
|  | 	} | ||||||
|  | 	assert(r.NumCompared <= 1) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (child *valueNode) PopStep() (parent *valueNode) { | ||||||
|  | 	if child.parent == nil { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 	parent = child.parent | ||||||
|  | 	parent.NumSame += child.NumSame | ||||||
|  | 	parent.NumDiff += child.NumDiff | ||||||
|  | 	parent.NumIgnored += child.NumIgnored | ||||||
|  | 	parent.NumCompared += child.NumCompared | ||||||
|  | 	parent.NumTransformed += child.NumTransformed | ||||||
|  | 	parent.NumChildren += child.NumChildren + 1 | ||||||
|  | 	if parent.MaxDepth < child.MaxDepth+1 { | ||||||
|  | 		parent.MaxDepth = child.MaxDepth + 1 | ||||||
|  | 	} | ||||||
|  | 	return parent | ||||||
|  | } | ||||||
							
								
								
									
										2
									
								
								vendor/github.com/google/go-github/v26/github/github.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/google/go-github/v26/github/github.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -527,7 +527,7 @@ func (c *Client) Do(ctx context.Context, req *http.Request, v interface{}) (*Res | |||||||
| 
 | 
 | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| 	defer func() { _ = resp.Body.Close() }() | 	defer resp.Body.Close() | ||||||
| 
 | 
 | ||||||
| 	response := newResponse(resp) | 	response := newResponse(resp) | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										3
									
								
								vendor/github.com/gophercloud/gophercloud/pagination/http.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								vendor/github.com/gophercloud/gophercloud/pagination/http.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -21,8 +21,7 @@ type PageResult struct { | |||||||
| func PageResultFrom(resp *http.Response) (PageResult, error) { | func PageResultFrom(resp *http.Response) (PageResult, error) { | ||||||
| 	var parsedBody interface{} | 	var parsedBody interface{} | ||||||
| 
 | 
 | ||||||
| 	defer func() { _ = resp.Body.Close() }() | 	defer resp.Body.Close() | ||||||
| 
 |  | ||||||
| 	rawBody, err := ioutil.ReadAll(resp.Body) | 	rawBody, err := ioutil.ReadAll(resp.Body) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return PageResult{}, err | 		return PageResult{}, err | ||||||
|  | |||||||
							
								
								
									
										2
									
								
								vendor/github.com/nicklaw5/helix/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/nicklaw5/helix/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,2 @@ | |||||||
|  | .DS_Store | ||||||
|  | debug.test | ||||||
							
								
								
									
										17
									
								
								vendor/github.com/nicklaw5/helix/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								vendor/github.com/nicklaw5/helix/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,17 @@ | |||||||
|  | language: go | ||||||
|  | 
 | ||||||
|  | sudo: false | ||||||
|  | 
 | ||||||
|  | go: | ||||||
|  |     - 1.8.x | ||||||
|  |     - 1.9.x | ||||||
|  |     - 1.10.x | ||||||
|  |     - 1.11.x | ||||||
|  | 
 | ||||||
|  | before_install: | ||||||
|  |     - go get golang.org/x/tools/cmd/cover | ||||||
|  |     - go get github.com/mattn/goveralls | ||||||
|  | 
 | ||||||
|  | script: | ||||||
|  |     - go test -v -parallel=10 -covermode=count -coverprofile=coverage.out | ||||||
|  |     - $HOME/gopath/bin/goveralls -coverprofile=coverage.out -service=travis-ci | ||||||
							
								
								
									
										21
									
								
								vendor/github.com/nicklaw5/helix/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								vendor/github.com/nicklaw5/helix/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,21 @@ | |||||||
|  | The MIT License (MIT) | ||||||
|  | 
 | ||||||
|  | Copyright (c) 2018 Nicholas Law | ||||||
|  | 
 | ||||||
|  | Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  | of this software and associated documentation files (the "Software"), to deal | ||||||
|  | in the Software without restriction, including without limitation the rights | ||||||
|  | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  | copies of the Software, and to permit persons to whom the Software is | ||||||
|  | furnished to do so, subject to the following conditions: | ||||||
|  | 
 | ||||||
|  | The above copyright notice and this permission notice shall be included in all | ||||||
|  | copies or substantial portions of the Software. | ||||||
|  | 
 | ||||||
|  | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||||
|  | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||||
|  | SOFTWARE. | ||||||
							
								
								
									
										103
									
								
								vendor/github.com/nicklaw5/helix/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								vendor/github.com/nicklaw5/helix/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,103 @@ | |||||||
|  | # helix | ||||||
|  | 
 | ||||||
|  | A Twitch Helix API client written in Go (Golang). | ||||||
|  | 
 | ||||||
|  | [](https://travis-ci.org/nicklaw5/helix) | ||||||
|  | [](https://coveralls.io/github/nicklaw5/helix) | ||||||
|  | 
 | ||||||
|  | ## Package Status | ||||||
|  | 
 | ||||||
|  | This project is a work in progress. Twitch has not finished all available endpoints/features for the Helix API, but as these get released they are likely to be implemented in this package. | ||||||
|  | 
 | ||||||
|  | ## Documentation & Examples | ||||||
|  | 
 | ||||||
|  | All documentation and usage examples for this package can be found in the [docs directory](docs). If you are looking for the Twitch API docs, see the [Twitch Developer website](https://dev.twitch.tv/docs/api). | ||||||
|  | 
 | ||||||
|  | ## Supported Endpoints & Features | ||||||
|  | 
 | ||||||
|  | **Authentication:** | ||||||
|  | 
 | ||||||
|  | - [x] Generate Authorization URL | ||||||
|  | - [x] Get App Access Tokens (OAuth Client Credentials Flow) | ||||||
|  | - [x] Get User Access Tokens (OAuth Authorization Code Flow) | ||||||
|  | - [x] Refresh User Access Tokens | ||||||
|  | - [x] Revoke User Access Tokens | ||||||
|  | 
 | ||||||
|  | **API Endpoint:** | ||||||
|  | 
 | ||||||
|  | - [x] Get Bits Leaderboard | ||||||
|  | - [x] Get Clip | ||||||
|  | - [x] Create Clip | ||||||
|  | - [x] Create Entitlement Grants Upload URL | ||||||
|  | - [x] Get Games | ||||||
|  | - [x] Get Top Games | ||||||
|  | - [x] Get Extension Analytics | ||||||
|  | - [x] Get Game Analytics | ||||||
|  | - [x] Get Streams | ||||||
|  | - [x] Get Streams Metadata | ||||||
|  | - [x] Create Stream Marker | ||||||
|  | - [x] Get Stream Markers | ||||||
|  | - [x] Get Users | ||||||
|  | - [x] Get Users Follows | ||||||
|  | - [x] Update User | ||||||
|  | - [x] Get Videos | ||||||
|  | - [x] Get Webhook Subscriptions | ||||||
|  | 
 | ||||||
|  | ## Quick Usage Example | ||||||
|  | 
 | ||||||
|  | This is a quick example of how to get users. Note that you don't need to provide both a list of ids and logins, one or the other will suffice. | ||||||
|  | 
 | ||||||
|  | ```go | ||||||
|  | client, err := helix.NewClient(&helix.Options{ | ||||||
|  |     ClientID: "your-client-id", | ||||||
|  | }) | ||||||
|  | if err != nil { | ||||||
|  |     // handle error | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | resp, err := client.GetUsers(&helix.UsersParams{ | ||||||
|  |     IDs:    []string{"26301881", "18074328"}, | ||||||
|  |     Logins: []string{"summit1g", "lirik"}, | ||||||
|  | }) | ||||||
|  | if err != nil { | ||||||
|  |     // handle error | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fmt.Printf("Status code: %d\n", resp.StatusCode) | ||||||
|  | fmt.Printf("Rate limit: %d\n", resp.GetRateLimit()) | ||||||
|  | fmt.Printf("Rate limit remaining: %d\n", resp.GetRateLimitRemaining()) | ||||||
|  | fmt.Printf("Rate limit reset: %d\n\n", resp.GetRateLimitReset()) | ||||||
|  | 
 | ||||||
|  | for _, user := range resp.Data.Users { | ||||||
|  |     fmt.Printf("ID: %s Name: %s\n", user.ID, user.DisplayName) | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Output: | ||||||
|  | 
 | ||||||
|  | ```txt | ||||||
|  | Status code: 200 | ||||||
|  | Rate limit: 30 | ||||||
|  | Rate limit remaining: 29 | ||||||
|  | Rate limit reset: 1517695315 | ||||||
|  | 
 | ||||||
|  | ID: 26301881 Name: sodapoppin | ||||||
|  | ID: 18074328 Name: destiny | ||||||
|  | ID: 26490481 Name: summit1g | ||||||
|  | ID: 23161357 Name: lirik | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ## Contributions | ||||||
|  | 
 | ||||||
|  | PRs are very much welcome. Where possible, please write tests for any code that is introduced by your PRs. | ||||||
|  | 
 | ||||||
|  | ## Contributors | ||||||
|  | 
 | ||||||
|  | Thanks to all of the following people (ordered alphabetically) for contributing their time for improving this library: | ||||||
|  | 
 | ||||||
|  | - Y.Horie ([@u5surf](https://github.com/u5surf)) | ||||||
|  | - Philipp Führer ([@flipkick](https://github.com/flipkick)) | ||||||
|  | 
 | ||||||
|  | ## License | ||||||
|  | 
 | ||||||
|  | This package is distributed under the terms of the [MIT](License) License. | ||||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user