Repository: jingweno/spotctl Branch: master Commit: 6f44a3f7a7b8 Files: 275 Total size: 1.5 MB Directory structure: gitextract_f0axi5je/ ├── .gitignore ├── Formula/ │ └── spotctl.rb ├── Gopkg.toml ├── LICENSE ├── README.md ├── bin/ │ └── package ├── cmd/ │ └── spotctl/ │ ├── auth.go │ ├── ctl.go │ ├── main.go │ ├── player.go │ └── version.go └── vendor/ ├── github.com/ │ ├── golang/ │ │ └── protobuf/ │ │ ├── .gitignore │ │ ├── .travis.yml │ │ ├── AUTHORS │ │ ├── CONTRIBUTORS │ │ ├── LICENSE │ │ ├── Make.protobuf │ │ ├── Makefile │ │ ├── README.md │ │ └── proto/ │ │ ├── Makefile │ │ ├── all_test.go │ │ ├── any_test.go │ │ ├── clone.go │ │ ├── clone_test.go │ │ ├── decode.go │ │ ├── decode_test.go │ │ ├── encode.go │ │ ├── encode_test.go │ │ ├── equal.go │ │ ├── equal_test.go │ │ ├── extensions.go │ │ ├── extensions_test.go │ │ ├── lib.go │ │ ├── map_test.go │ │ ├── message_set.go │ │ ├── message_set_test.go │ │ ├── pointer_reflect.go │ │ ├── pointer_unsafe.go │ │ ├── properties.go │ │ ├── proto3_test.go │ │ ├── size2_test.go │ │ ├── size_test.go │ │ ├── text.go │ │ ├── text_parser.go │ │ ├── text_parser_test.go │ │ └── text_test.go │ ├── inconshreveable/ │ │ └── mousetrap/ │ │ ├── LICENSE │ │ ├── README.md │ │ ├── trap_others.go │ │ ├── trap_windows.go │ │ └── trap_windows_1.4.go │ ├── maruel/ │ │ └── panicparse/ │ │ ├── .travis.yml │ │ ├── Gopkg.toml │ │ ├── LICENSE │ │ ├── README.md │ │ ├── main.go │ │ └── stack/ │ │ ├── source.go │ │ ├── source_test.go │ │ ├── stack.go │ │ ├── stack_test.go │ │ ├── ui.go │ │ └── ui_test.go │ ├── mattn/ │ │ └── go-runewidth/ │ │ ├── .travis.yml │ │ ├── LICENSE │ │ ├── README.mkd │ │ ├── runewidth.go │ │ ├── runewidth_js.go │ │ ├── runewidth_posix.go │ │ ├── runewidth_test.go │ │ └── runewidth_windows.go │ ├── mitchellh/ │ │ └── go-wordwrap/ │ │ ├── LICENSE.md │ │ ├── README.md │ │ ├── wordwrap.go │ │ └── wordwrap_test.go │ ├── nsf/ │ │ └── termbox-go/ │ │ ├── AUTHORS │ │ ├── LICENSE │ │ ├── README.md │ │ ├── api.go │ │ ├── api_common.go │ │ ├── api_windows.go │ │ ├── collect_terminfo.py │ │ ├── syscalls.go │ │ ├── syscalls_darwin.go │ │ ├── syscalls_darwin_amd64.go │ │ ├── syscalls_dragonfly.go │ │ ├── syscalls_freebsd.go │ │ ├── syscalls_linux.go │ │ ├── syscalls_netbsd.go │ │ ├── syscalls_openbsd.go │ │ ├── syscalls_windows.go │ │ ├── termbox.go │ │ ├── termbox_common.go │ │ ├── termbox_windows.go │ │ ├── terminfo.go │ │ └── terminfo_builtin.go │ ├── spf13/ │ │ ├── cobra/ │ │ │ ├── .gitignore │ │ │ ├── .mailmap │ │ │ ├── .travis.yml │ │ │ ├── LICENSE.txt │ │ │ ├── README.md │ │ │ ├── args.go │ │ │ ├── args_test.go │ │ │ ├── bash_completions.go │ │ │ ├── bash_completions.md │ │ │ ├── bash_completions_test.go │ │ │ ├── cobra.go │ │ │ ├── cobra_test.go │ │ │ ├── command.go │ │ │ ├── command_notwin.go │ │ │ ├── command_test.go │ │ │ ├── command_win.go │ │ │ ├── zsh_completions.go │ │ │ └── zsh_completions_test.go │ │ └── pflag/ │ │ ├── .gitignore │ │ ├── .travis.yml │ │ ├── LICENSE │ │ ├── README.md │ │ ├── bool.go │ │ ├── bool_slice.go │ │ ├── bool_slice_test.go │ │ ├── bool_test.go │ │ ├── count.go │ │ ├── count_test.go │ │ ├── duration.go │ │ ├── example_test.go │ │ ├── export_test.go │ │ ├── flag.go │ │ ├── flag_test.go │ │ ├── float32.go │ │ ├── float64.go │ │ ├── golangflag.go │ │ ├── golangflag_test.go │ │ ├── int.go │ │ ├── int32.go │ │ ├── int64.go │ │ ├── int8.go │ │ ├── int_slice.go │ │ ├── int_slice_test.go │ │ ├── ip.go │ │ ├── ip_slice.go │ │ ├── ip_slice_test.go │ │ ├── ip_test.go │ │ ├── ipmask.go │ │ ├── ipnet.go │ │ ├── ipnet_test.go │ │ ├── string.go │ │ ├── string_array.go │ │ ├── string_array_test.go │ │ ├── string_slice.go │ │ ├── string_slice_test.go │ │ ├── uint.go │ │ ├── uint16.go │ │ ├── uint32.go │ │ ├── uint64.go │ │ ├── uint8.go │ │ ├── uint_slice.go │ │ └── uint_slice_test.go │ └── zmb3/ │ └── spotify/ │ ├── .travis.yml │ ├── LICENSE │ ├── README.md │ ├── album.go │ ├── album_test.go │ ├── artist.go │ ├── artist_test.go │ ├── audio_analysis.go │ ├── audio_analysis_test.go │ ├── audio_features.go │ ├── audio_features_test.go │ ├── auth.go │ ├── category.go │ ├── category_test.go │ ├── countries.go │ ├── cursor.go │ ├── full_tests.bat │ ├── library.go │ ├── library_test.go │ ├── page.go │ ├── player.go │ ├── player_test.go │ ├── playlist.go │ ├── playlist_test.go │ ├── recommendation.go │ ├── recommendation_test.go │ ├── search.go │ ├── search_test.go │ ├── spotify.go │ ├── spotify_test.go │ ├── track.go │ ├── track_attributes.go │ ├── track_test.go │ ├── user.go │ └── user_test.go ├── golang.org/ │ └── x/ │ ├── net/ │ │ ├── .gitattributes │ │ ├── .gitignore │ │ ├── AUTHORS │ │ ├── CONTRIBUTING.md │ │ ├── CONTRIBUTORS │ │ ├── LICENSE │ │ ├── PATENTS │ │ ├── README.md │ │ ├── codereview.cfg │ │ └── context/ │ │ ├── context.go │ │ ├── context_test.go │ │ ├── ctxhttp/ │ │ │ ├── ctxhttp.go │ │ │ ├── ctxhttp_17_test.go │ │ │ ├── ctxhttp_pre17.go │ │ │ ├── ctxhttp_pre17_test.go │ │ │ └── ctxhttp_test.go │ │ ├── go17.go │ │ ├── go19.go │ │ ├── pre_go17.go │ │ ├── pre_go19.go │ │ └── withtimeout_test.go │ └── oauth2/ │ ├── .travis.yml │ ├── AUTHORS │ ├── CONTRIBUTING.md │ ├── CONTRIBUTORS │ ├── LICENSE │ ├── README.md │ ├── client_appengine.go │ ├── example_test.go │ ├── internal/ │ │ ├── doc.go │ │ ├── oauth2.go │ │ ├── oauth2_test.go │ │ ├── token.go │ │ ├── token_test.go │ │ ├── transport.go │ │ └── transport_test.go │ ├── oauth2.go │ ├── oauth2_test.go │ ├── token.go │ ├── token_test.go │ ├── transport.go │ └── transport_test.go └── google.golang.org/ └── appengine/ ├── .travis.yml ├── LICENSE ├── README.md ├── appengine.go ├── appengine_test.go ├── appengine_vm.go ├── errors.go ├── identity.go ├── internal/ │ ├── api.go │ ├── api_classic.go │ ├── api_common.go │ ├── api_race_test.go │ ├── api_test.go │ ├── app_id.go │ ├── app_id_test.go │ ├── base/ │ │ ├── api_base.pb.go │ │ └── api_base.proto │ ├── datastore/ │ │ ├── datastore_v3.pb.go │ │ └── datastore_v3.proto │ ├── identity.go │ ├── identity_classic.go │ ├── identity_vm.go │ ├── internal.go │ ├── internal_vm_test.go │ ├── log/ │ │ ├── log_service.pb.go │ │ └── log_service.proto │ ├── main.go │ ├── main_vm.go │ ├── metadata.go │ ├── net.go │ ├── net_test.go │ ├── regen.sh │ ├── remote_api/ │ │ ├── remote_api.pb.go │ │ └── remote_api.proto │ ├── transaction.go │ └── urlfetch/ │ ├── urlfetch_service.pb.go │ └── urlfetch_service.proto ├── namespace.go ├── namespace_test.go ├── timeout.go └── urlfetch/ └── urlfetch.go ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ build release ================================================ FILE: Formula/spotctl.rb ================================================ class Spotctl < Formula desc "A CLI to Spotify" homepage "https://github.com/jingweno/spotctl" version "1.0.1" sha256 "a0276bd0c0fb65e7b24885f17d3547276dcf9b059b9507abe51edfa5f5388f89" url "https://github.com/jingweno/spotctl/releases/download/v1.0.1/darwin-amd64-1.0.1.tar.gz" def install bin.install "spotctl" end end ================================================ FILE: Gopkg.toml ================================================ # Gopkg.toml example # # Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md # for detailed Gopkg.toml documentation. # # required = ["github.com/user/thing/cmd/thing"] # ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] # # [[constraint]] # name = "github.com/user/project" # version = "1.0.0" # # [[constraint]] # name = "github.com/user/project2" # branch = "dev" # source = "github.com/myfork/project2" # # [[override]] # name = "github.com/x/y" # version = "2.4.0" [[constraint]] name = "github.com/spf13/cobra" branch = "master" [[constraint]] branch = "master" name = "github.com/zmb3/spotify" [[constraint]] branch = "master" name = "github.com/gizak/termui" ================================================ FILE: LICENSE ================================================ Copyright (c) 2018 Jingwen Owen Ou 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. ================================================ FILE: README.md ================================================ # Spotctl `spotctl` is command-line interface to control Spotify from your favorite terminal. ## Demo One of the highlights is that `spotctl player` shows a real-time Spotify player that allows you to control it, right in your terminal! [![asciicast](https://asciinema.org/a/154262.png)](https://asciinema.org/a/154262) ## Installation ## Homebrew If you're on a Mac, you can install with [Homebrew](https://brew.sh/): ``` brew install https://raw.githubusercontent.com/jingweno/spotctl/master/Formula/spotctl.rb ``` ## Download You can download the latest release for your operating system [here](https://github.com/jingweno/spotctl/releases). ## Manual Installation `spotctl` needs to connect to Spotify's API in order to control it. To manually build it, you first need to sign up (or into) Spotify's developer site and [create an Application](https://developer.spotify.com/my-applications/#!/applications/create). Once you've done so, you can find its Client ID and Client Secret values and run the following command: ``` SPOTIFY_CLIENT_ID=XXX SPOTIFY_CLIENT_SECRET=YYY ./bin/build ``` ## Running **Please make sure the Spotify app is opened before running any `spotctl` commands**, since it talks to the Spotify API which in turns talks to the Spotify app in your local box. Here is a list of available commands: ``` $ spotctl -h A command-line interface to Spotify. Usage: spotctl [command] Available Commands: help Help about any command login Login with your Spotify credentials logout Clear your local Spotify credentials next Skip to the next track pause Pause Spotify playback play Resume playback or play a track, album, artist or playlist by name player Show the live player panel prev Return to the previous track repeat Toggle repeat playback mode shuffle Toggle shuffle playback mode status Show the current player status version Show version. vol Set or return volume percentage Flags: -h, --help help for spotctl Use "spotctl [command] --help" for more information about a command. ``` ## License [MIT](https://github.com/jingweno/spotctl/blob/master/LICENSE) ================================================ FILE: bin/package ================================================ #!/bin/bash -e version() { ver="$(git describe --tags HEAD 2>/dev/null || true)" if [ -z "$ver" ]; then ver="$(grep version version.go | head -1 | cut -d '"' -f2)" sha="$(git rev-parse --short HEAD 2>/dev/null || true)" [ -z "$sha" ] || ver="${ver}-g${sha}" fi echo "${ver#v}" } compress() { cd release for dir in */ do base=$(basename "$dir") cp ../README.md ../LICENSE $dir echo "Compressing $base" tar -zcf "${base}.tar.gz" "$dir" rm -rf $dir done echo ls -all } OSARCH="darwin/amd64 linux/amd64 linux/386 windows/amd64 windows/386" cd cmd/spotctl echo "Packaging spotctl $(version)" go get -u github.com/mitchellh/gox gox -osarch="$OSARCH" \ -ldflags "-X main.spotifyClientID=$SPOTIFY_CLIENT_ID -X main.spotifyClientSecret=$SPOTIFY_CLIENT_SECRET -X main.version=$(version)" \ -output="../../release/{{.OS}}-{{.Arch}}-$(version)/{{.Dir}}" echo cd - compress ================================================ FILE: cmd/spotctl/auth.go ================================================ package main import ( "crypto/rand" "encoding/base64" "fmt" "log" "net/http" "os" "github.com/spf13/cobra" "github.com/zmb3/spotify" "golang.org/x/oauth2" ) var loginCmd = &cobra.Command{ Use: "login", Short: "Login with your Spotify credentials", RunE: login, } var logoutCmd = &cobra.Command{ Use: "logout", Short: "Clear your local Spotify credentials", RunE: login, } func login(cmd *cobra.Command, args []string) error { state, err := generateRandomString(32) if err != nil { return err } ch := make(chan *oauth2.Token) http.Handle("/callback", &authHandler{state: state, ch: ch, auth: auth}) go http.ListenAndServe("localhost:10028", nil) url := auth.AuthURL(state) fmt.Println("Please log in to Spotify by visiting the following page in your browser:", url) tok := <-ch if err := saveToken(tok); err != nil { return err } return nil } func logout(cmd *cobra.Command, args []string) error { os.Remove(tokenPath) return nil } type authHandler struct { state string ch chan *oauth2.Token auth spotify.Authenticator } func (a *authHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { tok, err := a.auth.Token(a.state, r) if err != nil { http.Error(w, "Couldn't get token", http.StatusForbidden) log.Fatal(err) } if st := r.FormValue("state"); st != a.state { http.NotFound(w, r) log.Fatalf("State mismatch: %s != %s\n", st, a.state) } fmt.Fprintf(w, "Login successfully. Please return to your terminal.") a.ch <- tok } func generateRandomBytes(n int) ([]byte, error) { b := make([]byte, n) _, err := rand.Read(b) if err != nil { return nil, err } return b, nil } func generateRandomString(s int) (string, error) { b, err := generateRandomBytes(s) return base64.URLEncoding.EncodeToString(b), err } ================================================ FILE: cmd/spotctl/ctl.go ================================================ package main import ( "fmt" "strconv" "strings" "github.com/spf13/cobra" "github.com/zmb3/spotify" ) var ( playCmdFlagType string deviceNameFlag string ) var playCmd = &cobra.Command{ Use: "play [name]", Short: "Resume playback or play a track, album, artist or playlist by name", Long: `Resume playback or find a track, album, artist or playlist by name and play it. The search type can be specified with --type.`, RunE: play, } var pauseCmd = &cobra.Command{ Use: "pause", Short: "Pause Spotify playback", RunE: pause, } var nextCmd = &cobra.Command{ Use: "next", Short: "Skip to the next track", RunE: next, } var prevCmd = &cobra.Command{ Use: "prev", Short: "Return to the previous track", RunE: prev, } var volCmd = &cobra.Command{ Use: "vol [up|down|amount]", Short: "Set or return volume percentage", Long: `Set volume percentage to an amount between 0 and 100. If arg is up, volume is increased by 10%. If arg is down, volume is decreased by 10%. If no arg is provided, current volume percentage is returned.`, RunE: vol, } var statusCmd = &cobra.Command{ Use: "status", Short: "Show the current player status", RunE: status, } var shuffleCmd = &cobra.Command{ Use: "shuffle", Short: "Toggle shuffle playback mode", RunE: shuffle, } var repeatCmd = &cobra.Command{ Use: "repeat", Short: "Toggle repeat playback mode", RunE: repeat, } var devicesCmd = &cobra.Command{ Use: "devices", Short: "Show list of available devices", RunE: devices, } func shuffle(cmd *cobra.Command, args []string) error { state, err := client.PlayerState() if err != nil { return err } return client.Shuffle(!state.ShuffleState) } func repeat(cmd *cobra.Command, args []string) error { state, err := client.PlayerState() if err != nil { return err } var repeat string if state.RepeatState == "off" { repeat = "track" } else if state.RepeatState == "track" { repeat = "context" } else if state.RepeatState == "context" { repeat = "off" } else { return fmt.Errorf("unsupported repeat state %s", state.RepeatState) } opt := &spotify.PlayOptions{ DeviceID: findDeviceByName(deviceNameFlag), } return client.RepeatOpt(repeat, opt) } func play(cmd *cobra.Command, args []string) error { var ( opt = &spotify.PlayOptions{} err error ) if len(args) > 0 { // if args start with a spotify ID, play it directly, otherwise search for songs if strings.Contains(args[0], "spotify:") { opt = playByID(args[0]) // only play the first id } else { opt, err = searchToPlay(strings.Join(args, " "), playCmdFlagType) if err != nil { return err } } } opt.DeviceID = findDeviceByName(deviceNameFlag) return client.PlayOpt(opt) } func devices(cmd *cobra.Command, args []string) error { devices, err := client.PlayerDevices() if err != nil { return err } for _, device := range devices { active := "" if device.Active { active = "* " } fmt.Printf("%s%s - %s (volume %d%%)\n", active, device.Name, device.Type, device.Volume) } return nil } func vol(cmd *cobra.Command, args []string) error { state, err := client.PlayerState() if err != nil { return err } if len(args) == 0 { fmt.Printf("Current volume is %d%%.\n", state.Device.Volume) return nil } var currVolume int switch vol := args[0]; vol { case "up": currVolume = state.Device.Volume + 10 case "down": currVolume = state.Device.Volume - 10 default: currVolume, err = strconv.Atoi(vol) if err != nil { return err } } if currVolume < 0 { currVolume = 0 } if currVolume > 100 { currVolume = 100 } opt := &spotify.PlayOptions{ DeviceID: findDeviceByName(deviceNameFlag), } return client.VolumeOpt(currVolume, opt) } func pause(cmd *cobra.Command, args []string) error { opt := &spotify.PlayOptions{ DeviceID: findDeviceByName(deviceNameFlag), } return client.PauseOpt(opt) } func next(cmd *cobra.Command, args []string) error { opt := &spotify.PlayOptions{ DeviceID: findDeviceByName(deviceNameFlag), } return client.NextOpt(opt) } func prev(cmd *cobra.Command, args []string) error { opt := &spotify.PlayOptions{ DeviceID: findDeviceByName(deviceNameFlag), } return client.PreviousOpt(opt) } func status(cmd *cobra.Command, args []string) error { state, err := client.PlayerState() if err != nil { return err } if state.Playing && state.Item != nil { var artists []string for _, a := range state.Item.Artists { artists = append(artists, a.Name) } fmt.Printf("Spotify is currently playing on %s.\n", state.Device.Name) fmt.Printf("Artist: %s\n", strings.Join(artists, ", ")) fmt.Printf("Album: %s\n", state.Item.Album.Name) fmt.Printf("Track: %s\n", state.Item.Name) fmt.Printf("Position: %s / %s\n", durationToStr(state.Progress), durationToStr(state.Item.Duration)) } else { fmt.Println("Spotify is currently paused.") } return nil } // findDeviceByName finds the device by name. // If name is empty, the first Computer device ID is returned if it's available; // otherwise it returns the first device ID. func findDeviceByName(name string) *spotify.ID { devices, err := client.PlayerDevices() if err != nil { return nil } for _, device := range devices { if name != "" && device.Name == name { return &device.ID } else if device.Type == "Computer" { return &device.ID } } if len(devices) > 0 { return &devices[0].ID } return nil } func playByID(id string) *spotify.PlayOptions { var ( uris []spotify.URI context *spotify.URI ) if strings.Contains(id, "spotify:track") { uris = append(uris, spotify.URI(id)) } else { uri := spotify.URI(id) context = &uri } return &spotify.PlayOptions{ PlaybackContext: context, URIs: uris, } } func searchToPlay(query, t string) (*spotify.PlayOptions, error) { var st spotify.SearchType switch t { case "track": st = spotify.SearchTypeTrack case "album": st = spotify.SearchTypeAlbum case "artist": st = spotify.SearchTypeArtist case "playlist": st = spotify.SearchTypePlaylist default: return nil, fmt.Errorf("unsupported search type %s", t) } result, err := client.Search(query, st) if err != nil { return nil, err } var opt *spotify.PlayOptions switch t { case "track": if result.Tracks != nil && len(result.Tracks.Tracks) > 0 { opt = &spotify.PlayOptions{ URIs: []spotify.URI{result.Tracks.Tracks[0].URI}, } } case "album": if result.Albums != nil && len(result.Albums.Albums) > 0 { opt = &spotify.PlayOptions{ PlaybackContext: &result.Albums.Albums[0].URI, } } case "artist": if result.Artists != nil && len(result.Artists.Artists) > 0 { opt = &spotify.PlayOptions{ PlaybackContext: &result.Artists.Artists[0].URI, } } case "playlist": if result.Playlists != nil && len(result.Playlists.Playlists) > 0 { opt = &spotify.PlayOptions{ PlaybackContext: &result.Playlists.Playlists[0].URI, } } } return opt, nil } ================================================ FILE: cmd/spotctl/main.go ================================================ package main import ( "encoding/json" "fmt" "io/ioutil" "log" "os" "os/user" "path/filepath" "github.com/spf13/cobra" "github.com/zmb3/spotify" "golang.org/x/oauth2" ) const ( redirectURI = "http://localhost:10028/callback" ) var ( spotifyClientID string spotifyClientSecret string ) var ( auth spotify.Authenticator token *oauth2.Token client spotify.Client tokenPath string ) var rootCmd = &cobra.Command{ Use: "spotctl", Short: "A command-line interface to Spotify.", PersistentPreRun: preRootCmd, PersistentPostRun: postRootCmd, } var versionCmd = &cobra.Command{ Use: "version", Short: "Show version.", Run: ver, } func ver(cmd *cobra.Command, args []string) { fmt.Println(version) } func main() { rootCmd.AddCommand(loginCmd) rootCmd.AddCommand(logoutCmd) rootCmd.AddCommand(devicesCmd) rootCmd.AddCommand(playCmd) rootCmd.AddCommand(pauseCmd) rootCmd.AddCommand(nextCmd) rootCmd.AddCommand(prevCmd) rootCmd.AddCommand(volCmd) rootCmd.AddCommand(shuffleCmd) rootCmd.AddCommand(repeatCmd) rootCmd.AddCommand(statusCmd) rootCmd.AddCommand(playerCmd) rootCmd.AddCommand(versionCmd) playCmd.PersistentFlags().StringVarP(&playCmdFlagType, "type", "t", "track", "the type of [name] to play: track, album, artist or playlist.") playCmd.PersistentFlags().StringVarP(&deviceNameFlag, "device", "d", "", "the name of device") pauseCmd.PersistentFlags().StringVarP(&deviceNameFlag, "device", "d", "", "the name of device") nextCmd.PersistentFlags().StringVarP(&deviceNameFlag, "device", "d", "", "the name of device") prevCmd.PersistentFlags().StringVarP(&deviceNameFlag, "device", "d", "", "the name of device") volCmd.PersistentFlags().StringVarP(&deviceNameFlag, "device", "d", "", "the name of device") shuffleCmd.PersistentFlags().StringVarP(&deviceNameFlag, "device", "d", "", "the name of device") repeatCmd.PersistentFlags().StringVarP(&deviceNameFlag, "device", "d", "", "the name of device") playerCmd.PersistentFlags().StringVarP(&deviceNameFlag, "device", "d", "", "the name of device") if err := rootCmd.Execute(); err != nil { log.Fatal(err) } } func preRootCmd(cmd *cobra.Command, args []string) { usr, err := user.Current() if err != nil { log.Fatal(err) } tokenPath = filepath.Join(usr.HomeDir, ".spotctl") auth = spotify.NewAuthenticator( redirectURI, spotify.ScopeUserReadCurrentlyPlaying, spotify.ScopeUserReadPlaybackState, spotify.ScopeUserModifyPlaybackState, ) auth.SetAuthInfo(spotifyClientID, spotifyClientSecret) // skip reading token if this is a login/logout command if cmd.Use == "login" || cmd.Use == "logout" { return } token, err = readToken() if err != nil { if os.IsNotExist(err) { if err := login(cmd, args); err != nil { log.Fatal(err) } // read token one more time token, err = readToken() if err != nil { log.Fatal(err) } } else { log.Fatal(err) } } client = auth.NewClient(token) } func postRootCmd(cmd *cobra.Command, args []string) { // skip reading token if this is a login/logout command if cmd.Use == "login" || cmd.Use == "logout" { return } tokenInUse, err := client.Token() if err != nil { log.Fatal(err) } if tokenInUse != token { if err := saveToken(tokenInUse); err != nil { log.Fatal(err) } } } func saveToken(tok *oauth2.Token) error { f, err := os.OpenFile(tokenPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) if err != nil { return err } defer f.Close() enc := json.NewEncoder(f) return enc.Encode(tok) } func readToken() (*oauth2.Token, error) { content, err := ioutil.ReadFile(tokenPath) if err != nil { return nil, err } var tok oauth2.Token if err := json.Unmarshal(content, &tok); err != nil { return nil, err } return &tok, nil } ================================================ FILE: cmd/spotctl/player.go ================================================ package main import ( "fmt" "log" "strings" "time" ui "github.com/gizak/termui" "github.com/spf13/cobra" ) var playerCmd = &cobra.Command{ Use: "player", Short: "Show the live player panel", RunE: player, } func player(cmd *cobra.Command, args []string) error { if err := ui.Init(); err != nil { log.Fatal(err) } defer ui.Close() songList := ui.NewList() songList.Border = false songList.X = 0 songList.Y = 0 songList.Height = 2 songList.Width = 40 ctlList := ui.NewList() ctlList.Border = false ctlList.X = 0 ctlList.Y = 3 ctlList.Height = 2 ctlList.Width = 40 currPosLabel := ui.NewPar("") currPosLabel.X = 0 currPosLabel.Y = 6 currPosLabel.Width = 6 currPosLabel.Border = false progressGauge := ui.NewGauge() progressGauge.LabelAlign = ui.AlignCenter progressGauge.Height = 2 progressGauge.Y = 6 progressGauge.X = 6 progressGauge.Width = 30 progressGauge.Border = false progressGauge.Label = "" progressGauge.Percent = 0 progressGauge.PaddingBottom = 1 totalSecLabel := ui.NewPar("") totalSecLabel.X = 38 totalSecLabel.Y = 6 totalSecLabel.Width = 6 totalSecLabel.Border = false volGauge := ui.NewGauge() volGauge.LabelAlign = ui.AlignCenter volGauge.Height = 2 volGauge.Y = 8 volGauge.X = 0 volGauge.Width = 44 volGauge.Border = false volGauge.BarColor = ui.ColorBlue volGauge.PaddingBottom = 1 helpLabel := ui.NewPar("Press q - quit, p - play/pause, l/h - next/previous track, j/k - vol up/down, s - shuffle, r - repeat.") helpLabel.X = 0 helpLabel.Y = 10 helpLabel.Width = 40 helpLabel.Height = 5 helpLabel.Border = false helpLabel.WrapLength = 40 draw := func() { ui.Render( songList, ctlList, currPosLabel, progressGauge, totalSecLabel, volGauge, helpLabel, ) } ui.Handle("/sys/kbd/q", func(ui.Event) { ui.StopLoop() }) ui.Handle("/sys/kbd/p", func(ui.Event) { state, err := client.PlayerState() if err != nil { quitAndFatal(err) } if state.Playing { if err := pause(pauseCmd, []string{}); err != nil { quitAndFatal(err) } } else { if err := play(playCmd, []string{}); err != nil { quitAndFatal(err) } } }) ui.Handle("/sys/kbd/l", func(ui.Event) { if err := next(nextCmd, []string{}); err != nil { quitAndFatal(err) } }) ui.Handle("/sys/kbd/h", func(ui.Event) { if err := prev(prevCmd, []string{}); err != nil { quitAndFatal(err) } }) ui.Handle("/sys/kbd/j", func(ui.Event) { if err := vol(volCmd, []string{"up"}); err != nil { quitAndFatal(err) } }) ui.Handle("/sys/kbd/k", func(ui.Event) { if err := vol(volCmd, []string{"down"}); err != nil { quitAndFatal(err) } }) ui.Handle("/sys/kbd/s", func(ui.Event) { if err := shuffle(shuffleCmd, []string{}); err != nil { quitAndFatal(err) } }) ui.Handle("/sys/kbd/r", func(ui.Event) { if err := repeat(repeatCmd, []string{}); err != nil { quitAndFatal(err) } }) ui.Handle("/timer/1s", func(e ui.Event) { state, err := client.PlayerState() if err != nil { quitAndFatal(err) } volGauge.Percent = state.Device.Volume volGauge.Label = "Volume {{percent}}%" shuffleState := "off" if state.ShuffleState { shuffleState = "on" } ctlList.Items = []string{ "Shuffle " + shuffleState, "Repeat " + state.RepeatState, } if state.Playing { progressGauge.Label = "Playing" progressGauge.BarColor = ui.ColorGreen } else { progressGauge.Label = "Paused" progressGauge.BarColor = ui.ColorRed } if state.Item != nil { var artists []string for _, a := range state.Item.Artists { artists = append(artists, a.Name) } songList.Items = []string{ state.Item.Name, fmt.Sprintf("%s - %s", strings.Join(artists, ", "), state.Item.Album.Name), } currPosLabel.Text = durationToStr(state.Progress) totalSecLabel.Text = durationToStr(state.Item.Duration) progressGauge.Percent = progressPercent(state.Progress, state.Item.Duration) } draw() }) ui.Loop() return nil } func quitAndFatal(err error) { ui.StopLoop() ui.Close() log.Fatal(err) } func durationToStr(d int) string { sec := roundToSec(d) minInt := int(sec / 60) secInt := int(sec - float64(minInt*60)) return fmt.Sprintf("%d:%02d", minInt, secInt) } func roundToSec(d int) float64 { dur := (time.Duration(d) * time.Millisecond).Round(time.Second) return dur.Seconds() } func progressPercent(progress, total int) int { return int(roundToSec(progress) / roundToSec(total) * 100.0) } ================================================ FILE: cmd/spotctl/version.go ================================================ package main var ( version = "1.0.1" ) ================================================ FILE: vendor/github.com/golang/protobuf/.gitignore ================================================ .DS_Store *.[568ao] *.ao *.so *.pyc ._* .nfs.* [568a].out *~ *.orig core _obj _test _testmain.go protoc-gen-go/testdata/multi/*.pb.go _conformance/_conformance ================================================ FILE: vendor/github.com/golang/protobuf/.travis.yml ================================================ sudo: false language: go go: - 1.6.x - 1.7.x - 1.8.x - 1.9.x install: - go get -v -d -t github.com/golang/protobuf/... - curl -L https://github.com/google/protobuf/releases/download/v3.3.0/protoc-3.3.0-linux-x86_64.zip -o /tmp/protoc.zip - unzip /tmp/protoc.zip -d $HOME/protoc env: - PATH=$HOME/protoc/bin:$PATH script: - make all test ================================================ FILE: vendor/github.com/golang/protobuf/AUTHORS ================================================ # This source code refers to The Go Authors for copyright purposes. # The master list of authors is in the main Go distribution, # visible at http://tip.golang.org/AUTHORS. ================================================ FILE: vendor/github.com/golang/protobuf/CONTRIBUTORS ================================================ # This source code was written by the Go contributors. # The master list of contributors is in the main Go distribution, # visible at http://tip.golang.org/CONTRIBUTORS. ================================================ FILE: vendor/github.com/golang/protobuf/LICENSE ================================================ Go support for Protocol Buffers - Google's data interchange format Copyright 2010 The Go Authors. All rights reserved. https://github.com/golang/protobuf 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. ================================================ FILE: vendor/github.com/golang/protobuf/Make.protobuf ================================================ # Go support for Protocol Buffers - Google's data interchange format # # Copyright 2010 The Go Authors. All rights reserved. # https://github.com/golang/protobuf # # 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. # Includable Makefile to add a rule for generating .pb.go files from .proto files # (Google protocol buffer descriptions). # Typical use if myproto.proto is a file in package mypackage in this directory: # # include $(GOROOT)/src/pkg/github.com/golang/protobuf/Make.protobuf %.pb.go: %.proto protoc --go_out=. $< ================================================ FILE: vendor/github.com/golang/protobuf/Makefile ================================================ # Go support for Protocol Buffers - Google's data interchange format # # Copyright 2010 The Go Authors. All rights reserved. # https://github.com/golang/protobuf # # 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. all: install install: go install ./proto ./jsonpb ./ptypes go install ./protoc-gen-go test: go test ./proto ./jsonpb ./ptypes make -C protoc-gen-go/testdata test clean: go clean ./... nuke: go clean -i ./... regenerate: make -C protoc-gen-go/descriptor regenerate make -C protoc-gen-go/plugin regenerate make -C protoc-gen-go/testdata regenerate make -C proto/testdata regenerate make -C jsonpb/jsonpb_test_proto regenerate make -C _conformance regenerate ================================================ FILE: vendor/github.com/golang/protobuf/README.md ================================================ # Go support for Protocol Buffers [![Build Status](https://travis-ci.org/golang/protobuf.svg?branch=master)](https://travis-ci.org/golang/protobuf) [![GoDoc](https://godoc.org/github.com/golang/protobuf?status.svg)](https://godoc.org/github.com/golang/protobuf) Google's data interchange format. Copyright 2010 The Go Authors. https://github.com/golang/protobuf This package and the code it generates requires at least Go 1.4. This software implements Go bindings for protocol buffers. For information about protocol buffers themselves, see https://developers.google.com/protocol-buffers/ ## Installation ## To use this software, you must: - Install the standard C++ implementation of protocol buffers from https://developers.google.com/protocol-buffers/ - Of course, install the Go compiler and tools from https://golang.org/ See https://golang.org/doc/install for details or, if you are using gccgo, follow the instructions at https://golang.org/doc/install/gccgo - Grab the code from the repository and install the proto package. The simplest way is to run `go get -u github.com/golang/protobuf/protoc-gen-go`. The compiler plugin, protoc-gen-go, will be installed in $GOBIN, defaulting to $GOPATH/bin. It must be in your $PATH for the protocol compiler, protoc, to find it. This software has two parts: a 'protocol compiler plugin' that generates Go source files that, once compiled, can access and manage protocol buffers; and a library that implements run-time support for encoding (marshaling), decoding (unmarshaling), and accessing protocol buffers. There is support for gRPC in Go using protocol buffers. See the note at the bottom of this file for details. There are no insertion points in the plugin. ## Using protocol buffers with Go ## Once the software is installed, there are two steps to using it. First you must compile the protocol buffer definitions and then import them, with the support library, into your program. To compile the protocol buffer definition, run protoc with the --go_out parameter set to the directory you want to output the Go code to. protoc --go_out=. *.proto The generated files will be suffixed .pb.go. See the Test code below for an example using such a file. The package comment for the proto library contains text describing the interface provided in Go for protocol buffers. Here is an edited version. ========== The proto package converts data structures to and from the wire format of protocol buffers. It works in concert with the Go source code generated for .proto files by the protocol compiler. A summary of the properties of the protocol buffer interface for a protocol buffer variable v: - Names are turned from camel_case to CamelCase for export. - There are no methods on v to set fields; just treat them as structure fields. - There are getters that return a field's value if set, and return the field's default value if unset. The getters work even if the receiver is a nil message. - The zero value for a struct is its correct initialization state. All desired fields must be set before marshaling. - A Reset() method will restore a protobuf struct to its zero state. - Non-repeated fields are pointers to the values; nil means unset. That is, optional or required field int32 f becomes F *int32. - Repeated fields are slices. - Helper functions are available to aid the setting of fields. Helpers for getting values are superseded by the GetFoo methods and their use is deprecated. msg.Foo = proto.String("hello") // set field - Constants are defined to hold the default values of all fields that have them. They have the form Default_StructName_FieldName. Because the getter methods handle defaulted values, direct use of these constants should be rare. - Enums are given type names and maps from names to values. Enum values are prefixed with the enum's type name. Enum types have a String method, and a Enum method to assist in message construction. - Nested groups and enums have type names prefixed with the name of the surrounding message type. - Extensions are given descriptor names that start with E_, followed by an underscore-delimited list of the nested messages that contain it (if any) followed by the CamelCased name of the extension field itself. HasExtension, ClearExtension, GetExtension and SetExtension are functions for manipulating extensions. - Oneof field sets are given a single field in their message, with distinguished wrapper types for each possible field value. - Marshal and Unmarshal are functions to encode and decode the wire format. When the .proto file specifies `syntax="proto3"`, there are some differences: - Non-repeated fields of non-message type are values instead of pointers. - Enum types do not get an Enum method. Consider file test.proto, containing ```proto syntax = "proto2"; package example; enum FOO { X = 17; }; message Test { required string label = 1; optional int32 type = 2 [default=77]; repeated int64 reps = 3; optional group OptionalGroup = 4 { required string RequiredField = 5; } } ``` To create and play with a Test object from the example package, ```go package main import ( "log" "github.com/golang/protobuf/proto" "path/to/example" ) func main() { test := &example.Test { Label: proto.String("hello"), Type: proto.Int32(17), Reps: []int64{1, 2, 3}, Optionalgroup: &example.Test_OptionalGroup { RequiredField: proto.String("good bye"), }, } data, err := proto.Marshal(test) if err != nil { log.Fatal("marshaling error: ", err) } newTest := &example.Test{} err = proto.Unmarshal(data, newTest) if err != nil { log.Fatal("unmarshaling error: ", err) } // Now test and newTest contain the same data. if test.GetLabel() != newTest.GetLabel() { log.Fatalf("data mismatch %q != %q", test.GetLabel(), newTest.GetLabel()) } // etc. } ``` ## Parameters ## To pass extra parameters to the plugin, use a comma-separated parameter list separated from the output directory by a colon: protoc --go_out=plugins=grpc,import_path=mypackage:. *.proto - `import_prefix=xxx` - a prefix that is added onto the beginning of all imports. Useful for things like generating protos in a subdirectory, or regenerating vendored protobufs in-place. - `import_path=foo/bar` - used as the package if no input files declare `go_package`. If it contains slashes, everything up to the rightmost slash is ignored. - `plugins=plugin1+plugin2` - specifies the list of sub-plugins to load. The only plugin in this repo is `grpc`. - `Mfoo/bar.proto=quux/shme` - declares that foo/bar.proto is associated with Go package quux/shme. This is subject to the import_prefix parameter. ## gRPC Support ## If a proto file specifies RPC services, protoc-gen-go can be instructed to generate code compatible with gRPC (http://www.grpc.io/). To do this, pass the `plugins` parameter to protoc-gen-go; the usual way is to insert it into the --go_out argument to protoc: protoc --go_out=plugins=grpc:. *.proto ## Compatibility ## The library and the generated code are expected to be stable over time. However, we reserve the right to make breaking changes without notice for the following reasons: - Security. A security issue in the specification or implementation may come to light whose resolution requires breaking compatibility. We reserve the right to address such security issues. - Unspecified behavior. There are some aspects of the Protocol Buffers specification that are undefined. Programs that depend on such unspecified behavior may break in future releases. - Specification errors or changes. If it becomes necessary to address an inconsistency, incompleteness, or change in the Protocol Buffers specification, resolving the issue could affect the meaning or legality of existing programs. We reserve the right to address such issues, including updating the implementations. - Bugs. If the library has a bug that violates the specification, a program that depends on the buggy behavior may break if the bug is fixed. We reserve the right to fix such bugs. - Adding methods or fields to generated structs. These may conflict with field names that already exist in a schema, causing applications to break. When the code generator encounters a field in the schema that would collide with a generated field or method name, the code generator will append an underscore to the generated field or method name. - Adding, removing, or changing methods or fields in generated structs that start with `XXX`. These parts of the generated code are exported out of necessity, but should not be considered part of the public API. - Adding, removing, or changing unexported symbols in generated code. Any breaking changes outside of these will be announced 6 months in advance to protobuf@googlegroups.com. You should, whenever possible, use generated code created by the `protoc-gen-go` tool built at the same commit as the `proto` package. The `proto` package declares package-level constants in the form `ProtoPackageIsVersionX`. Application code and generated code may depend on one of these constants to ensure that compilation will fail if the available version of the proto library is too old. Whenever we make a change to the generated code that requires newer library support, in the same commit we will increment the version number of the generated code and declare a new package-level constant whose name incorporates the latest version number. Removing a compatibility constant is considered a breaking change and would be subject to the announcement policy stated above. The `protoc-gen-go/generator` package exposes a plugin interface, which is used by the gRPC code generation. This interface is not supported and is subject to incompatible changes without notice. ================================================ FILE: vendor/github.com/golang/protobuf/proto/Makefile ================================================ # Go support for Protocol Buffers - Google's data interchange format # # Copyright 2010 The Go Authors. All rights reserved. # https://github.com/golang/protobuf # # 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. install: go install test: install generate-test-pbs go test generate-test-pbs: make install make -C testdata protoc --go_out=Mtestdata/test.proto=github.com/golang/protobuf/proto/testdata,Mgoogle/protobuf/any.proto=github.com/golang/protobuf/ptypes/any:. proto3_proto/proto3.proto make ================================================ FILE: vendor/github.com/golang/protobuf/proto/all_test.go ================================================ // Go support for Protocol Buffers - Google's data interchange format // // Copyright 2010 The Go Authors. All rights reserved. // https://github.com/golang/protobuf // // 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. package proto_test import ( "bytes" "encoding/json" "errors" "fmt" "math" "math/rand" "reflect" "runtime/debug" "strings" "testing" "time" . "github.com/golang/protobuf/proto" . "github.com/golang/protobuf/proto/testdata" ) var globalO *Buffer func old() *Buffer { if globalO == nil { globalO = NewBuffer(nil) } globalO.Reset() return globalO } func equalbytes(b1, b2 []byte, t *testing.T) { if len(b1) != len(b2) { t.Errorf("wrong lengths: 2*%d != %d", len(b1), len(b2)) return } for i := 0; i < len(b1); i++ { if b1[i] != b2[i] { t.Errorf("bad byte[%d]:%x %x: %s %s", i, b1[i], b2[i], b1, b2) } } } func initGoTestField() *GoTestField { f := new(GoTestField) f.Label = String("label") f.Type = String("type") return f } // These are all structurally equivalent but the tag numbers differ. // (It's remarkable that required, optional, and repeated all have // 8 letters.) func initGoTest_RequiredGroup() *GoTest_RequiredGroup { return &GoTest_RequiredGroup{ RequiredField: String("required"), } } func initGoTest_OptionalGroup() *GoTest_OptionalGroup { return &GoTest_OptionalGroup{ RequiredField: String("optional"), } } func initGoTest_RepeatedGroup() *GoTest_RepeatedGroup { return &GoTest_RepeatedGroup{ RequiredField: String("repeated"), } } func initGoTest(setdefaults bool) *GoTest { pb := new(GoTest) if setdefaults { pb.F_BoolDefaulted = Bool(Default_GoTest_F_BoolDefaulted) pb.F_Int32Defaulted = Int32(Default_GoTest_F_Int32Defaulted) pb.F_Int64Defaulted = Int64(Default_GoTest_F_Int64Defaulted) pb.F_Fixed32Defaulted = Uint32(Default_GoTest_F_Fixed32Defaulted) pb.F_Fixed64Defaulted = Uint64(Default_GoTest_F_Fixed64Defaulted) pb.F_Uint32Defaulted = Uint32(Default_GoTest_F_Uint32Defaulted) pb.F_Uint64Defaulted = Uint64(Default_GoTest_F_Uint64Defaulted) pb.F_FloatDefaulted = Float32(Default_GoTest_F_FloatDefaulted) pb.F_DoubleDefaulted = Float64(Default_GoTest_F_DoubleDefaulted) pb.F_StringDefaulted = String(Default_GoTest_F_StringDefaulted) pb.F_BytesDefaulted = Default_GoTest_F_BytesDefaulted pb.F_Sint32Defaulted = Int32(Default_GoTest_F_Sint32Defaulted) pb.F_Sint64Defaulted = Int64(Default_GoTest_F_Sint64Defaulted) } pb.Kind = GoTest_TIME.Enum() pb.RequiredField = initGoTestField() pb.F_BoolRequired = Bool(true) pb.F_Int32Required = Int32(3) pb.F_Int64Required = Int64(6) pb.F_Fixed32Required = Uint32(32) pb.F_Fixed64Required = Uint64(64) pb.F_Uint32Required = Uint32(3232) pb.F_Uint64Required = Uint64(6464) pb.F_FloatRequired = Float32(3232) pb.F_DoubleRequired = Float64(6464) pb.F_StringRequired = String("string") pb.F_BytesRequired = []byte("bytes") pb.F_Sint32Required = Int32(-32) pb.F_Sint64Required = Int64(-64) pb.Requiredgroup = initGoTest_RequiredGroup() return pb } func fail(msg string, b *bytes.Buffer, s string, t *testing.T) { data := b.Bytes() ld := len(data) ls := len(s) / 2 fmt.Printf("fail %s ld=%d ls=%d\n", msg, ld, ls) // find the interesting spot - n n := ls if ld < ls { n = ld } j := 0 for i := 0; i < n; i++ { bs := hex(s[j])*16 + hex(s[j+1]) j += 2 if data[i] == bs { continue } n = i break } l := n - 10 if l < 0 { l = 0 } h := n + 10 // find the interesting spot - n fmt.Printf("is[%d]:", l) for i := l; i < h; i++ { if i >= ld { fmt.Printf(" --") continue } fmt.Printf(" %.2x", data[i]) } fmt.Printf("\n") fmt.Printf("sb[%d]:", l) for i := l; i < h; i++ { if i >= ls { fmt.Printf(" --") continue } bs := hex(s[j])*16 + hex(s[j+1]) j += 2 fmt.Printf(" %.2x", bs) } fmt.Printf("\n") t.Fail() // t.Errorf("%s: \ngood: %s\nbad: %x", msg, s, b.Bytes()) // Print the output in a partially-decoded format; can // be helpful when updating the test. It produces the output // that is pasted, with minor edits, into the argument to verify(). // data := b.Bytes() // nesting := 0 // for b.Len() > 0 { // start := len(data) - b.Len() // var u uint64 // u, err := DecodeVarint(b) // if err != nil { // fmt.Printf("decode error on varint:", err) // return // } // wire := u & 0x7 // tag := u >> 3 // switch wire { // case WireVarint: // v, err := DecodeVarint(b) // if err != nil { // fmt.Printf("decode error on varint:", err) // return // } // fmt.Printf("\t\t\"%x\" // field %d, encoding %d, value %d\n", // data[start:len(data)-b.Len()], tag, wire, v) // case WireFixed32: // v, err := DecodeFixed32(b) // if err != nil { // fmt.Printf("decode error on fixed32:", err) // return // } // fmt.Printf("\t\t\"%x\" // field %d, encoding %d, value %d\n", // data[start:len(data)-b.Len()], tag, wire, v) // case WireFixed64: // v, err := DecodeFixed64(b) // if err != nil { // fmt.Printf("decode error on fixed64:", err) // return // } // fmt.Printf("\t\t\"%x\" // field %d, encoding %d, value %d\n", // data[start:len(data)-b.Len()], tag, wire, v) // case WireBytes: // nb, err := DecodeVarint(b) // if err != nil { // fmt.Printf("decode error on bytes:", err) // return // } // after_tag := len(data) - b.Len() // str := make([]byte, nb) // _, err = b.Read(str) // if err != nil { // fmt.Printf("decode error on bytes:", err) // return // } // fmt.Printf("\t\t\"%x\" \"%x\" // field %d, encoding %d (FIELD)\n", // data[start:after_tag], str, tag, wire) // case WireStartGroup: // nesting++ // fmt.Printf("\t\t\"%x\"\t\t// start group field %d level %d\n", // data[start:len(data)-b.Len()], tag, nesting) // case WireEndGroup: // fmt.Printf("\t\t\"%x\"\t\t// end group field %d level %d\n", // data[start:len(data)-b.Len()], tag, nesting) // nesting-- // default: // fmt.Printf("unrecognized wire type %d\n", wire) // return // } // } } func hex(c uint8) uint8 { if '0' <= c && c <= '9' { return c - '0' } if 'a' <= c && c <= 'f' { return 10 + c - 'a' } if 'A' <= c && c <= 'F' { return 10 + c - 'A' } return 0 } func equal(b []byte, s string, t *testing.T) bool { if 2*len(b) != len(s) { // fail(fmt.Sprintf("wrong lengths: 2*%d != %d", len(b), len(s)), b, s, t) fmt.Printf("wrong lengths: 2*%d != %d\n", len(b), len(s)) return false } for i, j := 0, 0; i < len(b); i, j = i+1, j+2 { x := hex(s[j])*16 + hex(s[j+1]) if b[i] != x { // fail(fmt.Sprintf("bad byte[%d]:%x %x", i, b[i], x), b, s, t) fmt.Printf("bad byte[%d]:%x %x", i, b[i], x) return false } } return true } func overify(t *testing.T, pb *GoTest, expected string) { o := old() err := o.Marshal(pb) if err != nil { fmt.Printf("overify marshal-1 err = %v", err) o.DebugPrint("", o.Bytes()) t.Fatalf("expected = %s", expected) } if !equal(o.Bytes(), expected, t) { o.DebugPrint("overify neq 1", o.Bytes()) t.Fatalf("expected = %s", expected) } // Now test Unmarshal by recreating the original buffer. pbd := new(GoTest) err = o.Unmarshal(pbd) if err != nil { t.Fatalf("overify unmarshal err = %v", err) o.DebugPrint("", o.Bytes()) t.Fatalf("string = %s", expected) } o.Reset() err = o.Marshal(pbd) if err != nil { t.Errorf("overify marshal-2 err = %v", err) o.DebugPrint("", o.Bytes()) t.Fatalf("string = %s", expected) } if !equal(o.Bytes(), expected, t) { o.DebugPrint("overify neq 2", o.Bytes()) t.Fatalf("string = %s", expected) } } // Simple tests for numeric encode/decode primitives (varint, etc.) func TestNumericPrimitives(t *testing.T) { for i := uint64(0); i < 1e6; i += 111 { o := old() if o.EncodeVarint(i) != nil { t.Error("EncodeVarint") break } x, e := o.DecodeVarint() if e != nil { t.Fatal("DecodeVarint") } if x != i { t.Fatal("varint decode fail:", i, x) } o = old() if o.EncodeFixed32(i) != nil { t.Fatal("encFixed32") } x, e = o.DecodeFixed32() if e != nil { t.Fatal("decFixed32") } if x != i { t.Fatal("fixed32 decode fail:", i, x) } o = old() if o.EncodeFixed64(i*1234567) != nil { t.Error("encFixed64") break } x, e = o.DecodeFixed64() if e != nil { t.Error("decFixed64") break } if x != i*1234567 { t.Error("fixed64 decode fail:", i*1234567, x) break } o = old() i32 := int32(i - 12345) if o.EncodeZigzag32(uint64(i32)) != nil { t.Fatal("EncodeZigzag32") } x, e = o.DecodeZigzag32() if e != nil { t.Fatal("DecodeZigzag32") } if x != uint64(uint32(i32)) { t.Fatal("zigzag32 decode fail:", i32, x) } o = old() i64 := int64(i - 12345) if o.EncodeZigzag64(uint64(i64)) != nil { t.Fatal("EncodeZigzag64") } x, e = o.DecodeZigzag64() if e != nil { t.Fatal("DecodeZigzag64") } if x != uint64(i64) { t.Fatal("zigzag64 decode fail:", i64, x) } } } // fakeMarshaler is a simple struct implementing Marshaler and Message interfaces. type fakeMarshaler struct { b []byte err error } func (f *fakeMarshaler) Marshal() ([]byte, error) { return f.b, f.err } func (f *fakeMarshaler) String() string { return fmt.Sprintf("Bytes: %v Error: %v", f.b, f.err) } func (f *fakeMarshaler) ProtoMessage() {} func (f *fakeMarshaler) Reset() {} type msgWithFakeMarshaler struct { M *fakeMarshaler `protobuf:"bytes,1,opt,name=fake"` } func (m *msgWithFakeMarshaler) String() string { return CompactTextString(m) } func (m *msgWithFakeMarshaler) ProtoMessage() {} func (m *msgWithFakeMarshaler) Reset() {} // Simple tests for proto messages that implement the Marshaler interface. func TestMarshalerEncoding(t *testing.T) { tests := []struct { name string m Message want []byte errType reflect.Type }{ { name: "Marshaler that fails", m: &fakeMarshaler{ err: errors.New("some marshal err"), b: []byte{5, 6, 7}, }, // Since the Marshal method returned bytes, they should be written to the // buffer. (For efficiency, we assume that Marshal implementations are // always correct w.r.t. RequiredNotSetError and output.) want: []byte{5, 6, 7}, errType: reflect.TypeOf(errors.New("some marshal err")), }, { name: "Marshaler that fails with RequiredNotSetError", m: &msgWithFakeMarshaler{ M: &fakeMarshaler{ err: &RequiredNotSetError{}, b: []byte{5, 6, 7}, }, }, // Since there's an error that can be continued after, // the buffer should be written. want: []byte{ 10, 3, // for &msgWithFakeMarshaler 5, 6, 7, // for &fakeMarshaler }, errType: reflect.TypeOf(&RequiredNotSetError{}), }, { name: "Marshaler that succeeds", m: &fakeMarshaler{ b: []byte{0, 1, 2, 3, 4, 127, 255}, }, want: []byte{0, 1, 2, 3, 4, 127, 255}, }, } for _, test := range tests { b := NewBuffer(nil) err := b.Marshal(test.m) if reflect.TypeOf(err) != test.errType { t.Errorf("%s: got err %T(%v) wanted %T", test.name, err, err, test.errType) } if !reflect.DeepEqual(test.want, b.Bytes()) { t.Errorf("%s: got bytes %v wanted %v", test.name, b.Bytes(), test.want) } if size := Size(test.m); size != len(b.Bytes()) { t.Errorf("%s: Size(_) = %v, but marshaled to %v bytes", test.name, size, len(b.Bytes())) } m, mErr := Marshal(test.m) if !bytes.Equal(b.Bytes(), m) { t.Errorf("%s: Marshal returned %v, but (*Buffer).Marshal wrote %v", test.name, m, b.Bytes()) } if !reflect.DeepEqual(err, mErr) { t.Errorf("%s: Marshal err = %q, but (*Buffer).Marshal returned %q", test.name, fmt.Sprint(mErr), fmt.Sprint(err)) } } } // Simple tests for bytes func TestBytesPrimitives(t *testing.T) { o := old() bytes := []byte{'n', 'o', 'w', ' ', 'i', 's', ' ', 't', 'h', 'e', ' ', 't', 'i', 'm', 'e'} if o.EncodeRawBytes(bytes) != nil { t.Error("EncodeRawBytes") } decb, e := o.DecodeRawBytes(false) if e != nil { t.Error("DecodeRawBytes") } equalbytes(bytes, decb, t) } // Simple tests for strings func TestStringPrimitives(t *testing.T) { o := old() s := "now is the time" if o.EncodeStringBytes(s) != nil { t.Error("enc_string") } decs, e := o.DecodeStringBytes() if e != nil { t.Error("dec_string") } if s != decs { t.Error("string encode/decode fail:", s, decs) } } // Do we catch the "required bit not set" case? func TestRequiredBit(t *testing.T) { o := old() pb := new(GoTest) err := o.Marshal(pb) if err == nil { t.Error("did not catch missing required fields") } else if strings.Index(err.Error(), "Kind") < 0 { t.Error("wrong error type:", err) } } // Check that all fields are nil. // Clearly silly, and a residue from a more interesting test with an earlier, // different initialization property, but it once caught a compiler bug so // it lives. func checkInitialized(pb *GoTest, t *testing.T) { if pb.F_BoolDefaulted != nil { t.Error("New or Reset did not set boolean:", *pb.F_BoolDefaulted) } if pb.F_Int32Defaulted != nil { t.Error("New or Reset did not set int32:", *pb.F_Int32Defaulted) } if pb.F_Int64Defaulted != nil { t.Error("New or Reset did not set int64:", *pb.F_Int64Defaulted) } if pb.F_Fixed32Defaulted != nil { t.Error("New or Reset did not set fixed32:", *pb.F_Fixed32Defaulted) } if pb.F_Fixed64Defaulted != nil { t.Error("New or Reset did not set fixed64:", *pb.F_Fixed64Defaulted) } if pb.F_Uint32Defaulted != nil { t.Error("New or Reset did not set uint32:", *pb.F_Uint32Defaulted) } if pb.F_Uint64Defaulted != nil { t.Error("New or Reset did not set uint64:", *pb.F_Uint64Defaulted) } if pb.F_FloatDefaulted != nil { t.Error("New or Reset did not set float:", *pb.F_FloatDefaulted) } if pb.F_DoubleDefaulted != nil { t.Error("New or Reset did not set double:", *pb.F_DoubleDefaulted) } if pb.F_StringDefaulted != nil { t.Error("New or Reset did not set string:", *pb.F_StringDefaulted) } if pb.F_BytesDefaulted != nil { t.Error("New or Reset did not set bytes:", string(pb.F_BytesDefaulted)) } if pb.F_Sint32Defaulted != nil { t.Error("New or Reset did not set int32:", *pb.F_Sint32Defaulted) } if pb.F_Sint64Defaulted != nil { t.Error("New or Reset did not set int64:", *pb.F_Sint64Defaulted) } } // Does Reset() reset? func TestReset(t *testing.T) { pb := initGoTest(true) // muck with some values pb.F_BoolDefaulted = Bool(false) pb.F_Int32Defaulted = Int32(237) pb.F_Int64Defaulted = Int64(12346) pb.F_Fixed32Defaulted = Uint32(32000) pb.F_Fixed64Defaulted = Uint64(666) pb.F_Uint32Defaulted = Uint32(323232) pb.F_Uint64Defaulted = nil pb.F_FloatDefaulted = nil pb.F_DoubleDefaulted = Float64(0) pb.F_StringDefaulted = String("gotcha") pb.F_BytesDefaulted = []byte("asdfasdf") pb.F_Sint32Defaulted = Int32(123) pb.F_Sint64Defaulted = Int64(789) pb.Reset() checkInitialized(pb, t) } // All required fields set, no defaults provided. func TestEncodeDecode1(t *testing.T) { pb := initGoTest(false) overify(t, pb, "0807"+ // field 1, encoding 0, value 7 "220d"+"0a056c6162656c120474797065"+ // field 4, encoding 2 (GoTestField) "5001"+ // field 10, encoding 0, value 1 "5803"+ // field 11, encoding 0, value 3 "6006"+ // field 12, encoding 0, value 6 "6d20000000"+ // field 13, encoding 5, value 0x20 "714000000000000000"+ // field 14, encoding 1, value 0x40 "78a019"+ // field 15, encoding 0, value 0xca0 = 3232 "8001c032"+ // field 16, encoding 0, value 0x1940 = 6464 "8d0100004a45"+ // field 17, encoding 5, value 3232.0 "9101000000000040b940"+ // field 18, encoding 1, value 6464.0 "9a0106"+"737472696e67"+ // field 19, encoding 2, string "string" "b304"+ // field 70, encoding 3, start group "ba0408"+"7265717569726564"+ // field 71, encoding 2, string "required" "b404"+ // field 70, encoding 4, end group "aa0605"+"6279746573"+ // field 101, encoding 2, string "bytes" "b0063f"+ // field 102, encoding 0, 0x3f zigzag32 "b8067f") // field 103, encoding 0, 0x7f zigzag64 } // All required fields set, defaults provided. func TestEncodeDecode2(t *testing.T) { pb := initGoTest(true) overify(t, pb, "0807"+ // field 1, encoding 0, value 7 "220d"+"0a056c6162656c120474797065"+ // field 4, encoding 2 (GoTestField) "5001"+ // field 10, encoding 0, value 1 "5803"+ // field 11, encoding 0, value 3 "6006"+ // field 12, encoding 0, value 6 "6d20000000"+ // field 13, encoding 5, value 32 "714000000000000000"+ // field 14, encoding 1, value 64 "78a019"+ // field 15, encoding 0, value 3232 "8001c032"+ // field 16, encoding 0, value 6464 "8d0100004a45"+ // field 17, encoding 5, value 3232.0 "9101000000000040b940"+ // field 18, encoding 1, value 6464.0 "9a0106"+"737472696e67"+ // field 19, encoding 2 string "string" "c00201"+ // field 40, encoding 0, value 1 "c80220"+ // field 41, encoding 0, value 32 "d00240"+ // field 42, encoding 0, value 64 "dd0240010000"+ // field 43, encoding 5, value 320 "e1028002000000000000"+ // field 44, encoding 1, value 640 "e8028019"+ // field 45, encoding 0, value 3200 "f0028032"+ // field 46, encoding 0, value 6400 "fd02e0659948"+ // field 47, encoding 5, value 314159.0 "81030000000050971041"+ // field 48, encoding 1, value 271828.0 "8a0310"+"68656c6c6f2c2022776f726c6421220a"+ // field 49, encoding 2 string "hello, \"world!\"\n" "b304"+ // start group field 70 level 1 "ba0408"+"7265717569726564"+ // field 71, encoding 2, string "required" "b404"+ // end group field 70 level 1 "aa0605"+"6279746573"+ // field 101, encoding 2 string "bytes" "b0063f"+ // field 102, encoding 0, 0x3f zigzag32 "b8067f"+ // field 103, encoding 0, 0x7f zigzag64 "8a1907"+"4269676e6f7365"+ // field 401, encoding 2, string "Bignose" "90193f"+ // field 402, encoding 0, value 63 "98197f") // field 403, encoding 0, value 127 } // All default fields set to their default value by hand func TestEncodeDecode3(t *testing.T) { pb := initGoTest(false) pb.F_BoolDefaulted = Bool(true) pb.F_Int32Defaulted = Int32(32) pb.F_Int64Defaulted = Int64(64) pb.F_Fixed32Defaulted = Uint32(320) pb.F_Fixed64Defaulted = Uint64(640) pb.F_Uint32Defaulted = Uint32(3200) pb.F_Uint64Defaulted = Uint64(6400) pb.F_FloatDefaulted = Float32(314159) pb.F_DoubleDefaulted = Float64(271828) pb.F_StringDefaulted = String("hello, \"world!\"\n") pb.F_BytesDefaulted = []byte("Bignose") pb.F_Sint32Defaulted = Int32(-32) pb.F_Sint64Defaulted = Int64(-64) overify(t, pb, "0807"+ // field 1, encoding 0, value 7 "220d"+"0a056c6162656c120474797065"+ // field 4, encoding 2 (GoTestField) "5001"+ // field 10, encoding 0, value 1 "5803"+ // field 11, encoding 0, value 3 "6006"+ // field 12, encoding 0, value 6 "6d20000000"+ // field 13, encoding 5, value 32 "714000000000000000"+ // field 14, encoding 1, value 64 "78a019"+ // field 15, encoding 0, value 3232 "8001c032"+ // field 16, encoding 0, value 6464 "8d0100004a45"+ // field 17, encoding 5, value 3232.0 "9101000000000040b940"+ // field 18, encoding 1, value 6464.0 "9a0106"+"737472696e67"+ // field 19, encoding 2 string "string" "c00201"+ // field 40, encoding 0, value 1 "c80220"+ // field 41, encoding 0, value 32 "d00240"+ // field 42, encoding 0, value 64 "dd0240010000"+ // field 43, encoding 5, value 320 "e1028002000000000000"+ // field 44, encoding 1, value 640 "e8028019"+ // field 45, encoding 0, value 3200 "f0028032"+ // field 46, encoding 0, value 6400 "fd02e0659948"+ // field 47, encoding 5, value 314159.0 "81030000000050971041"+ // field 48, encoding 1, value 271828.0 "8a0310"+"68656c6c6f2c2022776f726c6421220a"+ // field 49, encoding 2 string "hello, \"world!\"\n" "b304"+ // start group field 70 level 1 "ba0408"+"7265717569726564"+ // field 71, encoding 2, string "required" "b404"+ // end group field 70 level 1 "aa0605"+"6279746573"+ // field 101, encoding 2 string "bytes" "b0063f"+ // field 102, encoding 0, 0x3f zigzag32 "b8067f"+ // field 103, encoding 0, 0x7f zigzag64 "8a1907"+"4269676e6f7365"+ // field 401, encoding 2, string "Bignose" "90193f"+ // field 402, encoding 0, value 63 "98197f") // field 403, encoding 0, value 127 } // All required fields set, defaults provided, all non-defaulted optional fields have values. func TestEncodeDecode4(t *testing.T) { pb := initGoTest(true) pb.Table = String("hello") pb.Param = Int32(7) pb.OptionalField = initGoTestField() pb.F_BoolOptional = Bool(true) pb.F_Int32Optional = Int32(32) pb.F_Int64Optional = Int64(64) pb.F_Fixed32Optional = Uint32(3232) pb.F_Fixed64Optional = Uint64(6464) pb.F_Uint32Optional = Uint32(323232) pb.F_Uint64Optional = Uint64(646464) pb.F_FloatOptional = Float32(32.) pb.F_DoubleOptional = Float64(64.) pb.F_StringOptional = String("hello") pb.F_BytesOptional = []byte("Bignose") pb.F_Sint32Optional = Int32(-32) pb.F_Sint64Optional = Int64(-64) pb.Optionalgroup = initGoTest_OptionalGroup() overify(t, pb, "0807"+ // field 1, encoding 0, value 7 "1205"+"68656c6c6f"+ // field 2, encoding 2, string "hello" "1807"+ // field 3, encoding 0, value 7 "220d"+"0a056c6162656c120474797065"+ // field 4, encoding 2 (GoTestField) "320d"+"0a056c6162656c120474797065"+ // field 6, encoding 2 (GoTestField) "5001"+ // field 10, encoding 0, value 1 "5803"+ // field 11, encoding 0, value 3 "6006"+ // field 12, encoding 0, value 6 "6d20000000"+ // field 13, encoding 5, value 32 "714000000000000000"+ // field 14, encoding 1, value 64 "78a019"+ // field 15, encoding 0, value 3232 "8001c032"+ // field 16, encoding 0, value 6464 "8d0100004a45"+ // field 17, encoding 5, value 3232.0 "9101000000000040b940"+ // field 18, encoding 1, value 6464.0 "9a0106"+"737472696e67"+ // field 19, encoding 2 string "string" "f00101"+ // field 30, encoding 0, value 1 "f80120"+ // field 31, encoding 0, value 32 "800240"+ // field 32, encoding 0, value 64 "8d02a00c0000"+ // field 33, encoding 5, value 3232 "91024019000000000000"+ // field 34, encoding 1, value 6464 "9802a0dd13"+ // field 35, encoding 0, value 323232 "a002c0ba27"+ // field 36, encoding 0, value 646464 "ad0200000042"+ // field 37, encoding 5, value 32.0 "b1020000000000005040"+ // field 38, encoding 1, value 64.0 "ba0205"+"68656c6c6f"+ // field 39, encoding 2, string "hello" "c00201"+ // field 40, encoding 0, value 1 "c80220"+ // field 41, encoding 0, value 32 "d00240"+ // field 42, encoding 0, value 64 "dd0240010000"+ // field 43, encoding 5, value 320 "e1028002000000000000"+ // field 44, encoding 1, value 640 "e8028019"+ // field 45, encoding 0, value 3200 "f0028032"+ // field 46, encoding 0, value 6400 "fd02e0659948"+ // field 47, encoding 5, value 314159.0 "81030000000050971041"+ // field 48, encoding 1, value 271828.0 "8a0310"+"68656c6c6f2c2022776f726c6421220a"+ // field 49, encoding 2 string "hello, \"world!\"\n" "b304"+ // start group field 70 level 1 "ba0408"+"7265717569726564"+ // field 71, encoding 2, string "required" "b404"+ // end group field 70 level 1 "d305"+ // start group field 90 level 1 "da0508"+"6f7074696f6e616c"+ // field 91, encoding 2, string "optional" "d405"+ // end group field 90 level 1 "aa0605"+"6279746573"+ // field 101, encoding 2 string "bytes" "b0063f"+ // field 102, encoding 0, 0x3f zigzag32 "b8067f"+ // field 103, encoding 0, 0x7f zigzag64 "ea1207"+"4269676e6f7365"+ // field 301, encoding 2, string "Bignose" "f0123f"+ // field 302, encoding 0, value 63 "f8127f"+ // field 303, encoding 0, value 127 "8a1907"+"4269676e6f7365"+ // field 401, encoding 2, string "Bignose" "90193f"+ // field 402, encoding 0, value 63 "98197f") // field 403, encoding 0, value 127 } // All required fields set, defaults provided, all repeated fields given two values. func TestEncodeDecode5(t *testing.T) { pb := initGoTest(true) pb.RepeatedField = []*GoTestField{initGoTestField(), initGoTestField()} pb.F_BoolRepeated = []bool{false, true} pb.F_Int32Repeated = []int32{32, 33} pb.F_Int64Repeated = []int64{64, 65} pb.F_Fixed32Repeated = []uint32{3232, 3333} pb.F_Fixed64Repeated = []uint64{6464, 6565} pb.F_Uint32Repeated = []uint32{323232, 333333} pb.F_Uint64Repeated = []uint64{646464, 656565} pb.F_FloatRepeated = []float32{32., 33.} pb.F_DoubleRepeated = []float64{64., 65.} pb.F_StringRepeated = []string{"hello", "sailor"} pb.F_BytesRepeated = [][]byte{[]byte("big"), []byte("nose")} pb.F_Sint32Repeated = []int32{32, -32} pb.F_Sint64Repeated = []int64{64, -64} pb.Repeatedgroup = []*GoTest_RepeatedGroup{initGoTest_RepeatedGroup(), initGoTest_RepeatedGroup()} overify(t, pb, "0807"+ // field 1, encoding 0, value 7 "220d"+"0a056c6162656c120474797065"+ // field 4, encoding 2 (GoTestField) "2a0d"+"0a056c6162656c120474797065"+ // field 5, encoding 2 (GoTestField) "2a0d"+"0a056c6162656c120474797065"+ // field 5, encoding 2 (GoTestField) "5001"+ // field 10, encoding 0, value 1 "5803"+ // field 11, encoding 0, value 3 "6006"+ // field 12, encoding 0, value 6 "6d20000000"+ // field 13, encoding 5, value 32 "714000000000000000"+ // field 14, encoding 1, value 64 "78a019"+ // field 15, encoding 0, value 3232 "8001c032"+ // field 16, encoding 0, value 6464 "8d0100004a45"+ // field 17, encoding 5, value 3232.0 "9101000000000040b940"+ // field 18, encoding 1, value 6464.0 "9a0106"+"737472696e67"+ // field 19, encoding 2 string "string" "a00100"+ // field 20, encoding 0, value 0 "a00101"+ // field 20, encoding 0, value 1 "a80120"+ // field 21, encoding 0, value 32 "a80121"+ // field 21, encoding 0, value 33 "b00140"+ // field 22, encoding 0, value 64 "b00141"+ // field 22, encoding 0, value 65 "bd01a00c0000"+ // field 23, encoding 5, value 3232 "bd01050d0000"+ // field 23, encoding 5, value 3333 "c1014019000000000000"+ // field 24, encoding 1, value 6464 "c101a519000000000000"+ // field 24, encoding 1, value 6565 "c801a0dd13"+ // field 25, encoding 0, value 323232 "c80195ac14"+ // field 25, encoding 0, value 333333 "d001c0ba27"+ // field 26, encoding 0, value 646464 "d001b58928"+ // field 26, encoding 0, value 656565 "dd0100000042"+ // field 27, encoding 5, value 32.0 "dd0100000442"+ // field 27, encoding 5, value 33.0 "e1010000000000005040"+ // field 28, encoding 1, value 64.0 "e1010000000000405040"+ // field 28, encoding 1, value 65.0 "ea0105"+"68656c6c6f"+ // field 29, encoding 2, string "hello" "ea0106"+"7361696c6f72"+ // field 29, encoding 2, string "sailor" "c00201"+ // field 40, encoding 0, value 1 "c80220"+ // field 41, encoding 0, value 32 "d00240"+ // field 42, encoding 0, value 64 "dd0240010000"+ // field 43, encoding 5, value 320 "e1028002000000000000"+ // field 44, encoding 1, value 640 "e8028019"+ // field 45, encoding 0, value 3200 "f0028032"+ // field 46, encoding 0, value 6400 "fd02e0659948"+ // field 47, encoding 5, value 314159.0 "81030000000050971041"+ // field 48, encoding 1, value 271828.0 "8a0310"+"68656c6c6f2c2022776f726c6421220a"+ // field 49, encoding 2 string "hello, \"world!\"\n" "b304"+ // start group field 70 level 1 "ba0408"+"7265717569726564"+ // field 71, encoding 2, string "required" "b404"+ // end group field 70 level 1 "8305"+ // start group field 80 level 1 "8a0508"+"7265706561746564"+ // field 81, encoding 2, string "repeated" "8405"+ // end group field 80 level 1 "8305"+ // start group field 80 level 1 "8a0508"+"7265706561746564"+ // field 81, encoding 2, string "repeated" "8405"+ // end group field 80 level 1 "aa0605"+"6279746573"+ // field 101, encoding 2 string "bytes" "b0063f"+ // field 102, encoding 0, 0x3f zigzag32 "b8067f"+ // field 103, encoding 0, 0x7f zigzag64 "ca0c03"+"626967"+ // field 201, encoding 2, string "big" "ca0c04"+"6e6f7365"+ // field 201, encoding 2, string "nose" "d00c40"+ // field 202, encoding 0, value 32 "d00c3f"+ // field 202, encoding 0, value -32 "d80c8001"+ // field 203, encoding 0, value 64 "d80c7f"+ // field 203, encoding 0, value -64 "8a1907"+"4269676e6f7365"+ // field 401, encoding 2, string "Bignose" "90193f"+ // field 402, encoding 0, value 63 "98197f") // field 403, encoding 0, value 127 } // All required fields set, all packed repeated fields given two values. func TestEncodeDecode6(t *testing.T) { pb := initGoTest(false) pb.F_BoolRepeatedPacked = []bool{false, true} pb.F_Int32RepeatedPacked = []int32{32, 33} pb.F_Int64RepeatedPacked = []int64{64, 65} pb.F_Fixed32RepeatedPacked = []uint32{3232, 3333} pb.F_Fixed64RepeatedPacked = []uint64{6464, 6565} pb.F_Uint32RepeatedPacked = []uint32{323232, 333333} pb.F_Uint64RepeatedPacked = []uint64{646464, 656565} pb.F_FloatRepeatedPacked = []float32{32., 33.} pb.F_DoubleRepeatedPacked = []float64{64., 65.} pb.F_Sint32RepeatedPacked = []int32{32, -32} pb.F_Sint64RepeatedPacked = []int64{64, -64} overify(t, pb, "0807"+ // field 1, encoding 0, value 7 "220d"+"0a056c6162656c120474797065"+ // field 4, encoding 2 (GoTestField) "5001"+ // field 10, encoding 0, value 1 "5803"+ // field 11, encoding 0, value 3 "6006"+ // field 12, encoding 0, value 6 "6d20000000"+ // field 13, encoding 5, value 32 "714000000000000000"+ // field 14, encoding 1, value 64 "78a019"+ // field 15, encoding 0, value 3232 "8001c032"+ // field 16, encoding 0, value 6464 "8d0100004a45"+ // field 17, encoding 5, value 3232.0 "9101000000000040b940"+ // field 18, encoding 1, value 6464.0 "9a0106"+"737472696e67"+ // field 19, encoding 2 string "string" "9203020001"+ // field 50, encoding 2, 2 bytes, value 0, value 1 "9a03022021"+ // field 51, encoding 2, 2 bytes, value 32, value 33 "a203024041"+ // field 52, encoding 2, 2 bytes, value 64, value 65 "aa0308"+ // field 53, encoding 2, 8 bytes "a00c0000050d0000"+ // value 3232, value 3333 "b20310"+ // field 54, encoding 2, 16 bytes "4019000000000000a519000000000000"+ // value 6464, value 6565 "ba0306"+ // field 55, encoding 2, 6 bytes "a0dd1395ac14"+ // value 323232, value 333333 "c20306"+ // field 56, encoding 2, 6 bytes "c0ba27b58928"+ // value 646464, value 656565 "ca0308"+ // field 57, encoding 2, 8 bytes "0000004200000442"+ // value 32.0, value 33.0 "d20310"+ // field 58, encoding 2, 16 bytes "00000000000050400000000000405040"+ // value 64.0, value 65.0 "b304"+ // start group field 70 level 1 "ba0408"+"7265717569726564"+ // field 71, encoding 2, string "required" "b404"+ // end group field 70 level 1 "aa0605"+"6279746573"+ // field 101, encoding 2 string "bytes" "b0063f"+ // field 102, encoding 0, 0x3f zigzag32 "b8067f"+ // field 103, encoding 0, 0x7f zigzag64 "b21f02"+ // field 502, encoding 2, 2 bytes "403f"+ // value 32, value -32 "ba1f03"+ // field 503, encoding 2, 3 bytes "80017f") // value 64, value -64 } // Test that we can encode empty bytes fields. func TestEncodeDecodeBytes1(t *testing.T) { pb := initGoTest(false) // Create our bytes pb.F_BytesRequired = []byte{} pb.F_BytesRepeated = [][]byte{{}} pb.F_BytesOptional = []byte{} d, err := Marshal(pb) if err != nil { t.Error(err) } pbd := new(GoTest) if err := Unmarshal(d, pbd); err != nil { t.Error(err) } if pbd.F_BytesRequired == nil || len(pbd.F_BytesRequired) != 0 { t.Error("required empty bytes field is incorrect") } if pbd.F_BytesRepeated == nil || len(pbd.F_BytesRepeated) == 1 && pbd.F_BytesRepeated[0] == nil { t.Error("repeated empty bytes field is incorrect") } if pbd.F_BytesOptional == nil || len(pbd.F_BytesOptional) != 0 { t.Error("optional empty bytes field is incorrect") } } // Test that we encode nil-valued fields of a repeated bytes field correctly. // Since entries in a repeated field cannot be nil, nil must mean empty value. func TestEncodeDecodeBytes2(t *testing.T) { pb := initGoTest(false) // Create our bytes pb.F_BytesRepeated = [][]byte{nil} d, err := Marshal(pb) if err != nil { t.Error(err) } pbd := new(GoTest) if err := Unmarshal(d, pbd); err != nil { t.Error(err) } if len(pbd.F_BytesRepeated) != 1 || pbd.F_BytesRepeated[0] == nil { t.Error("Unexpected value for repeated bytes field") } } // All required fields set, defaults provided, all repeated fields given two values. func TestSkippingUnrecognizedFields(t *testing.T) { o := old() pb := initGoTestField() // Marshal it normally. o.Marshal(pb) // Now new a GoSkipTest record. skip := &GoSkipTest{ SkipInt32: Int32(32), SkipFixed32: Uint32(3232), SkipFixed64: Uint64(6464), SkipString: String("skipper"), Skipgroup: &GoSkipTest_SkipGroup{ GroupInt32: Int32(75), GroupString: String("wxyz"), }, } // Marshal it into same buffer. o.Marshal(skip) pbd := new(GoTestField) o.Unmarshal(pbd) // The __unrecognized field should be a marshaling of GoSkipTest skipd := new(GoSkipTest) o.SetBuf(pbd.XXX_unrecognized) o.Unmarshal(skipd) if *skipd.SkipInt32 != *skip.SkipInt32 { t.Error("skip int32", skipd.SkipInt32) } if *skipd.SkipFixed32 != *skip.SkipFixed32 { t.Error("skip fixed32", skipd.SkipFixed32) } if *skipd.SkipFixed64 != *skip.SkipFixed64 { t.Error("skip fixed64", skipd.SkipFixed64) } if *skipd.SkipString != *skip.SkipString { t.Error("skip string", *skipd.SkipString) } if *skipd.Skipgroup.GroupInt32 != *skip.Skipgroup.GroupInt32 { t.Error("skip group int32", skipd.Skipgroup.GroupInt32) } if *skipd.Skipgroup.GroupString != *skip.Skipgroup.GroupString { t.Error("skip group string", *skipd.Skipgroup.GroupString) } } // Check that unrecognized fields of a submessage are preserved. func TestSubmessageUnrecognizedFields(t *testing.T) { nm := &NewMessage{ Nested: &NewMessage_Nested{ Name: String("Nigel"), FoodGroup: String("carbs"), }, } b, err := Marshal(nm) if err != nil { t.Fatalf("Marshal of NewMessage: %v", err) } // Unmarshal into an OldMessage. om := new(OldMessage) if err := Unmarshal(b, om); err != nil { t.Fatalf("Unmarshal to OldMessage: %v", err) } exp := &OldMessage{ Nested: &OldMessage_Nested{ Name: String("Nigel"), // normal protocol buffer users should not do this XXX_unrecognized: []byte("\x12\x05carbs"), }, } if !Equal(om, exp) { t.Errorf("om = %v, want %v", om, exp) } // Clone the OldMessage. om = Clone(om).(*OldMessage) if !Equal(om, exp) { t.Errorf("Clone(om) = %v, want %v", om, exp) } // Marshal the OldMessage, then unmarshal it into an empty NewMessage. if b, err = Marshal(om); err != nil { t.Fatalf("Marshal of OldMessage: %v", err) } t.Logf("Marshal(%v) -> %q", om, b) nm2 := new(NewMessage) if err := Unmarshal(b, nm2); err != nil { t.Fatalf("Unmarshal to NewMessage: %v", err) } if !Equal(nm, nm2) { t.Errorf("NewMessage round-trip: %v => %v", nm, nm2) } } // Check that an int32 field can be upgraded to an int64 field. func TestNegativeInt32(t *testing.T) { om := &OldMessage{ Num: Int32(-1), } b, err := Marshal(om) if err != nil { t.Fatalf("Marshal of OldMessage: %v", err) } // Check the size. It should be 11 bytes; // 1 for the field/wire type, and 10 for the negative number. if len(b) != 11 { t.Errorf("%v marshaled as %q, wanted 11 bytes", om, b) } // Unmarshal into a NewMessage. nm := new(NewMessage) if err := Unmarshal(b, nm); err != nil { t.Fatalf("Unmarshal to NewMessage: %v", err) } want := &NewMessage{ Num: Int64(-1), } if !Equal(nm, want) { t.Errorf("nm = %v, want %v", nm, want) } } // Check that we can grow an array (repeated field) to have many elements. // This test doesn't depend only on our encoding; for variety, it makes sure // we create, encode, and decode the correct contents explicitly. It's therefore // a bit messier. // This test also uses (and hence tests) the Marshal/Unmarshal functions // instead of the methods. func TestBigRepeated(t *testing.T) { pb := initGoTest(true) // Create the arrays const N = 50 // Internally the library starts much smaller. pb.Repeatedgroup = make([]*GoTest_RepeatedGroup, N) pb.F_Sint64Repeated = make([]int64, N) pb.F_Sint32Repeated = make([]int32, N) pb.F_BytesRepeated = make([][]byte, N) pb.F_StringRepeated = make([]string, N) pb.F_DoubleRepeated = make([]float64, N) pb.F_FloatRepeated = make([]float32, N) pb.F_Uint64Repeated = make([]uint64, N) pb.F_Uint32Repeated = make([]uint32, N) pb.F_Fixed64Repeated = make([]uint64, N) pb.F_Fixed32Repeated = make([]uint32, N) pb.F_Int64Repeated = make([]int64, N) pb.F_Int32Repeated = make([]int32, N) pb.F_BoolRepeated = make([]bool, N) pb.RepeatedField = make([]*GoTestField, N) // Fill in the arrays with checkable values. igtf := initGoTestField() igtrg := initGoTest_RepeatedGroup() for i := 0; i < N; i++ { pb.Repeatedgroup[i] = igtrg pb.F_Sint64Repeated[i] = int64(i) pb.F_Sint32Repeated[i] = int32(i) s := fmt.Sprint(i) pb.F_BytesRepeated[i] = []byte(s) pb.F_StringRepeated[i] = s pb.F_DoubleRepeated[i] = float64(i) pb.F_FloatRepeated[i] = float32(i) pb.F_Uint64Repeated[i] = uint64(i) pb.F_Uint32Repeated[i] = uint32(i) pb.F_Fixed64Repeated[i] = uint64(i) pb.F_Fixed32Repeated[i] = uint32(i) pb.F_Int64Repeated[i] = int64(i) pb.F_Int32Repeated[i] = int32(i) pb.F_BoolRepeated[i] = i%2 == 0 pb.RepeatedField[i] = igtf } // Marshal. buf, _ := Marshal(pb) // Now test Unmarshal by recreating the original buffer. pbd := new(GoTest) Unmarshal(buf, pbd) // Check the checkable values for i := uint64(0); i < N; i++ { if pbd.Repeatedgroup[i] == nil { // TODO: more checking? t.Error("pbd.Repeatedgroup bad") } var x uint64 x = uint64(pbd.F_Sint64Repeated[i]) if x != i { t.Error("pbd.F_Sint64Repeated bad", x, i) } x = uint64(pbd.F_Sint32Repeated[i]) if x != i { t.Error("pbd.F_Sint32Repeated bad", x, i) } s := fmt.Sprint(i) equalbytes(pbd.F_BytesRepeated[i], []byte(s), t) if pbd.F_StringRepeated[i] != s { t.Error("pbd.F_Sint32Repeated bad", pbd.F_StringRepeated[i], i) } x = uint64(pbd.F_DoubleRepeated[i]) if x != i { t.Error("pbd.F_DoubleRepeated bad", x, i) } x = uint64(pbd.F_FloatRepeated[i]) if x != i { t.Error("pbd.F_FloatRepeated bad", x, i) } x = pbd.F_Uint64Repeated[i] if x != i { t.Error("pbd.F_Uint64Repeated bad", x, i) } x = uint64(pbd.F_Uint32Repeated[i]) if x != i { t.Error("pbd.F_Uint32Repeated bad", x, i) } x = pbd.F_Fixed64Repeated[i] if x != i { t.Error("pbd.F_Fixed64Repeated bad", x, i) } x = uint64(pbd.F_Fixed32Repeated[i]) if x != i { t.Error("pbd.F_Fixed32Repeated bad", x, i) } x = uint64(pbd.F_Int64Repeated[i]) if x != i { t.Error("pbd.F_Int64Repeated bad", x, i) } x = uint64(pbd.F_Int32Repeated[i]) if x != i { t.Error("pbd.F_Int32Repeated bad", x, i) } if pbd.F_BoolRepeated[i] != (i%2 == 0) { t.Error("pbd.F_BoolRepeated bad", x, i) } if pbd.RepeatedField[i] == nil { // TODO: more checking? t.Error("pbd.RepeatedField bad") } } } // Verify we give a useful message when decoding to the wrong structure type. func TestTypeMismatch(t *testing.T) { pb1 := initGoTest(true) // Marshal o := old() o.Marshal(pb1) // Now Unmarshal it to the wrong type. pb2 := initGoTestField() err := o.Unmarshal(pb2) if err == nil { t.Error("expected error, got no error") } else if !strings.Contains(err.Error(), "bad wiretype") { t.Error("expected bad wiretype error, got", err) } } func encodeDecode(t *testing.T, in, out Message, msg string) { buf, err := Marshal(in) if err != nil { t.Fatalf("failed marshaling %v: %v", msg, err) } if err := Unmarshal(buf, out); err != nil { t.Fatalf("failed unmarshaling %v: %v", msg, err) } } func TestPackedNonPackedDecoderSwitching(t *testing.T) { np, p := new(NonPackedTest), new(PackedTest) // non-packed -> packed np.A = []int32{0, 1, 1, 2, 3, 5} encodeDecode(t, np, p, "non-packed -> packed") if !reflect.DeepEqual(np.A, p.B) { t.Errorf("failed non-packed -> packed; np.A=%+v, p.B=%+v", np.A, p.B) } // packed -> non-packed np.Reset() p.B = []int32{3, 1, 4, 1, 5, 9} encodeDecode(t, p, np, "packed -> non-packed") if !reflect.DeepEqual(p.B, np.A) { t.Errorf("failed packed -> non-packed; p.B=%+v, np.A=%+v", p.B, np.A) } } func TestProto1RepeatedGroup(t *testing.T) { pb := &MessageList{ Message: []*MessageList_Message{ { Name: String("blah"), Count: Int32(7), }, // NOTE: pb.Message[1] is a nil nil, }, } o := old() err := o.Marshal(pb) if err == nil || !strings.Contains(err.Error(), "repeated field Message has nil") { t.Fatalf("unexpected or no error when marshaling: %v", err) } } // Test that enums work. Checks for a bug introduced by making enums // named types instead of int32: newInt32FromUint64 would crash with // a type mismatch in reflect.PointTo. func TestEnum(t *testing.T) { pb := new(GoEnum) pb.Foo = FOO_FOO1.Enum() o := old() if err := o.Marshal(pb); err != nil { t.Fatal("error encoding enum:", err) } pb1 := new(GoEnum) if err := o.Unmarshal(pb1); err != nil { t.Fatal("error decoding enum:", err) } if *pb1.Foo != FOO_FOO1 { t.Error("expected 7 but got ", *pb1.Foo) } } // Enum types have String methods. Check that enum fields can be printed. // We don't care what the value actually is, just as long as it doesn't crash. func TestPrintingNilEnumFields(t *testing.T) { pb := new(GoEnum) _ = fmt.Sprintf("%+v", pb) } // Verify that absent required fields cause Marshal/Unmarshal to return errors. func TestRequiredFieldEnforcement(t *testing.T) { pb := new(GoTestField) _, err := Marshal(pb) if err == nil { t.Error("marshal: expected error, got nil") } else if _, ok := err.(*RequiredNotSetError); !ok || !strings.Contains(err.Error(), "Label") { t.Errorf("marshal: bad error type: %v", err) } // A slightly sneaky, yet valid, proto. It encodes the same required field twice, // so simply counting the required fields is insufficient. // field 1, encoding 2, value "hi" buf := []byte("\x0A\x02hi\x0A\x02hi") err = Unmarshal(buf, pb) if err == nil { t.Error("unmarshal: expected error, got nil") } else if _, ok := err.(*RequiredNotSetError); !ok || !strings.Contains(err.Error(), "{Unknown}") { t.Errorf("unmarshal: bad error type: %v", err) } } // Verify that absent required fields in groups cause Marshal/Unmarshal to return errors. func TestRequiredFieldEnforcementGroups(t *testing.T) { pb := &GoTestRequiredGroupField{Group: &GoTestRequiredGroupField_Group{}} if _, err := Marshal(pb); err == nil { t.Error("marshal: expected error, got nil") } else if _, ok := err.(*RequiredNotSetError); !ok || !strings.Contains(err.Error(), "Group.Field") { t.Errorf("marshal: bad error type: %v", err) } buf := []byte{11, 12} if err := Unmarshal(buf, pb); err == nil { t.Error("unmarshal: expected error, got nil") } else if _, ok := err.(*RequiredNotSetError); !ok || !strings.Contains(err.Error(), "Group.{Unknown}") { t.Errorf("unmarshal: bad error type: %v", err) } } func TestTypedNilMarshal(t *testing.T) { // A typed nil should return ErrNil and not crash. { var m *GoEnum if _, err := Marshal(m); err != ErrNil { t.Errorf("Marshal(%#v): got %v, want ErrNil", m, err) } } { m := &Communique{Union: &Communique_Msg{nil}} if _, err := Marshal(m); err == nil || err == ErrNil { t.Errorf("Marshal(%#v): got %v, want errOneofHasNil", m, err) } } } // A type that implements the Marshaler interface, but is not nillable. type nonNillableInt uint64 func (nni nonNillableInt) Marshal() ([]byte, error) { return EncodeVarint(uint64(nni)), nil } type NNIMessage struct { nni nonNillableInt } func (*NNIMessage) Reset() {} func (*NNIMessage) String() string { return "" } func (*NNIMessage) ProtoMessage() {} // A type that implements the Marshaler interface and is nillable. type nillableMessage struct { x uint64 } func (nm *nillableMessage) Marshal() ([]byte, error) { return EncodeVarint(nm.x), nil } type NMMessage struct { nm *nillableMessage } func (*NMMessage) Reset() {} func (*NMMessage) String() string { return "" } func (*NMMessage) ProtoMessage() {} // Verify a type that uses the Marshaler interface, but has a nil pointer. func TestNilMarshaler(t *testing.T) { // Try a struct with a Marshaler field that is nil. // It should be directly marshable. nmm := new(NMMessage) if _, err := Marshal(nmm); err != nil { t.Error("unexpected error marshaling nmm: ", err) } // Try a struct with a Marshaler field that is not nillable. nnim := new(NNIMessage) nnim.nni = 7 var _ Marshaler = nnim.nni // verify it is truly a Marshaler if _, err := Marshal(nnim); err != nil { t.Error("unexpected error marshaling nnim: ", err) } } func TestAllSetDefaults(t *testing.T) { // Exercise SetDefaults with all scalar field types. m := &Defaults{ // NaN != NaN, so override that here. F_Nan: Float32(1.7), } expected := &Defaults{ F_Bool: Bool(true), F_Int32: Int32(32), F_Int64: Int64(64), F_Fixed32: Uint32(320), F_Fixed64: Uint64(640), F_Uint32: Uint32(3200), F_Uint64: Uint64(6400), F_Float: Float32(314159), F_Double: Float64(271828), F_String: String(`hello, "world!"` + "\n"), F_Bytes: []byte("Bignose"), F_Sint32: Int32(-32), F_Sint64: Int64(-64), F_Enum: Defaults_GREEN.Enum(), F_Pinf: Float32(float32(math.Inf(1))), F_Ninf: Float32(float32(math.Inf(-1))), F_Nan: Float32(1.7), StrZero: String(""), } SetDefaults(m) if !Equal(m, expected) { t.Errorf("SetDefaults failed\n got %v\nwant %v", m, expected) } } func TestSetDefaultsWithSetField(t *testing.T) { // Check that a set value is not overridden. m := &Defaults{ F_Int32: Int32(12), } SetDefaults(m) if v := m.GetF_Int32(); v != 12 { t.Errorf("m.FInt32 = %v, want 12", v) } } func TestSetDefaultsWithSubMessage(t *testing.T) { m := &OtherMessage{ Key: Int64(123), Inner: &InnerMessage{ Host: String("gopher"), }, } expected := &OtherMessage{ Key: Int64(123), Inner: &InnerMessage{ Host: String("gopher"), Port: Int32(4000), }, } SetDefaults(m) if !Equal(m, expected) { t.Errorf("\n got %v\nwant %v", m, expected) } } func TestSetDefaultsWithRepeatedSubMessage(t *testing.T) { m := &MyMessage{ RepInner: []*InnerMessage{{}}, } expected := &MyMessage{ RepInner: []*InnerMessage{{ Port: Int32(4000), }}, } SetDefaults(m) if !Equal(m, expected) { t.Errorf("\n got %v\nwant %v", m, expected) } } func TestSetDefaultWithRepeatedNonMessage(t *testing.T) { m := &MyMessage{ Pet: []string{"turtle", "wombat"}, } expected := Clone(m) SetDefaults(m) if !Equal(m, expected) { t.Errorf("\n got %v\nwant %v", m, expected) } } func TestMaximumTagNumber(t *testing.T) { m := &MaxTag{ LastField: String("natural goat essence"), } buf, err := Marshal(m) if err != nil { t.Fatalf("proto.Marshal failed: %v", err) } m2 := new(MaxTag) if err := Unmarshal(buf, m2); err != nil { t.Fatalf("proto.Unmarshal failed: %v", err) } if got, want := m2.GetLastField(), *m.LastField; got != want { t.Errorf("got %q, want %q", got, want) } } func TestJSON(t *testing.T) { m := &MyMessage{ Count: Int32(4), Pet: []string{"bunny", "kitty"}, Inner: &InnerMessage{ Host: String("cauchy"), }, Bikeshed: MyMessage_GREEN.Enum(), } const expected = `{"count":4,"pet":["bunny","kitty"],"inner":{"host":"cauchy"},"bikeshed":1}` b, err := json.Marshal(m) if err != nil { t.Fatalf("json.Marshal failed: %v", err) } s := string(b) if s != expected { t.Errorf("got %s\nwant %s", s, expected) } received := new(MyMessage) if err := json.Unmarshal(b, received); err != nil { t.Fatalf("json.Unmarshal failed: %v", err) } if !Equal(received, m) { t.Fatalf("got %s, want %s", received, m) } // Test unmarshalling of JSON with symbolic enum name. const old = `{"count":4,"pet":["bunny","kitty"],"inner":{"host":"cauchy"},"bikeshed":"GREEN"}` received.Reset() if err := json.Unmarshal([]byte(old), received); err != nil { t.Fatalf("json.Unmarshal failed: %v", err) } if !Equal(received, m) { t.Fatalf("got %s, want %s", received, m) } } func TestBadWireType(t *testing.T) { b := []byte{7<<3 | 6} // field 7, wire type 6 pb := new(OtherMessage) if err := Unmarshal(b, pb); err == nil { t.Errorf("Unmarshal did not fail") } else if !strings.Contains(err.Error(), "unknown wire type") { t.Errorf("wrong error: %v", err) } } func TestBytesWithInvalidLength(t *testing.T) { // If a byte sequence has an invalid (negative) length, Unmarshal should not panic. b := []byte{2<<3 | WireBytes, 0xff, 0xff, 0xff, 0xff, 0xff, 0} Unmarshal(b, new(MyMessage)) } func TestLengthOverflow(t *testing.T) { // Overflowing a length should not panic. b := []byte{2<<3 | WireBytes, 1, 1, 3<<3 | WireBytes, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x01} Unmarshal(b, new(MyMessage)) } func TestVarintOverflow(t *testing.T) { // Overflowing a 64-bit length should not be allowed. b := []byte{1<<3 | WireVarint, 0x01, 3<<3 | WireBytes, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x01} if err := Unmarshal(b, new(MyMessage)); err == nil { t.Fatalf("Overflowed uint64 length without error") } } func TestUnmarshalFuzz(t *testing.T) { const N = 1000 seed := time.Now().UnixNano() t.Logf("RNG seed is %d", seed) rng := rand.New(rand.NewSource(seed)) buf := make([]byte, 20) for i := 0; i < N; i++ { for j := range buf { buf[j] = byte(rng.Intn(256)) } fuzzUnmarshal(t, buf) } } func TestMergeMessages(t *testing.T) { pb := &MessageList{Message: []*MessageList_Message{{Name: String("x"), Count: Int32(1)}}} data, err := Marshal(pb) if err != nil { t.Fatalf("Marshal: %v", err) } pb1 := new(MessageList) if err := Unmarshal(data, pb1); err != nil { t.Fatalf("first Unmarshal: %v", err) } if err := Unmarshal(data, pb1); err != nil { t.Fatalf("second Unmarshal: %v", err) } if len(pb1.Message) != 1 { t.Errorf("two Unmarshals produced %d Messages, want 1", len(pb1.Message)) } pb2 := new(MessageList) if err := UnmarshalMerge(data, pb2); err != nil { t.Fatalf("first UnmarshalMerge: %v", err) } if err := UnmarshalMerge(data, pb2); err != nil { t.Fatalf("second UnmarshalMerge: %v", err) } if len(pb2.Message) != 2 { t.Errorf("two UnmarshalMerges produced %d Messages, want 2", len(pb2.Message)) } } func TestExtensionMarshalOrder(t *testing.T) { m := &MyMessage{Count: Int(123)} if err := SetExtension(m, E_Ext_More, &Ext{Data: String("alpha")}); err != nil { t.Fatalf("SetExtension: %v", err) } if err := SetExtension(m, E_Ext_Text, String("aleph")); err != nil { t.Fatalf("SetExtension: %v", err) } if err := SetExtension(m, E_Ext_Number, Int32(1)); err != nil { t.Fatalf("SetExtension: %v", err) } // Serialize m several times, and check we get the same bytes each time. var orig []byte for i := 0; i < 100; i++ { b, err := Marshal(m) if err != nil { t.Fatalf("Marshal: %v", err) } if i == 0 { orig = b continue } if !bytes.Equal(b, orig) { t.Errorf("Bytes differ on attempt #%d", i) } } } // Many extensions, because small maps might not iterate differently on each iteration. var exts = []*ExtensionDesc{ E_X201, E_X202, E_X203, E_X204, E_X205, E_X206, E_X207, E_X208, E_X209, E_X210, E_X211, E_X212, E_X213, E_X214, E_X215, E_X216, E_X217, E_X218, E_X219, E_X220, E_X221, E_X222, E_X223, E_X224, E_X225, E_X226, E_X227, E_X228, E_X229, E_X230, E_X231, E_X232, E_X233, E_X234, E_X235, E_X236, E_X237, E_X238, E_X239, E_X240, E_X241, E_X242, E_X243, E_X244, E_X245, E_X246, E_X247, E_X248, E_X249, E_X250, } func TestMessageSetMarshalOrder(t *testing.T) { m := &MyMessageSet{} for _, x := range exts { if err := SetExtension(m, x, &Empty{}); err != nil { t.Fatalf("SetExtension: %v", err) } } buf, err := Marshal(m) if err != nil { t.Fatalf("Marshal: %v", err) } // Serialize m several times, and check we get the same bytes each time. for i := 0; i < 10; i++ { b1, err := Marshal(m) if err != nil { t.Fatalf("Marshal: %v", err) } if !bytes.Equal(b1, buf) { t.Errorf("Bytes differ on re-Marshal #%d", i) } m2 := &MyMessageSet{} if err := Unmarshal(buf, m2); err != nil { t.Errorf("Unmarshal: %v", err) } b2, err := Marshal(m2) if err != nil { t.Errorf("re-Marshal: %v", err) } if !bytes.Equal(b2, buf) { t.Errorf("Bytes differ on round-trip #%d", i) } } } func TestUnmarshalMergesMessages(t *testing.T) { // If a nested message occurs twice in the input, // the fields should be merged when decoding. a := &OtherMessage{ Key: Int64(123), Inner: &InnerMessage{ Host: String("polhode"), Port: Int32(1234), }, } aData, err := Marshal(a) if err != nil { t.Fatalf("Marshal(a): %v", err) } b := &OtherMessage{ Weight: Float32(1.2), Inner: &InnerMessage{ Host: String("herpolhode"), Connected: Bool(true), }, } bData, err := Marshal(b) if err != nil { t.Fatalf("Marshal(b): %v", err) } want := &OtherMessage{ Key: Int64(123), Weight: Float32(1.2), Inner: &InnerMessage{ Host: String("herpolhode"), Port: Int32(1234), Connected: Bool(true), }, } got := new(OtherMessage) if err := Unmarshal(append(aData, bData...), got); err != nil { t.Fatalf("Unmarshal: %v", err) } if !Equal(got, want) { t.Errorf("\n got %v\nwant %v", got, want) } } func TestEncodingSizes(t *testing.T) { tests := []struct { m Message n int }{ {&Defaults{F_Int32: Int32(math.MaxInt32)}, 6}, {&Defaults{F_Int32: Int32(math.MinInt32)}, 11}, {&Defaults{F_Uint32: Uint32(uint32(math.MaxInt32) + 1)}, 6}, {&Defaults{F_Uint32: Uint32(math.MaxUint32)}, 6}, } for _, test := range tests { b, err := Marshal(test.m) if err != nil { t.Errorf("Marshal(%v): %v", test.m, err) continue } if len(b) != test.n { t.Errorf("Marshal(%v) yielded %d bytes, want %d bytes", test.m, len(b), test.n) } } } func TestRequiredNotSetError(t *testing.T) { pb := initGoTest(false) pb.RequiredField.Label = nil pb.F_Int32Required = nil pb.F_Int64Required = nil expected := "0807" + // field 1, encoding 0, value 7 "2206" + "120474797065" + // field 4, encoding 2 (GoTestField) "5001" + // field 10, encoding 0, value 1 "6d20000000" + // field 13, encoding 5, value 0x20 "714000000000000000" + // field 14, encoding 1, value 0x40 "78a019" + // field 15, encoding 0, value 0xca0 = 3232 "8001c032" + // field 16, encoding 0, value 0x1940 = 6464 "8d0100004a45" + // field 17, encoding 5, value 3232.0 "9101000000000040b940" + // field 18, encoding 1, value 6464.0 "9a0106" + "737472696e67" + // field 19, encoding 2, string "string" "b304" + // field 70, encoding 3, start group "ba0408" + "7265717569726564" + // field 71, encoding 2, string "required" "b404" + // field 70, encoding 4, end group "aa0605" + "6279746573" + // field 101, encoding 2, string "bytes" "b0063f" + // field 102, encoding 0, 0x3f zigzag32 "b8067f" // field 103, encoding 0, 0x7f zigzag64 o := old() bytes, err := Marshal(pb) if _, ok := err.(*RequiredNotSetError); !ok { fmt.Printf("marshal-1 err = %v, want *RequiredNotSetError", err) o.DebugPrint("", bytes) t.Fatalf("expected = %s", expected) } if strings.Index(err.Error(), "RequiredField.Label") < 0 { t.Errorf("marshal-1 wrong err msg: %v", err) } if !equal(bytes, expected, t) { o.DebugPrint("neq 1", bytes) t.Fatalf("expected = %s", expected) } // Now test Unmarshal by recreating the original buffer. pbd := new(GoTest) err = Unmarshal(bytes, pbd) if _, ok := err.(*RequiredNotSetError); !ok { t.Fatalf("unmarshal err = %v, want *RequiredNotSetError", err) o.DebugPrint("", bytes) t.Fatalf("string = %s", expected) } if strings.Index(err.Error(), "RequiredField.{Unknown}") < 0 { t.Errorf("unmarshal wrong err msg: %v", err) } bytes, err = Marshal(pbd) if _, ok := err.(*RequiredNotSetError); !ok { t.Errorf("marshal-2 err = %v, want *RequiredNotSetError", err) o.DebugPrint("", bytes) t.Fatalf("string = %s", expected) } if strings.Index(err.Error(), "RequiredField.Label") < 0 { t.Errorf("marshal-2 wrong err msg: %v", err) } if !equal(bytes, expected, t) { o.DebugPrint("neq 2", bytes) t.Fatalf("string = %s", expected) } } func fuzzUnmarshal(t *testing.T, data []byte) { defer func() { if e := recover(); e != nil { t.Errorf("These bytes caused a panic: %+v", data) t.Logf("Stack:\n%s", debug.Stack()) t.FailNow() } }() pb := new(MyMessage) Unmarshal(data, pb) } func TestMapFieldMarshal(t *testing.T) { m := &MessageWithMap{ NameMapping: map[int32]string{ 1: "Rob", 4: "Ian", 8: "Dave", }, } b, err := Marshal(m) if err != nil { t.Fatalf("Marshal: %v", err) } // b should be the concatenation of these three byte sequences in some order. parts := []string{ "\n\a\b\x01\x12\x03Rob", "\n\a\b\x04\x12\x03Ian", "\n\b\b\x08\x12\x04Dave", } ok := false for i := range parts { for j := range parts { if j == i { continue } for k := range parts { if k == i || k == j { continue } try := parts[i] + parts[j] + parts[k] if bytes.Equal(b, []byte(try)) { ok = true break } } } } if !ok { t.Fatalf("Incorrect Marshal output.\n got %q\nwant %q (or a permutation of that)", b, parts[0]+parts[1]+parts[2]) } t.Logf("FYI b: %q", b) (new(Buffer)).DebugPrint("Dump of b", b) } func TestMapFieldRoundTrips(t *testing.T) { m := &MessageWithMap{ NameMapping: map[int32]string{ 1: "Rob", 4: "Ian", 8: "Dave", }, MsgMapping: map[int64]*FloatingPoint{ 0x7001: &FloatingPoint{F: Float64(2.0)}, }, ByteMapping: map[bool][]byte{ false: []byte("that's not right!"), true: []byte("aye, 'tis true!"), }, } b, err := Marshal(m) if err != nil { t.Fatalf("Marshal: %v", err) } t.Logf("FYI b: %q", b) m2 := new(MessageWithMap) if err := Unmarshal(b, m2); err != nil { t.Fatalf("Unmarshal: %v", err) } for _, pair := range [][2]interface{}{ {m.NameMapping, m2.NameMapping}, {m.MsgMapping, m2.MsgMapping}, {m.ByteMapping, m2.ByteMapping}, } { if !reflect.DeepEqual(pair[0], pair[1]) { t.Errorf("Map did not survive a round trip.\ninitial: %v\n final: %v", pair[0], pair[1]) } } } func TestMapFieldWithNil(t *testing.T) { m1 := &MessageWithMap{ MsgMapping: map[int64]*FloatingPoint{ 1: nil, }, } b, err := Marshal(m1) if err != nil { t.Fatalf("Marshal: %v", err) } m2 := new(MessageWithMap) if err := Unmarshal(b, m2); err != nil { t.Fatalf("Unmarshal: %v, got these bytes: %v", err, b) } if v, ok := m2.MsgMapping[1]; !ok { t.Error("msg_mapping[1] not present") } else if v != nil { t.Errorf("msg_mapping[1] not nil: %v", v) } } func TestMapFieldWithNilBytes(t *testing.T) { m1 := &MessageWithMap{ ByteMapping: map[bool][]byte{ false: []byte{}, true: nil, }, } n := Size(m1) b, err := Marshal(m1) if err != nil { t.Fatalf("Marshal: %v", err) } if n != len(b) { t.Errorf("Size(m1) = %d; want len(Marshal(m1)) = %d", n, len(b)) } m2 := new(MessageWithMap) if err := Unmarshal(b, m2); err != nil { t.Fatalf("Unmarshal: %v, got these bytes: %v", err, b) } if v, ok := m2.ByteMapping[false]; !ok { t.Error("byte_mapping[false] not present") } else if len(v) != 0 { t.Errorf("byte_mapping[false] not empty: %#v", v) } if v, ok := m2.ByteMapping[true]; !ok { t.Error("byte_mapping[true] not present") } else if len(v) != 0 { t.Errorf("byte_mapping[true] not empty: %#v", v) } } func TestDecodeMapFieldMissingKey(t *testing.T) { b := []byte{ 0x0A, 0x03, // message, tag 1 (name_mapping), of length 3 bytes // no key 0x12, 0x01, 0x6D, // string value of length 1 byte, value "m" } got := &MessageWithMap{} err := Unmarshal(b, got) if err != nil { t.Fatalf("failed to marshal map with missing key: %v", err) } want := &MessageWithMap{NameMapping: map[int32]string{0: "m"}} if !Equal(got, want) { t.Errorf("Unmarshaled map with no key was not as expected. got: %v, want %v", got, want) } } func TestDecodeMapFieldMissingValue(t *testing.T) { b := []byte{ 0x0A, 0x02, // message, tag 1 (name_mapping), of length 2 bytes 0x08, 0x01, // varint key, value 1 // no value } got := &MessageWithMap{} err := Unmarshal(b, got) if err != nil { t.Fatalf("failed to marshal map with missing value: %v", err) } want := &MessageWithMap{NameMapping: map[int32]string{1: ""}} if !Equal(got, want) { t.Errorf("Unmarshaled map with no value was not as expected. got: %v, want %v", got, want) } } func TestOneof(t *testing.T) { m := &Communique{} b, err := Marshal(m) if err != nil { t.Fatalf("Marshal of empty message with oneof: %v", err) } if len(b) != 0 { t.Errorf("Marshal of empty message yielded too many bytes: %v", b) } m = &Communique{ Union: &Communique_Name{"Barry"}, } // Round-trip. b, err = Marshal(m) if err != nil { t.Fatalf("Marshal of message with oneof: %v", err) } if len(b) != 7 { // name tag/wire (1) + name len (1) + name (5) t.Errorf("Incorrect marshal of message with oneof: %v", b) } m.Reset() if err := Unmarshal(b, m); err != nil { t.Fatalf("Unmarshal of message with oneof: %v", err) } if x, ok := m.Union.(*Communique_Name); !ok || x.Name != "Barry" { t.Errorf("After round trip, Union = %+v", m.Union) } if name := m.GetName(); name != "Barry" { t.Errorf("After round trip, GetName = %q, want %q", name, "Barry") } // Let's try with a message in the oneof. m.Union = &Communique_Msg{&Strings{StringField: String("deep deep string")}} b, err = Marshal(m) if err != nil { t.Fatalf("Marshal of message with oneof set to message: %v", err) } if len(b) != 20 { // msg tag/wire (1) + msg len (1) + msg (1 + 1 + 16) t.Errorf("Incorrect marshal of message with oneof set to message: %v", b) } m.Reset() if err := Unmarshal(b, m); err != nil { t.Fatalf("Unmarshal of message with oneof set to message: %v", err) } ss, ok := m.Union.(*Communique_Msg) if !ok || ss.Msg.GetStringField() != "deep deep string" { t.Errorf("After round trip with oneof set to message, Union = %+v", m.Union) } } func TestInefficientPackedBool(t *testing.T) { // https://github.com/golang/protobuf/issues/76 inp := []byte{ 0x12, 0x02, // 0x12 = 2<<3|2; 2 bytes // Usually a bool should take a single byte, // but it is permitted to be any varint. 0xb9, 0x30, } if err := Unmarshal(inp, new(MoreRepeated)); err != nil { t.Error(err) } } // Benchmarks func testMsg() *GoTest { pb := initGoTest(true) const N = 1000 // Internally the library starts much smaller. pb.F_Int32Repeated = make([]int32, N) pb.F_DoubleRepeated = make([]float64, N) for i := 0; i < N; i++ { pb.F_Int32Repeated[i] = int32(i) pb.F_DoubleRepeated[i] = float64(i) } return pb } func bytesMsg() *GoTest { pb := initGoTest(true) buf := make([]byte, 4000) for i := range buf { buf[i] = byte(i) } pb.F_BytesDefaulted = buf return pb } func benchmarkMarshal(b *testing.B, pb Message, marshal func(Message) ([]byte, error)) { d, _ := marshal(pb) b.SetBytes(int64(len(d))) b.ResetTimer() for i := 0; i < b.N; i++ { marshal(pb) } } func benchmarkBufferMarshal(b *testing.B, pb Message) { p := NewBuffer(nil) benchmarkMarshal(b, pb, func(pb0 Message) ([]byte, error) { p.Reset() err := p.Marshal(pb0) return p.Bytes(), err }) } func benchmarkSize(b *testing.B, pb Message) { benchmarkMarshal(b, pb, func(pb0 Message) ([]byte, error) { Size(pb) return nil, nil }) } func newOf(pb Message) Message { in := reflect.ValueOf(pb) if in.IsNil() { return pb } return reflect.New(in.Type().Elem()).Interface().(Message) } func benchmarkUnmarshal(b *testing.B, pb Message, unmarshal func([]byte, Message) error) { d, _ := Marshal(pb) b.SetBytes(int64(len(d))) pbd := newOf(pb) b.ResetTimer() for i := 0; i < b.N; i++ { unmarshal(d, pbd) } } func benchmarkBufferUnmarshal(b *testing.B, pb Message) { p := NewBuffer(nil) benchmarkUnmarshal(b, pb, func(d []byte, pb0 Message) error { p.SetBuf(d) return p.Unmarshal(pb0) }) } // Benchmark{Marshal,BufferMarshal,Size,Unmarshal,BufferUnmarshal}{,Bytes} func BenchmarkMarshal(b *testing.B) { benchmarkMarshal(b, testMsg(), Marshal) } func BenchmarkBufferMarshal(b *testing.B) { benchmarkBufferMarshal(b, testMsg()) } func BenchmarkSize(b *testing.B) { benchmarkSize(b, testMsg()) } func BenchmarkUnmarshal(b *testing.B) { benchmarkUnmarshal(b, testMsg(), Unmarshal) } func BenchmarkBufferUnmarshal(b *testing.B) { benchmarkBufferUnmarshal(b, testMsg()) } func BenchmarkMarshalBytes(b *testing.B) { benchmarkMarshal(b, bytesMsg(), Marshal) } func BenchmarkBufferMarshalBytes(b *testing.B) { benchmarkBufferMarshal(b, bytesMsg()) } func BenchmarkSizeBytes(b *testing.B) { benchmarkSize(b, bytesMsg()) } func BenchmarkUnmarshalBytes(b *testing.B) { benchmarkUnmarshal(b, bytesMsg(), Unmarshal) } func BenchmarkBufferUnmarshalBytes(b *testing.B) { benchmarkBufferUnmarshal(b, bytesMsg()) } func BenchmarkUnmarshalUnrecognizedFields(b *testing.B) { b.StopTimer() pb := initGoTestField() skip := &GoSkipTest{ SkipInt32: Int32(32), SkipFixed32: Uint32(3232), SkipFixed64: Uint64(6464), SkipString: String("skipper"), Skipgroup: &GoSkipTest_SkipGroup{ GroupInt32: Int32(75), GroupString: String("wxyz"), }, } pbd := new(GoTestField) p := NewBuffer(nil) p.Marshal(pb) p.Marshal(skip) p2 := NewBuffer(nil) b.StartTimer() for i := 0; i < b.N; i++ { p2.SetBuf(p.Bytes()) p2.Unmarshal(pbd) } } ================================================ FILE: vendor/github.com/golang/protobuf/proto/any_test.go ================================================ // Go support for Protocol Buffers - Google's data interchange format // // Copyright 2016 The Go Authors. All rights reserved. // https://github.com/golang/protobuf // // 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. package proto_test import ( "strings" "testing" "github.com/golang/protobuf/proto" pb "github.com/golang/protobuf/proto/proto3_proto" testpb "github.com/golang/protobuf/proto/testdata" anypb "github.com/golang/protobuf/ptypes/any" ) var ( expandedMarshaler = proto.TextMarshaler{ExpandAny: true} expandedCompactMarshaler = proto.TextMarshaler{Compact: true, ExpandAny: true} ) // anyEqual reports whether two messages which may be google.protobuf.Any or may // contain google.protobuf.Any fields are equal. We can't use proto.Equal for // comparison, because semantically equivalent messages may be marshaled to // binary in different tag order. Instead, trust that TextMarshaler with // ExpandAny option works and compare the text marshaling results. func anyEqual(got, want proto.Message) bool { // if messages are proto.Equal, no need to marshal. if proto.Equal(got, want) { return true } g := expandedMarshaler.Text(got) w := expandedMarshaler.Text(want) return g == w } type golden struct { m proto.Message t, c string } var goldenMessages = makeGolden() func makeGolden() []golden { nested := &pb.Nested{Bunny: "Monty"} nb, err := proto.Marshal(nested) if err != nil { panic(err) } m1 := &pb.Message{ Name: "David", ResultCount: 47, Anything: &anypb.Any{TypeUrl: "type.googleapis.com/" + proto.MessageName(nested), Value: nb}, } m2 := &pb.Message{ Name: "David", ResultCount: 47, Anything: &anypb.Any{TypeUrl: "http://[::1]/type.googleapis.com/" + proto.MessageName(nested), Value: nb}, } m3 := &pb.Message{ Name: "David", ResultCount: 47, Anything: &anypb.Any{TypeUrl: `type.googleapis.com/"/` + proto.MessageName(nested), Value: nb}, } m4 := &pb.Message{ Name: "David", ResultCount: 47, Anything: &anypb.Any{TypeUrl: "type.googleapis.com/a/path/" + proto.MessageName(nested), Value: nb}, } m5 := &anypb.Any{TypeUrl: "type.googleapis.com/" + proto.MessageName(nested), Value: nb} any1 := &testpb.MyMessage{Count: proto.Int32(47), Name: proto.String("David")} proto.SetExtension(any1, testpb.E_Ext_More, &testpb.Ext{Data: proto.String("foo")}) proto.SetExtension(any1, testpb.E_Ext_Text, proto.String("bar")) any1b, err := proto.Marshal(any1) if err != nil { panic(err) } any2 := &testpb.MyMessage{Count: proto.Int32(42), Bikeshed: testpb.MyMessage_GREEN.Enum(), RepBytes: [][]byte{[]byte("roboto")}} proto.SetExtension(any2, testpb.E_Ext_More, &testpb.Ext{Data: proto.String("baz")}) any2b, err := proto.Marshal(any2) if err != nil { panic(err) } m6 := &pb.Message{ Name: "David", ResultCount: 47, Anything: &anypb.Any{TypeUrl: "type.googleapis.com/" + proto.MessageName(any1), Value: any1b}, ManyThings: []*anypb.Any{ &anypb.Any{TypeUrl: "type.googleapis.com/" + proto.MessageName(any2), Value: any2b}, &anypb.Any{TypeUrl: "type.googleapis.com/" + proto.MessageName(any1), Value: any1b}, }, } const ( m1Golden = ` name: "David" result_count: 47 anything: < [type.googleapis.com/proto3_proto.Nested]: < bunny: "Monty" > > ` m2Golden = ` name: "David" result_count: 47 anything: < ["http://[::1]/type.googleapis.com/proto3_proto.Nested"]: < bunny: "Monty" > > ` m3Golden = ` name: "David" result_count: 47 anything: < ["type.googleapis.com/\"/proto3_proto.Nested"]: < bunny: "Monty" > > ` m4Golden = ` name: "David" result_count: 47 anything: < [type.googleapis.com/a/path/proto3_proto.Nested]: < bunny: "Monty" > > ` m5Golden = ` [type.googleapis.com/proto3_proto.Nested]: < bunny: "Monty" > ` m6Golden = ` name: "David" result_count: 47 anything: < [type.googleapis.com/testdata.MyMessage]: < count: 47 name: "David" [testdata.Ext.more]: < data: "foo" > [testdata.Ext.text]: "bar" > > many_things: < [type.googleapis.com/testdata.MyMessage]: < count: 42 bikeshed: GREEN rep_bytes: "roboto" [testdata.Ext.more]: < data: "baz" > > > many_things: < [type.googleapis.com/testdata.MyMessage]: < count: 47 name: "David" [testdata.Ext.more]: < data: "foo" > [testdata.Ext.text]: "bar" > > ` ) return []golden{ {m1, strings.TrimSpace(m1Golden) + "\n", strings.TrimSpace(compact(m1Golden)) + " "}, {m2, strings.TrimSpace(m2Golden) + "\n", strings.TrimSpace(compact(m2Golden)) + " "}, {m3, strings.TrimSpace(m3Golden) + "\n", strings.TrimSpace(compact(m3Golden)) + " "}, {m4, strings.TrimSpace(m4Golden) + "\n", strings.TrimSpace(compact(m4Golden)) + " "}, {m5, strings.TrimSpace(m5Golden) + "\n", strings.TrimSpace(compact(m5Golden)) + " "}, {m6, strings.TrimSpace(m6Golden) + "\n", strings.TrimSpace(compact(m6Golden)) + " "}, } } func TestMarshalGolden(t *testing.T) { for _, tt := range goldenMessages { if got, want := expandedMarshaler.Text(tt.m), tt.t; got != want { t.Errorf("message %v: got:\n%s\nwant:\n%s", tt.m, got, want) } if got, want := expandedCompactMarshaler.Text(tt.m), tt.c; got != want { t.Errorf("message %v: got:\n`%s`\nwant:\n`%s`", tt.m, got, want) } } } func TestUnmarshalGolden(t *testing.T) { for _, tt := range goldenMessages { want := tt.m got := proto.Clone(tt.m) got.Reset() if err := proto.UnmarshalText(tt.t, got); err != nil { t.Errorf("failed to unmarshal\n%s\nerror: %v", tt.t, err) } if !anyEqual(got, want) { t.Errorf("message:\n%s\ngot:\n%s\nwant:\n%s", tt.t, got, want) } got.Reset() if err := proto.UnmarshalText(tt.c, got); err != nil { t.Errorf("failed to unmarshal\n%s\nerror: %v", tt.c, err) } if !anyEqual(got, want) { t.Errorf("message:\n%s\ngot:\n%s\nwant:\n%s", tt.c, got, want) } } } func TestMarshalUnknownAny(t *testing.T) { m := &pb.Message{ Anything: &anypb.Any{ TypeUrl: "foo", Value: []byte("bar"), }, } want := `anything: < type_url: "foo" value: "bar" > ` got := expandedMarshaler.Text(m) if got != want { t.Errorf("got\n`%s`\nwant\n`%s`", got, want) } } func TestAmbiguousAny(t *testing.T) { pb := &anypb.Any{} err := proto.UnmarshalText(` type_url: "ttt/proto3_proto.Nested" value: "\n\x05Monty" `, pb) t.Logf("result: %v (error: %v)", expandedMarshaler.Text(pb), err) if err != nil { t.Errorf("failed to parse ambiguous Any message: %v", err) } } func TestUnmarshalOverwriteAny(t *testing.T) { pb := &anypb.Any{} err := proto.UnmarshalText(` [type.googleapis.com/a/path/proto3_proto.Nested]: < bunny: "Monty" > [type.googleapis.com/a/path/proto3_proto.Nested]: < bunny: "Rabbit of Caerbannog" > `, pb) want := `line 7: Any message unpacked multiple times, or "type_url" already set` if err.Error() != want { t.Errorf("incorrect error.\nHave: %v\nWant: %v", err.Error(), want) } } func TestUnmarshalAnyMixAndMatch(t *testing.T) { pb := &anypb.Any{} err := proto.UnmarshalText(` value: "\n\x05Monty" [type.googleapis.com/a/path/proto3_proto.Nested]: < bunny: "Rabbit of Caerbannog" > `, pb) want := `line 5: Any message unpacked multiple times, or "value" already set` if err.Error() != want { t.Errorf("incorrect error.\nHave: %v\nWant: %v", err.Error(), want) } } ================================================ FILE: vendor/github.com/golang/protobuf/proto/clone.go ================================================ // Go support for Protocol Buffers - Google's data interchange format // // Copyright 2011 The Go Authors. All rights reserved. // https://github.com/golang/protobuf // // 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. // Protocol buffer deep copy and merge. // TODO: RawMessage. package proto import ( "log" "reflect" "strings" ) // Clone returns a deep copy of a protocol buffer. func Clone(pb Message) Message { in := reflect.ValueOf(pb) if in.IsNil() { return pb } out := reflect.New(in.Type().Elem()) // out is empty so a merge is a deep copy. mergeStruct(out.Elem(), in.Elem()) return out.Interface().(Message) } // Merge merges src into dst. // Required and optional fields that are set in src will be set to that value in dst. // Elements of repeated fields will be appended. // Merge panics if src and dst are not the same type, or if dst is nil. func Merge(dst, src Message) { in := reflect.ValueOf(src) out := reflect.ValueOf(dst) if out.IsNil() { panic("proto: nil destination") } if in.Type() != out.Type() { // Explicit test prior to mergeStruct so that mistyped nils will fail panic("proto: type mismatch") } if in.IsNil() { // Merging nil into non-nil is a quiet no-op return } mergeStruct(out.Elem(), in.Elem()) } func mergeStruct(out, in reflect.Value) { sprop := GetProperties(in.Type()) for i := 0; i < in.NumField(); i++ { f := in.Type().Field(i) if strings.HasPrefix(f.Name, "XXX_") { continue } mergeAny(out.Field(i), in.Field(i), false, sprop.Prop[i]) } if emIn, ok := extendable(in.Addr().Interface()); ok { emOut, _ := extendable(out.Addr().Interface()) mIn, muIn := emIn.extensionsRead() if mIn != nil { mOut := emOut.extensionsWrite() muIn.Lock() mergeExtension(mOut, mIn) muIn.Unlock() } } uf := in.FieldByName("XXX_unrecognized") if !uf.IsValid() { return } uin := uf.Bytes() if len(uin) > 0 { out.FieldByName("XXX_unrecognized").SetBytes(append([]byte(nil), uin...)) } } // mergeAny performs a merge between two values of the same type. // viaPtr indicates whether the values were indirected through a pointer (implying proto2). // prop is set if this is a struct field (it may be nil). func mergeAny(out, in reflect.Value, viaPtr bool, prop *Properties) { if in.Type() == protoMessageType { if !in.IsNil() { if out.IsNil() { out.Set(reflect.ValueOf(Clone(in.Interface().(Message)))) } else { Merge(out.Interface().(Message), in.Interface().(Message)) } } return } switch in.Kind() { case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64, reflect.String, reflect.Uint32, reflect.Uint64: if !viaPtr && isProto3Zero(in) { return } out.Set(in) case reflect.Interface: // Probably a oneof field; copy non-nil values. if in.IsNil() { return } // Allocate destination if it is not set, or set to a different type. // Otherwise we will merge as normal. if out.IsNil() || out.Elem().Type() != in.Elem().Type() { out.Set(reflect.New(in.Elem().Elem().Type())) // interface -> *T -> T -> new(T) } mergeAny(out.Elem(), in.Elem(), false, nil) case reflect.Map: if in.Len() == 0 { return } if out.IsNil() { out.Set(reflect.MakeMap(in.Type())) } // For maps with value types of *T or []byte we need to deep copy each value. elemKind := in.Type().Elem().Kind() for _, key := range in.MapKeys() { var val reflect.Value switch elemKind { case reflect.Ptr: val = reflect.New(in.Type().Elem().Elem()) mergeAny(val, in.MapIndex(key), false, nil) case reflect.Slice: val = in.MapIndex(key) val = reflect.ValueOf(append([]byte{}, val.Bytes()...)) default: val = in.MapIndex(key) } out.SetMapIndex(key, val) } case reflect.Ptr: if in.IsNil() { return } if out.IsNil() { out.Set(reflect.New(in.Elem().Type())) } mergeAny(out.Elem(), in.Elem(), true, nil) case reflect.Slice: if in.IsNil() { return } if in.Type().Elem().Kind() == reflect.Uint8 { // []byte is a scalar bytes field, not a repeated field. // Edge case: if this is in a proto3 message, a zero length // bytes field is considered the zero value, and should not // be merged. if prop != nil && prop.proto3 && in.Len() == 0 { return } // Make a deep copy. // Append to []byte{} instead of []byte(nil) so that we never end up // with a nil result. out.SetBytes(append([]byte{}, in.Bytes()...)) return } n := in.Len() if out.IsNil() { out.Set(reflect.MakeSlice(in.Type(), 0, n)) } switch in.Type().Elem().Kind() { case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64, reflect.String, reflect.Uint32, reflect.Uint64: out.Set(reflect.AppendSlice(out, in)) default: for i := 0; i < n; i++ { x := reflect.Indirect(reflect.New(in.Type().Elem())) mergeAny(x, in.Index(i), false, nil) out.Set(reflect.Append(out, x)) } } case reflect.Struct: mergeStruct(out, in) default: // unknown type, so not a protocol buffer log.Printf("proto: don't know how to copy %v", in) } } func mergeExtension(out, in map[int32]Extension) { for extNum, eIn := range in { eOut := Extension{desc: eIn.desc} if eIn.value != nil { v := reflect.New(reflect.TypeOf(eIn.value)).Elem() mergeAny(v, reflect.ValueOf(eIn.value), false, nil) eOut.value = v.Interface() } if eIn.enc != nil { eOut.enc = make([]byte, len(eIn.enc)) copy(eOut.enc, eIn.enc) } out[extNum] = eOut } } ================================================ FILE: vendor/github.com/golang/protobuf/proto/clone_test.go ================================================ // Go support for Protocol Buffers - Google's data interchange format // // Copyright 2011 The Go Authors. All rights reserved. // https://github.com/golang/protobuf // // 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. package proto_test import ( "testing" "github.com/golang/protobuf/proto" proto3pb "github.com/golang/protobuf/proto/proto3_proto" pb "github.com/golang/protobuf/proto/testdata" ) var cloneTestMessage = &pb.MyMessage{ Count: proto.Int32(42), Name: proto.String("Dave"), Pet: []string{"bunny", "kitty", "horsey"}, Inner: &pb.InnerMessage{ Host: proto.String("niles"), Port: proto.Int32(9099), Connected: proto.Bool(true), }, Others: []*pb.OtherMessage{ { Value: []byte("some bytes"), }, }, Somegroup: &pb.MyMessage_SomeGroup{ GroupField: proto.Int32(6), }, RepBytes: [][]byte{[]byte("sham"), []byte("wow")}, } func init() { ext := &pb.Ext{ Data: proto.String("extension"), } if err := proto.SetExtension(cloneTestMessage, pb.E_Ext_More, ext); err != nil { panic("SetExtension: " + err.Error()) } } func TestClone(t *testing.T) { m := proto.Clone(cloneTestMessage).(*pb.MyMessage) if !proto.Equal(m, cloneTestMessage) { t.Errorf("Clone(%v) = %v", cloneTestMessage, m) } // Verify it was a deep copy. *m.Inner.Port++ if proto.Equal(m, cloneTestMessage) { t.Error("Mutating clone changed the original") } // Byte fields and repeated fields should be copied. if &m.Pet[0] == &cloneTestMessage.Pet[0] { t.Error("Pet: repeated field not copied") } if &m.Others[0] == &cloneTestMessage.Others[0] { t.Error("Others: repeated field not copied") } if &m.Others[0].Value[0] == &cloneTestMessage.Others[0].Value[0] { t.Error("Others[0].Value: bytes field not copied") } if &m.RepBytes[0] == &cloneTestMessage.RepBytes[0] { t.Error("RepBytes: repeated field not copied") } if &m.RepBytes[0][0] == &cloneTestMessage.RepBytes[0][0] { t.Error("RepBytes[0]: bytes field not copied") } } func TestCloneNil(t *testing.T) { var m *pb.MyMessage if c := proto.Clone(m); !proto.Equal(m, c) { t.Errorf("Clone(%v) = %v", m, c) } } var mergeTests = []struct { src, dst, want proto.Message }{ { src: &pb.MyMessage{ Count: proto.Int32(42), }, dst: &pb.MyMessage{ Name: proto.String("Dave"), }, want: &pb.MyMessage{ Count: proto.Int32(42), Name: proto.String("Dave"), }, }, { src: &pb.MyMessage{ Inner: &pb.InnerMessage{ Host: proto.String("hey"), Connected: proto.Bool(true), }, Pet: []string{"horsey"}, Others: []*pb.OtherMessage{ { Value: []byte("some bytes"), }, }, }, dst: &pb.MyMessage{ Inner: &pb.InnerMessage{ Host: proto.String("niles"), Port: proto.Int32(9099), }, Pet: []string{"bunny", "kitty"}, Others: []*pb.OtherMessage{ { Key: proto.Int64(31415926535), }, { // Explicitly test a src=nil field Inner: nil, }, }, }, want: &pb.MyMessage{ Inner: &pb.InnerMessage{ Host: proto.String("hey"), Connected: proto.Bool(true), Port: proto.Int32(9099), }, Pet: []string{"bunny", "kitty", "horsey"}, Others: []*pb.OtherMessage{ { Key: proto.Int64(31415926535), }, {}, { Value: []byte("some bytes"), }, }, }, }, { src: &pb.MyMessage{ RepBytes: [][]byte{[]byte("wow")}, }, dst: &pb.MyMessage{ Somegroup: &pb.MyMessage_SomeGroup{ GroupField: proto.Int32(6), }, RepBytes: [][]byte{[]byte("sham")}, }, want: &pb.MyMessage{ Somegroup: &pb.MyMessage_SomeGroup{ GroupField: proto.Int32(6), }, RepBytes: [][]byte{[]byte("sham"), []byte("wow")}, }, }, // Check that a scalar bytes field replaces rather than appends. { src: &pb.OtherMessage{Value: []byte("foo")}, dst: &pb.OtherMessage{Value: []byte("bar")}, want: &pb.OtherMessage{Value: []byte("foo")}, }, { src: &pb.MessageWithMap{ NameMapping: map[int32]string{6: "Nigel"}, MsgMapping: map[int64]*pb.FloatingPoint{ 0x4001: &pb.FloatingPoint{F: proto.Float64(2.0)}, 0x4002: &pb.FloatingPoint{ F: proto.Float64(2.0), }, }, ByteMapping: map[bool][]byte{true: []byte("wowsa")}, }, dst: &pb.MessageWithMap{ NameMapping: map[int32]string{ 6: "Bruce", // should be overwritten 7: "Andrew", }, MsgMapping: map[int64]*pb.FloatingPoint{ 0x4002: &pb.FloatingPoint{ F: proto.Float64(3.0), Exact: proto.Bool(true), }, // the entire message should be overwritten }, }, want: &pb.MessageWithMap{ NameMapping: map[int32]string{ 6: "Nigel", 7: "Andrew", }, MsgMapping: map[int64]*pb.FloatingPoint{ 0x4001: &pb.FloatingPoint{F: proto.Float64(2.0)}, 0x4002: &pb.FloatingPoint{ F: proto.Float64(2.0), }, }, ByteMapping: map[bool][]byte{true: []byte("wowsa")}, }, }, // proto3 shouldn't merge zero values, // in the same way that proto2 shouldn't merge nils. { src: &proto3pb.Message{ Name: "Aaron", Data: []byte(""), // zero value, but not nil }, dst: &proto3pb.Message{ HeightInCm: 176, Data: []byte("texas!"), }, want: &proto3pb.Message{ Name: "Aaron", HeightInCm: 176, Data: []byte("texas!"), }, }, // Oneof fields should merge by assignment. { src: &pb.Communique{ Union: &pb.Communique_Number{41}, }, dst: &pb.Communique{ Union: &pb.Communique_Name{"Bobby Tables"}, }, want: &pb.Communique{ Union: &pb.Communique_Number{41}, }, }, // Oneof nil is the same as not set. { src: &pb.Communique{}, dst: &pb.Communique{ Union: &pb.Communique_Name{"Bobby Tables"}, }, want: &pb.Communique{ Union: &pb.Communique_Name{"Bobby Tables"}, }, }, { src: &proto3pb.Message{ Terrain: map[string]*proto3pb.Nested{ "kay_a": &proto3pb.Nested{Cute: true}, // replace "kay_b": &proto3pb.Nested{Bunny: "rabbit"}, // insert }, }, dst: &proto3pb.Message{ Terrain: map[string]*proto3pb.Nested{ "kay_a": &proto3pb.Nested{Bunny: "lost"}, // replaced "kay_c": &proto3pb.Nested{Bunny: "bunny"}, // keep }, }, want: &proto3pb.Message{ Terrain: map[string]*proto3pb.Nested{ "kay_a": &proto3pb.Nested{Cute: true}, "kay_b": &proto3pb.Nested{Bunny: "rabbit"}, "kay_c": &proto3pb.Nested{Bunny: "bunny"}, }, }, }, } func TestMerge(t *testing.T) { for _, m := range mergeTests { got := proto.Clone(m.dst) proto.Merge(got, m.src) if !proto.Equal(got, m.want) { t.Errorf("Merge(%v, %v)\n got %v\nwant %v\n", m.dst, m.src, got, m.want) } } } ================================================ FILE: vendor/github.com/golang/protobuf/proto/decode.go ================================================ // Go support for Protocol Buffers - Google's data interchange format // // Copyright 2010 The Go Authors. All rights reserved. // https://github.com/golang/protobuf // // 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. package proto /* * Routines for decoding protocol buffer data to construct in-memory representations. */ import ( "errors" "fmt" "io" "os" "reflect" ) // errOverflow is returned when an integer is too large to be represented. var errOverflow = errors.New("proto: integer overflow") // ErrInternalBadWireType is returned by generated code when an incorrect // wire type is encountered. It does not get returned to user code. var ErrInternalBadWireType = errors.New("proto: internal error: bad wiretype for oneof") // The fundamental decoders that interpret bytes on the wire. // Those that take integer types all return uint64 and are // therefore of type valueDecoder. // DecodeVarint reads a varint-encoded integer from the slice. // It returns the integer and the number of bytes consumed, or // zero if there is not enough. // This is the format for the // int32, int64, uint32, uint64, bool, and enum // protocol buffer types. func DecodeVarint(buf []byte) (x uint64, n int) { for shift := uint(0); shift < 64; shift += 7 { if n >= len(buf) { return 0, 0 } b := uint64(buf[n]) n++ x |= (b & 0x7F) << shift if (b & 0x80) == 0 { return x, n } } // The number is too large to represent in a 64-bit value. return 0, 0 } func (p *Buffer) decodeVarintSlow() (x uint64, err error) { i := p.index l := len(p.buf) for shift := uint(0); shift < 64; shift += 7 { if i >= l { err = io.ErrUnexpectedEOF return } b := p.buf[i] i++ x |= (uint64(b) & 0x7F) << shift if b < 0x80 { p.index = i return } } // The number is too large to represent in a 64-bit value. err = errOverflow return } // DecodeVarint reads a varint-encoded integer from the Buffer. // This is the format for the // int32, int64, uint32, uint64, bool, and enum // protocol buffer types. func (p *Buffer) DecodeVarint() (x uint64, err error) { i := p.index buf := p.buf if i >= len(buf) { return 0, io.ErrUnexpectedEOF } else if buf[i] < 0x80 { p.index++ return uint64(buf[i]), nil } else if len(buf)-i < 10 { return p.decodeVarintSlow() } var b uint64 // we already checked the first byte x = uint64(buf[i]) - 0x80 i++ b = uint64(buf[i]) i++ x += b << 7 if b&0x80 == 0 { goto done } x -= 0x80 << 7 b = uint64(buf[i]) i++ x += b << 14 if b&0x80 == 0 { goto done } x -= 0x80 << 14 b = uint64(buf[i]) i++ x += b << 21 if b&0x80 == 0 { goto done } x -= 0x80 << 21 b = uint64(buf[i]) i++ x += b << 28 if b&0x80 == 0 { goto done } x -= 0x80 << 28 b = uint64(buf[i]) i++ x += b << 35 if b&0x80 == 0 { goto done } x -= 0x80 << 35 b = uint64(buf[i]) i++ x += b << 42 if b&0x80 == 0 { goto done } x -= 0x80 << 42 b = uint64(buf[i]) i++ x += b << 49 if b&0x80 == 0 { goto done } x -= 0x80 << 49 b = uint64(buf[i]) i++ x += b << 56 if b&0x80 == 0 { goto done } x -= 0x80 << 56 b = uint64(buf[i]) i++ x += b << 63 if b&0x80 == 0 { goto done } // x -= 0x80 << 63 // Always zero. return 0, errOverflow done: p.index = i return x, nil } // DecodeFixed64 reads a 64-bit integer from the Buffer. // This is the format for the // fixed64, sfixed64, and double protocol buffer types. func (p *Buffer) DecodeFixed64() (x uint64, err error) { // x, err already 0 i := p.index + 8 if i < 0 || i > len(p.buf) { err = io.ErrUnexpectedEOF return } p.index = i x = uint64(p.buf[i-8]) x |= uint64(p.buf[i-7]) << 8 x |= uint64(p.buf[i-6]) << 16 x |= uint64(p.buf[i-5]) << 24 x |= uint64(p.buf[i-4]) << 32 x |= uint64(p.buf[i-3]) << 40 x |= uint64(p.buf[i-2]) << 48 x |= uint64(p.buf[i-1]) << 56 return } // DecodeFixed32 reads a 32-bit integer from the Buffer. // This is the format for the // fixed32, sfixed32, and float protocol buffer types. func (p *Buffer) DecodeFixed32() (x uint64, err error) { // x, err already 0 i := p.index + 4 if i < 0 || i > len(p.buf) { err = io.ErrUnexpectedEOF return } p.index = i x = uint64(p.buf[i-4]) x |= uint64(p.buf[i-3]) << 8 x |= uint64(p.buf[i-2]) << 16 x |= uint64(p.buf[i-1]) << 24 return } // DecodeZigzag64 reads a zigzag-encoded 64-bit integer // from the Buffer. // This is the format used for the sint64 protocol buffer type. func (p *Buffer) DecodeZigzag64() (x uint64, err error) { x, err = p.DecodeVarint() if err != nil { return } x = (x >> 1) ^ uint64((int64(x&1)<<63)>>63) return } // DecodeZigzag32 reads a zigzag-encoded 32-bit integer // from the Buffer. // This is the format used for the sint32 protocol buffer type. func (p *Buffer) DecodeZigzag32() (x uint64, err error) { x, err = p.DecodeVarint() if err != nil { return } x = uint64((uint32(x) >> 1) ^ uint32((int32(x&1)<<31)>>31)) return } // These are not ValueDecoders: they produce an array of bytes or a string. // bytes, embedded messages // DecodeRawBytes reads a count-delimited byte buffer from the Buffer. // This is the format used for the bytes protocol buffer // type and for embedded messages. func (p *Buffer) DecodeRawBytes(alloc bool) (buf []byte, err error) { n, err := p.DecodeVarint() if err != nil { return nil, err } nb := int(n) if nb < 0 { return nil, fmt.Errorf("proto: bad byte length %d", nb) } end := p.index + nb if end < p.index || end > len(p.buf) { return nil, io.ErrUnexpectedEOF } if !alloc { // todo: check if can get more uses of alloc=false buf = p.buf[p.index:end] p.index += nb return } buf = make([]byte, nb) copy(buf, p.buf[p.index:]) p.index += nb return } // DecodeStringBytes reads an encoded string from the Buffer. // This is the format used for the proto2 string type. func (p *Buffer) DecodeStringBytes() (s string, err error) { buf, err := p.DecodeRawBytes(false) if err != nil { return } return string(buf), nil } // Skip the next item in the buffer. Its wire type is decoded and presented as an argument. // If the protocol buffer has extensions, and the field matches, add it as an extension. // Otherwise, if the XXX_unrecognized field exists, append the skipped data there. func (o *Buffer) skipAndSave(t reflect.Type, tag, wire int, base structPointer, unrecField field) error { oi := o.index err := o.skip(t, tag, wire) if err != nil { return err } if !unrecField.IsValid() { return nil } ptr := structPointer_Bytes(base, unrecField) // Add the skipped field to struct field obuf := o.buf o.buf = *ptr o.EncodeVarint(uint64(tag<<3 | wire)) *ptr = append(o.buf, obuf[oi:o.index]...) o.buf = obuf return nil } // Skip the next item in the buffer. Its wire type is decoded and presented as an argument. func (o *Buffer) skip(t reflect.Type, tag, wire int) error { var u uint64 var err error switch wire { case WireVarint: _, err = o.DecodeVarint() case WireFixed64: _, err = o.DecodeFixed64() case WireBytes: _, err = o.DecodeRawBytes(false) case WireFixed32: _, err = o.DecodeFixed32() case WireStartGroup: for { u, err = o.DecodeVarint() if err != nil { break } fwire := int(u & 0x7) if fwire == WireEndGroup { break } ftag := int(u >> 3) err = o.skip(t, ftag, fwire) if err != nil { break } } default: err = fmt.Errorf("proto: can't skip unknown wire type %d for %s", wire, t) } return err } // Unmarshaler is the interface representing objects that can // unmarshal themselves. The method should reset the receiver before // decoding starts. The argument points to data that may be // overwritten, so implementations should not keep references to the // buffer. type Unmarshaler interface { Unmarshal([]byte) error } // Unmarshal parses the protocol buffer representation in buf and places the // decoded result in pb. If the struct underlying pb does not match // the data in buf, the results can be unpredictable. // // Unmarshal resets pb before starting to unmarshal, so any // existing data in pb is always removed. Use UnmarshalMerge // to preserve and append to existing data. func Unmarshal(buf []byte, pb Message) error { pb.Reset() return UnmarshalMerge(buf, pb) } // UnmarshalMerge parses the protocol buffer representation in buf and // writes the decoded result to pb. If the struct underlying pb does not match // the data in buf, the results can be unpredictable. // // UnmarshalMerge merges into existing data in pb. // Most code should use Unmarshal instead. func UnmarshalMerge(buf []byte, pb Message) error { // If the object can unmarshal itself, let it. if u, ok := pb.(Unmarshaler); ok { return u.Unmarshal(buf) } return NewBuffer(buf).Unmarshal(pb) } // DecodeMessage reads a count-delimited message from the Buffer. func (p *Buffer) DecodeMessage(pb Message) error { enc, err := p.DecodeRawBytes(false) if err != nil { return err } return NewBuffer(enc).Unmarshal(pb) } // DecodeGroup reads a tag-delimited group from the Buffer. func (p *Buffer) DecodeGroup(pb Message) error { typ, base, err := getbase(pb) if err != nil { return err } return p.unmarshalType(typ.Elem(), GetProperties(typ.Elem()), true, base) } // Unmarshal parses the protocol buffer representation in the // Buffer and places the decoded result in pb. If the struct // underlying pb does not match the data in the buffer, the results can be // unpredictable. // // Unlike proto.Unmarshal, this does not reset pb before starting to unmarshal. func (p *Buffer) Unmarshal(pb Message) error { // If the object can unmarshal itself, let it. if u, ok := pb.(Unmarshaler); ok { err := u.Unmarshal(p.buf[p.index:]) p.index = len(p.buf) return err } typ, base, err := getbase(pb) if err != nil { return err } err = p.unmarshalType(typ.Elem(), GetProperties(typ.Elem()), false, base) if collectStats { stats.Decode++ } return err } // unmarshalType does the work of unmarshaling a structure. func (o *Buffer) unmarshalType(st reflect.Type, prop *StructProperties, is_group bool, base structPointer) error { var state errorState required, reqFields := prop.reqCount, uint64(0) var err error for err == nil && o.index < len(o.buf) { oi := o.index var u uint64 u, err = o.DecodeVarint() if err != nil { break } wire := int(u & 0x7) if wire == WireEndGroup { if is_group { if required > 0 { // Not enough information to determine the exact field. // (See below.) return &RequiredNotSetError{"{Unknown}"} } return nil // input is satisfied } return fmt.Errorf("proto: %s: wiretype end group for non-group", st) } tag := int(u >> 3) if tag <= 0 { return fmt.Errorf("proto: %s: illegal tag %d (wire type %d)", st, tag, wire) } fieldnum, ok := prop.decoderTags.get(tag) if !ok { // Maybe it's an extension? if prop.extendable { if e, _ := extendable(structPointer_Interface(base, st)); isExtensionField(e, int32(tag)) { if err = o.skip(st, tag, wire); err == nil { extmap := e.extensionsWrite() ext := extmap[int32(tag)] // may be missing ext.enc = append(ext.enc, o.buf[oi:o.index]...) extmap[int32(tag)] = ext } continue } } // Maybe it's a oneof? if prop.oneofUnmarshaler != nil { m := structPointer_Interface(base, st).(Message) // First return value indicates whether tag is a oneof field. ok, err = prop.oneofUnmarshaler(m, tag, wire, o) if err == ErrInternalBadWireType { // Map the error to something more descriptive. // Do the formatting here to save generated code space. err = fmt.Errorf("bad wiretype for oneof field in %T", m) } if ok { continue } } err = o.skipAndSave(st, tag, wire, base, prop.unrecField) continue } p := prop.Prop[fieldnum] if p.dec == nil { fmt.Fprintf(os.Stderr, "proto: no protobuf decoder for %s.%s\n", st, st.Field(fieldnum).Name) continue } dec := p.dec if wire != WireStartGroup && wire != p.WireType { if wire == WireBytes && p.packedDec != nil { // a packable field dec = p.packedDec } else { err = fmt.Errorf("proto: bad wiretype for field %s.%s: got wiretype %d, want %d", st, st.Field(fieldnum).Name, wire, p.WireType) continue } } decErr := dec(o, p, base) if decErr != nil && !state.shouldContinue(decErr, p) { err = decErr } if err == nil && p.Required { // Successfully decoded a required field. if tag <= 64 { // use bitmap for fields 1-64 to catch field reuse. var mask uint64 = 1 << uint64(tag-1) if reqFields&mask == 0 { // new required field reqFields |= mask required-- } } else { // This is imprecise. It can be fooled by a required field // with a tag > 64 that is encoded twice; that's very rare. // A fully correct implementation would require allocating // a data structure, which we would like to avoid. required-- } } } if err == nil { if is_group { return io.ErrUnexpectedEOF } if state.err != nil { return state.err } if required > 0 { // Not enough information to determine the exact field. If we use extra // CPU, we could determine the field only if the missing required field // has a tag <= 64 and we check reqFields. return &RequiredNotSetError{"{Unknown}"} } } return err } // Individual type decoders // For each, // u is the decoded value, // v is a pointer to the field (pointer) in the struct // Sizes of the pools to allocate inside the Buffer. // The goal is modest amortization and allocation // on at least 16-byte boundaries. const ( boolPoolSize = 16 uint32PoolSize = 8 uint64PoolSize = 4 ) // Decode a bool. func (o *Buffer) dec_bool(p *Properties, base structPointer) error { u, err := p.valDec(o) if err != nil { return err } if len(o.bools) == 0 { o.bools = make([]bool, boolPoolSize) } o.bools[0] = u != 0 *structPointer_Bool(base, p.field) = &o.bools[0] o.bools = o.bools[1:] return nil } func (o *Buffer) dec_proto3_bool(p *Properties, base structPointer) error { u, err := p.valDec(o) if err != nil { return err } *structPointer_BoolVal(base, p.field) = u != 0 return nil } // Decode an int32. func (o *Buffer) dec_int32(p *Properties, base structPointer) error { u, err := p.valDec(o) if err != nil { return err } word32_Set(structPointer_Word32(base, p.field), o, uint32(u)) return nil } func (o *Buffer) dec_proto3_int32(p *Properties, base structPointer) error { u, err := p.valDec(o) if err != nil { return err } word32Val_Set(structPointer_Word32Val(base, p.field), uint32(u)) return nil } // Decode an int64. func (o *Buffer) dec_int64(p *Properties, base structPointer) error { u, err := p.valDec(o) if err != nil { return err } word64_Set(structPointer_Word64(base, p.field), o, u) return nil } func (o *Buffer) dec_proto3_int64(p *Properties, base structPointer) error { u, err := p.valDec(o) if err != nil { return err } word64Val_Set(structPointer_Word64Val(base, p.field), o, u) return nil } // Decode a string. func (o *Buffer) dec_string(p *Properties, base structPointer) error { s, err := o.DecodeStringBytes() if err != nil { return err } *structPointer_String(base, p.field) = &s return nil } func (o *Buffer) dec_proto3_string(p *Properties, base structPointer) error { s, err := o.DecodeStringBytes() if err != nil { return err } *structPointer_StringVal(base, p.field) = s return nil } // Decode a slice of bytes ([]byte). func (o *Buffer) dec_slice_byte(p *Properties, base structPointer) error { b, err := o.DecodeRawBytes(true) if err != nil { return err } *structPointer_Bytes(base, p.field) = b return nil } // Decode a slice of bools ([]bool). func (o *Buffer) dec_slice_bool(p *Properties, base structPointer) error { u, err := p.valDec(o) if err != nil { return err } v := structPointer_BoolSlice(base, p.field) *v = append(*v, u != 0) return nil } // Decode a slice of bools ([]bool) in packed format. func (o *Buffer) dec_slice_packed_bool(p *Properties, base structPointer) error { v := structPointer_BoolSlice(base, p.field) nn, err := o.DecodeVarint() if err != nil { return err } nb := int(nn) // number of bytes of encoded bools fin := o.index + nb if fin < o.index { return errOverflow } y := *v for o.index < fin { u, err := p.valDec(o) if err != nil { return err } y = append(y, u != 0) } *v = y return nil } // Decode a slice of int32s ([]int32). func (o *Buffer) dec_slice_int32(p *Properties, base structPointer) error { u, err := p.valDec(o) if err != nil { return err } structPointer_Word32Slice(base, p.field).Append(uint32(u)) return nil } // Decode a slice of int32s ([]int32) in packed format. func (o *Buffer) dec_slice_packed_int32(p *Properties, base structPointer) error { v := structPointer_Word32Slice(base, p.field) nn, err := o.DecodeVarint() if err != nil { return err } nb := int(nn) // number of bytes of encoded int32s fin := o.index + nb if fin < o.index { return errOverflow } for o.index < fin { u, err := p.valDec(o) if err != nil { return err } v.Append(uint32(u)) } return nil } // Decode a slice of int64s ([]int64). func (o *Buffer) dec_slice_int64(p *Properties, base structPointer) error { u, err := p.valDec(o) if err != nil { return err } structPointer_Word64Slice(base, p.field).Append(u) return nil } // Decode a slice of int64s ([]int64) in packed format. func (o *Buffer) dec_slice_packed_int64(p *Properties, base structPointer) error { v := structPointer_Word64Slice(base, p.field) nn, err := o.DecodeVarint() if err != nil { return err } nb := int(nn) // number of bytes of encoded int64s fin := o.index + nb if fin < o.index { return errOverflow } for o.index < fin { u, err := p.valDec(o) if err != nil { return err } v.Append(u) } return nil } // Decode a slice of strings ([]string). func (o *Buffer) dec_slice_string(p *Properties, base structPointer) error { s, err := o.DecodeStringBytes() if err != nil { return err } v := structPointer_StringSlice(base, p.field) *v = append(*v, s) return nil } // Decode a slice of slice of bytes ([][]byte). func (o *Buffer) dec_slice_slice_byte(p *Properties, base structPointer) error { b, err := o.DecodeRawBytes(true) if err != nil { return err } v := structPointer_BytesSlice(base, p.field) *v = append(*v, b) return nil } // Decode a map field. func (o *Buffer) dec_new_map(p *Properties, base structPointer) error { raw, err := o.DecodeRawBytes(false) if err != nil { return err } oi := o.index // index at the end of this map entry o.index -= len(raw) // move buffer back to start of map entry mptr := structPointer_NewAt(base, p.field, p.mtype) // *map[K]V if mptr.Elem().IsNil() { mptr.Elem().Set(reflect.MakeMap(mptr.Type().Elem())) } v := mptr.Elem() // map[K]V // Prepare addressable doubly-indirect placeholders for the key and value types. // See enc_new_map for why. keyptr := reflect.New(reflect.PtrTo(p.mtype.Key())).Elem() // addressable *K keybase := toStructPointer(keyptr.Addr()) // **K var valbase structPointer var valptr reflect.Value switch p.mtype.Elem().Kind() { case reflect.Slice: // []byte var dummy []byte valptr = reflect.ValueOf(&dummy) // *[]byte valbase = toStructPointer(valptr) // *[]byte case reflect.Ptr: // message; valptr is **Msg; need to allocate the intermediate pointer valptr = reflect.New(reflect.PtrTo(p.mtype.Elem())).Elem() // addressable *V valptr.Set(reflect.New(valptr.Type().Elem())) valbase = toStructPointer(valptr) default: // everything else valptr = reflect.New(reflect.PtrTo(p.mtype.Elem())).Elem() // addressable *V valbase = toStructPointer(valptr.Addr()) // **V } // Decode. // This parses a restricted wire format, namely the encoding of a message // with two fields. See enc_new_map for the format. for o.index < oi { // tagcode for key and value properties are always a single byte // because they have tags 1 and 2. tagcode := o.buf[o.index] o.index++ switch tagcode { case p.mkeyprop.tagcode[0]: if err := p.mkeyprop.dec(o, p.mkeyprop, keybase); err != nil { return err } case p.mvalprop.tagcode[0]: if err := p.mvalprop.dec(o, p.mvalprop, valbase); err != nil { return err } default: // TODO: Should we silently skip this instead? return fmt.Errorf("proto: bad map data tag %d", raw[0]) } } keyelem, valelem := keyptr.Elem(), valptr.Elem() if !keyelem.IsValid() { keyelem = reflect.Zero(p.mtype.Key()) } if !valelem.IsValid() { valelem = reflect.Zero(p.mtype.Elem()) } v.SetMapIndex(keyelem, valelem) return nil } // Decode a group. func (o *Buffer) dec_struct_group(p *Properties, base structPointer) error { bas := structPointer_GetStructPointer(base, p.field) if structPointer_IsNil(bas) { // allocate new nested message bas = toStructPointer(reflect.New(p.stype)) structPointer_SetStructPointer(base, p.field, bas) } return o.unmarshalType(p.stype, p.sprop, true, bas) } // Decode an embedded message. func (o *Buffer) dec_struct_message(p *Properties, base structPointer) (err error) { raw, e := o.DecodeRawBytes(false) if e != nil { return e } bas := structPointer_GetStructPointer(base, p.field) if structPointer_IsNil(bas) { // allocate new nested message bas = toStructPointer(reflect.New(p.stype)) structPointer_SetStructPointer(base, p.field, bas) } // If the object can unmarshal itself, let it. if p.isUnmarshaler { iv := structPointer_Interface(bas, p.stype) return iv.(Unmarshaler).Unmarshal(raw) } obuf := o.buf oi := o.index o.buf = raw o.index = 0 err = o.unmarshalType(p.stype, p.sprop, false, bas) o.buf = obuf o.index = oi return err } // Decode a slice of embedded messages. func (o *Buffer) dec_slice_struct_message(p *Properties, base structPointer) error { return o.dec_slice_struct(p, false, base) } // Decode a slice of embedded groups. func (o *Buffer) dec_slice_struct_group(p *Properties, base structPointer) error { return o.dec_slice_struct(p, true, base) } // Decode a slice of structs ([]*struct). func (o *Buffer) dec_slice_struct(p *Properties, is_group bool, base structPointer) error { v := reflect.New(p.stype) bas := toStructPointer(v) structPointer_StructPointerSlice(base, p.field).Append(bas) if is_group { err := o.unmarshalType(p.stype, p.sprop, is_group, bas) return err } raw, err := o.DecodeRawBytes(false) if err != nil { return err } // If the object can unmarshal itself, let it. if p.isUnmarshaler { iv := v.Interface() return iv.(Unmarshaler).Unmarshal(raw) } obuf := o.buf oi := o.index o.buf = raw o.index = 0 err = o.unmarshalType(p.stype, p.sprop, is_group, bas) o.buf = obuf o.index = oi return err } ================================================ FILE: vendor/github.com/golang/protobuf/proto/decode_test.go ================================================ // Go support for Protocol Buffers - Google's data interchange format // // Copyright 2010 The Go Authors. All rights reserved. // https://github.com/golang/protobuf // // 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. // +build go1.7 package proto_test import ( "fmt" "testing" "github.com/golang/protobuf/proto" tpb "github.com/golang/protobuf/proto/proto3_proto" ) var ( bytesBlackhole []byte msgBlackhole = new(tpb.Message) ) // BenchmarkVarint32ArraySmall shows the performance on an array of small int32 fields (1 and // 2 bytes long). func BenchmarkVarint32ArraySmall(b *testing.B) { for i := uint(1); i <= 10; i++ { dist := genInt32Dist([7]int{0, 3, 1}, 1<2GB. ErrTooLarge = errors.New("proto: message encodes to over 2 GB") ) // The fundamental encoders that put bytes on the wire. // Those that take integer types all accept uint64 and are // therefore of type valueEncoder. const maxVarintBytes = 10 // maximum length of a varint // maxMarshalSize is the largest allowed size of an encoded protobuf, // since C++ and Java use signed int32s for the size. const maxMarshalSize = 1<<31 - 1 // EncodeVarint returns the varint encoding of x. // This is the format for the // int32, int64, uint32, uint64, bool, and enum // protocol buffer types. // Not used by the package itself, but helpful to clients // wishing to use the same encoding. func EncodeVarint(x uint64) []byte { var buf [maxVarintBytes]byte var n int for n = 0; x > 127; n++ { buf[n] = 0x80 | uint8(x&0x7F) x >>= 7 } buf[n] = uint8(x) n++ return buf[0:n] } // EncodeVarint writes a varint-encoded integer to the Buffer. // This is the format for the // int32, int64, uint32, uint64, bool, and enum // protocol buffer types. func (p *Buffer) EncodeVarint(x uint64) error { for x >= 1<<7 { p.buf = append(p.buf, uint8(x&0x7f|0x80)) x >>= 7 } p.buf = append(p.buf, uint8(x)) return nil } // SizeVarint returns the varint encoding size of an integer. func SizeVarint(x uint64) int { return sizeVarint(x) } func sizeVarint(x uint64) (n int) { for { n++ x >>= 7 if x == 0 { break } } return n } // EncodeFixed64 writes a 64-bit integer to the Buffer. // This is the format for the // fixed64, sfixed64, and double protocol buffer types. func (p *Buffer) EncodeFixed64(x uint64) error { p.buf = append(p.buf, uint8(x), uint8(x>>8), uint8(x>>16), uint8(x>>24), uint8(x>>32), uint8(x>>40), uint8(x>>48), uint8(x>>56)) return nil } func sizeFixed64(x uint64) int { return 8 } // EncodeFixed32 writes a 32-bit integer to the Buffer. // This is the format for the // fixed32, sfixed32, and float protocol buffer types. func (p *Buffer) EncodeFixed32(x uint64) error { p.buf = append(p.buf, uint8(x), uint8(x>>8), uint8(x>>16), uint8(x>>24)) return nil } func sizeFixed32(x uint64) int { return 4 } // EncodeZigzag64 writes a zigzag-encoded 64-bit integer // to the Buffer. // This is the format used for the sint64 protocol buffer type. func (p *Buffer) EncodeZigzag64(x uint64) error { // use signed number to get arithmetic right shift. return p.EncodeVarint((x << 1) ^ uint64((int64(x) >> 63))) } func sizeZigzag64(x uint64) int { return sizeVarint((x << 1) ^ uint64((int64(x) >> 63))) } // EncodeZigzag32 writes a zigzag-encoded 32-bit integer // to the Buffer. // This is the format used for the sint32 protocol buffer type. func (p *Buffer) EncodeZigzag32(x uint64) error { // use signed number to get arithmetic right shift. return p.EncodeVarint(uint64((uint32(x) << 1) ^ uint32((int32(x) >> 31)))) } func sizeZigzag32(x uint64) int { return sizeVarint(uint64((uint32(x) << 1) ^ uint32((int32(x) >> 31)))) } // EncodeRawBytes writes a count-delimited byte buffer to the Buffer. // This is the format used for the bytes protocol buffer // type and for embedded messages. func (p *Buffer) EncodeRawBytes(b []byte) error { p.EncodeVarint(uint64(len(b))) p.buf = append(p.buf, b...) return nil } func sizeRawBytes(b []byte) int { return sizeVarint(uint64(len(b))) + len(b) } // EncodeStringBytes writes an encoded string to the Buffer. // This is the format used for the proto2 string type. func (p *Buffer) EncodeStringBytes(s string) error { p.EncodeVarint(uint64(len(s))) p.buf = append(p.buf, s...) return nil } func sizeStringBytes(s string) int { return sizeVarint(uint64(len(s))) + len(s) } // Marshaler is the interface representing objects that can marshal themselves. type Marshaler interface { Marshal() ([]byte, error) } // Marshal takes the protocol buffer // and encodes it into the wire format, returning the data. func Marshal(pb Message) ([]byte, error) { // Can the object marshal itself? if m, ok := pb.(Marshaler); ok { return m.Marshal() } p := NewBuffer(nil) err := p.Marshal(pb) if p.buf == nil && err == nil { // Return a non-nil slice on success. return []byte{}, nil } return p.buf, err } // EncodeMessage writes the protocol buffer to the Buffer, // prefixed by a varint-encoded length. func (p *Buffer) EncodeMessage(pb Message) error { t, base, err := getbase(pb) if structPointer_IsNil(base) { return ErrNil } if err == nil { var state errorState err = p.enc_len_struct(GetProperties(t.Elem()), base, &state) } return err } // Marshal takes the protocol buffer // and encodes it into the wire format, writing the result to the // Buffer. func (p *Buffer) Marshal(pb Message) error { // Can the object marshal itself? if m, ok := pb.(Marshaler); ok { data, err := m.Marshal() p.buf = append(p.buf, data...) return err } t, base, err := getbase(pb) if structPointer_IsNil(base) { return ErrNil } if err == nil { err = p.enc_struct(GetProperties(t.Elem()), base) } if collectStats { (stats).Encode++ // Parens are to work around a goimports bug. } if len(p.buf) > maxMarshalSize { return ErrTooLarge } return err } // Size returns the encoded size of a protocol buffer. func Size(pb Message) (n int) { // Can the object marshal itself? If so, Size is slow. // TODO: add Size to Marshaler, or add a Sizer interface. if m, ok := pb.(Marshaler); ok { b, _ := m.Marshal() return len(b) } t, base, err := getbase(pb) if structPointer_IsNil(base) { return 0 } if err == nil { n = size_struct(GetProperties(t.Elem()), base) } if collectStats { (stats).Size++ // Parens are to work around a goimports bug. } return } // Individual type encoders. // Encode a bool. func (o *Buffer) enc_bool(p *Properties, base structPointer) error { v := *structPointer_Bool(base, p.field) if v == nil { return ErrNil } x := 0 if *v { x = 1 } o.buf = append(o.buf, p.tagcode...) p.valEnc(o, uint64(x)) return nil } func (o *Buffer) enc_proto3_bool(p *Properties, base structPointer) error { v := *structPointer_BoolVal(base, p.field) if !v { return ErrNil } o.buf = append(o.buf, p.tagcode...) p.valEnc(o, 1) return nil } func size_bool(p *Properties, base structPointer) int { v := *structPointer_Bool(base, p.field) if v == nil { return 0 } return len(p.tagcode) + 1 // each bool takes exactly one byte } func size_proto3_bool(p *Properties, base structPointer) int { v := *structPointer_BoolVal(base, p.field) if !v && !p.oneof { return 0 } return len(p.tagcode) + 1 // each bool takes exactly one byte } // Encode an int32. func (o *Buffer) enc_int32(p *Properties, base structPointer) error { v := structPointer_Word32(base, p.field) if word32_IsNil(v) { return ErrNil } x := int32(word32_Get(v)) // permit sign extension to use full 64-bit range o.buf = append(o.buf, p.tagcode...) p.valEnc(o, uint64(x)) return nil } func (o *Buffer) enc_proto3_int32(p *Properties, base structPointer) error { v := structPointer_Word32Val(base, p.field) x := int32(word32Val_Get(v)) // permit sign extension to use full 64-bit range if x == 0 { return ErrNil } o.buf = append(o.buf, p.tagcode...) p.valEnc(o, uint64(x)) return nil } func size_int32(p *Properties, base structPointer) (n int) { v := structPointer_Word32(base, p.field) if word32_IsNil(v) { return 0 } x := int32(word32_Get(v)) // permit sign extension to use full 64-bit range n += len(p.tagcode) n += p.valSize(uint64(x)) return } func size_proto3_int32(p *Properties, base structPointer) (n int) { v := structPointer_Word32Val(base, p.field) x := int32(word32Val_Get(v)) // permit sign extension to use full 64-bit range if x == 0 && !p.oneof { return 0 } n += len(p.tagcode) n += p.valSize(uint64(x)) return } // Encode a uint32. // Exactly the same as int32, except for no sign extension. func (o *Buffer) enc_uint32(p *Properties, base structPointer) error { v := structPointer_Word32(base, p.field) if word32_IsNil(v) { return ErrNil } x := word32_Get(v) o.buf = append(o.buf, p.tagcode...) p.valEnc(o, uint64(x)) return nil } func (o *Buffer) enc_proto3_uint32(p *Properties, base structPointer) error { v := structPointer_Word32Val(base, p.field) x := word32Val_Get(v) if x == 0 { return ErrNil } o.buf = append(o.buf, p.tagcode...) p.valEnc(o, uint64(x)) return nil } func size_uint32(p *Properties, base structPointer) (n int) { v := structPointer_Word32(base, p.field) if word32_IsNil(v) { return 0 } x := word32_Get(v) n += len(p.tagcode) n += p.valSize(uint64(x)) return } func size_proto3_uint32(p *Properties, base structPointer) (n int) { v := structPointer_Word32Val(base, p.field) x := word32Val_Get(v) if x == 0 && !p.oneof { return 0 } n += len(p.tagcode) n += p.valSize(uint64(x)) return } // Encode an int64. func (o *Buffer) enc_int64(p *Properties, base structPointer) error { v := structPointer_Word64(base, p.field) if word64_IsNil(v) { return ErrNil } x := word64_Get(v) o.buf = append(o.buf, p.tagcode...) p.valEnc(o, x) return nil } func (o *Buffer) enc_proto3_int64(p *Properties, base structPointer) error { v := structPointer_Word64Val(base, p.field) x := word64Val_Get(v) if x == 0 { return ErrNil } o.buf = append(o.buf, p.tagcode...) p.valEnc(o, x) return nil } func size_int64(p *Properties, base structPointer) (n int) { v := structPointer_Word64(base, p.field) if word64_IsNil(v) { return 0 } x := word64_Get(v) n += len(p.tagcode) n += p.valSize(x) return } func size_proto3_int64(p *Properties, base structPointer) (n int) { v := structPointer_Word64Val(base, p.field) x := word64Val_Get(v) if x == 0 && !p.oneof { return 0 } n += len(p.tagcode) n += p.valSize(x) return } // Encode a string. func (o *Buffer) enc_string(p *Properties, base structPointer) error { v := *structPointer_String(base, p.field) if v == nil { return ErrNil } x := *v o.buf = append(o.buf, p.tagcode...) o.EncodeStringBytes(x) return nil } func (o *Buffer) enc_proto3_string(p *Properties, base structPointer) error { v := *structPointer_StringVal(base, p.field) if v == "" { return ErrNil } o.buf = append(o.buf, p.tagcode...) o.EncodeStringBytes(v) return nil } func size_string(p *Properties, base structPointer) (n int) { v := *structPointer_String(base, p.field) if v == nil { return 0 } x := *v n += len(p.tagcode) n += sizeStringBytes(x) return } func size_proto3_string(p *Properties, base structPointer) (n int) { v := *structPointer_StringVal(base, p.field) if v == "" && !p.oneof { return 0 } n += len(p.tagcode) n += sizeStringBytes(v) return } // All protocol buffer fields are nillable, but be careful. func isNil(v reflect.Value) bool { switch v.Kind() { case reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: return v.IsNil() } return false } // Encode a message struct. func (o *Buffer) enc_struct_message(p *Properties, base structPointer) error { var state errorState structp := structPointer_GetStructPointer(base, p.field) if structPointer_IsNil(structp) { return ErrNil } // Can the object marshal itself? if p.isMarshaler { m := structPointer_Interface(structp, p.stype).(Marshaler) data, err := m.Marshal() if err != nil && !state.shouldContinue(err, nil) { return err } o.buf = append(o.buf, p.tagcode...) o.EncodeRawBytes(data) return state.err } o.buf = append(o.buf, p.tagcode...) return o.enc_len_struct(p.sprop, structp, &state) } func size_struct_message(p *Properties, base structPointer) int { structp := structPointer_GetStructPointer(base, p.field) if structPointer_IsNil(structp) { return 0 } // Can the object marshal itself? if p.isMarshaler { m := structPointer_Interface(structp, p.stype).(Marshaler) data, _ := m.Marshal() n0 := len(p.tagcode) n1 := sizeRawBytes(data) return n0 + n1 } n0 := len(p.tagcode) n1 := size_struct(p.sprop, structp) n2 := sizeVarint(uint64(n1)) // size of encoded length return n0 + n1 + n2 } // Encode a group struct. func (o *Buffer) enc_struct_group(p *Properties, base structPointer) error { var state errorState b := structPointer_GetStructPointer(base, p.field) if structPointer_IsNil(b) { return ErrNil } o.EncodeVarint(uint64((p.Tag << 3) | WireStartGroup)) err := o.enc_struct(p.sprop, b) if err != nil && !state.shouldContinue(err, nil) { return err } o.EncodeVarint(uint64((p.Tag << 3) | WireEndGroup)) return state.err } func size_struct_group(p *Properties, base structPointer) (n int) { b := structPointer_GetStructPointer(base, p.field) if structPointer_IsNil(b) { return 0 } n += sizeVarint(uint64((p.Tag << 3) | WireStartGroup)) n += size_struct(p.sprop, b) n += sizeVarint(uint64((p.Tag << 3) | WireEndGroup)) return } // Encode a slice of bools ([]bool). func (o *Buffer) enc_slice_bool(p *Properties, base structPointer) error { s := *structPointer_BoolSlice(base, p.field) l := len(s) if l == 0 { return ErrNil } for _, x := range s { o.buf = append(o.buf, p.tagcode...) v := uint64(0) if x { v = 1 } p.valEnc(o, v) } return nil } func size_slice_bool(p *Properties, base structPointer) int { s := *structPointer_BoolSlice(base, p.field) l := len(s) if l == 0 { return 0 } return l * (len(p.tagcode) + 1) // each bool takes exactly one byte } // Encode a slice of bools ([]bool) in packed format. func (o *Buffer) enc_slice_packed_bool(p *Properties, base structPointer) error { s := *structPointer_BoolSlice(base, p.field) l := len(s) if l == 0 { return ErrNil } o.buf = append(o.buf, p.tagcode...) o.EncodeVarint(uint64(l)) // each bool takes exactly one byte for _, x := range s { v := uint64(0) if x { v = 1 } p.valEnc(o, v) } return nil } func size_slice_packed_bool(p *Properties, base structPointer) (n int) { s := *structPointer_BoolSlice(base, p.field) l := len(s) if l == 0 { return 0 } n += len(p.tagcode) n += sizeVarint(uint64(l)) n += l // each bool takes exactly one byte return } // Encode a slice of bytes ([]byte). func (o *Buffer) enc_slice_byte(p *Properties, base structPointer) error { s := *structPointer_Bytes(base, p.field) if s == nil { return ErrNil } o.buf = append(o.buf, p.tagcode...) o.EncodeRawBytes(s) return nil } func (o *Buffer) enc_proto3_slice_byte(p *Properties, base structPointer) error { s := *structPointer_Bytes(base, p.field) if len(s) == 0 { return ErrNil } o.buf = append(o.buf, p.tagcode...) o.EncodeRawBytes(s) return nil } func size_slice_byte(p *Properties, base structPointer) (n int) { s := *structPointer_Bytes(base, p.field) if s == nil && !p.oneof { return 0 } n += len(p.tagcode) n += sizeRawBytes(s) return } func size_proto3_slice_byte(p *Properties, base structPointer) (n int) { s := *structPointer_Bytes(base, p.field) if len(s) == 0 && !p.oneof { return 0 } n += len(p.tagcode) n += sizeRawBytes(s) return } // Encode a slice of int32s ([]int32). func (o *Buffer) enc_slice_int32(p *Properties, base structPointer) error { s := structPointer_Word32Slice(base, p.field) l := s.Len() if l == 0 { return ErrNil } for i := 0; i < l; i++ { o.buf = append(o.buf, p.tagcode...) x := int32(s.Index(i)) // permit sign extension to use full 64-bit range p.valEnc(o, uint64(x)) } return nil } func size_slice_int32(p *Properties, base structPointer) (n int) { s := structPointer_Word32Slice(base, p.field) l := s.Len() if l == 0 { return 0 } for i := 0; i < l; i++ { n += len(p.tagcode) x := int32(s.Index(i)) // permit sign extension to use full 64-bit range n += p.valSize(uint64(x)) } return } // Encode a slice of int32s ([]int32) in packed format. func (o *Buffer) enc_slice_packed_int32(p *Properties, base structPointer) error { s := structPointer_Word32Slice(base, p.field) l := s.Len() if l == 0 { return ErrNil } // TODO: Reuse a Buffer. buf := NewBuffer(nil) for i := 0; i < l; i++ { x := int32(s.Index(i)) // permit sign extension to use full 64-bit range p.valEnc(buf, uint64(x)) } o.buf = append(o.buf, p.tagcode...) o.EncodeVarint(uint64(len(buf.buf))) o.buf = append(o.buf, buf.buf...) return nil } func size_slice_packed_int32(p *Properties, base structPointer) (n int) { s := structPointer_Word32Slice(base, p.field) l := s.Len() if l == 0 { return 0 } var bufSize int for i := 0; i < l; i++ { x := int32(s.Index(i)) // permit sign extension to use full 64-bit range bufSize += p.valSize(uint64(x)) } n += len(p.tagcode) n += sizeVarint(uint64(bufSize)) n += bufSize return } // Encode a slice of uint32s ([]uint32). // Exactly the same as int32, except for no sign extension. func (o *Buffer) enc_slice_uint32(p *Properties, base structPointer) error { s := structPointer_Word32Slice(base, p.field) l := s.Len() if l == 0 { return ErrNil } for i := 0; i < l; i++ { o.buf = append(o.buf, p.tagcode...) x := s.Index(i) p.valEnc(o, uint64(x)) } return nil } func size_slice_uint32(p *Properties, base structPointer) (n int) { s := structPointer_Word32Slice(base, p.field) l := s.Len() if l == 0 { return 0 } for i := 0; i < l; i++ { n += len(p.tagcode) x := s.Index(i) n += p.valSize(uint64(x)) } return } // Encode a slice of uint32s ([]uint32) in packed format. // Exactly the same as int32, except for no sign extension. func (o *Buffer) enc_slice_packed_uint32(p *Properties, base structPointer) error { s := structPointer_Word32Slice(base, p.field) l := s.Len() if l == 0 { return ErrNil } // TODO: Reuse a Buffer. buf := NewBuffer(nil) for i := 0; i < l; i++ { p.valEnc(buf, uint64(s.Index(i))) } o.buf = append(o.buf, p.tagcode...) o.EncodeVarint(uint64(len(buf.buf))) o.buf = append(o.buf, buf.buf...) return nil } func size_slice_packed_uint32(p *Properties, base structPointer) (n int) { s := structPointer_Word32Slice(base, p.field) l := s.Len() if l == 0 { return 0 } var bufSize int for i := 0; i < l; i++ { bufSize += p.valSize(uint64(s.Index(i))) } n += len(p.tagcode) n += sizeVarint(uint64(bufSize)) n += bufSize return } // Encode a slice of int64s ([]int64). func (o *Buffer) enc_slice_int64(p *Properties, base structPointer) error { s := structPointer_Word64Slice(base, p.field) l := s.Len() if l == 0 { return ErrNil } for i := 0; i < l; i++ { o.buf = append(o.buf, p.tagcode...) p.valEnc(o, s.Index(i)) } return nil } func size_slice_int64(p *Properties, base structPointer) (n int) { s := structPointer_Word64Slice(base, p.field) l := s.Len() if l == 0 { return 0 } for i := 0; i < l; i++ { n += len(p.tagcode) n += p.valSize(s.Index(i)) } return } // Encode a slice of int64s ([]int64) in packed format. func (o *Buffer) enc_slice_packed_int64(p *Properties, base structPointer) error { s := structPointer_Word64Slice(base, p.field) l := s.Len() if l == 0 { return ErrNil } // TODO: Reuse a Buffer. buf := NewBuffer(nil) for i := 0; i < l; i++ { p.valEnc(buf, s.Index(i)) } o.buf = append(o.buf, p.tagcode...) o.EncodeVarint(uint64(len(buf.buf))) o.buf = append(o.buf, buf.buf...) return nil } func size_slice_packed_int64(p *Properties, base structPointer) (n int) { s := structPointer_Word64Slice(base, p.field) l := s.Len() if l == 0 { return 0 } var bufSize int for i := 0; i < l; i++ { bufSize += p.valSize(s.Index(i)) } n += len(p.tagcode) n += sizeVarint(uint64(bufSize)) n += bufSize return } // Encode a slice of slice of bytes ([][]byte). func (o *Buffer) enc_slice_slice_byte(p *Properties, base structPointer) error { ss := *structPointer_BytesSlice(base, p.field) l := len(ss) if l == 0 { return ErrNil } for i := 0; i < l; i++ { o.buf = append(o.buf, p.tagcode...) o.EncodeRawBytes(ss[i]) } return nil } func size_slice_slice_byte(p *Properties, base structPointer) (n int) { ss := *structPointer_BytesSlice(base, p.field) l := len(ss) if l == 0 { return 0 } n += l * len(p.tagcode) for i := 0; i < l; i++ { n += sizeRawBytes(ss[i]) } return } // Encode a slice of strings ([]string). func (o *Buffer) enc_slice_string(p *Properties, base structPointer) error { ss := *structPointer_StringSlice(base, p.field) l := len(ss) for i := 0; i < l; i++ { o.buf = append(o.buf, p.tagcode...) o.EncodeStringBytes(ss[i]) } return nil } func size_slice_string(p *Properties, base structPointer) (n int) { ss := *structPointer_StringSlice(base, p.field) l := len(ss) n += l * len(p.tagcode) for i := 0; i < l; i++ { n += sizeStringBytes(ss[i]) } return } // Encode a slice of message structs ([]*struct). func (o *Buffer) enc_slice_struct_message(p *Properties, base structPointer) error { var state errorState s := structPointer_StructPointerSlice(base, p.field) l := s.Len() for i := 0; i < l; i++ { structp := s.Index(i) if structPointer_IsNil(structp) { return errRepeatedHasNil } // Can the object marshal itself? if p.isMarshaler { m := structPointer_Interface(structp, p.stype).(Marshaler) data, err := m.Marshal() if err != nil && !state.shouldContinue(err, nil) { return err } o.buf = append(o.buf, p.tagcode...) o.EncodeRawBytes(data) continue } o.buf = append(o.buf, p.tagcode...) err := o.enc_len_struct(p.sprop, structp, &state) if err != nil && !state.shouldContinue(err, nil) { if err == ErrNil { return errRepeatedHasNil } return err } } return state.err } func size_slice_struct_message(p *Properties, base structPointer) (n int) { s := structPointer_StructPointerSlice(base, p.field) l := s.Len() n += l * len(p.tagcode) for i := 0; i < l; i++ { structp := s.Index(i) if structPointer_IsNil(structp) { return // return the size up to this point } // Can the object marshal itself? if p.isMarshaler { m := structPointer_Interface(structp, p.stype).(Marshaler) data, _ := m.Marshal() n += sizeRawBytes(data) continue } n0 := size_struct(p.sprop, structp) n1 := sizeVarint(uint64(n0)) // size of encoded length n += n0 + n1 } return } // Encode a slice of group structs ([]*struct). func (o *Buffer) enc_slice_struct_group(p *Properties, base structPointer) error { var state errorState s := structPointer_StructPointerSlice(base, p.field) l := s.Len() for i := 0; i < l; i++ { b := s.Index(i) if structPointer_IsNil(b) { return errRepeatedHasNil } o.EncodeVarint(uint64((p.Tag << 3) | WireStartGroup)) err := o.enc_struct(p.sprop, b) if err != nil && !state.shouldContinue(err, nil) { if err == ErrNil { return errRepeatedHasNil } return err } o.EncodeVarint(uint64((p.Tag << 3) | WireEndGroup)) } return state.err } func size_slice_struct_group(p *Properties, base structPointer) (n int) { s := structPointer_StructPointerSlice(base, p.field) l := s.Len() n += l * sizeVarint(uint64((p.Tag<<3)|WireStartGroup)) n += l * sizeVarint(uint64((p.Tag<<3)|WireEndGroup)) for i := 0; i < l; i++ { b := s.Index(i) if structPointer_IsNil(b) { return // return size up to this point } n += size_struct(p.sprop, b) } return } // Encode an extension map. func (o *Buffer) enc_map(p *Properties, base structPointer) error { exts := structPointer_ExtMap(base, p.field) if err := encodeExtensionsMap(*exts); err != nil { return err } return o.enc_map_body(*exts) } func (o *Buffer) enc_exts(p *Properties, base structPointer) error { exts := structPointer_Extensions(base, p.field) v, mu := exts.extensionsRead() if v == nil { return nil } mu.Lock() defer mu.Unlock() if err := encodeExtensionsMap(v); err != nil { return err } return o.enc_map_body(v) } func (o *Buffer) enc_map_body(v map[int32]Extension) error { // Fast-path for common cases: zero or one extensions. if len(v) <= 1 { for _, e := range v { o.buf = append(o.buf, e.enc...) } return nil } // Sort keys to provide a deterministic encoding. keys := make([]int, 0, len(v)) for k := range v { keys = append(keys, int(k)) } sort.Ints(keys) for _, k := range keys { o.buf = append(o.buf, v[int32(k)].enc...) } return nil } func size_map(p *Properties, base structPointer) int { v := structPointer_ExtMap(base, p.field) return extensionsMapSize(*v) } func size_exts(p *Properties, base structPointer) int { v := structPointer_Extensions(base, p.field) return extensionsSize(v) } // Encode a map field. func (o *Buffer) enc_new_map(p *Properties, base structPointer) error { var state errorState // XXX: or do we need to plumb this through? /* A map defined as map map_field = N; is encoded in the same way as message MapFieldEntry { key_type key = 1; value_type value = 2; } repeated MapFieldEntry map_field = N; */ v := structPointer_NewAt(base, p.field, p.mtype).Elem() // map[K]V if v.Len() == 0 { return nil } keycopy, valcopy, keybase, valbase := mapEncodeScratch(p.mtype) enc := func() error { if err := p.mkeyprop.enc(o, p.mkeyprop, keybase); err != nil { return err } if err := p.mvalprop.enc(o, p.mvalprop, valbase); err != nil && err != ErrNil { return err } return nil } // Don't sort map keys. It is not required by the spec, and C++ doesn't do it. for _, key := range v.MapKeys() { val := v.MapIndex(key) keycopy.Set(key) valcopy.Set(val) o.buf = append(o.buf, p.tagcode...) if err := o.enc_len_thing(enc, &state); err != nil { return err } } return nil } func size_new_map(p *Properties, base structPointer) int { v := structPointer_NewAt(base, p.field, p.mtype).Elem() // map[K]V keycopy, valcopy, keybase, valbase := mapEncodeScratch(p.mtype) n := 0 for _, key := range v.MapKeys() { val := v.MapIndex(key) keycopy.Set(key) valcopy.Set(val) // Tag codes for key and val are the responsibility of the sub-sizer. keysize := p.mkeyprop.size(p.mkeyprop, keybase) valsize := p.mvalprop.size(p.mvalprop, valbase) entry := keysize + valsize // Add on tag code and length of map entry itself. n += len(p.tagcode) + sizeVarint(uint64(entry)) + entry } return n } // mapEncodeScratch returns a new reflect.Value matching the map's value type, // and a structPointer suitable for passing to an encoder or sizer. func mapEncodeScratch(mapType reflect.Type) (keycopy, valcopy reflect.Value, keybase, valbase structPointer) { // Prepare addressable doubly-indirect placeholders for the key and value types. // This is needed because the element-type encoders expect **T, but the map iteration produces T. keycopy = reflect.New(mapType.Key()).Elem() // addressable K keyptr := reflect.New(reflect.PtrTo(keycopy.Type())).Elem() // addressable *K keyptr.Set(keycopy.Addr()) // keybase = toStructPointer(keyptr.Addr()) // **K // Value types are more varied and require special handling. switch mapType.Elem().Kind() { case reflect.Slice: // []byte var dummy []byte valcopy = reflect.ValueOf(&dummy).Elem() // addressable []byte valbase = toStructPointer(valcopy.Addr()) case reflect.Ptr: // message; the generated field type is map[K]*Msg (so V is *Msg), // so we only need one level of indirection. valcopy = reflect.New(mapType.Elem()).Elem() // addressable V valbase = toStructPointer(valcopy.Addr()) default: // everything else valcopy = reflect.New(mapType.Elem()).Elem() // addressable V valptr := reflect.New(reflect.PtrTo(valcopy.Type())).Elem() // addressable *V valptr.Set(valcopy.Addr()) // valbase = toStructPointer(valptr.Addr()) // **V } return } // Encode a struct. func (o *Buffer) enc_struct(prop *StructProperties, base structPointer) error { var state errorState // Encode fields in tag order so that decoders may use optimizations // that depend on the ordering. // https://developers.google.com/protocol-buffers/docs/encoding#order for _, i := range prop.order { p := prop.Prop[i] if p.enc != nil { err := p.enc(o, p, base) if err != nil { if err == ErrNil { if p.Required && state.err == nil { state.err = &RequiredNotSetError{p.Name} } } else if err == errRepeatedHasNil { // Give more context to nil values in repeated fields. return errors.New("repeated field " + p.OrigName + " has nil element") } else if !state.shouldContinue(err, p) { return err } } if len(o.buf) > maxMarshalSize { return ErrTooLarge } } } // Do oneof fields. if prop.oneofMarshaler != nil { m := structPointer_Interface(base, prop.stype).(Message) if err := prop.oneofMarshaler(m, o); err == ErrNil { return errOneofHasNil } else if err != nil { return err } } // Add unrecognized fields at the end. if prop.unrecField.IsValid() { v := *structPointer_Bytes(base, prop.unrecField) if len(o.buf)+len(v) > maxMarshalSize { return ErrTooLarge } if len(v) > 0 { o.buf = append(o.buf, v...) } } return state.err } func size_struct(prop *StructProperties, base structPointer) (n int) { for _, i := range prop.order { p := prop.Prop[i] if p.size != nil { n += p.size(p, base) } } // Add unrecognized fields at the end. if prop.unrecField.IsValid() { v := *structPointer_Bytes(base, prop.unrecField) n += len(v) } // Factor in any oneof fields. if prop.oneofSizer != nil { m := structPointer_Interface(base, prop.stype).(Message) n += prop.oneofSizer(m) } return } var zeroes [20]byte // longer than any conceivable sizeVarint // Encode a struct, preceded by its encoded length (as a varint). func (o *Buffer) enc_len_struct(prop *StructProperties, base structPointer, state *errorState) error { return o.enc_len_thing(func() error { return o.enc_struct(prop, base) }, state) } // Encode something, preceded by its encoded length (as a varint). func (o *Buffer) enc_len_thing(enc func() error, state *errorState) error { iLen := len(o.buf) o.buf = append(o.buf, 0, 0, 0, 0) // reserve four bytes for length iMsg := len(o.buf) err := enc() if err != nil && !state.shouldContinue(err, nil) { return err } lMsg := len(o.buf) - iMsg lLen := sizeVarint(uint64(lMsg)) switch x := lLen - (iMsg - iLen); { case x > 0: // actual length is x bytes larger than the space we reserved // Move msg x bytes right. o.buf = append(o.buf, zeroes[:x]...) copy(o.buf[iMsg+x:], o.buf[iMsg:iMsg+lMsg]) case x < 0: // actual length is x bytes smaller than the space we reserved // Move msg x bytes left. copy(o.buf[iMsg+x:], o.buf[iMsg:iMsg+lMsg]) o.buf = o.buf[:len(o.buf)+x] // x is negative } // Encode the length in the reserved space. o.buf = o.buf[:iLen] o.EncodeVarint(uint64(lMsg)) o.buf = o.buf[:len(o.buf)+lMsg] return state.err } // errorState maintains the first error that occurs and updates that error // with additional context. type errorState struct { err error } // shouldContinue reports whether encoding should continue upon encountering the // given error. If the error is RequiredNotSetError, shouldContinue returns true // and, if this is the first appearance of that error, remembers it for future // reporting. // // If prop is not nil, it may update any error with additional context about the // field with the error. func (s *errorState) shouldContinue(err error, prop *Properties) bool { // Ignore unset required fields. reqNotSet, ok := err.(*RequiredNotSetError) if !ok { return false } if s.err == nil { if prop != nil { err = &RequiredNotSetError{prop.Name + "." + reqNotSet.field} } s.err = err } return true } ================================================ FILE: vendor/github.com/golang/protobuf/proto/encode_test.go ================================================ // Go support for Protocol Buffers - Google's data interchange format // // Copyright 2010 The Go Authors. All rights reserved. // https://github.com/golang/protobuf // // 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. // +build go1.7 package proto_test import ( "strconv" "testing" "github.com/golang/protobuf/proto" tpb "github.com/golang/protobuf/proto/proto3_proto" "github.com/golang/protobuf/ptypes" ) var ( blackhole []byte ) // BenchmarkAny creates increasingly large arbitrary Any messages. The type is always the // same. func BenchmarkAny(b *testing.B) { data := make([]byte, 1<<20) quantum := 1 << 10 for i := uint(0); i <= 10; i++ { b.Run(strconv.Itoa(quantum<= len(o.buf) { break } } return value.Interface(), nil } // GetExtensions returns a slice of the extensions present in pb that are also listed in es. // The returned slice has the same length as es; missing extensions will appear as nil elements. func GetExtensions(pb Message, es []*ExtensionDesc) (extensions []interface{}, err error) { epb, ok := extendable(pb) if !ok { return nil, errors.New("proto: not an extendable proto") } extensions = make([]interface{}, len(es)) for i, e := range es { extensions[i], err = GetExtension(epb, e) if err == ErrMissingExtension { err = nil } if err != nil { return } } return } // ExtensionDescs returns a new slice containing pb's extension descriptors, in undefined order. // For non-registered extensions, ExtensionDescs returns an incomplete descriptor containing // just the Field field, which defines the extension's field number. func ExtensionDescs(pb Message) ([]*ExtensionDesc, error) { epb, ok := extendable(pb) if !ok { return nil, fmt.Errorf("proto: %T is not an extendable proto.Message", pb) } registeredExtensions := RegisteredExtensions(pb) emap, mu := epb.extensionsRead() if emap == nil { return nil, nil } mu.Lock() defer mu.Unlock() extensions := make([]*ExtensionDesc, 0, len(emap)) for extid, e := range emap { desc := e.desc if desc == nil { desc = registeredExtensions[extid] if desc == nil { desc = &ExtensionDesc{Field: extid} } } extensions = append(extensions, desc) } return extensions, nil } // SetExtension sets the specified extension of pb to the specified value. func SetExtension(pb Message, extension *ExtensionDesc, value interface{}) error { epb, ok := extendable(pb) if !ok { return errors.New("proto: not an extendable proto") } if err := checkExtensionTypes(epb, extension); err != nil { return err } typ := reflect.TypeOf(extension.ExtensionType) if typ != reflect.TypeOf(value) { return errors.New("proto: bad extension value type") } // nil extension values need to be caught early, because the // encoder can't distinguish an ErrNil due to a nil extension // from an ErrNil due to a missing field. Extensions are // always optional, so the encoder would just swallow the error // and drop all the extensions from the encoded message. if reflect.ValueOf(value).IsNil() { return fmt.Errorf("proto: SetExtension called with nil value of type %T", value) } extmap := epb.extensionsWrite() extmap[extension.Field] = Extension{desc: extension, value: value} return nil } // ClearAllExtensions clears all extensions from pb. func ClearAllExtensions(pb Message) { epb, ok := extendable(pb) if !ok { return } m := epb.extensionsWrite() for k := range m { delete(m, k) } } // A global registry of extensions. // The generated code will register the generated descriptors by calling RegisterExtension. var extensionMaps = make(map[reflect.Type]map[int32]*ExtensionDesc) // RegisterExtension is called from the generated code. func RegisterExtension(desc *ExtensionDesc) { st := reflect.TypeOf(desc.ExtendedType).Elem() m := extensionMaps[st] if m == nil { m = make(map[int32]*ExtensionDesc) extensionMaps[st] = m } if _, ok := m[desc.Field]; ok { panic("proto: duplicate extension registered: " + st.String() + " " + strconv.Itoa(int(desc.Field))) } m[desc.Field] = desc } // RegisteredExtensions returns a map of the registered extensions of a // protocol buffer struct, indexed by the extension number. // The argument pb should be a nil pointer to the struct type. func RegisteredExtensions(pb Message) map[int32]*ExtensionDesc { return extensionMaps[reflect.TypeOf(pb).Elem()] } ================================================ FILE: vendor/github.com/golang/protobuf/proto/extensions_test.go ================================================ // Go support for Protocol Buffers - Google's data interchange format // // Copyright 2014 The Go Authors. All rights reserved. // https://github.com/golang/protobuf // // 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. package proto_test import ( "bytes" "fmt" "reflect" "sort" "testing" "github.com/golang/protobuf/proto" pb "github.com/golang/protobuf/proto/testdata" "golang.org/x/sync/errgroup" ) func TestGetExtensionsWithMissingExtensions(t *testing.T) { msg := &pb.MyMessage{} ext1 := &pb.Ext{} if err := proto.SetExtension(msg, pb.E_Ext_More, ext1); err != nil { t.Fatalf("Could not set ext1: %s", err) } exts, err := proto.GetExtensions(msg, []*proto.ExtensionDesc{ pb.E_Ext_More, pb.E_Ext_Text, }) if err != nil { t.Fatalf("GetExtensions() failed: %s", err) } if exts[0] != ext1 { t.Errorf("ext1 not in returned extensions: %T %v", exts[0], exts[0]) } if exts[1] != nil { t.Errorf("ext2 in returned extensions: %T %v", exts[1], exts[1]) } } func TestExtensionDescsWithMissingExtensions(t *testing.T) { msg := &pb.MyMessage{Count: proto.Int32(0)} extdesc1 := pb.E_Ext_More if descs, err := proto.ExtensionDescs(msg); len(descs) != 0 || err != nil { t.Errorf("proto.ExtensionDescs: got %d descs, error %v; want 0, nil", len(descs), err) } ext1 := &pb.Ext{} if err := proto.SetExtension(msg, extdesc1, ext1); err != nil { t.Fatalf("Could not set ext1: %s", err) } extdesc2 := &proto.ExtensionDesc{ ExtendedType: (*pb.MyMessage)(nil), ExtensionType: (*bool)(nil), Field: 123456789, Name: "a.b", Tag: "varint,123456789,opt", } ext2 := proto.Bool(false) if err := proto.SetExtension(msg, extdesc2, ext2); err != nil { t.Fatalf("Could not set ext2: %s", err) } b, err := proto.Marshal(msg) if err != nil { t.Fatalf("Could not marshal msg: %v", err) } if err := proto.Unmarshal(b, msg); err != nil { t.Fatalf("Could not unmarshal into msg: %v", err) } descs, err := proto.ExtensionDescs(msg) if err != nil { t.Fatalf("proto.ExtensionDescs: got error %v", err) } sortExtDescs(descs) wantDescs := []*proto.ExtensionDesc{extdesc1, &proto.ExtensionDesc{Field: extdesc2.Field}} if !reflect.DeepEqual(descs, wantDescs) { t.Errorf("proto.ExtensionDescs(msg) sorted extension ids: got %+v, want %+v", descs, wantDescs) } } type ExtensionDescSlice []*proto.ExtensionDesc func (s ExtensionDescSlice) Len() int { return len(s) } func (s ExtensionDescSlice) Less(i, j int) bool { return s[i].Field < s[j].Field } func (s ExtensionDescSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] } func sortExtDescs(s []*proto.ExtensionDesc) { sort.Sort(ExtensionDescSlice(s)) } func TestGetExtensionStability(t *testing.T) { check := func(m *pb.MyMessage) bool { ext1, err := proto.GetExtension(m, pb.E_Ext_More) if err != nil { t.Fatalf("GetExtension() failed: %s", err) } ext2, err := proto.GetExtension(m, pb.E_Ext_More) if err != nil { t.Fatalf("GetExtension() failed: %s", err) } return ext1 == ext2 } msg := &pb.MyMessage{Count: proto.Int32(4)} ext0 := &pb.Ext{} if err := proto.SetExtension(msg, pb.E_Ext_More, ext0); err != nil { t.Fatalf("Could not set ext1: %s", ext0) } if !check(msg) { t.Errorf("GetExtension() not stable before marshaling") } bb, err := proto.Marshal(msg) if err != nil { t.Fatalf("Marshal() failed: %s", err) } msg1 := &pb.MyMessage{} err = proto.Unmarshal(bb, msg1) if err != nil { t.Fatalf("Unmarshal() failed: %s", err) } if !check(msg1) { t.Errorf("GetExtension() not stable after unmarshaling") } } func TestGetExtensionDefaults(t *testing.T) { var setFloat64 float64 = 1 var setFloat32 float32 = 2 var setInt32 int32 = 3 var setInt64 int64 = 4 var setUint32 uint32 = 5 var setUint64 uint64 = 6 var setBool = true var setBool2 = false var setString = "Goodnight string" var setBytes = []byte("Goodnight bytes") var setEnum = pb.DefaultsMessage_TWO type testcase struct { ext *proto.ExtensionDesc // Extension we are testing. want interface{} // Expected value of extension, or nil (meaning that GetExtension will fail). def interface{} // Expected value of extension after ClearExtension(). } tests := []testcase{ {pb.E_NoDefaultDouble, setFloat64, nil}, {pb.E_NoDefaultFloat, setFloat32, nil}, {pb.E_NoDefaultInt32, setInt32, nil}, {pb.E_NoDefaultInt64, setInt64, nil}, {pb.E_NoDefaultUint32, setUint32, nil}, {pb.E_NoDefaultUint64, setUint64, nil}, {pb.E_NoDefaultSint32, setInt32, nil}, {pb.E_NoDefaultSint64, setInt64, nil}, {pb.E_NoDefaultFixed32, setUint32, nil}, {pb.E_NoDefaultFixed64, setUint64, nil}, {pb.E_NoDefaultSfixed32, setInt32, nil}, {pb.E_NoDefaultSfixed64, setInt64, nil}, {pb.E_NoDefaultBool, setBool, nil}, {pb.E_NoDefaultBool, setBool2, nil}, {pb.E_NoDefaultString, setString, nil}, {pb.E_NoDefaultBytes, setBytes, nil}, {pb.E_NoDefaultEnum, setEnum, nil}, {pb.E_DefaultDouble, setFloat64, float64(3.1415)}, {pb.E_DefaultFloat, setFloat32, float32(3.14)}, {pb.E_DefaultInt32, setInt32, int32(42)}, {pb.E_DefaultInt64, setInt64, int64(43)}, {pb.E_DefaultUint32, setUint32, uint32(44)}, {pb.E_DefaultUint64, setUint64, uint64(45)}, {pb.E_DefaultSint32, setInt32, int32(46)}, {pb.E_DefaultSint64, setInt64, int64(47)}, {pb.E_DefaultFixed32, setUint32, uint32(48)}, {pb.E_DefaultFixed64, setUint64, uint64(49)}, {pb.E_DefaultSfixed32, setInt32, int32(50)}, {pb.E_DefaultSfixed64, setInt64, int64(51)}, {pb.E_DefaultBool, setBool, true}, {pb.E_DefaultBool, setBool2, true}, {pb.E_DefaultString, setString, "Hello, string"}, {pb.E_DefaultBytes, setBytes, []byte("Hello, bytes")}, {pb.E_DefaultEnum, setEnum, pb.DefaultsMessage_ONE}, } checkVal := func(test testcase, msg *pb.DefaultsMessage, valWant interface{}) error { val, err := proto.GetExtension(msg, test.ext) if err != nil { if valWant != nil { return fmt.Errorf("GetExtension(): %s", err) } if want := proto.ErrMissingExtension; err != want { return fmt.Errorf("Unexpected error: got %v, want %v", err, want) } return nil } // All proto2 extension values are either a pointer to a value or a slice of values. ty := reflect.TypeOf(val) tyWant := reflect.TypeOf(test.ext.ExtensionType) if got, want := ty, tyWant; got != want { return fmt.Errorf("unexpected reflect.TypeOf(): got %v want %v", got, want) } tye := ty.Elem() tyeWant := tyWant.Elem() if got, want := tye, tyeWant; got != want { return fmt.Errorf("unexpected reflect.TypeOf().Elem(): got %v want %v", got, want) } // Check the name of the type of the value. // If it is an enum it will be type int32 with the name of the enum. if got, want := tye.Name(), tye.Name(); got != want { return fmt.Errorf("unexpected reflect.TypeOf().Elem().Name(): got %v want %v", got, want) } // Check that value is what we expect. // If we have a pointer in val, get the value it points to. valExp := val if ty.Kind() == reflect.Ptr { valExp = reflect.ValueOf(val).Elem().Interface() } if got, want := valExp, valWant; !reflect.DeepEqual(got, want) { return fmt.Errorf("unexpected reflect.DeepEqual(): got %v want %v", got, want) } return nil } setTo := func(test testcase) interface{} { setTo := reflect.ValueOf(test.want) if typ := reflect.TypeOf(test.ext.ExtensionType); typ.Kind() == reflect.Ptr { setTo = reflect.New(typ).Elem() setTo.Set(reflect.New(setTo.Type().Elem())) setTo.Elem().Set(reflect.ValueOf(test.want)) } return setTo.Interface() } for _, test := range tests { msg := &pb.DefaultsMessage{} name := test.ext.Name // Check the initial value. if err := checkVal(test, msg, test.def); err != nil { t.Errorf("%s: %v", name, err) } // Set the per-type value and check value. name = fmt.Sprintf("%s (set to %T %v)", name, test.want, test.want) if err := proto.SetExtension(msg, test.ext, setTo(test)); err != nil { t.Errorf("%s: SetExtension(): %v", name, err) continue } if err := checkVal(test, msg, test.want); err != nil { t.Errorf("%s: %v", name, err) continue } // Set and check the value. name += " (cleared)" proto.ClearExtension(msg, test.ext) if err := checkVal(test, msg, test.def); err != nil { t.Errorf("%s: %v", name, err) } } } func TestExtensionsRoundTrip(t *testing.T) { msg := &pb.MyMessage{} ext1 := &pb.Ext{ Data: proto.String("hi"), } ext2 := &pb.Ext{ Data: proto.String("there"), } exists := proto.HasExtension(msg, pb.E_Ext_More) if exists { t.Error("Extension More present unexpectedly") } if err := proto.SetExtension(msg, pb.E_Ext_More, ext1); err != nil { t.Error(err) } if err := proto.SetExtension(msg, pb.E_Ext_More, ext2); err != nil { t.Error(err) } e, err := proto.GetExtension(msg, pb.E_Ext_More) if err != nil { t.Error(err) } x, ok := e.(*pb.Ext) if !ok { t.Errorf("e has type %T, expected testdata.Ext", e) } else if *x.Data != "there" { t.Errorf("SetExtension failed to overwrite, got %+v, not 'there'", x) } proto.ClearExtension(msg, pb.E_Ext_More) if _, err = proto.GetExtension(msg, pb.E_Ext_More); err != proto.ErrMissingExtension { t.Errorf("got %v, expected ErrMissingExtension", e) } if _, err := proto.GetExtension(msg, pb.E_X215); err == nil { t.Error("expected bad extension error, got nil") } if err := proto.SetExtension(msg, pb.E_X215, 12); err == nil { t.Error("expected extension err") } if err := proto.SetExtension(msg, pb.E_Ext_More, 12); err == nil { t.Error("expected some sort of type mismatch error, got nil") } } func TestNilExtension(t *testing.T) { msg := &pb.MyMessage{ Count: proto.Int32(1), } if err := proto.SetExtension(msg, pb.E_Ext_Text, proto.String("hello")); err != nil { t.Fatal(err) } if err := proto.SetExtension(msg, pb.E_Ext_More, (*pb.Ext)(nil)); err == nil { t.Error("expected SetExtension to fail due to a nil extension") } else if want := "proto: SetExtension called with nil value of type *testdata.Ext"; err.Error() != want { t.Errorf("expected error %v, got %v", want, err) } // Note: if the behavior of Marshal is ever changed to ignore nil extensions, update // this test to verify that E_Ext_Text is properly propagated through marshal->unmarshal. } func TestMarshalUnmarshalRepeatedExtension(t *testing.T) { // Add a repeated extension to the result. tests := []struct { name string ext []*pb.ComplexExtension }{ { "two fields", []*pb.ComplexExtension{ {First: proto.Int32(7)}, {Second: proto.Int32(11)}, }, }, { "repeated field", []*pb.ComplexExtension{ {Third: []int32{1000}}, {Third: []int32{2000}}, }, }, { "two fields and repeated field", []*pb.ComplexExtension{ {Third: []int32{1000}}, {First: proto.Int32(9)}, {Second: proto.Int32(21)}, {Third: []int32{2000}}, }, }, } for _, test := range tests { // Marshal message with a repeated extension. msg1 := new(pb.OtherMessage) err := proto.SetExtension(msg1, pb.E_RComplex, test.ext) if err != nil { t.Fatalf("[%s] Error setting extension: %v", test.name, err) } b, err := proto.Marshal(msg1) if err != nil { t.Fatalf("[%s] Error marshaling message: %v", test.name, err) } // Unmarshal and read the merged proto. msg2 := new(pb.OtherMessage) err = proto.Unmarshal(b, msg2) if err != nil { t.Fatalf("[%s] Error unmarshaling message: %v", test.name, err) } e, err := proto.GetExtension(msg2, pb.E_RComplex) if err != nil { t.Fatalf("[%s] Error getting extension: %v", test.name, err) } ext := e.([]*pb.ComplexExtension) if ext == nil { t.Fatalf("[%s] Invalid extension", test.name) } if !reflect.DeepEqual(ext, test.ext) { t.Errorf("[%s] Wrong value for ComplexExtension: got: %v want: %v\n", test.name, ext, test.ext) } } } func TestUnmarshalRepeatingNonRepeatedExtension(t *testing.T) { // We may see multiple instances of the same extension in the wire // format. For example, the proto compiler may encode custom options in // this way. Here, we verify that we merge the extensions together. tests := []struct { name string ext []*pb.ComplexExtension }{ { "two fields", []*pb.ComplexExtension{ {First: proto.Int32(7)}, {Second: proto.Int32(11)}, }, }, { "repeated field", []*pb.ComplexExtension{ {Third: []int32{1000}}, {Third: []int32{2000}}, }, }, { "two fields and repeated field", []*pb.ComplexExtension{ {Third: []int32{1000}}, {First: proto.Int32(9)}, {Second: proto.Int32(21)}, {Third: []int32{2000}}, }, }, } for _, test := range tests { var buf bytes.Buffer var want pb.ComplexExtension // Generate a serialized representation of a repeated extension // by catenating bytes together. for i, e := range test.ext { // Merge to create the wanted proto. proto.Merge(&want, e) // serialize the message msg := new(pb.OtherMessage) err := proto.SetExtension(msg, pb.E_Complex, e) if err != nil { t.Fatalf("[%s] Error setting extension %d: %v", test.name, i, err) } b, err := proto.Marshal(msg) if err != nil { t.Fatalf("[%s] Error marshaling message %d: %v", test.name, i, err) } buf.Write(b) } // Unmarshal and read the merged proto. msg2 := new(pb.OtherMessage) err := proto.Unmarshal(buf.Bytes(), msg2) if err != nil { t.Fatalf("[%s] Error unmarshaling message: %v", test.name, err) } e, err := proto.GetExtension(msg2, pb.E_Complex) if err != nil { t.Fatalf("[%s] Error getting extension: %v", test.name, err) } ext := e.(*pb.ComplexExtension) if ext == nil { t.Fatalf("[%s] Invalid extension", test.name) } if !reflect.DeepEqual(*ext, want) { t.Errorf("[%s] Wrong value for ComplexExtension: got: %s want: %s\n", test.name, ext, want) } } } func TestClearAllExtensions(t *testing.T) { // unregistered extension desc := &proto.ExtensionDesc{ ExtendedType: (*pb.MyMessage)(nil), ExtensionType: (*bool)(nil), Field: 101010100, Name: "emptyextension", Tag: "varint,0,opt", } m := &pb.MyMessage{} if proto.HasExtension(m, desc) { t.Errorf("proto.HasExtension(%s): got true, want false", proto.MarshalTextString(m)) } if err := proto.SetExtension(m, desc, proto.Bool(true)); err != nil { t.Errorf("proto.SetExtension(m, desc, true): got error %q, want nil", err) } if !proto.HasExtension(m, desc) { t.Errorf("proto.HasExtension(%s): got false, want true", proto.MarshalTextString(m)) } proto.ClearAllExtensions(m) if proto.HasExtension(m, desc) { t.Errorf("proto.HasExtension(%s): got true, want false", proto.MarshalTextString(m)) } } func TestMarshalRace(t *testing.T) { // unregistered extension desc := &proto.ExtensionDesc{ ExtendedType: (*pb.MyMessage)(nil), ExtensionType: (*bool)(nil), Field: 101010100, Name: "emptyextension", Tag: "varint,0,opt", } m := &pb.MyMessage{Count: proto.Int32(4)} if err := proto.SetExtension(m, desc, proto.Bool(true)); err != nil { t.Errorf("proto.SetExtension(m, desc, true): got error %q, want nil", err) } var g errgroup.Group for n := 3; n > 0; n-- { g.Go(func() error { _, err := proto.Marshal(m) return err }) } if err := g.Wait(); err != nil { t.Fatal(err) } } ================================================ FILE: vendor/github.com/golang/protobuf/proto/lib.go ================================================ // Go support for Protocol Buffers - Google's data interchange format // // Copyright 2010 The Go Authors. All rights reserved. // https://github.com/golang/protobuf // // 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. /* Package proto converts data structures to and from the wire format of protocol buffers. It works in concert with the Go source code generated for .proto files by the protocol compiler. A summary of the properties of the protocol buffer interface for a protocol buffer variable v: - Names are turned from camel_case to CamelCase for export. - There are no methods on v to set fields; just treat them as structure fields. - There are getters that return a field's value if set, and return the field's default value if unset. The getters work even if the receiver is a nil message. - The zero value for a struct is its correct initialization state. All desired fields must be set before marshaling. - A Reset() method will restore a protobuf struct to its zero state. - Non-repeated fields are pointers to the values; nil means unset. That is, optional or required field int32 f becomes F *int32. - Repeated fields are slices. - Helper functions are available to aid the setting of fields. msg.Foo = proto.String("hello") // set field - Constants are defined to hold the default values of all fields that have them. They have the form Default_StructName_FieldName. Because the getter methods handle defaulted values, direct use of these constants should be rare. - Enums are given type names and maps from names to values. Enum values are prefixed by the enclosing message's name, or by the enum's type name if it is a top-level enum. Enum types have a String method, and a Enum method to assist in message construction. - Nested messages, groups and enums have type names prefixed with the name of the surrounding message type. - Extensions are given descriptor names that start with E_, followed by an underscore-delimited list of the nested messages that contain it (if any) followed by the CamelCased name of the extension field itself. HasExtension, ClearExtension, GetExtension and SetExtension are functions for manipulating extensions. - Oneof field sets are given a single field in their message, with distinguished wrapper types for each possible field value. - Marshal and Unmarshal are functions to encode and decode the wire format. When the .proto file specifies `syntax="proto3"`, there are some differences: - Non-repeated fields of non-message type are values instead of pointers. - Enum types do not get an Enum method. The simplest way to describe this is to see an example. Given file test.proto, containing package example; enum FOO { X = 17; } message Test { required string label = 1; optional int32 type = 2 [default=77]; repeated int64 reps = 3; optional group OptionalGroup = 4 { required string RequiredField = 5; } oneof union { int32 number = 6; string name = 7; } } The resulting file, test.pb.go, is: package example import proto "github.com/golang/protobuf/proto" import math "math" type FOO int32 const ( FOO_X FOO = 17 ) var FOO_name = map[int32]string{ 17: "X", } var FOO_value = map[string]int32{ "X": 17, } func (x FOO) Enum() *FOO { p := new(FOO) *p = x return p } func (x FOO) String() string { return proto.EnumName(FOO_name, int32(x)) } func (x *FOO) UnmarshalJSON(data []byte) error { value, err := proto.UnmarshalJSONEnum(FOO_value, data) if err != nil { return err } *x = FOO(value) return nil } type Test struct { Label *string `protobuf:"bytes,1,req,name=label" json:"label,omitempty"` Type *int32 `protobuf:"varint,2,opt,name=type,def=77" json:"type,omitempty"` Reps []int64 `protobuf:"varint,3,rep,name=reps" json:"reps,omitempty"` Optionalgroup *Test_OptionalGroup `protobuf:"group,4,opt,name=OptionalGroup" json:"optionalgroup,omitempty"` // Types that are valid to be assigned to Union: // *Test_Number // *Test_Name Union isTest_Union `protobuf_oneof:"union"` XXX_unrecognized []byte `json:"-"` } func (m *Test) Reset() { *m = Test{} } func (m *Test) String() string { return proto.CompactTextString(m) } func (*Test) ProtoMessage() {} type isTest_Union interface { isTest_Union() } type Test_Number struct { Number int32 `protobuf:"varint,6,opt,name=number"` } type Test_Name struct { Name string `protobuf:"bytes,7,opt,name=name"` } func (*Test_Number) isTest_Union() {} func (*Test_Name) isTest_Union() {} func (m *Test) GetUnion() isTest_Union { if m != nil { return m.Union } return nil } const Default_Test_Type int32 = 77 func (m *Test) GetLabel() string { if m != nil && m.Label != nil { return *m.Label } return "" } func (m *Test) GetType() int32 { if m != nil && m.Type != nil { return *m.Type } return Default_Test_Type } func (m *Test) GetOptionalgroup() *Test_OptionalGroup { if m != nil { return m.Optionalgroup } return nil } type Test_OptionalGroup struct { RequiredField *string `protobuf:"bytes,5,req" json:"RequiredField,omitempty"` } func (m *Test_OptionalGroup) Reset() { *m = Test_OptionalGroup{} } func (m *Test_OptionalGroup) String() string { return proto.CompactTextString(m) } func (m *Test_OptionalGroup) GetRequiredField() string { if m != nil && m.RequiredField != nil { return *m.RequiredField } return "" } func (m *Test) GetNumber() int32 { if x, ok := m.GetUnion().(*Test_Number); ok { return x.Number } return 0 } func (m *Test) GetName() string { if x, ok := m.GetUnion().(*Test_Name); ok { return x.Name } return "" } func init() { proto.RegisterEnum("example.FOO", FOO_name, FOO_value) } To create and play with a Test object: package main import ( "log" "github.com/golang/protobuf/proto" pb "./example.pb" ) func main() { test := &pb.Test{ Label: proto.String("hello"), Type: proto.Int32(17), Reps: []int64{1, 2, 3}, Optionalgroup: &pb.Test_OptionalGroup{ RequiredField: proto.String("good bye"), }, Union: &pb.Test_Name{"fred"}, } data, err := proto.Marshal(test) if err != nil { log.Fatal("marshaling error: ", err) } newTest := &pb.Test{} err = proto.Unmarshal(data, newTest) if err != nil { log.Fatal("unmarshaling error: ", err) } // Now test and newTest contain the same data. if test.GetLabel() != newTest.GetLabel() { log.Fatalf("data mismatch %q != %q", test.GetLabel(), newTest.GetLabel()) } // Use a type switch to determine which oneof was set. switch u := test.Union.(type) { case *pb.Test_Number: // u.Number contains the number. case *pb.Test_Name: // u.Name contains the string. } // etc. } */ package proto import ( "encoding/json" "fmt" "log" "reflect" "sort" "strconv" "sync" ) // Message is implemented by generated protocol buffer messages. type Message interface { Reset() String() string ProtoMessage() } // Stats records allocation details about the protocol buffer encoders // and decoders. Useful for tuning the library itself. type Stats struct { Emalloc uint64 // mallocs in encode Dmalloc uint64 // mallocs in decode Encode uint64 // number of encodes Decode uint64 // number of decodes Chit uint64 // number of cache hits Cmiss uint64 // number of cache misses Size uint64 // number of sizes } // Set to true to enable stats collection. const collectStats = false var stats Stats // GetStats returns a copy of the global Stats structure. func GetStats() Stats { return stats } // A Buffer is a buffer manager for marshaling and unmarshaling // protocol buffers. It may be reused between invocations to // reduce memory usage. It is not necessary to use a Buffer; // the global functions Marshal and Unmarshal create a // temporary Buffer and are fine for most applications. type Buffer struct { buf []byte // encode/decode byte stream index int // read point // pools of basic types to amortize allocation. bools []bool uint32s []uint32 uint64s []uint64 // extra pools, only used with pointer_reflect.go int32s []int32 int64s []int64 float32s []float32 float64s []float64 } // NewBuffer allocates a new Buffer and initializes its internal data to // the contents of the argument slice. func NewBuffer(e []byte) *Buffer { return &Buffer{buf: e} } // Reset resets the Buffer, ready for marshaling a new protocol buffer. func (p *Buffer) Reset() { p.buf = p.buf[0:0] // for reading/writing p.index = 0 // for reading } // SetBuf replaces the internal buffer with the slice, // ready for unmarshaling the contents of the slice. func (p *Buffer) SetBuf(s []byte) { p.buf = s p.index = 0 } // Bytes returns the contents of the Buffer. func (p *Buffer) Bytes() []byte { return p.buf } /* * Helper routines for simplifying the creation of optional fields of basic type. */ // Bool is a helper routine that allocates a new bool value // to store v and returns a pointer to it. func Bool(v bool) *bool { return &v } // Int32 is a helper routine that allocates a new int32 value // to store v and returns a pointer to it. func Int32(v int32) *int32 { return &v } // Int is a helper routine that allocates a new int32 value // to store v and returns a pointer to it, but unlike Int32 // its argument value is an int. func Int(v int) *int32 { p := new(int32) *p = int32(v) return p } // Int64 is a helper routine that allocates a new int64 value // to store v and returns a pointer to it. func Int64(v int64) *int64 { return &v } // Float32 is a helper routine that allocates a new float32 value // to store v and returns a pointer to it. func Float32(v float32) *float32 { return &v } // Float64 is a helper routine that allocates a new float64 value // to store v and returns a pointer to it. func Float64(v float64) *float64 { return &v } // Uint32 is a helper routine that allocates a new uint32 value // to store v and returns a pointer to it. func Uint32(v uint32) *uint32 { return &v } // Uint64 is a helper routine that allocates a new uint64 value // to store v and returns a pointer to it. func Uint64(v uint64) *uint64 { return &v } // String is a helper routine that allocates a new string value // to store v and returns a pointer to it. func String(v string) *string { return &v } // EnumName is a helper function to simplify printing protocol buffer enums // by name. Given an enum map and a value, it returns a useful string. func EnumName(m map[int32]string, v int32) string { s, ok := m[v] if ok { return s } return strconv.Itoa(int(v)) } // UnmarshalJSONEnum is a helper function to simplify recovering enum int values // from their JSON-encoded representation. Given a map from the enum's symbolic // names to its int values, and a byte buffer containing the JSON-encoded // value, it returns an int32 that can be cast to the enum type by the caller. // // The function can deal with both JSON representations, numeric and symbolic. func UnmarshalJSONEnum(m map[string]int32, data []byte, enumName string) (int32, error) { if data[0] == '"' { // New style: enums are strings. var repr string if err := json.Unmarshal(data, &repr); err != nil { return -1, err } val, ok := m[repr] if !ok { return 0, fmt.Errorf("unrecognized enum %s value %q", enumName, repr) } return val, nil } // Old style: enums are ints. var val int32 if err := json.Unmarshal(data, &val); err != nil { return 0, fmt.Errorf("cannot unmarshal %#q into enum %s", data, enumName) } return val, nil } // DebugPrint dumps the encoded data in b in a debugging format with a header // including the string s. Used in testing but made available for general debugging. func (p *Buffer) DebugPrint(s string, b []byte) { var u uint64 obuf := p.buf index := p.index p.buf = b p.index = 0 depth := 0 fmt.Printf("\n--- %s ---\n", s) out: for { for i := 0; i < depth; i++ { fmt.Print(" ") } index := p.index if index == len(p.buf) { break } op, err := p.DecodeVarint() if err != nil { fmt.Printf("%3d: fetching op err %v\n", index, err) break out } tag := op >> 3 wire := op & 7 switch wire { default: fmt.Printf("%3d: t=%3d unknown wire=%d\n", index, tag, wire) break out case WireBytes: var r []byte r, err = p.DecodeRawBytes(false) if err != nil { break out } fmt.Printf("%3d: t=%3d bytes [%d]", index, tag, len(r)) if len(r) <= 6 { for i := 0; i < len(r); i++ { fmt.Printf(" %.2x", r[i]) } } else { for i := 0; i < 3; i++ { fmt.Printf(" %.2x", r[i]) } fmt.Printf(" ..") for i := len(r) - 3; i < len(r); i++ { fmt.Printf(" %.2x", r[i]) } } fmt.Printf("\n") case WireFixed32: u, err = p.DecodeFixed32() if err != nil { fmt.Printf("%3d: t=%3d fix32 err %v\n", index, tag, err) break out } fmt.Printf("%3d: t=%3d fix32 %d\n", index, tag, u) case WireFixed64: u, err = p.DecodeFixed64() if err != nil { fmt.Printf("%3d: t=%3d fix64 err %v\n", index, tag, err) break out } fmt.Printf("%3d: t=%3d fix64 %d\n", index, tag, u) case WireVarint: u, err = p.DecodeVarint() if err != nil { fmt.Printf("%3d: t=%3d varint err %v\n", index, tag, err) break out } fmt.Printf("%3d: t=%3d varint %d\n", index, tag, u) case WireStartGroup: fmt.Printf("%3d: t=%3d start\n", index, tag) depth++ case WireEndGroup: depth-- fmt.Printf("%3d: t=%3d end\n", index, tag) } } if depth != 0 { fmt.Printf("%3d: start-end not balanced %d\n", p.index, depth) } fmt.Printf("\n") p.buf = obuf p.index = index } // SetDefaults sets unset protocol buffer fields to their default values. // It only modifies fields that are both unset and have defined defaults. // It recursively sets default values in any non-nil sub-messages. func SetDefaults(pb Message) { setDefaults(reflect.ValueOf(pb), true, false) } // v is a pointer to a struct. func setDefaults(v reflect.Value, recur, zeros bool) { v = v.Elem() defaultMu.RLock() dm, ok := defaults[v.Type()] defaultMu.RUnlock() if !ok { dm = buildDefaultMessage(v.Type()) defaultMu.Lock() defaults[v.Type()] = dm defaultMu.Unlock() } for _, sf := range dm.scalars { f := v.Field(sf.index) if !f.IsNil() { // field already set continue } dv := sf.value if dv == nil && !zeros { // no explicit default, and don't want to set zeros continue } fptr := f.Addr().Interface() // **T // TODO: Consider batching the allocations we do here. switch sf.kind { case reflect.Bool: b := new(bool) if dv != nil { *b = dv.(bool) } *(fptr.(**bool)) = b case reflect.Float32: f := new(float32) if dv != nil { *f = dv.(float32) } *(fptr.(**float32)) = f case reflect.Float64: f := new(float64) if dv != nil { *f = dv.(float64) } *(fptr.(**float64)) = f case reflect.Int32: // might be an enum if ft := f.Type(); ft != int32PtrType { // enum f.Set(reflect.New(ft.Elem())) if dv != nil { f.Elem().SetInt(int64(dv.(int32))) } } else { // int32 field i := new(int32) if dv != nil { *i = dv.(int32) } *(fptr.(**int32)) = i } case reflect.Int64: i := new(int64) if dv != nil { *i = dv.(int64) } *(fptr.(**int64)) = i case reflect.String: s := new(string) if dv != nil { *s = dv.(string) } *(fptr.(**string)) = s case reflect.Uint8: // exceptional case: []byte var b []byte if dv != nil { db := dv.([]byte) b = make([]byte, len(db)) copy(b, db) } else { b = []byte{} } *(fptr.(*[]byte)) = b case reflect.Uint32: u := new(uint32) if dv != nil { *u = dv.(uint32) } *(fptr.(**uint32)) = u case reflect.Uint64: u := new(uint64) if dv != nil { *u = dv.(uint64) } *(fptr.(**uint64)) = u default: log.Printf("proto: can't set default for field %v (sf.kind=%v)", f, sf.kind) } } for _, ni := range dm.nested { f := v.Field(ni) // f is *T or []*T or map[T]*T switch f.Kind() { case reflect.Ptr: if f.IsNil() { continue } setDefaults(f, recur, zeros) case reflect.Slice: for i := 0; i < f.Len(); i++ { e := f.Index(i) if e.IsNil() { continue } setDefaults(e, recur, zeros) } case reflect.Map: for _, k := range f.MapKeys() { e := f.MapIndex(k) if e.IsNil() { continue } setDefaults(e, recur, zeros) } } } } var ( // defaults maps a protocol buffer struct type to a slice of the fields, // with its scalar fields set to their proto-declared non-zero default values. defaultMu sync.RWMutex defaults = make(map[reflect.Type]defaultMessage) int32PtrType = reflect.TypeOf((*int32)(nil)) ) // defaultMessage represents information about the default values of a message. type defaultMessage struct { scalars []scalarField nested []int // struct field index of nested messages } type scalarField struct { index int // struct field index kind reflect.Kind // element type (the T in *T or []T) value interface{} // the proto-declared default value, or nil } // t is a struct type. func buildDefaultMessage(t reflect.Type) (dm defaultMessage) { sprop := GetProperties(t) for _, prop := range sprop.Prop { fi, ok := sprop.decoderTags.get(prop.Tag) if !ok { // XXX_unrecognized continue } ft := t.Field(fi).Type sf, nested, err := fieldDefault(ft, prop) switch { case err != nil: log.Print(err) case nested: dm.nested = append(dm.nested, fi) case sf != nil: sf.index = fi dm.scalars = append(dm.scalars, *sf) } } return dm } // fieldDefault returns the scalarField for field type ft. // sf will be nil if the field can not have a default. // nestedMessage will be true if this is a nested message. // Note that sf.index is not set on return. func fieldDefault(ft reflect.Type, prop *Properties) (sf *scalarField, nestedMessage bool, err error) { var canHaveDefault bool switch ft.Kind() { case reflect.Ptr: if ft.Elem().Kind() == reflect.Struct { nestedMessage = true } else { canHaveDefault = true // proto2 scalar field } case reflect.Slice: switch ft.Elem().Kind() { case reflect.Ptr: nestedMessage = true // repeated message case reflect.Uint8: canHaveDefault = true // bytes field } case reflect.Map: if ft.Elem().Kind() == reflect.Ptr { nestedMessage = true // map with message values } } if !canHaveDefault { if nestedMessage { return nil, true, nil } return nil, false, nil } // We now know that ft is a pointer or slice. sf = &scalarField{kind: ft.Elem().Kind()} // scalar fields without defaults if !prop.HasDefault { return sf, false, nil } // a scalar field: either *T or []byte switch ft.Elem().Kind() { case reflect.Bool: x, err := strconv.ParseBool(prop.Default) if err != nil { return nil, false, fmt.Errorf("proto: bad default bool %q: %v", prop.Default, err) } sf.value = x case reflect.Float32: x, err := strconv.ParseFloat(prop.Default, 32) if err != nil { return nil, false, fmt.Errorf("proto: bad default float32 %q: %v", prop.Default, err) } sf.value = float32(x) case reflect.Float64: x, err := strconv.ParseFloat(prop.Default, 64) if err != nil { return nil, false, fmt.Errorf("proto: bad default float64 %q: %v", prop.Default, err) } sf.value = x case reflect.Int32: x, err := strconv.ParseInt(prop.Default, 10, 32) if err != nil { return nil, false, fmt.Errorf("proto: bad default int32 %q: %v", prop.Default, err) } sf.value = int32(x) case reflect.Int64: x, err := strconv.ParseInt(prop.Default, 10, 64) if err != nil { return nil, false, fmt.Errorf("proto: bad default int64 %q: %v", prop.Default, err) } sf.value = x case reflect.String: sf.value = prop.Default case reflect.Uint8: // []byte (not *uint8) sf.value = []byte(prop.Default) case reflect.Uint32: x, err := strconv.ParseUint(prop.Default, 10, 32) if err != nil { return nil, false, fmt.Errorf("proto: bad default uint32 %q: %v", prop.Default, err) } sf.value = uint32(x) case reflect.Uint64: x, err := strconv.ParseUint(prop.Default, 10, 64) if err != nil { return nil, false, fmt.Errorf("proto: bad default uint64 %q: %v", prop.Default, err) } sf.value = x default: return nil, false, fmt.Errorf("proto: unhandled def kind %v", ft.Elem().Kind()) } return sf, false, nil } // Map fields may have key types of non-float scalars, strings and enums. // The easiest way to sort them in some deterministic order is to use fmt. // If this turns out to be inefficient we can always consider other options, // such as doing a Schwartzian transform. func mapKeys(vs []reflect.Value) sort.Interface { s := mapKeySorter{ vs: vs, // default Less function: textual comparison less: func(a, b reflect.Value) bool { return fmt.Sprint(a.Interface()) < fmt.Sprint(b.Interface()) }, } // Type specialization per https://developers.google.com/protocol-buffers/docs/proto#maps; // numeric keys are sorted numerically. if len(vs) == 0 { return s } switch vs[0].Kind() { case reflect.Int32, reflect.Int64: s.less = func(a, b reflect.Value) bool { return a.Int() < b.Int() } case reflect.Uint32, reflect.Uint64: s.less = func(a, b reflect.Value) bool { return a.Uint() < b.Uint() } } return s } type mapKeySorter struct { vs []reflect.Value less func(a, b reflect.Value) bool } func (s mapKeySorter) Len() int { return len(s.vs) } func (s mapKeySorter) Swap(i, j int) { s.vs[i], s.vs[j] = s.vs[j], s.vs[i] } func (s mapKeySorter) Less(i, j int) bool { return s.less(s.vs[i], s.vs[j]) } // isProto3Zero reports whether v is a zero proto3 value. func isProto3Zero(v reflect.Value) bool { switch v.Kind() { case reflect.Bool: return !v.Bool() case reflect.Int32, reflect.Int64: return v.Int() == 0 case reflect.Uint32, reflect.Uint64: return v.Uint() == 0 case reflect.Float32, reflect.Float64: return v.Float() == 0 case reflect.String: return v.String() == "" } return false } // ProtoPackageIsVersion2 is referenced from generated protocol buffer files // to assert that that code is compatible with this version of the proto package. const ProtoPackageIsVersion2 = true // ProtoPackageIsVersion1 is referenced from generated protocol buffer files // to assert that that code is compatible with this version of the proto package. const ProtoPackageIsVersion1 = true ================================================ FILE: vendor/github.com/golang/protobuf/proto/map_test.go ================================================ package proto_test import ( "fmt" "testing" "github.com/golang/protobuf/proto" ppb "github.com/golang/protobuf/proto/proto3_proto" ) func marshalled() []byte { m := &ppb.IntMaps{} for i := 0; i < 1000; i++ { m.Maps = append(m.Maps, &ppb.IntMap{ Rtt: map[int32]int32{1: 2}, }) } b, err := proto.Marshal(m) if err != nil { panic(fmt.Sprintf("Can't marshal %+v: %v", m, err)) } return b } func BenchmarkConcurrentMapUnmarshal(b *testing.B) { in := marshalled() b.RunParallel(func(pb *testing.PB) { for pb.Next() { var out ppb.IntMaps if err := proto.Unmarshal(in, &out); err != nil { b.Errorf("Can't unmarshal ppb.IntMaps: %v", err) } } }) } func BenchmarkSequentialMapUnmarshal(b *testing.B) { in := marshalled() b.ResetTimer() for i := 0; i < b.N; i++ { var out ppb.IntMaps if err := proto.Unmarshal(in, &out); err != nil { b.Errorf("Can't unmarshal ppb.IntMaps: %v", err) } } } ================================================ FILE: vendor/github.com/golang/protobuf/proto/message_set.go ================================================ // Go support for Protocol Buffers - Google's data interchange format // // Copyright 2010 The Go Authors. All rights reserved. // https://github.com/golang/protobuf // // 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. package proto /* * Support for message sets. */ import ( "bytes" "encoding/json" "errors" "fmt" "reflect" "sort" ) // errNoMessageTypeID occurs when a protocol buffer does not have a message type ID. // A message type ID is required for storing a protocol buffer in a message set. var errNoMessageTypeID = errors.New("proto does not have a message type ID") // The first two types (_MessageSet_Item and messageSet) // model what the protocol compiler produces for the following protocol message: // message MessageSet { // repeated group Item = 1 { // required int32 type_id = 2; // required string message = 3; // }; // } // That is the MessageSet wire format. We can't use a proto to generate these // because that would introduce a circular dependency between it and this package. type _MessageSet_Item struct { TypeId *int32 `protobuf:"varint,2,req,name=type_id"` Message []byte `protobuf:"bytes,3,req,name=message"` } type messageSet struct { Item []*_MessageSet_Item `protobuf:"group,1,rep"` XXX_unrecognized []byte // TODO: caching? } // Make sure messageSet is a Message. var _ Message = (*messageSet)(nil) // messageTypeIder is an interface satisfied by a protocol buffer type // that may be stored in a MessageSet. type messageTypeIder interface { MessageTypeId() int32 } func (ms *messageSet) find(pb Message) *_MessageSet_Item { mti, ok := pb.(messageTypeIder) if !ok { return nil } id := mti.MessageTypeId() for _, item := range ms.Item { if *item.TypeId == id { return item } } return nil } func (ms *messageSet) Has(pb Message) bool { if ms.find(pb) != nil { return true } return false } func (ms *messageSet) Unmarshal(pb Message) error { if item := ms.find(pb); item != nil { return Unmarshal(item.Message, pb) } if _, ok := pb.(messageTypeIder); !ok { return errNoMessageTypeID } return nil // TODO: return error instead? } func (ms *messageSet) Marshal(pb Message) error { msg, err := Marshal(pb) if err != nil { return err } if item := ms.find(pb); item != nil { // reuse existing item item.Message = msg return nil } mti, ok := pb.(messageTypeIder) if !ok { return errNoMessageTypeID } mtid := mti.MessageTypeId() ms.Item = append(ms.Item, &_MessageSet_Item{ TypeId: &mtid, Message: msg, }) return nil } func (ms *messageSet) Reset() { *ms = messageSet{} } func (ms *messageSet) String() string { return CompactTextString(ms) } func (*messageSet) ProtoMessage() {} // Support for the message_set_wire_format message option. func skipVarint(buf []byte) []byte { i := 0 for ; buf[i]&0x80 != 0; i++ { } return buf[i+1:] } // MarshalMessageSet encodes the extension map represented by m in the message set wire format. // It is called by generated Marshal methods on protocol buffer messages with the message_set_wire_format option. func MarshalMessageSet(exts interface{}) ([]byte, error) { var m map[int32]Extension switch exts := exts.(type) { case *XXX_InternalExtensions: if err := encodeExtensions(exts); err != nil { return nil, err } m, _ = exts.extensionsRead() case map[int32]Extension: if err := encodeExtensionsMap(exts); err != nil { return nil, err } m = exts default: return nil, errors.New("proto: not an extension map") } // Sort extension IDs to provide a deterministic encoding. // See also enc_map in encode.go. ids := make([]int, 0, len(m)) for id := range m { ids = append(ids, int(id)) } sort.Ints(ids) ms := &messageSet{Item: make([]*_MessageSet_Item, 0, len(m))} for _, id := range ids { e := m[int32(id)] // Remove the wire type and field number varint, as well as the length varint. msg := skipVarint(skipVarint(e.enc)) ms.Item = append(ms.Item, &_MessageSet_Item{ TypeId: Int32(int32(id)), Message: msg, }) } return Marshal(ms) } // UnmarshalMessageSet decodes the extension map encoded in buf in the message set wire format. // It is called by generated Unmarshal methods on protocol buffer messages with the message_set_wire_format option. func UnmarshalMessageSet(buf []byte, exts interface{}) error { var m map[int32]Extension switch exts := exts.(type) { case *XXX_InternalExtensions: m = exts.extensionsWrite() case map[int32]Extension: m = exts default: return errors.New("proto: not an extension map") } ms := new(messageSet) if err := Unmarshal(buf, ms); err != nil { return err } for _, item := range ms.Item { id := *item.TypeId msg := item.Message // Restore wire type and field number varint, plus length varint. // Be careful to preserve duplicate items. b := EncodeVarint(uint64(id)<<3 | WireBytes) if ext, ok := m[id]; ok { // Existing data; rip off the tag and length varint // so we join the new data correctly. // We can assume that ext.enc is set because we are unmarshaling. o := ext.enc[len(b):] // skip wire type and field number _, n := DecodeVarint(o) // calculate length of length varint o = o[n:] // skip length varint msg = append(o, msg...) // join old data and new data } b = append(b, EncodeVarint(uint64(len(msg)))...) b = append(b, msg...) m[id] = Extension{enc: b} } return nil } // MarshalMessageSetJSON encodes the extension map represented by m in JSON format. // It is called by generated MarshalJSON methods on protocol buffer messages with the message_set_wire_format option. func MarshalMessageSetJSON(exts interface{}) ([]byte, error) { var m map[int32]Extension switch exts := exts.(type) { case *XXX_InternalExtensions: m, _ = exts.extensionsRead() case map[int32]Extension: m = exts default: return nil, errors.New("proto: not an extension map") } var b bytes.Buffer b.WriteByte('{') // Process the map in key order for deterministic output. ids := make([]int32, 0, len(m)) for id := range m { ids = append(ids, id) } sort.Sort(int32Slice(ids)) // int32Slice defined in text.go for i, id := range ids { ext := m[id] if i > 0 { b.WriteByte(',') } msd, ok := messageSetMap[id] if !ok { // Unknown type; we can't render it, so skip it. continue } fmt.Fprintf(&b, `"[%s]":`, msd.name) x := ext.value if x == nil { x = reflect.New(msd.t.Elem()).Interface() if err := Unmarshal(ext.enc, x.(Message)); err != nil { return nil, err } } d, err := json.Marshal(x) if err != nil { return nil, err } b.Write(d) } b.WriteByte('}') return b.Bytes(), nil } // UnmarshalMessageSetJSON decodes the extension map encoded in buf in JSON format. // It is called by generated UnmarshalJSON methods on protocol buffer messages with the message_set_wire_format option. func UnmarshalMessageSetJSON(buf []byte, exts interface{}) error { // Common-case fast path. if len(buf) == 0 || bytes.Equal(buf, []byte("{}")) { return nil } // This is fairly tricky, and it's not clear that it is needed. return errors.New("TODO: UnmarshalMessageSetJSON not yet implemented") } // A global registry of types that can be used in a MessageSet. var messageSetMap = make(map[int32]messageSetDesc) type messageSetDesc struct { t reflect.Type // pointer to struct name string } // RegisterMessageSetType is called from the generated code. func RegisterMessageSetType(m Message, fieldNum int32, name string) { messageSetMap[fieldNum] = messageSetDesc{ t: reflect.TypeOf(m), name: name, } } ================================================ FILE: vendor/github.com/golang/protobuf/proto/message_set_test.go ================================================ // Go support for Protocol Buffers - Google's data interchange format // // Copyright 2014 The Go Authors. All rights reserved. // https://github.com/golang/protobuf // // 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. package proto import ( "bytes" "testing" ) func TestUnmarshalMessageSetWithDuplicate(t *testing.T) { // Check that a repeated message set entry will be concatenated. in := &messageSet{ Item: []*_MessageSet_Item{ {TypeId: Int32(12345), Message: []byte("hoo")}, {TypeId: Int32(12345), Message: []byte("hah")}, }, } b, err := Marshal(in) if err != nil { t.Fatalf("Marshal: %v", err) } t.Logf("Marshaled bytes: %q", b) var extensions XXX_InternalExtensions if err := UnmarshalMessageSet(b, &extensions); err != nil { t.Fatalf("UnmarshalMessageSet: %v", err) } ext, ok := extensions.p.extensionMap[12345] if !ok { t.Fatalf("Didn't retrieve extension 12345; map is %v", extensions.p.extensionMap) } // Skip wire type/field number and length varints. got := skipVarint(skipVarint(ext.enc)) if want := []byte("hoohah"); !bytes.Equal(got, want) { t.Errorf("Combined extension is %q, want %q", got, want) } } ================================================ FILE: vendor/github.com/golang/protobuf/proto/pointer_reflect.go ================================================ // Go support for Protocol Buffers - Google's data interchange format // // Copyright 2012 The Go Authors. All rights reserved. // https://github.com/golang/protobuf // // 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. // +build appengine js // This file contains an implementation of proto field accesses using package reflect. // It is slower than the code in pointer_unsafe.go but it avoids package unsafe and can // be used on App Engine. package proto import ( "math" "reflect" ) // A structPointer is a pointer to a struct. type structPointer struct { v reflect.Value } // toStructPointer returns a structPointer equivalent to the given reflect value. // The reflect value must itself be a pointer to a struct. func toStructPointer(v reflect.Value) structPointer { return structPointer{v} } // IsNil reports whether p is nil. func structPointer_IsNil(p structPointer) bool { return p.v.IsNil() } // Interface returns the struct pointer as an interface value. func structPointer_Interface(p structPointer, _ reflect.Type) interface{} { return p.v.Interface() } // A field identifies a field in a struct, accessible from a structPointer. // In this implementation, a field is identified by the sequence of field indices // passed to reflect's FieldByIndex. type field []int // toField returns a field equivalent to the given reflect field. func toField(f *reflect.StructField) field { return f.Index } // invalidField is an invalid field identifier. var invalidField = field(nil) // IsValid reports whether the field identifier is valid. func (f field) IsValid() bool { return f != nil } // field returns the given field in the struct as a reflect value. func structPointer_field(p structPointer, f field) reflect.Value { // Special case: an extension map entry with a value of type T // passes a *T to the struct-handling code with a zero field, // expecting that it will be treated as equivalent to *struct{ X T }, // which has the same memory layout. We have to handle that case // specially, because reflect will panic if we call FieldByIndex on a // non-struct. if f == nil { return p.v.Elem() } return p.v.Elem().FieldByIndex(f) } // ifield returns the given field in the struct as an interface value. func structPointer_ifield(p structPointer, f field) interface{} { return structPointer_field(p, f).Addr().Interface() } // Bytes returns the address of a []byte field in the struct. func structPointer_Bytes(p structPointer, f field) *[]byte { return structPointer_ifield(p, f).(*[]byte) } // BytesSlice returns the address of a [][]byte field in the struct. func structPointer_BytesSlice(p structPointer, f field) *[][]byte { return structPointer_ifield(p, f).(*[][]byte) } // Bool returns the address of a *bool field in the struct. func structPointer_Bool(p structPointer, f field) **bool { return structPointer_ifield(p, f).(**bool) } // BoolVal returns the address of a bool field in the struct. func structPointer_BoolVal(p structPointer, f field) *bool { return structPointer_ifield(p, f).(*bool) } // BoolSlice returns the address of a []bool field in the struct. func structPointer_BoolSlice(p structPointer, f field) *[]bool { return structPointer_ifield(p, f).(*[]bool) } // String returns the address of a *string field in the struct. func structPointer_String(p structPointer, f field) **string { return structPointer_ifield(p, f).(**string) } // StringVal returns the address of a string field in the struct. func structPointer_StringVal(p structPointer, f field) *string { return structPointer_ifield(p, f).(*string) } // StringSlice returns the address of a []string field in the struct. func structPointer_StringSlice(p structPointer, f field) *[]string { return structPointer_ifield(p, f).(*[]string) } // Extensions returns the address of an extension map field in the struct. func structPointer_Extensions(p structPointer, f field) *XXX_InternalExtensions { return structPointer_ifield(p, f).(*XXX_InternalExtensions) } // ExtMap returns the address of an extension map field in the struct. func structPointer_ExtMap(p structPointer, f field) *map[int32]Extension { return structPointer_ifield(p, f).(*map[int32]Extension) } // NewAt returns the reflect.Value for a pointer to a field in the struct. func structPointer_NewAt(p structPointer, f field, typ reflect.Type) reflect.Value { return structPointer_field(p, f).Addr() } // SetStructPointer writes a *struct field in the struct. func structPointer_SetStructPointer(p structPointer, f field, q structPointer) { structPointer_field(p, f).Set(q.v) } // GetStructPointer reads a *struct field in the struct. func structPointer_GetStructPointer(p structPointer, f field) structPointer { return structPointer{structPointer_field(p, f)} } // StructPointerSlice the address of a []*struct field in the struct. func structPointer_StructPointerSlice(p structPointer, f field) structPointerSlice { return structPointerSlice{structPointer_field(p, f)} } // A structPointerSlice represents the address of a slice of pointers to structs // (themselves messages or groups). That is, v.Type() is *[]*struct{...}. type structPointerSlice struct { v reflect.Value } func (p structPointerSlice) Len() int { return p.v.Len() } func (p structPointerSlice) Index(i int) structPointer { return structPointer{p.v.Index(i)} } func (p structPointerSlice) Append(q structPointer) { p.v.Set(reflect.Append(p.v, q.v)) } var ( int32Type = reflect.TypeOf(int32(0)) uint32Type = reflect.TypeOf(uint32(0)) float32Type = reflect.TypeOf(float32(0)) int64Type = reflect.TypeOf(int64(0)) uint64Type = reflect.TypeOf(uint64(0)) float64Type = reflect.TypeOf(float64(0)) ) // A word32 represents a field of type *int32, *uint32, *float32, or *enum. // That is, v.Type() is *int32, *uint32, *float32, or *enum and v is assignable. type word32 struct { v reflect.Value } // IsNil reports whether p is nil. func word32_IsNil(p word32) bool { return p.v.IsNil() } // Set sets p to point at a newly allocated word with bits set to x. func word32_Set(p word32, o *Buffer, x uint32) { t := p.v.Type().Elem() switch t { case int32Type: if len(o.int32s) == 0 { o.int32s = make([]int32, uint32PoolSize) } o.int32s[0] = int32(x) p.v.Set(reflect.ValueOf(&o.int32s[0])) o.int32s = o.int32s[1:] return case uint32Type: if len(o.uint32s) == 0 { o.uint32s = make([]uint32, uint32PoolSize) } o.uint32s[0] = x p.v.Set(reflect.ValueOf(&o.uint32s[0])) o.uint32s = o.uint32s[1:] return case float32Type: if len(o.float32s) == 0 { o.float32s = make([]float32, uint32PoolSize) } o.float32s[0] = math.Float32frombits(x) p.v.Set(reflect.ValueOf(&o.float32s[0])) o.float32s = o.float32s[1:] return } // must be enum p.v.Set(reflect.New(t)) p.v.Elem().SetInt(int64(int32(x))) } // Get gets the bits pointed at by p, as a uint32. func word32_Get(p word32) uint32 { elem := p.v.Elem() switch elem.Kind() { case reflect.Int32: return uint32(elem.Int()) case reflect.Uint32: return uint32(elem.Uint()) case reflect.Float32: return math.Float32bits(float32(elem.Float())) } panic("unreachable") } // Word32 returns a reference to a *int32, *uint32, *float32, or *enum field in the struct. func structPointer_Word32(p structPointer, f field) word32 { return word32{structPointer_field(p, f)} } // A word32Val represents a field of type int32, uint32, float32, or enum. // That is, v.Type() is int32, uint32, float32, or enum and v is assignable. type word32Val struct { v reflect.Value } // Set sets *p to x. func word32Val_Set(p word32Val, x uint32) { switch p.v.Type() { case int32Type: p.v.SetInt(int64(x)) return case uint32Type: p.v.SetUint(uint64(x)) return case float32Type: p.v.SetFloat(float64(math.Float32frombits(x))) return } // must be enum p.v.SetInt(int64(int32(x))) } // Get gets the bits pointed at by p, as a uint32. func word32Val_Get(p word32Val) uint32 { elem := p.v switch elem.Kind() { case reflect.Int32: return uint32(elem.Int()) case reflect.Uint32: return uint32(elem.Uint()) case reflect.Float32: return math.Float32bits(float32(elem.Float())) } panic("unreachable") } // Word32Val returns a reference to a int32, uint32, float32, or enum field in the struct. func structPointer_Word32Val(p structPointer, f field) word32Val { return word32Val{structPointer_field(p, f)} } // A word32Slice is a slice of 32-bit values. // That is, v.Type() is []int32, []uint32, []float32, or []enum. type word32Slice struct { v reflect.Value } func (p word32Slice) Append(x uint32) { n, m := p.v.Len(), p.v.Cap() if n < m { p.v.SetLen(n + 1) } else { t := p.v.Type().Elem() p.v.Set(reflect.Append(p.v, reflect.Zero(t))) } elem := p.v.Index(n) switch elem.Kind() { case reflect.Int32: elem.SetInt(int64(int32(x))) case reflect.Uint32: elem.SetUint(uint64(x)) case reflect.Float32: elem.SetFloat(float64(math.Float32frombits(x))) } } func (p word32Slice) Len() int { return p.v.Len() } func (p word32Slice) Index(i int) uint32 { elem := p.v.Index(i) switch elem.Kind() { case reflect.Int32: return uint32(elem.Int()) case reflect.Uint32: return uint32(elem.Uint()) case reflect.Float32: return math.Float32bits(float32(elem.Float())) } panic("unreachable") } // Word32Slice returns a reference to a []int32, []uint32, []float32, or []enum field in the struct. func structPointer_Word32Slice(p structPointer, f field) word32Slice { return word32Slice{structPointer_field(p, f)} } // word64 is like word32 but for 64-bit values. type word64 struct { v reflect.Value } func word64_Set(p word64, o *Buffer, x uint64) { t := p.v.Type().Elem() switch t { case int64Type: if len(o.int64s) == 0 { o.int64s = make([]int64, uint64PoolSize) } o.int64s[0] = int64(x) p.v.Set(reflect.ValueOf(&o.int64s[0])) o.int64s = o.int64s[1:] return case uint64Type: if len(o.uint64s) == 0 { o.uint64s = make([]uint64, uint64PoolSize) } o.uint64s[0] = x p.v.Set(reflect.ValueOf(&o.uint64s[0])) o.uint64s = o.uint64s[1:] return case float64Type: if len(o.float64s) == 0 { o.float64s = make([]float64, uint64PoolSize) } o.float64s[0] = math.Float64frombits(x) p.v.Set(reflect.ValueOf(&o.float64s[0])) o.float64s = o.float64s[1:] return } panic("unreachable") } func word64_IsNil(p word64) bool { return p.v.IsNil() } func word64_Get(p word64) uint64 { elem := p.v.Elem() switch elem.Kind() { case reflect.Int64: return uint64(elem.Int()) case reflect.Uint64: return elem.Uint() case reflect.Float64: return math.Float64bits(elem.Float()) } panic("unreachable") } func structPointer_Word64(p structPointer, f field) word64 { return word64{structPointer_field(p, f)} } // word64Val is like word32Val but for 64-bit values. type word64Val struct { v reflect.Value } func word64Val_Set(p word64Val, o *Buffer, x uint64) { switch p.v.Type() { case int64Type: p.v.SetInt(int64(x)) return case uint64Type: p.v.SetUint(x) return case float64Type: p.v.SetFloat(math.Float64frombits(x)) return } panic("unreachable") } func word64Val_Get(p word64Val) uint64 { elem := p.v switch elem.Kind() { case reflect.Int64: return uint64(elem.Int()) case reflect.Uint64: return elem.Uint() case reflect.Float64: return math.Float64bits(elem.Float()) } panic("unreachable") } func structPointer_Word64Val(p structPointer, f field) word64Val { return word64Val{structPointer_field(p, f)} } type word64Slice struct { v reflect.Value } func (p word64Slice) Append(x uint64) { n, m := p.v.Len(), p.v.Cap() if n < m { p.v.SetLen(n + 1) } else { t := p.v.Type().Elem() p.v.Set(reflect.Append(p.v, reflect.Zero(t))) } elem := p.v.Index(n) switch elem.Kind() { case reflect.Int64: elem.SetInt(int64(int64(x))) case reflect.Uint64: elem.SetUint(uint64(x)) case reflect.Float64: elem.SetFloat(float64(math.Float64frombits(x))) } } func (p word64Slice) Len() int { return p.v.Len() } func (p word64Slice) Index(i int) uint64 { elem := p.v.Index(i) switch elem.Kind() { case reflect.Int64: return uint64(elem.Int()) case reflect.Uint64: return uint64(elem.Uint()) case reflect.Float64: return math.Float64bits(float64(elem.Float())) } panic("unreachable") } func structPointer_Word64Slice(p structPointer, f field) word64Slice { return word64Slice{structPointer_field(p, f)} } ================================================ FILE: vendor/github.com/golang/protobuf/proto/pointer_unsafe.go ================================================ // Go support for Protocol Buffers - Google's data interchange format // // Copyright 2012 The Go Authors. All rights reserved. // https://github.com/golang/protobuf // // 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. // +build !appengine,!js // This file contains the implementation of the proto field accesses using package unsafe. package proto import ( "reflect" "unsafe" ) // NOTE: These type_Foo functions would more idiomatically be methods, // but Go does not allow methods on pointer types, and we must preserve // some pointer type for the garbage collector. We use these // funcs with clunky names as our poor approximation to methods. // // An alternative would be // type structPointer struct { p unsafe.Pointer } // but that does not registerize as well. // A structPointer is a pointer to a struct. type structPointer unsafe.Pointer // toStructPointer returns a structPointer equivalent to the given reflect value. func toStructPointer(v reflect.Value) structPointer { return structPointer(unsafe.Pointer(v.Pointer())) } // IsNil reports whether p is nil. func structPointer_IsNil(p structPointer) bool { return p == nil } // Interface returns the struct pointer, assumed to have element type t, // as an interface value. func structPointer_Interface(p structPointer, t reflect.Type) interface{} { return reflect.NewAt(t, unsafe.Pointer(p)).Interface() } // A field identifies a field in a struct, accessible from a structPointer. // In this implementation, a field is identified by its byte offset from the start of the struct. type field uintptr // toField returns a field equivalent to the given reflect field. func toField(f *reflect.StructField) field { return field(f.Offset) } // invalidField is an invalid field identifier. const invalidField = ^field(0) // IsValid reports whether the field identifier is valid. func (f field) IsValid() bool { return f != ^field(0) } // Bytes returns the address of a []byte field in the struct. func structPointer_Bytes(p structPointer, f field) *[]byte { return (*[]byte)(unsafe.Pointer(uintptr(p) + uintptr(f))) } // BytesSlice returns the address of a [][]byte field in the struct. func structPointer_BytesSlice(p structPointer, f field) *[][]byte { return (*[][]byte)(unsafe.Pointer(uintptr(p) + uintptr(f))) } // Bool returns the address of a *bool field in the struct. func structPointer_Bool(p structPointer, f field) **bool { return (**bool)(unsafe.Pointer(uintptr(p) + uintptr(f))) } // BoolVal returns the address of a bool field in the struct. func structPointer_BoolVal(p structPointer, f field) *bool { return (*bool)(unsafe.Pointer(uintptr(p) + uintptr(f))) } // BoolSlice returns the address of a []bool field in the struct. func structPointer_BoolSlice(p structPointer, f field) *[]bool { return (*[]bool)(unsafe.Pointer(uintptr(p) + uintptr(f))) } // String returns the address of a *string field in the struct. func structPointer_String(p structPointer, f field) **string { return (**string)(unsafe.Pointer(uintptr(p) + uintptr(f))) } // StringVal returns the address of a string field in the struct. func structPointer_StringVal(p structPointer, f field) *string { return (*string)(unsafe.Pointer(uintptr(p) + uintptr(f))) } // StringSlice returns the address of a []string field in the struct. func structPointer_StringSlice(p structPointer, f field) *[]string { return (*[]string)(unsafe.Pointer(uintptr(p) + uintptr(f))) } // ExtMap returns the address of an extension map field in the struct. func structPointer_Extensions(p structPointer, f field) *XXX_InternalExtensions { return (*XXX_InternalExtensions)(unsafe.Pointer(uintptr(p) + uintptr(f))) } func structPointer_ExtMap(p structPointer, f field) *map[int32]Extension { return (*map[int32]Extension)(unsafe.Pointer(uintptr(p) + uintptr(f))) } // NewAt returns the reflect.Value for a pointer to a field in the struct. func structPointer_NewAt(p structPointer, f field, typ reflect.Type) reflect.Value { return reflect.NewAt(typ, unsafe.Pointer(uintptr(p)+uintptr(f))) } // SetStructPointer writes a *struct field in the struct. func structPointer_SetStructPointer(p structPointer, f field, q structPointer) { *(*structPointer)(unsafe.Pointer(uintptr(p) + uintptr(f))) = q } // GetStructPointer reads a *struct field in the struct. func structPointer_GetStructPointer(p structPointer, f field) structPointer { return *(*structPointer)(unsafe.Pointer(uintptr(p) + uintptr(f))) } // StructPointerSlice the address of a []*struct field in the struct. func structPointer_StructPointerSlice(p structPointer, f field) *structPointerSlice { return (*structPointerSlice)(unsafe.Pointer(uintptr(p) + uintptr(f))) } // A structPointerSlice represents a slice of pointers to structs (themselves submessages or groups). type structPointerSlice []structPointer func (v *structPointerSlice) Len() int { return len(*v) } func (v *structPointerSlice) Index(i int) structPointer { return (*v)[i] } func (v *structPointerSlice) Append(p structPointer) { *v = append(*v, p) } // A word32 is the address of a "pointer to 32-bit value" field. type word32 **uint32 // IsNil reports whether *v is nil. func word32_IsNil(p word32) bool { return *p == nil } // Set sets *v to point at a newly allocated word set to x. func word32_Set(p word32, o *Buffer, x uint32) { if len(o.uint32s) == 0 { o.uint32s = make([]uint32, uint32PoolSize) } o.uint32s[0] = x *p = &o.uint32s[0] o.uint32s = o.uint32s[1:] } // Get gets the value pointed at by *v. func word32_Get(p word32) uint32 { return **p } // Word32 returns the address of a *int32, *uint32, *float32, or *enum field in the struct. func structPointer_Word32(p structPointer, f field) word32 { return word32((**uint32)(unsafe.Pointer(uintptr(p) + uintptr(f)))) } // A word32Val is the address of a 32-bit value field. type word32Val *uint32 // Set sets *p to x. func word32Val_Set(p word32Val, x uint32) { *p = x } // Get gets the value pointed at by p. func word32Val_Get(p word32Val) uint32 { return *p } // Word32Val returns the address of a *int32, *uint32, *float32, or *enum field in the struct. func structPointer_Word32Val(p structPointer, f field) word32Val { return word32Val((*uint32)(unsafe.Pointer(uintptr(p) + uintptr(f)))) } // A word32Slice is a slice of 32-bit values. type word32Slice []uint32 func (v *word32Slice) Append(x uint32) { *v = append(*v, x) } func (v *word32Slice) Len() int { return len(*v) } func (v *word32Slice) Index(i int) uint32 { return (*v)[i] } // Word32Slice returns the address of a []int32, []uint32, []float32, or []enum field in the struct. func structPointer_Word32Slice(p structPointer, f field) *word32Slice { return (*word32Slice)(unsafe.Pointer(uintptr(p) + uintptr(f))) } // word64 is like word32 but for 64-bit values. type word64 **uint64 func word64_Set(p word64, o *Buffer, x uint64) { if len(o.uint64s) == 0 { o.uint64s = make([]uint64, uint64PoolSize) } o.uint64s[0] = x *p = &o.uint64s[0] o.uint64s = o.uint64s[1:] } func word64_IsNil(p word64) bool { return *p == nil } func word64_Get(p word64) uint64 { return **p } func structPointer_Word64(p structPointer, f field) word64 { return word64((**uint64)(unsafe.Pointer(uintptr(p) + uintptr(f)))) } // word64Val is like word32Val but for 64-bit values. type word64Val *uint64 func word64Val_Set(p word64Val, o *Buffer, x uint64) { *p = x } func word64Val_Get(p word64Val) uint64 { return *p } func structPointer_Word64Val(p structPointer, f field) word64Val { return word64Val((*uint64)(unsafe.Pointer(uintptr(p) + uintptr(f)))) } // word64Slice is like word32Slice but for 64-bit values. type word64Slice []uint64 func (v *word64Slice) Append(x uint64) { *v = append(*v, x) } func (v *word64Slice) Len() int { return len(*v) } func (v *word64Slice) Index(i int) uint64 { return (*v)[i] } func structPointer_Word64Slice(p structPointer, f field) *word64Slice { return (*word64Slice)(unsafe.Pointer(uintptr(p) + uintptr(f))) } ================================================ FILE: vendor/github.com/golang/protobuf/proto/properties.go ================================================ // Go support for Protocol Buffers - Google's data interchange format // // Copyright 2010 The Go Authors. All rights reserved. // https://github.com/golang/protobuf // // 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. package proto /* * Routines for encoding data into the wire format for protocol buffers. */ import ( "fmt" "log" "os" "reflect" "sort" "strconv" "strings" "sync" ) const debug bool = false // Constants that identify the encoding of a value on the wire. const ( WireVarint = 0 WireFixed64 = 1 WireBytes = 2 WireStartGroup = 3 WireEndGroup = 4 WireFixed32 = 5 ) const startSize = 10 // initial slice/string sizes // Encoders are defined in encode.go // An encoder outputs the full representation of a field, including its // tag and encoder type. type encoder func(p *Buffer, prop *Properties, base structPointer) error // A valueEncoder encodes a single integer in a particular encoding. type valueEncoder func(o *Buffer, x uint64) error // Sizers are defined in encode.go // A sizer returns the encoded size of a field, including its tag and encoder // type. type sizer func(prop *Properties, base structPointer) int // A valueSizer returns the encoded size of a single integer in a particular // encoding. type valueSizer func(x uint64) int // Decoders are defined in decode.go // A decoder creates a value from its wire representation. // Unrecognized subelements are saved in unrec. type decoder func(p *Buffer, prop *Properties, base structPointer) error // A valueDecoder decodes a single integer in a particular encoding. type valueDecoder func(o *Buffer) (x uint64, err error) // A oneofMarshaler does the marshaling for all oneof fields in a message. type oneofMarshaler func(Message, *Buffer) error // A oneofUnmarshaler does the unmarshaling for a oneof field in a message. type oneofUnmarshaler func(Message, int, int, *Buffer) (bool, error) // A oneofSizer does the sizing for all oneof fields in a message. type oneofSizer func(Message) int // tagMap is an optimization over map[int]int for typical protocol buffer // use-cases. Encoded protocol buffers are often in tag order with small tag // numbers. type tagMap struct { fastTags []int slowTags map[int]int } // tagMapFastLimit is the upper bound on the tag number that will be stored in // the tagMap slice rather than its map. const tagMapFastLimit = 1024 func (p *tagMap) get(t int) (int, bool) { if t > 0 && t < tagMapFastLimit { if t >= len(p.fastTags) { return 0, false } fi := p.fastTags[t] return fi, fi >= 0 } fi, ok := p.slowTags[t] return fi, ok } func (p *tagMap) put(t int, fi int) { if t > 0 && t < tagMapFastLimit { for len(p.fastTags) < t+1 { p.fastTags = append(p.fastTags, -1) } p.fastTags[t] = fi return } if p.slowTags == nil { p.slowTags = make(map[int]int) } p.slowTags[t] = fi } // StructProperties represents properties for all the fields of a struct. // decoderTags and decoderOrigNames should only be used by the decoder. type StructProperties struct { Prop []*Properties // properties for each field reqCount int // required count decoderTags tagMap // map from proto tag to struct field number decoderOrigNames map[string]int // map from original name to struct field number order []int // list of struct field numbers in tag order unrecField field // field id of the XXX_unrecognized []byte field extendable bool // is this an extendable proto oneofMarshaler oneofMarshaler oneofUnmarshaler oneofUnmarshaler oneofSizer oneofSizer stype reflect.Type // OneofTypes contains information about the oneof fields in this message. // It is keyed by the original name of a field. OneofTypes map[string]*OneofProperties } // OneofProperties represents information about a specific field in a oneof. type OneofProperties struct { Type reflect.Type // pointer to generated struct type for this oneof field Field int // struct field number of the containing oneof in the message Prop *Properties } // Implement the sorting interface so we can sort the fields in tag order, as recommended by the spec. // See encode.go, (*Buffer).enc_struct. func (sp *StructProperties) Len() int { return len(sp.order) } func (sp *StructProperties) Less(i, j int) bool { return sp.Prop[sp.order[i]].Tag < sp.Prop[sp.order[j]].Tag } func (sp *StructProperties) Swap(i, j int) { sp.order[i], sp.order[j] = sp.order[j], sp.order[i] } // Properties represents the protocol-specific behavior of a single struct field. type Properties struct { Name string // name of the field, for error messages OrigName string // original name before protocol compiler (always set) JSONName string // name to use for JSON; determined by protoc Wire string WireType int Tag int Required bool Optional bool Repeated bool Packed bool // relevant for repeated primitives only Enum string // set for enum types only proto3 bool // whether this is known to be a proto3 field; set for []byte only oneof bool // whether this is a oneof field Default string // default value HasDefault bool // whether an explicit default was provided def_uint64 uint64 enc encoder valEnc valueEncoder // set for bool and numeric types only field field tagcode []byte // encoding of EncodeVarint((Tag<<3)|WireType) tagbuf [8]byte stype reflect.Type // set for struct types only sprop *StructProperties // set for struct types only isMarshaler bool isUnmarshaler bool mtype reflect.Type // set for map types only mkeyprop *Properties // set for map types only mvalprop *Properties // set for map types only size sizer valSize valueSizer // set for bool and numeric types only dec decoder valDec valueDecoder // set for bool and numeric types only // If this is a packable field, this will be the decoder for the packed version of the field. packedDec decoder } // String formats the properties in the protobuf struct field tag style. func (p *Properties) String() string { s := p.Wire s = "," s += strconv.Itoa(p.Tag) if p.Required { s += ",req" } if p.Optional { s += ",opt" } if p.Repeated { s += ",rep" } if p.Packed { s += ",packed" } s += ",name=" + p.OrigName if p.JSONName != p.OrigName { s += ",json=" + p.JSONName } if p.proto3 { s += ",proto3" } if p.oneof { s += ",oneof" } if len(p.Enum) > 0 { s += ",enum=" + p.Enum } if p.HasDefault { s += ",def=" + p.Default } return s } // Parse populates p by parsing a string in the protobuf struct field tag style. func (p *Properties) Parse(s string) { // "bytes,49,opt,name=foo,def=hello!" fields := strings.Split(s, ",") // breaks def=, but handled below. if len(fields) < 2 { fmt.Fprintf(os.Stderr, "proto: tag has too few fields: %q\n", s) return } p.Wire = fields[0] switch p.Wire { case "varint": p.WireType = WireVarint p.valEnc = (*Buffer).EncodeVarint p.valDec = (*Buffer).DecodeVarint p.valSize = sizeVarint case "fixed32": p.WireType = WireFixed32 p.valEnc = (*Buffer).EncodeFixed32 p.valDec = (*Buffer).DecodeFixed32 p.valSize = sizeFixed32 case "fixed64": p.WireType = WireFixed64 p.valEnc = (*Buffer).EncodeFixed64 p.valDec = (*Buffer).DecodeFixed64 p.valSize = sizeFixed64 case "zigzag32": p.WireType = WireVarint p.valEnc = (*Buffer).EncodeZigzag32 p.valDec = (*Buffer).DecodeZigzag32 p.valSize = sizeZigzag32 case "zigzag64": p.WireType = WireVarint p.valEnc = (*Buffer).EncodeZigzag64 p.valDec = (*Buffer).DecodeZigzag64 p.valSize = sizeZigzag64 case "bytes", "group": p.WireType = WireBytes // no numeric converter for non-numeric types default: fmt.Fprintf(os.Stderr, "proto: tag has unknown wire type: %q\n", s) return } var err error p.Tag, err = strconv.Atoi(fields[1]) if err != nil { return } for i := 2; i < len(fields); i++ { f := fields[i] switch { case f == "req": p.Required = true case f == "opt": p.Optional = true case f == "rep": p.Repeated = true case f == "packed": p.Packed = true case strings.HasPrefix(f, "name="): p.OrigName = f[5:] case strings.HasPrefix(f, "json="): p.JSONName = f[5:] case strings.HasPrefix(f, "enum="): p.Enum = f[5:] case f == "proto3": p.proto3 = true case f == "oneof": p.oneof = true case strings.HasPrefix(f, "def="): p.HasDefault = true p.Default = f[4:] // rest of string if i+1 < len(fields) { // Commas aren't escaped, and def is always last. p.Default += "," + strings.Join(fields[i+1:], ",") break } } } } func logNoSliceEnc(t1, t2 reflect.Type) { fmt.Fprintf(os.Stderr, "proto: no slice oenc for %T = []%T\n", t1, t2) } var protoMessageType = reflect.TypeOf((*Message)(nil)).Elem() // Initialize the fields for encoding and decoding. func (p *Properties) setEncAndDec(typ reflect.Type, f *reflect.StructField, lockGetProp bool) { p.enc = nil p.dec = nil p.size = nil switch t1 := typ; t1.Kind() { default: fmt.Fprintf(os.Stderr, "proto: no coders for %v\n", t1) // proto3 scalar types case reflect.Bool: p.enc = (*Buffer).enc_proto3_bool p.dec = (*Buffer).dec_proto3_bool p.size = size_proto3_bool case reflect.Int32: p.enc = (*Buffer).enc_proto3_int32 p.dec = (*Buffer).dec_proto3_int32 p.size = size_proto3_int32 case reflect.Uint32: p.enc = (*Buffer).enc_proto3_uint32 p.dec = (*Buffer).dec_proto3_int32 // can reuse p.size = size_proto3_uint32 case reflect.Int64, reflect.Uint64: p.enc = (*Buffer).enc_proto3_int64 p.dec = (*Buffer).dec_proto3_int64 p.size = size_proto3_int64 case reflect.Float32: p.enc = (*Buffer).enc_proto3_uint32 // can just treat them as bits p.dec = (*Buffer).dec_proto3_int32 p.size = size_proto3_uint32 case reflect.Float64: p.enc = (*Buffer).enc_proto3_int64 // can just treat them as bits p.dec = (*Buffer).dec_proto3_int64 p.size = size_proto3_int64 case reflect.String: p.enc = (*Buffer).enc_proto3_string p.dec = (*Buffer).dec_proto3_string p.size = size_proto3_string case reflect.Ptr: switch t2 := t1.Elem(); t2.Kind() { default: fmt.Fprintf(os.Stderr, "proto: no encoder function for %v -> %v\n", t1, t2) break case reflect.Bool: p.enc = (*Buffer).enc_bool p.dec = (*Buffer).dec_bool p.size = size_bool case reflect.Int32: p.enc = (*Buffer).enc_int32 p.dec = (*Buffer).dec_int32 p.size = size_int32 case reflect.Uint32: p.enc = (*Buffer).enc_uint32 p.dec = (*Buffer).dec_int32 // can reuse p.size = size_uint32 case reflect.Int64, reflect.Uint64: p.enc = (*Buffer).enc_int64 p.dec = (*Buffer).dec_int64 p.size = size_int64 case reflect.Float32: p.enc = (*Buffer).enc_uint32 // can just treat them as bits p.dec = (*Buffer).dec_int32 p.size = size_uint32 case reflect.Float64: p.enc = (*Buffer).enc_int64 // can just treat them as bits p.dec = (*Buffer).dec_int64 p.size = size_int64 case reflect.String: p.enc = (*Buffer).enc_string p.dec = (*Buffer).dec_string p.size = size_string case reflect.Struct: p.stype = t1.Elem() p.isMarshaler = isMarshaler(t1) p.isUnmarshaler = isUnmarshaler(t1) if p.Wire == "bytes" { p.enc = (*Buffer).enc_struct_message p.dec = (*Buffer).dec_struct_message p.size = size_struct_message } else { p.enc = (*Buffer).enc_struct_group p.dec = (*Buffer).dec_struct_group p.size = size_struct_group } } case reflect.Slice: switch t2 := t1.Elem(); t2.Kind() { default: logNoSliceEnc(t1, t2) break case reflect.Bool: if p.Packed { p.enc = (*Buffer).enc_slice_packed_bool p.size = size_slice_packed_bool } else { p.enc = (*Buffer).enc_slice_bool p.size = size_slice_bool } p.dec = (*Buffer).dec_slice_bool p.packedDec = (*Buffer).dec_slice_packed_bool case reflect.Int32: if p.Packed { p.enc = (*Buffer).enc_slice_packed_int32 p.size = size_slice_packed_int32 } else { p.enc = (*Buffer).enc_slice_int32 p.size = size_slice_int32 } p.dec = (*Buffer).dec_slice_int32 p.packedDec = (*Buffer).dec_slice_packed_int32 case reflect.Uint32: if p.Packed { p.enc = (*Buffer).enc_slice_packed_uint32 p.size = size_slice_packed_uint32 } else { p.enc = (*Buffer).enc_slice_uint32 p.size = size_slice_uint32 } p.dec = (*Buffer).dec_slice_int32 p.packedDec = (*Buffer).dec_slice_packed_int32 case reflect.Int64, reflect.Uint64: if p.Packed { p.enc = (*Buffer).enc_slice_packed_int64 p.size = size_slice_packed_int64 } else { p.enc = (*Buffer).enc_slice_int64 p.size = size_slice_int64 } p.dec = (*Buffer).dec_slice_int64 p.packedDec = (*Buffer).dec_slice_packed_int64 case reflect.Uint8: p.dec = (*Buffer).dec_slice_byte if p.proto3 { p.enc = (*Buffer).enc_proto3_slice_byte p.size = size_proto3_slice_byte } else { p.enc = (*Buffer).enc_slice_byte p.size = size_slice_byte } case reflect.Float32, reflect.Float64: switch t2.Bits() { case 32: // can just treat them as bits if p.Packed { p.enc = (*Buffer).enc_slice_packed_uint32 p.size = size_slice_packed_uint32 } else { p.enc = (*Buffer).enc_slice_uint32 p.size = size_slice_uint32 } p.dec = (*Buffer).dec_slice_int32 p.packedDec = (*Buffer).dec_slice_packed_int32 case 64: // can just treat them as bits if p.Packed { p.enc = (*Buffer).enc_slice_packed_int64 p.size = size_slice_packed_int64 } else { p.enc = (*Buffer).enc_slice_int64 p.size = size_slice_int64 } p.dec = (*Buffer).dec_slice_int64 p.packedDec = (*Buffer).dec_slice_packed_int64 default: logNoSliceEnc(t1, t2) break } case reflect.String: p.enc = (*Buffer).enc_slice_string p.dec = (*Buffer).dec_slice_string p.size = size_slice_string case reflect.Ptr: switch t3 := t2.Elem(); t3.Kind() { default: fmt.Fprintf(os.Stderr, "proto: no ptr oenc for %T -> %T -> %T\n", t1, t2, t3) break case reflect.Struct: p.stype = t2.Elem() p.isMarshaler = isMarshaler(t2) p.isUnmarshaler = isUnmarshaler(t2) if p.Wire == "bytes" { p.enc = (*Buffer).enc_slice_struct_message p.dec = (*Buffer).dec_slice_struct_message p.size = size_slice_struct_message } else { p.enc = (*Buffer).enc_slice_struct_group p.dec = (*Buffer).dec_slice_struct_group p.size = size_slice_struct_group } } case reflect.Slice: switch t2.Elem().Kind() { default: fmt.Fprintf(os.Stderr, "proto: no slice elem oenc for %T -> %T -> %T\n", t1, t2, t2.Elem()) break case reflect.Uint8: p.enc = (*Buffer).enc_slice_slice_byte p.dec = (*Buffer).dec_slice_slice_byte p.size = size_slice_slice_byte } } case reflect.Map: p.enc = (*Buffer).enc_new_map p.dec = (*Buffer).dec_new_map p.size = size_new_map p.mtype = t1 p.mkeyprop = &Properties{} p.mkeyprop.init(reflect.PtrTo(p.mtype.Key()), "Key", f.Tag.Get("protobuf_key"), nil, lockGetProp) p.mvalprop = &Properties{} vtype := p.mtype.Elem() if vtype.Kind() != reflect.Ptr && vtype.Kind() != reflect.Slice { // The value type is not a message (*T) or bytes ([]byte), // so we need encoders for the pointer to this type. vtype = reflect.PtrTo(vtype) } p.mvalprop.init(vtype, "Value", f.Tag.Get("protobuf_val"), nil, lockGetProp) } // precalculate tag code wire := p.WireType if p.Packed { wire = WireBytes } x := uint32(p.Tag)<<3 | uint32(wire) i := 0 for i = 0; x > 127; i++ { p.tagbuf[i] = 0x80 | uint8(x&0x7F) x >>= 7 } p.tagbuf[i] = uint8(x) p.tagcode = p.tagbuf[0 : i+1] if p.stype != nil { if lockGetProp { p.sprop = GetProperties(p.stype) } else { p.sprop = getPropertiesLocked(p.stype) } } } var ( marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem() unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem() ) // isMarshaler reports whether type t implements Marshaler. func isMarshaler(t reflect.Type) bool { // We're checking for (likely) pointer-receiver methods // so if t is not a pointer, something is very wrong. // The calls above only invoke isMarshaler on pointer types. if t.Kind() != reflect.Ptr { panic("proto: misuse of isMarshaler") } return t.Implements(marshalerType) } // isUnmarshaler reports whether type t implements Unmarshaler. func isUnmarshaler(t reflect.Type) bool { // We're checking for (likely) pointer-receiver methods // so if t is not a pointer, something is very wrong. // The calls above only invoke isUnmarshaler on pointer types. if t.Kind() != reflect.Ptr { panic("proto: misuse of isUnmarshaler") } return t.Implements(unmarshalerType) } // Init populates the properties from a protocol buffer struct tag. func (p *Properties) Init(typ reflect.Type, name, tag string, f *reflect.StructField) { p.init(typ, name, tag, f, true) } func (p *Properties) init(typ reflect.Type, name, tag string, f *reflect.StructField, lockGetProp bool) { // "bytes,49,opt,def=hello!" p.Name = name p.OrigName = name if f != nil { p.field = toField(f) } if tag == "" { return } p.Parse(tag) p.setEncAndDec(typ, f, lockGetProp) } var ( propertiesMu sync.RWMutex propertiesMap = make(map[reflect.Type]*StructProperties) ) // GetProperties returns the list of properties for the type represented by t. // t must represent a generated struct type of a protocol message. func GetProperties(t reflect.Type) *StructProperties { if t.Kind() != reflect.Struct { panic("proto: type must have kind struct") } // Most calls to GetProperties in a long-running program will be // retrieving details for types we have seen before. propertiesMu.RLock() sprop, ok := propertiesMap[t] propertiesMu.RUnlock() if ok { if collectStats { stats.Chit++ } return sprop } propertiesMu.Lock() sprop = getPropertiesLocked(t) propertiesMu.Unlock() return sprop } // getPropertiesLocked requires that propertiesMu is held. func getPropertiesLocked(t reflect.Type) *StructProperties { if prop, ok := propertiesMap[t]; ok { if collectStats { stats.Chit++ } return prop } if collectStats { stats.Cmiss++ } prop := new(StructProperties) // in case of recursive protos, fill this in now. propertiesMap[t] = prop // build properties prop.extendable = reflect.PtrTo(t).Implements(extendableProtoType) || reflect.PtrTo(t).Implements(extendableProtoV1Type) prop.unrecField = invalidField prop.Prop = make([]*Properties, t.NumField()) prop.order = make([]int, t.NumField()) for i := 0; i < t.NumField(); i++ { f := t.Field(i) p := new(Properties) name := f.Name p.init(f.Type, name, f.Tag.Get("protobuf"), &f, false) if f.Name == "XXX_InternalExtensions" { // special case p.enc = (*Buffer).enc_exts p.dec = nil // not needed p.size = size_exts } else if f.Name == "XXX_extensions" { // special case p.enc = (*Buffer).enc_map p.dec = nil // not needed p.size = size_map } else if f.Name == "XXX_unrecognized" { // special case prop.unrecField = toField(&f) } oneof := f.Tag.Get("protobuf_oneof") // special case if oneof != "" { // Oneof fields don't use the traditional protobuf tag. p.OrigName = oneof } prop.Prop[i] = p prop.order[i] = i if debug { print(i, " ", f.Name, " ", t.String(), " ") if p.Tag > 0 { print(p.String()) } print("\n") } if p.enc == nil && !strings.HasPrefix(f.Name, "XXX_") && oneof == "" { fmt.Fprintln(os.Stderr, "proto: no encoder for", f.Name, f.Type.String(), "[GetProperties]") } } // Re-order prop.order. sort.Sort(prop) type oneofMessage interface { XXX_OneofFuncs() (func(Message, *Buffer) error, func(Message, int, int, *Buffer) (bool, error), func(Message) int, []interface{}) } if om, ok := reflect.Zero(reflect.PtrTo(t)).Interface().(oneofMessage); ok { var oots []interface{} prop.oneofMarshaler, prop.oneofUnmarshaler, prop.oneofSizer, oots = om.XXX_OneofFuncs() prop.stype = t // Interpret oneof metadata. prop.OneofTypes = make(map[string]*OneofProperties) for _, oot := range oots { oop := &OneofProperties{ Type: reflect.ValueOf(oot).Type(), // *T Prop: new(Properties), } sft := oop.Type.Elem().Field(0) oop.Prop.Name = sft.Name oop.Prop.Parse(sft.Tag.Get("protobuf")) // There will be exactly one interface field that // this new value is assignable to. for i := 0; i < t.NumField(); i++ { f := t.Field(i) if f.Type.Kind() != reflect.Interface { continue } if !oop.Type.AssignableTo(f.Type) { continue } oop.Field = i break } prop.OneofTypes[oop.Prop.OrigName] = oop } } // build required counts // build tags reqCount := 0 prop.decoderOrigNames = make(map[string]int) for i, p := range prop.Prop { if strings.HasPrefix(p.Name, "XXX_") { // Internal fields should not appear in tags/origNames maps. // They are handled specially when encoding and decoding. continue } if p.Required { reqCount++ } prop.decoderTags.put(p.Tag, i) prop.decoderOrigNames[p.OrigName] = i } prop.reqCount = reqCount return prop } // Return the Properties object for the x[0]'th field of the structure. func propByIndex(t reflect.Type, x []int) *Properties { if len(x) != 1 { fmt.Fprintf(os.Stderr, "proto: field index dimension %d (not 1) for type %s\n", len(x), t) return nil } prop := GetProperties(t) return prop.Prop[x[0]] } // Get the address and type of a pointer to a struct from an interface. func getbase(pb Message) (t reflect.Type, b structPointer, err error) { if pb == nil { err = ErrNil return } // get the reflect type of the pointer to the struct. t = reflect.TypeOf(pb) // get the address of the struct. value := reflect.ValueOf(pb) b = toStructPointer(value) return } // A global registry of enum types. // The generated code will register the generated maps by calling RegisterEnum. var enumValueMaps = make(map[string]map[string]int32) // RegisterEnum is called from the generated code to install the enum descriptor // maps into the global table to aid parsing text format protocol buffers. func RegisterEnum(typeName string, unusedNameMap map[int32]string, valueMap map[string]int32) { if _, ok := enumValueMaps[typeName]; ok { panic("proto: duplicate enum registered: " + typeName) } enumValueMaps[typeName] = valueMap } // EnumValueMap returns the mapping from names to integers of the // enum type enumType, or a nil if not found. func EnumValueMap(enumType string) map[string]int32 { return enumValueMaps[enumType] } // A registry of all linked message types. // The string is a fully-qualified proto name ("pkg.Message"). var ( protoTypes = make(map[string]reflect.Type) revProtoTypes = make(map[reflect.Type]string) ) // RegisterType is called from generated code and maps from the fully qualified // proto name to the type (pointer to struct) of the protocol buffer. func RegisterType(x Message, name string) { if _, ok := protoTypes[name]; ok { // TODO: Some day, make this a panic. log.Printf("proto: duplicate proto type registered: %s", name) return } t := reflect.TypeOf(x) protoTypes[name] = t revProtoTypes[t] = name } // MessageName returns the fully-qualified proto name for the given message type. func MessageName(x Message) string { type xname interface { XXX_MessageName() string } if m, ok := x.(xname); ok { return m.XXX_MessageName() } return revProtoTypes[reflect.TypeOf(x)] } // MessageType returns the message type (pointer to struct) for a named message. func MessageType(name string) reflect.Type { return protoTypes[name] } // A registry of all linked proto files. var ( protoFiles = make(map[string][]byte) // file name => fileDescriptor ) // RegisterFile is called from generated code and maps from the // full file name of a .proto file to its compressed FileDescriptorProto. func RegisterFile(filename string, fileDescriptor []byte) { protoFiles[filename] = fileDescriptor } // FileDescriptor returns the compressed FileDescriptorProto for a .proto file. func FileDescriptor(filename string) []byte { return protoFiles[filename] } ================================================ FILE: vendor/github.com/golang/protobuf/proto/proto3_test.go ================================================ // Go support for Protocol Buffers - Google's data interchange format // // Copyright 2014 The Go Authors. All rights reserved. // https://github.com/golang/protobuf // // 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. package proto_test import ( "testing" "github.com/golang/protobuf/proto" pb "github.com/golang/protobuf/proto/proto3_proto" tpb "github.com/golang/protobuf/proto/testdata" ) func TestProto3ZeroValues(t *testing.T) { tests := []struct { desc string m proto.Message }{ {"zero message", &pb.Message{}}, {"empty bytes field", &pb.Message{Data: []byte{}}}, } for _, test := range tests { b, err := proto.Marshal(test.m) if err != nil { t.Errorf("%s: proto.Marshal: %v", test.desc, err) continue } if len(b) > 0 { t.Errorf("%s: Encoding is non-empty: %q", test.desc, b) } } } func TestRoundTripProto3(t *testing.T) { m := &pb.Message{ Name: "David", // (2 | 1<<3): 0x0a 0x05 "David" Hilarity: pb.Message_PUNS, // (0 | 2<<3): 0x10 0x01 HeightInCm: 178, // (0 | 3<<3): 0x18 0xb2 0x01 Data: []byte("roboto"), // (2 | 4<<3): 0x20 0x06 "roboto" ResultCount: 47, // (0 | 7<<3): 0x38 0x2f TrueScotsman: true, // (0 | 8<<3): 0x40 0x01 Score: 8.1, // (5 | 9<<3): 0x4d <8.1> Key: []uint64{1, 0xdeadbeef}, Nested: &pb.Nested{ Bunny: "Monty", }, } t.Logf(" m: %v", m) b, err := proto.Marshal(m) if err != nil { t.Fatalf("proto.Marshal: %v", err) } t.Logf(" b: %q", b) m2 := new(pb.Message) if err := proto.Unmarshal(b, m2); err != nil { t.Fatalf("proto.Unmarshal: %v", err) } t.Logf("m2: %v", m2) if !proto.Equal(m, m2) { t.Errorf("proto.Equal returned false:\n m: %v\nm2: %v", m, m2) } } func TestGettersForBasicTypesExist(t *testing.T) { var m pb.Message if got := m.GetNested().GetBunny(); got != "" { t.Errorf("m.GetNested().GetBunny() = %q, want empty string", got) } if got := m.GetNested().GetCute(); got { t.Errorf("m.GetNested().GetCute() = %t, want false", got) } } func TestProto3SetDefaults(t *testing.T) { in := &pb.Message{ Terrain: map[string]*pb.Nested{ "meadow": new(pb.Nested), }, Proto2Field: new(tpb.SubDefaults), Proto2Value: map[string]*tpb.SubDefaults{ "badlands": new(tpb.SubDefaults), }, } got := proto.Clone(in).(*pb.Message) proto.SetDefaults(got) // There are no defaults in proto3. Everything should be the zero value, but // we need to remember to set defaults for nested proto2 messages. want := &pb.Message{ Terrain: map[string]*pb.Nested{ "meadow": new(pb.Nested), }, Proto2Field: &tpb.SubDefaults{N: proto.Int64(7)}, Proto2Value: map[string]*tpb.SubDefaults{ "badlands": &tpb.SubDefaults{N: proto.Int64(7)}, }, } if !proto.Equal(got, want) { t.Errorf("with in = %v\nproto.SetDefaults(in) =>\ngot %v\nwant %v", in, got, want) } } ================================================ FILE: vendor/github.com/golang/protobuf/proto/size2_test.go ================================================ // Go support for Protocol Buffers - Google's data interchange format // // Copyright 2012 The Go Authors. All rights reserved. // https://github.com/golang/protobuf // // 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. package proto import ( "testing" ) // This is a separate file and package from size_test.go because that one uses // generated messages and thus may not be in package proto without having a circular // dependency, whereas this file tests unexported details of size.go. func TestVarintSize(t *testing.T) { // Check the edge cases carefully. testCases := []struct { n uint64 size int }{ {0, 1}, {1, 1}, {127, 1}, {128, 2}, {16383, 2}, {16384, 3}, {1<<63 - 1, 9}, {1 << 63, 10}, } for _, tc := range testCases { size := sizeVarint(tc.n) if size != tc.size { t.Errorf("sizeVarint(%d) = %d, want %d", tc.n, size, tc.size) } } } ================================================ FILE: vendor/github.com/golang/protobuf/proto/size_test.go ================================================ // Go support for Protocol Buffers - Google's data interchange format // // Copyright 2012 The Go Authors. All rights reserved. // https://github.com/golang/protobuf // // 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. package proto_test import ( "log" "strings" "testing" . "github.com/golang/protobuf/proto" proto3pb "github.com/golang/protobuf/proto/proto3_proto" pb "github.com/golang/protobuf/proto/testdata" ) var messageWithExtension1 = &pb.MyMessage{Count: Int32(7)} // messageWithExtension2 is in equal_test.go. var messageWithExtension3 = &pb.MyMessage{Count: Int32(8)} func init() { if err := SetExtension(messageWithExtension1, pb.E_Ext_More, &pb.Ext{Data: String("Abbott")}); err != nil { log.Panicf("SetExtension: %v", err) } if err := SetExtension(messageWithExtension3, pb.E_Ext_More, &pb.Ext{Data: String("Costello")}); err != nil { log.Panicf("SetExtension: %v", err) } // Force messageWithExtension3 to have the extension encoded. Marshal(messageWithExtension3) } var SizeTests = []struct { desc string pb Message }{ {"empty", &pb.OtherMessage{}}, // Basic types. {"bool", &pb.Defaults{F_Bool: Bool(true)}}, {"int32", &pb.Defaults{F_Int32: Int32(12)}}, {"negative int32", &pb.Defaults{F_Int32: Int32(-1)}}, {"small int64", &pb.Defaults{F_Int64: Int64(1)}}, {"big int64", &pb.Defaults{F_Int64: Int64(1 << 20)}}, {"negative int64", &pb.Defaults{F_Int64: Int64(-1)}}, {"fixed32", &pb.Defaults{F_Fixed32: Uint32(71)}}, {"fixed64", &pb.Defaults{F_Fixed64: Uint64(72)}}, {"uint32", &pb.Defaults{F_Uint32: Uint32(123)}}, {"uint64", &pb.Defaults{F_Uint64: Uint64(124)}}, {"float", &pb.Defaults{F_Float: Float32(12.6)}}, {"double", &pb.Defaults{F_Double: Float64(13.9)}}, {"string", &pb.Defaults{F_String: String("niles")}}, {"bytes", &pb.Defaults{F_Bytes: []byte("wowsa")}}, {"bytes, empty", &pb.Defaults{F_Bytes: []byte{}}}, {"sint32", &pb.Defaults{F_Sint32: Int32(65)}}, {"sint64", &pb.Defaults{F_Sint64: Int64(67)}}, {"enum", &pb.Defaults{F_Enum: pb.Defaults_BLUE.Enum()}}, // Repeated. {"empty repeated bool", &pb.MoreRepeated{Bools: []bool{}}}, {"repeated bool", &pb.MoreRepeated{Bools: []bool{false, true, true, false}}}, {"packed repeated bool", &pb.MoreRepeated{BoolsPacked: []bool{false, true, true, false, true, true, true}}}, {"repeated int32", &pb.MoreRepeated{Ints: []int32{1, 12203, 1729, -1}}}, {"repeated int32 packed", &pb.MoreRepeated{IntsPacked: []int32{1, 12203, 1729}}}, {"repeated int64 packed", &pb.MoreRepeated{Int64SPacked: []int64{ // Need enough large numbers to verify that the header is counting the number of bytes // for the field, not the number of elements. 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, }}}, {"repeated string", &pb.MoreRepeated{Strings: []string{"r", "ken", "gri"}}}, {"repeated fixed", &pb.MoreRepeated{Fixeds: []uint32{1, 2, 3, 4}}}, // Nested. {"nested", &pb.OldMessage{Nested: &pb.OldMessage_Nested{Name: String("whatever")}}}, {"group", &pb.GroupOld{G: &pb.GroupOld_G{X: Int32(12345)}}}, // Other things. {"unrecognized", &pb.MoreRepeated{XXX_unrecognized: []byte{13<<3 | 0, 4}}}, {"extension (unencoded)", messageWithExtension1}, {"extension (encoded)", messageWithExtension3}, // proto3 message {"proto3 empty", &proto3pb.Message{}}, {"proto3 bool", &proto3pb.Message{TrueScotsman: true}}, {"proto3 int64", &proto3pb.Message{ResultCount: 1}}, {"proto3 uint32", &proto3pb.Message{HeightInCm: 123}}, {"proto3 float", &proto3pb.Message{Score: 12.6}}, {"proto3 string", &proto3pb.Message{Name: "Snezana"}}, {"proto3 bytes", &proto3pb.Message{Data: []byte("wowsa")}}, {"proto3 bytes, empty", &proto3pb.Message{Data: []byte{}}}, {"proto3 enum", &proto3pb.Message{Hilarity: proto3pb.Message_PUNS}}, {"proto3 map field with empty bytes", &proto3pb.MessageWithMap{ByteMapping: map[bool][]byte{false: []byte{}}}}, {"map field", &pb.MessageWithMap{NameMapping: map[int32]string{1: "Rob", 7: "Andrew"}}}, {"map field with message", &pb.MessageWithMap{MsgMapping: map[int64]*pb.FloatingPoint{0x7001: &pb.FloatingPoint{F: Float64(2.0)}}}}, {"map field with bytes", &pb.MessageWithMap{ByteMapping: map[bool][]byte{true: []byte("this time for sure")}}}, {"map field with empty bytes", &pb.MessageWithMap{ByteMapping: map[bool][]byte{true: []byte{}}}}, {"map field with big entry", &pb.MessageWithMap{NameMapping: map[int32]string{8: strings.Repeat("x", 125)}}}, {"map field with big key and val", &pb.MessageWithMap{StrToStr: map[string]string{strings.Repeat("x", 70): strings.Repeat("y", 70)}}}, {"map field with big numeric key", &pb.MessageWithMap{NameMapping: map[int32]string{0xf00d: "om nom nom"}}}, {"oneof not set", &pb.Oneof{}}, {"oneof bool", &pb.Oneof{Union: &pb.Oneof_F_Bool{true}}}, {"oneof zero int32", &pb.Oneof{Union: &pb.Oneof_F_Int32{0}}}, {"oneof big int32", &pb.Oneof{Union: &pb.Oneof_F_Int32{1 << 20}}}, {"oneof int64", &pb.Oneof{Union: &pb.Oneof_F_Int64{42}}}, {"oneof fixed32", &pb.Oneof{Union: &pb.Oneof_F_Fixed32{43}}}, {"oneof fixed64", &pb.Oneof{Union: &pb.Oneof_F_Fixed64{44}}}, {"oneof uint32", &pb.Oneof{Union: &pb.Oneof_F_Uint32{45}}}, {"oneof uint64", &pb.Oneof{Union: &pb.Oneof_F_Uint64{46}}}, {"oneof float", &pb.Oneof{Union: &pb.Oneof_F_Float{47.1}}}, {"oneof double", &pb.Oneof{Union: &pb.Oneof_F_Double{48.9}}}, {"oneof string", &pb.Oneof{Union: &pb.Oneof_F_String{"Rhythmic Fman"}}}, {"oneof bytes", &pb.Oneof{Union: &pb.Oneof_F_Bytes{[]byte("let go")}}}, {"oneof sint32", &pb.Oneof{Union: &pb.Oneof_F_Sint32{50}}}, {"oneof sint64", &pb.Oneof{Union: &pb.Oneof_F_Sint64{51}}}, {"oneof enum", &pb.Oneof{Union: &pb.Oneof_F_Enum{pb.MyMessage_BLUE}}}, {"message for oneof", &pb.GoTestField{Label: String("k"), Type: String("v")}}, {"oneof message", &pb.Oneof{Union: &pb.Oneof_F_Message{&pb.GoTestField{Label: String("k"), Type: String("v")}}}}, {"oneof group", &pb.Oneof{Union: &pb.Oneof_FGroup{&pb.Oneof_F_Group{X: Int32(52)}}}}, {"oneof largest tag", &pb.Oneof{Union: &pb.Oneof_F_Largest_Tag{1}}}, {"multiple oneofs", &pb.Oneof{Union: &pb.Oneof_F_Int32{1}, Tormato: &pb.Oneof_Value{2}}}, } func TestSize(t *testing.T) { for _, tc := range SizeTests { size := Size(tc.pb) b, err := Marshal(tc.pb) if err != nil { t.Errorf("%v: Marshal failed: %v", tc.desc, err) continue } if size != len(b) { t.Errorf("%v: Size(%v) = %d, want %d", tc.desc, tc.pb, size, len(b)) t.Logf("%v: bytes: %#v", tc.desc, b) } } } ================================================ FILE: vendor/github.com/golang/protobuf/proto/text.go ================================================ // Go support for Protocol Buffers - Google's data interchange format // // Copyright 2010 The Go Authors. All rights reserved. // https://github.com/golang/protobuf // // 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. package proto // Functions for writing the text protocol buffer format. import ( "bufio" "bytes" "encoding" "errors" "fmt" "io" "log" "math" "reflect" "sort" "strings" ) var ( newline = []byte("\n") spaces = []byte(" ") gtNewline = []byte(">\n") endBraceNewline = []byte("}\n") backslashN = []byte{'\\', 'n'} backslashR = []byte{'\\', 'r'} backslashT = []byte{'\\', 't'} backslashDQ = []byte{'\\', '"'} backslashBS = []byte{'\\', '\\'} posInf = []byte("inf") negInf = []byte("-inf") nan = []byte("nan") ) type writer interface { io.Writer WriteByte(byte) error } // textWriter is an io.Writer that tracks its indentation level. type textWriter struct { ind int complete bool // if the current position is a complete line compact bool // whether to write out as a one-liner w writer } func (w *textWriter) WriteString(s string) (n int, err error) { if !strings.Contains(s, "\n") { if !w.compact && w.complete { w.writeIndent() } w.complete = false return io.WriteString(w.w, s) } // WriteString is typically called without newlines, so this // codepath and its copy are rare. We copy to avoid // duplicating all of Write's logic here. return w.Write([]byte(s)) } func (w *textWriter) Write(p []byte) (n int, err error) { newlines := bytes.Count(p, newline) if newlines == 0 { if !w.compact && w.complete { w.writeIndent() } n, err = w.w.Write(p) w.complete = false return n, err } frags := bytes.SplitN(p, newline, newlines+1) if w.compact { for i, frag := range frags { if i > 0 { if err := w.w.WriteByte(' '); err != nil { return n, err } n++ } nn, err := w.w.Write(frag) n += nn if err != nil { return n, err } } return n, nil } for i, frag := range frags { if w.complete { w.writeIndent() } nn, err := w.w.Write(frag) n += nn if err != nil { return n, err } if i+1 < len(frags) { if err := w.w.WriteByte('\n'); err != nil { return n, err } n++ } } w.complete = len(frags[len(frags)-1]) == 0 return n, nil } func (w *textWriter) WriteByte(c byte) error { if w.compact && c == '\n' { c = ' ' } if !w.compact && w.complete { w.writeIndent() } err := w.w.WriteByte(c) w.complete = c == '\n' return err } func (w *textWriter) indent() { w.ind++ } func (w *textWriter) unindent() { if w.ind == 0 { log.Print("proto: textWriter unindented too far") return } w.ind-- } func writeName(w *textWriter, props *Properties) error { if _, err := w.WriteString(props.OrigName); err != nil { return err } if props.Wire != "group" { return w.WriteByte(':') } return nil } // raw is the interface satisfied by RawMessage. type raw interface { Bytes() []byte } func requiresQuotes(u string) bool { // When type URL contains any characters except [0-9A-Za-z./\-]*, it must be quoted. for _, ch := range u { switch { case ch == '.' || ch == '/' || ch == '_': continue case '0' <= ch && ch <= '9': continue case 'A' <= ch && ch <= 'Z': continue case 'a' <= ch && ch <= 'z': continue default: return true } } return false } // isAny reports whether sv is a google.protobuf.Any message func isAny(sv reflect.Value) bool { type wkt interface { XXX_WellKnownType() string } t, ok := sv.Addr().Interface().(wkt) return ok && t.XXX_WellKnownType() == "Any" } // writeProto3Any writes an expanded google.protobuf.Any message. // // It returns (false, nil) if sv value can't be unmarshaled (e.g. because // required messages are not linked in). // // It returns (true, error) when sv was written in expanded format or an error // was encountered. func (tm *TextMarshaler) writeProto3Any(w *textWriter, sv reflect.Value) (bool, error) { turl := sv.FieldByName("TypeUrl") val := sv.FieldByName("Value") if !turl.IsValid() || !val.IsValid() { return true, errors.New("proto: invalid google.protobuf.Any message") } b, ok := val.Interface().([]byte) if !ok { return true, errors.New("proto: invalid google.protobuf.Any message") } parts := strings.Split(turl.String(), "/") mt := MessageType(parts[len(parts)-1]) if mt == nil { return false, nil } m := reflect.New(mt.Elem()) if err := Unmarshal(b, m.Interface().(Message)); err != nil { return false, nil } w.Write([]byte("[")) u := turl.String() if requiresQuotes(u) { writeString(w, u) } else { w.Write([]byte(u)) } if w.compact { w.Write([]byte("]:<")) } else { w.Write([]byte("]: <\n")) w.ind++ } if err := tm.writeStruct(w, m.Elem()); err != nil { return true, err } if w.compact { w.Write([]byte("> ")) } else { w.ind-- w.Write([]byte(">\n")) } return true, nil } func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error { if tm.ExpandAny && isAny(sv) { if canExpand, err := tm.writeProto3Any(w, sv); canExpand { return err } } st := sv.Type() sprops := GetProperties(st) for i := 0; i < sv.NumField(); i++ { fv := sv.Field(i) props := sprops.Prop[i] name := st.Field(i).Name if strings.HasPrefix(name, "XXX_") { // There are two XXX_ fields: // XXX_unrecognized []byte // XXX_extensions map[int32]proto.Extension // The first is handled here; // the second is handled at the bottom of this function. if name == "XXX_unrecognized" && !fv.IsNil() { if err := writeUnknownStruct(w, fv.Interface().([]byte)); err != nil { return err } } continue } if fv.Kind() == reflect.Ptr && fv.IsNil() { // Field not filled in. This could be an optional field or // a required field that wasn't filled in. Either way, there // isn't anything we can show for it. continue } if fv.Kind() == reflect.Slice && fv.IsNil() { // Repeated field that is empty, or a bytes field that is unused. continue } if props.Repeated && fv.Kind() == reflect.Slice { // Repeated field. for j := 0; j < fv.Len(); j++ { if err := writeName(w, props); err != nil { return err } if !w.compact { if err := w.WriteByte(' '); err != nil { return err } } v := fv.Index(j) if v.Kind() == reflect.Ptr && v.IsNil() { // A nil message in a repeated field is not valid, // but we can handle that more gracefully than panicking. if _, err := w.Write([]byte("\n")); err != nil { return err } continue } if err := tm.writeAny(w, v, props); err != nil { return err } if err := w.WriteByte('\n'); err != nil { return err } } continue } if fv.Kind() == reflect.Map { // Map fields are rendered as a repeated struct with key/value fields. keys := fv.MapKeys() sort.Sort(mapKeys(keys)) for _, key := range keys { val := fv.MapIndex(key) if err := writeName(w, props); err != nil { return err } if !w.compact { if err := w.WriteByte(' '); err != nil { return err } } // open struct if err := w.WriteByte('<'); err != nil { return err } if !w.compact { if err := w.WriteByte('\n'); err != nil { return err } } w.indent() // key if _, err := w.WriteString("key:"); err != nil { return err } if !w.compact { if err := w.WriteByte(' '); err != nil { return err } } if err := tm.writeAny(w, key, props.mkeyprop); err != nil { return err } if err := w.WriteByte('\n'); err != nil { return err } // nil values aren't legal, but we can avoid panicking because of them. if val.Kind() != reflect.Ptr || !val.IsNil() { // value if _, err := w.WriteString("value:"); err != nil { return err } if !w.compact { if err := w.WriteByte(' '); err != nil { return err } } if err := tm.writeAny(w, val, props.mvalprop); err != nil { return err } if err := w.WriteByte('\n'); err != nil { return err } } // close struct w.unindent() if err := w.WriteByte('>'); err != nil { return err } if err := w.WriteByte('\n'); err != nil { return err } } continue } if props.proto3 && fv.Kind() == reflect.Slice && fv.Len() == 0 { // empty bytes field continue } if fv.Kind() != reflect.Ptr && fv.Kind() != reflect.Slice { // proto3 non-repeated scalar field; skip if zero value if isProto3Zero(fv) { continue } } if fv.Kind() == reflect.Interface { // Check if it is a oneof. if st.Field(i).Tag.Get("protobuf_oneof") != "" { // fv is nil, or holds a pointer to generated struct. // That generated struct has exactly one field, // which has a protobuf struct tag. if fv.IsNil() { continue } inner := fv.Elem().Elem() // interface -> *T -> T tag := inner.Type().Field(0).Tag.Get("protobuf") props = new(Properties) // Overwrite the outer props var, but not its pointee. props.Parse(tag) // Write the value in the oneof, not the oneof itself. fv = inner.Field(0) // Special case to cope with malformed messages gracefully: // If the value in the oneof is a nil pointer, don't panic // in writeAny. if fv.Kind() == reflect.Ptr && fv.IsNil() { // Use errors.New so writeAny won't render quotes. msg := errors.New("/* nil */") fv = reflect.ValueOf(&msg).Elem() } } } if err := writeName(w, props); err != nil { return err } if !w.compact { if err := w.WriteByte(' '); err != nil { return err } } if b, ok := fv.Interface().(raw); ok { if err := writeRaw(w, b.Bytes()); err != nil { return err } continue } // Enums have a String method, so writeAny will work fine. if err := tm.writeAny(w, fv, props); err != nil { return err } if err := w.WriteByte('\n'); err != nil { return err } } // Extensions (the XXX_extensions field). pv := sv.Addr() if _, ok := extendable(pv.Interface()); ok { if err := tm.writeExtensions(w, pv); err != nil { return err } } return nil } // writeRaw writes an uninterpreted raw message. func writeRaw(w *textWriter, b []byte) error { if err := w.WriteByte('<'); err != nil { return err } if !w.compact { if err := w.WriteByte('\n'); err != nil { return err } } w.indent() if err := writeUnknownStruct(w, b); err != nil { return err } w.unindent() if err := w.WriteByte('>'); err != nil { return err } return nil } // writeAny writes an arbitrary field. func (tm *TextMarshaler) writeAny(w *textWriter, v reflect.Value, props *Properties) error { v = reflect.Indirect(v) // Floats have special cases. if v.Kind() == reflect.Float32 || v.Kind() == reflect.Float64 { x := v.Float() var b []byte switch { case math.IsInf(x, 1): b = posInf case math.IsInf(x, -1): b = negInf case math.IsNaN(x): b = nan } if b != nil { _, err := w.Write(b) return err } // Other values are handled below. } // We don't attempt to serialise every possible value type; only those // that can occur in protocol buffers. switch v.Kind() { case reflect.Slice: // Should only be a []byte; repeated fields are handled in writeStruct. if err := writeString(w, string(v.Bytes())); err != nil { return err } case reflect.String: if err := writeString(w, v.String()); err != nil { return err } case reflect.Struct: // Required/optional group/message. var bra, ket byte = '<', '>' if props != nil && props.Wire == "group" { bra, ket = '{', '}' } if err := w.WriteByte(bra); err != nil { return err } if !w.compact { if err := w.WriteByte('\n'); err != nil { return err } } w.indent() if etm, ok := v.Interface().(encoding.TextMarshaler); ok { text, err := etm.MarshalText() if err != nil { return err } if _, err = w.Write(text); err != nil { return err } } else if err := tm.writeStruct(w, v); err != nil { return err } w.unindent() if err := w.WriteByte(ket); err != nil { return err } default: _, err := fmt.Fprint(w, v.Interface()) return err } return nil } // equivalent to C's isprint. func isprint(c byte) bool { return c >= 0x20 && c < 0x7f } // writeString writes a string in the protocol buffer text format. // It is similar to strconv.Quote except we don't use Go escape sequences, // we treat the string as a byte sequence, and we use octal escapes. // These differences are to maintain interoperability with the other // languages' implementations of the text format. func writeString(w *textWriter, s string) error { // use WriteByte here to get any needed indent if err := w.WriteByte('"'); err != nil { return err } // Loop over the bytes, not the runes. for i := 0; i < len(s); i++ { var err error // Divergence from C++: we don't escape apostrophes. // There's no need to escape them, and the C++ parser // copes with a naked apostrophe. switch c := s[i]; c { case '\n': _, err = w.w.Write(backslashN) case '\r': _, err = w.w.Write(backslashR) case '\t': _, err = w.w.Write(backslashT) case '"': _, err = w.w.Write(backslashDQ) case '\\': _, err = w.w.Write(backslashBS) default: if isprint(c) { err = w.w.WriteByte(c) } else { _, err = fmt.Fprintf(w.w, "\\%03o", c) } } if err != nil { return err } } return w.WriteByte('"') } func writeUnknownStruct(w *textWriter, data []byte) (err error) { if !w.compact { if _, err := fmt.Fprintf(w, "/* %d unknown bytes */\n", len(data)); err != nil { return err } } b := NewBuffer(data) for b.index < len(b.buf) { x, err := b.DecodeVarint() if err != nil { _, err := fmt.Fprintf(w, "/* %v */\n", err) return err } wire, tag := x&7, x>>3 if wire == WireEndGroup { w.unindent() if _, err := w.Write(endBraceNewline); err != nil { return err } continue } if _, err := fmt.Fprint(w, tag); err != nil { return err } if wire != WireStartGroup { if err := w.WriteByte(':'); err != nil { return err } } if !w.compact || wire == WireStartGroup { if err := w.WriteByte(' '); err != nil { return err } } switch wire { case WireBytes: buf, e := b.DecodeRawBytes(false) if e == nil { _, err = fmt.Fprintf(w, "%q", buf) } else { _, err = fmt.Fprintf(w, "/* %v */", e) } case WireFixed32: x, err = b.DecodeFixed32() err = writeUnknownInt(w, x, err) case WireFixed64: x, err = b.DecodeFixed64() err = writeUnknownInt(w, x, err) case WireStartGroup: err = w.WriteByte('{') w.indent() case WireVarint: x, err = b.DecodeVarint() err = writeUnknownInt(w, x, err) default: _, err = fmt.Fprintf(w, "/* unknown wire type %d */", wire) } if err != nil { return err } if err = w.WriteByte('\n'); err != nil { return err } } return nil } func writeUnknownInt(w *textWriter, x uint64, err error) error { if err == nil { _, err = fmt.Fprint(w, x) } else { _, err = fmt.Fprintf(w, "/* %v */", err) } return err } type int32Slice []int32 func (s int32Slice) Len() int { return len(s) } func (s int32Slice) Less(i, j int) bool { return s[i] < s[j] } func (s int32Slice) Swap(i, j int) { s[i], s[j] = s[j], s[i] } // writeExtensions writes all the extensions in pv. // pv is assumed to be a pointer to a protocol message struct that is extendable. func (tm *TextMarshaler) writeExtensions(w *textWriter, pv reflect.Value) error { emap := extensionMaps[pv.Type().Elem()] ep, _ := extendable(pv.Interface()) // Order the extensions by ID. // This isn't strictly necessary, but it will give us // canonical output, which will also make testing easier. m, mu := ep.extensionsRead() if m == nil { return nil } mu.Lock() ids := make([]int32, 0, len(m)) for id := range m { ids = append(ids, id) } sort.Sort(int32Slice(ids)) mu.Unlock() for _, extNum := range ids { ext := m[extNum] var desc *ExtensionDesc if emap != nil { desc = emap[extNum] } if desc == nil { // Unknown extension. if err := writeUnknownStruct(w, ext.enc); err != nil { return err } continue } pb, err := GetExtension(ep, desc) if err != nil { return fmt.Errorf("failed getting extension: %v", err) } // Repeated extensions will appear as a slice. if !desc.repeated() { if err := tm.writeExtension(w, desc.Name, pb); err != nil { return err } } else { v := reflect.ValueOf(pb) for i := 0; i < v.Len(); i++ { if err := tm.writeExtension(w, desc.Name, v.Index(i).Interface()); err != nil { return err } } } } return nil } func (tm *TextMarshaler) writeExtension(w *textWriter, name string, pb interface{}) error { if _, err := fmt.Fprintf(w, "[%s]:", name); err != nil { return err } if !w.compact { if err := w.WriteByte(' '); err != nil { return err } } if err := tm.writeAny(w, reflect.ValueOf(pb), nil); err != nil { return err } if err := w.WriteByte('\n'); err != nil { return err } return nil } func (w *textWriter) writeIndent() { if !w.complete { return } remain := w.ind * 2 for remain > 0 { n := remain if n > len(spaces) { n = len(spaces) } w.w.Write(spaces[:n]) remain -= n } w.complete = false } // TextMarshaler is a configurable text format marshaler. type TextMarshaler struct { Compact bool // use compact text format (one line). ExpandAny bool // expand google.protobuf.Any messages of known types } // Marshal writes a given protocol buffer in text format. // The only errors returned are from w. func (tm *TextMarshaler) Marshal(w io.Writer, pb Message) error { val := reflect.ValueOf(pb) if pb == nil || val.IsNil() { w.Write([]byte("")) return nil } var bw *bufio.Writer ww, ok := w.(writer) if !ok { bw = bufio.NewWriter(w) ww = bw } aw := &textWriter{ w: ww, complete: true, compact: tm.Compact, } if etm, ok := pb.(encoding.TextMarshaler); ok { text, err := etm.MarshalText() if err != nil { return err } if _, err = aw.Write(text); err != nil { return err } if bw != nil { return bw.Flush() } return nil } // Dereference the received pointer so we don't have outer < and >. v := reflect.Indirect(val) if err := tm.writeStruct(aw, v); err != nil { return err } if bw != nil { return bw.Flush() } return nil } // Text is the same as Marshal, but returns the string directly. func (tm *TextMarshaler) Text(pb Message) string { var buf bytes.Buffer tm.Marshal(&buf, pb) return buf.String() } var ( defaultTextMarshaler = TextMarshaler{} compactTextMarshaler = TextMarshaler{Compact: true} ) // TODO: consider removing some of the Marshal functions below. // MarshalText writes a given protocol buffer in text format. // The only errors returned are from w. func MarshalText(w io.Writer, pb Message) error { return defaultTextMarshaler.Marshal(w, pb) } // MarshalTextString is the same as MarshalText, but returns the string directly. func MarshalTextString(pb Message) string { return defaultTextMarshaler.Text(pb) } // CompactText writes a given protocol buffer in compact text format (one line). func CompactText(w io.Writer, pb Message) error { return compactTextMarshaler.Marshal(w, pb) } // CompactTextString is the same as CompactText, but returns the string directly. func CompactTextString(pb Message) string { return compactTextMarshaler.Text(pb) } ================================================ FILE: vendor/github.com/golang/protobuf/proto/text_parser.go ================================================ // Go support for Protocol Buffers - Google's data interchange format // // Copyright 2010 The Go Authors. All rights reserved. // https://github.com/golang/protobuf // // 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. package proto // Functions for parsing the Text protocol buffer format. // TODO: message sets. import ( "encoding" "errors" "fmt" "reflect" "strconv" "strings" "unicode/utf8" ) // Error string emitted when deserializing Any and fields are already set const anyRepeatedlyUnpacked = "Any message unpacked multiple times, or %q already set" type ParseError struct { Message string Line int // 1-based line number Offset int // 0-based byte offset from start of input } func (p *ParseError) Error() string { if p.Line == 1 { // show offset only for first line return fmt.Sprintf("line 1.%d: %v", p.Offset, p.Message) } return fmt.Sprintf("line %d: %v", p.Line, p.Message) } type token struct { value string err *ParseError line int // line number offset int // byte number from start of input, not start of line unquoted string // the unquoted version of value, if it was a quoted string } func (t *token) String() string { if t.err == nil { return fmt.Sprintf("%q (line=%d, offset=%d)", t.value, t.line, t.offset) } return fmt.Sprintf("parse error: %v", t.err) } type textParser struct { s string // remaining input done bool // whether the parsing is finished (success or error) backed bool // whether back() was called offset, line int cur token } func newTextParser(s string) *textParser { p := new(textParser) p.s = s p.line = 1 p.cur.line = 1 return p } func (p *textParser) errorf(format string, a ...interface{}) *ParseError { pe := &ParseError{fmt.Sprintf(format, a...), p.cur.line, p.cur.offset} p.cur.err = pe p.done = true return pe } // Numbers and identifiers are matched by [-+._A-Za-z0-9] func isIdentOrNumberChar(c byte) bool { switch { case 'A' <= c && c <= 'Z', 'a' <= c && c <= 'z': return true case '0' <= c && c <= '9': return true } switch c { case '-', '+', '.', '_': return true } return false } func isWhitespace(c byte) bool { switch c { case ' ', '\t', '\n', '\r': return true } return false } func isQuote(c byte) bool { switch c { case '"', '\'': return true } return false } func (p *textParser) skipWhitespace() { i := 0 for i < len(p.s) && (isWhitespace(p.s[i]) || p.s[i] == '#') { if p.s[i] == '#' { // comment; skip to end of line or input for i < len(p.s) && p.s[i] != '\n' { i++ } if i == len(p.s) { break } } if p.s[i] == '\n' { p.line++ } i++ } p.offset += i p.s = p.s[i:len(p.s)] if len(p.s) == 0 { p.done = true } } func (p *textParser) advance() { // Skip whitespace p.skipWhitespace() if p.done { return } // Start of non-whitespace p.cur.err = nil p.cur.offset, p.cur.line = p.offset, p.line p.cur.unquoted = "" switch p.s[0] { case '<', '>', '{', '}', ':', '[', ']', ';', ',', '/': // Single symbol p.cur.value, p.s = p.s[0:1], p.s[1:len(p.s)] case '"', '\'': // Quoted string i := 1 for i < len(p.s) && p.s[i] != p.s[0] && p.s[i] != '\n' { if p.s[i] == '\\' && i+1 < len(p.s) { // skip escaped char i++ } i++ } if i >= len(p.s) || p.s[i] != p.s[0] { p.errorf("unmatched quote") return } unq, err := unquoteC(p.s[1:i], rune(p.s[0])) if err != nil { p.errorf("invalid quoted string %s: %v", p.s[0:i+1], err) return } p.cur.value, p.s = p.s[0:i+1], p.s[i+1:len(p.s)] p.cur.unquoted = unq default: i := 0 for i < len(p.s) && isIdentOrNumberChar(p.s[i]) { i++ } if i == 0 { p.errorf("unexpected byte %#x", p.s[0]) return } p.cur.value, p.s = p.s[0:i], p.s[i:len(p.s)] } p.offset += len(p.cur.value) } var ( errBadUTF8 = errors.New("proto: bad UTF-8") errBadHex = errors.New("proto: bad hexadecimal") ) func unquoteC(s string, quote rune) (string, error) { // This is based on C++'s tokenizer.cc. // Despite its name, this is *not* parsing C syntax. // For instance, "\0" is an invalid quoted string. // Avoid allocation in trivial cases. simple := true for _, r := range s { if r == '\\' || r == quote { simple = false break } } if simple { return s, nil } buf := make([]byte, 0, 3*len(s)/2) for len(s) > 0 { r, n := utf8.DecodeRuneInString(s) if r == utf8.RuneError && n == 1 { return "", errBadUTF8 } s = s[n:] if r != '\\' { if r < utf8.RuneSelf { buf = append(buf, byte(r)) } else { buf = append(buf, string(r)...) } continue } ch, tail, err := unescape(s) if err != nil { return "", err } buf = append(buf, ch...) s = tail } return string(buf), nil } func unescape(s string) (ch string, tail string, err error) { r, n := utf8.DecodeRuneInString(s) if r == utf8.RuneError && n == 1 { return "", "", errBadUTF8 } s = s[n:] switch r { case 'a': return "\a", s, nil case 'b': return "\b", s, nil case 'f': return "\f", s, nil case 'n': return "\n", s, nil case 'r': return "\r", s, nil case 't': return "\t", s, nil case 'v': return "\v", s, nil case '?': return "?", s, nil // trigraph workaround case '\'', '"', '\\': return string(r), s, nil case '0', '1', '2', '3', '4', '5', '6', '7', 'x', 'X': if len(s) < 2 { return "", "", fmt.Errorf(`\%c requires 2 following digits`, r) } base := 8 ss := s[:2] s = s[2:] if r == 'x' || r == 'X' { base = 16 } else { ss = string(r) + ss } i, err := strconv.ParseUint(ss, base, 8) if err != nil { return "", "", err } return string([]byte{byte(i)}), s, nil case 'u', 'U': n := 4 if r == 'U' { n = 8 } if len(s) < n { return "", "", fmt.Errorf(`\%c requires %d digits`, r, n) } bs := make([]byte, n/2) for i := 0; i < n; i += 2 { a, ok1 := unhex(s[i]) b, ok2 := unhex(s[i+1]) if !ok1 || !ok2 { return "", "", errBadHex } bs[i/2] = a<<4 | b } s = s[n:] return string(bs), s, nil } return "", "", fmt.Errorf(`unknown escape \%c`, r) } // Adapted from src/pkg/strconv/quote.go. func unhex(b byte) (v byte, ok bool) { switch { case '0' <= b && b <= '9': return b - '0', true case 'a' <= b && b <= 'f': return b - 'a' + 10, true case 'A' <= b && b <= 'F': return b - 'A' + 10, true } return 0, false } // Back off the parser by one token. Can only be done between calls to next(). // It makes the next advance() a no-op. func (p *textParser) back() { p.backed = true } // Advances the parser and returns the new current token. func (p *textParser) next() *token { if p.backed || p.done { p.backed = false return &p.cur } p.advance() if p.done { p.cur.value = "" } else if len(p.cur.value) > 0 && isQuote(p.cur.value[0]) { // Look for multiple quoted strings separated by whitespace, // and concatenate them. cat := p.cur for { p.skipWhitespace() if p.done || !isQuote(p.s[0]) { break } p.advance() if p.cur.err != nil { return &p.cur } cat.value += " " + p.cur.value cat.unquoted += p.cur.unquoted } p.done = false // parser may have seen EOF, but we want to return cat p.cur = cat } return &p.cur } func (p *textParser) consumeToken(s string) error { tok := p.next() if tok.err != nil { return tok.err } if tok.value != s { p.back() return p.errorf("expected %q, found %q", s, tok.value) } return nil } // Return a RequiredNotSetError indicating which required field was not set. func (p *textParser) missingRequiredFieldError(sv reflect.Value) *RequiredNotSetError { st := sv.Type() sprops := GetProperties(st) for i := 0; i < st.NumField(); i++ { if !isNil(sv.Field(i)) { continue } props := sprops.Prop[i] if props.Required { return &RequiredNotSetError{fmt.Sprintf("%v.%v", st, props.OrigName)} } } return &RequiredNotSetError{fmt.Sprintf("%v.", st)} // should not happen } // Returns the index in the struct for the named field, as well as the parsed tag properties. func structFieldByName(sprops *StructProperties, name string) (int, *Properties, bool) { i, ok := sprops.decoderOrigNames[name] if ok { return i, sprops.Prop[i], true } return -1, nil, false } // Consume a ':' from the input stream (if the next token is a colon), // returning an error if a colon is needed but not present. func (p *textParser) checkForColon(props *Properties, typ reflect.Type) *ParseError { tok := p.next() if tok.err != nil { return tok.err } if tok.value != ":" { // Colon is optional when the field is a group or message. needColon := true switch props.Wire { case "group": needColon = false case "bytes": // A "bytes" field is either a message, a string, or a repeated field; // those three become *T, *string and []T respectively, so we can check for // this field being a pointer to a non-string. if typ.Kind() == reflect.Ptr { // *T or *string if typ.Elem().Kind() == reflect.String { break } } else if typ.Kind() == reflect.Slice { // []T or []*T if typ.Elem().Kind() != reflect.Ptr { break } } else if typ.Kind() == reflect.String { // The proto3 exception is for a string field, // which requires a colon. break } needColon = false } if needColon { return p.errorf("expected ':', found %q", tok.value) } p.back() } return nil } func (p *textParser) readStruct(sv reflect.Value, terminator string) error { st := sv.Type() sprops := GetProperties(st) reqCount := sprops.reqCount var reqFieldErr error fieldSet := make(map[string]bool) // A struct is a sequence of "name: value", terminated by one of // '>' or '}', or the end of the input. A name may also be // "[extension]" or "[type/url]". // // The whole struct can also be an expanded Any message, like: // [type/url] < ... struct contents ... > for { tok := p.next() if tok.err != nil { return tok.err } if tok.value == terminator { break } if tok.value == "[" { // Looks like an extension or an Any. // // TODO: Check whether we need to handle // namespace rooted names (e.g. ".something.Foo"). extName, err := p.consumeExtName() if err != nil { return err } if s := strings.LastIndex(extName, "/"); s >= 0 { // If it contains a slash, it's an Any type URL. messageName := extName[s+1:] mt := MessageType(messageName) if mt == nil { return p.errorf("unrecognized message %q in google.protobuf.Any", messageName) } tok = p.next() if tok.err != nil { return tok.err } // consume an optional colon if tok.value == ":" { tok = p.next() if tok.err != nil { return tok.err } } var terminator string switch tok.value { case "<": terminator = ">" case "{": terminator = "}" default: return p.errorf("expected '{' or '<', found %q", tok.value) } v := reflect.New(mt.Elem()) if pe := p.readStruct(v.Elem(), terminator); pe != nil { return pe } b, err := Marshal(v.Interface().(Message)) if err != nil { return p.errorf("failed to marshal message of type %q: %v", messageName, err) } if fieldSet["type_url"] { return p.errorf(anyRepeatedlyUnpacked, "type_url") } if fieldSet["value"] { return p.errorf(anyRepeatedlyUnpacked, "value") } sv.FieldByName("TypeUrl").SetString(extName) sv.FieldByName("Value").SetBytes(b) fieldSet["type_url"] = true fieldSet["value"] = true continue } var desc *ExtensionDesc // This could be faster, but it's functional. // TODO: Do something smarter than a linear scan. for _, d := range RegisteredExtensions(reflect.New(st).Interface().(Message)) { if d.Name == extName { desc = d break } } if desc == nil { return p.errorf("unrecognized extension %q", extName) } props := &Properties{} props.Parse(desc.Tag) typ := reflect.TypeOf(desc.ExtensionType) if err := p.checkForColon(props, typ); err != nil { return err } rep := desc.repeated() // Read the extension structure, and set it in // the value we're constructing. var ext reflect.Value if !rep { ext = reflect.New(typ).Elem() } else { ext = reflect.New(typ.Elem()).Elem() } if err := p.readAny(ext, props); err != nil { if _, ok := err.(*RequiredNotSetError); !ok { return err } reqFieldErr = err } ep := sv.Addr().Interface().(Message) if !rep { SetExtension(ep, desc, ext.Interface()) } else { old, err := GetExtension(ep, desc) var sl reflect.Value if err == nil { sl = reflect.ValueOf(old) // existing slice } else { sl = reflect.MakeSlice(typ, 0, 1) } sl = reflect.Append(sl, ext) SetExtension(ep, desc, sl.Interface()) } if err := p.consumeOptionalSeparator(); err != nil { return err } continue } // This is a normal, non-extension field. name := tok.value var dst reflect.Value fi, props, ok := structFieldByName(sprops, name) if ok { dst = sv.Field(fi) } else if oop, ok := sprops.OneofTypes[name]; ok { // It is a oneof. props = oop.Prop nv := reflect.New(oop.Type.Elem()) dst = nv.Elem().Field(0) field := sv.Field(oop.Field) if !field.IsNil() { return p.errorf("field '%s' would overwrite already parsed oneof '%s'", name, sv.Type().Field(oop.Field).Name) } field.Set(nv) } if !dst.IsValid() { return p.errorf("unknown field name %q in %v", name, st) } if dst.Kind() == reflect.Map { // Consume any colon. if err := p.checkForColon(props, dst.Type()); err != nil { return err } // Construct the map if it doesn't already exist. if dst.IsNil() { dst.Set(reflect.MakeMap(dst.Type())) } key := reflect.New(dst.Type().Key()).Elem() val := reflect.New(dst.Type().Elem()).Elem() // The map entry should be this sequence of tokens: // < key : KEY value : VALUE > // However, implementations may omit key or value, and technically // we should support them in any order. See b/28924776 for a time // this went wrong. tok := p.next() var terminator string switch tok.value { case "<": terminator = ">" case "{": terminator = "}" default: return p.errorf("expected '{' or '<', found %q", tok.value) } for { tok := p.next() if tok.err != nil { return tok.err } if tok.value == terminator { break } switch tok.value { case "key": if err := p.consumeToken(":"); err != nil { return err } if err := p.readAny(key, props.mkeyprop); err != nil { return err } if err := p.consumeOptionalSeparator(); err != nil { return err } case "value": if err := p.checkForColon(props.mvalprop, dst.Type().Elem()); err != nil { return err } if err := p.readAny(val, props.mvalprop); err != nil { return err } if err := p.consumeOptionalSeparator(); err != nil { return err } default: p.back() return p.errorf(`expected "key", "value", or %q, found %q`, terminator, tok.value) } } dst.SetMapIndex(key, val) continue } // Check that it's not already set if it's not a repeated field. if !props.Repeated && fieldSet[name] { return p.errorf("non-repeated field %q was repeated", name) } if err := p.checkForColon(props, dst.Type()); err != nil { return err } // Parse into the field. fieldSet[name] = true if err := p.readAny(dst, props); err != nil { if _, ok := err.(*RequiredNotSetError); !ok { return err } reqFieldErr = err } if props.Required { reqCount-- } if err := p.consumeOptionalSeparator(); err != nil { return err } } if reqCount > 0 { return p.missingRequiredFieldError(sv) } return reqFieldErr } // consumeExtName consumes extension name or expanded Any type URL and the // following ']'. It returns the name or URL consumed. func (p *textParser) consumeExtName() (string, error) { tok := p.next() if tok.err != nil { return "", tok.err } // If extension name or type url is quoted, it's a single token. if len(tok.value) > 2 && isQuote(tok.value[0]) && tok.value[len(tok.value)-1] == tok.value[0] { name, err := unquoteC(tok.value[1:len(tok.value)-1], rune(tok.value[0])) if err != nil { return "", err } return name, p.consumeToken("]") } // Consume everything up to "]" var parts []string for tok.value != "]" { parts = append(parts, tok.value) tok = p.next() if tok.err != nil { return "", p.errorf("unrecognized type_url or extension name: %s", tok.err) } } return strings.Join(parts, ""), nil } // consumeOptionalSeparator consumes an optional semicolon or comma. // It is used in readStruct to provide backward compatibility. func (p *textParser) consumeOptionalSeparator() error { tok := p.next() if tok.err != nil { return tok.err } if tok.value != ";" && tok.value != "," { p.back() } return nil } func (p *textParser) readAny(v reflect.Value, props *Properties) error { tok := p.next() if tok.err != nil { return tok.err } if tok.value == "" { return p.errorf("unexpected EOF") } switch fv := v; fv.Kind() { case reflect.Slice: at := v.Type() if at.Elem().Kind() == reflect.Uint8 { // Special case for []byte if tok.value[0] != '"' && tok.value[0] != '\'' { // Deliberately written out here, as the error after // this switch statement would write "invalid []byte: ...", // which is not as user-friendly. return p.errorf("invalid string: %v", tok.value) } bytes := []byte(tok.unquoted) fv.Set(reflect.ValueOf(bytes)) return nil } // Repeated field. if tok.value == "[" { // Repeated field with list notation, like [1,2,3]. for { fv.Set(reflect.Append(fv, reflect.New(at.Elem()).Elem())) err := p.readAny(fv.Index(fv.Len()-1), props) if err != nil { return err } tok := p.next() if tok.err != nil { return tok.err } if tok.value == "]" { break } if tok.value != "," { return p.errorf("Expected ']' or ',' found %q", tok.value) } } return nil } // One value of the repeated field. p.back() fv.Set(reflect.Append(fv, reflect.New(at.Elem()).Elem())) return p.readAny(fv.Index(fv.Len()-1), props) case reflect.Bool: // true/1/t/True or false/f/0/False. switch tok.value { case "true", "1", "t", "True": fv.SetBool(true) return nil case "false", "0", "f", "False": fv.SetBool(false) return nil } case reflect.Float32, reflect.Float64: v := tok.value // Ignore 'f' for compatibility with output generated by C++, but don't // remove 'f' when the value is "-inf" or "inf". if strings.HasSuffix(v, "f") && tok.value != "-inf" && tok.value != "inf" { v = v[:len(v)-1] } if f, err := strconv.ParseFloat(v, fv.Type().Bits()); err == nil { fv.SetFloat(f) return nil } case reflect.Int32: if x, err := strconv.ParseInt(tok.value, 0, 32); err == nil { fv.SetInt(x) return nil } if len(props.Enum) == 0 { break } m, ok := enumValueMaps[props.Enum] if !ok { break } x, ok := m[tok.value] if !ok { break } fv.SetInt(int64(x)) return nil case reflect.Int64: if x, err := strconv.ParseInt(tok.value, 0, 64); err == nil { fv.SetInt(x) return nil } case reflect.Ptr: // A basic field (indirected through pointer), or a repeated message/group p.back() fv.Set(reflect.New(fv.Type().Elem())) return p.readAny(fv.Elem(), props) case reflect.String: if tok.value[0] == '"' || tok.value[0] == '\'' { fv.SetString(tok.unquoted) return nil } case reflect.Struct: var terminator string switch tok.value { case "{": terminator = "}" case "<": terminator = ">" default: return p.errorf("expected '{' or '<', found %q", tok.value) } // TODO: Handle nested messages which implement encoding.TextUnmarshaler. return p.readStruct(fv, terminator) case reflect.Uint32: if x, err := strconv.ParseUint(tok.value, 0, 32); err == nil { fv.SetUint(x) return nil } case reflect.Uint64: if x, err := strconv.ParseUint(tok.value, 0, 64); err == nil { fv.SetUint(x) return nil } } return p.errorf("invalid %v: %v", v.Type(), tok.value) } // UnmarshalText reads a protocol buffer in Text format. UnmarshalText resets pb // before starting to unmarshal, so any existing data in pb is always removed. // If a required field is not set and no other error occurs, // UnmarshalText returns *RequiredNotSetError. func UnmarshalText(s string, pb Message) error { if um, ok := pb.(encoding.TextUnmarshaler); ok { err := um.UnmarshalText([]byte(s)) return err } pb.Reset() v := reflect.ValueOf(pb) if pe := newTextParser(s).readStruct(v.Elem(), ""); pe != nil { return pe } return nil } ================================================ FILE: vendor/github.com/golang/protobuf/proto/text_parser_test.go ================================================ // Go support for Protocol Buffers - Google's data interchange format // // Copyright 2010 The Go Authors. All rights reserved. // https://github.com/golang/protobuf // // 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. package proto_test import ( "math" "reflect" "testing" . "github.com/golang/protobuf/proto" proto3pb "github.com/golang/protobuf/proto/proto3_proto" . "github.com/golang/protobuf/proto/testdata" ) type UnmarshalTextTest struct { in string err string // if "", no error expected out *MyMessage } func buildExtStructTest(text string) UnmarshalTextTest { msg := &MyMessage{ Count: Int32(42), } SetExtension(msg, E_Ext_More, &Ext{ Data: String("Hello, world!"), }) return UnmarshalTextTest{in: text, out: msg} } func buildExtDataTest(text string) UnmarshalTextTest { msg := &MyMessage{ Count: Int32(42), } SetExtension(msg, E_Ext_Text, String("Hello, world!")) SetExtension(msg, E_Ext_Number, Int32(1729)) return UnmarshalTextTest{in: text, out: msg} } func buildExtRepStringTest(text string) UnmarshalTextTest { msg := &MyMessage{ Count: Int32(42), } if err := SetExtension(msg, E_Greeting, []string{"bula", "hola"}); err != nil { panic(err) } return UnmarshalTextTest{in: text, out: msg} } var unMarshalTextTests = []UnmarshalTextTest{ // Basic { in: " count:42\n name:\"Dave\" ", out: &MyMessage{ Count: Int32(42), Name: String("Dave"), }, }, // Empty quoted string { in: `count:42 name:""`, out: &MyMessage{ Count: Int32(42), Name: String(""), }, }, // Quoted string concatenation with double quotes { in: `count:42 name: "My name is "` + "\n" + `"elsewhere"`, out: &MyMessage{ Count: Int32(42), Name: String("My name is elsewhere"), }, }, // Quoted string concatenation with single quotes { in: "count:42 name: 'My name is '\n'elsewhere'", out: &MyMessage{ Count: Int32(42), Name: String("My name is elsewhere"), }, }, // Quoted string concatenations with mixed quotes { in: "count:42 name: 'My name is '\n\"elsewhere\"", out: &MyMessage{ Count: Int32(42), Name: String("My name is elsewhere"), }, }, { in: "count:42 name: \"My name is \"\n'elsewhere'", out: &MyMessage{ Count: Int32(42), Name: String("My name is elsewhere"), }, }, // Quoted string with escaped apostrophe { in: `count:42 name: "HOLIDAY - New Year\'s Day"`, out: &MyMessage{ Count: Int32(42), Name: String("HOLIDAY - New Year's Day"), }, }, // Quoted string with single quote { in: `count:42 name: 'Roger "The Ramster" Ramjet'`, out: &MyMessage{ Count: Int32(42), Name: String(`Roger "The Ramster" Ramjet`), }, }, // Quoted string with all the accepted special characters from the C++ test { in: `count:42 name: ` + "\"\\\"A string with \\' characters \\n and \\r newlines and \\t tabs and \\001 slashes \\\\ and multiple spaces\"", out: &MyMessage{ Count: Int32(42), Name: String("\"A string with ' characters \n and \r newlines and \t tabs and \001 slashes \\ and multiple spaces"), }, }, // Quoted string with quoted backslash { in: `count:42 name: "\\'xyz"`, out: &MyMessage{ Count: Int32(42), Name: String(`\'xyz`), }, }, // Quoted string with UTF-8 bytes. { in: "count:42 name: '\303\277\302\201\xAB'", out: &MyMessage{ Count: Int32(42), Name: String("\303\277\302\201\xAB"), }, }, // Bad quoted string { in: `inner: < host: "\0" >` + "\n", err: `line 1.15: invalid quoted string "\0": \0 requires 2 following digits`, }, // Number too large for int64 { in: "count: 1 others { key: 123456789012345678901 }", err: "line 1.23: invalid int64: 123456789012345678901", }, // Number too large for int32 { in: "count: 1234567890123", err: "line 1.7: invalid int32: 1234567890123", }, // Number in hexadecimal { in: "count: 0x2beef", out: &MyMessage{ Count: Int32(0x2beef), }, }, // Number in octal { in: "count: 024601", out: &MyMessage{ Count: Int32(024601), }, }, // Floating point number with "f" suffix { in: "count: 4 others:< weight: 17.0f >", out: &MyMessage{ Count: Int32(4), Others: []*OtherMessage{ { Weight: Float32(17), }, }, }, }, // Floating point positive infinity { in: "count: 4 bigfloat: inf", out: &MyMessage{ Count: Int32(4), Bigfloat: Float64(math.Inf(1)), }, }, // Floating point negative infinity { in: "count: 4 bigfloat: -inf", out: &MyMessage{ Count: Int32(4), Bigfloat: Float64(math.Inf(-1)), }, }, // Number too large for float32 { in: "others:< weight: 12345678901234567890123456789012345678901234567890 >", err: "line 1.17: invalid float32: 12345678901234567890123456789012345678901234567890", }, // Number posing as a quoted string { in: `inner: < host: 12 >` + "\n", err: `line 1.15: invalid string: 12`, }, // Quoted string posing as int32 { in: `count: "12"`, err: `line 1.7: invalid int32: "12"`, }, // Quoted string posing a float32 { in: `others:< weight: "17.4" >`, err: `line 1.17: invalid float32: "17.4"`, }, // Enum { in: `count:42 bikeshed: BLUE`, out: &MyMessage{ Count: Int32(42), Bikeshed: MyMessage_BLUE.Enum(), }, }, // Repeated field { in: `count:42 pet: "horsey" pet:"bunny"`, out: &MyMessage{ Count: Int32(42), Pet: []string{"horsey", "bunny"}, }, }, // Repeated field with list notation { in: `count:42 pet: ["horsey", "bunny"]`, out: &MyMessage{ Count: Int32(42), Pet: []string{"horsey", "bunny"}, }, }, // Repeated message with/without colon and <>/{} { in: `count:42 others:{} others{} others:<> others:{}`, out: &MyMessage{ Count: Int32(42), Others: []*OtherMessage{ {}, {}, {}, {}, }, }, }, // Missing colon for inner message { in: `count:42 inner < host: "cauchy.syd" >`, out: &MyMessage{ Count: Int32(42), Inner: &InnerMessage{ Host: String("cauchy.syd"), }, }, }, // Missing colon for string field { in: `name "Dave"`, err: `line 1.5: expected ':', found "\"Dave\""`, }, // Missing colon for int32 field { in: `count 42`, err: `line 1.6: expected ':', found "42"`, }, // Missing required field { in: `name: "Pawel"`, err: `proto: required field "testdata.MyMessage.count" not set`, out: &MyMessage{ Name: String("Pawel"), }, }, // Missing required field in a required submessage { in: `count: 42 we_must_go_deeper < leo_finally_won_an_oscar <> >`, err: `proto: required field "testdata.InnerMessage.host" not set`, out: &MyMessage{ Count: Int32(42), WeMustGoDeeper: &RequiredInnerMessage{LeoFinallyWonAnOscar: &InnerMessage{}}, }, }, // Repeated non-repeated field { in: `name: "Rob" name: "Russ"`, err: `line 1.12: non-repeated field "name" was repeated`, }, // Group { in: `count: 17 SomeGroup { group_field: 12 }`, out: &MyMessage{ Count: Int32(17), Somegroup: &MyMessage_SomeGroup{ GroupField: Int32(12), }, }, }, // Semicolon between fields { in: `count:3;name:"Calvin"`, out: &MyMessage{ Count: Int32(3), Name: String("Calvin"), }, }, // Comma between fields { in: `count:4,name:"Ezekiel"`, out: &MyMessage{ Count: Int32(4), Name: String("Ezekiel"), }, }, // Boolean false { in: `count:42 inner { host: "example.com" connected: false }`, out: &MyMessage{ Count: Int32(42), Inner: &InnerMessage{ Host: String("example.com"), Connected: Bool(false), }, }, }, // Boolean true { in: `count:42 inner { host: "example.com" connected: true }`, out: &MyMessage{ Count: Int32(42), Inner: &InnerMessage{ Host: String("example.com"), Connected: Bool(true), }, }, }, // Boolean 0 { in: `count:42 inner { host: "example.com" connected: 0 }`, out: &MyMessage{ Count: Int32(42), Inner: &InnerMessage{ Host: String("example.com"), Connected: Bool(false), }, }, }, // Boolean 1 { in: `count:42 inner { host: "example.com" connected: 1 }`, out: &MyMessage{ Count: Int32(42), Inner: &InnerMessage{ Host: String("example.com"), Connected: Bool(true), }, }, }, // Boolean f { in: `count:42 inner { host: "example.com" connected: f }`, out: &MyMessage{ Count: Int32(42), Inner: &InnerMessage{ Host: String("example.com"), Connected: Bool(false), }, }, }, // Boolean t { in: `count:42 inner { host: "example.com" connected: t }`, out: &MyMessage{ Count: Int32(42), Inner: &InnerMessage{ Host: String("example.com"), Connected: Bool(true), }, }, }, // Boolean False { in: `count:42 inner { host: "example.com" connected: False }`, out: &MyMessage{ Count: Int32(42), Inner: &InnerMessage{ Host: String("example.com"), Connected: Bool(false), }, }, }, // Boolean True { in: `count:42 inner { host: "example.com" connected: True }`, out: &MyMessage{ Count: Int32(42), Inner: &InnerMessage{ Host: String("example.com"), Connected: Bool(true), }, }, }, // Extension buildExtStructTest(`count: 42 [testdata.Ext.more]:`), buildExtStructTest(`count: 42 [testdata.Ext.more] {data:"Hello, world!"}`), buildExtDataTest(`count: 42 [testdata.Ext.text]:"Hello, world!" [testdata.Ext.number]:1729`), buildExtRepStringTest(`count: 42 [testdata.greeting]:"bula" [testdata.greeting]:"hola"`), // Big all-in-one { in: "count:42 # Meaning\n" + `name:"Dave" ` + `quote:"\"I didn't want to go.\"" ` + `pet:"bunny" ` + `pet:"kitty" ` + `pet:"horsey" ` + `inner:<` + ` host:"footrest.syd" ` + ` port:7001 ` + ` connected:true ` + `> ` + `others:<` + ` key:3735928559 ` + ` value:"\x01A\a\f" ` + `> ` + `others:<` + " weight:58.9 # Atomic weight of Co\n" + ` inner:<` + ` host:"lesha.mtv" ` + ` port:8002 ` + ` >` + `>`, out: &MyMessage{ Count: Int32(42), Name: String("Dave"), Quote: String(`"I didn't want to go."`), Pet: []string{"bunny", "kitty", "horsey"}, Inner: &InnerMessage{ Host: String("footrest.syd"), Port: Int32(7001), Connected: Bool(true), }, Others: []*OtherMessage{ { Key: Int64(3735928559), Value: []byte{0x1, 'A', '\a', '\f'}, }, { Weight: Float32(58.9), Inner: &InnerMessage{ Host: String("lesha.mtv"), Port: Int32(8002), }, }, }, }, }, } func TestUnmarshalText(t *testing.T) { for i, test := range unMarshalTextTests { pb := new(MyMessage) err := UnmarshalText(test.in, pb) if test.err == "" { // We don't expect failure. if err != nil { t.Errorf("Test %d: Unexpected error: %v", i, err) } else if !reflect.DeepEqual(pb, test.out) { t.Errorf("Test %d: Incorrect populated \nHave: %v\nWant: %v", i, pb, test.out) } } else { // We do expect failure. if err == nil { t.Errorf("Test %d: Didn't get expected error: %v", i, test.err) } else if err.Error() != test.err { t.Errorf("Test %d: Incorrect error.\nHave: %v\nWant: %v", i, err.Error(), test.err) } else if _, ok := err.(*RequiredNotSetError); ok && test.out != nil && !reflect.DeepEqual(pb, test.out) { t.Errorf("Test %d: Incorrect populated \nHave: %v\nWant: %v", i, pb, test.out) } } } } func TestUnmarshalTextCustomMessage(t *testing.T) { msg := &textMessage{} if err := UnmarshalText("custom", msg); err != nil { t.Errorf("Unexpected error from custom unmarshal: %v", err) } if UnmarshalText("not custom", msg) == nil { t.Errorf("Didn't get expected error from custom unmarshal") } } // Regression test; this caused a panic. func TestRepeatedEnum(t *testing.T) { pb := new(RepeatedEnum) if err := UnmarshalText("color: RED", pb); err != nil { t.Fatal(err) } exp := &RepeatedEnum{ Color: []RepeatedEnum_Color{RepeatedEnum_RED}, } if !Equal(pb, exp) { t.Errorf("Incorrect populated \nHave: %v\nWant: %v", pb, exp) } } func TestProto3TextParsing(t *testing.T) { m := new(proto3pb.Message) const in = `name: "Wallace" true_scotsman: true` want := &proto3pb.Message{ Name: "Wallace", TrueScotsman: true, } if err := UnmarshalText(in, m); err != nil { t.Fatal(err) } if !Equal(m, want) { t.Errorf("\n got %v\nwant %v", m, want) } } func TestMapParsing(t *testing.T) { m := new(MessageWithMap) const in = `name_mapping: name_mapping:` + `msg_mapping:,>` + // separating commas are okay `msg_mapping>` + // no colon after "value" `msg_mapping:>` + // omitted key `msg_mapping:` + // omitted value `byte_mapping:` + `byte_mapping:<>` // omitted key and value want := &MessageWithMap{ NameMapping: map[int32]string{ 1: "Beatles", 1234: "Feist", }, MsgMapping: map[int64]*FloatingPoint{ -4: {F: Float64(2.0)}, -2: {F: Float64(4.0)}, 0: {F: Float64(5.0)}, 1: nil, }, ByteMapping: map[bool][]byte{ false: nil, true: []byte("so be it"), }, } if err := UnmarshalText(in, m); err != nil { t.Fatal(err) } if !Equal(m, want) { t.Errorf("\n got %v\nwant %v", m, want) } } func TestOneofParsing(t *testing.T) { const in = `name:"Shrek"` m := new(Communique) want := &Communique{Union: &Communique_Name{"Shrek"}} if err := UnmarshalText(in, m); err != nil { t.Fatal(err) } if !Equal(m, want) { t.Errorf("\n got %v\nwant %v", m, want) } const inOverwrite = `name:"Shrek" number:42` m = new(Communique) testErr := "line 1.13: field 'number' would overwrite already parsed oneof 'Union'" if err := UnmarshalText(inOverwrite, m); err == nil { t.Errorf("TestOneofParsing: Didn't get expected error: %v", testErr) } else if err.Error() != testErr { t.Errorf("TestOneofParsing: Incorrect error.\nHave: %v\nWant: %v", err.Error(), testErr) } } var benchInput string func init() { benchInput = "count: 4\n" for i := 0; i < 1000; i++ { benchInput += "pet: \"fido\"\n" } // Check it is valid input. pb := new(MyMessage) err := UnmarshalText(benchInput, pb) if err != nil { panic("Bad benchmark input: " + err.Error()) } } func BenchmarkUnmarshalText(b *testing.B) { pb := new(MyMessage) for i := 0; i < b.N; i++ { UnmarshalText(benchInput, pb) } b.SetBytes(int64(len(benchInput))) } ================================================ FILE: vendor/github.com/golang/protobuf/proto/text_test.go ================================================ // Go support for Protocol Buffers - Google's data interchange format // // Copyright 2010 The Go Authors. All rights reserved. // https://github.com/golang/protobuf // // 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. package proto_test import ( "bytes" "errors" "io/ioutil" "math" "strings" "testing" "github.com/golang/protobuf/proto" proto3pb "github.com/golang/protobuf/proto/proto3_proto" pb "github.com/golang/protobuf/proto/testdata" ) // textMessage implements the methods that allow it to marshal and unmarshal // itself as text. type textMessage struct { } func (*textMessage) MarshalText() ([]byte, error) { return []byte("custom"), nil } func (*textMessage) UnmarshalText(bytes []byte) error { if string(bytes) != "custom" { return errors.New("expected 'custom'") } return nil } func (*textMessage) Reset() {} func (*textMessage) String() string { return "" } func (*textMessage) ProtoMessage() {} func newTestMessage() *pb.MyMessage { msg := &pb.MyMessage{ Count: proto.Int32(42), Name: proto.String("Dave"), Quote: proto.String(`"I didn't want to go."`), Pet: []string{"bunny", "kitty", "horsey"}, Inner: &pb.InnerMessage{ Host: proto.String("footrest.syd"), Port: proto.Int32(7001), Connected: proto.Bool(true), }, Others: []*pb.OtherMessage{ { Key: proto.Int64(0xdeadbeef), Value: []byte{1, 65, 7, 12}, }, { Weight: proto.Float32(6.022), Inner: &pb.InnerMessage{ Host: proto.String("lesha.mtv"), Port: proto.Int32(8002), }, }, }, Bikeshed: pb.MyMessage_BLUE.Enum(), Somegroup: &pb.MyMessage_SomeGroup{ GroupField: proto.Int32(8), }, // One normally wouldn't do this. // This is an undeclared tag 13, as a varint (wire type 0) with value 4. XXX_unrecognized: []byte{13<<3 | 0, 4}, } ext := &pb.Ext{ Data: proto.String("Big gobs for big rats"), } if err := proto.SetExtension(msg, pb.E_Ext_More, ext); err != nil { panic(err) } greetings := []string{"adg", "easy", "cow"} if err := proto.SetExtension(msg, pb.E_Greeting, greetings); err != nil { panic(err) } // Add an unknown extension. We marshal a pb.Ext, and fake the ID. b, err := proto.Marshal(&pb.Ext{Data: proto.String("3G skiing")}) if err != nil { panic(err) } b = append(proto.EncodeVarint(201<<3|proto.WireBytes), b...) proto.SetRawExtension(msg, 201, b) // Extensions can be plain fields, too, so let's test that. b = append(proto.EncodeVarint(202<<3|proto.WireVarint), 19) proto.SetRawExtension(msg, 202, b) return msg } const text = `count: 42 name: "Dave" quote: "\"I didn't want to go.\"" pet: "bunny" pet: "kitty" pet: "horsey" inner: < host: "footrest.syd" port: 7001 connected: true > others: < key: 3735928559 value: "\001A\007\014" > others: < weight: 6.022 inner: < host: "lesha.mtv" port: 8002 > > bikeshed: BLUE SomeGroup { group_field: 8 } /* 2 unknown bytes */ 13: 4 [testdata.Ext.more]: < data: "Big gobs for big rats" > [testdata.greeting]: "adg" [testdata.greeting]: "easy" [testdata.greeting]: "cow" /* 13 unknown bytes */ 201: "\t3G skiing" /* 3 unknown bytes */ 202: 19 ` func TestMarshalText(t *testing.T) { buf := new(bytes.Buffer) if err := proto.MarshalText(buf, newTestMessage()); err != nil { t.Fatalf("proto.MarshalText: %v", err) } s := buf.String() if s != text { t.Errorf("Got:\n===\n%v===\nExpected:\n===\n%v===\n", s, text) } } func TestMarshalTextCustomMessage(t *testing.T) { buf := new(bytes.Buffer) if err := proto.MarshalText(buf, &textMessage{}); err != nil { t.Fatalf("proto.MarshalText: %v", err) } s := buf.String() if s != "custom" { t.Errorf("Got %q, expected %q", s, "custom") } } func TestMarshalTextNil(t *testing.T) { want := "" tests := []proto.Message{nil, (*pb.MyMessage)(nil)} for i, test := range tests { buf := new(bytes.Buffer) if err := proto.MarshalText(buf, test); err != nil { t.Fatal(err) } if got := buf.String(); got != want { t.Errorf("%d: got %q want %q", i, got, want) } } } func TestMarshalTextUnknownEnum(t *testing.T) { // The Color enum only specifies values 0-2. m := &pb.MyMessage{Bikeshed: pb.MyMessage_Color(3).Enum()} got := m.String() const want = `bikeshed:3 ` if got != want { t.Errorf("\n got %q\nwant %q", got, want) } } func TestTextOneof(t *testing.T) { tests := []struct { m proto.Message want string }{ // zero message {&pb.Communique{}, ``}, // scalar field {&pb.Communique{Union: &pb.Communique_Number{4}}, `number:4`}, // message field {&pb.Communique{Union: &pb.Communique_Msg{ &pb.Strings{StringField: proto.String("why hello!")}, }}, `msg:`}, // bad oneof (should not panic) {&pb.Communique{Union: &pb.Communique_Msg{nil}}, `msg:/* nil */`}, } for _, test := range tests { got := strings.TrimSpace(test.m.String()) if got != test.want { t.Errorf("\n got %s\nwant %s", got, test.want) } } } func BenchmarkMarshalTextBuffered(b *testing.B) { buf := new(bytes.Buffer) m := newTestMessage() for i := 0; i < b.N; i++ { buf.Reset() proto.MarshalText(buf, m) } } func BenchmarkMarshalTextUnbuffered(b *testing.B) { w := ioutil.Discard m := newTestMessage() for i := 0; i < b.N; i++ { proto.MarshalText(w, m) } } func compact(src string) string { // s/[ \n]+/ /g; s/ $//; dst := make([]byte, len(src)) space, comment := false, false j := 0 for i := 0; i < len(src); i++ { if strings.HasPrefix(src[i:], "/*") { comment = true i++ continue } if comment && strings.HasPrefix(src[i:], "*/") { comment = false i++ continue } if comment { continue } c := src[i] if c == ' ' || c == '\n' { space = true continue } if j > 0 && (dst[j-1] == ':' || dst[j-1] == '<' || dst[j-1] == '{') { space = false } if c == '{' { space = false } if space { dst[j] = ' ' j++ space = false } dst[j] = c j++ } if space { dst[j] = ' ' j++ } return string(dst[0:j]) } var compactText = compact(text) func TestCompactText(t *testing.T) { s := proto.CompactTextString(newTestMessage()) if s != compactText { t.Errorf("Got:\n===\n%v===\nExpected:\n===\n%v\n===\n", s, compactText) } } func TestStringEscaping(t *testing.T) { testCases := []struct { in *pb.Strings out string }{ { // Test data from C++ test (TextFormatTest.StringEscape). // Single divergence: we don't escape apostrophes. &pb.Strings{StringField: proto.String("\"A string with ' characters \n and \r newlines and \t tabs and \001 slashes \\ and multiple spaces")}, "string_field: \"\\\"A string with ' characters \\n and \\r newlines and \\t tabs and \\001 slashes \\\\ and multiple spaces\"\n", }, { // Test data from the same C++ test. &pb.Strings{StringField: proto.String("\350\260\267\346\255\214")}, "string_field: \"\\350\\260\\267\\346\\255\\214\"\n", }, { // Some UTF-8. &pb.Strings{StringField: proto.String("\x00\x01\xff\x81")}, `string_field: "\000\001\377\201"` + "\n", }, } for i, tc := range testCases { var buf bytes.Buffer if err := proto.MarshalText(&buf, tc.in); err != nil { t.Errorf("proto.MarsalText: %v", err) continue } s := buf.String() if s != tc.out { t.Errorf("#%d: Got:\n%s\nExpected:\n%s\n", i, s, tc.out) continue } // Check round-trip. pb := new(pb.Strings) if err := proto.UnmarshalText(s, pb); err != nil { t.Errorf("#%d: UnmarshalText: %v", i, err) continue } if !proto.Equal(pb, tc.in) { t.Errorf("#%d: Round-trip failed:\nstart: %v\n end: %v", i, tc.in, pb) } } } // A limitedWriter accepts some output before it fails. // This is a proxy for something like a nearly-full or imminently-failing disk, // or a network connection that is about to die. type limitedWriter struct { b bytes.Buffer limit int } var outOfSpace = errors.New("proto: insufficient space") func (w *limitedWriter) Write(p []byte) (n int, err error) { var avail = w.limit - w.b.Len() if avail <= 0 { return 0, outOfSpace } if len(p) <= avail { return w.b.Write(p) } n, _ = w.b.Write(p[:avail]) return n, outOfSpace } func TestMarshalTextFailing(t *testing.T) { // Try lots of different sizes to exercise more error code-paths. for lim := 0; lim < len(text); lim++ { buf := new(limitedWriter) buf.limit = lim err := proto.MarshalText(buf, newTestMessage()) // We expect a certain error, but also some partial results in the buffer. if err != outOfSpace { t.Errorf("Got:\n===\n%v===\nExpected:\n===\n%v===\n", err, outOfSpace) } s := buf.b.String() x := text[:buf.limit] if s != x { t.Errorf("Got:\n===\n%v===\nExpected:\n===\n%v===\n", s, x) } } } func TestFloats(t *testing.T) { tests := []struct { f float64 want string }{ {0, "0"}, {4.7, "4.7"}, {math.Inf(1), "inf"}, {math.Inf(-1), "-inf"}, {math.NaN(), "nan"}, } for _, test := range tests { msg := &pb.FloatingPoint{F: &test.f} got := strings.TrimSpace(msg.String()) want := `f:` + test.want if got != want { t.Errorf("f=%f: got %q, want %q", test.f, got, want) } } } func TestRepeatedNilText(t *testing.T) { m := &pb.MessageList{ Message: []*pb.MessageList_Message{ nil, &pb.MessageList_Message{ Name: proto.String("Horse"), }, nil, }, } want := `Message Message { name: "Horse" } Message ` if s := proto.MarshalTextString(m); s != want { t.Errorf(" got: %s\nwant: %s", s, want) } } func TestProto3Text(t *testing.T) { tests := []struct { m proto.Message want string }{ // zero message {&proto3pb.Message{}, ``}, // zero message except for an empty byte slice {&proto3pb.Message{Data: []byte{}}, ``}, // trivial case {&proto3pb.Message{Name: "Rob", HeightInCm: 175}, `name:"Rob" height_in_cm:175`}, // empty map {&pb.MessageWithMap{}, ``}, // non-empty map; map format is the same as a repeated struct, // and they are sorted by key (numerically for numeric keys). { &pb.MessageWithMap{NameMapping: map[int32]string{ -1: "Negatory", 7: "Lucky", 1234: "Feist", 6345789: "Otis", }}, `name_mapping: ` + `name_mapping: ` + `name_mapping: ` + `name_mapping:`, }, // map with nil value; not well-defined, but we shouldn't crash { &pb.MessageWithMap{MsgMapping: map[int64]*pb.FloatingPoint{7: nil}}, `msg_mapping:`, }, } for _, test := range tests { got := strings.TrimSpace(test.m.String()) if got != test.want { t.Errorf("\n got %s\nwant %s", got, test.want) } } } ================================================ FILE: vendor/github.com/inconshreveable/mousetrap/LICENSE ================================================ Copyright 2014 Alan Shreve Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: vendor/github.com/inconshreveable/mousetrap/README.md ================================================ # mousetrap mousetrap is a tiny library that answers a single question. On a Windows machine, was the process invoked by someone double clicking on the executable file while browsing in explorer? ### Motivation Windows developers unfamiliar with command line tools will often "double-click" the executable for a tool. Because most CLI tools print the help and then exit when invoked without arguments, this is often very frustrating for those users. mousetrap provides a way to detect these invocations so that you can provide more helpful behavior and instructions on how to run the CLI tool. To see what this looks like, both from an organizational and a technical perspective, see https://inconshreveable.com/09-09-2014/sweat-the-small-stuff/ ### The interface The library exposes a single interface: func StartedByExplorer() (bool) ================================================ FILE: vendor/github.com/inconshreveable/mousetrap/trap_others.go ================================================ // +build !windows package mousetrap // StartedByExplorer returns true if the program was invoked by the user // double-clicking on the executable from explorer.exe // // It is conservative and returns false if any of the internal calls fail. // It does not guarantee that the program was run from a terminal. It only can tell you // whether it was launched from explorer.exe // // On non-Windows platforms, it always returns false. func StartedByExplorer() bool { return false } ================================================ FILE: vendor/github.com/inconshreveable/mousetrap/trap_windows.go ================================================ // +build windows // +build !go1.4 package mousetrap import ( "fmt" "os" "syscall" "unsafe" ) const ( // defined by the Win32 API th32cs_snapprocess uintptr = 0x2 ) var ( kernel = syscall.MustLoadDLL("kernel32.dll") CreateToolhelp32Snapshot = kernel.MustFindProc("CreateToolhelp32Snapshot") Process32First = kernel.MustFindProc("Process32FirstW") Process32Next = kernel.MustFindProc("Process32NextW") ) // ProcessEntry32 structure defined by the Win32 API type processEntry32 struct { dwSize uint32 cntUsage uint32 th32ProcessID uint32 th32DefaultHeapID int th32ModuleID uint32 cntThreads uint32 th32ParentProcessID uint32 pcPriClassBase int32 dwFlags uint32 szExeFile [syscall.MAX_PATH]uint16 } func getProcessEntry(pid int) (pe *processEntry32, err error) { snapshot, _, e1 := CreateToolhelp32Snapshot.Call(th32cs_snapprocess, uintptr(0)) if snapshot == uintptr(syscall.InvalidHandle) { err = fmt.Errorf("CreateToolhelp32Snapshot: %v", e1) return } defer syscall.CloseHandle(syscall.Handle(snapshot)) var processEntry processEntry32 processEntry.dwSize = uint32(unsafe.Sizeof(processEntry)) ok, _, e1 := Process32First.Call(snapshot, uintptr(unsafe.Pointer(&processEntry))) if ok == 0 { err = fmt.Errorf("Process32First: %v", e1) return } for { if processEntry.th32ProcessID == uint32(pid) { pe = &processEntry return } ok, _, e1 = Process32Next.Call(snapshot, uintptr(unsafe.Pointer(&processEntry))) if ok == 0 { err = fmt.Errorf("Process32Next: %v", e1) return } } } func getppid() (pid int, err error) { pe, err := getProcessEntry(os.Getpid()) if err != nil { return } pid = int(pe.th32ParentProcessID) return } // StartedByExplorer returns true if the program was invoked by the user double-clicking // on the executable from explorer.exe // // It is conservative and returns false if any of the internal calls fail. // It does not guarantee that the program was run from a terminal. It only can tell you // whether it was launched from explorer.exe func StartedByExplorer() bool { ppid, err := getppid() if err != nil { return false } pe, err := getProcessEntry(ppid) if err != nil { return false } name := syscall.UTF16ToString(pe.szExeFile[:]) return name == "explorer.exe" } ================================================ FILE: vendor/github.com/inconshreveable/mousetrap/trap_windows_1.4.go ================================================ // +build windows // +build go1.4 package mousetrap import ( "os" "syscall" "unsafe" ) func getProcessEntry(pid int) (*syscall.ProcessEntry32, error) { snapshot, err := syscall.CreateToolhelp32Snapshot(syscall.TH32CS_SNAPPROCESS, 0) if err != nil { return nil, err } defer syscall.CloseHandle(snapshot) var procEntry syscall.ProcessEntry32 procEntry.Size = uint32(unsafe.Sizeof(procEntry)) if err = syscall.Process32First(snapshot, &procEntry); err != nil { return nil, err } for { if procEntry.ProcessID == uint32(pid) { return &procEntry, nil } err = syscall.Process32Next(snapshot, &procEntry) if err != nil { return nil, err } } } // StartedByExplorer returns true if the program was invoked by the user double-clicking // on the executable from explorer.exe // // It is conservative and returns false if any of the internal calls fail. // It does not guarantee that the program was run from a terminal. It only can tell you // whether it was launched from explorer.exe func StartedByExplorer() bool { pe, err := getProcessEntry(os.Getppid()) if err != nil { return false } return "explorer.exe" == syscall.UTF16ToString(pe.ExeFile[:]) } ================================================ FILE: vendor/github.com/maruel/panicparse/.travis.yml ================================================ # Copyright 2014 Marc-Antoine Ruel. All rights reserved. # Use of this source code is governed under the Apache License, Version 2.0 # that can be found in the LICENSE file. sudo: false language: go go: - 1.8.x - 1.x before_install: - go get github.com/maruel/pre-commit-go/cmd/pcg script: - pcg ================================================ FILE: vendor/github.com/maruel/panicparse/Gopkg.toml ================================================ # Gopkg.toml example # # Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md # for detailed Gopkg.toml documentation. # # required = ["github.com/user/thing/cmd/thing"] # ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] # # [[constraint]] # name = "github.com/user/project" # version = "1.0.0" # # [[constraint]] # name = "github.com/user/project2" # branch = "dev" # source = "github.com/myfork/project2" # # [[override]] # name = "github.com/x/y" # version = "2.4.0" [[constraint]] name = "github.com/maruel/ut" version = "1.0.0" [[constraint]] name = "github.com/mattn/go-colorable" version = "0.0.9" [[constraint]] name = "github.com/mattn/go-isatty" version = "0.0.2" [[constraint]] branch = "master" name = "github.com/mgutz/ansi" ================================================ FILE: vendor/github.com/maruel/panicparse/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright 2015 Marc-Antoine Ruel Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: vendor/github.com/maruel/panicparse/README.md ================================================ panicparse ========== Parses panic stack traces, densifies and deduplicates goroutines with similar stack traces. Helps debugging crashes and deadlocks in heavily parallelized process. [![Build Status](https://travis-ci.org/maruel/panicparse.svg?branch=master)](https://travis-ci.org/maruel/panicparse) panicparse helps make sense of Go crash dumps: ![Screencast](https://raw.githubusercontent.com/wiki/maruel/panicparse/parse.gif "Screencast") Features -------- * >50% more compact output than original stack dump yet more readable. * Exported symbols are bold, private symbols are darker. * Stdlib is green, main is yellow, rest is red. * Deduplicates redundant goroutine stacks. Useful for large server crashes. * Arguments as pointer IDs instead of raw pointer values. * Pushes stdlib-only stacks at the bottom to help focus on important code. * Usable as a library! [![GoDoc](https://godoc.org/github.com/maruel/panicparse/stack?status.svg)](https://godoc.org/github.com/maruel/panicparse/stack) * Warning: please pin the version (e.g. vendor it). Breaking changes are not planned but may happen. * Parses the source files if available to augment the output. * Works on Windows. Installation ------------ go get github.com/maruel/panicparse/cmd/pp Usage ----- ### Piping a stack trace from another process #### TL;DR * Ubuntu (bash v4 or zsh): `|&` * OSX, [install bash 4+](README.md#updating-bash-on-osx), then: `|&` * Windows _or_ OSX with stock bash v3: `2>&1 |` * [Fish](http://fishshell.com/) shell: `^|` #### Longer version `pp` streams its stdin to stdout as long as it doesn't detect any panic. `panic()` and Go's native deadlock detector [print to stderr](https://golang.org/src/runtime/panic1.go) via the native [`print()` function](https://golang.org/pkg/builtin/#print). **Bash v4** or **zsh**: `|&` tells the shell to redirect stderr to stdout, it's an alias for `2>&1 |` ([bash v4](https://www.gnu.org/software/bash/manual/bash.html#Pipelines), [zsh](http://zsh.sourceforge.net/Doc/Release/Shell-Grammar.html#Simple-Commands-_0026-Pipelines)): go test -v |&pp **Windows or OSX native bash** [(which is 3.2.57)](http://meta.ath0.com/2012/02/05/apples-great-gpl-purge/): They don't have this shortcut, so use the long form: go test -v 2>&1 | pp **Fish**: It uses [^ for stderr redirection](http://fishshell.com/docs/current/tutorial.html#tut_pipes_and_redirections) so the shortcut is `^|`: go test -v ^|pp **PowerShell**: [It has broken `2>&1` redirection](https://connect.microsoft.com/PowerShell/feedback/details/765551/in-powershell-v3-you-cant-redirect-stderr-to-stdout-without-generating-error-records). The workaround is to shell out to cmd.exe. :( ### Investigate deadlock On POSIX, use `Ctrl-\` to send SIGQUIT to your process, `pp` will ignore the signal and will parse the stack trace. ### Parsing from a file To dump to a file then parse, pass the file path of a stack trace go test 2> stack.txt pp stack.txt Tips ---- ### GOTRACEBACK Starting with Go 1.6, [`GOTRACEBACK`](https://golang.org/pkg/runtime/) defaults to `single` instead of `all` / `1` that was used in 1.5 and before. To get all goroutines trace and not just the crashing one, set the environment variable: export GOTRACEBACK=all or `set GOTRACEBACK=all` on Windows. Probably worth to put it in your `.bashrc`. ### Updating bash on OSX Install bash v4+ on OSX via [homebrew](http://brew.sh) or [macports](https://www.macports.org/). Your future self will appreciate having done that. ### If you have `/usr/bin/pp` installed If you try `pp` for the first time and you get: Creating tables and indexes... Done. and/or /usr/bin/pp5.18: No input files specified you may be running the _Perl PAR Packager_ instead of panicparse. You have two choices, either you put `$GOPATH/bin` at the begining of `$PATH` or use long name `panicparse` with: go get github.com/maruel/panicparse then using `panicparse` instead of `pp`: go test 2> panicparse ================================================ FILE: vendor/github.com/maruel/panicparse/main.go ================================================ // Copyright 2015 Marc-Antoine Ruel. All rights reserved. // Use of this source code is governed under the Apache License, Version 2.0 // that can be found in the LICENSE file. // panicparse: analyzes stack dump of Go processes and simplifies it. // // It is mostly useful on servers will large number of identical goroutines, // making the crash dump harder to read than strictly necesary. // // Colors: // - Magenta: first goroutine to be listed. // - Yellow: main package. // - Green: standard library. // - Red: other packages. // // Bright colors are used for exported symbols. package main import ( "fmt" "os" "github.com/maruel/panicparse/internal" ) func main() { if err := internal.Main(); err != nil { fmt.Fprintf(os.Stderr, "Failed: %s\n", err) os.Exit(1) } } ================================================ FILE: vendor/github.com/maruel/panicparse/stack/source.go ================================================ // Copyright 2015 Marc-Antoine Ruel. All rights reserved. // Use of this source code is governed under the Apache License, Version 2.0 // that can be found in the LICENSE file. // This file contains the code to process sources, to be able to deduct the // original types. package stack import ( "bytes" "fmt" "go/ast" "go/parser" "go/token" "io/ioutil" "log" "math" "strings" ) // cache is a cache of sources on the file system. type cache struct { files map[string][]byte parsed map[string]*parsedFile } // Augment processes source files to improve calls to be more descriptive. // // It modifies goroutines in place. func Augment(goroutines []Goroutine) { c := &cache{} for i := range goroutines { c.augmentGoroutine(&goroutines[i]) } } // augmentGoroutine processes source files to improve call to be more // descriptive. // // It modifies the routine. func (c *cache) augmentGoroutine(goroutine *Goroutine) { if c.files == nil { c.files = map[string][]byte{} } if c.parsed == nil { c.parsed = map[string]*parsedFile{} } // For each call site, look at the next call and populate it. Then we can // walk back and reformat things. for i := range goroutine.Stack.Calls { c.load(goroutine.Stack.Calls[i].SourcePath) } // Once all loaded, we can look at the next call when available. for i := 0; i < len(goroutine.Stack.Calls)-1; i++ { // Get the AST from the previous call and process the call line with it. if f := c.getFuncAST(&goroutine.Stack.Calls[i]); f != nil { processCall(&goroutine.Stack.Calls[i], f) } } } // Private stuff. // load loads a source file and parses the AST tree. Failures are ignored. func (c *cache) load(fileName string) { if _, ok := c.parsed[fileName]; ok { return } c.parsed[fileName] = nil if !strings.HasSuffix(fileName, ".go") { // Ignore C and assembly. c.files[fileName] = nil return } log.Printf("load(%s)", fileName) if _, ok := c.files[fileName]; !ok { var err error if c.files[fileName], err = ioutil.ReadFile(fileName); err != nil { log.Printf("Failed to read %s: %s", fileName, err) c.files[fileName] = nil return } } fset := token.NewFileSet() src := c.files[fileName] parsed, err := parser.ParseFile(fset, fileName, src, 0) if err != nil { log.Printf("Failed to parse %s: %s", fileName, err) return } // Convert the line number into raw file offset. offsets := []int{0, 0} start := 0 for l := 1; start < len(src); l++ { start += bytes.IndexByte(src[start:], '\n') + 1 offsets = append(offsets, start) } c.parsed[fileName] = &parsedFile{offsets, parsed} } func (c *cache) getFuncAST(call *Call) *ast.FuncDecl { if p := c.parsed[call.SourcePath]; p != nil { return p.getFuncAST(call.Func.Name(), call.Line) } return nil } type parsedFile struct { lineToByteOffset []int parsed *ast.File } // getFuncAST gets the callee site function AST representation for the code // inside the function f at line l. func (p *parsedFile) getFuncAST(f string, l int) (d *ast.FuncDecl) { if len(p.lineToByteOffset) <= l { // The line number in the stack trace line does not exist in the file. That // can only mean that the sources on disk do not match the sources used to // build the binary. // TODO(maruel): This should be surfaced, so that source parsing is // completely ignored. return } // Walk the AST to find the lineToByteOffset that fits the line number. var lastFunc *ast.FuncDecl var found ast.Node // Inspect() goes depth first. This means for example that a function like: // func a() { // b := func() {} // c() // } // // Were we are looking at the c() call can return confused values. It is // important to look at the actual ast.Node hierarchy. ast.Inspect(p.parsed, func(n ast.Node) bool { if d != nil { return false } if n == nil { return true } if found != nil { // We are walking up. } if int(n.Pos()) >= p.lineToByteOffset[l] { // We are expecting a ast.CallExpr node. It can be harder to figure out // when there are multiple calls on a single line, as the stack trace // doesn't have file byte offset information, only line based. // gofmt will always format to one function call per line but there can // be edge cases, like: // a = A{Foo(), Bar()} d = lastFunc //p.processNode(call, n) return false } else if f, ok := n.(*ast.FuncDecl); ok { lastFunc = f } return true }) return } func name(n ast.Node) string { switch t := n.(type) { case *ast.InterfaceType: return "interface{}" case *ast.Ident: return t.Name case *ast.SelectorExpr: return t.Sel.Name case *ast.StarExpr: return "*" + name(t.X) default: return "" } } // fieldToType returns the type name and whether if it's an ellipsis. func fieldToType(f *ast.Field) (string, bool) { switch arg := f.Type.(type) { case *ast.ArrayType: return "[]" + name(arg.Elt), false case *ast.Ellipsis: return name(arg.Elt), true case *ast.FuncType: // Do not print the function signature to not overload the trace. return "func", false case *ast.Ident: return arg.Name, false case *ast.InterfaceType: return "interface{}", false case *ast.SelectorExpr: return arg.Sel.Name, false case *ast.StarExpr: return "*" + name(arg.X), false case *ast.MapType: return fmt.Sprintf("map[%s]%s", name(arg.Key), name(arg.Value)), false case *ast.ChanType: return fmt.Sprintf("chan %s", name(arg.Value)), false default: // TODO(maruel): Implement anything missing. return "", false } } // extractArgumentsType returns the name of the type of each input argument. func extractArgumentsType(f *ast.FuncDecl) ([]string, bool) { var fields []*ast.Field if f.Recv != nil { if len(f.Recv.List) != 1 { panic("Expect only one receiver; please fix panicparse's code") } // If it is an object receiver (vs a pointer receiver), its address is not // printed in the stack trace so it needs to be ignored. if _, ok := f.Recv.List[0].Type.(*ast.StarExpr); ok { fields = append(fields, f.Recv.List[0]) } } var types []string extra := false for _, arg := range append(fields, f.Type.Params.List...) { // Assert that extra is only set on the last item of fields? var t string t, extra = fieldToType(arg) mult := len(arg.Names) if mult == 0 { mult = 1 } for i := 0; i < mult; i++ { types = append(types, t) } } return types, extra } // processCall walks the function and populate call accordingly. func processCall(call *Call, f *ast.FuncDecl) { values := make([]uint64, len(call.Args.Values)) for i := range call.Args.Values { values[i] = call.Args.Values[i].Value } index := 0 pop := func() uint64 { if len(values) != 0 { x := values[0] values = values[1:] index++ return x } return 0 } popName := func() string { n := call.Args.Values[index].Name v := pop() if len(n) == 0 { return fmt.Sprintf("0x%x", v) } return n } types, extra := extractArgumentsType(f) for i := 0; len(values) != 0; i++ { var t string if i >= len(types) { if !extra { // These are unexpected value! Print them as hex. call.Args.Processed = append(call.Args.Processed, popName()) continue } t = types[len(types)-1] } else { t = types[i] } switch t { case "float32": call.Args.Processed = append(call.Args.Processed, fmt.Sprintf("%g", math.Float32frombits(uint32(pop())))) case "float64": call.Args.Processed = append(call.Args.Processed, fmt.Sprintf("%g", math.Float64frombits(pop()))) case "int", "int8", "int16", "int32", "int64", "uint", "uint8", "uint16", "uint32", "uint64": call.Args.Processed = append(call.Args.Processed, fmt.Sprintf("%d", pop())) case "string": call.Args.Processed = append(call.Args.Processed, fmt.Sprintf("%s(%s, len=%d)", t, popName(), pop())) default: if strings.HasPrefix(t, "*") { call.Args.Processed = append(call.Args.Processed, fmt.Sprintf("%s(%s)", t, popName())) } else if strings.HasPrefix(t, "[]") { call.Args.Processed = append(call.Args.Processed, fmt.Sprintf("%s(%s len=%d cap=%d)", t, popName(), pop(), pop())) } else { // Assumes it's an interface. For now, discard the object value, which // is probably not a good idea. call.Args.Processed = append(call.Args.Processed, fmt.Sprintf("%s(%s)", t, popName())) pop() } } if len(values) == 0 && call.Args.Elided { return } } } ================================================ FILE: vendor/github.com/maruel/panicparse/stack/source_test.go ================================================ // Copyright 2015 Marc-Antoine Ruel. All rights reserved. // Use of this source code is governed under the Apache License, Version 2.0 // that can be found in the LICENSE file. package stack import ( "bytes" "fmt" "io/ioutil" "os" "os/exec" "path/filepath" "strings" "testing" "github.com/maruel/ut" ) func TestAugment(t *testing.T) { data := []struct { name string input string expected Stack }{ { "Local function doesn't interfere", `package main func f(s string) { a := func(i int) int { return 1 + i } _ = a(3) panic("ooh") } func main() { f("yo") }`, Stack{ Calls: []Call{ { SourcePath: "main.go", Line: 7, Func: Function{"main.f"}, Args: Args{ Values: []Arg{{Value: pointer, Name: ""}, {Value: 0x2}}, }, }, {SourcePath: "main.go", Line: 10, Func: Function{"main.main"}}, }, }, }, { "func", `package main func f(a func() string) { panic(a()) } func main() { f(func() string { return "ooh" }) }`, Stack{ Calls: []Call{ { SourcePath: "main.go", Line: 3, Func: Function{Raw: "main.f"}, Args: Args{Values: []Arg{{Value: pointer}}}, }, {SourcePath: "main.go", Line: 6, Func: Function{Raw: "main.main"}}, }, }, }, { "func ellipsis", `package main func f(a ...func() string) { panic(a[0]()) } func main() { f(func() string { return "ooh" }) }`, Stack{ Calls: []Call{ { SourcePath: "main.go", Line: 3, Func: Function{Raw: "main.f"}, Args: Args{ Values: []Arg{{Value: pointer}, {Value: 0x1}, {Value: 0x1}}, }, }, {SourcePath: "main.go", Line: 6, Func: Function{Raw: "main.main"}}, }, }, }, { "interface{}", `package main func f(a []interface{}) { panic("ooh") } func main() { f(make([]interface{}, 5, 7)) }`, Stack{ Calls: []Call{ { SourcePath: "main.go", Line: 3, Func: Function{Raw: "main.f"}, Args: Args{ Values: []Arg{{Value: pointer}, {Value: 0x5}, {Value: 0x7}}, }, }, {SourcePath: "main.go", Line: 6, Func: Function{Raw: "main.main"}}, }, }, }, { "[]int", `package main func f(a []int) { panic("ooh") } func main() { f(make([]int, 5, 7)) }`, Stack{ Calls: []Call{ { SourcePath: "main.go", Line: 3, Func: Function{Raw: "main.f"}, Args: Args{ Values: []Arg{{Value: pointer}, {Value: 5}, {Value: 7}}, }, }, {SourcePath: "main.go", Line: 6, Func: Function{Raw: "main.main"}}, }, }, }, { "[]interface{}", `package main func f(a []interface{}) { panic(a[0].(string)) } func main() { f([]interface{}{"ooh"}) }`, Stack{ Calls: []Call{ { SourcePath: "main.go", Line: 3, Func: Function{Raw: "main.f"}, Args: Args{ Values: []Arg{{Value: pointer}, {Value: 1}, {Value: 1}}, }, }, {SourcePath: "main.go", Line: 6, Func: Function{Raw: "main.main"}}, }, }, }, { "map[int]int", `package main func f(a map[int]int) { panic("ooh") } func main() { f(map[int]int{1: 2}) }`, Stack{ Calls: []Call{ { SourcePath: "main.go", Line: 3, Func: Function{Raw: "main.f"}, Args: Args{ Values: []Arg{{Value: pointer}}, }, }, {SourcePath: "main.go", Line: 6, Func: Function{Raw: "main.main"}}, }, }, }, { "map[interface{}]interface{}", `package main func f(a map[interface{}]interface{}) { panic("ooh") } func main() { f(make(map[interface{}]interface{})) }`, Stack{ Calls: []Call{ { SourcePath: "main.go", Line: 3, Func: Function{Raw: "main.f"}, Args: Args{ Values: []Arg{{Value: pointer}}, }, }, {SourcePath: "main.go", Line: 6, Func: Function{Raw: "main.main"}}, }, }, }, { "chan int", `package main func f(a chan int) { panic("ooh") } func main() { f(make(chan int)) }`, Stack{ Calls: []Call{ { SourcePath: "main.go", Line: 3, Func: Function{Raw: "main.f"}, Args: Args{ Values: []Arg{{Value: pointer}}, }, }, {SourcePath: "main.go", Line: 6, Func: Function{Raw: "main.main"}}, }, }, }, { "chan interface{}", `package main func f(a chan interface{}) { panic("ooh") } func main() { f(make(chan interface{})) }`, Stack{ Calls: []Call{ { SourcePath: "main.go", Line: 3, Func: Function{Raw: "main.f"}, Args: Args{ Values: []Arg{{Value: pointer}}, }, }, {SourcePath: "main.go", Line: 6, Func: Function{Raw: "main.main"}}, }, }, }, { "non-pointer method", `package main type S struct { } func (s S) f() { panic("ooh") } func main() { var s S s.f() }`, Stack{ Calls: []Call{ {SourcePath: "main.go", Line: 5, Func: Function{Raw: "main.S.f"}}, {SourcePath: "main.go", Line: 9, Func: Function{Raw: "main.main"}}, }, }, }, { "pointer method", `package main type S struct { } func (s *S) f() { panic("ooh") } func main() { var s S s.f() }`, Stack{ Calls: []Call{ { SourcePath: "main.go", Line: 5, Func: Function{Raw: "main.(*S).f"}, Args: Args{Values: []Arg{{Value: pointer}}}, }, {SourcePath: "main.go", Line: 9, Func: Function{Raw: "main.main"}}, }, }, }, { "string", `package main func f(s string) { panic(s) } func main() { f("ooh") }`, Stack{ Calls: []Call{ { SourcePath: "main.go", Line: 3, Func: Function{Raw: "main.f"}, Args: Args{Values: []Arg{{Value: pointer}, {Value: 0x3}}}, }, {SourcePath: "main.go", Line: 6, Func: Function{Raw: "main.main"}}, }, }, }, { "string and int", `package main func f(s string, i int) { panic(s) } func main() { f("ooh", 42) }`, Stack{ Calls: []Call{ { SourcePath: "main.go", Line: 3, Func: Function{Raw: "main.f"}, Args: Args{Values: []Arg{{Value: pointer}, {Value: 0x3}, {Value: 42}}}, }, {SourcePath: "main.go", Line: 6, Func: Function{Raw: "main.main"}}, }, }, }, { "values are elided", `package main func f(s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12 int, s13 interface{}) { panic("ooh") } func main() { f(0, 0, 0, 0, 0, 0, 0, 0, 42, 43, 44, 45, nil) }`, Stack{ Calls: []Call{ { SourcePath: "main.go", Line: 3, Func: Function{Raw: "main.f"}, Args: Args{ Values: []Arg{{}, {}, {}, {}, {}, {}, {}, {}, {Value: 42}, {Value: 43}}, Elided: true, }, }, {SourcePath: "main.go", Line: 6, Func: Function{Raw: "main.main"}}, }, }, }, { "error", `package main import "errors" func f(err error) { panic(err.Error()) } func main() { f(errors.New("ooh")) }`, Stack{ Calls: []Call{ { SourcePath: "main.go", Line: 4, Func: Function{Raw: "main.f"}, Args: Args{ Values: []Arg{{Value: pointer}, {Value: pointer}}, }, }, {SourcePath: "main.go", Line: 7, Func: Function{Raw: "main.main"}}, }, }, }, { "error unnamed", `package main import "errors" func f(error) { panic("ooh") } func main() { f(errors.New("ooh")) }`, Stack{ Calls: []Call{ { SourcePath: "main.go", Line: 4, Func: Function{Raw: "main.f"}, Args: Args{ Values: []Arg{{Value: pointer}, {Value: pointer}}, }, }, {SourcePath: "main.go", Line: 7, Func: Function{Raw: "main.main"}}, }, }, }, { "float32", `package main func f(v float32) { panic("ooh") } func main() { f(0.5) }`, Stack{ Calls: []Call{ { SourcePath: "main.go", Line: 3, Func: Function{Raw: "main.f"}, Args: Args{ // The value is NOT a pointer but floating point encoding is not // deterministic. Values: []Arg{{Value: pointer}}, }, }, {SourcePath: "main.go", Line: 6, Func: Function{Raw: "main.main"}}, }, }, }, { "float64", `package main func f(v float64) { panic("ooh") } func main() { f(0.5) }`, Stack{ Calls: []Call{ { SourcePath: "main.go", Line: 3, Func: Function{Raw: "main.f"}, Args: Args{ // The value is NOT a pointer but floating point encoding is not // deterministic. Values: []Arg{{Value: pointer}}, }, }, {SourcePath: "main.go", Line: 6, Func: Function{Raw: "main.main"}}, }, }, }, } for i, line := range data { extra := bytes.Buffer{} _, content := getCrash(t, line.input) goroutines, err := ParseDump(bytes.NewBuffer(content), &extra) if err != nil { t.Fatalf("failed to parse input for test %s: %v", line.name, err) } // On go1.4, there's one less space. actual := extra.String() if actual != "panic: ooh\n\nexit status 2\n" && actual != "panic: ooh\nexit status 2\n" { t.Fatalf("Unexpected panic output:\n%#v", actual) } s := goroutines[0].Signature.Stack t.Logf("Test: %v", line.name) zapPointers(t, line.name, &line.expected, &s) zapPaths(&s) ut.AssertEqualIndex(t, i, line.expected, s) } } func TestAugmentDummy(t *testing.T) { goroutines := []Goroutine{ { Signature: Signature{ Stack: Stack{ Calls: []Call{{SourcePath: "missing.go"}}, }, }, }, } Augment(goroutines) } func TestLoad(t *testing.T) { c := &cache{ files: map[string][]byte{"bad.go": []byte("bad content")}, parsed: map[string]*parsedFile{}, } c.load("foo.asm") c.load("bad.go") c.load("doesnt_exist.go") if l := len(c.parsed); l != 3 { t.Fatalf("expected 3, got %d", l) } if c.parsed["foo.asm"] != nil { t.Fatalf("foo.asm is not present; should not have been loaded") } if c.parsed["bad.go"] != nil { t.Fatalf("bad.go is not valid code; should not have been loaded") } if c.parsed["doesnt_exist.go"] != nil { t.Fatalf("doesnt_exist.go is not present; should not have been loaded") } if c.getFuncAST(&Call{SourcePath: "other"}) != nil { t.Fatalf("there's no 'other'") } } // const pointer = uint64(0xfffffffff) const pointerStr = "0xfffffffff" func overrideEnv(env []string, key, value string) []string { prefix := key + "=" for i, e := range env { if strings.HasPrefix(e, prefix) { env[i] = prefix + value return env } } return append(env, prefix+value) } func getCrash(t *testing.T, content string) (string, []byte) { name, err := ioutil.TempDir("", "panicparse") if err != nil { t.Fatalf("failed to create temporary directory: %v", err) } defer func() { if err := os.RemoveAll(name); err != nil { t.Fatalf("failed to remove temporary directory %q: %v", name, err) } }() main := filepath.Join(name, "main.go") if err := ioutil.WriteFile(main, []byte(content), 0500); err != nil { t.Fatalf("failed to write %q: %v", main, err) } cmd := exec.Command("go", "run", main) // Use the Go 1.4 compatible format. cmd.Env = overrideEnv(os.Environ(), "GOTRACEBACK", "1") out, err := cmd.CombinedOutput() if err == nil { t.Fatal("expected error since this is supposed to crash") } return main, out } // zapPointers zaps out pointers. func zapPointers(t *testing.T, name string, expected, s *Stack) { for i := range s.Calls { if i >= len(expected.Calls) { // When using GOTRACEBACK=2, it'll include runtime.main() and // runtime.goexit(). Ignore these since they could be changed in a future // version. s.Calls = s.Calls[:len(expected.Calls)] break } for j := range s.Calls[i].Args.Values { if j >= len(expected.Calls[i].Args.Values) { break } if expected.Calls[i].Args.Values[j].Value == pointer { // Replace the pointer value. if s.Calls[i].Args.Values[j].Value == 0 { t.Fatalf("%s: Call %d, value %d, expected pointer, got 0", name, i, j) } old := fmt.Sprintf("0x%x", s.Calls[i].Args.Values[j].Value) s.Calls[i].Args.Values[j].Value = pointer for k := range s.Calls[i].Args.Processed { s.Calls[i].Args.Processed[k] = strings.Replace(s.Calls[i].Args.Processed[k], old, pointerStr, -1) } } } } } // zapPaths removes the directory part and only keep the base file name. func zapPaths(s *Stack) { for j := range s.Calls { s.Calls[j].SourcePath = filepath.Base(s.Calls[j].SourcePath) } } ================================================ FILE: vendor/github.com/maruel/panicparse/stack/stack.go ================================================ // Copyright 2015 Marc-Antoine Ruel. All rights reserved. // Use of this source code is governed under the Apache License, Version 2.0 // that can be found in the LICENSE file. // Package stack analyzes stack dump of Go processes and simplifies it. // // It is mostly useful on servers will large number of identical goroutines, // making the crash dump harder to read than strictly necesary. package stack import ( "bufio" "bytes" "errors" "fmt" "io" "math" "net/url" "os" "path/filepath" "regexp" "runtime" "sort" "strconv" "strings" "unicode" "unicode/utf8" ) const lockedToThread = "locked to thread" var ( // TODO(maruel): Handle corrupted stack cases: // - missed stack barrier // - found next stack barrier at 0x123; expected // - runtime: unexpected return pc for FUNC_NAME called from 0x123 reRoutineHeader = regexp.MustCompile("^goroutine (\\d+) \\[([^\\]]+)\\]\\:\r?\n$") reMinutes = regexp.MustCompile("^(\\d+) minutes$") reUnavail = regexp.MustCompile("^(?:\t| +)goroutine running on other thread; stack unavailable") // See gentraceback() in src/runtime/traceback.go for more information. // - Sometimes the source file comes up as "". It is the // compiler than generated these, not the runtime. // - The tab may be replaced with spaces when a user copy-paste it, handle // this transparently. // - "runtime.gopanic" is explicitly replaced with "panic" by gentraceback(). // - The +0x123 byte offset is printed when frame.pc > _func.entry. _func is // generated by the linker. // - The +0x123 byte offset is not included with generated code, e.g. unnamed // functions "func·006()" which is generally go func() { ... }() // statements. Since the _func is generated at runtime, it's probably why // _func.entry is not set. // - C calls may have fp=0x123 sp=0x123 appended. I think it normally happens // when a signal is not correctly handled. It is printed with m.throwing>0. // These are discarded. // - For cgo, the source file may be "??". reFile = regexp.MustCompile("^(?:\t| +)(\\?\\?|\\|.+\\.(?:c|go|s))\\:(\\d+)(?:| \\+0x[0-9a-f]+)(?:| fp=0x[0-9a-f]+ sp=0x[0-9a-f]+)\r?\n$") // Sadly, it doesn't note the goroutine number so we could cascade them per // parenthood. reCreated = regexp.MustCompile("^created by (.+)\r?\n$") reFunc = regexp.MustCompile("^(.+)\\((.*)\\)\r?\n$") reElided = regexp.MustCompile("^\\.\\.\\.additional frames elided\\.\\.\\.\r?\n$") // Include frequent GOROOT value on Windows, distro provided and user // installed path. This simplifies the user's life when processing a trace // generated on another VM. // TODO(maruel): Guess the path automatically via traces containing the // 'runtime' package, which is very frequent. This would be "less bad" than // throwing up random values at the parser. goroots = []string{runtime.GOROOT(), "c:/go", "/usr/lib/go", "/usr/local/go"} ) // Similarity is the level at which two call lines arguments must match to be // considered similar enough to coalesce them. type Similarity int const ( // ExactFlags requires same bits (e.g. Locked). ExactFlags Similarity = iota // ExactLines requests the exact same arguments on the call line. ExactLines // AnyPointer considers different pointers a similar call line. AnyPointer // AnyValue accepts any value as similar call line. AnyValue ) // Function is a function call. // // Go stack traces print a mangled function call, this wrapper unmangle the // string before printing and adds other filtering methods. type Function struct { Raw string } // String is the fully qualified function name. // // Sadly Go is a bit confused when the package name doesn't match the directory // containing the source file and will use the directory name instead of the // real package name. func (f Function) String() string { s, _ := url.QueryUnescape(f.Raw) return s } // Name is the naked function name. func (f Function) Name() string { parts := strings.SplitN(filepath.Base(f.Raw), ".", 2) if len(parts) == 1 { return parts[0] } return parts[1] } // PkgName is the package name for this function reference. func (f Function) PkgName() string { parts := strings.SplitN(filepath.Base(f.Raw), ".", 2) if len(parts) == 1 { return "" } s, _ := url.QueryUnescape(parts[0]) return s } // PkgDotName returns "." format. func (f Function) PkgDotName() string { parts := strings.SplitN(filepath.Base(f.Raw), ".", 2) s, _ := url.QueryUnescape(parts[0]) if len(parts) == 1 { return parts[0] } if s != "" || parts[1] != "" { return s + "." + parts[1] } return "" } // IsExported returns true if the function is exported. func (f Function) IsExported() bool { name := f.Name() parts := strings.Split(name, ".") r, _ := utf8.DecodeRuneInString(parts[len(parts)-1]) if unicode.ToUpper(r) == r { return true } return f.PkgName() == "main" && name == "main" } // Arg is an argument on a Call. type Arg struct { Value uint64 // Value is the raw value as found in the stack trace Name string // Name is a pseudo name given to the argument } // IsPtr returns true if we guess it's a pointer. It's only a guess, it can be // easily be confused by a bitmask. func (a *Arg) IsPtr() bool { // Assumes all pointers are above 16Mb and positive. return a.Value > 16*1024*1024 && a.Value < math.MaxInt64 } func (a Arg) String() string { if a.Name != "" { return a.Name } if a.Value == 0 { return "0" } return fmt.Sprintf("0x%x", a.Value) } // Args is a series of function call arguments. type Args struct { Values []Arg // Values is the arguments as shown on the stack trace. They are mangled via simplification. Processed []string // Processed is the arguments generated from processing the source files. It can have a length lower than Values. Elided bool // If set, it means there was a trailing ", ..." } func (a Args) String() string { var v []string if len(a.Processed) != 0 { v = make([]string, 0, len(a.Processed)) for _, item := range a.Processed { v = append(v, item) } } else { v = make([]string, 0, len(a.Values)) for _, item := range a.Values { v = append(v, item.String()) } } if a.Elided { v = append(v, "...") } return strings.Join(v, ", ") } // Equal returns true only if both arguments are exactly equal. func (a *Args) Equal(r *Args) bool { if a.Elided != r.Elided || len(a.Values) != len(r.Values) { return false } for i, l := range a.Values { if l != r.Values[i] { return false } } return true } // Similar returns true if the two Args are equal or almost but not quite // equal. func (a *Args) Similar(r *Args, similar Similarity) bool { if a.Elided != r.Elided || len(a.Values) != len(r.Values) { return false } if similar == AnyValue { return true } for i, l := range a.Values { switch similar { case ExactFlags, ExactLines: if l != r.Values[i] { return false } default: if l.IsPtr() != r.Values[i].IsPtr() || (!l.IsPtr() && l != r.Values[i]) { return false } } } return true } // Merge merges two similar Args, zapping out differences. func (a *Args) Merge(r *Args) Args { out := Args{ Values: make([]Arg, len(a.Values)), Elided: a.Elided, } for i, l := range a.Values { if l != r.Values[i] { out.Values[i].Name = "*" out.Values[i].Value = l.Value } else { out.Values[i] = l } } return out } // Call is an item in the stack trace. type Call struct { SourcePath string // Full path name of the source file Line int // Line number Func Function // Fully qualified function name (encoded). Args Args // Call arguments } // Equal returns true only if both calls are exactly equal. func (c *Call) Equal(r *Call) bool { return c.SourcePath == r.SourcePath && c.Line == r.Line && c.Func == r.Func && c.Args.Equal(&r.Args) } // Similar returns true if the two Call are equal or almost but not quite // equal. func (c *Call) Similar(r *Call, similar Similarity) bool { return c.SourcePath == r.SourcePath && c.Line == r.Line && c.Func == r.Func && c.Args.Similar(&r.Args, similar) } // Merge merges two similar Call, zapping out differences. func (c *Call) Merge(r *Call) Call { return Call{ SourcePath: c.SourcePath, Line: c.Line, Func: c.Func, Args: c.Args.Merge(&r.Args), } } // SourceName returns the base file name of the source file. func (c *Call) SourceName() string { return filepath.Base(c.SourcePath) } // SourceLine returns "source.go:line", including only the base file name. func (c *Call) SourceLine() string { return fmt.Sprintf("%s:%d", c.SourceName(), c.Line) } // FullSourceLine returns "/path/to/source.go:line". func (c *Call) FullSourceLine() string { return fmt.Sprintf("%s:%d", c.SourcePath, c.Line) } // PkgSource is one directory plus the file name of the source file. func (c *Call) PkgSource() string { return filepath.Join(filepath.Base(filepath.Dir(c.SourcePath)), c.SourceName()) } const testMainSource = "_test" + string(os.PathSeparator) + "_testmain.go" // IsStdlib returns true if it is a Go standard library function. This includes // the 'go test' generated main executable. func (c *Call) IsStdlib() bool { for _, goroot := range goroots { if strings.HasPrefix(c.SourcePath, goroot) { return true } } // Consider _test/_testmain.go as stdlib since it's injected by "go test". return c.PkgSource() == testMainSource } // IsPkgMain returns true if it is in the main package. func (c *Call) IsPkgMain() bool { return c.Func.PkgName() == "main" } // Stack is a call stack. type Stack struct { Calls []Call // Call stack. First is original function, last is leaf function. Elided bool // Happens when there's >100 items in Stack, currently hardcoded in package runtime. } // Equal returns true on if both call stacks are exactly equal. func (s *Stack) Equal(r *Stack) bool { if len(s.Calls) != len(r.Calls) || s.Elided != r.Elided { return false } for i := range s.Calls { if !s.Calls[i].Equal(&r.Calls[i]) { return false } } return true } // Similar returns true if the two Stack are equal or almost but not quite // equal. func (s *Stack) Similar(r *Stack, similar Similarity) bool { if len(s.Calls) != len(r.Calls) || s.Elided != r.Elided { return false } for i := range s.Calls { if !s.Calls[i].Similar(&r.Calls[i], similar) { return false } } return true } // Merge merges two similar Stack, zapping out differences. func (s *Stack) Merge(r *Stack) *Stack { // Assumes similar stacks have the same length. out := &Stack{ Calls: make([]Call, len(s.Calls)), Elided: s.Elided, } for i := range s.Calls { out.Calls[i] = s.Calls[i].Merge(&r.Calls[i]) } return out } // Less compares two Stack, where the ones that are less are more // important, so they come up front. A Stack with more private functions is // 'less' so it is at the top. Inversely, a Stack with only public // functions is 'more' so it is at the bottom. func (s *Stack) Less(r *Stack) bool { lStdlib := 0 lPrivate := 0 for _, c := range s.Calls { if c.IsStdlib() { lStdlib++ } else { lPrivate++ } } rStdlib := 0 rPrivate := 0 for _, s := range r.Calls { if s.IsStdlib() { rStdlib++ } else { rPrivate++ } } if lPrivate > rPrivate { return true } if lPrivate < rPrivate { return false } if lStdlib > rStdlib { return false } if lStdlib < rStdlib { return true } // Stack lengths are the same. for x := range s.Calls { if s.Calls[x].Func.Raw < r.Calls[x].Func.Raw { return true } if s.Calls[x].Func.Raw > r.Calls[x].Func.Raw { return true } if s.Calls[x].PkgSource() < r.Calls[x].PkgSource() { return true } if s.Calls[x].PkgSource() > r.Calls[x].PkgSource() { return true } if s.Calls[x].Line < r.Calls[x].Line { return true } if s.Calls[x].Line > r.Calls[x].Line { return true } } return false } // Signature represents the signature of one or multiple goroutines. // // It is effectively the stack trace plus the goroutine internal bits, like // it's state, if it is thread locked, which call site created this goroutine, // etc. type Signature struct { // Use git grep 'gopark(|unlock)\(' to find them all plus everything listed // in runtime/traceback.go. Valid values includes: // - chan send, chan receive, select // - finalizer wait, mark wait (idle), // - Concurrent GC wait, GC sweep wait, force gc (idle) // - IO wait, panicwait // - semacquire, semarelease // - sleep, timer goroutine (idle) // - trace reader (blocked) // Stuck cases: // - chan send (nil chan), chan receive (nil chan), select (no cases) // Runnable states: // - idle, runnable, running, syscall, waiting, dead, enqueue, copystack, // Scan states: // - scan, scanrunnable, scanrunning, scansyscall, scanwaiting, scandead, // scanenqueue State string CreatedBy Call // Which other goroutine which created this one. SleepMin int // Wait time in minutes, if applicable. SleepMax int // Wait time in minutes, if applicable. Stack Stack Locked bool // Locked to an OS thread. } // Equal returns true only if both signatures are exactly equal. func (s *Signature) Equal(r *Signature) bool { if s.State != r.State || !s.CreatedBy.Equal(&r.CreatedBy) || s.Locked != r.Locked || s.SleepMin != r.SleepMin || s.SleepMax != r.SleepMax { return false } return s.Stack.Equal(&r.Stack) } // Similar returns true if the two Signature are equal or almost but not quite // equal. func (s *Signature) Similar(r *Signature, similar Similarity) bool { if s.State != r.State || !s.CreatedBy.Similar(&r.CreatedBy, similar) { return false } if similar == ExactFlags && s.Locked != r.Locked { return false } return s.Stack.Similar(&r.Stack, similar) } // Merge merges two similar Signature, zapping out differences. func (s *Signature) Merge(r *Signature) *Signature { min := s.SleepMin if r.SleepMin < min { min = r.SleepMin } max := s.SleepMax if r.SleepMax > max { max = r.SleepMax } return &Signature{ State: s.State, // Drop right side. CreatedBy: s.CreatedBy, // Drop right side. SleepMin: min, SleepMax: max, Stack: *s.Stack.Merge(&r.Stack), Locked: s.Locked || r.Locked, // TODO(maruel): This is weirdo. } } // Less compares two Signature, where the ones that are less are more // important, so they come up front. A Signature with more private functions is // 'less' so it is at the top. Inversely, a Signature with only public // functions is 'more' so it is at the bottom. func (s *Signature) Less(r *Signature) bool { if s.Stack.Less(&r.Stack) { return true } if r.Stack.Less(&s.Stack) { return false } if s.Locked && !r.Locked { return true } if r.Locked && !s.Locked { return false } if s.State < r.State { return true } if s.State > r.State { return false } return false } // Goroutine represents the state of one goroutine, including the stack trace. type Goroutine struct { Signature // It's stack trace, internal bits, state, which call site created it, etc. ID int // Goroutine ID. First bool // First is the goroutine first printed, normally the one that crashed. } // Bucketize returns the number of similar goroutines. func Bucketize(goroutines []Goroutine, similar Similarity) map[*Signature][]Goroutine { out := map[*Signature][]Goroutine{} // O(n²). Fix eventually. for _, routine := range goroutines { found := false for key := range out { // When a match is found, this effectively drops the other goroutine ID. if key.Similar(&routine.Signature, similar) { found = true if !key.Equal(&routine.Signature) { // Almost but not quite equal. There's different pointers passed // around but the same values. Zap out the different values. newKey := key.Merge(&routine.Signature) out[newKey] = append(out[key], routine) delete(out, key) } else { out[key] = append(out[key], routine) } break } } if !found { key := &Signature{} *key = routine.Signature out[key] = []Goroutine{routine} } } return out } // Bucket is a stack trace signature and the list of goroutines that fits this // signature. type Bucket struct { Signature Routines []Goroutine } // First returns true if it contains the first goroutine, e.g. the ones that // likely generated the panic() call, if any. func (b *Bucket) First() bool { for _, r := range b.Routines { if r.First { return true } } return false } // Less does reverse sort. func (b *Bucket) Less(r *Bucket) bool { if b.First() { return true } if r.First() { return false } return b.Signature.Less(&r.Signature) } // Buckets is a list of Bucket sorted by repeation count. type Buckets []Bucket func (b Buckets) Len() int { return len(b) } func (b Buckets) Less(i, j int) bool { return b[i].Less(&b[j]) } func (b Buckets) Swap(i, j int) { b[j], b[i] = b[i], b[j] } // SortBuckets creates a list of Bucket from each goroutine stack trace count. func SortBuckets(buckets map[*Signature][]Goroutine) Buckets { out := make(Buckets, 0, len(buckets)) for signature, count := range buckets { out = append(out, Bucket{*signature, count}) } sort.Sort(out) return out } // scanLines is similar to bufio.ScanLines except that it: // - doesn't drop '\n' // - doesn't strip '\r' // - returns when the data is bufio.MaxScanTokenSize bytes func scanLines(data []byte, atEOF bool) (advance int, token []byte, err error) { if atEOF && len(data) == 0 { return 0, nil, nil } if i := bytes.IndexByte(data, '\n'); i >= 0 { return i + 1, data[0 : i+1], nil } if atEOF { return len(data), data, nil } if len(data) >= bufio.MaxScanTokenSize { // Returns the line even if it is not at EOF nor has a '\n', otherwise the // scanner will return bufio.ErrTooLong which is definitely not what we // want. return len(data), data, nil } return 0, nil, nil } // ParseDump processes the output from runtime.Stack(). // // It supports piping from another command and assumes there is junk before the // actual stack trace. The junk is streamed to out. func ParseDump(r io.Reader, out io.Writer) ([]Goroutine, error) { goroutines := make([]Goroutine, 0, 16) var goroutine *Goroutine scanner := bufio.NewScanner(r) scanner.Split(scanLines) // TODO(maruel): Use a formal state machine. Patterns follows: // - reRoutineHeader // Either: // - reUnavail // - reFunc + reFile in a loop // - reElided // Optionally ends with: // - reCreated + reFile // Between each goroutine stack dump: an empty line created := false // firstLine is the first line after the reRoutineHeader header line. firstLine := false for scanner.Scan() { line := scanner.Text() if line == "\n" || line == "\r\n" { if goroutine != nil { goroutine = nil continue } } else if line[len(line)-1] == '\n' { if goroutine == nil { if match := reRoutineHeader.FindStringSubmatch(line); match != nil { if id, err := strconv.Atoi(match[1]); err == nil { // See runtime/traceback.go. // ", \d+ minutes, locked to thread" items := strings.Split(match[2], ", ") sleep := 0 locked := false for i := 1; i < len(items); i++ { if items[i] == lockedToThread { locked = true continue } // Look for duration, if any. if match2 := reMinutes.FindStringSubmatch(items[i]); match2 != nil { sleep, _ = strconv.Atoi(match2[1]) } } goroutines = append(goroutines, Goroutine{ Signature: Signature{ State: items[0], SleepMin: sleep, SleepMax: sleep, Locked: locked, }, ID: id, First: len(goroutines) == 0, }) goroutine = &goroutines[len(goroutines)-1] firstLine = true continue } } } else { if firstLine { firstLine = false if match := reUnavail.FindStringSubmatch(line); match != nil { // Generate a fake stack entry. goroutine.Stack.Calls = []Call{{SourcePath: ""}} continue } } if match := reFile.FindStringSubmatch(line); match != nil { // Triggers after a reFunc or a reCreated. num, err := strconv.Atoi(match[2]) if err != nil { return goroutines, fmt.Errorf("failed to parse int on line: \"%s\"", line) } if created { created = false goroutine.CreatedBy.SourcePath = match[1] goroutine.CreatedBy.Line = num } else { i := len(goroutine.Stack.Calls) - 1 if i < 0 { return goroutines, errors.New("unexpected order") } goroutine.Stack.Calls[i].SourcePath = match[1] goroutine.Stack.Calls[i].Line = num } continue } if match := reCreated.FindStringSubmatch(line); match != nil { created = true goroutine.CreatedBy.Func.Raw = match[1] continue } if match := reFunc.FindStringSubmatch(line); match != nil { args := Args{} for _, a := range strings.Split(match[2], ", ") { if a == "..." { args.Elided = true continue } if a == "" { // Remaining values were dropped. break } v, err := strconv.ParseUint(a, 0, 64) if err != nil { return goroutines, fmt.Errorf("failed to parse int on line: \"%s\"", line) } args.Values = append(args.Values, Arg{Value: v}) } goroutine.Stack.Calls = append(goroutine.Stack.Calls, Call{Func: Function{match[1]}, Args: args}) continue } if match := reElided.FindStringSubmatch(line); match != nil { goroutine.Stack.Elided = true continue } } } _, _ = io.WriteString(out, line) goroutine = nil } nameArguments(goroutines) return goroutines, scanner.Err() } // Private stuff. func nameArguments(goroutines []Goroutine) { // Set a name for any pointer occuring more than once. type object struct { args []*Arg inPrimary bool id int } objects := map[uint64]object{} // Enumerate all the arguments. for i := range goroutines { for j := range goroutines[i].Stack.Calls { for k := range goroutines[i].Stack.Calls[j].Args.Values { arg := goroutines[i].Stack.Calls[j].Args.Values[k] if arg.IsPtr() { objects[arg.Value] = object{ args: append(objects[arg.Value].args, &goroutines[i].Stack.Calls[j].Args.Values[k]), inPrimary: objects[arg.Value].inPrimary || i == 0, } } } } // CreatedBy.Args is never set. } order := uint64Slice{} for k, obj := range objects { if len(obj.args) > 1 && obj.inPrimary { order = append(order, k) } } sort.Sort(order) nextID := 1 for _, k := range order { for _, arg := range objects[k].args { arg.Name = fmt.Sprintf("#%d", nextID) } nextID++ } // Now do the rest. This is done so the output is deterministic. order = uint64Slice{} for k := range objects { order = append(order, k) } sort.Sort(order) for _, k := range order { // Process the remaining pointers, they were not referenced by primary // thread so will have higher IDs. if objects[k].inPrimary { continue } for _, arg := range objects[k].args { arg.Name = fmt.Sprintf("#%d", nextID) } nextID++ } } type uint64Slice []uint64 func (a uint64Slice) Len() int { return len(a) } func (a uint64Slice) Swap(i, j int) { a[i], a[j] = a[j], a[i] } func (a uint64Slice) Less(i, j int) bool { return a[i] < a[j] } ================================================ FILE: vendor/github.com/maruel/panicparse/stack/stack_test.go ================================================ // Copyright 2015 Marc-Antoine Ruel. All rights reserved. // Use of this source code is governed under the Apache License, Version 2.0 // that can be found in the LICENSE file. package stack import ( "bufio" "bytes" "errors" "io" "io/ioutil" "os" "path/filepath" "strings" "testing" "github.com/maruel/ut" ) var goroot = goroots[0] const crash = `panic: oh no! goroutine 1 [running]: panic(0x0, 0x0) /home/user/src/golang/src/runtime/panic.go:464 +0x3e6 main.crash2(0x7fe50b49d028, 0xc82000a1e0) /home/user/src/foo.go:45 +0x23 main.main() /home/user/src/foo.go:50 +0xa6 ` func Example() { in := bytes.NewBufferString(crash) goroutines, err := ParseDump(in, os.Stdout) if err != nil { return } // Optional: Check for GOTRACEBACK being set, in particular if there is only // one goroutine returned. // Use a color palette based on ANSI code. p := &Palette{} buckets := SortBuckets(Bucketize(goroutines, AnyValue)) srcLen, pkgLen := CalcLengths(buckets, false) for _, bucket := range buckets { io.WriteString(os.Stdout, p.BucketHeader(&bucket, false, len(buckets) > 1)) io.WriteString(os.Stdout, p.StackLines(&bucket.Signature, srcLen, pkgLen, false)) } // Output: // panic: oh no! // // 1: running // panic.go:464 panic(0, 0) // main foo.go:45 crash2(0x7fe50b49d028, 0xc82000a1e0) // main foo.go:50 main() } func TestParseDump1(t *testing.T) { // One call from main, one from stdlib, one from third party. // Create a long first line that will be ignored. It is to guard against // https://github.com/maruel/panicparse/issues/17. long := strings.Repeat("a", bufio.MaxScanTokenSize+1) data := []string{ long, "panic: reflect.Set: value of type", "", "goroutine 1 [running]:", "github.com/cockroachdb/cockroach/storage/engine._Cfunc_DBIterSeek()", " ??:0 +0x6d", "gopkg.in/yaml%2ev2.handleErr(0xc208033b20)", " /gopath/src/gopkg.in/yaml.v2/yaml.go:153 +0xc6", "reflect.Value.assignTo(0x570860, 0xc20803f3e0, 0x15)", " " + goroot + "/src/reflect/value.go:2125 +0x368", "main.main()", " /gopath/src/github.com/foo/bar/baz.go:428 +0x27", "", } extra := &bytes.Buffer{} goroutines, err := ParseDump(bytes.NewBufferString(strings.Join(data, "\n")), extra) ut.AssertEqual(t, nil, err) ut.AssertEqual(t, long+"\npanic: reflect.Set: value of type\n\n", extra.String()) expected := []Goroutine{ { Signature: Signature{ State: "running", Stack: Stack{ Calls: []Call{ { SourcePath: "??", Func: Function{"github.com/cockroachdb/cockroach/storage/engine._Cfunc_DBIterSeek"}, }, { SourcePath: "/gopath/src/gopkg.in/yaml.v2/yaml.go", Line: 153, Func: Function{"gopkg.in/yaml%2ev2.handleErr"}, Args: Args{Values: []Arg{{Value: 0xc208033b20}}}, }, { SourcePath: goroot + "/src/reflect/value.go", Line: 2125, Func: Function{"reflect.Value.assignTo"}, Args: Args{Values: []Arg{{Value: 0x570860}, {Value: 0xc20803f3e0}, {Value: 0x15}}}, }, { SourcePath: "/gopath/src/github.com/foo/bar/baz.go", Line: 428, Func: Function{"main.main"}, }, }, }, }, ID: 1, First: true, }, } ut.AssertEqual(t, expected, goroutines) } func TestParseDumpLongWait(t *testing.T) { // One call from main, one from stdlib, one from third party. data := []string{ "panic: bleh", "", "goroutine 1 [chan send, 100 minutes]:", "gopkg.in/yaml%2ev2.handleErr(0xc208033b20)", " /gopath/src/gopkg.in/yaml.v2/yaml.go:153 +0xc6", "", "goroutine 2 [chan send, locked to thread]:", "gopkg.in/yaml%2ev2.handleErr(0xc208033b21)", " /gopath/src/gopkg.in/yaml.v2/yaml.go:153 +0xc6", "", "goroutine 3 [chan send, 101 minutes, locked to thread]:", "gopkg.in/yaml%2ev2.handleErr(0xc208033b22)", " /gopath/src/gopkg.in/yaml.v2/yaml.go:153 +0xc6", "", } extra := &bytes.Buffer{} goroutines, err := ParseDump(bytes.NewBufferString(strings.Join(data, "\n")), extra) ut.AssertEqual(t, nil, err) ut.AssertEqual(t, "panic: bleh\n\n", extra.String()) expected := []Goroutine{ { Signature: Signature{ State: "chan send", SleepMin: 100, SleepMax: 100, Stack: Stack{ Calls: []Call{ { SourcePath: "/gopath/src/gopkg.in/yaml.v2/yaml.go", Line: 153, Func: Function{"gopkg.in/yaml%2ev2.handleErr"}, Args: Args{Values: []Arg{{Value: 0xc208033b20}}}, }, }, }, }, ID: 1, First: true, }, { Signature: Signature{ State: "chan send", Locked: true, Stack: Stack{ Calls: []Call{ { SourcePath: "/gopath/src/gopkg.in/yaml.v2/yaml.go", Line: 153, Func: Function{"gopkg.in/yaml%2ev2.handleErr"}, Args: Args{Values: []Arg{{Value: 0xc208033b21, Name: "#1"}}}, }, }, }, }, ID: 2, }, { Signature: Signature{ State: "chan send", SleepMin: 101, SleepMax: 101, Stack: Stack{ Calls: []Call{ { SourcePath: "/gopath/src/gopkg.in/yaml.v2/yaml.go", Line: 153, Func: Function{"gopkg.in/yaml%2ev2.handleErr"}, Args: Args{Values: []Arg{{Value: 0xc208033b22, Name: "#2"}}}, }, }, }, Locked: true, }, ID: 3, }, } ut.AssertEqual(t, expected, goroutines) } func TestParseDumpAsm(t *testing.T) { data := []string{ "panic: reflect.Set: value of type", "", "goroutine 16 [garbage collection]:", "runtime.switchtoM()", "\t" + goroot + "/src/runtime/asm_amd64.s:198 fp=0xc20cfb80d8 sp=0xc20cfb80d0", "", } extra := &bytes.Buffer{} goroutines, err := ParseDump(bytes.NewBufferString(strings.Join(data, "\n")), extra) ut.AssertEqual(t, nil, err) expected := []Goroutine{ { Signature: Signature{ State: "garbage collection", Stack: Stack{ Calls: []Call{ { SourcePath: goroot + "/src/runtime/asm_amd64.s", Line: 198, Func: Function{Raw: "runtime.switchtoM"}, }, }, }, }, ID: 16, First: true, }, } ut.AssertEqual(t, expected, goroutines) ut.AssertEqual(t, "panic: reflect.Set: value of type\n\n", extra.String()) } func TestParseDumpLineErr(t *testing.T) { data := []string{ "panic: reflect.Set: value of type", "", "goroutine 1 [running]:", "github.com/foo/bar.recurseType()", "\t/gopath/src/github.com/foo/bar/baz.go:12345678901234567890", "", } extra := &bytes.Buffer{} goroutines, err := ParseDump(bytes.NewBufferString(strings.Join(data, "\n")), extra) ut.AssertEqual(t, errors.New("failed to parse int on line: \"\t/gopath/src/github.com/foo/bar/baz.go:12345678901234567890\n\""), err) expected := []Goroutine{ { Signature: Signature{ State: "running", Stack: Stack{Calls: []Call{{Func: Function{Raw: "github.com/foo/bar.recurseType"}}}}, }, ID: 1, First: true, }, } ut.AssertEqual(t, expected, goroutines) } func TestParseDumpValueErr(t *testing.T) { data := []string{ "panic: reflect.Set: value of type", "", "goroutine 1 [running]:", "github.com/foo/bar.recurseType(123456789012345678901)", "\t/gopath/src/github.com/foo/bar/baz.go:9", "", } extra := &bytes.Buffer{} goroutines, err := ParseDump(bytes.NewBufferString(strings.Join(data, "\n")), extra) ut.AssertEqual(t, errors.New("failed to parse int on line: \"github.com/foo/bar.recurseType(123456789012345678901)\n\""), err) expected := []Goroutine{ { Signature: Signature{State: "running"}, ID: 1, First: true, }, } ut.AssertEqual(t, expected, goroutines) } func TestParseDumpOrderErr(t *testing.T) { data := []string{ "panic: reflect.Set: value of type", "", "goroutine 16 [garbage collection]:", " /gopath/src/gopkg.in/yaml.v2/yaml.go:153 +0xc6", "runtime.switchtoM()", "\t" + goroot + "/src/runtime/asm_amd64.s:198 fp=0xc20cfb80d8 sp=0xc20cfb80d0", "", } extra := &bytes.Buffer{} goroutines, err := ParseDump(bytes.NewBufferString(strings.Join(data, "\n")), extra) ut.AssertEqual(t, errors.New("unexpected order"), err) expected := []Goroutine{ { Signature: Signature{State: "garbage collection"}, ID: 16, First: true, }, } ut.AssertEqual(t, expected, goroutines) ut.AssertEqual(t, "panic: reflect.Set: value of type\n\n", extra.String()) } func TestParseDumpElided(t *testing.T) { data := []string{ "panic: reflect.Set: value of type", "", "goroutine 16 [garbage collection]:", "github.com/foo/bar.recurseType(0x7f4fa9a3ec70, 0xc208062580, 0x7f4fa9a3e818, 0x50a820, 0xc20803a8a0)", "\t/gopath/src/github.com/foo/bar/baz.go:53 +0x845 fp=0xc20cfc66d8 sp=0xc20cfc6470", "...additional frames elided...", "created by testing.RunTests", "\t" + goroot + "/src/testing/testing.go:555 +0xa8b", "", } extra := &bytes.Buffer{} goroutines, err := ParseDump(bytes.NewBufferString(strings.Join(data, "\n")), extra) ut.AssertEqual(t, nil, err) expected := []Goroutine{ { Signature: Signature{ State: "garbage collection", Stack: Stack{ Calls: []Call{ { SourcePath: "/gopath/src/github.com/foo/bar/baz.go", Line: 53, Func: Function{Raw: "github.com/foo/bar.recurseType"}, Args: Args{ Values: []Arg{ {Value: 0x7f4fa9a3ec70}, {Value: 0xc208062580}, {Value: 0x7f4fa9a3e818}, {Value: 0x50a820}, {Value: 0xc20803a8a0}, }, }, }, }, Elided: true, }, CreatedBy: Call{ SourcePath: goroot + "/src/testing/testing.go", Line: 555, Func: Function{Raw: "testing.RunTests"}, }, }, ID: 16, First: true, }, } ut.AssertEqual(t, expected, goroutines) ut.AssertEqual(t, "panic: reflect.Set: value of type\n\n", extra.String()) } func TestParseDumpSysCall(t *testing.T) { data := []string{ "panic: reflect.Set: value of type", "", "goroutine 5 [syscall]:", "runtime.notetsleepg(0x918100, 0xffffffffffffffff, 0x1)", "\t" + goroot + "/src/runtime/lock_futex.go:201 +0x52 fp=0xc208018f68 sp=0xc208018f40", "runtime.signal_recv(0x0)", "\t" + goroot + "/src/runtime/sigqueue.go:109 +0x135 fp=0xc208018fa0 sp=0xc208018f68", "os/signal.loop()", "\t" + goroot + "/src/os/signal/signal_unix.go:21 +0x1f fp=0xc208018fe0 sp=0xc208018fa0", "runtime.goexit()", "\t" + goroot + "/src/runtime/asm_amd64.s:2232 +0x1 fp=0xc208018fe8 sp=0xc208018fe0", "created by os/signal.init·1", "\t" + goroot + "/src/os/signal/signal_unix.go:27 +0x35", "", } extra := &bytes.Buffer{} goroutines, err := ParseDump(bytes.NewBufferString(strings.Join(data, "\n")), extra) ut.AssertEqual(t, nil, err) expected := []Goroutine{ { Signature: Signature{ State: "syscall", Stack: Stack{ Calls: []Call{ { SourcePath: goroot + "/src/runtime/lock_futex.go", Line: 201, Func: Function{Raw: "runtime.notetsleepg"}, Args: Args{ Values: []Arg{ {Value: 0x918100}, {Value: 0xffffffffffffffff}, {Value: 0x1}, }, }, }, { SourcePath: goroot + "/src/runtime/sigqueue.go", Line: 109, Func: Function{Raw: "runtime.signal_recv"}, Args: Args{ Values: []Arg{{}}, }, }, { SourcePath: goroot + "/src/os/signal/signal_unix.go", Line: 21, Func: Function{Raw: "os/signal.loop"}, }, { SourcePath: goroot + "/src/runtime/asm_amd64.s", Line: 2232, Func: Function{Raw: "runtime.goexit"}, }, }, }, CreatedBy: Call{ SourcePath: goroot + "/src/os/signal/signal_unix.go", Line: 27, Func: Function{Raw: "os/signal.init·1"}, }, }, ID: 5, First: true, }, } ut.AssertEqual(t, expected, goroutines) ut.AssertEqual(t, "panic: reflect.Set: value of type\n\n", extra.String()) } func TestParseDumpUnavail(t *testing.T) { data := []string{ "panic: reflect.Set: value of type", "", "goroutine 24 [running]:", "\tgoroutine running on other thread; stack unavailable", "created by github.com/foo.New", "\t/gopath/src/github.com/foo/bar.go:131 +0x381", "", } extra := &bytes.Buffer{} goroutines, err := ParseDump(bytes.NewBufferString(strings.Join(data, "\n")), extra) ut.AssertEqual(t, nil, err) expected := []Goroutine{ { Signature: Signature{ State: "running", Stack: Stack{ Calls: []Call{{SourcePath: ""}}, }, CreatedBy: Call{ SourcePath: "/gopath/src/github.com/foo/bar.go", Line: 131, Func: Function{Raw: "github.com/foo.New"}, }, }, ID: 24, First: true, }, } ut.AssertEqual(t, expected, goroutines) ut.AssertEqual(t, "panic: reflect.Set: value of type\n\n", extra.String()) } func TestParseDumpSameBucket(t *testing.T) { // 2 goroutines with the same signature data := []string{ "panic: runtime error: index out of range", "", "goroutine 6 [chan receive]:", "main.func·001()", " /gopath/src/github.com/foo/bar/baz.go:72 +0x49", "created by main.mainImpl", " /gopath/src/github.com/foo/bar/baz.go:74 +0xeb", "", "goroutine 7 [chan receive]:", "main.func·001()", " /gopath/src/github.com/foo/bar/baz.go:72 +0x49", "created by main.mainImpl", " /gopath/src/github.com/foo/bar/baz.go:74 +0xeb", "", } goroutines, err := ParseDump(bytes.NewBufferString(strings.Join(data, "\n")), &bytes.Buffer{}) ut.AssertEqual(t, nil, err) expectedGR := []Goroutine{ { Signature: Signature{ State: "chan receive", Stack: Stack{ Calls: []Call{ { SourcePath: "/gopath/src/github.com/foo/bar/baz.go", Line: 72, Func: Function{"main.func·001"}, }, }, }, CreatedBy: Call{ SourcePath: "/gopath/src/github.com/foo/bar/baz.go", Line: 74, Func: Function{"main.mainImpl"}, }, }, ID: 6, First: true, }, { Signature: Signature{ State: "chan receive", Stack: Stack{ Calls: []Call{ { SourcePath: "/gopath/src/github.com/foo/bar/baz.go", Line: 72, Func: Function{"main.func·001"}, }, }, }, CreatedBy: Call{ SourcePath: "/gopath/src/github.com/foo/bar/baz.go", Line: 74, Func: Function{"main.mainImpl"}, }, }, ID: 7, }, } ut.AssertEqual(t, expectedGR, goroutines) expectedBuckets := Buckets{{expectedGR[0].Signature, []Goroutine{expectedGR[0], expectedGR[1]}}} ut.AssertEqual(t, expectedBuckets, SortBuckets(Bucketize(goroutines, ExactLines))) } func TestBucketizeNotAggressive(t *testing.T) { // 2 goroutines with the same signature data := []string{ "panic: runtime error: index out of range", "", "goroutine 6 [chan receive]:", "main.func·001(0x11000000, 2)", " /gopath/src/github.com/foo/bar/baz.go:72 +0x49", "", "goroutine 7 [chan receive]:", "main.func·001(0x21000000, 2)", " /gopath/src/github.com/foo/bar/baz.go:72 +0x49", "", } goroutines, err := ParseDump(bytes.NewBufferString(strings.Join(data, "\n")), &bytes.Buffer{}) ut.AssertEqual(t, nil, err) expectedGR := []Goroutine{ { Signature: Signature{ State: "chan receive", Stack: Stack{ Calls: []Call{ { SourcePath: "/gopath/src/github.com/foo/bar/baz.go", Line: 72, Func: Function{"main.func·001"}, Args: Args{Values: []Arg{{0x11000000, ""}, {Value: 2}}}, }, }, }, }, ID: 6, First: true, }, { Signature: Signature{ State: "chan receive", Stack: Stack{ Calls: []Call{ { SourcePath: "/gopath/src/github.com/foo/bar/baz.go", Line: 72, Func: Function{"main.func·001"}, Args: Args{Values: []Arg{{0x21000000, "#1"}, {Value: 2}}}, }, }, }, }, ID: 7, }, } ut.AssertEqual(t, expectedGR, goroutines) expectedBuckets := Buckets{ {expectedGR[0].Signature, []Goroutine{expectedGR[0]}}, {expectedGR[1].Signature, []Goroutine{expectedGR[1]}}, } ut.AssertEqual(t, expectedBuckets, SortBuckets(Bucketize(goroutines, ExactLines))) } func TestBucketizeAggressive(t *testing.T) { // 2 goroutines with the same signature data := []string{ "panic: runtime error: index out of range", "", "goroutine 6 [chan receive, 10 minutes]:", "main.func·001(0x11000000, 2)", " /gopath/src/github.com/foo/bar/baz.go:72 +0x49", "", "goroutine 7 [chan receive, 50 minutes]:", "main.func·001(0x21000000, 2)", " /gopath/src/github.com/foo/bar/baz.go:72 +0x49", "", "goroutine 8 [chan receive, 100 minutes]:", "main.func·001(0x21000000, 2)", " /gopath/src/github.com/foo/bar/baz.go:72 +0x49", "", } goroutines, err := ParseDump(bytes.NewBufferString(strings.Join(data, "\n")), &bytes.Buffer{}) ut.AssertEqual(t, nil, err) expectedGR := []Goroutine{ { Signature: Signature{ State: "chan receive", SleepMin: 10, SleepMax: 10, Stack: Stack{ Calls: []Call{ { SourcePath: "/gopath/src/github.com/foo/bar/baz.go", Line: 72, Func: Function{"main.func·001"}, Args: Args{Values: []Arg{{0x11000000, ""}, {Value: 2}}}, }, }, }, }, ID: 6, First: true, }, { Signature: Signature{ State: "chan receive", SleepMin: 50, SleepMax: 50, Stack: Stack{ Calls: []Call{ { SourcePath: "/gopath/src/github.com/foo/bar/baz.go", Line: 72, Func: Function{"main.func·001"}, Args: Args{Values: []Arg{{0x21000000, "#1"}, {Value: 2}}}, }, }, }, }, ID: 7, }, { Signature: Signature{ State: "chan receive", SleepMin: 100, SleepMax: 100, Stack: Stack{ Calls: []Call{ { SourcePath: "/gopath/src/github.com/foo/bar/baz.go", Line: 72, Func: Function{"main.func·001"}, Args: Args{Values: []Arg{{0x21000000, "#1"}, {Value: 2}}}, }, }, }, }, ID: 8, }, } ut.AssertEqual(t, expectedGR, goroutines) signature := Signature{ State: "chan receive", SleepMin: 10, SleepMax: 100, Stack: Stack{ Calls: []Call{ { SourcePath: "/gopath/src/github.com/foo/bar/baz.go", Line: 72, Func: Function{"main.func·001"}, Args: Args{Values: []Arg{{0x11000000, "*"}, {Value: 2}}}, }, }, }, } expectedBuckets := Buckets{{signature, []Goroutine{expectedGR[0], expectedGR[1], expectedGR[2]}}} ut.AssertEqual(t, expectedBuckets, SortBuckets(Bucketize(goroutines, AnyPointer))) } func TestParseDumpNoOffset(t *testing.T) { data := []string{ "panic: runtime error: index out of range", "", "goroutine 37 [runnable]:", "github.com/foo.func·002()", " /gopath/src/github.com/foo/bar.go:110", "created by github.com/foo.New", " /gopath/src/github.com/foo/bar.go:113 +0x43b", "", } goroutines, err := ParseDump(bytes.NewBufferString(strings.Join(data, "\n")), &bytes.Buffer{}) ut.AssertEqual(t, nil, err) expectedGR := []Goroutine{ { Signature: Signature{ State: "runnable", Stack: Stack{ Calls: []Call{ { SourcePath: "/gopath/src/github.com/foo/bar.go", Line: 110, Func: Function{"github.com/foo.func·002"}, }, }, }, CreatedBy: Call{ SourcePath: "/gopath/src/github.com/foo/bar.go", Line: 113, Func: Function{"github.com/foo.New"}, }, }, ID: 37, First: true, }, } ut.AssertEqual(t, expectedGR, goroutines) } func TestParseDumpJunk(t *testing.T) { // For coverage of scanLines. data := []string{ "panic: reflect.Set: value of type", "", "goroutine 1 [running]:", "junk", } goroutines, err := ParseDump(bytes.NewBufferString(strings.Join(data, "\n")), &bytes.Buffer{}) ut.AssertEqual(t, nil, err) expectedGR := []Goroutine{ { Signature: Signature{State: "running"}, ID: 1, First: true, }, } ut.AssertEqual(t, expectedGR, goroutines) } func TestParseCCode(t *testing.T) { data := []string{ "SIGQUIT: quit", "PC=0x43f349", "", "goroutine 0 [idle]:", "runtime.epollwait(0x4, 0x7fff671c7118, 0xffffffff00000080, 0x0, 0xffffffff0028c1be, 0x0, 0x0, 0x0, 0x0, 0x0, ...)", " " + goroot + "/src/runtime/sys_linux_amd64.s:400 +0x19", "runtime.netpoll(0x901b01, 0x0)", " " + goroot + "/src/runtime/netpoll_epoll.go:68 +0xa3", "findrunnable(0xc208012000)", " " + goroot + "/src/runtime/proc.c:1472 +0x485", "schedule()", " " + goroot + "/src/runtime/proc.c:1575 +0x151", "runtime.park_m(0xc2080017a0)", " " + goroot + "/src/runtime/proc.c:1654 +0x113", "runtime.mcall(0x432684)", " " + goroot + "/src/runtime/asm_amd64.s:186 +0x5a", "", } goroutines, err := ParseDump(bytes.NewBufferString(strings.Join(data, "\n")), &bytes.Buffer{}) ut.AssertEqual(t, nil, err) expectedGR := []Goroutine{ { Signature: Signature{ State: "idle", Stack: Stack{ Calls: []Call{ { SourcePath: goroot + "/src/runtime/sys_linux_amd64.s", Line: 400, Func: Function{"runtime.epollwait"}, Args: Args{ Values: []Arg{ {Value: 0x4}, {Value: 0x7fff671c7118}, {Value: 0xffffffff00000080}, {}, {Value: 0xffffffff0028c1be}, {}, {}, {}, {}, {}, }, Elided: true, }, }, { SourcePath: goroot + "/src/runtime/netpoll_epoll.go", Line: 68, Func: Function{"runtime.netpoll"}, Args: Args{Values: []Arg{{Value: 0x901b01}, {}}}, }, { SourcePath: goroot + "/src/runtime/proc.c", Line: 1472, Func: Function{"findrunnable"}, Args: Args{Values: []Arg{{Value: 0xc208012000}}}, }, { SourcePath: goroot + "/src/runtime/proc.c", Line: 1575, Func: Function{"schedule"}, }, { SourcePath: goroot + "/src/runtime/proc.c", Line: 1654, Func: Function{"runtime.park_m"}, Args: Args{Values: []Arg{{Value: 0xc2080017a0}}}, }, { SourcePath: goroot + "/src/runtime/asm_amd64.s", Line: 186, Func: Function{"runtime.mcall"}, Args: Args{Values: []Arg{{Value: 0x432684}}}, }, }, }, }, ID: 0, First: true, }, } ut.AssertEqual(t, expectedGR, goroutines) } func TestParseWithCarriageReturn(t *testing.T) { data := []string{ "goroutine 1 [running]:", "github.com/cockroachdb/cockroach/storage/engine._Cfunc_DBIterSeek()", " ??:0 +0x6d", "gopkg.in/yaml%2ev2.handleErr(0xc208033b20)", " /gopath/src/gopkg.in/yaml.v2/yaml.go:153 +0xc6", "reflect.Value.assignTo(0x570860, 0xc20803f3e0, 0x15)", " " + goroot + "/src/reflect/value.go:2125 +0x368", "main.main()", " /gopath/src/github.com/foo/bar/baz.go:428 +0x27", "", } goroutines, err := ParseDump(bytes.NewBufferString(strings.Join(data, "\r\n")), ioutil.Discard) ut.AssertEqual(t, nil, err) expected := []Goroutine{ { Signature: Signature{ State: "running", Stack: Stack{ Calls: []Call{ { SourcePath: "??", Func: Function{"github.com/cockroachdb/cockroach/storage/engine._Cfunc_DBIterSeek"}, }, { SourcePath: "/gopath/src/gopkg.in/yaml.v2/yaml.go", Line: 153, Func: Function{"gopkg.in/yaml%2ev2.handleErr"}, Args: Args{Values: []Arg{{Value: 0xc208033b20}}}, }, { SourcePath: goroot + "/src/reflect/value.go", Line: 2125, Func: Function{"reflect.Value.assignTo"}, Args: Args{Values: []Arg{{Value: 0x570860}, {Value: 0xc20803f3e0}, {Value: 0x15}}}, }, { SourcePath: "/gopath/src/github.com/foo/bar/baz.go", Line: 428, Func: Function{"main.main"}, }, }, }, }, ID: 1, First: true, }, } ut.AssertEqual(t, expected, goroutines) } func TestCallPkg1(t *testing.T) { c := Call{ SourcePath: "/gopath/src/gopkg.in/yaml.v2/yaml.go", Line: 153, Func: Function{"gopkg.in/yaml%2ev2.handleErr"}, Args: Args{Values: []Arg{{Value: 0xc208033b20}}}, } ut.AssertEqual(t, "yaml.go", c.SourceName()) ut.AssertEqual(t, filepath.Join("yaml.v2", "yaml.go"), c.PkgSource()) ut.AssertEqual(t, "gopkg.in/yaml.v2.handleErr", c.Func.String()) ut.AssertEqual(t, "handleErr", c.Func.Name()) // This is due to directory name not matching the package name. ut.AssertEqual(t, "yaml.v2", c.Func.PkgName()) ut.AssertEqual(t, false, c.Func.IsExported()) ut.AssertEqual(t, false, c.IsStdlib()) ut.AssertEqual(t, false, c.IsPkgMain()) } func TestCallPkg2(t *testing.T) { c := Call{ SourcePath: "/gopath/src/gopkg.in/yaml.v2/yaml.go", Line: 153, Func: Function{"gopkg.in/yaml%2ev2.(*decoder).unmarshal"}, Args: Args{Values: []Arg{{Value: 0xc208033b20}}}, } ut.AssertEqual(t, "yaml.go", c.SourceName()) ut.AssertEqual(t, filepath.Join("yaml.v2", "yaml.go"), c.PkgSource()) // TODO(maruel): Using '/' for this function is inconsistent on Windows // w.r.t. other functions. ut.AssertEqual(t, "gopkg.in/yaml.v2.(*decoder).unmarshal", c.Func.String()) ut.AssertEqual(t, "(*decoder).unmarshal", c.Func.Name()) // This is due to directory name not matching the package name. ut.AssertEqual(t, "yaml.v2", c.Func.PkgName()) ut.AssertEqual(t, false, c.Func.IsExported()) ut.AssertEqual(t, false, c.IsStdlib()) ut.AssertEqual(t, false, c.IsPkgMain()) } func TestCallStdlib(t *testing.T) { c := Call{ SourcePath: goroot + "/src/reflect/value.go", Line: 2125, Func: Function{"reflect.Value.assignTo"}, Args: Args{Values: []Arg{{Value: 0x570860}, {Value: 0xc20803f3e0}, {Value: 0x15}}}, } ut.AssertEqual(t, "value.go", c.SourceName()) ut.AssertEqual(t, "value.go:2125", c.SourceLine()) ut.AssertEqual(t, filepath.Join("reflect", "value.go"), c.PkgSource()) ut.AssertEqual(t, "reflect.Value.assignTo", c.Func.String()) ut.AssertEqual(t, "Value.assignTo", c.Func.Name()) ut.AssertEqual(t, "reflect", c.Func.PkgName()) ut.AssertEqual(t, false, c.Func.IsExported()) ut.AssertEqual(t, true, c.IsStdlib()) ut.AssertEqual(t, false, c.IsPkgMain()) } func TestCallMain(t *testing.T) { c := Call{ SourcePath: "/gopath/src/github.com/foo/bar/main.go", Line: 428, Func: Function{"main.main"}, } ut.AssertEqual(t, "main.go", c.SourceName()) ut.AssertEqual(t, "main.go:428", c.SourceLine()) ut.AssertEqual(t, filepath.Join("bar", "main.go"), c.PkgSource()) ut.AssertEqual(t, "main.main", c.Func.String()) ut.AssertEqual(t, "main", c.Func.Name()) ut.AssertEqual(t, "main", c.Func.PkgName()) ut.AssertEqual(t, true, c.Func.IsExported()) ut.AssertEqual(t, false, c.IsStdlib()) ut.AssertEqual(t, true, c.IsPkgMain()) } func TestCallC(t *testing.T) { c := Call{ SourcePath: goroot + "/src/runtime/proc.c", Line: 1472, Func: Function{"findrunnable"}, Args: Args{Values: []Arg{{Value: 0xc208012000}}}, } ut.AssertEqual(t, "proc.c", c.SourceName()) ut.AssertEqual(t, "proc.c:1472", c.SourceLine()) ut.AssertEqual(t, filepath.Join("runtime", "proc.c"), c.PkgSource()) ut.AssertEqual(t, "findrunnable", c.Func.String()) ut.AssertEqual(t, "findrunnable", c.Func.Name()) ut.AssertEqual(t, "", c.Func.PkgName()) ut.AssertEqual(t, false, c.Func.IsExported()) ut.AssertEqual(t, true, c.IsStdlib()) ut.AssertEqual(t, false, c.IsPkgMain()) } func TestArgs(t *testing.T) { a := Args{ Values: []Arg{ {Value: 0x4}, {Value: 0x7fff671c7118}, {Value: 0xffffffff00000080}, {}, {Value: 0xffffffff0028c1be}, {}, {}, {}, {}, {}, }, Elided: true, } ut.AssertEqual(t, "0x4, 0x7fff671c7118, 0xffffffff00000080, 0, 0xffffffff0028c1be, 0, 0, 0, 0, 0, ...", a.String()) } func TestFunctionAnonymous(t *testing.T) { f := Function{"main.func·001"} ut.AssertEqual(t, "main.func·001", f.String()) ut.AssertEqual(t, "main.func·001", f.PkgDotName()) ut.AssertEqual(t, "func·001", f.Name()) ut.AssertEqual(t, "main", f.PkgName()) ut.AssertEqual(t, false, f.IsExported()) } func TestFunctionGC(t *testing.T) { f := Function{"gc"} ut.AssertEqual(t, "gc", f.String()) ut.AssertEqual(t, "gc", f.PkgDotName()) ut.AssertEqual(t, "gc", f.Name()) ut.AssertEqual(t, "", f.PkgName()) ut.AssertEqual(t, false, f.IsExported()) } ================================================ FILE: vendor/github.com/maruel/panicparse/stack/ui.go ================================================ // Copyright 2016 Marc-Antoine Ruel. All rights reserved. // Use of this source code is governed under the Apache License, Version 2.0 // that can be found in the LICENSE file. package stack import ( "fmt" "strings" ) // Palette defines the color used. // // An empty object Palette{} can be used to disable coloring. type Palette struct { EOLReset string // Routine header. RoutineFirst string // The first routine printed. Routine string // Following routines. CreatedBy string // Call line. Package string SourceFile string FunctionStdLib string FunctionStdLibExported string FunctionMain string FunctionOther string FunctionOtherExported string Arguments string } // CalcLengths returns the maximum length of the source lines and package names. func CalcLengths(buckets Buckets, fullPath bool) (int, int) { srcLen := 0 pkgLen := 0 for _, bucket := range buckets { for _, line := range bucket.Signature.Stack.Calls { l := 0 if fullPath { l = len(line.FullSourceLine()) } else { l = len(line.SourceLine()) } if l > srcLen { srcLen = l } l = len(line.Func.PkgName()) if l > pkgLen { pkgLen = l } } } return srcLen, pkgLen } // functionColor returns the color to be used for the function name based on // the type of package the function is in. func (p *Palette) functionColor(line *Call) string { if line.IsStdlib() { if line.Func.IsExported() { return p.FunctionStdLibExported } return p.FunctionStdLib } else if line.IsPkgMain() { return p.FunctionMain } else if line.Func.IsExported() { return p.FunctionOtherExported } return p.FunctionOther } // routineColor returns the color for the header of the goroutines bucket. func (p *Palette) routineColor(bucket *Bucket, multipleBuckets bool) string { if bucket.First() && multipleBuckets { return p.RoutineFirst } return p.Routine } // BucketHeader prints the header of a goroutine signature. func (p *Palette) BucketHeader(bucket *Bucket, fullPath, multipleBuckets bool) string { extra := "" if bucket.SleepMax != 0 { if bucket.SleepMin != bucket.SleepMax { extra += fmt.Sprintf(" [%d~%d minutes]", bucket.SleepMin, bucket.SleepMax) } else { extra += fmt.Sprintf(" [%d minutes]", bucket.SleepMax) } } if bucket.Locked { extra += " [locked]" } created := bucket.CreatedBy.Func.PkgDotName() if created != "" { created += " @ " if fullPath { created += bucket.CreatedBy.FullSourceLine() } else { created += bucket.CreatedBy.SourceLine() } extra += p.CreatedBy + " [Created by " + created + "]" } return fmt.Sprintf( "%s%d: %s%s%s\n", p.routineColor(bucket, multipleBuckets), len(bucket.Routines), bucket.State, extra, p.EOLReset) } // callLine prints one stack line. func (p *Palette) callLine(line *Call, srcLen, pkgLen int, fullPath bool) string { src := "" if fullPath { src = line.FullSourceLine() } else { src = line.SourceLine() } return fmt.Sprintf( " %s%-*s %s%-*s %s%s%s(%s)%s", p.Package, pkgLen, line.Func.PkgName(), p.SourceFile, srcLen, src, p.functionColor(line), line.Func.Name(), p.Arguments, line.Args, p.EOLReset) } // StackLines prints one complete stack trace, without the header. func (p *Palette) StackLines(signature *Signature, srcLen, pkgLen int, fullPath bool) string { out := make([]string, len(signature.Stack.Calls)) for i := range signature.Stack.Calls { out[i] = p.callLine(&signature.Stack.Calls[i], srcLen, pkgLen, fullPath) } if signature.Stack.Elided { out = append(out, " (...)") } return strings.Join(out, "\n") + "\n" } ================================================ FILE: vendor/github.com/maruel/panicparse/stack/ui_test.go ================================================ // Copyright 2016 Marc-Antoine Ruel. All rights reserved. // Use of this source code is governed under the Apache License, Version 2.0 // that can be found in the LICENSE file. package stack import ( "testing" "github.com/maruel/ut" ) var p = &Palette{ EOLReset: "A", RoutineFirst: "B", Routine: "C", CreatedBy: "D", Package: "E", SourceFile: "F", FunctionStdLib: "G", FunctionStdLibExported: "H", FunctionMain: "I", FunctionOther: "J", FunctionOtherExported: "K", Arguments: "L", } func TestCalcLengths(t *testing.T) { t.Parallel() b := Buckets{ { Signature{Stack: Stack{Calls: []Call{{SourcePath: "/gopath/baz.go", Func: Function{"main.func·001"}}}}}, nil, }, } srcLen, pkgLen := CalcLengths(b, true) ut.AssertEqual(t, 16, srcLen) ut.AssertEqual(t, 4, pkgLen) srcLen, pkgLen = CalcLengths(b, false) ut.AssertEqual(t, 8, srcLen) ut.AssertEqual(t, 4, pkgLen) } func TestBucketHeader(t *testing.T) { t.Parallel() b := &Bucket{ Signature{ State: "chan receive", CreatedBy: Call{ SourcePath: "/gopath/src/github.com/foo/bar/baz.go", Line: 74, Func: Function{"main.mainImpl"}, }, SleepMax: 6, SleepMin: 2, }, []Goroutine{ { First: true, }, {}, }, } ut.AssertEqual(t, "B2: chan receive [2~6 minutes]D [Created by main.mainImpl @ /gopath/src/github.com/foo/bar/baz.go:74]A\n", p.BucketHeader(b, true, true)) ut.AssertEqual(t, "C2: chan receive [2~6 minutes]D [Created by main.mainImpl @ /gopath/src/github.com/foo/bar/baz.go:74]A\n", p.BucketHeader(b, true, false)) ut.AssertEqual(t, "B2: chan receive [2~6 minutes]D [Created by main.mainImpl @ baz.go:74]A\n", p.BucketHeader(b, false, true)) ut.AssertEqual(t, "C2: chan receive [2~6 minutes]D [Created by main.mainImpl @ baz.go:74]A\n", p.BucketHeader(b, false, false)) b = &Bucket{ Signature{ State: "b0rked", SleepMax: 6, SleepMin: 6, Locked: true, }, nil, } ut.AssertEqual(t, "C0: b0rked [6 minutes] [locked]A\n", p.BucketHeader(b, false, false)) } func TestStackLines(t *testing.T) { t.Parallel() s := &Signature{ State: "idle", Stack: Stack{ Calls: []Call{ { SourcePath: goroot + "/src/runtime/sys_linux_amd64.s", Line: 400, Func: Function{"runtime.Epollwait"}, Args: Args{ Values: []Arg{ {Value: 0x4}, {Value: 0x7fff671c7118}, {Value: 0xffffffff00000080}, {}, {Value: 0xffffffff0028c1be}, {}, {}, {}, {}, {}, }, Elided: true, }, }, { SourcePath: goroot + "/src/runtime/netpoll_epoll.go", Line: 68, Func: Function{"runtime.netpoll"}, Args: Args{Values: []Arg{{Value: 0x901b01}, {}}}, }, { SourcePath: "/src/main.go", Line: 1472, Func: Function{"main.Main"}, Args: Args{Values: []Arg{{Value: 0xc208012000}}}, }, { SourcePath: "/src/foo/bar.go", Line: 1575, Func: Function{"foo.OtherExported"}, }, { SourcePath: "/src/foo/bar.go", Line: 10, Func: Function{"foo.otherPrivate"}, }, }, Elided: true, }, } expected := "" + " Eruntime F" + goroot + "/src/runtime/sys_linux_amd64.s:400 HEpollwaitL(0x4, 0x7fff671c7118, 0xffffffff00000080, 0, 0xffffffff0028c1be, 0, 0, 0, 0, 0, ...)A\n" + " Eruntime F" + goroot + "/src/runtime/netpoll_epoll.go:68 GnetpollL(0x901b01, 0)A\n" + " Emain F/src/main.go:1472 IMainL(0xc208012000)A\n" + " Efoo F/src/foo/bar.go:1575 KOtherExportedL()A\n" + " Efoo F/src/foo/bar.go:10 JotherPrivateL()A\n" + " (...)\n" ut.AssertEqual(t, expected, p.StackLines(s, 10, 10, true)) expected = "" + " Eruntime Fsys_linux_amd64.s:400 HEpollwaitL(0x4, 0x7fff671c7118, 0xffffffff00000080, 0, 0xffffffff0028c1be, 0, 0, 0, 0, 0, ...)A\n" + " Eruntime Fnetpoll_epoll.go:68 GnetpollL(0x901b01, 0)A\n" + " Emain Fmain.go:1472 IMainL(0xc208012000)A\n" + " Efoo Fbar.go:1575 KOtherExportedL()A\n" + " Efoo Fbar.go:10 JotherPrivateL()A\n" + " (...)\n" ut.AssertEqual(t, expected, p.StackLines(s, 10, 10, false)) } ================================================ FILE: vendor/github.com/mattn/go-runewidth/.travis.yml ================================================ language: go go: - tip before_install: - go get github.com/mattn/goveralls - go get golang.org/x/tools/cmd/cover script: - $HOME/gopath/bin/goveralls -repotoken lAKAWPzcGsD3A8yBX3BGGtRUdJ6CaGERL ================================================ FILE: vendor/github.com/mattn/go-runewidth/LICENSE ================================================ The MIT License (MIT) Copyright (c) 2016 Yasuhiro Matsumoto 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. ================================================ FILE: vendor/github.com/mattn/go-runewidth/README.mkd ================================================ go-runewidth ============ [![Build Status](https://travis-ci.org/mattn/go-runewidth.png?branch=master)](https://travis-ci.org/mattn/go-runewidth) [![Coverage Status](https://coveralls.io/repos/mattn/go-runewidth/badge.png?branch=HEAD)](https://coveralls.io/r/mattn/go-runewidth?branch=HEAD) [![GoDoc](https://godoc.org/github.com/mattn/go-runewidth?status.svg)](http://godoc.org/github.com/mattn/go-runewidth) [![Go Report Card](https://goreportcard.com/badge/github.com/mattn/go-runewidth)](https://goreportcard.com/report/github.com/mattn/go-runewidth) Provides functions to get fixed width of the character or string. Usage ----- ```go runewidth.StringWidth("つのだ☆HIRO") == 12 ``` Author ------ Yasuhiro Matsumoto License ------- under the MIT License: http://mattn.mit-license.org/2013 ================================================ FILE: vendor/github.com/mattn/go-runewidth/runewidth.go ================================================ package runewidth var ( // EastAsianWidth will be set true if the current locale is CJK EastAsianWidth = IsEastAsian() // DefaultCondition is a condition in current locale DefaultCondition = &Condition{EastAsianWidth} ) type interval struct { first rune last rune } type table []interval func inTables(r rune, ts ...table) bool { for _, t := range ts { if inTable(r, t) { return true } } return false } func inTable(r rune, t table) bool { // func (t table) IncludesRune(r rune) bool { if r < t[0].first { return false } bot := 0 top := len(t) - 1 for top >= bot { mid := (bot + top) / 2 switch { case t[mid].last < r: bot = mid + 1 case t[mid].first > r: top = mid - 1 default: return true } } return false } var private = table{ {0x00E000, 0x00F8FF}, {0x0F0000, 0x0FFFFD}, {0x100000, 0x10FFFD}, } var nonprint = table{ {0x0000, 0x001F}, {0x007F, 0x009F}, {0x00AD, 0x00AD}, {0x070F, 0x070F}, {0x180B, 0x180E}, {0x200B, 0x200F}, {0x202A, 0x202E}, {0x206A, 0x206F}, {0xD800, 0xDFFF}, {0xFEFF, 0xFEFF}, {0xFFF9, 0xFFFB}, {0xFFFE, 0xFFFF}, } var combining = table{ {0x0300, 0x036F}, {0x0483, 0x0489}, {0x0591, 0x05BD}, {0x05BF, 0x05BF}, {0x05C1, 0x05C2}, {0x05C4, 0x05C5}, {0x05C7, 0x05C7}, {0x0610, 0x061A}, {0x064B, 0x065F}, {0x0670, 0x0670}, {0x06D6, 0x06DC}, {0x06DF, 0x06E4}, {0x06E7, 0x06E8}, {0x06EA, 0x06ED}, {0x0711, 0x0711}, {0x0730, 0x074A}, {0x07A6, 0x07B0}, {0x07EB, 0x07F3}, {0x0816, 0x0819}, {0x081B, 0x0823}, {0x0825, 0x0827}, {0x0829, 0x082D}, {0x0859, 0x085B}, {0x08D4, 0x08E1}, {0x08E3, 0x0903}, {0x093A, 0x093C}, {0x093E, 0x094F}, {0x0951, 0x0957}, {0x0962, 0x0963}, {0x0981, 0x0983}, {0x09BC, 0x09BC}, {0x09BE, 0x09C4}, {0x09C7, 0x09C8}, {0x09CB, 0x09CD}, {0x09D7, 0x09D7}, {0x09E2, 0x09E3}, {0x0A01, 0x0A03}, {0x0A3C, 0x0A3C}, {0x0A3E, 0x0A42}, {0x0A47, 0x0A48}, {0x0A4B, 0x0A4D}, {0x0A51, 0x0A51}, {0x0A70, 0x0A71}, {0x0A75, 0x0A75}, {0x0A81, 0x0A83}, {0x0ABC, 0x0ABC}, {0x0ABE, 0x0AC5}, {0x0AC7, 0x0AC9}, {0x0ACB, 0x0ACD}, {0x0AE2, 0x0AE3}, {0x0B01, 0x0B03}, {0x0B3C, 0x0B3C}, {0x0B3E, 0x0B44}, {0x0B47, 0x0B48}, {0x0B4B, 0x0B4D}, {0x0B56, 0x0B57}, {0x0B62, 0x0B63}, {0x0B82, 0x0B82}, {0x0BBE, 0x0BC2}, {0x0BC6, 0x0BC8}, {0x0BCA, 0x0BCD}, {0x0BD7, 0x0BD7}, {0x0C00, 0x0C03}, {0x0C3E, 0x0C44}, {0x0C46, 0x0C48}, {0x0C4A, 0x0C4D}, {0x0C55, 0x0C56}, {0x0C62, 0x0C63}, {0x0C81, 0x0C83}, {0x0CBC, 0x0CBC}, {0x0CBE, 0x0CC4}, {0x0CC6, 0x0CC8}, {0x0CCA, 0x0CCD}, {0x0CD5, 0x0CD6}, {0x0CE2, 0x0CE3}, {0x0D01, 0x0D03}, {0x0D3E, 0x0D44}, {0x0D46, 0x0D48}, {0x0D4A, 0x0D4D}, {0x0D57, 0x0D57}, {0x0D62, 0x0D63}, {0x0D82, 0x0D83}, {0x0DCA, 0x0DCA}, {0x0DCF, 0x0DD4}, {0x0DD6, 0x0DD6}, {0x0DD8, 0x0DDF}, {0x0DF2, 0x0DF3}, {0x0E31, 0x0E31}, {0x0E34, 0x0E3A}, {0x0E47, 0x0E4E}, {0x0EB1, 0x0EB1}, {0x0EB4, 0x0EB9}, {0x0EBB, 0x0EBC}, {0x0EC8, 0x0ECD}, {0x0F18, 0x0F19}, {0x0F35, 0x0F35}, {0x0F37, 0x0F37}, {0x0F39, 0x0F39}, {0x0F3E, 0x0F3F}, {0x0F71, 0x0F84}, {0x0F86, 0x0F87}, {0x0F8D, 0x0F97}, {0x0F99, 0x0FBC}, {0x0FC6, 0x0FC6}, {0x102B, 0x103E}, {0x1056, 0x1059}, {0x105E, 0x1060}, {0x1062, 0x1064}, {0x1067, 0x106D}, {0x1071, 0x1074}, {0x1082, 0x108D}, {0x108F, 0x108F}, {0x109A, 0x109D}, {0x135D, 0x135F}, {0x1712, 0x1714}, {0x1732, 0x1734}, {0x1752, 0x1753}, {0x1772, 0x1773}, {0x17B4, 0x17D3}, {0x17DD, 0x17DD}, {0x180B, 0x180D}, {0x1885, 0x1886}, {0x18A9, 0x18A9}, {0x1920, 0x192B}, {0x1930, 0x193B}, {0x1A17, 0x1A1B}, {0x1A55, 0x1A5E}, {0x1A60, 0x1A7C}, {0x1A7F, 0x1A7F}, {0x1AB0, 0x1ABE}, {0x1B00, 0x1B04}, {0x1B34, 0x1B44}, {0x1B6B, 0x1B73}, {0x1B80, 0x1B82}, {0x1BA1, 0x1BAD}, {0x1BE6, 0x1BF3}, {0x1C24, 0x1C37}, {0x1CD0, 0x1CD2}, {0x1CD4, 0x1CE8}, {0x1CED, 0x1CED}, {0x1CF2, 0x1CF4}, {0x1CF8, 0x1CF9}, {0x1DC0, 0x1DF5}, {0x1DFB, 0x1DFF}, {0x20D0, 0x20F0}, {0x2CEF, 0x2CF1}, {0x2D7F, 0x2D7F}, {0x2DE0, 0x2DFF}, {0x302A, 0x302F}, {0x3099, 0x309A}, {0xA66F, 0xA672}, {0xA674, 0xA67D}, {0xA69E, 0xA69F}, {0xA6F0, 0xA6F1}, {0xA802, 0xA802}, {0xA806, 0xA806}, {0xA80B, 0xA80B}, {0xA823, 0xA827}, {0xA880, 0xA881}, {0xA8B4, 0xA8C5}, {0xA8E0, 0xA8F1}, {0xA926, 0xA92D}, {0xA947, 0xA953}, {0xA980, 0xA983}, {0xA9B3, 0xA9C0}, {0xA9E5, 0xA9E5}, {0xAA29, 0xAA36}, {0xAA43, 0xAA43}, {0xAA4C, 0xAA4D}, {0xAA7B, 0xAA7D}, {0xAAB0, 0xAAB0}, {0xAAB2, 0xAAB4}, {0xAAB7, 0xAAB8}, {0xAABE, 0xAABF}, {0xAAC1, 0xAAC1}, {0xAAEB, 0xAAEF}, {0xAAF5, 0xAAF6}, {0xABE3, 0xABEA}, {0xABEC, 0xABED}, {0xFB1E, 0xFB1E}, {0xFE00, 0xFE0F}, {0xFE20, 0xFE2F}, {0x101FD, 0x101FD}, {0x102E0, 0x102E0}, {0x10376, 0x1037A}, {0x10A01, 0x10A03}, {0x10A05, 0x10A06}, {0x10A0C, 0x10A0F}, {0x10A38, 0x10A3A}, {0x10A3F, 0x10A3F}, {0x10AE5, 0x10AE6}, {0x11000, 0x11002}, {0x11038, 0x11046}, {0x1107F, 0x11082}, {0x110B0, 0x110BA}, {0x11100, 0x11102}, {0x11127, 0x11134}, {0x11173, 0x11173}, {0x11180, 0x11182}, {0x111B3, 0x111C0}, {0x111CA, 0x111CC}, {0x1122C, 0x11237}, {0x1123E, 0x1123E}, {0x112DF, 0x112EA}, {0x11300, 0x11303}, {0x1133C, 0x1133C}, {0x1133E, 0x11344}, {0x11347, 0x11348}, {0x1134B, 0x1134D}, {0x11357, 0x11357}, {0x11362, 0x11363}, {0x11366, 0x1136C}, {0x11370, 0x11374}, {0x11435, 0x11446}, {0x114B0, 0x114C3}, {0x115AF, 0x115B5}, {0x115B8, 0x115C0}, {0x115DC, 0x115DD}, {0x11630, 0x11640}, {0x116AB, 0x116B7}, {0x1171D, 0x1172B}, {0x11C2F, 0x11C36}, {0x11C38, 0x11C3F}, {0x11C92, 0x11CA7}, {0x11CA9, 0x11CB6}, {0x16AF0, 0x16AF4}, {0x16B30, 0x16B36}, {0x16F51, 0x16F7E}, {0x16F8F, 0x16F92}, {0x1BC9D, 0x1BC9E}, {0x1D165, 0x1D169}, {0x1D16D, 0x1D172}, {0x1D17B, 0x1D182}, {0x1D185, 0x1D18B}, {0x1D1AA, 0x1D1AD}, {0x1D242, 0x1D244}, {0x1DA00, 0x1DA36}, {0x1DA3B, 0x1DA6C}, {0x1DA75, 0x1DA75}, {0x1DA84, 0x1DA84}, {0x1DA9B, 0x1DA9F}, {0x1DAA1, 0x1DAAF}, {0x1E000, 0x1E006}, {0x1E008, 0x1E018}, {0x1E01B, 0x1E021}, {0x1E023, 0x1E024}, {0x1E026, 0x1E02A}, {0x1E8D0, 0x1E8D6}, {0x1E944, 0x1E94A}, {0xE0100, 0xE01EF}, } var doublewidth = table{ {0x1100, 0x115F}, {0x231A, 0x231B}, {0x2329, 0x232A}, {0x23E9, 0x23EC}, {0x23F0, 0x23F0}, {0x23F3, 0x23F3}, {0x25FD, 0x25FE}, {0x2614, 0x2615}, {0x2648, 0x2653}, {0x267F, 0x267F}, {0x2693, 0x2693}, {0x26A1, 0x26A1}, {0x26AA, 0x26AB}, {0x26BD, 0x26BE}, {0x26C4, 0x26C5}, {0x26CE, 0x26CE}, {0x26D4, 0x26D4}, {0x26EA, 0x26EA}, {0x26F2, 0x26F3}, {0x26F5, 0x26F5}, {0x26FA, 0x26FA}, {0x26FD, 0x26FD}, {0x2705, 0x2705}, {0x270A, 0x270B}, {0x2728, 0x2728}, {0x274C, 0x274C}, {0x274E, 0x274E}, {0x2753, 0x2755}, {0x2757, 0x2757}, {0x2795, 0x2797}, {0x27B0, 0x27B0}, {0x27BF, 0x27BF}, {0x2B1B, 0x2B1C}, {0x2B50, 0x2B50}, {0x2B55, 0x2B55}, {0x2E80, 0x2E99}, {0x2E9B, 0x2EF3}, {0x2F00, 0x2FD5}, {0x2FF0, 0x2FFB}, {0x3000, 0x303E}, {0x3041, 0x3096}, {0x3099, 0x30FF}, {0x3105, 0x312D}, {0x3131, 0x318E}, {0x3190, 0x31BA}, {0x31C0, 0x31E3}, {0x31F0, 0x321E}, {0x3220, 0x3247}, {0x3250, 0x32FE}, {0x3300, 0x4DBF}, {0x4E00, 0xA48C}, {0xA490, 0xA4C6}, {0xA960, 0xA97C}, {0xAC00, 0xD7A3}, {0xF900, 0xFAFF}, {0xFE10, 0xFE19}, {0xFE30, 0xFE52}, {0xFE54, 0xFE66}, {0xFE68, 0xFE6B}, {0xFF01, 0xFF60}, {0xFFE0, 0xFFE6}, {0x16FE0, 0x16FE0}, {0x17000, 0x187EC}, {0x18800, 0x18AF2}, {0x1B000, 0x1B001}, {0x1F004, 0x1F004}, {0x1F0CF, 0x1F0CF}, {0x1F18E, 0x1F18E}, {0x1F191, 0x1F19A}, {0x1F200, 0x1F202}, {0x1F210, 0x1F23B}, {0x1F240, 0x1F248}, {0x1F250, 0x1F251}, {0x1F300, 0x1F320}, {0x1F32D, 0x1F335}, {0x1F337, 0x1F37C}, {0x1F37E, 0x1F393}, {0x1F3A0, 0x1F3CA}, {0x1F3CF, 0x1F3D3}, {0x1F3E0, 0x1F3F0}, {0x1F3F4, 0x1F3F4}, {0x1F3F8, 0x1F43E}, {0x1F440, 0x1F440}, {0x1F442, 0x1F4FC}, {0x1F4FF, 0x1F53D}, {0x1F54B, 0x1F54E}, {0x1F550, 0x1F567}, {0x1F57A, 0x1F57A}, {0x1F595, 0x1F596}, {0x1F5A4, 0x1F5A4}, {0x1F5FB, 0x1F64F}, {0x1F680, 0x1F6C5}, {0x1F6CC, 0x1F6CC}, {0x1F6D0, 0x1F6D2}, {0x1F6EB, 0x1F6EC}, {0x1F6F4, 0x1F6F6}, {0x1F910, 0x1F91E}, {0x1F920, 0x1F927}, {0x1F930, 0x1F930}, {0x1F933, 0x1F93E}, {0x1F940, 0x1F94B}, {0x1F950, 0x1F95E}, {0x1F980, 0x1F991}, {0x1F9C0, 0x1F9C0}, {0x20000, 0x2FFFD}, {0x30000, 0x3FFFD}, } var ambiguous = table{ {0x00A1, 0x00A1}, {0x00A4, 0x00A4}, {0x00A7, 0x00A8}, {0x00AA, 0x00AA}, {0x00AD, 0x00AE}, {0x00B0, 0x00B4}, {0x00B6, 0x00BA}, {0x00BC, 0x00BF}, {0x00C6, 0x00C6}, {0x00D0, 0x00D0}, {0x00D7, 0x00D8}, {0x00DE, 0x00E1}, {0x00E6, 0x00E6}, {0x00E8, 0x00EA}, {0x00EC, 0x00ED}, {0x00F0, 0x00F0}, {0x00F2, 0x00F3}, {0x00F7, 0x00FA}, {0x00FC, 0x00FC}, {0x00FE, 0x00FE}, {0x0101, 0x0101}, {0x0111, 0x0111}, {0x0113, 0x0113}, {0x011B, 0x011B}, {0x0126, 0x0127}, {0x012B, 0x012B}, {0x0131, 0x0133}, {0x0138, 0x0138}, {0x013F, 0x0142}, {0x0144, 0x0144}, {0x0148, 0x014B}, {0x014D, 0x014D}, {0x0152, 0x0153}, {0x0166, 0x0167}, {0x016B, 0x016B}, {0x01CE, 0x01CE}, {0x01D0, 0x01D0}, {0x01D2, 0x01D2}, {0x01D4, 0x01D4}, {0x01D6, 0x01D6}, {0x01D8, 0x01D8}, {0x01DA, 0x01DA}, {0x01DC, 0x01DC}, {0x0251, 0x0251}, {0x0261, 0x0261}, {0x02C4, 0x02C4}, {0x02C7, 0x02C7}, {0x02C9, 0x02CB}, {0x02CD, 0x02CD}, {0x02D0, 0x02D0}, {0x02D8, 0x02DB}, {0x02DD, 0x02DD}, {0x02DF, 0x02DF}, {0x0300, 0x036F}, {0x0391, 0x03A1}, {0x03A3, 0x03A9}, {0x03B1, 0x03C1}, {0x03C3, 0x03C9}, {0x0401, 0x0401}, {0x0410, 0x044F}, {0x0451, 0x0451}, {0x2010, 0x2010}, {0x2013, 0x2016}, {0x2018, 0x2019}, {0x201C, 0x201D}, {0x2020, 0x2022}, {0x2024, 0x2027}, {0x2030, 0x2030}, {0x2032, 0x2033}, {0x2035, 0x2035}, {0x203B, 0x203B}, {0x203E, 0x203E}, {0x2074, 0x2074}, {0x207F, 0x207F}, {0x2081, 0x2084}, {0x20AC, 0x20AC}, {0x2103, 0x2103}, {0x2105, 0x2105}, {0x2109, 0x2109}, {0x2113, 0x2113}, {0x2116, 0x2116}, {0x2121, 0x2122}, {0x2126, 0x2126}, {0x212B, 0x212B}, {0x2153, 0x2154}, {0x215B, 0x215E}, {0x2160, 0x216B}, {0x2170, 0x2179}, {0x2189, 0x2189}, {0x2190, 0x2199}, {0x21B8, 0x21B9}, {0x21D2, 0x21D2}, {0x21D4, 0x21D4}, {0x21E7, 0x21E7}, {0x2200, 0x2200}, {0x2202, 0x2203}, {0x2207, 0x2208}, {0x220B, 0x220B}, {0x220F, 0x220F}, {0x2211, 0x2211}, {0x2215, 0x2215}, {0x221A, 0x221A}, {0x221D, 0x2220}, {0x2223, 0x2223}, {0x2225, 0x2225}, {0x2227, 0x222C}, {0x222E, 0x222E}, {0x2234, 0x2237}, {0x223C, 0x223D}, {0x2248, 0x2248}, {0x224C, 0x224C}, {0x2252, 0x2252}, {0x2260, 0x2261}, {0x2264, 0x2267}, {0x226A, 0x226B}, {0x226E, 0x226F}, {0x2282, 0x2283}, {0x2286, 0x2287}, {0x2295, 0x2295}, {0x2299, 0x2299}, {0x22A5, 0x22A5}, {0x22BF, 0x22BF}, {0x2312, 0x2312}, {0x2460, 0x24E9}, {0x24EB, 0x254B}, {0x2550, 0x2573}, {0x2580, 0x258F}, {0x2592, 0x2595}, {0x25A0, 0x25A1}, {0x25A3, 0x25A9}, {0x25B2, 0x25B3}, {0x25B6, 0x25B7}, {0x25BC, 0x25BD}, {0x25C0, 0x25C1}, {0x25C6, 0x25C8}, {0x25CB, 0x25CB}, {0x25CE, 0x25D1}, {0x25E2, 0x25E5}, {0x25EF, 0x25EF}, {0x2605, 0x2606}, {0x2609, 0x2609}, {0x260E, 0x260F}, {0x261C, 0x261C}, {0x261E, 0x261E}, {0x2640, 0x2640}, {0x2642, 0x2642}, {0x2660, 0x2661}, {0x2663, 0x2665}, {0x2667, 0x266A}, {0x266C, 0x266D}, {0x266F, 0x266F}, {0x269E, 0x269F}, {0x26BF, 0x26BF}, {0x26C6, 0x26CD}, {0x26CF, 0x26D3}, {0x26D5, 0x26E1}, {0x26E3, 0x26E3}, {0x26E8, 0x26E9}, {0x26EB, 0x26F1}, {0x26F4, 0x26F4}, {0x26F6, 0x26F9}, {0x26FB, 0x26FC}, {0x26FE, 0x26FF}, {0x273D, 0x273D}, {0x2776, 0x277F}, {0x2B56, 0x2B59}, {0x3248, 0x324F}, {0xE000, 0xF8FF}, {0xFE00, 0xFE0F}, {0xFFFD, 0xFFFD}, {0x1F100, 0x1F10A}, {0x1F110, 0x1F12D}, {0x1F130, 0x1F169}, {0x1F170, 0x1F18D}, {0x1F18F, 0x1F190}, {0x1F19B, 0x1F1AC}, {0xE0100, 0xE01EF}, {0xF0000, 0xFFFFD}, {0x100000, 0x10FFFD}, } var emoji = table{ {0x1F1E6, 0x1F1FF}, {0x1F321, 0x1F321}, {0x1F324, 0x1F32C}, {0x1F336, 0x1F336}, {0x1F37D, 0x1F37D}, {0x1F396, 0x1F397}, {0x1F399, 0x1F39B}, {0x1F39E, 0x1F39F}, {0x1F3CB, 0x1F3CE}, {0x1F3D4, 0x1F3DF}, {0x1F3F3, 0x1F3F5}, {0x1F3F7, 0x1F3F7}, {0x1F43F, 0x1F43F}, {0x1F441, 0x1F441}, {0x1F4FD, 0x1F4FD}, {0x1F549, 0x1F54A}, {0x1F56F, 0x1F570}, {0x1F573, 0x1F579}, {0x1F587, 0x1F587}, {0x1F58A, 0x1F58D}, {0x1F590, 0x1F590}, {0x1F5A5, 0x1F5A5}, {0x1F5A8, 0x1F5A8}, {0x1F5B1, 0x1F5B2}, {0x1F5BC, 0x1F5BC}, {0x1F5C2, 0x1F5C4}, {0x1F5D1, 0x1F5D3}, {0x1F5DC, 0x1F5DE}, {0x1F5E1, 0x1F5E1}, {0x1F5E3, 0x1F5E3}, {0x1F5E8, 0x1F5E8}, {0x1F5EF, 0x1F5EF}, {0x1F5F3, 0x1F5F3}, {0x1F5FA, 0x1F5FA}, {0x1F6CB, 0x1F6CF}, {0x1F6E0, 0x1F6E5}, {0x1F6E9, 0x1F6E9}, {0x1F6F0, 0x1F6F0}, {0x1F6F3, 0x1F6F3}, } var notassigned = table{ {0x0378, 0x0379}, {0x0380, 0x0383}, {0x038B, 0x038B}, {0x038D, 0x038D}, {0x03A2, 0x03A2}, {0x0530, 0x0530}, {0x0557, 0x0558}, {0x0560, 0x0560}, {0x0588, 0x0588}, {0x058B, 0x058C}, {0x0590, 0x0590}, {0x05C8, 0x05CF}, {0x05EB, 0x05EF}, {0x05F5, 0x05FF}, {0x061D, 0x061D}, {0x070E, 0x070E}, {0x074B, 0x074C}, {0x07B2, 0x07BF}, {0x07FB, 0x07FF}, {0x082E, 0x082F}, {0x083F, 0x083F}, {0x085C, 0x085D}, {0x085F, 0x089F}, {0x08B5, 0x08B5}, {0x08BE, 0x08D3}, {0x0984, 0x0984}, {0x098D, 0x098E}, {0x0991, 0x0992}, {0x09A9, 0x09A9}, {0x09B1, 0x09B1}, {0x09B3, 0x09B5}, {0x09BA, 0x09BB}, {0x09C5, 0x09C6}, {0x09C9, 0x09CA}, {0x09CF, 0x09D6}, {0x09D8, 0x09DB}, {0x09DE, 0x09DE}, {0x09E4, 0x09E5}, {0x09FC, 0x0A00}, {0x0A04, 0x0A04}, {0x0A0B, 0x0A0E}, {0x0A11, 0x0A12}, {0x0A29, 0x0A29}, {0x0A31, 0x0A31}, {0x0A34, 0x0A34}, {0x0A37, 0x0A37}, {0x0A3A, 0x0A3B}, {0x0A3D, 0x0A3D}, {0x0A43, 0x0A46}, {0x0A49, 0x0A4A}, {0x0A4E, 0x0A50}, {0x0A52, 0x0A58}, {0x0A5D, 0x0A5D}, {0x0A5F, 0x0A65}, {0x0A76, 0x0A80}, {0x0A84, 0x0A84}, {0x0A8E, 0x0A8E}, {0x0A92, 0x0A92}, {0x0AA9, 0x0AA9}, {0x0AB1, 0x0AB1}, {0x0AB4, 0x0AB4}, {0x0ABA, 0x0ABB}, {0x0AC6, 0x0AC6}, {0x0ACA, 0x0ACA}, {0x0ACE, 0x0ACF}, {0x0AD1, 0x0ADF}, {0x0AE4, 0x0AE5}, {0x0AF2, 0x0AF8}, {0x0AFA, 0x0B00}, {0x0B04, 0x0B04}, {0x0B0D, 0x0B0E}, {0x0B11, 0x0B12}, {0x0B29, 0x0B29}, {0x0B31, 0x0B31}, {0x0B34, 0x0B34}, {0x0B3A, 0x0B3B}, {0x0B45, 0x0B46}, {0x0B49, 0x0B4A}, {0x0B4E, 0x0B55}, {0x0B58, 0x0B5B}, {0x0B5E, 0x0B5E}, {0x0B64, 0x0B65}, {0x0B78, 0x0B81}, {0x0B84, 0x0B84}, {0x0B8B, 0x0B8D}, {0x0B91, 0x0B91}, {0x0B96, 0x0B98}, {0x0B9B, 0x0B9B}, {0x0B9D, 0x0B9D}, {0x0BA0, 0x0BA2}, {0x0BA5, 0x0BA7}, {0x0BAB, 0x0BAD}, {0x0BBA, 0x0BBD}, {0x0BC3, 0x0BC5}, {0x0BC9, 0x0BC9}, {0x0BCE, 0x0BCF}, {0x0BD1, 0x0BD6}, {0x0BD8, 0x0BE5}, {0x0BFB, 0x0BFF}, {0x0C04, 0x0C04}, {0x0C0D, 0x0C0D}, {0x0C11, 0x0C11}, {0x0C29, 0x0C29}, {0x0C3A, 0x0C3C}, {0x0C45, 0x0C45}, {0x0C49, 0x0C49}, {0x0C4E, 0x0C54}, {0x0C57, 0x0C57}, {0x0C5B, 0x0C5F}, {0x0C64, 0x0C65}, {0x0C70, 0x0C77}, {0x0C84, 0x0C84}, {0x0C8D, 0x0C8D}, {0x0C91, 0x0C91}, {0x0CA9, 0x0CA9}, {0x0CB4, 0x0CB4}, {0x0CBA, 0x0CBB}, {0x0CC5, 0x0CC5}, {0x0CC9, 0x0CC9}, {0x0CCE, 0x0CD4}, {0x0CD7, 0x0CDD}, {0x0CDF, 0x0CDF}, {0x0CE4, 0x0CE5}, {0x0CF0, 0x0CF0}, {0x0CF3, 0x0D00}, {0x0D04, 0x0D04}, {0x0D0D, 0x0D0D}, {0x0D11, 0x0D11}, {0x0D3B, 0x0D3C}, {0x0D45, 0x0D45}, {0x0D49, 0x0D49}, {0x0D50, 0x0D53}, {0x0D64, 0x0D65}, {0x0D80, 0x0D81}, {0x0D84, 0x0D84}, {0x0D97, 0x0D99}, {0x0DB2, 0x0DB2}, {0x0DBC, 0x0DBC}, {0x0DBE, 0x0DBF}, {0x0DC7, 0x0DC9}, {0x0DCB, 0x0DCE}, {0x0DD5, 0x0DD5}, {0x0DD7, 0x0DD7}, {0x0DE0, 0x0DE5}, {0x0DF0, 0x0DF1}, {0x0DF5, 0x0E00}, {0x0E3B, 0x0E3E}, {0x0E5C, 0x0E80}, {0x0E83, 0x0E83}, {0x0E85, 0x0E86}, {0x0E89, 0x0E89}, {0x0E8B, 0x0E8C}, {0x0E8E, 0x0E93}, {0x0E98, 0x0E98}, {0x0EA0, 0x0EA0}, {0x0EA4, 0x0EA4}, {0x0EA6, 0x0EA6}, {0x0EA8, 0x0EA9}, {0x0EAC, 0x0EAC}, {0x0EBA, 0x0EBA}, {0x0EBE, 0x0EBF}, {0x0EC5, 0x0EC5}, {0x0EC7, 0x0EC7}, {0x0ECE, 0x0ECF}, {0x0EDA, 0x0EDB}, {0x0EE0, 0x0EFF}, {0x0F48, 0x0F48}, {0x0F6D, 0x0F70}, {0x0F98, 0x0F98}, {0x0FBD, 0x0FBD}, {0x0FCD, 0x0FCD}, {0x0FDB, 0x0FFF}, {0x10C6, 0x10C6}, {0x10C8, 0x10CC}, {0x10CE, 0x10CF}, {0x1249, 0x1249}, {0x124E, 0x124F}, {0x1257, 0x1257}, {0x1259, 0x1259}, {0x125E, 0x125F}, {0x1289, 0x1289}, {0x128E, 0x128F}, {0x12B1, 0x12B1}, {0x12B6, 0x12B7}, {0x12BF, 0x12BF}, {0x12C1, 0x12C1}, {0x12C6, 0x12C7}, {0x12D7, 0x12D7}, {0x1311, 0x1311}, {0x1316, 0x1317}, {0x135B, 0x135C}, {0x137D, 0x137F}, {0x139A, 0x139F}, {0x13F6, 0x13F7}, {0x13FE, 0x13FF}, {0x169D, 0x169F}, {0x16F9, 0x16FF}, {0x170D, 0x170D}, {0x1715, 0x171F}, {0x1737, 0x173F}, {0x1754, 0x175F}, {0x176D, 0x176D}, {0x1771, 0x1771}, {0x1774, 0x177F}, {0x17DE, 0x17DF}, {0x17EA, 0x17EF}, {0x17FA, 0x17FF}, {0x180F, 0x180F}, {0x181A, 0x181F}, {0x1878, 0x187F}, {0x18AB, 0x18AF}, {0x18F6, 0x18FF}, {0x191F, 0x191F}, {0x192C, 0x192F}, {0x193C, 0x193F}, {0x1941, 0x1943}, {0x196E, 0x196F}, {0x1975, 0x197F}, {0x19AC, 0x19AF}, {0x19CA, 0x19CF}, {0x19DB, 0x19DD}, {0x1A1C, 0x1A1D}, {0x1A5F, 0x1A5F}, {0x1A7D, 0x1A7E}, {0x1A8A, 0x1A8F}, {0x1A9A, 0x1A9F}, {0x1AAE, 0x1AAF}, {0x1ABF, 0x1AFF}, {0x1B4C, 0x1B4F}, {0x1B7D, 0x1B7F}, {0x1BF4, 0x1BFB}, {0x1C38, 0x1C3A}, {0x1C4A, 0x1C4C}, {0x1C89, 0x1CBF}, {0x1CC8, 0x1CCF}, {0x1CF7, 0x1CF7}, {0x1CFA, 0x1CFF}, {0x1DF6, 0x1DFA}, {0x1F16, 0x1F17}, {0x1F1E, 0x1F1F}, {0x1F46, 0x1F47}, {0x1F4E, 0x1F4F}, {0x1F58, 0x1F58}, {0x1F5A, 0x1F5A}, {0x1F5C, 0x1F5C}, {0x1F5E, 0x1F5E}, {0x1F7E, 0x1F7F}, {0x1FB5, 0x1FB5}, {0x1FC5, 0x1FC5}, {0x1FD4, 0x1FD5}, {0x1FDC, 0x1FDC}, {0x1FF0, 0x1FF1}, {0x1FF5, 0x1FF5}, {0x1FFF, 0x1FFF}, {0x2065, 0x2065}, {0x2072, 0x2073}, {0x208F, 0x208F}, {0x209D, 0x209F}, {0x20BF, 0x20CF}, {0x20F1, 0x20FF}, {0x218C, 0x218F}, {0x23FF, 0x23FF}, {0x2427, 0x243F}, {0x244B, 0x245F}, {0x2B74, 0x2B75}, {0x2B96, 0x2B97}, {0x2BBA, 0x2BBC}, {0x2BC9, 0x2BC9}, {0x2BD2, 0x2BEB}, {0x2BF0, 0x2BFF}, {0x2C2F, 0x2C2F}, {0x2C5F, 0x2C5F}, {0x2CF4, 0x2CF8}, {0x2D26, 0x2D26}, {0x2D28, 0x2D2C}, {0x2D2E, 0x2D2F}, {0x2D68, 0x2D6E}, {0x2D71, 0x2D7E}, {0x2D97, 0x2D9F}, {0x2DA7, 0x2DA7}, {0x2DAF, 0x2DAF}, {0x2DB7, 0x2DB7}, {0x2DBF, 0x2DBF}, {0x2DC7, 0x2DC7}, {0x2DCF, 0x2DCF}, {0x2DD7, 0x2DD7}, {0x2DDF, 0x2DDF}, {0x2E45, 0x2E7F}, {0x2E9A, 0x2E9A}, {0x2EF4, 0x2EFF}, {0x2FD6, 0x2FEF}, {0x2FFC, 0x2FFF}, {0x3040, 0x3040}, {0x3097, 0x3098}, {0x3100, 0x3104}, {0x312E, 0x3130}, {0x318F, 0x318F}, {0x31BB, 0x31BF}, {0x31E4, 0x31EF}, {0x321F, 0x321F}, {0x32FF, 0x32FF}, {0x4DB6, 0x4DBF}, {0x9FD6, 0x9FFF}, {0xA48D, 0xA48F}, {0xA4C7, 0xA4CF}, {0xA62C, 0xA63F}, {0xA6F8, 0xA6FF}, {0xA7AF, 0xA7AF}, {0xA7B8, 0xA7F6}, {0xA82C, 0xA82F}, {0xA83A, 0xA83F}, {0xA878, 0xA87F}, {0xA8C6, 0xA8CD}, {0xA8DA, 0xA8DF}, {0xA8FE, 0xA8FF}, {0xA954, 0xA95E}, {0xA97D, 0xA97F}, {0xA9CE, 0xA9CE}, {0xA9DA, 0xA9DD}, {0xA9FF, 0xA9FF}, {0xAA37, 0xAA3F}, {0xAA4E, 0xAA4F}, {0xAA5A, 0xAA5B}, {0xAAC3, 0xAADA}, {0xAAF7, 0xAB00}, {0xAB07, 0xAB08}, {0xAB0F, 0xAB10}, {0xAB17, 0xAB1F}, {0xAB27, 0xAB27}, {0xAB2F, 0xAB2F}, {0xAB66, 0xAB6F}, {0xABEE, 0xABEF}, {0xABFA, 0xABFF}, {0xD7A4, 0xD7AF}, {0xD7C7, 0xD7CA}, {0xD7FC, 0xD7FF}, {0xFA6E, 0xFA6F}, {0xFADA, 0xFAFF}, {0xFB07, 0xFB12}, {0xFB18, 0xFB1C}, {0xFB37, 0xFB37}, {0xFB3D, 0xFB3D}, {0xFB3F, 0xFB3F}, {0xFB42, 0xFB42}, {0xFB45, 0xFB45}, {0xFBC2, 0xFBD2}, {0xFD40, 0xFD4F}, {0xFD90, 0xFD91}, {0xFDC8, 0xFDEF}, {0xFDFE, 0xFDFF}, {0xFE1A, 0xFE1F}, {0xFE53, 0xFE53}, {0xFE67, 0xFE67}, {0xFE6C, 0xFE6F}, {0xFE75, 0xFE75}, {0xFEFD, 0xFEFE}, {0xFF00, 0xFF00}, {0xFFBF, 0xFFC1}, {0xFFC8, 0xFFC9}, {0xFFD0, 0xFFD1}, {0xFFD8, 0xFFD9}, {0xFFDD, 0xFFDF}, {0xFFE7, 0xFFE7}, {0xFFEF, 0xFFF8}, {0xFFFE, 0xFFFF}, {0x1000C, 0x1000C}, {0x10027, 0x10027}, {0x1003B, 0x1003B}, {0x1003E, 0x1003E}, {0x1004E, 0x1004F}, {0x1005E, 0x1007F}, {0x100FB, 0x100FF}, {0x10103, 0x10106}, {0x10134, 0x10136}, {0x1018F, 0x1018F}, {0x1019C, 0x1019F}, {0x101A1, 0x101CF}, {0x101FE, 0x1027F}, {0x1029D, 0x1029F}, {0x102D1, 0x102DF}, {0x102FC, 0x102FF}, {0x10324, 0x1032F}, {0x1034B, 0x1034F}, {0x1037B, 0x1037F}, {0x1039E, 0x1039E}, {0x103C4, 0x103C7}, {0x103D6, 0x103FF}, {0x1049E, 0x1049F}, {0x104AA, 0x104AF}, {0x104D4, 0x104D7}, {0x104FC, 0x104FF}, {0x10528, 0x1052F}, {0x10564, 0x1056E}, {0x10570, 0x105FF}, {0x10737, 0x1073F}, {0x10756, 0x1075F}, {0x10768, 0x107FF}, {0x10806, 0x10807}, {0x10809, 0x10809}, {0x10836, 0x10836}, {0x10839, 0x1083B}, {0x1083D, 0x1083E}, {0x10856, 0x10856}, {0x1089F, 0x108A6}, {0x108B0, 0x108DF}, {0x108F3, 0x108F3}, {0x108F6, 0x108FA}, {0x1091C, 0x1091E}, {0x1093A, 0x1093E}, {0x10940, 0x1097F}, {0x109B8, 0x109BB}, {0x109D0, 0x109D1}, {0x10A04, 0x10A04}, {0x10A07, 0x10A0B}, {0x10A14, 0x10A14}, {0x10A18, 0x10A18}, {0x10A34, 0x10A37}, {0x10A3B, 0x10A3E}, {0x10A48, 0x10A4F}, {0x10A59, 0x10A5F}, {0x10AA0, 0x10ABF}, {0x10AE7, 0x10AEA}, {0x10AF7, 0x10AFF}, {0x10B36, 0x10B38}, {0x10B56, 0x10B57}, {0x10B73, 0x10B77}, {0x10B92, 0x10B98}, {0x10B9D, 0x10BA8}, {0x10BB0, 0x10BFF}, {0x10C49, 0x10C7F}, {0x10CB3, 0x10CBF}, {0x10CF3, 0x10CF9}, {0x10D00, 0x10E5F}, {0x10E7F, 0x10FFF}, {0x1104E, 0x11051}, {0x11070, 0x1107E}, {0x110C2, 0x110CF}, {0x110E9, 0x110EF}, {0x110FA, 0x110FF}, {0x11135, 0x11135}, {0x11144, 0x1114F}, {0x11177, 0x1117F}, {0x111CE, 0x111CF}, {0x111E0, 0x111E0}, {0x111F5, 0x111FF}, {0x11212, 0x11212}, {0x1123F, 0x1127F}, {0x11287, 0x11287}, {0x11289, 0x11289}, {0x1128E, 0x1128E}, {0x1129E, 0x1129E}, {0x112AA, 0x112AF}, {0x112EB, 0x112EF}, {0x112FA, 0x112FF}, {0x11304, 0x11304}, {0x1130D, 0x1130E}, {0x11311, 0x11312}, {0x11329, 0x11329}, {0x11331, 0x11331}, {0x11334, 0x11334}, {0x1133A, 0x1133B}, {0x11345, 0x11346}, {0x11349, 0x1134A}, {0x1134E, 0x1134F}, {0x11351, 0x11356}, {0x11358, 0x1135C}, {0x11364, 0x11365}, {0x1136D, 0x1136F}, {0x11375, 0x113FF}, {0x1145A, 0x1145A}, {0x1145C, 0x1145C}, {0x1145E, 0x1147F}, {0x114C8, 0x114CF}, {0x114DA, 0x1157F}, {0x115B6, 0x115B7}, {0x115DE, 0x115FF}, {0x11645, 0x1164F}, {0x1165A, 0x1165F}, {0x1166D, 0x1167F}, {0x116B8, 0x116BF}, {0x116CA, 0x116FF}, {0x1171A, 0x1171C}, {0x1172C, 0x1172F}, {0x11740, 0x1189F}, {0x118F3, 0x118FE}, {0x11900, 0x11ABF}, {0x11AF9, 0x11BFF}, {0x11C09, 0x11C09}, {0x11C37, 0x11C37}, {0x11C46, 0x11C4F}, {0x11C6D, 0x11C6F}, {0x11C90, 0x11C91}, {0x11CA8, 0x11CA8}, {0x11CB7, 0x11FFF}, {0x1239A, 0x123FF}, {0x1246F, 0x1246F}, {0x12475, 0x1247F}, {0x12544, 0x12FFF}, {0x1342F, 0x143FF}, {0x14647, 0x167FF}, {0x16A39, 0x16A3F}, {0x16A5F, 0x16A5F}, {0x16A6A, 0x16A6D}, {0x16A70, 0x16ACF}, {0x16AEE, 0x16AEF}, {0x16AF6, 0x16AFF}, {0x16B46, 0x16B4F}, {0x16B5A, 0x16B5A}, {0x16B62, 0x16B62}, {0x16B78, 0x16B7C}, {0x16B90, 0x16EFF}, {0x16F45, 0x16F4F}, {0x16F7F, 0x16F8E}, {0x16FA0, 0x16FDF}, {0x16FE1, 0x16FFF}, {0x187ED, 0x187FF}, {0x18AF3, 0x1AFFF}, {0x1B002, 0x1BBFF}, {0x1BC6B, 0x1BC6F}, {0x1BC7D, 0x1BC7F}, {0x1BC89, 0x1BC8F}, {0x1BC9A, 0x1BC9B}, {0x1BCA4, 0x1CFFF}, {0x1D0F6, 0x1D0FF}, {0x1D127, 0x1D128}, {0x1D1E9, 0x1D1FF}, {0x1D246, 0x1D2FF}, {0x1D357, 0x1D35F}, {0x1D372, 0x1D3FF}, {0x1D455, 0x1D455}, {0x1D49D, 0x1D49D}, {0x1D4A0, 0x1D4A1}, {0x1D4A3, 0x1D4A4}, {0x1D4A7, 0x1D4A8}, {0x1D4AD, 0x1D4AD}, {0x1D4BA, 0x1D4BA}, {0x1D4BC, 0x1D4BC}, {0x1D4C4, 0x1D4C4}, {0x1D506, 0x1D506}, {0x1D50B, 0x1D50C}, {0x1D515, 0x1D515}, {0x1D51D, 0x1D51D}, {0x1D53A, 0x1D53A}, {0x1D53F, 0x1D53F}, {0x1D545, 0x1D545}, {0x1D547, 0x1D549}, {0x1D551, 0x1D551}, {0x1D6A6, 0x1D6A7}, {0x1D7CC, 0x1D7CD}, {0x1DA8C, 0x1DA9A}, {0x1DAA0, 0x1DAA0}, {0x1DAB0, 0x1DFFF}, {0x1E007, 0x1E007}, {0x1E019, 0x1E01A}, {0x1E022, 0x1E022}, {0x1E025, 0x1E025}, {0x1E02B, 0x1E7FF}, {0x1E8C5, 0x1E8C6}, {0x1E8D7, 0x1E8FF}, {0x1E94B, 0x1E94F}, {0x1E95A, 0x1E95D}, {0x1E960, 0x1EDFF}, {0x1EE04, 0x1EE04}, {0x1EE20, 0x1EE20}, {0x1EE23, 0x1EE23}, {0x1EE25, 0x1EE26}, {0x1EE28, 0x1EE28}, {0x1EE33, 0x1EE33}, {0x1EE38, 0x1EE38}, {0x1EE3A, 0x1EE3A}, {0x1EE3C, 0x1EE41}, {0x1EE43, 0x1EE46}, {0x1EE48, 0x1EE48}, {0x1EE4A, 0x1EE4A}, {0x1EE4C, 0x1EE4C}, {0x1EE50, 0x1EE50}, {0x1EE53, 0x1EE53}, {0x1EE55, 0x1EE56}, {0x1EE58, 0x1EE58}, {0x1EE5A, 0x1EE5A}, {0x1EE5C, 0x1EE5C}, {0x1EE5E, 0x1EE5E}, {0x1EE60, 0x1EE60}, {0x1EE63, 0x1EE63}, {0x1EE65, 0x1EE66}, {0x1EE6B, 0x1EE6B}, {0x1EE73, 0x1EE73}, {0x1EE78, 0x1EE78}, {0x1EE7D, 0x1EE7D}, {0x1EE7F, 0x1EE7F}, {0x1EE8A, 0x1EE8A}, {0x1EE9C, 0x1EEA0}, {0x1EEA4, 0x1EEA4}, {0x1EEAA, 0x1EEAA}, {0x1EEBC, 0x1EEEF}, {0x1EEF2, 0x1EFFF}, {0x1F02C, 0x1F02F}, {0x1F094, 0x1F09F}, {0x1F0AF, 0x1F0B0}, {0x1F0C0, 0x1F0C0}, {0x1F0D0, 0x1F0D0}, {0x1F0F6, 0x1F0FF}, {0x1F10D, 0x1F10F}, {0x1F12F, 0x1F12F}, {0x1F16C, 0x1F16F}, {0x1F1AD, 0x1F1E5}, {0x1F203, 0x1F20F}, {0x1F23C, 0x1F23F}, {0x1F249, 0x1F24F}, {0x1F252, 0x1F2FF}, {0x1F6D3, 0x1F6DF}, {0x1F6ED, 0x1F6EF}, {0x1F6F7, 0x1F6FF}, {0x1F774, 0x1F77F}, {0x1F7D5, 0x1F7FF}, {0x1F80C, 0x1F80F}, {0x1F848, 0x1F84F}, {0x1F85A, 0x1F85F}, {0x1F888, 0x1F88F}, {0x1F8AE, 0x1F90F}, {0x1F91F, 0x1F91F}, {0x1F928, 0x1F92F}, {0x1F931, 0x1F932}, {0x1F93F, 0x1F93F}, {0x1F94C, 0x1F94F}, {0x1F95F, 0x1F97F}, {0x1F992, 0x1F9BF}, {0x1F9C1, 0x1FFFF}, {0x2A6D7, 0x2A6FF}, {0x2B735, 0x2B73F}, {0x2B81E, 0x2B81F}, {0x2CEA2, 0x2F7FF}, {0x2FA1E, 0xE0000}, {0xE0002, 0xE001F}, {0xE0080, 0xE00FF}, {0xE01F0, 0xEFFFF}, {0xFFFFE, 0xFFFFF}, } var neutral = table{ {0x0000, 0x001F}, {0x007F, 0x007F}, {0x0080, 0x009F}, {0x00A0, 0x00A0}, {0x00A9, 0x00A9}, {0x00AB, 0x00AB}, {0x00B5, 0x00B5}, {0x00BB, 0x00BB}, {0x00C0, 0x00C5}, {0x00C7, 0x00CF}, {0x00D1, 0x00D6}, {0x00D9, 0x00DD}, {0x00E2, 0x00E5}, {0x00E7, 0x00E7}, {0x00EB, 0x00EB}, {0x00EE, 0x00EF}, {0x00F1, 0x00F1}, {0x00F4, 0x00F6}, {0x00FB, 0x00FB}, {0x00FD, 0x00FD}, {0x00FF, 0x00FF}, {0x0100, 0x0100}, {0x0102, 0x0110}, {0x0112, 0x0112}, {0x0114, 0x011A}, {0x011C, 0x0125}, {0x0128, 0x012A}, {0x012C, 0x0130}, {0x0134, 0x0137}, {0x0139, 0x013E}, {0x0143, 0x0143}, {0x0145, 0x0147}, {0x014C, 0x014C}, {0x014E, 0x0151}, {0x0154, 0x0165}, {0x0168, 0x016A}, {0x016C, 0x017F}, {0x0180, 0x01BA}, {0x01BB, 0x01BB}, {0x01BC, 0x01BF}, {0x01C0, 0x01C3}, {0x01C4, 0x01CD}, {0x01CF, 0x01CF}, {0x01D1, 0x01D1}, {0x01D3, 0x01D3}, {0x01D5, 0x01D5}, {0x01D7, 0x01D7}, {0x01D9, 0x01D9}, {0x01DB, 0x01DB}, {0x01DD, 0x024F}, {0x0250, 0x0250}, {0x0252, 0x0260}, {0x0262, 0x0293}, {0x0294, 0x0294}, {0x0295, 0x02AF}, {0x02B0, 0x02C1}, {0x02C2, 0x02C3}, {0x02C5, 0x02C5}, {0x02C6, 0x02C6}, {0x02C8, 0x02C8}, {0x02CC, 0x02CC}, {0x02CE, 0x02CF}, {0x02D1, 0x02D1}, {0x02D2, 0x02D7}, {0x02DC, 0x02DC}, {0x02DE, 0x02DE}, {0x02E0, 0x02E4}, {0x02E5, 0x02EB}, {0x02EC, 0x02EC}, {0x02ED, 0x02ED}, {0x02EE, 0x02EE}, {0x02EF, 0x02FF}, {0x0370, 0x0373}, {0x0374, 0x0374}, {0x0375, 0x0375}, {0x0376, 0x0377}, {0x037A, 0x037A}, {0x037B, 0x037D}, {0x037E, 0x037E}, {0x037F, 0x037F}, {0x0384, 0x0385}, {0x0386, 0x0386}, {0x0387, 0x0387}, {0x0388, 0x038A}, {0x038C, 0x038C}, {0x038E, 0x0390}, {0x03AA, 0x03B0}, {0x03C2, 0x03C2}, {0x03CA, 0x03F5}, {0x03F6, 0x03F6}, {0x03F7, 0x03FF}, {0x0400, 0x0400}, {0x0402, 0x040F}, {0x0450, 0x0450}, {0x0452, 0x0481}, {0x0482, 0x0482}, {0x0483, 0x0487}, {0x0488, 0x0489}, {0x048A, 0x04FF}, {0x0500, 0x052F}, {0x0531, 0x0556}, {0x0559, 0x0559}, {0x055A, 0x055F}, {0x0561, 0x0587}, {0x0589, 0x0589}, {0x058A, 0x058A}, {0x058D, 0x058E}, {0x058F, 0x058F}, {0x0591, 0x05BD}, {0x05BE, 0x05BE}, {0x05BF, 0x05BF}, {0x05C0, 0x05C0}, {0x05C1, 0x05C2}, {0x05C3, 0x05C3}, {0x05C4, 0x05C5}, {0x05C6, 0x05C6}, {0x05C7, 0x05C7}, {0x05D0, 0x05EA}, {0x05F0, 0x05F2}, {0x05F3, 0x05F4}, {0x0600, 0x0605}, {0x0606, 0x0608}, {0x0609, 0x060A}, {0x060B, 0x060B}, {0x060C, 0x060D}, {0x060E, 0x060F}, {0x0610, 0x061A}, {0x061B, 0x061B}, {0x061C, 0x061C}, {0x061E, 0x061F}, {0x0620, 0x063F}, {0x0640, 0x0640}, {0x0641, 0x064A}, {0x064B, 0x065F}, {0x0660, 0x0669}, {0x066A, 0x066D}, {0x066E, 0x066F}, {0x0670, 0x0670}, {0x0671, 0x06D3}, {0x06D4, 0x06D4}, {0x06D5, 0x06D5}, {0x06D6, 0x06DC}, {0x06DD, 0x06DD}, {0x06DE, 0x06DE}, {0x06DF, 0x06E4}, {0x06E5, 0x06E6}, {0x06E7, 0x06E8}, {0x06E9, 0x06E9}, {0x06EA, 0x06ED}, {0x06EE, 0x06EF}, {0x06F0, 0x06F9}, {0x06FA, 0x06FC}, {0x06FD, 0x06FE}, {0x06FF, 0x06FF}, {0x0700, 0x070D}, {0x070F, 0x070F}, {0x0710, 0x0710}, {0x0711, 0x0711}, {0x0712, 0x072F}, {0x0730, 0x074A}, {0x074D, 0x074F}, {0x0750, 0x077F}, {0x0780, 0x07A5}, {0x07A6, 0x07B0}, {0x07B1, 0x07B1}, {0x07C0, 0x07C9}, {0x07CA, 0x07EA}, {0x07EB, 0x07F3}, {0x07F4, 0x07F5}, {0x07F6, 0x07F6}, {0x07F7, 0x07F9}, {0x07FA, 0x07FA}, {0x0800, 0x0815}, {0x0816, 0x0819}, {0x081A, 0x081A}, {0x081B, 0x0823}, {0x0824, 0x0824}, {0x0825, 0x0827}, {0x0828, 0x0828}, {0x0829, 0x082D}, {0x0830, 0x083E}, {0x0840, 0x0858}, {0x0859, 0x085B}, {0x085E, 0x085E}, {0x08A0, 0x08B4}, {0x08B6, 0x08BD}, {0x08D4, 0x08E1}, {0x08E2, 0x08E2}, {0x08E3, 0x08FF}, {0x0900, 0x0902}, {0x0903, 0x0903}, {0x0904, 0x0939}, {0x093A, 0x093A}, {0x093B, 0x093B}, {0x093C, 0x093C}, {0x093D, 0x093D}, {0x093E, 0x0940}, {0x0941, 0x0948}, {0x0949, 0x094C}, {0x094D, 0x094D}, {0x094E, 0x094F}, {0x0950, 0x0950}, {0x0951, 0x0957}, {0x0958, 0x0961}, {0x0962, 0x0963}, {0x0964, 0x0965}, {0x0966, 0x096F}, {0x0970, 0x0970}, {0x0971, 0x0971}, {0x0972, 0x097F}, {0x0980, 0x0980}, {0x0981, 0x0981}, {0x0982, 0x0983}, {0x0985, 0x098C}, {0x098F, 0x0990}, {0x0993, 0x09A8}, {0x09AA, 0x09B0}, {0x09B2, 0x09B2}, {0x09B6, 0x09B9}, {0x09BC, 0x09BC}, {0x09BD, 0x09BD}, {0x09BE, 0x09C0}, {0x09C1, 0x09C4}, {0x09C7, 0x09C8}, {0x09CB, 0x09CC}, {0x09CD, 0x09CD}, {0x09CE, 0x09CE}, {0x09D7, 0x09D7}, {0x09DC, 0x09DD}, {0x09DF, 0x09E1}, {0x09E2, 0x09E3}, {0x09E6, 0x09EF}, {0x09F0, 0x09F1}, {0x09F2, 0x09F3}, {0x09F4, 0x09F9}, {0x09FA, 0x09FA}, {0x09FB, 0x09FB}, {0x0A01, 0x0A02}, {0x0A03, 0x0A03}, {0x0A05, 0x0A0A}, {0x0A0F, 0x0A10}, {0x0A13, 0x0A28}, {0x0A2A, 0x0A30}, {0x0A32, 0x0A33}, {0x0A35, 0x0A36}, {0x0A38, 0x0A39}, {0x0A3C, 0x0A3C}, {0x0A3E, 0x0A40}, {0x0A41, 0x0A42}, {0x0A47, 0x0A48}, {0x0A4B, 0x0A4D}, {0x0A51, 0x0A51}, {0x0A59, 0x0A5C}, {0x0A5E, 0x0A5E}, {0x0A66, 0x0A6F}, {0x0A70, 0x0A71}, {0x0A72, 0x0A74}, {0x0A75, 0x0A75}, {0x0A81, 0x0A82}, {0x0A83, 0x0A83}, {0x0A85, 0x0A8D}, {0x0A8F, 0x0A91}, {0x0A93, 0x0AA8}, {0x0AAA, 0x0AB0}, {0x0AB2, 0x0AB3}, {0x0AB5, 0x0AB9}, {0x0ABC, 0x0ABC}, {0x0ABD, 0x0ABD}, {0x0ABE, 0x0AC0}, {0x0AC1, 0x0AC5}, {0x0AC7, 0x0AC8}, {0x0AC9, 0x0AC9}, {0x0ACB, 0x0ACC}, {0x0ACD, 0x0ACD}, {0x0AD0, 0x0AD0}, {0x0AE0, 0x0AE1}, {0x0AE2, 0x0AE3}, {0x0AE6, 0x0AEF}, {0x0AF0, 0x0AF0}, {0x0AF1, 0x0AF1}, {0x0AF9, 0x0AF9}, {0x0B01, 0x0B01}, {0x0B02, 0x0B03}, {0x0B05, 0x0B0C}, {0x0B0F, 0x0B10}, {0x0B13, 0x0B28}, {0x0B2A, 0x0B30}, {0x0B32, 0x0B33}, {0x0B35, 0x0B39}, {0x0B3C, 0x0B3C}, {0x0B3D, 0x0B3D}, {0x0B3E, 0x0B3E}, {0x0B3F, 0x0B3F}, {0x0B40, 0x0B40}, {0x0B41, 0x0B44}, {0x0B47, 0x0B48}, {0x0B4B, 0x0B4C}, {0x0B4D, 0x0B4D}, {0x0B56, 0x0B56}, {0x0B57, 0x0B57}, {0x0B5C, 0x0B5D}, {0x0B5F, 0x0B61}, {0x0B62, 0x0B63}, {0x0B66, 0x0B6F}, {0x0B70, 0x0B70}, {0x0B71, 0x0B71}, {0x0B72, 0x0B77}, {0x0B82, 0x0B82}, {0x0B83, 0x0B83}, {0x0B85, 0x0B8A}, {0x0B8E, 0x0B90}, {0x0B92, 0x0B95}, {0x0B99, 0x0B9A}, {0x0B9C, 0x0B9C}, {0x0B9E, 0x0B9F}, {0x0BA3, 0x0BA4}, {0x0BA8, 0x0BAA}, {0x0BAE, 0x0BB9}, {0x0BBE, 0x0BBF}, {0x0BC0, 0x0BC0}, {0x0BC1, 0x0BC2}, {0x0BC6, 0x0BC8}, {0x0BCA, 0x0BCC}, {0x0BCD, 0x0BCD}, {0x0BD0, 0x0BD0}, {0x0BD7, 0x0BD7}, {0x0BE6, 0x0BEF}, {0x0BF0, 0x0BF2}, {0x0BF3, 0x0BF8}, {0x0BF9, 0x0BF9}, {0x0BFA, 0x0BFA}, {0x0C00, 0x0C00}, {0x0C01, 0x0C03}, {0x0C05, 0x0C0C}, {0x0C0E, 0x0C10}, {0x0C12, 0x0C28}, {0x0C2A, 0x0C39}, {0x0C3D, 0x0C3D}, {0x0C3E, 0x0C40}, {0x0C41, 0x0C44}, {0x0C46, 0x0C48}, {0x0C4A, 0x0C4D}, {0x0C55, 0x0C56}, {0x0C58, 0x0C5A}, {0x0C60, 0x0C61}, {0x0C62, 0x0C63}, {0x0C66, 0x0C6F}, {0x0C78, 0x0C7E}, {0x0C7F, 0x0C7F}, {0x0C80, 0x0C80}, {0x0C81, 0x0C81}, {0x0C82, 0x0C83}, {0x0C85, 0x0C8C}, {0x0C8E, 0x0C90}, {0x0C92, 0x0CA8}, {0x0CAA, 0x0CB3}, {0x0CB5, 0x0CB9}, {0x0CBC, 0x0CBC}, {0x0CBD, 0x0CBD}, {0x0CBE, 0x0CBE}, {0x0CBF, 0x0CBF}, {0x0CC0, 0x0CC4}, {0x0CC6, 0x0CC6}, {0x0CC7, 0x0CC8}, {0x0CCA, 0x0CCB}, {0x0CCC, 0x0CCD}, {0x0CD5, 0x0CD6}, {0x0CDE, 0x0CDE}, {0x0CE0, 0x0CE1}, {0x0CE2, 0x0CE3}, {0x0CE6, 0x0CEF}, {0x0CF1, 0x0CF2}, {0x0D01, 0x0D01}, {0x0D02, 0x0D03}, {0x0D05, 0x0D0C}, {0x0D0E, 0x0D10}, {0x0D12, 0x0D3A}, {0x0D3D, 0x0D3D}, {0x0D3E, 0x0D40}, {0x0D41, 0x0D44}, {0x0D46, 0x0D48}, {0x0D4A, 0x0D4C}, {0x0D4D, 0x0D4D}, {0x0D4E, 0x0D4E}, {0x0D4F, 0x0D4F}, {0x0D54, 0x0D56}, {0x0D57, 0x0D57}, {0x0D58, 0x0D5E}, {0x0D5F, 0x0D61}, {0x0D62, 0x0D63}, {0x0D66, 0x0D6F}, {0x0D70, 0x0D78}, {0x0D79, 0x0D79}, {0x0D7A, 0x0D7F}, {0x0D82, 0x0D83}, {0x0D85, 0x0D96}, {0x0D9A, 0x0DB1}, {0x0DB3, 0x0DBB}, {0x0DBD, 0x0DBD}, {0x0DC0, 0x0DC6}, {0x0DCA, 0x0DCA}, {0x0DCF, 0x0DD1}, {0x0DD2, 0x0DD4}, {0x0DD6, 0x0DD6}, {0x0DD8, 0x0DDF}, {0x0DE6, 0x0DEF}, {0x0DF2, 0x0DF3}, {0x0DF4, 0x0DF4}, {0x0E01, 0x0E30}, {0x0E31, 0x0E31}, {0x0E32, 0x0E33}, {0x0E34, 0x0E3A}, {0x0E3F, 0x0E3F}, {0x0E40, 0x0E45}, {0x0E46, 0x0E46}, {0x0E47, 0x0E4E}, {0x0E4F, 0x0E4F}, {0x0E50, 0x0E59}, {0x0E5A, 0x0E5B}, {0x0E81, 0x0E82}, {0x0E84, 0x0E84}, {0x0E87, 0x0E88}, {0x0E8A, 0x0E8A}, {0x0E8D, 0x0E8D}, {0x0E94, 0x0E97}, {0x0E99, 0x0E9F}, {0x0EA1, 0x0EA3}, {0x0EA5, 0x0EA5}, {0x0EA7, 0x0EA7}, {0x0EAA, 0x0EAB}, {0x0EAD, 0x0EB0}, {0x0EB1, 0x0EB1}, {0x0EB2, 0x0EB3}, {0x0EB4, 0x0EB9}, {0x0EBB, 0x0EBC}, {0x0EBD, 0x0EBD}, {0x0EC0, 0x0EC4}, {0x0EC6, 0x0EC6}, {0x0EC8, 0x0ECD}, {0x0ED0, 0x0ED9}, {0x0EDC, 0x0EDF}, {0x0F00, 0x0F00}, {0x0F01, 0x0F03}, {0x0F04, 0x0F12}, {0x0F13, 0x0F13}, {0x0F14, 0x0F14}, {0x0F15, 0x0F17}, {0x0F18, 0x0F19}, {0x0F1A, 0x0F1F}, {0x0F20, 0x0F29}, {0x0F2A, 0x0F33}, {0x0F34, 0x0F34}, {0x0F35, 0x0F35}, {0x0F36, 0x0F36}, {0x0F37, 0x0F37}, {0x0F38, 0x0F38}, {0x0F39, 0x0F39}, {0x0F3A, 0x0F3A}, {0x0F3B, 0x0F3B}, {0x0F3C, 0x0F3C}, {0x0F3D, 0x0F3D}, {0x0F3E, 0x0F3F}, {0x0F40, 0x0F47}, {0x0F49, 0x0F6C}, {0x0F71, 0x0F7E}, {0x0F7F, 0x0F7F}, {0x0F80, 0x0F84}, {0x0F85, 0x0F85}, {0x0F86, 0x0F87}, {0x0F88, 0x0F8C}, {0x0F8D, 0x0F97}, {0x0F99, 0x0FBC}, {0x0FBE, 0x0FC5}, {0x0FC6, 0x0FC6}, {0x0FC7, 0x0FCC}, {0x0FCE, 0x0FCF}, {0x0FD0, 0x0FD4}, {0x0FD5, 0x0FD8}, {0x0FD9, 0x0FDA}, {0x1000, 0x102A}, {0x102B, 0x102C}, {0x102D, 0x1030}, {0x1031, 0x1031}, {0x1032, 0x1037}, {0x1038, 0x1038}, {0x1039, 0x103A}, {0x103B, 0x103C}, {0x103D, 0x103E}, {0x103F, 0x103F}, {0x1040, 0x1049}, {0x104A, 0x104F}, {0x1050, 0x1055}, {0x1056, 0x1057}, {0x1058, 0x1059}, {0x105A, 0x105D}, {0x105E, 0x1060}, {0x1061, 0x1061}, {0x1062, 0x1064}, {0x1065, 0x1066}, {0x1067, 0x106D}, {0x106E, 0x1070}, {0x1071, 0x1074}, {0x1075, 0x1081}, {0x1082, 0x1082}, {0x1083, 0x1084}, {0x1085, 0x1086}, {0x1087, 0x108C}, {0x108D, 0x108D}, {0x108E, 0x108E}, {0x108F, 0x108F}, {0x1090, 0x1099}, {0x109A, 0x109C}, {0x109D, 0x109D}, {0x109E, 0x109F}, {0x10A0, 0x10C5}, {0x10C7, 0x10C7}, {0x10CD, 0x10CD}, {0x10D0, 0x10FA}, {0x10FB, 0x10FB}, {0x10FC, 0x10FC}, {0x10FD, 0x10FF}, {0x1160, 0x11FF}, {0x1200, 0x1248}, {0x124A, 0x124D}, {0x1250, 0x1256}, {0x1258, 0x1258}, {0x125A, 0x125D}, {0x1260, 0x1288}, {0x128A, 0x128D}, {0x1290, 0x12B0}, {0x12B2, 0x12B5}, {0x12B8, 0x12BE}, {0x12C0, 0x12C0}, {0x12C2, 0x12C5}, {0x12C8, 0x12D6}, {0x12D8, 0x1310}, {0x1312, 0x1315}, {0x1318, 0x135A}, {0x135D, 0x135F}, {0x1360, 0x1368}, {0x1369, 0x137C}, {0x1380, 0x138F}, {0x1390, 0x1399}, {0x13A0, 0x13F5}, {0x13F8, 0x13FD}, {0x1400, 0x1400}, {0x1401, 0x166C}, {0x166D, 0x166E}, {0x166F, 0x167F}, {0x1680, 0x1680}, {0x1681, 0x169A}, {0x169B, 0x169B}, {0x169C, 0x169C}, {0x16A0, 0x16EA}, {0x16EB, 0x16ED}, {0x16EE, 0x16F0}, {0x16F1, 0x16F8}, {0x1700, 0x170C}, {0x170E, 0x1711}, {0x1712, 0x1714}, {0x1720, 0x1731}, {0x1732, 0x1734}, {0x1735, 0x1736}, {0x1740, 0x1751}, {0x1752, 0x1753}, {0x1760, 0x176C}, {0x176E, 0x1770}, {0x1772, 0x1773}, {0x1780, 0x17B3}, {0x17B4, 0x17B5}, {0x17B6, 0x17B6}, {0x17B7, 0x17BD}, {0x17BE, 0x17C5}, {0x17C6, 0x17C6}, {0x17C7, 0x17C8}, {0x17C9, 0x17D3}, {0x17D4, 0x17D6}, {0x17D7, 0x17D7}, {0x17D8, 0x17DA}, {0x17DB, 0x17DB}, {0x17DC, 0x17DC}, {0x17DD, 0x17DD}, {0x17E0, 0x17E9}, {0x17F0, 0x17F9}, {0x1800, 0x1805}, {0x1806, 0x1806}, {0x1807, 0x180A}, {0x180B, 0x180D}, {0x180E, 0x180E}, {0x1810, 0x1819}, {0x1820, 0x1842}, {0x1843, 0x1843}, {0x1844, 0x1877}, {0x1880, 0x1884}, {0x1885, 0x1886}, {0x1887, 0x18A8}, {0x18A9, 0x18A9}, {0x18AA, 0x18AA}, {0x18B0, 0x18F5}, {0x1900, 0x191E}, {0x1920, 0x1922}, {0x1923, 0x1926}, {0x1927, 0x1928}, {0x1929, 0x192B}, {0x1930, 0x1931}, {0x1932, 0x1932}, {0x1933, 0x1938}, {0x1939, 0x193B}, {0x1940, 0x1940}, {0x1944, 0x1945}, {0x1946, 0x194F}, {0x1950, 0x196D}, {0x1970, 0x1974}, {0x1980, 0x19AB}, {0x19B0, 0x19C9}, {0x19D0, 0x19D9}, {0x19DA, 0x19DA}, {0x19DE, 0x19DF}, {0x19E0, 0x19FF}, {0x1A00, 0x1A16}, {0x1A17, 0x1A18}, {0x1A19, 0x1A1A}, {0x1A1B, 0x1A1B}, {0x1A1E, 0x1A1F}, {0x1A20, 0x1A54}, {0x1A55, 0x1A55}, {0x1A56, 0x1A56}, {0x1A57, 0x1A57}, {0x1A58, 0x1A5E}, {0x1A60, 0x1A60}, {0x1A61, 0x1A61}, {0x1A62, 0x1A62}, {0x1A63, 0x1A64}, {0x1A65, 0x1A6C}, {0x1A6D, 0x1A72}, {0x1A73, 0x1A7C}, {0x1A7F, 0x1A7F}, {0x1A80, 0x1A89}, {0x1A90, 0x1A99}, {0x1AA0, 0x1AA6}, {0x1AA7, 0x1AA7}, {0x1AA8, 0x1AAD}, {0x1AB0, 0x1ABD}, {0x1ABE, 0x1ABE}, {0x1B00, 0x1B03}, {0x1B04, 0x1B04}, {0x1B05, 0x1B33}, {0x1B34, 0x1B34}, {0x1B35, 0x1B35}, {0x1B36, 0x1B3A}, {0x1B3B, 0x1B3B}, {0x1B3C, 0x1B3C}, {0x1B3D, 0x1B41}, {0x1B42, 0x1B42}, {0x1B43, 0x1B44}, {0x1B45, 0x1B4B}, {0x1B50, 0x1B59}, {0x1B5A, 0x1B60}, {0x1B61, 0x1B6A}, {0x1B6B, 0x1B73}, {0x1B74, 0x1B7C}, {0x1B80, 0x1B81}, {0x1B82, 0x1B82}, {0x1B83, 0x1BA0}, {0x1BA1, 0x1BA1}, {0x1BA2, 0x1BA5}, {0x1BA6, 0x1BA7}, {0x1BA8, 0x1BA9}, {0x1BAA, 0x1BAA}, {0x1BAB, 0x1BAD}, {0x1BAE, 0x1BAF}, {0x1BB0, 0x1BB9}, {0x1BBA, 0x1BBF}, {0x1BC0, 0x1BE5}, {0x1BE6, 0x1BE6}, {0x1BE7, 0x1BE7}, {0x1BE8, 0x1BE9}, {0x1BEA, 0x1BEC}, {0x1BED, 0x1BED}, {0x1BEE, 0x1BEE}, {0x1BEF, 0x1BF1}, {0x1BF2, 0x1BF3}, {0x1BFC, 0x1BFF}, {0x1C00, 0x1C23}, {0x1C24, 0x1C2B}, {0x1C2C, 0x1C33}, {0x1C34, 0x1C35}, {0x1C36, 0x1C37}, {0x1C3B, 0x1C3F}, {0x1C40, 0x1C49}, {0x1C4D, 0x1C4F}, {0x1C50, 0x1C59}, {0x1C5A, 0x1C77}, {0x1C78, 0x1C7D}, {0x1C7E, 0x1C7F}, {0x1C80, 0x1C88}, {0x1CC0, 0x1CC7}, {0x1CD0, 0x1CD2}, {0x1CD3, 0x1CD3}, {0x1CD4, 0x1CE0}, {0x1CE1, 0x1CE1}, {0x1CE2, 0x1CE8}, {0x1CE9, 0x1CEC}, {0x1CED, 0x1CED}, {0x1CEE, 0x1CF1}, {0x1CF2, 0x1CF3}, {0x1CF4, 0x1CF4}, {0x1CF5, 0x1CF6}, {0x1CF8, 0x1CF9}, {0x1D00, 0x1D2B}, {0x1D2C, 0x1D6A}, {0x1D6B, 0x1D77}, {0x1D78, 0x1D78}, {0x1D79, 0x1D7F}, {0x1D80, 0x1D9A}, {0x1D9B, 0x1DBF}, {0x1DC0, 0x1DF5}, {0x1DFB, 0x1DFF}, {0x1E00, 0x1EFF}, {0x1F00, 0x1F15}, {0x1F18, 0x1F1D}, {0x1F20, 0x1F45}, {0x1F48, 0x1F4D}, {0x1F50, 0x1F57}, {0x1F59, 0x1F59}, {0x1F5B, 0x1F5B}, {0x1F5D, 0x1F5D}, {0x1F5F, 0x1F7D}, {0x1F80, 0x1FB4}, {0x1FB6, 0x1FBC}, {0x1FBD, 0x1FBD}, {0x1FBE, 0x1FBE}, {0x1FBF, 0x1FC1}, {0x1FC2, 0x1FC4}, {0x1FC6, 0x1FCC}, {0x1FCD, 0x1FCF}, {0x1FD0, 0x1FD3}, {0x1FD6, 0x1FDB}, {0x1FDD, 0x1FDF}, {0x1FE0, 0x1FEC}, {0x1FED, 0x1FEF}, {0x1FF2, 0x1FF4}, {0x1FF6, 0x1FFC}, {0x1FFD, 0x1FFE}, {0x2000, 0x200A}, {0x200B, 0x200F}, {0x2011, 0x2012}, {0x2017, 0x2017}, {0x201A, 0x201A}, {0x201B, 0x201B}, {0x201E, 0x201E}, {0x201F, 0x201F}, {0x2023, 0x2023}, {0x2028, 0x2028}, {0x2029, 0x2029}, {0x202A, 0x202E}, {0x202F, 0x202F}, {0x2031, 0x2031}, {0x2034, 0x2034}, {0x2036, 0x2038}, {0x2039, 0x2039}, {0x203A, 0x203A}, {0x203C, 0x203D}, {0x203F, 0x2040}, {0x2041, 0x2043}, {0x2044, 0x2044}, {0x2045, 0x2045}, {0x2046, 0x2046}, {0x2047, 0x2051}, {0x2052, 0x2052}, {0x2053, 0x2053}, {0x2054, 0x2054}, {0x2055, 0x205E}, {0x205F, 0x205F}, {0x2060, 0x2064}, {0x2066, 0x206F}, {0x2070, 0x2070}, {0x2071, 0x2071}, {0x2075, 0x2079}, {0x207A, 0x207C}, {0x207D, 0x207D}, {0x207E, 0x207E}, {0x2080, 0x2080}, {0x2085, 0x2089}, {0x208A, 0x208C}, {0x208D, 0x208D}, {0x208E, 0x208E}, {0x2090, 0x209C}, {0x20A0, 0x20A8}, {0x20AA, 0x20AB}, {0x20AD, 0x20BE}, {0x20D0, 0x20DC}, {0x20DD, 0x20E0}, {0x20E1, 0x20E1}, {0x20E2, 0x20E4}, {0x20E5, 0x20F0}, {0x2100, 0x2101}, {0x2102, 0x2102}, {0x2104, 0x2104}, {0x2106, 0x2106}, {0x2107, 0x2107}, {0x2108, 0x2108}, {0x210A, 0x2112}, {0x2114, 0x2114}, {0x2115, 0x2115}, {0x2117, 0x2117}, {0x2118, 0x2118}, {0x2119, 0x211D}, {0x211E, 0x2120}, {0x2123, 0x2123}, {0x2124, 0x2124}, {0x2125, 0x2125}, {0x2127, 0x2127}, {0x2128, 0x2128}, {0x2129, 0x2129}, {0x212A, 0x212A}, {0x212C, 0x212D}, {0x212E, 0x212E}, {0x212F, 0x2134}, {0x2135, 0x2138}, {0x2139, 0x2139}, {0x213A, 0x213B}, {0x213C, 0x213F}, {0x2140, 0x2144}, {0x2145, 0x2149}, {0x214A, 0x214A}, {0x214B, 0x214B}, {0x214C, 0x214D}, {0x214E, 0x214E}, {0x214F, 0x214F}, {0x2150, 0x2152}, {0x2155, 0x215A}, {0x215F, 0x215F}, {0x216C, 0x216F}, {0x217A, 0x2182}, {0x2183, 0x2184}, {0x2185, 0x2188}, {0x218A, 0x218B}, {0x219A, 0x219B}, {0x219C, 0x219F}, {0x21A0, 0x21A0}, {0x21A1, 0x21A2}, {0x21A3, 0x21A3}, {0x21A4, 0x21A5}, {0x21A6, 0x21A6}, {0x21A7, 0x21AD}, {0x21AE, 0x21AE}, {0x21AF, 0x21B7}, {0x21BA, 0x21CD}, {0x21CE, 0x21CF}, {0x21D0, 0x21D1}, {0x21D3, 0x21D3}, {0x21D5, 0x21E6}, {0x21E8, 0x21F3}, {0x21F4, 0x21FF}, {0x2201, 0x2201}, {0x2204, 0x2206}, {0x2209, 0x220A}, {0x220C, 0x220E}, {0x2210, 0x2210}, {0x2212, 0x2214}, {0x2216, 0x2219}, {0x221B, 0x221C}, {0x2221, 0x2222}, {0x2224, 0x2224}, {0x2226, 0x2226}, {0x222D, 0x222D}, {0x222F, 0x2233}, {0x2238, 0x223B}, {0x223E, 0x2247}, {0x2249, 0x224B}, {0x224D, 0x2251}, {0x2253, 0x225F}, {0x2262, 0x2263}, {0x2268, 0x2269}, {0x226C, 0x226D}, {0x2270, 0x2281}, {0x2284, 0x2285}, {0x2288, 0x2294}, {0x2296, 0x2298}, {0x229A, 0x22A4}, {0x22A6, 0x22BE}, {0x22C0, 0x22FF}, {0x2300, 0x2307}, {0x2308, 0x2308}, {0x2309, 0x2309}, {0x230A, 0x230A}, {0x230B, 0x230B}, {0x230C, 0x2311}, {0x2313, 0x2319}, {0x231C, 0x231F}, {0x2320, 0x2321}, {0x2322, 0x2328}, {0x232B, 0x237B}, {0x237C, 0x237C}, {0x237D, 0x239A}, {0x239B, 0x23B3}, {0x23B4, 0x23DB}, {0x23DC, 0x23E1}, {0x23E2, 0x23E8}, {0x23ED, 0x23EF}, {0x23F1, 0x23F2}, {0x23F4, 0x23FE}, {0x2400, 0x2426}, {0x2440, 0x244A}, {0x24EA, 0x24EA}, {0x254C, 0x254F}, {0x2574, 0x257F}, {0x2590, 0x2591}, {0x2596, 0x259F}, {0x25A2, 0x25A2}, {0x25AA, 0x25B1}, {0x25B4, 0x25B5}, {0x25B8, 0x25BB}, {0x25BE, 0x25BF}, {0x25C2, 0x25C5}, {0x25C9, 0x25CA}, {0x25CC, 0x25CD}, {0x25D2, 0x25E1}, {0x25E6, 0x25EE}, {0x25F0, 0x25F7}, {0x25F8, 0x25FC}, {0x25FF, 0x25FF}, {0x2600, 0x2604}, {0x2607, 0x2608}, {0x260A, 0x260D}, {0x2610, 0x2613}, {0x2616, 0x261B}, {0x261D, 0x261D}, {0x261F, 0x263F}, {0x2641, 0x2641}, {0x2643, 0x2647}, {0x2654, 0x265F}, {0x2662, 0x2662}, {0x2666, 0x2666}, {0x266B, 0x266B}, {0x266E, 0x266E}, {0x2670, 0x267E}, {0x2680, 0x2692}, {0x2694, 0x269D}, {0x26A0, 0x26A0}, {0x26A2, 0x26A9}, {0x26AC, 0x26BC}, {0x26C0, 0x26C3}, {0x26E2, 0x26E2}, {0x26E4, 0x26E7}, {0x2700, 0x2704}, {0x2706, 0x2709}, {0x270C, 0x2727}, {0x2729, 0x273C}, {0x273E, 0x274B}, {0x274D, 0x274D}, {0x274F, 0x2752}, {0x2756, 0x2756}, {0x2758, 0x2767}, {0x2768, 0x2768}, {0x2769, 0x2769}, {0x276A, 0x276A}, {0x276B, 0x276B}, {0x276C, 0x276C}, {0x276D, 0x276D}, {0x276E, 0x276E}, {0x276F, 0x276F}, {0x2770, 0x2770}, {0x2771, 0x2771}, {0x2772, 0x2772}, {0x2773, 0x2773}, {0x2774, 0x2774}, {0x2775, 0x2775}, {0x2780, 0x2793}, {0x2794, 0x2794}, {0x2798, 0x27AF}, {0x27B1, 0x27BE}, {0x27C0, 0x27C4}, {0x27C5, 0x27C5}, {0x27C6, 0x27C6}, {0x27C7, 0x27E5}, {0x27EE, 0x27EE}, {0x27EF, 0x27EF}, {0x27F0, 0x27FF}, {0x2800, 0x28FF}, {0x2900, 0x297F}, {0x2980, 0x2982}, {0x2983, 0x2983}, {0x2984, 0x2984}, {0x2987, 0x2987}, {0x2988, 0x2988}, {0x2989, 0x2989}, {0x298A, 0x298A}, {0x298B, 0x298B}, {0x298C, 0x298C}, {0x298D, 0x298D}, {0x298E, 0x298E}, {0x298F, 0x298F}, {0x2990, 0x2990}, {0x2991, 0x2991}, {0x2992, 0x2992}, {0x2993, 0x2993}, {0x2994, 0x2994}, {0x2995, 0x2995}, {0x2996, 0x2996}, {0x2997, 0x2997}, {0x2998, 0x2998}, {0x2999, 0x29D7}, {0x29D8, 0x29D8}, {0x29D9, 0x29D9}, {0x29DA, 0x29DA}, {0x29DB, 0x29DB}, {0x29DC, 0x29FB}, {0x29FC, 0x29FC}, {0x29FD, 0x29FD}, {0x29FE, 0x29FF}, {0x2A00, 0x2AFF}, {0x2B00, 0x2B1A}, {0x2B1D, 0x2B2F}, {0x2B30, 0x2B44}, {0x2B45, 0x2B46}, {0x2B47, 0x2B4C}, {0x2B4D, 0x2B4F}, {0x2B51, 0x2B54}, {0x2B5A, 0x2B73}, {0x2B76, 0x2B95}, {0x2B98, 0x2BB9}, {0x2BBD, 0x2BC8}, {0x2BCA, 0x2BD1}, {0x2BEC, 0x2BEF}, {0x2C00, 0x2C2E}, {0x2C30, 0x2C5E}, {0x2C60, 0x2C7B}, {0x2C7C, 0x2C7D}, {0x2C7E, 0x2C7F}, {0x2C80, 0x2CE4}, {0x2CE5, 0x2CEA}, {0x2CEB, 0x2CEE}, {0x2CEF, 0x2CF1}, {0x2CF2, 0x2CF3}, {0x2CF9, 0x2CFC}, {0x2CFD, 0x2CFD}, {0x2CFE, 0x2CFF}, {0x2D00, 0x2D25}, {0x2D27, 0x2D27}, {0x2D2D, 0x2D2D}, {0x2D30, 0x2D67}, {0x2D6F, 0x2D6F}, {0x2D70, 0x2D70}, {0x2D7F, 0x2D7F}, {0x2D80, 0x2D96}, {0x2DA0, 0x2DA6}, {0x2DA8, 0x2DAE}, {0x2DB0, 0x2DB6}, {0x2DB8, 0x2DBE}, {0x2DC0, 0x2DC6}, {0x2DC8, 0x2DCE}, {0x2DD0, 0x2DD6}, {0x2DD8, 0x2DDE}, {0x2DE0, 0x2DFF}, {0x2E00, 0x2E01}, {0x2E02, 0x2E02}, {0x2E03, 0x2E03}, {0x2E04, 0x2E04}, {0x2E05, 0x2E05}, {0x2E06, 0x2E08}, {0x2E09, 0x2E09}, {0x2E0A, 0x2E0A}, {0x2E0B, 0x2E0B}, {0x2E0C, 0x2E0C}, {0x2E0D, 0x2E0D}, {0x2E0E, 0x2E16}, {0x2E17, 0x2E17}, {0x2E18, 0x2E19}, {0x2E1A, 0x2E1A}, {0x2E1B, 0x2E1B}, {0x2E1C, 0x2E1C}, {0x2E1D, 0x2E1D}, {0x2E1E, 0x2E1F}, {0x2E20, 0x2E20}, {0x2E21, 0x2E21}, {0x2E22, 0x2E22}, {0x2E23, 0x2E23}, {0x2E24, 0x2E24}, {0x2E25, 0x2E25}, {0x2E26, 0x2E26}, {0x2E27, 0x2E27}, {0x2E28, 0x2E28}, {0x2E29, 0x2E29}, {0x2E2A, 0x2E2E}, {0x2E2F, 0x2E2F}, {0x2E30, 0x2E39}, {0x2E3A, 0x2E3B}, {0x2E3C, 0x2E3F}, {0x2E40, 0x2E40}, {0x2E41, 0x2E41}, {0x2E42, 0x2E42}, {0x2E43, 0x2E44}, {0x303F, 0x303F}, {0x4DC0, 0x4DFF}, {0xA4D0, 0xA4F7}, {0xA4F8, 0xA4FD}, {0xA4FE, 0xA4FF}, {0xA500, 0xA60B}, {0xA60C, 0xA60C}, {0xA60D, 0xA60F}, {0xA610, 0xA61F}, {0xA620, 0xA629}, {0xA62A, 0xA62B}, {0xA640, 0xA66D}, {0xA66E, 0xA66E}, {0xA66F, 0xA66F}, {0xA670, 0xA672}, {0xA673, 0xA673}, {0xA674, 0xA67D}, {0xA67E, 0xA67E}, {0xA67F, 0xA67F}, {0xA680, 0xA69B}, {0xA69C, 0xA69D}, {0xA69E, 0xA69F}, {0xA6A0, 0xA6E5}, {0xA6E6, 0xA6EF}, {0xA6F0, 0xA6F1}, {0xA6F2, 0xA6F7}, {0xA700, 0xA716}, {0xA717, 0xA71F}, {0xA720, 0xA721}, {0xA722, 0xA76F}, {0xA770, 0xA770}, {0xA771, 0xA787}, {0xA788, 0xA788}, {0xA789, 0xA78A}, {0xA78B, 0xA78E}, {0xA78F, 0xA78F}, {0xA790, 0xA7AE}, {0xA7B0, 0xA7B7}, {0xA7F7, 0xA7F7}, {0xA7F8, 0xA7F9}, {0xA7FA, 0xA7FA}, {0xA7FB, 0xA7FF}, {0xA800, 0xA801}, {0xA802, 0xA802}, {0xA803, 0xA805}, {0xA806, 0xA806}, {0xA807, 0xA80A}, {0xA80B, 0xA80B}, {0xA80C, 0xA822}, {0xA823, 0xA824}, {0xA825, 0xA826}, {0xA827, 0xA827}, {0xA828, 0xA82B}, {0xA830, 0xA835}, {0xA836, 0xA837}, {0xA838, 0xA838}, {0xA839, 0xA839}, {0xA840, 0xA873}, {0xA874, 0xA877}, {0xA880, 0xA881}, {0xA882, 0xA8B3}, {0xA8B4, 0xA8C3}, {0xA8C4, 0xA8C5}, {0xA8CE, 0xA8CF}, {0xA8D0, 0xA8D9}, {0xA8E0, 0xA8F1}, {0xA8F2, 0xA8F7}, {0xA8F8, 0xA8FA}, {0xA8FB, 0xA8FB}, {0xA8FC, 0xA8FC}, {0xA8FD, 0xA8FD}, {0xA900, 0xA909}, {0xA90A, 0xA925}, {0xA926, 0xA92D}, {0xA92E, 0xA92F}, {0xA930, 0xA946}, {0xA947, 0xA951}, {0xA952, 0xA953}, {0xA95F, 0xA95F}, {0xA980, 0xA982}, {0xA983, 0xA983}, {0xA984, 0xA9B2}, {0xA9B3, 0xA9B3}, {0xA9B4, 0xA9B5}, {0xA9B6, 0xA9B9}, {0xA9BA, 0xA9BB}, {0xA9BC, 0xA9BC}, {0xA9BD, 0xA9C0}, {0xA9C1, 0xA9CD}, {0xA9CF, 0xA9CF}, {0xA9D0, 0xA9D9}, {0xA9DE, 0xA9DF}, {0xA9E0, 0xA9E4}, {0xA9E5, 0xA9E5}, {0xA9E6, 0xA9E6}, {0xA9E7, 0xA9EF}, {0xA9F0, 0xA9F9}, {0xA9FA, 0xA9FE}, {0xAA00, 0xAA28}, {0xAA29, 0xAA2E}, {0xAA2F, 0xAA30}, {0xAA31, 0xAA32}, {0xAA33, 0xAA34}, {0xAA35, 0xAA36}, {0xAA40, 0xAA42}, {0xAA43, 0xAA43}, {0xAA44, 0xAA4B}, {0xAA4C, 0xAA4C}, {0xAA4D, 0xAA4D}, {0xAA50, 0xAA59}, {0xAA5C, 0xAA5F}, {0xAA60, 0xAA6F}, {0xAA70, 0xAA70}, {0xAA71, 0xAA76}, {0xAA77, 0xAA79}, {0xAA7A, 0xAA7A}, {0xAA7B, 0xAA7B}, {0xAA7C, 0xAA7C}, {0xAA7D, 0xAA7D}, {0xAA7E, 0xAA7F}, {0xAA80, 0xAAAF}, {0xAAB0, 0xAAB0}, {0xAAB1, 0xAAB1}, {0xAAB2, 0xAAB4}, {0xAAB5, 0xAAB6}, {0xAAB7, 0xAAB8}, {0xAAB9, 0xAABD}, {0xAABE, 0xAABF}, {0xAAC0, 0xAAC0}, {0xAAC1, 0xAAC1}, {0xAAC2, 0xAAC2}, {0xAADB, 0xAADC}, {0xAADD, 0xAADD}, {0xAADE, 0xAADF}, {0xAAE0, 0xAAEA}, {0xAAEB, 0xAAEB}, {0xAAEC, 0xAAED}, {0xAAEE, 0xAAEF}, {0xAAF0, 0xAAF1}, {0xAAF2, 0xAAF2}, {0xAAF3, 0xAAF4}, {0xAAF5, 0xAAF5}, {0xAAF6, 0xAAF6}, {0xAB01, 0xAB06}, {0xAB09, 0xAB0E}, {0xAB11, 0xAB16}, {0xAB20, 0xAB26}, {0xAB28, 0xAB2E}, {0xAB30, 0xAB5A}, {0xAB5B, 0xAB5B}, {0xAB5C, 0xAB5F}, {0xAB60, 0xAB65}, {0xAB70, 0xABBF}, {0xABC0, 0xABE2}, {0xABE3, 0xABE4}, {0xABE5, 0xABE5}, {0xABE6, 0xABE7}, {0xABE8, 0xABE8}, {0xABE9, 0xABEA}, {0xABEB, 0xABEB}, {0xABEC, 0xABEC}, {0xABED, 0xABED}, {0xABF0, 0xABF9}, {0xD7B0, 0xD7C6}, {0xD7CB, 0xD7FB}, {0xD800, 0xDB7F}, {0xDB80, 0xDBFF}, {0xDC00, 0xDFFF}, {0xFB00, 0xFB06}, {0xFB13, 0xFB17}, {0xFB1D, 0xFB1D}, {0xFB1E, 0xFB1E}, {0xFB1F, 0xFB28}, {0xFB29, 0xFB29}, {0xFB2A, 0xFB36}, {0xFB38, 0xFB3C}, {0xFB3E, 0xFB3E}, {0xFB40, 0xFB41}, {0xFB43, 0xFB44}, {0xFB46, 0xFB4F}, {0xFB50, 0xFBB1}, {0xFBB2, 0xFBC1}, {0xFBD3, 0xFD3D}, {0xFD3E, 0xFD3E}, {0xFD3F, 0xFD3F}, {0xFD50, 0xFD8F}, {0xFD92, 0xFDC7}, {0xFDF0, 0xFDFB}, {0xFDFC, 0xFDFC}, {0xFDFD, 0xFDFD}, {0xFE20, 0xFE2F}, {0xFE70, 0xFE74}, {0xFE76, 0xFEFC}, {0xFEFF, 0xFEFF}, {0xFFF9, 0xFFFB}, {0xFFFC, 0xFFFC}, {0x10000, 0x1000B}, {0x1000D, 0x10026}, {0x10028, 0x1003A}, {0x1003C, 0x1003D}, {0x1003F, 0x1004D}, {0x10050, 0x1005D}, {0x10080, 0x100FA}, {0x10100, 0x10102}, {0x10107, 0x10133}, {0x10137, 0x1013F}, {0x10140, 0x10174}, {0x10175, 0x10178}, {0x10179, 0x10189}, {0x1018A, 0x1018B}, {0x1018C, 0x1018E}, {0x10190, 0x1019B}, {0x101A0, 0x101A0}, {0x101D0, 0x101FC}, {0x101FD, 0x101FD}, {0x10280, 0x1029C}, {0x102A0, 0x102D0}, {0x102E0, 0x102E0}, {0x102E1, 0x102FB}, {0x10300, 0x1031F}, {0x10320, 0x10323}, {0x10330, 0x10340}, {0x10341, 0x10341}, {0x10342, 0x10349}, {0x1034A, 0x1034A}, {0x10350, 0x10375}, {0x10376, 0x1037A}, {0x10380, 0x1039D}, {0x1039F, 0x1039F}, {0x103A0, 0x103C3}, {0x103C8, 0x103CF}, {0x103D0, 0x103D0}, {0x103D1, 0x103D5}, {0x10400, 0x1044F}, {0x10450, 0x1047F}, {0x10480, 0x1049D}, {0x104A0, 0x104A9}, {0x104B0, 0x104D3}, {0x104D8, 0x104FB}, {0x10500, 0x10527}, {0x10530, 0x10563}, {0x1056F, 0x1056F}, {0x10600, 0x10736}, {0x10740, 0x10755}, {0x10760, 0x10767}, {0x10800, 0x10805}, {0x10808, 0x10808}, {0x1080A, 0x10835}, {0x10837, 0x10838}, {0x1083C, 0x1083C}, {0x1083F, 0x1083F}, {0x10840, 0x10855}, {0x10857, 0x10857}, {0x10858, 0x1085F}, {0x10860, 0x10876}, {0x10877, 0x10878}, {0x10879, 0x1087F}, {0x10880, 0x1089E}, {0x108A7, 0x108AF}, {0x108E0, 0x108F2}, {0x108F4, 0x108F5}, {0x108FB, 0x108FF}, {0x10900, 0x10915}, {0x10916, 0x1091B}, {0x1091F, 0x1091F}, {0x10920, 0x10939}, {0x1093F, 0x1093F}, {0x10980, 0x1099F}, {0x109A0, 0x109B7}, {0x109BC, 0x109BD}, {0x109BE, 0x109BF}, {0x109C0, 0x109CF}, {0x109D2, 0x109FF}, {0x10A00, 0x10A00}, {0x10A01, 0x10A03}, {0x10A05, 0x10A06}, {0x10A0C, 0x10A0F}, {0x10A10, 0x10A13}, {0x10A15, 0x10A17}, {0x10A19, 0x10A33}, {0x10A38, 0x10A3A}, {0x10A3F, 0x10A3F}, {0x10A40, 0x10A47}, {0x10A50, 0x10A58}, {0x10A60, 0x10A7C}, {0x10A7D, 0x10A7E}, {0x10A7F, 0x10A7F}, {0x10A80, 0x10A9C}, {0x10A9D, 0x10A9F}, {0x10AC0, 0x10AC7}, {0x10AC8, 0x10AC8}, {0x10AC9, 0x10AE4}, {0x10AE5, 0x10AE6}, {0x10AEB, 0x10AEF}, {0x10AF0, 0x10AF6}, {0x10B00, 0x10B35}, {0x10B39, 0x10B3F}, {0x10B40, 0x10B55}, {0x10B58, 0x10B5F}, {0x10B60, 0x10B72}, {0x10B78, 0x10B7F}, {0x10B80, 0x10B91}, {0x10B99, 0x10B9C}, {0x10BA9, 0x10BAF}, {0x10C00, 0x10C48}, {0x10C80, 0x10CB2}, {0x10CC0, 0x10CF2}, {0x10CFA, 0x10CFF}, {0x10E60, 0x10E7E}, {0x11000, 0x11000}, {0x11001, 0x11001}, {0x11002, 0x11002}, {0x11003, 0x11037}, {0x11038, 0x11046}, {0x11047, 0x1104D}, {0x11052, 0x11065}, {0x11066, 0x1106F}, {0x1107F, 0x1107F}, {0x11080, 0x11081}, {0x11082, 0x11082}, {0x11083, 0x110AF}, {0x110B0, 0x110B2}, {0x110B3, 0x110B6}, {0x110B7, 0x110B8}, {0x110B9, 0x110BA}, {0x110BB, 0x110BC}, {0x110BD, 0x110BD}, {0x110BE, 0x110C1}, {0x110D0, 0x110E8}, {0x110F0, 0x110F9}, {0x11100, 0x11102}, {0x11103, 0x11126}, {0x11127, 0x1112B}, {0x1112C, 0x1112C}, {0x1112D, 0x11134}, {0x11136, 0x1113F}, {0x11140, 0x11143}, {0x11150, 0x11172}, {0x11173, 0x11173}, {0x11174, 0x11175}, {0x11176, 0x11176}, {0x11180, 0x11181}, {0x11182, 0x11182}, {0x11183, 0x111B2}, {0x111B3, 0x111B5}, {0x111B6, 0x111BE}, {0x111BF, 0x111C0}, {0x111C1, 0x111C4}, {0x111C5, 0x111C9}, {0x111CA, 0x111CC}, {0x111CD, 0x111CD}, {0x111D0, 0x111D9}, {0x111DA, 0x111DA}, {0x111DB, 0x111DB}, {0x111DC, 0x111DC}, {0x111DD, 0x111DF}, {0x111E1, 0x111F4}, {0x11200, 0x11211}, {0x11213, 0x1122B}, {0x1122C, 0x1122E}, {0x1122F, 0x11231}, {0x11232, 0x11233}, {0x11234, 0x11234}, {0x11235, 0x11235}, {0x11236, 0x11237}, {0x11238, 0x1123D}, {0x1123E, 0x1123E}, {0x11280, 0x11286}, {0x11288, 0x11288}, {0x1128A, 0x1128D}, {0x1128F, 0x1129D}, {0x1129F, 0x112A8}, {0x112A9, 0x112A9}, {0x112B0, 0x112DE}, {0x112DF, 0x112DF}, {0x112E0, 0x112E2}, {0x112E3, 0x112EA}, {0x112F0, 0x112F9}, {0x11300, 0x11301}, {0x11302, 0x11303}, {0x11305, 0x1130C}, {0x1130F, 0x11310}, {0x11313, 0x11328}, {0x1132A, 0x11330}, {0x11332, 0x11333}, {0x11335, 0x11339}, {0x1133C, 0x1133C}, {0x1133D, 0x1133D}, {0x1133E, 0x1133F}, {0x11340, 0x11340}, {0x11341, 0x11344}, {0x11347, 0x11348}, {0x1134B, 0x1134D}, {0x11350, 0x11350}, {0x11357, 0x11357}, {0x1135D, 0x11361}, {0x11362, 0x11363}, {0x11366, 0x1136C}, {0x11370, 0x11374}, {0x11400, 0x11434}, {0x11435, 0x11437}, {0x11438, 0x1143F}, {0x11440, 0x11441}, {0x11442, 0x11444}, {0x11445, 0x11445}, {0x11446, 0x11446}, {0x11447, 0x1144A}, {0x1144B, 0x1144F}, {0x11450, 0x11459}, {0x1145B, 0x1145B}, {0x1145D, 0x1145D}, {0x11480, 0x114AF}, {0x114B0, 0x114B2}, {0x114B3, 0x114B8}, {0x114B9, 0x114B9}, {0x114BA, 0x114BA}, {0x114BB, 0x114BE}, {0x114BF, 0x114C0}, {0x114C1, 0x114C1}, {0x114C2, 0x114C3}, {0x114C4, 0x114C5}, {0x114C6, 0x114C6}, {0x114C7, 0x114C7}, {0x114D0, 0x114D9}, {0x11580, 0x115AE}, {0x115AF, 0x115B1}, {0x115B2, 0x115B5}, {0x115B8, 0x115BB}, {0x115BC, 0x115BD}, {0x115BE, 0x115BE}, {0x115BF, 0x115C0}, {0x115C1, 0x115D7}, {0x115D8, 0x115DB}, {0x115DC, 0x115DD}, {0x11600, 0x1162F}, {0x11630, 0x11632}, {0x11633, 0x1163A}, {0x1163B, 0x1163C}, {0x1163D, 0x1163D}, {0x1163E, 0x1163E}, {0x1163F, 0x11640}, {0x11641, 0x11643}, {0x11644, 0x11644}, {0x11650, 0x11659}, {0x11660, 0x1166C}, {0x11680, 0x116AA}, {0x116AB, 0x116AB}, {0x116AC, 0x116AC}, {0x116AD, 0x116AD}, {0x116AE, 0x116AF}, {0x116B0, 0x116B5}, {0x116B6, 0x116B6}, {0x116B7, 0x116B7}, {0x116C0, 0x116C9}, {0x11700, 0x11719}, {0x1171D, 0x1171F}, {0x11720, 0x11721}, {0x11722, 0x11725}, {0x11726, 0x11726}, {0x11727, 0x1172B}, {0x11730, 0x11739}, {0x1173A, 0x1173B}, {0x1173C, 0x1173E}, {0x1173F, 0x1173F}, {0x118A0, 0x118DF}, {0x118E0, 0x118E9}, {0x118EA, 0x118F2}, {0x118FF, 0x118FF}, {0x11AC0, 0x11AF8}, {0x11C00, 0x11C08}, {0x11C0A, 0x11C2E}, {0x11C2F, 0x11C2F}, {0x11C30, 0x11C36}, {0x11C38, 0x11C3D}, {0x11C3E, 0x11C3E}, {0x11C3F, 0x11C3F}, {0x11C40, 0x11C40}, {0x11C41, 0x11C45}, {0x11C50, 0x11C59}, {0x11C5A, 0x11C6C}, {0x11C70, 0x11C71}, {0x11C72, 0x11C8F}, {0x11C92, 0x11CA7}, {0x11CA9, 0x11CA9}, {0x11CAA, 0x11CB0}, {0x11CB1, 0x11CB1}, {0x11CB2, 0x11CB3}, {0x11CB4, 0x11CB4}, {0x11CB5, 0x11CB6}, {0x12000, 0x12399}, {0x12400, 0x1246E}, {0x12470, 0x12474}, {0x12480, 0x12543}, {0x13000, 0x1342E}, {0x14400, 0x14646}, {0x16800, 0x16A38}, {0x16A40, 0x16A5E}, {0x16A60, 0x16A69}, {0x16A6E, 0x16A6F}, {0x16AD0, 0x16AED}, {0x16AF0, 0x16AF4}, {0x16AF5, 0x16AF5}, {0x16B00, 0x16B2F}, {0x16B30, 0x16B36}, {0x16B37, 0x16B3B}, {0x16B3C, 0x16B3F}, {0x16B40, 0x16B43}, {0x16B44, 0x16B44}, {0x16B45, 0x16B45}, {0x16B50, 0x16B59}, {0x16B5B, 0x16B61}, {0x16B63, 0x16B77}, {0x16B7D, 0x16B8F}, {0x16F00, 0x16F44}, {0x16F50, 0x16F50}, {0x16F51, 0x16F7E}, {0x16F8F, 0x16F92}, {0x16F93, 0x16F9F}, {0x1BC00, 0x1BC6A}, {0x1BC70, 0x1BC7C}, {0x1BC80, 0x1BC88}, {0x1BC90, 0x1BC99}, {0x1BC9C, 0x1BC9C}, {0x1BC9D, 0x1BC9E}, {0x1BC9F, 0x1BC9F}, {0x1BCA0, 0x1BCA3}, {0x1D000, 0x1D0F5}, {0x1D100, 0x1D126}, {0x1D129, 0x1D164}, {0x1D165, 0x1D166}, {0x1D167, 0x1D169}, {0x1D16A, 0x1D16C}, {0x1D16D, 0x1D172}, {0x1D173, 0x1D17A}, {0x1D17B, 0x1D182}, {0x1D183, 0x1D184}, {0x1D185, 0x1D18B}, {0x1D18C, 0x1D1A9}, {0x1D1AA, 0x1D1AD}, {0x1D1AE, 0x1D1E8}, {0x1D200, 0x1D241}, {0x1D242, 0x1D244}, {0x1D245, 0x1D245}, {0x1D300, 0x1D356}, {0x1D360, 0x1D371}, {0x1D400, 0x1D454}, {0x1D456, 0x1D49C}, {0x1D49E, 0x1D49F}, {0x1D4A2, 0x1D4A2}, {0x1D4A5, 0x1D4A6}, {0x1D4A9, 0x1D4AC}, {0x1D4AE, 0x1D4B9}, {0x1D4BB, 0x1D4BB}, {0x1D4BD, 0x1D4C3}, {0x1D4C5, 0x1D505}, {0x1D507, 0x1D50A}, {0x1D50D, 0x1D514}, {0x1D516, 0x1D51C}, {0x1D51E, 0x1D539}, {0x1D53B, 0x1D53E}, {0x1D540, 0x1D544}, {0x1D546, 0x1D546}, {0x1D54A, 0x1D550}, {0x1D552, 0x1D6A5}, {0x1D6A8, 0x1D6C0}, {0x1D6C1, 0x1D6C1}, {0x1D6C2, 0x1D6DA}, {0x1D6DB, 0x1D6DB}, {0x1D6DC, 0x1D6FA}, {0x1D6FB, 0x1D6FB}, {0x1D6FC, 0x1D714}, {0x1D715, 0x1D715}, {0x1D716, 0x1D734}, {0x1D735, 0x1D735}, {0x1D736, 0x1D74E}, {0x1D74F, 0x1D74F}, {0x1D750, 0x1D76E}, {0x1D76F, 0x1D76F}, {0x1D770, 0x1D788}, {0x1D789, 0x1D789}, {0x1D78A, 0x1D7A8}, {0x1D7A9, 0x1D7A9}, {0x1D7AA, 0x1D7C2}, {0x1D7C3, 0x1D7C3}, {0x1D7C4, 0x1D7CB}, {0x1D7CE, 0x1D7FF}, {0x1D800, 0x1D9FF}, {0x1DA00, 0x1DA36}, {0x1DA37, 0x1DA3A}, {0x1DA3B, 0x1DA6C}, {0x1DA6D, 0x1DA74}, {0x1DA75, 0x1DA75}, {0x1DA76, 0x1DA83}, {0x1DA84, 0x1DA84}, {0x1DA85, 0x1DA86}, {0x1DA87, 0x1DA8B}, {0x1DA9B, 0x1DA9F}, {0x1DAA1, 0x1DAAF}, {0x1E000, 0x1E006}, {0x1E008, 0x1E018}, {0x1E01B, 0x1E021}, {0x1E023, 0x1E024}, {0x1E026, 0x1E02A}, {0x1E800, 0x1E8C4}, {0x1E8C7, 0x1E8CF}, {0x1E8D0, 0x1E8D6}, {0x1E900, 0x1E943}, {0x1E944, 0x1E94A}, {0x1E950, 0x1E959}, {0x1E95E, 0x1E95F}, {0x1EE00, 0x1EE03}, {0x1EE05, 0x1EE1F}, {0x1EE21, 0x1EE22}, {0x1EE24, 0x1EE24}, {0x1EE27, 0x1EE27}, {0x1EE29, 0x1EE32}, {0x1EE34, 0x1EE37}, {0x1EE39, 0x1EE39}, {0x1EE3B, 0x1EE3B}, {0x1EE42, 0x1EE42}, {0x1EE47, 0x1EE47}, {0x1EE49, 0x1EE49}, {0x1EE4B, 0x1EE4B}, {0x1EE4D, 0x1EE4F}, {0x1EE51, 0x1EE52}, {0x1EE54, 0x1EE54}, {0x1EE57, 0x1EE57}, {0x1EE59, 0x1EE59}, {0x1EE5B, 0x1EE5B}, {0x1EE5D, 0x1EE5D}, {0x1EE5F, 0x1EE5F}, {0x1EE61, 0x1EE62}, {0x1EE64, 0x1EE64}, {0x1EE67, 0x1EE6A}, {0x1EE6C, 0x1EE72}, {0x1EE74, 0x1EE77}, {0x1EE79, 0x1EE7C}, {0x1EE7E, 0x1EE7E}, {0x1EE80, 0x1EE89}, {0x1EE8B, 0x1EE9B}, {0x1EEA1, 0x1EEA3}, {0x1EEA5, 0x1EEA9}, {0x1EEAB, 0x1EEBB}, {0x1EEF0, 0x1EEF1}, {0x1F000, 0x1F003}, {0x1F005, 0x1F02B}, {0x1F030, 0x1F093}, {0x1F0A0, 0x1F0AE}, {0x1F0B1, 0x1F0BF}, {0x1F0C1, 0x1F0CE}, {0x1F0D1, 0x1F0F5}, {0x1F10B, 0x1F10C}, {0x1F12E, 0x1F12E}, {0x1F16A, 0x1F16B}, {0x1F1E6, 0x1F1FF}, {0x1F321, 0x1F32C}, {0x1F336, 0x1F336}, {0x1F37D, 0x1F37D}, {0x1F394, 0x1F39F}, {0x1F3CB, 0x1F3CE}, {0x1F3D4, 0x1F3DF}, {0x1F3F1, 0x1F3F3}, {0x1F3F5, 0x1F3F7}, {0x1F43F, 0x1F43F}, {0x1F441, 0x1F441}, {0x1F4FD, 0x1F4FE}, {0x1F53E, 0x1F54A}, {0x1F54F, 0x1F54F}, {0x1F568, 0x1F579}, {0x1F57B, 0x1F594}, {0x1F597, 0x1F5A3}, {0x1F5A5, 0x1F5FA}, {0x1F650, 0x1F67F}, {0x1F6C6, 0x1F6CB}, {0x1F6CD, 0x1F6CF}, {0x1F6E0, 0x1F6EA}, {0x1F6F0, 0x1F6F3}, {0x1F700, 0x1F773}, {0x1F780, 0x1F7D4}, {0x1F800, 0x1F80B}, {0x1F810, 0x1F847}, {0x1F850, 0x1F859}, {0x1F860, 0x1F887}, {0x1F890, 0x1F8AD}, {0xE0001, 0xE0001}, {0xE0020, 0xE007F}, } // Condition have flag EastAsianWidth whether the current locale is CJK or not. type Condition struct { EastAsianWidth bool } // NewCondition return new instance of Condition which is current locale. func NewCondition() *Condition { return &Condition{EastAsianWidth} } // RuneWidth returns the number of cells in r. // See http://www.unicode.org/reports/tr11/ func (c *Condition) RuneWidth(r rune) int { switch { case r < 0 || r > 0x10FFFF || inTables(r, nonprint, combining, notassigned): return 0 case (c.EastAsianWidth && IsAmbiguousWidth(r)) || inTables(r, doublewidth, emoji): return 2 default: return 1 } } // StringWidth return width as you can see func (c *Condition) StringWidth(s string) (width int) { for _, r := range []rune(s) { width += c.RuneWidth(r) } return width } // Truncate return string truncated with w cells func (c *Condition) Truncate(s string, w int, tail string) string { if c.StringWidth(s) <= w { return s } r := []rune(s) tw := c.StringWidth(tail) w -= tw width := 0 i := 0 for ; i < len(r); i++ { cw := c.RuneWidth(r[i]) if width+cw > w { break } width += cw } return string(r[0:i]) + tail } // Wrap return string wrapped with w cells func (c *Condition) Wrap(s string, w int) string { width := 0 out := "" for _, r := range []rune(s) { cw := RuneWidth(r) if r == '\n' { out += string(r) width = 0 continue } else if width+cw > w { out += "\n" width = 0 out += string(r) width += cw continue } out += string(r) width += cw } return out } // FillLeft return string filled in left by spaces in w cells func (c *Condition) FillLeft(s string, w int) string { width := c.StringWidth(s) count := w - width if count > 0 { b := make([]byte, count) for i := range b { b[i] = ' ' } return string(b) + s } return s } // FillRight return string filled in left by spaces in w cells func (c *Condition) FillRight(s string, w int) string { width := c.StringWidth(s) count := w - width if count > 0 { b := make([]byte, count) for i := range b { b[i] = ' ' } return s + string(b) } return s } // RuneWidth returns the number of cells in r. // See http://www.unicode.org/reports/tr11/ func RuneWidth(r rune) int { return DefaultCondition.RuneWidth(r) } // IsAmbiguousWidth returns whether is ambiguous width or not. func IsAmbiguousWidth(r rune) bool { return inTables(r, private, ambiguous) } // IsNeutralWidth returns whether is neutral width or not. func IsNeutralWidth(r rune) bool { return inTable(r, neutral) } // StringWidth return width as you can see func StringWidth(s string) (width int) { return DefaultCondition.StringWidth(s) } // Truncate return string truncated with w cells func Truncate(s string, w int, tail string) string { return DefaultCondition.Truncate(s, w, tail) } // Wrap return string wrapped with w cells func Wrap(s string, w int) string { return DefaultCondition.Wrap(s, w) } // FillLeft return string filled in left by spaces in w cells func FillLeft(s string, w int) string { return DefaultCondition.FillLeft(s, w) } // FillRight return string filled in left by spaces in w cells func FillRight(s string, w int) string { return DefaultCondition.FillRight(s, w) } ================================================ FILE: vendor/github.com/mattn/go-runewidth/runewidth_js.go ================================================ // +build js package runewidth func IsEastAsian() bool { // TODO: Implement this for the web. Detect east asian in a compatible way, and return true. return false } ================================================ FILE: vendor/github.com/mattn/go-runewidth/runewidth_posix.go ================================================ // +build !windows,!js package runewidth import ( "os" "regexp" "strings" ) var reLoc = regexp.MustCompile(`^[a-z][a-z][a-z]?(?:_[A-Z][A-Z])?\.(.+)`) var mblenTable = map[string]int{ "utf-8": 6, "utf8": 6, "jis": 8, "eucjp": 3, "euckr": 2, "euccn": 2, "sjis": 2, "cp932": 2, "cp51932": 2, "cp936": 2, "cp949": 2, "cp950": 2, "big5": 2, "gbk": 2, "gb2312": 2, } func isEastAsian(locale string) bool { charset := strings.ToLower(locale) r := reLoc.FindStringSubmatch(locale) if len(r) == 2 { charset = strings.ToLower(r[1]) } if strings.HasSuffix(charset, "@cjk_narrow") { return false } for pos, b := range []byte(charset) { if b == '@' { charset = charset[:pos] break } } max := 1 if m, ok := mblenTable[charset]; ok { max = m } if max > 1 && (charset[0] != 'u' || strings.HasPrefix(locale, "ja") || strings.HasPrefix(locale, "ko") || strings.HasPrefix(locale, "zh")) { return true } return false } // IsEastAsian return true if the current locale is CJK func IsEastAsian() bool { locale := os.Getenv("LC_CTYPE") if locale == "" { locale = os.Getenv("LANG") } // ignore C locale if locale == "POSIX" || locale == "C" { return false } if len(locale) > 1 && locale[0] == 'C' && (locale[1] == '.' || locale[1] == '-') { return false } return isEastAsian(locale) } ================================================ FILE: vendor/github.com/mattn/go-runewidth/runewidth_test.go ================================================ package runewidth import ( "sort" "testing" ) var _ sort.Interface = (*table)(nil) func (t table) Len() int { return len(t) } func (t table) Less(i, j int) bool { return t[i].first < t[j].first } func (t *table) Swap(i, j int) { (*t)[i], (*t)[j] = (*t)[j], (*t)[i] } var tables = []table{ private, nonprint, combining, doublewidth, ambiguous, emoji, notassigned, neutral, } func TestSorted(t *testing.T) { for _, tbl := range tables { if !sort.IsSorted(&tbl) { t.Errorf("not sorted") } } } var runewidthtests = []struct { in rune out int eaout int }{ {'世', 2, 2}, {'界', 2, 2}, {'セ', 1, 1}, {'カ', 1, 1}, {'イ', 1, 1}, {'☆', 1, 2}, // double width in ambiguous {'\x00', 0, 0}, {'\x01', 0, 0}, {'\u0300', 0, 0}, } func TestRuneWidth(t *testing.T) { c := NewCondition() for _, tt := range runewidthtests { if out := c.RuneWidth(tt.in); out != tt.out { t.Errorf("RuneWidth(%q) = %d, want %d", tt.in, out, tt.out) } } c.EastAsianWidth = true for _, tt := range runewidthtests { if out := c.RuneWidth(tt.in); out != tt.eaout { t.Errorf("RuneWidth(%q) = %d, want %d", tt.in, out, tt.eaout) } } } var isambiguouswidthtests = []struct { in rune out bool }{ {'世', false}, {'■', true}, {'界', false}, {'○', true}, {'㈱', false}, {'①', true}, {'②', true}, {'③', true}, {'④', true}, {'⑤', true}, {'⑥', true}, {'⑦', true}, {'⑧', true}, {'⑨', true}, {'⑩', true}, {'⑪', true}, {'⑫', true}, {'⑬', true}, {'⑭', true}, {'⑮', true}, {'⑯', true}, {'⑰', true}, {'⑱', true}, {'⑲', true}, {'⑳', true}, {'☆', true}, } func TestIsAmbiguousWidth(t *testing.T) { for _, tt := range isambiguouswidthtests { if out := IsAmbiguousWidth(tt.in); out != tt.out { t.Errorf("IsAmbiguousWidth(%q) = %v, want %v", tt.in, out, tt.out) } } } var stringwidthtests = []struct { in string out int eaout int }{ {"■㈱の世界①", 10, 12}, {"スター☆", 7, 8}, {"つのだ☆HIRO", 11, 12}, } func TestStringWidth(t *testing.T) { c := NewCondition() for _, tt := range stringwidthtests { if out := c.StringWidth(tt.in); out != tt.out { t.Errorf("StringWidth(%q) = %q, want %q", tt.in, out, tt.out) } } c.EastAsianWidth = true for _, tt := range stringwidthtests { if out := c.StringWidth(tt.in); out != tt.eaout { t.Errorf("StringWidth(%q) = %q, want %q", tt.in, out, tt.eaout) } } } func TestStringWidthInvalid(t *testing.T) { s := "こんにちわ\x00世界" if out := StringWidth(s); out != 14 { t.Errorf("StringWidth(%q) = %q, want %q", s, out, 14) } } func TestTruncateSmaller(t *testing.T) { s := "あいうえお" expected := "あいうえお" if out := Truncate(s, 10, "..."); out != expected { t.Errorf("Truncate(%q) = %q, want %q", s, out, expected) } } func TestTruncate(t *testing.T) { s := "あいうえおあいうえおえおおおおおおおおおおおおおおおおおおおおおおおおおおおおおお" expected := "あいうえおあいうえおえおおおおおおおおおおおおおおおおおおおおおおおおおおお..." out := Truncate(s, 80, "...") if out != expected { t.Errorf("Truncate(%q) = %q, want %q", s, out, expected) } width := StringWidth(out) if width != 79 { t.Errorf("width of Truncate(%q) should be %d, but %d", s, 79, width) } } func TestTruncateFit(t *testing.T) { s := "aあいうえおあいうえおえおおおおおおおおおおおおおおおおおおおおおおおおおおおおおお" expected := "aあいうえおあいうえおえおおおおおおおおおおおおおおおおおおおおおおおおおおお..." out := Truncate(s, 80, "...") if out != expected { t.Errorf("Truncate(%q) = %q, want %q", s, out, expected) } width := StringWidth(out) if width != 80 { t.Errorf("width of Truncate(%q) should be %d, but %d", s, 80, width) } } func TestTruncateJustFit(t *testing.T) { s := "あいうえおあいうえおえおおおおおおおおおおおおおおおおおおおおおおおおおおおおお" expected := "あいうえおあいうえおえおおおおおおおおおおおおおおおおおおおおおおおおおおおおお" out := Truncate(s, 80, "...") if out != expected { t.Errorf("Truncate(%q) = %q, want %q", s, out, expected) } width := StringWidth(out) if width != 80 { t.Errorf("width of Truncate(%q) should be %d, but %d", s, 80, width) } } func TestWrap(t *testing.T) { s := `東京特許許可局局長はよく柿喰う客だ/東京特許許可局局長はよく柿喰う客だ 123456789012345678901234567890 END` expected := `東京特許許可局局長はよく柿喰う 客だ/東京特許許可局局長はよく 柿喰う客だ 123456789012345678901234567890 END` if out := Wrap(s, 30); out != expected { t.Errorf("Wrap(%q) = %q, want %q", s, out, expected) } } func TestTruncateNoNeeded(t *testing.T) { s := "あいうえおあい" expected := "あいうえおあい" if out := Truncate(s, 80, "..."); out != expected { t.Errorf("Truncate(%q) = %q, want %q", s, out, expected) } } var isneutralwidthtests = []struct { in rune out bool }{ {'→', false}, {'┊', false}, {'┈', false}, {'~', false}, {'└', false}, {'⣀', true}, {'⣀', true}, } func TestIsNeutralWidth(t *testing.T) { for _, tt := range isneutralwidthtests { if out := IsNeutralWidth(tt.in); out != tt.out { t.Errorf("IsNeutralWidth(%q) = %v, want %v", tt.in, out, tt.out) } } } func TestFillLeft(t *testing.T) { s := "あxいうえお" expected := " あxいうえお" if out := FillLeft(s, 15); out != expected { t.Errorf("FillLeft(%q) = %q, want %q", s, out, expected) } } func TestFillLeftFit(t *testing.T) { s := "あいうえお" expected := "あいうえお" if out := FillLeft(s, 10); out != expected { t.Errorf("FillLeft(%q) = %q, want %q", s, out, expected) } } func TestFillRight(t *testing.T) { s := "あxいうえお" expected := "あxいうえお " if out := FillRight(s, 15); out != expected { t.Errorf("FillRight(%q) = %q, want %q", s, out, expected) } } func TestFillRightFit(t *testing.T) { s := "あいうえお" expected := "あいうえお" if out := FillRight(s, 10); out != expected { t.Errorf("FillRight(%q) = %q, want %q", s, out, expected) } } ================================================ FILE: vendor/github.com/mattn/go-runewidth/runewidth_windows.go ================================================ package runewidth import ( "syscall" ) var ( kernel32 = syscall.NewLazyDLL("kernel32") procGetConsoleOutputCP = kernel32.NewProc("GetConsoleOutputCP") ) // IsEastAsian return true if the current locale is CJK func IsEastAsian() bool { r1, _, _ := procGetConsoleOutputCP.Call() if r1 == 0 { return false } switch int(r1) { case 932, 51932, 936, 949, 950: return true } return false } ================================================ FILE: vendor/github.com/mitchellh/go-wordwrap/LICENSE.md ================================================ The MIT License (MIT) Copyright (c) 2014 Mitchell Hashimoto 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. ================================================ FILE: vendor/github.com/mitchellh/go-wordwrap/README.md ================================================ # go-wordwrap `go-wordwrap` (Golang package: `wordwrap`) is a package for Go that automatically wraps words into multiple lines. The primary use case for this is in formatting CLI output, but of course word wrapping is a generally useful thing to do. ## Installation and Usage Install using `go get github.com/mitchellh/go-wordwrap`. Full documentation is available at http://godoc.org/github.com/mitchellh/go-wordwrap Below is an example of its usage ignoring errors: ```go wrapped := wordwrap.WrapString("foo bar baz", 3) fmt.Println(wrapped) ``` Would output: ``` foo bar baz ``` ## Word Wrap Algorithm This library doesn't use any clever algorithm for word wrapping. The wrapping is actually very naive: whenever there is whitespace or an explicit linebreak. The goal of this library is for word wrapping CLI output, so the input is typically pretty well controlled human language. Because of this, the naive approach typically works just fine. In the future, we'd like to make the algorithm more advanced. We would do so without breaking the API. ================================================ FILE: vendor/github.com/mitchellh/go-wordwrap/wordwrap.go ================================================ package wordwrap import ( "bytes" "unicode" ) // WrapString wraps the given string within lim width in characters. // // Wrapping is currently naive and only happens at white-space. A future // version of the library will implement smarter wrapping. This means that // pathological cases can dramatically reach past the limit, such as a very // long word. func WrapString(s string, lim uint) string { // Initialize a buffer with a slightly larger size to account for breaks init := make([]byte, 0, len(s)) buf := bytes.NewBuffer(init) var current uint var wordBuf, spaceBuf bytes.Buffer for _, char := range s { if char == '\n' { if wordBuf.Len() == 0 { if current+uint(spaceBuf.Len()) > lim { current = 0 } else { current += uint(spaceBuf.Len()) spaceBuf.WriteTo(buf) } spaceBuf.Reset() } else { current += uint(spaceBuf.Len() + wordBuf.Len()) spaceBuf.WriteTo(buf) spaceBuf.Reset() wordBuf.WriteTo(buf) wordBuf.Reset() } buf.WriteRune(char) current = 0 } else if unicode.IsSpace(char) { if spaceBuf.Len() == 0 || wordBuf.Len() > 0 { current += uint(spaceBuf.Len() + wordBuf.Len()) spaceBuf.WriteTo(buf) spaceBuf.Reset() wordBuf.WriteTo(buf) wordBuf.Reset() } spaceBuf.WriteRune(char) } else { wordBuf.WriteRune(char) if current+uint(spaceBuf.Len()+wordBuf.Len()) > lim && uint(wordBuf.Len()) < lim { buf.WriteRune('\n') current = 0 spaceBuf.Reset() } } } if wordBuf.Len() == 0 { if current+uint(spaceBuf.Len()) <= lim { spaceBuf.WriteTo(buf) } } else { spaceBuf.WriteTo(buf) wordBuf.WriteTo(buf) } return buf.String() } ================================================ FILE: vendor/github.com/mitchellh/go-wordwrap/wordwrap_test.go ================================================ package wordwrap import ( "testing" ) func TestWrapString(t *testing.T) { cases := []struct { Input, Output string Lim uint }{ // A simple word passes through. { "foo", "foo", 4, }, // A single word that is too long passes through. // We do not break words. { "foobarbaz", "foobarbaz", 4, }, // Lines are broken at whitespace. { "foo bar baz", "foo\nbar\nbaz", 4, }, // Lines are broken at whitespace, even if words // are too long. We do not break words. { "foo bars bazzes", "foo\nbars\nbazzes", 4, }, // A word that would run beyond the width is wrapped. { "fo sop", "fo\nsop", 4, }, // Whitespace that trails a line and fits the width // passes through, as does whitespace prefixing an // explicit line break. A tab counts as one character. { "foo\nb\t r\n baz", "foo\nb\t r\n baz", 4, }, // Trailing whitespace is removed if it doesn't fit the width. // Runs of whitespace on which a line is broken are removed. { "foo \nb ar ", "foo\nb\nar", 4, }, // An explicit line break at the end of the input is preserved. { "foo bar baz\n", "foo\nbar\nbaz\n", 4, }, // Explicit break are always preserved. { "\nfoo bar\n\n\nbaz\n", "\nfoo\nbar\n\n\nbaz\n", 4, }, // Complete example: { " This is a list: \n\n\t* foo\n\t* bar\n\n\n\t* baz \nBAM ", " This\nis a\nlist: \n\n\t* foo\n\t* bar\n\n\n\t* baz\nBAM", 6, }, } for i, tc := range cases { actual := WrapString(tc.Input, tc.Lim) if actual != tc.Output { t.Fatalf("Case %d Input:\n\n`%s`\n\nActual Output:\n\n`%s`", i, tc.Input, actual) } } } ================================================ FILE: vendor/github.com/nsf/termbox-go/AUTHORS ================================================ # Please keep this file sorted. Georg Reinke nsf ================================================ FILE: vendor/github.com/nsf/termbox-go/LICENSE ================================================ Copyright (C) 2012 termbox-go authors 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. ================================================ FILE: vendor/github.com/nsf/termbox-go/README.md ================================================ ## Termbox Termbox is a library that provides a minimalistic API which allows the programmer to write text-based user interfaces. The library is crossplatform and has both terminal-based implementations on *nix operating systems and a winapi console based implementation for windows operating systems. The basic idea is an abstraction of the greatest common subset of features available on all major terminals and other terminal-like APIs in a minimalistic fashion. Small API means it is easy to implement, test, maintain and learn it, that's what makes the termbox a distinct library in its area. ### Installation Install and update this go package with `go get -u github.com/nsf/termbox-go` ### Examples For examples of what can be done take a look at demos in the _demos directory. You can try them with go run: `go run _demos/keyboard.go` There are also some interesting projects using termbox-go: - [godit](https://github.com/nsf/godit) is an emacsish lightweight text editor written using termbox. - [gomatrix](https://github.com/GeertJohan/gomatrix) connects to The Matrix and displays its data streams in your terminal. - [gotetris](https://github.com/jjinux/gotetris) is an implementation of Tetris. - [sokoban-go](https://github.com/rn2dy/sokoban-go) is an implementation of sokoban game. - [hecate](https://github.com/evanmiller/hecate) is a hex editor designed by Satan. - [httopd](https://github.com/verdverm/httopd) is top for httpd logs. - [mop](https://github.com/mop-tracker/mop) is stock market tracker for hackers. - [termui](https://github.com/gizak/termui) is a terminal dashboard. - [termloop](https://github.com/JoelOtter/termloop) is a terminal game engine. - [xterm-color-chart](https://github.com/kutuluk/xterm-color-chart) is a XTerm 256 color chart. - [gocui](https://github.com/jroimartin/gocui) is a minimalist Go library aimed at creating console user interfaces. - [dry](https://github.com/moncho/dry) is an interactive cli to manage Docker containers. - [pxl](https://github.com/ichinaski/pxl) displays images in the terminal. - [snake-game](https://github.com/DyegoCosta/snake-game) is an implementation of the Snake game. - [gone](https://github.com/guillaumebreton/gone) is a CLI pomodoro® timer. - [Spoof.go](https://github.com/sabey/spoofgo) controllable movement spoofing from the cli - [lf](https://github.com/gokcehan/lf) is a terminal file manager - [rat](https://github.com/ericfreese/rat) lets you compose shell commands to build terminal applications. - [httplab](https://github.com/gchaincl/httplab) An interactive web server. - [tetris](https://github.com/MichaelS11/tetris) Go Tetris with AI option - [wot](https://github.com/kyu-suke/wot) Wait time during command is completed. - [2048-go](https://github.com/1984weed/2048-go) is 2048 in Go - [jv](https://github.com/maxzender/jv) helps you view JSON on the command-line. - [pinger](https://github.com/hirose31/pinger) helps you to monitor numerous hosts using ICMP ECHO_REQUEST. - [vixl44](https://github.com/sebashwa/vixl44) lets you create pixel art inside your terminal using vim movements ### API reference [godoc.org/github.com/nsf/termbox-go](http://godoc.org/github.com/nsf/termbox-go) ================================================ FILE: vendor/github.com/nsf/termbox-go/api.go ================================================ // +build !windows package termbox import "github.com/mattn/go-runewidth" import "fmt" import "os" import "os/signal" import "syscall" import "runtime" // public API // Initializes termbox library. This function should be called before any other functions. // After successful initialization, the library must be finalized using 'Close' function. // // Example usage: // err := termbox.Init() // if err != nil { // panic(err) // } // defer termbox.Close() func Init() error { var err error out, err = os.OpenFile("/dev/tty", syscall.O_WRONLY, 0) if err != nil { return err } in, err = syscall.Open("/dev/tty", syscall.O_RDONLY, 0) if err != nil { return err } err = setup_term() if err != nil { return fmt.Errorf("termbox: error while reading terminfo data: %v", err) } signal.Notify(sigwinch, syscall.SIGWINCH) signal.Notify(sigio, syscall.SIGIO) _, err = fcntl(in, syscall.F_SETFL, syscall.O_ASYNC|syscall.O_NONBLOCK) if err != nil { return err } _, err = fcntl(in, syscall.F_SETOWN, syscall.Getpid()) if runtime.GOOS != "darwin" && err != nil { return err } err = tcgetattr(out.Fd(), &orig_tios) if err != nil { return err } tios := orig_tios tios.Iflag &^= syscall_IGNBRK | syscall_BRKINT | syscall_PARMRK | syscall_ISTRIP | syscall_INLCR | syscall_IGNCR | syscall_ICRNL | syscall_IXON tios.Lflag &^= syscall_ECHO | syscall_ECHONL | syscall_ICANON | syscall_ISIG | syscall_IEXTEN tios.Cflag &^= syscall_CSIZE | syscall_PARENB tios.Cflag |= syscall_CS8 tios.Cc[syscall_VMIN] = 1 tios.Cc[syscall_VTIME] = 0 err = tcsetattr(out.Fd(), &tios) if err != nil { return err } out.WriteString(funcs[t_enter_ca]) out.WriteString(funcs[t_enter_keypad]) out.WriteString(funcs[t_hide_cursor]) out.WriteString(funcs[t_clear_screen]) termw, termh = get_term_size(out.Fd()) back_buffer.init(termw, termh) front_buffer.init(termw, termh) back_buffer.clear() front_buffer.clear() go func() { buf := make([]byte, 128) for { select { case <-sigio: for { n, err := syscall.Read(in, buf) if err == syscall.EAGAIN || err == syscall.EWOULDBLOCK { break } select { case input_comm <- input_event{buf[:n], err}: ie := <-input_comm buf = ie.data[:128] case <-quit: return } } case <-quit: return } } }() IsInit = true return nil } // Interrupt an in-progress call to PollEvent by causing it to return // EventInterrupt. Note that this function will block until the PollEvent // function has successfully been interrupted. func Interrupt() { interrupt_comm <- struct{}{} } // Finalizes termbox library, should be called after successful initialization // when termbox's functionality isn't required anymore. func Close() { quit <- 1 out.WriteString(funcs[t_show_cursor]) out.WriteString(funcs[t_sgr0]) out.WriteString(funcs[t_clear_screen]) out.WriteString(funcs[t_exit_ca]) out.WriteString(funcs[t_exit_keypad]) out.WriteString(funcs[t_exit_mouse]) tcsetattr(out.Fd(), &orig_tios) out.Close() syscall.Close(in) // reset the state, so that on next Init() it will work again termw = 0 termh = 0 input_mode = InputEsc out = nil in = 0 lastfg = attr_invalid lastbg = attr_invalid lastx = coord_invalid lasty = coord_invalid cursor_x = cursor_hidden cursor_y = cursor_hidden foreground = ColorDefault background = ColorDefault IsInit = false } // Synchronizes the internal back buffer with the terminal. func Flush() error { // invalidate cursor position lastx = coord_invalid lasty = coord_invalid update_size_maybe() for y := 0; y < front_buffer.height; y++ { line_offset := y * front_buffer.width for x := 0; x < front_buffer.width; { cell_offset := line_offset + x back := &back_buffer.cells[cell_offset] front := &front_buffer.cells[cell_offset] if back.Ch < ' ' { back.Ch = ' ' } w := runewidth.RuneWidth(back.Ch) if w == 0 || w == 2 && runewidth.IsAmbiguousWidth(back.Ch) { w = 1 } if *back == *front { x += w continue } *front = *back send_attr(back.Fg, back.Bg) if w == 2 && x == front_buffer.width-1 { // there's not enough space for 2-cells rune, // let's just put a space in there send_char(x, y, ' ') } else { send_char(x, y, back.Ch) if w == 2 { next := cell_offset + 1 front_buffer.cells[next] = Cell{ Ch: 0, Fg: back.Fg, Bg: back.Bg, } } } x += w } } if !is_cursor_hidden(cursor_x, cursor_y) { write_cursor(cursor_x, cursor_y) } return flush() } // Sets the position of the cursor. See also HideCursor(). func SetCursor(x, y int) { if is_cursor_hidden(cursor_x, cursor_y) && !is_cursor_hidden(x, y) { outbuf.WriteString(funcs[t_show_cursor]) } if !is_cursor_hidden(cursor_x, cursor_y) && is_cursor_hidden(x, y) { outbuf.WriteString(funcs[t_hide_cursor]) } cursor_x, cursor_y = x, y if !is_cursor_hidden(cursor_x, cursor_y) { write_cursor(cursor_x, cursor_y) } } // The shortcut for SetCursor(-1, -1). func HideCursor() { SetCursor(cursor_hidden, cursor_hidden) } // Changes cell's parameters in the internal back buffer at the specified // position. func SetCell(x, y int, ch rune, fg, bg Attribute) { if x < 0 || x >= back_buffer.width { return } if y < 0 || y >= back_buffer.height { return } back_buffer.cells[y*back_buffer.width+x] = Cell{ch, fg, bg} } // Returns a slice into the termbox's back buffer. You can get its dimensions // using 'Size' function. The slice remains valid as long as no 'Clear' or // 'Flush' function calls were made after call to this function. func CellBuffer() []Cell { return back_buffer.cells } // After getting a raw event from PollRawEvent function call, you can parse it // again into an ordinary one using termbox logic. That is parse an event as // termbox would do it. Returned event in addition to usual Event struct fields // sets N field to the amount of bytes used within 'data' slice. If the length // of 'data' slice is zero or event cannot be parsed for some other reason, the // function will return a special event type: EventNone. // // IMPORTANT: EventNone may contain a non-zero N, which means you should skip // these bytes, because termbox cannot recognize them. // // NOTE: This API is experimental and may change in future. func ParseEvent(data []byte) Event { event := Event{Type: EventKey} ok := extract_event(data, &event) if !ok { return Event{Type: EventNone, N: event.N} } return event } // Wait for an event and return it. This is a blocking function call. Instead // of EventKey and EventMouse it returns EventRaw events. Raw event is written // into `data` slice and Event's N field is set to the amount of bytes written. // The minimum required length of the 'data' slice is 1. This requirement may // vary on different platforms. // // NOTE: This API is experimental and may change in future. func PollRawEvent(data []byte) Event { if len(data) == 0 { panic("len(data) >= 1 is a requirement") } var event Event if extract_raw_event(data, &event) { return event } for { select { case ev := <-input_comm: if ev.err != nil { return Event{Type: EventError, Err: ev.err} } inbuf = append(inbuf, ev.data...) input_comm <- ev if extract_raw_event(data, &event) { return event } case <-interrupt_comm: event.Type = EventInterrupt return event case <-sigwinch: event.Type = EventResize event.Width, event.Height = get_term_size(out.Fd()) return event } } } // Wait for an event and return it. This is a blocking function call. func PollEvent() Event { var event Event // try to extract event from input buffer, return on success event.Type = EventKey ok := extract_event(inbuf, &event) if event.N != 0 { copy(inbuf, inbuf[event.N:]) inbuf = inbuf[:len(inbuf)-event.N] } if ok { return event } for { select { case ev := <-input_comm: if ev.err != nil { return Event{Type: EventError, Err: ev.err} } inbuf = append(inbuf, ev.data...) input_comm <- ev ok := extract_event(inbuf, &event) if event.N != 0 { copy(inbuf, inbuf[event.N:]) inbuf = inbuf[:len(inbuf)-event.N] } if ok { return event } case <-interrupt_comm: event.Type = EventInterrupt return event case <-sigwinch: event.Type = EventResize event.Width, event.Height = get_term_size(out.Fd()) return event } } } // Returns the size of the internal back buffer (which is mostly the same as // terminal's window size in characters). But it doesn't always match the size // of the terminal window, after the terminal size has changed, the internal // back buffer will get in sync only after Clear or Flush function calls. func Size() (width int, height int) { return termw, termh } // Clears the internal back buffer. func Clear(fg, bg Attribute) error { foreground, background = fg, bg err := update_size_maybe() back_buffer.clear() return err } // Sets termbox input mode. Termbox has two input modes: // // 1. Esc input mode. When ESC sequence is in the buffer and it doesn't match // any known sequence. ESC means KeyEsc. This is the default input mode. // // 2. Alt input mode. When ESC sequence is in the buffer and it doesn't match // any known sequence. ESC enables ModAlt modifier for the next keyboard event. // // Both input modes can be OR'ed with Mouse mode. Setting Mouse mode bit up will // enable mouse button press/release and drag events. // // If 'mode' is InputCurrent, returns the current input mode. See also Input* // constants. func SetInputMode(mode InputMode) InputMode { if mode == InputCurrent { return input_mode } if mode&(InputEsc|InputAlt) == 0 { mode |= InputEsc } if mode&(InputEsc|InputAlt) == InputEsc|InputAlt { mode &^= InputAlt } if mode&InputMouse != 0 { out.WriteString(funcs[t_enter_mouse]) } else { out.WriteString(funcs[t_exit_mouse]) } input_mode = mode return input_mode } // Sets the termbox output mode. Termbox has four output options: // // 1. OutputNormal => [1..8] // This mode provides 8 different colors: // black, red, green, yellow, blue, magenta, cyan, white // Shortcut: ColorBlack, ColorRed, ... // Attributes: AttrBold, AttrUnderline, AttrReverse // // Example usage: // SetCell(x, y, '@', ColorBlack | AttrBold, ColorRed); // // 2. Output256 => [1..256] // In this mode you can leverage the 256 terminal mode: // 0x01 - 0x08: the 8 colors as in OutputNormal // 0x09 - 0x10: Color* | AttrBold // 0x11 - 0xe8: 216 different colors // 0xe9 - 0x1ff: 24 different shades of grey // // Example usage: // SetCell(x, y, '@', 184, 240); // SetCell(x, y, '@', 0xb8, 0xf0); // // 3. Output216 => [1..216] // This mode supports the 3rd range of the 256 mode only. // But you don't need to provide an offset. // // 4. OutputGrayscale => [1..26] // This mode supports the 4th range of the 256 mode // and black and white colors from 3th range of the 256 mode // But you don't need to provide an offset. // // In all modes, 0x00 represents the default color. // // `go run _demos/output.go` to see its impact on your terminal. // // If 'mode' is OutputCurrent, it returns the current output mode. // // Note that this may return a different OutputMode than the one requested, // as the requested mode may not be available on the target platform. func SetOutputMode(mode OutputMode) OutputMode { if mode == OutputCurrent { return output_mode } output_mode = mode return output_mode } // Sync comes handy when something causes desync between termbox's understanding // of a terminal buffer and the reality. Such as a third party process. Sync // forces a complete resync between the termbox and a terminal, it may not be // visually pretty though. func Sync() error { front_buffer.clear() err := send_clear() if err != nil { return err } return Flush() } ================================================ FILE: vendor/github.com/nsf/termbox-go/api_common.go ================================================ // termbox is a library for creating cross-platform text-based interfaces package termbox // public API, common OS agnostic part type ( InputMode int OutputMode int EventType uint8 Modifier uint8 Key uint16 Attribute uint16 ) // This type represents a termbox event. The 'Mod', 'Key' and 'Ch' fields are // valid if 'Type' is EventKey. The 'Width' and 'Height' fields are valid if // 'Type' is EventResize. The 'Err' field is valid if 'Type' is EventError. type Event struct { Type EventType // one of Event* constants Mod Modifier // one of Mod* constants or 0 Key Key // one of Key* constants, invalid if 'Ch' is not 0 Ch rune // a unicode character Width int // width of the screen Height int // height of the screen Err error // error in case if input failed MouseX int // x coord of mouse MouseY int // y coord of mouse N int // number of bytes written when getting a raw event } // A cell, single conceptual entity on the screen. The screen is basically a 2d // array of cells. 'Ch' is a unicode character, 'Fg' and 'Bg' are foreground // and background attributes respectively. type Cell struct { Ch rune Fg Attribute Bg Attribute } // To know if termbox has been initialized or not var ( IsInit bool = false ) // Key constants, see Event.Key field. const ( KeyF1 Key = 0xFFFF - iota KeyF2 KeyF3 KeyF4 KeyF5 KeyF6 KeyF7 KeyF8 KeyF9 KeyF10 KeyF11 KeyF12 KeyInsert KeyDelete KeyHome KeyEnd KeyPgup KeyPgdn KeyArrowUp KeyArrowDown KeyArrowLeft KeyArrowRight key_min // see terminfo MouseLeft MouseMiddle MouseRight MouseRelease MouseWheelUp MouseWheelDown ) const ( KeyCtrlTilde Key = 0x00 KeyCtrl2 Key = 0x00 KeyCtrlSpace Key = 0x00 KeyCtrlA Key = 0x01 KeyCtrlB Key = 0x02 KeyCtrlC Key = 0x03 KeyCtrlD Key = 0x04 KeyCtrlE Key = 0x05 KeyCtrlF Key = 0x06 KeyCtrlG Key = 0x07 KeyBackspace Key = 0x08 KeyCtrlH Key = 0x08 KeyTab Key = 0x09 KeyCtrlI Key = 0x09 KeyCtrlJ Key = 0x0A KeyCtrlK Key = 0x0B KeyCtrlL Key = 0x0C KeyEnter Key = 0x0D KeyCtrlM Key = 0x0D KeyCtrlN Key = 0x0E KeyCtrlO Key = 0x0F KeyCtrlP Key = 0x10 KeyCtrlQ Key = 0x11 KeyCtrlR Key = 0x12 KeyCtrlS Key = 0x13 KeyCtrlT Key = 0x14 KeyCtrlU Key = 0x15 KeyCtrlV Key = 0x16 KeyCtrlW Key = 0x17 KeyCtrlX Key = 0x18 KeyCtrlY Key = 0x19 KeyCtrlZ Key = 0x1A KeyEsc Key = 0x1B KeyCtrlLsqBracket Key = 0x1B KeyCtrl3 Key = 0x1B KeyCtrl4 Key = 0x1C KeyCtrlBackslash Key = 0x1C KeyCtrl5 Key = 0x1D KeyCtrlRsqBracket Key = 0x1D KeyCtrl6 Key = 0x1E KeyCtrl7 Key = 0x1F KeyCtrlSlash Key = 0x1F KeyCtrlUnderscore Key = 0x1F KeySpace Key = 0x20 KeyBackspace2 Key = 0x7F KeyCtrl8 Key = 0x7F ) // Alt modifier constant, see Event.Mod field and SetInputMode function. const ( ModAlt Modifier = 1 << iota ModMotion ) // Cell colors, you can combine a color with multiple attributes using bitwise // OR ('|'). const ( ColorDefault Attribute = iota ColorBlack ColorRed ColorGreen ColorYellow ColorBlue ColorMagenta ColorCyan ColorWhite ) // Cell attributes, it is possible to use multiple attributes by combining them // using bitwise OR ('|'). Although, colors cannot be combined. But you can // combine attributes and a single color. // // It's worth mentioning that some platforms don't support certain attibutes. // For example windows console doesn't support AttrUnderline. And on some // terminals applying AttrBold to background may result in blinking text. Use // them with caution and test your code on various terminals. const ( AttrBold Attribute = 1 << (iota + 9) AttrUnderline AttrReverse ) // Input mode. See SetInputMode function. const ( InputEsc InputMode = 1 << iota InputAlt InputMouse InputCurrent InputMode = 0 ) // Output mode. See SetOutputMode function. const ( OutputCurrent OutputMode = iota OutputNormal Output256 Output216 OutputGrayscale ) // Event type. See Event.Type field. const ( EventKey EventType = iota EventResize EventMouse EventError EventInterrupt EventRaw EventNone ) ================================================ FILE: vendor/github.com/nsf/termbox-go/api_windows.go ================================================ package termbox import ( "syscall" ) // public API // Initializes termbox library. This function should be called before any other functions. // After successful initialization, the library must be finalized using 'Close' function. // // Example usage: // err := termbox.Init() // if err != nil { // panic(err) // } // defer termbox.Close() func Init() error { var err error interrupt, err = create_event() if err != nil { return err } in, err = syscall.Open("CONIN$", syscall.O_RDWR, 0) if err != nil { return err } out, err = syscall.Open("CONOUT$", syscall.O_RDWR, 0) if err != nil { return err } err = get_console_mode(in, &orig_mode) if err != nil { return err } err = set_console_mode(in, enable_window_input) if err != nil { return err } orig_size = get_term_size(out) win_size := get_win_size(out) err = set_console_screen_buffer_size(out, win_size) if err != nil { return err } err = get_console_cursor_info(out, &orig_cursor_info) if err != nil { return err } show_cursor(false) term_size = get_term_size(out) back_buffer.init(int(term_size.x), int(term_size.y)) front_buffer.init(int(term_size.x), int(term_size.y)) back_buffer.clear() front_buffer.clear() clear() diffbuf = make([]diff_msg, 0, 32) go input_event_producer() IsInit = true return nil } // Finalizes termbox library, should be called after successful initialization // when termbox's functionality isn't required anymore. func Close() { // we ignore errors here, because we can't really do anything about them Clear(0, 0) Flush() // stop event producer cancel_comm <- true set_event(interrupt) select { case <-input_comm: default: } <-cancel_done_comm set_console_cursor_info(out, &orig_cursor_info) set_console_cursor_position(out, coord{}) set_console_screen_buffer_size(out, orig_size) set_console_mode(in, orig_mode) syscall.Close(in) syscall.Close(out) syscall.Close(interrupt) IsInit = false } // Interrupt an in-progress call to PollEvent by causing it to return // EventInterrupt. Note that this function will block until the PollEvent // function has successfully been interrupted. func Interrupt() { interrupt_comm <- struct{}{} } // Synchronizes the internal back buffer with the terminal. func Flush() error { update_size_maybe() prepare_diff_messages() for _, diff := range diffbuf { r := small_rect{ left: 0, top: diff.pos, right: term_size.x - 1, bottom: diff.pos + diff.lines - 1, } write_console_output(out, diff.chars, r) } if !is_cursor_hidden(cursor_x, cursor_y) { move_cursor(cursor_x, cursor_y) } return nil } // Sets the position of the cursor. See also HideCursor(). func SetCursor(x, y int) { if is_cursor_hidden(cursor_x, cursor_y) && !is_cursor_hidden(x, y) { show_cursor(true) } if !is_cursor_hidden(cursor_x, cursor_y) && is_cursor_hidden(x, y) { show_cursor(false) } cursor_x, cursor_y = x, y if !is_cursor_hidden(cursor_x, cursor_y) { move_cursor(cursor_x, cursor_y) } } // The shortcut for SetCursor(-1, -1). func HideCursor() { SetCursor(cursor_hidden, cursor_hidden) } // Changes cell's parameters in the internal back buffer at the specified // position. func SetCell(x, y int, ch rune, fg, bg Attribute) { if x < 0 || x >= back_buffer.width { return } if y < 0 || y >= back_buffer.height { return } back_buffer.cells[y*back_buffer.width+x] = Cell{ch, fg, bg} } // Returns a slice into the termbox's back buffer. You can get its dimensions // using 'Size' function. The slice remains valid as long as no 'Clear' or // 'Flush' function calls were made after call to this function. func CellBuffer() []Cell { return back_buffer.cells } // Wait for an event and return it. This is a blocking function call. func PollEvent() Event { select { case ev := <-input_comm: return ev case <-interrupt_comm: return Event{Type: EventInterrupt} } } // Returns the size of the internal back buffer (which is mostly the same as // console's window size in characters). But it doesn't always match the size // of the console window, after the console size has changed, the internal back // buffer will get in sync only after Clear or Flush function calls. func Size() (int, int) { return int(term_size.x), int(term_size.y) } // Clears the internal back buffer. func Clear(fg, bg Attribute) error { foreground, background = fg, bg update_size_maybe() back_buffer.clear() return nil } // Sets termbox input mode. Termbox has two input modes: // // 1. Esc input mode. When ESC sequence is in the buffer and it doesn't match // any known sequence. ESC means KeyEsc. This is the default input mode. // // 2. Alt input mode. When ESC sequence is in the buffer and it doesn't match // any known sequence. ESC enables ModAlt modifier for the next keyboard event. // // Both input modes can be OR'ed with Mouse mode. Setting Mouse mode bit up will // enable mouse button press/release and drag events. // // If 'mode' is InputCurrent, returns the current input mode. See also Input* // constants. func SetInputMode(mode InputMode) InputMode { if mode == InputCurrent { return input_mode } if mode&InputMouse != 0 { err := set_console_mode(in, enable_window_input|enable_mouse_input|enable_extended_flags) if err != nil { panic(err) } } else { err := set_console_mode(in, enable_window_input) if err != nil { panic(err) } } input_mode = mode return input_mode } // Sets the termbox output mode. // // Windows console does not support extra colour modes, // so this will always set and return OutputNormal. func SetOutputMode(mode OutputMode) OutputMode { return OutputNormal } // Sync comes handy when something causes desync between termbox's understanding // of a terminal buffer and the reality. Such as a third party process. Sync // forces a complete resync between the termbox and a terminal, it may not be // visually pretty though. At the moment on Windows it does nothing. func Sync() error { return nil } ================================================ FILE: vendor/github.com/nsf/termbox-go/collect_terminfo.py ================================================ #!/usr/bin/env python import sys, os, subprocess def escaped(s): return repr(s)[1:-1] def tput(term, name): try: return subprocess.check_output(['tput', '-T%s' % term, name]).decode() except subprocess.CalledProcessError as e: return e.output.decode() def w(s): if s == None: return sys.stdout.write(s) terminals = { 'xterm' : 'xterm', 'rxvt-256color' : 'rxvt_256color', 'rxvt-unicode' : 'rxvt_unicode', 'linux' : 'linux', 'Eterm' : 'eterm', 'screen' : 'screen' } keys = [ "F1", "kf1", "F2", "kf2", "F3", "kf3", "F4", "kf4", "F5", "kf5", "F6", "kf6", "F7", "kf7", "F8", "kf8", "F9", "kf9", "F10", "kf10", "F11", "kf11", "F12", "kf12", "INSERT", "kich1", "DELETE", "kdch1", "HOME", "khome", "END", "kend", "PGUP", "kpp", "PGDN", "knp", "KEY_UP", "kcuu1", "KEY_DOWN", "kcud1", "KEY_LEFT", "kcub1", "KEY_RIGHT", "kcuf1" ] funcs = [ "T_ENTER_CA", "smcup", "T_EXIT_CA", "rmcup", "T_SHOW_CURSOR", "cnorm", "T_HIDE_CURSOR", "civis", "T_CLEAR_SCREEN", "clear", "T_SGR0", "sgr0", "T_UNDERLINE", "smul", "T_BOLD", "bold", "T_BLINK", "blink", "T_REVERSE", "rev", "T_ENTER_KEYPAD", "smkx", "T_EXIT_KEYPAD", "rmkx" ] def iter_pairs(iterable): iterable = iter(iterable) while True: yield (next(iterable), next(iterable)) def do_term(term, nick): w("// %s\n" % term) w("var %s_keys = []string{\n\t" % nick) for k, v in iter_pairs(keys): w('"') w(escaped(tput(term, v))) w('",') w("\n}\n") w("var %s_funcs = []string{\n\t" % nick) for k,v in iter_pairs(funcs): w('"') if v == "sgr": w("\\033[3%d;4%dm") elif v == "cup": w("\\033[%d;%dH") else: w(escaped(tput(term, v))) w('", ') w("\n}\n\n") def do_terms(d): w("var terms = []struct {\n") w("\tname string\n") w("\tkeys []string\n") w("\tfuncs []string\n") w("}{\n") for k, v in d.items(): w('\t{"%s", %s_keys, %s_funcs},\n' % (k, v, v)) w("}\n\n") w("// +build !windows\n\npackage termbox\n\n") for k,v in terminals.items(): do_term(k, v) do_terms(terminals) ================================================ FILE: vendor/github.com/nsf/termbox-go/syscalls.go ================================================ // +build ignore package termbox /* #include #include */ import "C" type syscall_Termios C.struct_termios const ( syscall_IGNBRK = C.IGNBRK syscall_BRKINT = C.BRKINT syscall_PARMRK = C.PARMRK syscall_ISTRIP = C.ISTRIP syscall_INLCR = C.INLCR syscall_IGNCR = C.IGNCR syscall_ICRNL = C.ICRNL syscall_IXON = C.IXON syscall_OPOST = C.OPOST syscall_ECHO = C.ECHO syscall_ECHONL = C.ECHONL syscall_ICANON = C.ICANON syscall_ISIG = C.ISIG syscall_IEXTEN = C.IEXTEN syscall_CSIZE = C.CSIZE syscall_PARENB = C.PARENB syscall_CS8 = C.CS8 syscall_VMIN = C.VMIN syscall_VTIME = C.VTIME // on darwin change these to (on *bsd too?): // C.TIOCGETA // C.TIOCSETA syscall_TCGETS = C.TCGETS syscall_TCSETS = C.TCSETS ) ================================================ FILE: vendor/github.com/nsf/termbox-go/syscalls_darwin.go ================================================ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs syscalls.go // +build !amd64 package termbox type syscall_Termios struct { Iflag uint32 Oflag uint32 Cflag uint32 Lflag uint32 Cc [20]uint8 Ispeed uint32 Ospeed uint32 } const ( syscall_IGNBRK = 0x1 syscall_BRKINT = 0x2 syscall_PARMRK = 0x8 syscall_ISTRIP = 0x20 syscall_INLCR = 0x40 syscall_IGNCR = 0x80 syscall_ICRNL = 0x100 syscall_IXON = 0x200 syscall_OPOST = 0x1 syscall_ECHO = 0x8 syscall_ECHONL = 0x10 syscall_ICANON = 0x100 syscall_ISIG = 0x80 syscall_IEXTEN = 0x400 syscall_CSIZE = 0x300 syscall_PARENB = 0x1000 syscall_CS8 = 0x300 syscall_VMIN = 0x10 syscall_VTIME = 0x11 syscall_TCGETS = 0x402c7413 syscall_TCSETS = 0x802c7414 ) ================================================ FILE: vendor/github.com/nsf/termbox-go/syscalls_darwin_amd64.go ================================================ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs syscalls.go package termbox type syscall_Termios struct { Iflag uint64 Oflag uint64 Cflag uint64 Lflag uint64 Cc [20]uint8 Pad_cgo_0 [4]byte Ispeed uint64 Ospeed uint64 } const ( syscall_IGNBRK = 0x1 syscall_BRKINT = 0x2 syscall_PARMRK = 0x8 syscall_ISTRIP = 0x20 syscall_INLCR = 0x40 syscall_IGNCR = 0x80 syscall_ICRNL = 0x100 syscall_IXON = 0x200 syscall_OPOST = 0x1 syscall_ECHO = 0x8 syscall_ECHONL = 0x10 syscall_ICANON = 0x100 syscall_ISIG = 0x80 syscall_IEXTEN = 0x400 syscall_CSIZE = 0x300 syscall_PARENB = 0x1000 syscall_CS8 = 0x300 syscall_VMIN = 0x10 syscall_VTIME = 0x11 syscall_TCGETS = 0x40487413 syscall_TCSETS = 0x80487414 ) ================================================ FILE: vendor/github.com/nsf/termbox-go/syscalls_dragonfly.go ================================================ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs syscalls.go package termbox type syscall_Termios struct { Iflag uint32 Oflag uint32 Cflag uint32 Lflag uint32 Cc [20]uint8 Ispeed uint32 Ospeed uint32 } const ( syscall_IGNBRK = 0x1 syscall_BRKINT = 0x2 syscall_PARMRK = 0x8 syscall_ISTRIP = 0x20 syscall_INLCR = 0x40 syscall_IGNCR = 0x80 syscall_ICRNL = 0x100 syscall_IXON = 0x200 syscall_OPOST = 0x1 syscall_ECHO = 0x8 syscall_ECHONL = 0x10 syscall_ICANON = 0x100 syscall_ISIG = 0x80 syscall_IEXTEN = 0x400 syscall_CSIZE = 0x300 syscall_PARENB = 0x1000 syscall_CS8 = 0x300 syscall_VMIN = 0x10 syscall_VTIME = 0x11 syscall_TCGETS = 0x402c7413 syscall_TCSETS = 0x802c7414 ) ================================================ FILE: vendor/github.com/nsf/termbox-go/syscalls_freebsd.go ================================================ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs syscalls.go package termbox type syscall_Termios struct { Iflag uint32 Oflag uint32 Cflag uint32 Lflag uint32 Cc [20]uint8 Ispeed uint32 Ospeed uint32 } const ( syscall_IGNBRK = 0x1 syscall_BRKINT = 0x2 syscall_PARMRK = 0x8 syscall_ISTRIP = 0x20 syscall_INLCR = 0x40 syscall_IGNCR = 0x80 syscall_ICRNL = 0x100 syscall_IXON = 0x200 syscall_OPOST = 0x1 syscall_ECHO = 0x8 syscall_ECHONL = 0x10 syscall_ICANON = 0x100 syscall_ISIG = 0x80 syscall_IEXTEN = 0x400 syscall_CSIZE = 0x300 syscall_PARENB = 0x1000 syscall_CS8 = 0x300 syscall_VMIN = 0x10 syscall_VTIME = 0x11 syscall_TCGETS = 0x402c7413 syscall_TCSETS = 0x802c7414 ) ================================================ FILE: vendor/github.com/nsf/termbox-go/syscalls_linux.go ================================================ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs syscalls.go package termbox import "syscall" type syscall_Termios syscall.Termios const ( syscall_IGNBRK = syscall.IGNBRK syscall_BRKINT = syscall.BRKINT syscall_PARMRK = syscall.PARMRK syscall_ISTRIP = syscall.ISTRIP syscall_INLCR = syscall.INLCR syscall_IGNCR = syscall.IGNCR syscall_ICRNL = syscall.ICRNL syscall_IXON = syscall.IXON syscall_OPOST = syscall.OPOST syscall_ECHO = syscall.ECHO syscall_ECHONL = syscall.ECHONL syscall_ICANON = syscall.ICANON syscall_ISIG = syscall.ISIG syscall_IEXTEN = syscall.IEXTEN syscall_CSIZE = syscall.CSIZE syscall_PARENB = syscall.PARENB syscall_CS8 = syscall.CS8 syscall_VMIN = syscall.VMIN syscall_VTIME = syscall.VTIME syscall_TCGETS = syscall.TCGETS syscall_TCSETS = syscall.TCSETS ) ================================================ FILE: vendor/github.com/nsf/termbox-go/syscalls_netbsd.go ================================================ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs syscalls.go package termbox type syscall_Termios struct { Iflag uint32 Oflag uint32 Cflag uint32 Lflag uint32 Cc [20]uint8 Ispeed int32 Ospeed int32 } const ( syscall_IGNBRK = 0x1 syscall_BRKINT = 0x2 syscall_PARMRK = 0x8 syscall_ISTRIP = 0x20 syscall_INLCR = 0x40 syscall_IGNCR = 0x80 syscall_ICRNL = 0x100 syscall_IXON = 0x200 syscall_OPOST = 0x1 syscall_ECHO = 0x8 syscall_ECHONL = 0x10 syscall_ICANON = 0x100 syscall_ISIG = 0x80 syscall_IEXTEN = 0x400 syscall_CSIZE = 0x300 syscall_PARENB = 0x1000 syscall_CS8 = 0x300 syscall_VMIN = 0x10 syscall_VTIME = 0x11 syscall_TCGETS = 0x402c7413 syscall_TCSETS = 0x802c7414 ) ================================================ FILE: vendor/github.com/nsf/termbox-go/syscalls_openbsd.go ================================================ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs syscalls.go package termbox type syscall_Termios struct { Iflag uint32 Oflag uint32 Cflag uint32 Lflag uint32 Cc [20]uint8 Ispeed int32 Ospeed int32 } const ( syscall_IGNBRK = 0x1 syscall_BRKINT = 0x2 syscall_PARMRK = 0x8 syscall_ISTRIP = 0x20 syscall_INLCR = 0x40 syscall_IGNCR = 0x80 syscall_ICRNL = 0x100 syscall_IXON = 0x200 syscall_OPOST = 0x1 syscall_ECHO = 0x8 syscall_ECHONL = 0x10 syscall_ICANON = 0x100 syscall_ISIG = 0x80 syscall_IEXTEN = 0x400 syscall_CSIZE = 0x300 syscall_PARENB = 0x1000 syscall_CS8 = 0x300 syscall_VMIN = 0x10 syscall_VTIME = 0x11 syscall_TCGETS = 0x402c7413 syscall_TCSETS = 0x802c7414 ) ================================================ FILE: vendor/github.com/nsf/termbox-go/syscalls_windows.go ================================================ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs -- -DUNICODE syscalls.go package termbox const ( foreground_blue = 0x1 foreground_green = 0x2 foreground_red = 0x4 foreground_intensity = 0x8 background_blue = 0x10 background_green = 0x20 background_red = 0x40 background_intensity = 0x80 std_input_handle = -0xa std_output_handle = -0xb key_event = 0x1 mouse_event = 0x2 window_buffer_size_event = 0x4 enable_window_input = 0x8 enable_mouse_input = 0x10 enable_extended_flags = 0x80 vk_f1 = 0x70 vk_f2 = 0x71 vk_f3 = 0x72 vk_f4 = 0x73 vk_f5 = 0x74 vk_f6 = 0x75 vk_f7 = 0x76 vk_f8 = 0x77 vk_f9 = 0x78 vk_f10 = 0x79 vk_f11 = 0x7a vk_f12 = 0x7b vk_insert = 0x2d vk_delete = 0x2e vk_home = 0x24 vk_end = 0x23 vk_pgup = 0x21 vk_pgdn = 0x22 vk_arrow_up = 0x26 vk_arrow_down = 0x28 vk_arrow_left = 0x25 vk_arrow_right = 0x27 vk_backspace = 0x8 vk_tab = 0x9 vk_enter = 0xd vk_esc = 0x1b vk_space = 0x20 left_alt_pressed = 0x2 left_ctrl_pressed = 0x8 right_alt_pressed = 0x1 right_ctrl_pressed = 0x4 shift_pressed = 0x10 generic_read = 0x80000000 generic_write = 0x40000000 console_textmode_buffer = 0x1 ) ================================================ FILE: vendor/github.com/nsf/termbox-go/termbox.go ================================================ // +build !windows package termbox import "unicode/utf8" import "bytes" import "syscall" import "unsafe" import "strings" import "strconv" import "os" import "io" // private API const ( t_enter_ca = iota t_exit_ca t_show_cursor t_hide_cursor t_clear_screen t_sgr0 t_underline t_bold t_blink t_reverse t_enter_keypad t_exit_keypad t_enter_mouse t_exit_mouse t_max_funcs ) const ( coord_invalid = -2 attr_invalid = Attribute(0xFFFF) ) type input_event struct { data []byte err error } var ( // term specific sequences keys []string funcs []string // termbox inner state orig_tios syscall_Termios back_buffer cellbuf front_buffer cellbuf termw int termh int input_mode = InputEsc output_mode = OutputNormal out *os.File in int lastfg = attr_invalid lastbg = attr_invalid lastx = coord_invalid lasty = coord_invalid cursor_x = cursor_hidden cursor_y = cursor_hidden foreground = ColorDefault background = ColorDefault inbuf = make([]byte, 0, 64) outbuf bytes.Buffer sigwinch = make(chan os.Signal, 1) sigio = make(chan os.Signal, 1) quit = make(chan int) input_comm = make(chan input_event) interrupt_comm = make(chan struct{}) intbuf = make([]byte, 0, 16) // grayscale indexes grayscale = []Attribute{ 0, 17, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 232, } ) func write_cursor(x, y int) { outbuf.WriteString("\033[") outbuf.Write(strconv.AppendUint(intbuf, uint64(y+1), 10)) outbuf.WriteString(";") outbuf.Write(strconv.AppendUint(intbuf, uint64(x+1), 10)) outbuf.WriteString("H") } func write_sgr_fg(a Attribute) { switch output_mode { case Output256, Output216, OutputGrayscale: outbuf.WriteString("\033[38;5;") outbuf.Write(strconv.AppendUint(intbuf, uint64(a-1), 10)) outbuf.WriteString("m") default: outbuf.WriteString("\033[3") outbuf.Write(strconv.AppendUint(intbuf, uint64(a-1), 10)) outbuf.WriteString("m") } } func write_sgr_bg(a Attribute) { switch output_mode { case Output256, Output216, OutputGrayscale: outbuf.WriteString("\033[48;5;") outbuf.Write(strconv.AppendUint(intbuf, uint64(a-1), 10)) outbuf.WriteString("m") default: outbuf.WriteString("\033[4") outbuf.Write(strconv.AppendUint(intbuf, uint64(a-1), 10)) outbuf.WriteString("m") } } func write_sgr(fg, bg Attribute) { switch output_mode { case Output256, Output216, OutputGrayscale: outbuf.WriteString("\033[38;5;") outbuf.Write(strconv.AppendUint(intbuf, uint64(fg-1), 10)) outbuf.WriteString("m") outbuf.WriteString("\033[48;5;") outbuf.Write(strconv.AppendUint(intbuf, uint64(bg-1), 10)) outbuf.WriteString("m") default: outbuf.WriteString("\033[3") outbuf.Write(strconv.AppendUint(intbuf, uint64(fg-1), 10)) outbuf.WriteString(";4") outbuf.Write(strconv.AppendUint(intbuf, uint64(bg-1), 10)) outbuf.WriteString("m") } } type winsize struct { rows uint16 cols uint16 xpixels uint16 ypixels uint16 } func get_term_size(fd uintptr) (int, int) { var sz winsize _, _, _ = syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(syscall.TIOCGWINSZ), uintptr(unsafe.Pointer(&sz))) return int(sz.cols), int(sz.rows) } func send_attr(fg, bg Attribute) { if fg == lastfg && bg == lastbg { return } outbuf.WriteString(funcs[t_sgr0]) var fgcol, bgcol Attribute switch output_mode { case Output256: fgcol = fg & 0x1FF bgcol = bg & 0x1FF case Output216: fgcol = fg & 0xFF bgcol = bg & 0xFF if fgcol > 216 { fgcol = ColorDefault } if bgcol > 216 { bgcol = ColorDefault } if fgcol != ColorDefault { fgcol += 0x10 } if bgcol != ColorDefault { bgcol += 0x10 } case OutputGrayscale: fgcol = fg & 0x1F bgcol = bg & 0x1F if fgcol > 26 { fgcol = ColorDefault } if bgcol > 26 { bgcol = ColorDefault } if fgcol != ColorDefault { fgcol = grayscale[fgcol] } if bgcol != ColorDefault { bgcol = grayscale[bgcol] } default: fgcol = fg & 0x0F bgcol = bg & 0x0F } if fgcol != ColorDefault { if bgcol != ColorDefault { write_sgr(fgcol, bgcol) } else { write_sgr_fg(fgcol) } } else if bgcol != ColorDefault { write_sgr_bg(bgcol) } if fg&AttrBold != 0 { outbuf.WriteString(funcs[t_bold]) } if bg&AttrBold != 0 { outbuf.WriteString(funcs[t_blink]) } if fg&AttrUnderline != 0 { outbuf.WriteString(funcs[t_underline]) } if fg&AttrReverse|bg&AttrReverse != 0 { outbuf.WriteString(funcs[t_reverse]) } lastfg, lastbg = fg, bg } func send_char(x, y int, ch rune) { var buf [8]byte n := utf8.EncodeRune(buf[:], ch) if x-1 != lastx || y != lasty { write_cursor(x, y) } lastx, lasty = x, y outbuf.Write(buf[:n]) } func flush() error { _, err := io.Copy(out, &outbuf) outbuf.Reset() return err } func send_clear() error { send_attr(foreground, background) outbuf.WriteString(funcs[t_clear_screen]) if !is_cursor_hidden(cursor_x, cursor_y) { write_cursor(cursor_x, cursor_y) } // we need to invalidate cursor position too and these two vars are // used only for simple cursor positioning optimization, cursor // actually may be in the correct place, but we simply discard // optimization once and it gives us simple solution for the case when // cursor moved lastx = coord_invalid lasty = coord_invalid return flush() } func update_size_maybe() error { w, h := get_term_size(out.Fd()) if w != termw || h != termh { termw, termh = w, h back_buffer.resize(termw, termh) front_buffer.resize(termw, termh) front_buffer.clear() return send_clear() } return nil } func tcsetattr(fd uintptr, termios *syscall_Termios) error { r, _, e := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(syscall_TCSETS), uintptr(unsafe.Pointer(termios))) if r != 0 { return os.NewSyscallError("SYS_IOCTL", e) } return nil } func tcgetattr(fd uintptr, termios *syscall_Termios) error { r, _, e := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(syscall_TCGETS), uintptr(unsafe.Pointer(termios))) if r != 0 { return os.NewSyscallError("SYS_IOCTL", e) } return nil } func parse_mouse_event(event *Event, buf string) (int, bool) { if strings.HasPrefix(buf, "\033[M") && len(buf) >= 6 { // X10 mouse encoding, the simplest one // \033 [ M Cb Cx Cy b := buf[3] - 32 switch b & 3 { case 0: if b&64 != 0 { event.Key = MouseWheelUp } else { event.Key = MouseLeft } case 1: if b&64 != 0 { event.Key = MouseWheelDown } else { event.Key = MouseMiddle } case 2: event.Key = MouseRight case 3: event.Key = MouseRelease default: return 6, false } event.Type = EventMouse // KeyEvent by default if b&32 != 0 { event.Mod |= ModMotion } // the coord is 1,1 for upper left event.MouseX = int(buf[4]) - 1 - 32 event.MouseY = int(buf[5]) - 1 - 32 return 6, true } else if strings.HasPrefix(buf, "\033[<") || strings.HasPrefix(buf, "\033[") { // xterm 1006 extended mode or urxvt 1015 extended mode // xterm: \033 [ < Cb ; Cx ; Cy (M or m) // urxvt: \033 [ Cb ; Cx ; Cy M // find the first M or m, that's where we stop mi := strings.IndexAny(buf, "Mm") if mi == -1 { return 0, false } // whether it's a capital M or not isM := buf[mi] == 'M' // whether it's urxvt or not isU := false // buf[2] is safe here, because having M or m found means we have at // least 3 bytes in a string if buf[2] == '<' { buf = buf[3:mi] } else { isU = true buf = buf[2:mi] } s1 := strings.Index(buf, ";") s2 := strings.LastIndex(buf, ";") // not found or only one ';' if s1 == -1 || s2 == -1 || s1 == s2 { return 0, false } n1, err := strconv.ParseInt(buf[0:s1], 10, 64) if err != nil { return 0, false } n2, err := strconv.ParseInt(buf[s1+1:s2], 10, 64) if err != nil { return 0, false } n3, err := strconv.ParseInt(buf[s2+1:], 10, 64) if err != nil { return 0, false } // on urxvt, first number is encoded exactly as in X10, but we need to // make it zero-based, on xterm it is zero-based already if isU { n1 -= 32 } switch n1 & 3 { case 0: if n1&64 != 0 { event.Key = MouseWheelUp } else { event.Key = MouseLeft } case 1: if n1&64 != 0 { event.Key = MouseWheelDown } else { event.Key = MouseMiddle } case 2: event.Key = MouseRight case 3: event.Key = MouseRelease default: return mi + 1, false } if !isM { // on xterm mouse release is signaled by lowercase m event.Key = MouseRelease } event.Type = EventMouse // KeyEvent by default if n1&32 != 0 { event.Mod |= ModMotion } event.MouseX = int(n2) - 1 event.MouseY = int(n3) - 1 return mi + 1, true } return 0, false } func parse_escape_sequence(event *Event, buf []byte) (int, bool) { bufstr := string(buf) for i, key := range keys { if strings.HasPrefix(bufstr, key) { event.Ch = 0 event.Key = Key(0xFFFF - i) return len(key), true } } // if none of the keys match, let's try mouse seqences return parse_mouse_event(event, bufstr) } func extract_raw_event(data []byte, event *Event) bool { if len(inbuf) == 0 { return false } n := len(data) if n == 0 { return false } n = copy(data, inbuf) copy(inbuf, inbuf[n:]) inbuf = inbuf[:len(inbuf)-n] event.N = n event.Type = EventRaw return true } func extract_event(inbuf []byte, event *Event) bool { if len(inbuf) == 0 { event.N = 0 return false } if inbuf[0] == '\033' { // possible escape sequence if n, ok := parse_escape_sequence(event, inbuf); n != 0 { event.N = n return ok } // it's not escape sequence, then it's Alt or Esc, check input_mode switch { case input_mode&InputEsc != 0: // if we're in escape mode, fill Esc event, pop buffer, return success event.Ch = 0 event.Key = KeyEsc event.Mod = 0 event.N = 1 return true case input_mode&InputAlt != 0: // if we're in alt mode, set Alt modifier to event and redo parsing event.Mod = ModAlt ok := extract_event(inbuf[1:], event) if ok { event.N++ } else { event.N = 0 } return ok default: panic("unreachable") } } // if we're here, this is not an escape sequence and not an alt sequence // so, it's a FUNCTIONAL KEY or a UNICODE character // first of all check if it's a functional key if Key(inbuf[0]) <= KeySpace || Key(inbuf[0]) == KeyBackspace2 { // fill event, pop buffer, return success event.Ch = 0 event.Key = Key(inbuf[0]) event.N = 1 return true } // the only possible option is utf8 rune if r, n := utf8.DecodeRune(inbuf); r != utf8.RuneError { event.Ch = r event.Key = 0 event.N = n return true } return false } func fcntl(fd int, cmd int, arg int) (val int, err error) { r, _, e := syscall.Syscall(syscall.SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg)) val = int(r) if e != 0 { err = e } return } ================================================ FILE: vendor/github.com/nsf/termbox-go/termbox_common.go ================================================ package termbox // private API, common OS agnostic part type cellbuf struct { width int height int cells []Cell } func (this *cellbuf) init(width, height int) { this.width = width this.height = height this.cells = make([]Cell, width*height) } func (this *cellbuf) resize(width, height int) { if this.width == width && this.height == height { return } oldw := this.width oldh := this.height oldcells := this.cells this.init(width, height) this.clear() minw, minh := oldw, oldh if width < minw { minw = width } if height < minh { minh = height } for i := 0; i < minh; i++ { srco, dsto := i*oldw, i*width src := oldcells[srco : srco+minw] dst := this.cells[dsto : dsto+minw] copy(dst, src) } } func (this *cellbuf) clear() { for i := range this.cells { c := &this.cells[i] c.Ch = ' ' c.Fg = foreground c.Bg = background } } const cursor_hidden = -1 func is_cursor_hidden(x, y int) bool { return x == cursor_hidden || y == cursor_hidden } ================================================ FILE: vendor/github.com/nsf/termbox-go/termbox_windows.go ================================================ package termbox import "syscall" import "unsafe" import "unicode/utf16" import "github.com/mattn/go-runewidth" type ( wchar uint16 short int16 dword uint32 word uint16 char_info struct { char wchar attr word } coord struct { x short y short } small_rect struct { left short top short right short bottom short } console_screen_buffer_info struct { size coord cursor_position coord attributes word window small_rect maximum_window_size coord } console_cursor_info struct { size dword visible int32 } input_record struct { event_type word _ [2]byte event [16]byte } key_event_record struct { key_down int32 repeat_count word virtual_key_code word virtual_scan_code word unicode_char wchar control_key_state dword } window_buffer_size_record struct { size coord } mouse_event_record struct { mouse_pos coord button_state dword control_key_state dword event_flags dword } ) const ( mouse_lmb = 0x1 mouse_rmb = 0x2 mouse_mmb = 0x4 | 0x8 | 0x10 SM_CXMIN = 28 SM_CYMIN = 29 ) func (this coord) uintptr() uintptr { return uintptr(*(*int32)(unsafe.Pointer(&this))) } var kernel32 = syscall.NewLazyDLL("kernel32.dll") var moduser32 = syscall.NewLazyDLL("user32.dll") var is_cjk = runewidth.IsEastAsian() var ( proc_set_console_active_screen_buffer = kernel32.NewProc("SetConsoleActiveScreenBuffer") proc_set_console_screen_buffer_size = kernel32.NewProc("SetConsoleScreenBufferSize") proc_create_console_screen_buffer = kernel32.NewProc("CreateConsoleScreenBuffer") proc_get_console_screen_buffer_info = kernel32.NewProc("GetConsoleScreenBufferInfo") proc_write_console_output = kernel32.NewProc("WriteConsoleOutputW") proc_write_console_output_character = kernel32.NewProc("WriteConsoleOutputCharacterW") proc_write_console_output_attribute = kernel32.NewProc("WriteConsoleOutputAttribute") proc_set_console_cursor_info = kernel32.NewProc("SetConsoleCursorInfo") proc_set_console_cursor_position = kernel32.NewProc("SetConsoleCursorPosition") proc_get_console_cursor_info = kernel32.NewProc("GetConsoleCursorInfo") proc_read_console_input = kernel32.NewProc("ReadConsoleInputW") proc_get_console_mode = kernel32.NewProc("GetConsoleMode") proc_set_console_mode = kernel32.NewProc("SetConsoleMode") proc_fill_console_output_character = kernel32.NewProc("FillConsoleOutputCharacterW") proc_fill_console_output_attribute = kernel32.NewProc("FillConsoleOutputAttribute") proc_create_event = kernel32.NewProc("CreateEventW") proc_wait_for_multiple_objects = kernel32.NewProc("WaitForMultipleObjects") proc_set_event = kernel32.NewProc("SetEvent") get_system_metrics = moduser32.NewProc("GetSystemMetrics") ) func set_console_active_screen_buffer(h syscall.Handle) (err error) { r0, _, e1 := syscall.Syscall(proc_set_console_active_screen_buffer.Addr(), 1, uintptr(h), 0, 0) if int(r0) == 0 { if e1 != 0 { err = error(e1) } else { err = syscall.EINVAL } } return } func set_console_screen_buffer_size(h syscall.Handle, size coord) (err error) { r0, _, e1 := syscall.Syscall(proc_set_console_screen_buffer_size.Addr(), 2, uintptr(h), size.uintptr(), 0) if int(r0) == 0 { if e1 != 0 { err = error(e1) } else { err = syscall.EINVAL } } return } func create_console_screen_buffer() (h syscall.Handle, err error) { r0, _, e1 := syscall.Syscall6(proc_create_console_screen_buffer.Addr(), 5, uintptr(generic_read|generic_write), 0, 0, console_textmode_buffer, 0, 0) if int(r0) == 0 { if e1 != 0 { err = error(e1) } else { err = syscall.EINVAL } } return syscall.Handle(r0), err } func get_console_screen_buffer_info(h syscall.Handle, info *console_screen_buffer_info) (err error) { r0, _, e1 := syscall.Syscall(proc_get_console_screen_buffer_info.Addr(), 2, uintptr(h), uintptr(unsafe.Pointer(info)), 0) if int(r0) == 0 { if e1 != 0 { err = error(e1) } else { err = syscall.EINVAL } } return } func write_console_output(h syscall.Handle, chars []char_info, dst small_rect) (err error) { tmp_coord = coord{dst.right - dst.left + 1, dst.bottom - dst.top + 1} tmp_rect = dst r0, _, e1 := syscall.Syscall6(proc_write_console_output.Addr(), 5, uintptr(h), uintptr(unsafe.Pointer(&chars[0])), tmp_coord.uintptr(), tmp_coord0.uintptr(), uintptr(unsafe.Pointer(&tmp_rect)), 0) if int(r0) == 0 { if e1 != 0 { err = error(e1) } else { err = syscall.EINVAL } } return } func write_console_output_character(h syscall.Handle, chars []wchar, pos coord) (err error) { r0, _, e1 := syscall.Syscall6(proc_write_console_output_character.Addr(), 5, uintptr(h), uintptr(unsafe.Pointer(&chars[0])), uintptr(len(chars)), pos.uintptr(), uintptr(unsafe.Pointer(&tmp_arg)), 0) if int(r0) == 0 { if e1 != 0 { err = error(e1) } else { err = syscall.EINVAL } } return } func write_console_output_attribute(h syscall.Handle, attrs []word, pos coord) (err error) { r0, _, e1 := syscall.Syscall6(proc_write_console_output_attribute.Addr(), 5, uintptr(h), uintptr(unsafe.Pointer(&attrs[0])), uintptr(len(attrs)), pos.uintptr(), uintptr(unsafe.Pointer(&tmp_arg)), 0) if int(r0) == 0 { if e1 != 0 { err = error(e1) } else { err = syscall.EINVAL } } return } func set_console_cursor_info(h syscall.Handle, info *console_cursor_info) (err error) { r0, _, e1 := syscall.Syscall(proc_set_console_cursor_info.Addr(), 2, uintptr(h), uintptr(unsafe.Pointer(info)), 0) if int(r0) == 0 { if e1 != 0 { err = error(e1) } else { err = syscall.EINVAL } } return } func get_console_cursor_info(h syscall.Handle, info *console_cursor_info) (err error) { r0, _, e1 := syscall.Syscall(proc_get_console_cursor_info.Addr(), 2, uintptr(h), uintptr(unsafe.Pointer(info)), 0) if int(r0) == 0 { if e1 != 0 { err = error(e1) } else { err = syscall.EINVAL } } return } func set_console_cursor_position(h syscall.Handle, pos coord) (err error) { r0, _, e1 := syscall.Syscall(proc_set_console_cursor_position.Addr(), 2, uintptr(h), pos.uintptr(), 0) if int(r0) == 0 { if e1 != 0 { err = error(e1) } else { err = syscall.EINVAL } } return } func read_console_input(h syscall.Handle, record *input_record) (err error) { r0, _, e1 := syscall.Syscall6(proc_read_console_input.Addr(), 4, uintptr(h), uintptr(unsafe.Pointer(record)), 1, uintptr(unsafe.Pointer(&tmp_arg)), 0, 0) if int(r0) == 0 { if e1 != 0 { err = error(e1) } else { err = syscall.EINVAL } } return } func get_console_mode(h syscall.Handle, mode *dword) (err error) { r0, _, e1 := syscall.Syscall(proc_get_console_mode.Addr(), 2, uintptr(h), uintptr(unsafe.Pointer(mode)), 0) if int(r0) == 0 { if e1 != 0 { err = error(e1) } else { err = syscall.EINVAL } } return } func set_console_mode(h syscall.Handle, mode dword) (err error) { r0, _, e1 := syscall.Syscall(proc_set_console_mode.Addr(), 2, uintptr(h), uintptr(mode), 0) if int(r0) == 0 { if e1 != 0 { err = error(e1) } else { err = syscall.EINVAL } } return } func fill_console_output_character(h syscall.Handle, char wchar, n int) (err error) { r0, _, e1 := syscall.Syscall6(proc_fill_console_output_character.Addr(), 5, uintptr(h), uintptr(char), uintptr(n), tmp_coord.uintptr(), uintptr(unsafe.Pointer(&tmp_arg)), 0) if int(r0) == 0 { if e1 != 0 { err = error(e1) } else { err = syscall.EINVAL } } return } func fill_console_output_attribute(h syscall.Handle, attr word, n int) (err error) { r0, _, e1 := syscall.Syscall6(proc_fill_console_output_attribute.Addr(), 5, uintptr(h), uintptr(attr), uintptr(n), tmp_coord.uintptr(), uintptr(unsafe.Pointer(&tmp_arg)), 0) if int(r0) == 0 { if e1 != 0 { err = error(e1) } else { err = syscall.EINVAL } } return } func create_event() (out syscall.Handle, err error) { r0, _, e1 := syscall.Syscall6(proc_create_event.Addr(), 4, 0, 0, 0, 0, 0, 0) if int(r0) == 0 { if e1 != 0 { err = error(e1) } else { err = syscall.EINVAL } } return syscall.Handle(r0), err } func wait_for_multiple_objects(objects []syscall.Handle) (err error) { r0, _, e1 := syscall.Syscall6(proc_wait_for_multiple_objects.Addr(), 4, uintptr(len(objects)), uintptr(unsafe.Pointer(&objects[0])), 0, 0xFFFFFFFF, 0, 0) if uint32(r0) == 0xFFFFFFFF { if e1 != 0 { err = error(e1) } else { err = syscall.EINVAL } } return } func set_event(ev syscall.Handle) (err error) { r0, _, e1 := syscall.Syscall(proc_set_event.Addr(), 1, uintptr(ev), 0, 0) if int(r0) == 0 { if e1 != 0 { err = error(e1) } else { err = syscall.EINVAL } } return } type diff_msg struct { pos short lines short chars []char_info } type input_event struct { event Event err error } var ( orig_cursor_info console_cursor_info orig_size coord orig_mode dword orig_screen syscall.Handle back_buffer cellbuf front_buffer cellbuf term_size coord input_mode = InputEsc cursor_x = cursor_hidden cursor_y = cursor_hidden foreground = ColorDefault background = ColorDefault in syscall.Handle out syscall.Handle interrupt syscall.Handle charbuf []char_info diffbuf []diff_msg beg_x = -1 beg_y = -1 beg_i = -1 input_comm = make(chan Event) interrupt_comm = make(chan struct{}) cancel_comm = make(chan bool, 1) cancel_done_comm = make(chan bool) alt_mode_esc = false // these ones just to prevent heap allocs at all costs tmp_info console_screen_buffer_info tmp_arg dword tmp_coord0 = coord{0, 0} tmp_coord = coord{0, 0} tmp_rect = small_rect{0, 0, 0, 0} ) func get_cursor_position(out syscall.Handle) coord { err := get_console_screen_buffer_info(out, &tmp_info) if err != nil { panic(err) } return tmp_info.cursor_position } func get_term_size(out syscall.Handle) coord { err := get_console_screen_buffer_info(out, &tmp_info) if err != nil { panic(err) } return tmp_info.size } func get_win_min_size(out syscall.Handle) coord { x, _, err := get_system_metrics.Call(SM_CXMIN) y, _, err := get_system_metrics.Call(SM_CYMIN) if x == 0 || y == 0 { if err != nil { panic(err) } } return coord{ x: short(x), y: short(y), } } func get_win_size(out syscall.Handle) coord { err := get_console_screen_buffer_info(out, &tmp_info) if err != nil { panic(err) } min_size := get_win_min_size(out) size := coord{ x: tmp_info.window.right - tmp_info.window.left + 1, y: tmp_info.window.bottom - tmp_info.window.top + 1, } if size.x < min_size.x { size.x = min_size.x } if size.y < min_size.y { size.y = min_size.y } return size } func update_size_maybe() { size := get_term_size(out) if size.x != term_size.x || size.y != term_size.y { term_size = size back_buffer.resize(int(size.x), int(size.y)) front_buffer.resize(int(size.x), int(size.y)) front_buffer.clear() clear() area := int(size.x) * int(size.y) if cap(charbuf) < area { charbuf = make([]char_info, 0, area) } } } var color_table_bg = []word{ 0, // default (black) 0, // black background_red, background_green, background_red | background_green, // yellow background_blue, background_red | background_blue, // magenta background_green | background_blue, // cyan background_red | background_blue | background_green, // white } var color_table_fg = []word{ foreground_red | foreground_blue | foreground_green, // default (white) 0, foreground_red, foreground_green, foreground_red | foreground_green, // yellow foreground_blue, foreground_red | foreground_blue, // magenta foreground_green | foreground_blue, // cyan foreground_red | foreground_blue | foreground_green, // white } const ( replacement_char = '\uFFFD' max_rune = '\U0010FFFF' surr1 = 0xd800 surr2 = 0xdc00 surr3 = 0xe000 surr_self = 0x10000 ) func append_diff_line(y int) int { n := 0 for x := 0; x < front_buffer.width; { cell_offset := y*front_buffer.width + x back := &back_buffer.cells[cell_offset] front := &front_buffer.cells[cell_offset] attr, char := cell_to_char_info(*back) charbuf = append(charbuf, char_info{attr: attr, char: char[0]}) *front = *back n++ w := runewidth.RuneWidth(back.Ch) if w == 0 || w == 2 && runewidth.IsAmbiguousWidth(back.Ch) { w = 1 } x += w // If not CJK, fill trailing space with whitespace if !is_cjk && w == 2 { charbuf = append(charbuf, char_info{attr: attr, char: ' '}) } } return n } // compares 'back_buffer' with 'front_buffer' and prepares all changes in the form of // 'diff_msg's in the 'diff_buf' func prepare_diff_messages() { // clear buffers diffbuf = diffbuf[:0] charbuf = charbuf[:0] var diff diff_msg gbeg := 0 for y := 0; y < front_buffer.height; y++ { same := true line_offset := y * front_buffer.width for x := 0; x < front_buffer.width; x++ { cell_offset := line_offset + x back := &back_buffer.cells[cell_offset] front := &front_buffer.cells[cell_offset] if *back != *front { same = false break } } if same && diff.lines > 0 { diffbuf = append(diffbuf, diff) diff = diff_msg{} } if !same { beg := len(charbuf) end := beg + append_diff_line(y) if diff.lines == 0 { diff.pos = short(y) gbeg = beg } diff.lines++ diff.chars = charbuf[gbeg:end] } } if diff.lines > 0 { diffbuf = append(diffbuf, diff) diff = diff_msg{} } } func get_ct(table []word, idx int) word { idx = idx & 0x0F if idx >= len(table) { idx = len(table) - 1 } return table[idx] } func cell_to_char_info(c Cell) (attr word, wc [2]wchar) { attr = get_ct(color_table_fg, int(c.Fg)) | get_ct(color_table_bg, int(c.Bg)) if c.Fg&AttrReverse|c.Bg&AttrReverse != 0 { attr = (attr&0xF0)>>4 | (attr&0x0F)<<4 } if c.Fg&AttrBold != 0 { attr |= foreground_intensity } if c.Bg&AttrBold != 0 { attr |= background_intensity } r0, r1 := utf16.EncodeRune(c.Ch) if r0 == 0xFFFD { wc[0] = wchar(c.Ch) wc[1] = ' ' } else { wc[0] = wchar(r0) wc[1] = wchar(r1) } return } func move_cursor(x, y int) { err := set_console_cursor_position(out, coord{short(x), short(y)}) if err != nil { panic(err) } } func show_cursor(visible bool) { var v int32 if visible { v = 1 } var info console_cursor_info info.size = 100 info.visible = v err := set_console_cursor_info(out, &info) if err != nil { panic(err) } } func clear() { var err error attr, char := cell_to_char_info(Cell{ ' ', foreground, background, }) area := int(term_size.x) * int(term_size.y) err = fill_console_output_attribute(out, attr, area) if err != nil { panic(err) } err = fill_console_output_character(out, char[0], area) if err != nil { panic(err) } if !is_cursor_hidden(cursor_x, cursor_y) { move_cursor(cursor_x, cursor_y) } } func key_event_record_to_event(r *key_event_record) (Event, bool) { if r.key_down == 0 { return Event{}, false } e := Event{Type: EventKey} if input_mode&InputAlt != 0 { if alt_mode_esc { e.Mod = ModAlt alt_mode_esc = false } if r.control_key_state&(left_alt_pressed|right_alt_pressed) != 0 { e.Mod = ModAlt } } ctrlpressed := r.control_key_state&(left_ctrl_pressed|right_ctrl_pressed) != 0 if r.virtual_key_code >= vk_f1 && r.virtual_key_code <= vk_f12 { switch r.virtual_key_code { case vk_f1: e.Key = KeyF1 case vk_f2: e.Key = KeyF2 case vk_f3: e.Key = KeyF3 case vk_f4: e.Key = KeyF4 case vk_f5: e.Key = KeyF5 case vk_f6: e.Key = KeyF6 case vk_f7: e.Key = KeyF7 case vk_f8: e.Key = KeyF8 case vk_f9: e.Key = KeyF9 case vk_f10: e.Key = KeyF10 case vk_f11: e.Key = KeyF11 case vk_f12: e.Key = KeyF12 default: panic("unreachable") } return e, true } if r.virtual_key_code <= vk_delete { switch r.virtual_key_code { case vk_insert: e.Key = KeyInsert case vk_delete: e.Key = KeyDelete case vk_home: e.Key = KeyHome case vk_end: e.Key = KeyEnd case vk_pgup: e.Key = KeyPgup case vk_pgdn: e.Key = KeyPgdn case vk_arrow_up: e.Key = KeyArrowUp case vk_arrow_down: e.Key = KeyArrowDown case vk_arrow_left: e.Key = KeyArrowLeft case vk_arrow_right: e.Key = KeyArrowRight case vk_backspace: if ctrlpressed { e.Key = KeyBackspace2 } else { e.Key = KeyBackspace } case vk_tab: e.Key = KeyTab case vk_enter: e.Key = KeyEnter case vk_esc: switch { case input_mode&InputEsc != 0: e.Key = KeyEsc case input_mode&InputAlt != 0: alt_mode_esc = true return Event{}, false } case vk_space: if ctrlpressed { // manual return here, because KeyCtrlSpace is zero e.Key = KeyCtrlSpace return e, true } else { e.Key = KeySpace } } if e.Key != 0 { return e, true } } if ctrlpressed { if Key(r.unicode_char) >= KeyCtrlA && Key(r.unicode_char) <= KeyCtrlRsqBracket { e.Key = Key(r.unicode_char) if input_mode&InputAlt != 0 && e.Key == KeyEsc { alt_mode_esc = true return Event{}, false } return e, true } switch r.virtual_key_code { case 192, 50: // manual return here, because KeyCtrl2 is zero e.Key = KeyCtrl2 return e, true case 51: if input_mode&InputAlt != 0 { alt_mode_esc = true return Event{}, false } e.Key = KeyCtrl3 case 52: e.Key = KeyCtrl4 case 53: e.Key = KeyCtrl5 case 54: e.Key = KeyCtrl6 case 189, 191, 55: e.Key = KeyCtrl7 case 8, 56: e.Key = KeyCtrl8 } if e.Key != 0 { return e, true } } if r.unicode_char != 0 { e.Ch = rune(r.unicode_char) return e, true } return Event{}, false } func input_event_producer() { var r input_record var err error var last_button Key var last_button_pressed Key var last_state = dword(0) var last_x, last_y = -1, -1 handles := []syscall.Handle{in, interrupt} for { err = wait_for_multiple_objects(handles) if err != nil { input_comm <- Event{Type: EventError, Err: err} } select { case <-cancel_comm: cancel_done_comm <- true return default: } err = read_console_input(in, &r) if err != nil { input_comm <- Event{Type: EventError, Err: err} } switch r.event_type { case key_event: kr := (*key_event_record)(unsafe.Pointer(&r.event)) ev, ok := key_event_record_to_event(kr) if ok { for i := 0; i < int(kr.repeat_count); i++ { input_comm <- ev } } case window_buffer_size_event: sr := *(*window_buffer_size_record)(unsafe.Pointer(&r.event)) input_comm <- Event{ Type: EventResize, Width: int(sr.size.x), Height: int(sr.size.y), } case mouse_event: mr := *(*mouse_event_record)(unsafe.Pointer(&r.event)) ev := Event{Type: EventMouse} switch mr.event_flags { case 0, 2: // single or double click cur_state := mr.button_state switch { case last_state&mouse_lmb == 0 && cur_state&mouse_lmb != 0: last_button = MouseLeft last_button_pressed = last_button case last_state&mouse_rmb == 0 && cur_state&mouse_rmb != 0: last_button = MouseRight last_button_pressed = last_button case last_state&mouse_mmb == 0 && cur_state&mouse_mmb != 0: last_button = MouseMiddle last_button_pressed = last_button case last_state&mouse_lmb != 0 && cur_state&mouse_lmb == 0: last_button = MouseRelease case last_state&mouse_rmb != 0 && cur_state&mouse_rmb == 0: last_button = MouseRelease case last_state&mouse_mmb != 0 && cur_state&mouse_mmb == 0: last_button = MouseRelease default: last_state = cur_state continue } last_state = cur_state ev.Key = last_button last_x, last_y = int(mr.mouse_pos.x), int(mr.mouse_pos.y) ev.MouseX = last_x ev.MouseY = last_y case 1: // mouse motion x, y := int(mr.mouse_pos.x), int(mr.mouse_pos.y) if last_state != 0 && (last_x != x || last_y != y) { ev.Key = last_button_pressed ev.Mod = ModMotion ev.MouseX = x ev.MouseY = y last_x, last_y = x, y } else { ev.Type = EventNone } case 4: // mouse wheel n := int16(mr.button_state >> 16) if n > 0 { ev.Key = MouseWheelUp } else { ev.Key = MouseWheelDown } last_x, last_y = int(mr.mouse_pos.x), int(mr.mouse_pos.y) ev.MouseX = last_x ev.MouseY = last_y default: ev.Type = EventNone } if ev.Type != EventNone { input_comm <- ev } } } } ================================================ FILE: vendor/github.com/nsf/termbox-go/terminfo.go ================================================ // +build !windows // This file contains a simple and incomplete implementation of the terminfo // database. Information was taken from the ncurses manpages term(5) and // terminfo(5). Currently, only the string capabilities for special keys and for // functions without parameters are actually used. Colors are still done with // ANSI escape sequences. Other special features that are not (yet?) supported // are reading from ~/.terminfo, the TERMINFO_DIRS variable, Berkeley database // format and extended capabilities. package termbox import ( "bytes" "encoding/binary" "encoding/hex" "errors" "fmt" "io/ioutil" "os" "strings" ) const ( ti_magic = 0432 ti_header_length = 12 ti_mouse_enter = "\x1b[?1000h\x1b[?1002h\x1b[?1015h\x1b[?1006h" ti_mouse_leave = "\x1b[?1006l\x1b[?1015l\x1b[?1002l\x1b[?1000l" ) func load_terminfo() ([]byte, error) { var data []byte var err error term := os.Getenv("TERM") if term == "" { return nil, fmt.Errorf("termbox: TERM not set") } // The following behaviour follows the one described in terminfo(5) as // distributed by ncurses. terminfo := os.Getenv("TERMINFO") if terminfo != "" { // if TERMINFO is set, no other directory should be searched return ti_try_path(terminfo) } // next, consider ~/.terminfo home := os.Getenv("HOME") if home != "" { data, err = ti_try_path(home + "/.terminfo") if err == nil { return data, nil } } // next, TERMINFO_DIRS dirs := os.Getenv("TERMINFO_DIRS") if dirs != "" { for _, dir := range strings.Split(dirs, ":") { if dir == "" { // "" -> "/usr/share/terminfo" dir = "/usr/share/terminfo" } data, err = ti_try_path(dir) if err == nil { return data, nil } } } // fall back to /usr/share/terminfo return ti_try_path("/usr/share/terminfo") } func ti_try_path(path string) (data []byte, err error) { // load_terminfo already made sure it is set term := os.Getenv("TERM") // first try, the typical *nix path terminfo := path + "/" + term[0:1] + "/" + term data, err = ioutil.ReadFile(terminfo) if err == nil { return } // fallback to darwin specific dirs structure terminfo = path + "/" + hex.EncodeToString([]byte(term[:1])) + "/" + term data, err = ioutil.ReadFile(terminfo) return } func setup_term_builtin() error { name := os.Getenv("TERM") if name == "" { return errors.New("termbox: TERM environment variable not set") } for _, t := range terms { if t.name == name { keys = t.keys funcs = t.funcs return nil } } compat_table := []struct { partial string keys []string funcs []string }{ {"xterm", xterm_keys, xterm_funcs}, {"rxvt", rxvt_unicode_keys, rxvt_unicode_funcs}, {"linux", linux_keys, linux_funcs}, {"Eterm", eterm_keys, eterm_funcs}, {"screen", screen_keys, screen_funcs}, // let's assume that 'cygwin' is xterm compatible {"cygwin", xterm_keys, xterm_funcs}, {"st", xterm_keys, xterm_funcs}, } // try compatibility variants for _, it := range compat_table { if strings.Contains(name, it.partial) { keys = it.keys funcs = it.funcs return nil } } return errors.New("termbox: unsupported terminal") } func setup_term() (err error) { var data []byte var header [6]int16 var str_offset, table_offset int16 data, err = load_terminfo() if err != nil { return setup_term_builtin() } rd := bytes.NewReader(data) // 0: magic number, 1: size of names section, 2: size of boolean section, 3: // size of numbers section (in integers), 4: size of the strings section (in // integers), 5: size of the string table err = binary.Read(rd, binary.LittleEndian, header[:]) if err != nil { return } if (header[1]+header[2])%2 != 0 { // old quirk to align everything on word boundaries header[2] += 1 } str_offset = ti_header_length + header[1] + header[2] + 2*header[3] table_offset = str_offset + 2*header[4] keys = make([]string, 0xFFFF-key_min) for i, _ := range keys { keys[i], err = ti_read_string(rd, str_offset+2*ti_keys[i], table_offset) if err != nil { return } } funcs = make([]string, t_max_funcs) // the last two entries are reserved for mouse. because the table offset is // not there, the two entries have to fill in manually for i, _ := range funcs[:len(funcs)-2] { funcs[i], err = ti_read_string(rd, str_offset+2*ti_funcs[i], table_offset) if err != nil { return } } funcs[t_max_funcs-2] = ti_mouse_enter funcs[t_max_funcs-1] = ti_mouse_leave return nil } func ti_read_string(rd *bytes.Reader, str_off, table int16) (string, error) { var off int16 _, err := rd.Seek(int64(str_off), 0) if err != nil { return "", err } err = binary.Read(rd, binary.LittleEndian, &off) if err != nil { return "", err } _, err = rd.Seek(int64(table+off), 0) if err != nil { return "", err } var bs []byte for { b, err := rd.ReadByte() if err != nil { return "", err } if b == byte(0x00) { break } bs = append(bs, b) } return string(bs), nil } // "Maps" the function constants from termbox.go to the number of the respective // string capability in the terminfo file. Taken from (ncurses) term.h. var ti_funcs = []int16{ 28, 40, 16, 13, 5, 39, 36, 27, 26, 34, 89, 88, } // Same as above for the special keys. var ti_keys = []int16{ 66, 68 /* apparently not a typo; 67 is F10 for whatever reason */, 69, 70, 71, 72, 73, 74, 75, 67, 216, 217, 77, 59, 76, 164, 82, 81, 87, 61, 79, 83, } ================================================ FILE: vendor/github.com/nsf/termbox-go/terminfo_builtin.go ================================================ // +build !windows package termbox // Eterm var eterm_keys = []string{ "\x1b[11~", "\x1b[12~", "\x1b[13~", "\x1b[14~", "\x1b[15~", "\x1b[17~", "\x1b[18~", "\x1b[19~", "\x1b[20~", "\x1b[21~", "\x1b[23~", "\x1b[24~", "\x1b[2~", "\x1b[3~", "\x1b[7~", "\x1b[8~", "\x1b[5~", "\x1b[6~", "\x1b[A", "\x1b[B", "\x1b[D", "\x1b[C", } var eterm_funcs = []string{ "\x1b7\x1b[?47h", "\x1b[2J\x1b[?47l\x1b8", "\x1b[?25h", "\x1b[?25l", "\x1b[H\x1b[2J", "\x1b[m\x0f", "\x1b[4m", "\x1b[1m", "\x1b[5m", "\x1b[7m", "", "", "", "", } // screen var screen_keys = []string{ "\x1bOP", "\x1bOQ", "\x1bOR", "\x1bOS", "\x1b[15~", "\x1b[17~", "\x1b[18~", "\x1b[19~", "\x1b[20~", "\x1b[21~", "\x1b[23~", "\x1b[24~", "\x1b[2~", "\x1b[3~", "\x1b[1~", "\x1b[4~", "\x1b[5~", "\x1b[6~", "\x1bOA", "\x1bOB", "\x1bOD", "\x1bOC", } var screen_funcs = []string{ "\x1b[?1049h", "\x1b[?1049l", "\x1b[34h\x1b[?25h", "\x1b[?25l", "\x1b[H\x1b[J", "\x1b[m\x0f", "\x1b[4m", "\x1b[1m", "\x1b[5m", "\x1b[7m", "\x1b[?1h\x1b=", "\x1b[?1l\x1b>", ti_mouse_enter, ti_mouse_leave, } // xterm var xterm_keys = []string{ "\x1bOP", "\x1bOQ", "\x1bOR", "\x1bOS", "\x1b[15~", "\x1b[17~", "\x1b[18~", "\x1b[19~", "\x1b[20~", "\x1b[21~", "\x1b[23~", "\x1b[24~", "\x1b[2~", "\x1b[3~", "\x1bOH", "\x1bOF", "\x1b[5~", "\x1b[6~", "\x1bOA", "\x1bOB", "\x1bOD", "\x1bOC", } var xterm_funcs = []string{ "\x1b[?1049h", "\x1b[?1049l", "\x1b[?12l\x1b[?25h", "\x1b[?25l", "\x1b[H\x1b[2J", "\x1b(B\x1b[m", "\x1b[4m", "\x1b[1m", "\x1b[5m", "\x1b[7m", "\x1b[?1h\x1b=", "\x1b[?1l\x1b>", ti_mouse_enter, ti_mouse_leave, } // rxvt-unicode var rxvt_unicode_keys = []string{ "\x1b[11~", "\x1b[12~", "\x1b[13~", "\x1b[14~", "\x1b[15~", "\x1b[17~", "\x1b[18~", "\x1b[19~", "\x1b[20~", "\x1b[21~", "\x1b[23~", "\x1b[24~", "\x1b[2~", "\x1b[3~", "\x1b[7~", "\x1b[8~", "\x1b[5~", "\x1b[6~", "\x1b[A", "\x1b[B", "\x1b[D", "\x1b[C", } var rxvt_unicode_funcs = []string{ "\x1b[?1049h", "\x1b[r\x1b[?1049l", "\x1b[?25h", "\x1b[?25l", "\x1b[H\x1b[2J", "\x1b[m\x1b(B", "\x1b[4m", "\x1b[1m", "\x1b[5m", "\x1b[7m", "\x1b=", "\x1b>", ti_mouse_enter, ti_mouse_leave, } // linux var linux_keys = []string{ "\x1b[[A", "\x1b[[B", "\x1b[[C", "\x1b[[D", "\x1b[[E", "\x1b[17~", "\x1b[18~", "\x1b[19~", "\x1b[20~", "\x1b[21~", "\x1b[23~", "\x1b[24~", "\x1b[2~", "\x1b[3~", "\x1b[1~", "\x1b[4~", "\x1b[5~", "\x1b[6~", "\x1b[A", "\x1b[B", "\x1b[D", "\x1b[C", } var linux_funcs = []string{ "", "", "\x1b[?25h\x1b[?0c", "\x1b[?25l\x1b[?1c", "\x1b[H\x1b[J", "\x1b[0;10m", "\x1b[4m", "\x1b[1m", "\x1b[5m", "\x1b[7m", "", "", "", "", } // rxvt-256color var rxvt_256color_keys = []string{ "\x1b[11~", "\x1b[12~", "\x1b[13~", "\x1b[14~", "\x1b[15~", "\x1b[17~", "\x1b[18~", "\x1b[19~", "\x1b[20~", "\x1b[21~", "\x1b[23~", "\x1b[24~", "\x1b[2~", "\x1b[3~", "\x1b[7~", "\x1b[8~", "\x1b[5~", "\x1b[6~", "\x1b[A", "\x1b[B", "\x1b[D", "\x1b[C", } var rxvt_256color_funcs = []string{ "\x1b7\x1b[?47h", "\x1b[2J\x1b[?47l\x1b8", "\x1b[?25h", "\x1b[?25l", "\x1b[H\x1b[2J", "\x1b[m\x0f", "\x1b[4m", "\x1b[1m", "\x1b[5m", "\x1b[7m", "\x1b=", "\x1b>", ti_mouse_enter, ti_mouse_leave, } var terms = []struct { name string keys []string funcs []string }{ {"Eterm", eterm_keys, eterm_funcs}, {"screen", screen_keys, screen_funcs}, {"xterm", xterm_keys, xterm_funcs}, {"rxvt-unicode", rxvt_unicode_keys, rxvt_unicode_funcs}, {"linux", linux_keys, linux_funcs}, {"rxvt-256color", rxvt_256color_keys, rxvt_256color_funcs}, } ================================================ FILE: vendor/github.com/spf13/cobra/.gitignore ================================================ # Compiled Object files, Static and Dynamic libs (Shared Objects) *.o *.a *.so # Folders _obj _test # Architecture specific extensions/prefixes *.[568vq] [568vq].out *.cgo1.go *.cgo2.c _cgo_defun.c _cgo_gotypes.go _cgo_export.* _testmain.go # Vim files https://github.com/github/gitignore/blob/master/Global/Vim.gitignore # swap [._]*.s[a-w][a-z] [._]s[a-w][a-z] # session Session.vim # temporary .netrwhist *~ # auto-generated tag files tags *.exe cobra.test ================================================ FILE: vendor/github.com/spf13/cobra/.mailmap ================================================ Steve Francia Bjørn Erik Pedersen Fabiano Franz ================================================ FILE: vendor/github.com/spf13/cobra/.travis.yml ================================================ language: go matrix: include: - go: 1.7.6 - go: 1.8.3 - go: tip allow_failures: - go: tip before_install: - mkdir -p bin - curl -Lso bin/shellcheck https://github.com/caarlos0/shellcheck-docker/releases/download/v0.4.3/shellcheck - chmod +x bin/shellcheck script: - PATH=$PATH:$PWD/bin go test -v ./... - go build - diff -u <(echo -n) <(gofmt -d -s .) - if [ -z $NOVET ]; then diff -u <(echo -n) <(go tool vet . 2>&1 | grep -vE 'ExampleCommand|bash_completions.*Fprint'); fi ================================================ FILE: vendor/github.com/spf13/cobra/LICENSE.txt ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. ================================================ FILE: vendor/github.com/spf13/cobra/README.md ================================================ ![cobra logo](https://cloud.githubusercontent.com/assets/173412/10886352/ad566232-814f-11e5-9cd0-aa101788c117.png) Cobra is both a library for creating powerful modern CLI applications as well as a program to generate applications and command files. Many of the most widely used Go projects are built using Cobra including: * [Kubernetes](http://kubernetes.io/) * [Hugo](http://gohugo.io) * [rkt](https://github.com/coreos/rkt) * [etcd](https://github.com/coreos/etcd) * [Moby (former Docker)](https://github.com/moby/moby) * [Docker (distribution)](https://github.com/docker/distribution) * [OpenShift](https://www.openshift.com/) * [Delve](https://github.com/derekparker/delve) * [GopherJS](http://www.gopherjs.org/) * [CockroachDB](http://www.cockroachlabs.com/) * [Bleve](http://www.blevesearch.com/) * [ProjectAtomic (enterprise)](http://www.projectatomic.io/) * [GiantSwarm's swarm](https://github.com/giantswarm/cli) * [Nanobox](https://github.com/nanobox-io/nanobox)/[Nanopack](https://github.com/nanopack) * [rclone](http://rclone.org/) * [nehm](https://github.com/bogem/nehm) * [Pouch](https://github.com/alibaba/pouch) [![Build Status](https://travis-ci.org/spf13/cobra.svg "Travis CI status")](https://travis-ci.org/spf13/cobra) [![CircleCI status](https://circleci.com/gh/spf13/cobra.png?circle-token=:circle-token "CircleCI status")](https://circleci.com/gh/spf13/cobra) [![GoDoc](https://godoc.org/github.com/spf13/cobra?status.svg)](https://godoc.org/github.com/spf13/cobra) # Table of Contents - [Overview](#overview) - [Concepts](#concepts) * [Commands](#commands) * [Flags](#flags) - [Installing](#installing) - [Getting Started](#getting-started) * [Using the Cobra Generator](#using-the-cobra-generator) * [Using the Cobra Library](#using-the-cobra-library) * [Working with Flags](#working-with-flags) * [Positional and Custom Arguments](#positional-and-custom-arguments) * [Example](#example) * [Help Command](#help-command) * [Usage Message](#usage-message) * [PreRun and PostRun Hooks](#prerun-and-postrun-hooks) * [Suggestions when "unknown command" happens](#suggestions-when-unknown-command-happens) * [Generating documentation for your command](#generating-documentation-for-your-command) * [Generating bash completions](#generating-bash-completions) - [Contributing](#contributing) - [License](#license) # Overview Cobra is a library providing a simple interface to create powerful modern CLI interfaces similar to git & go tools. Cobra is also an application that will generate your application scaffolding to rapidly develop a Cobra-based application. Cobra provides: * Easy subcommand-based CLIs: `app server`, `app fetch`, etc. * Fully POSIX-compliant flags (including short & long versions) * Nested subcommands * Global, local and cascading flags * Easy generation of applications & commands with `cobra init appname` & `cobra add cmdname` * Intelligent suggestions (`app srver`... did you mean `app server`?) * Automatic help generation for commands and flags * Automatic help flag recognition of `-h`, `--help`, etc. * Automatically generated bash autocomplete for your application * Automatically generated man pages for your application * Command aliases so you can change things without breaking them * The flexibility to define your own help, usage, etc. * Optional tight integration with [viper](http://github.com/spf13/viper) for 12-factor apps # Concepts Cobra is built on a structure of commands, arguments & flags. **Commands** represent actions, **Args** are things and **Flags** are modifiers for those actions. The best applications will read like sentences when used. Users will know how to use the application because they will natively understand how to use it. The pattern to follow is `APPNAME VERB NOUN --ADJECTIVE.` or `APPNAME COMMAND ARG --FLAG` A few good real world examples may better illustrate this point. In the following example, 'server' is a command, and 'port' is a flag: hugo server --port=1313 In this command we are telling Git to clone the url bare. git clone URL --bare ## Commands Command is the central point of the application. Each interaction that the application supports will be contained in a Command. A command can have children commands and optionally run an action. In the example above, 'server' is the command. [More about cobra.Command](https://godoc.org/github.com/spf13/cobra#Command) ## Flags A flag is a way to modify the behavior of a command. Cobra supports fully POSIX-compliant flags as well as the Go [flag package](https://golang.org/pkg/flag/). A Cobra command can define flags that persist through to children commands and flags that are only available to that command. In the example above, 'port' is the flag. Flag functionality is provided by the [pflag library](https://github.com/spf13/pflag), a fork of the flag standard library which maintains the same interface while adding POSIX compliance. # Installing Using Cobra is easy. First, use `go get` to install the latest version of the library. This command will install the `cobra` generator executable along with the library and its dependencies: go get -u github.com/spf13/cobra/cobra Next, include Cobra in your application: ```go import "github.com/spf13/cobra" ``` # Getting Started While you are welcome to provide your own organization, typically a Cobra-based application will follow the following organizational structure: ``` ▾ appName/ ▾ cmd/ add.go your.go commands.go here.go main.go ``` In a Cobra app, typically the main.go file is very bare. It serves one purpose: initializing Cobra. ```go package main import ( "fmt" "os" "{pathToYourApp}/cmd" ) func main() { cmd.Execute() } ``` ## Using the Cobra Generator Cobra provides its own program that will create your application and add any commands you want. It's the easiest way to incorporate Cobra into your application. [Here](https://github.com/spf13/cobra/blob/master/cobra/README.md) you can find more information about it. ## Using the Cobra Library To manually implement Cobra you need to create a bare main.go file and a rootCmd file. You will optionally provide additional commands as you see fit. ### Create rootCmd Cobra doesn't require any special constructors. Simply create your commands. Ideally you place this in app/cmd/root.go: ```go var rootCmd = &cobra.Command{ Use: "hugo", Short: "Hugo is a very fast static site generator", Long: `A Fast and Flexible Static Site Generator built with love by spf13 and friends in Go. Complete documentation is available at http://hugo.spf13.com`, Run: func(cmd *cobra.Command, args []string) { // Do Stuff Here }, } ``` You will additionally define flags and handle configuration in your init() function. For example cmd/root.go: ```go import ( "fmt" "os" homedir "github.com/mitchellh/go-homedir" "github.com/spf13/cobra" "github.com/spf13/viper" ) func init() { cobra.OnInitialize(initConfig) rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobra.yaml)") rootCmd.PersistentFlags().StringVarP(&projectBase, "projectbase", "b", "", "base project directory eg. github.com/spf13/") rootCmd.PersistentFlags().StringP("author", "a", "YOUR NAME", "Author name for copyright attribution") rootCmd.PersistentFlags().StringVarP(&userLicense, "license", "l", "", "Name of license for the project (can provide `licensetext` in config)") rootCmd.PersistentFlags().Bool("viper", true, "Use Viper for configuration") viper.BindPFlag("author", rootCmd.PersistentFlags().Lookup("author")) viper.BindPFlag("projectbase", rootCmd.PersistentFlags().Lookup("projectbase")) viper.BindPFlag("useViper", rootCmd.PersistentFlags().Lookup("viper")) viper.SetDefault("author", "NAME HERE ") viper.SetDefault("license", "apache") } func initConfig() { // Don't forget to read config either from cfgFile or from home directory! if cfgFile != "" { // Use config file from the flag. viper.SetConfigFile(cfgFile) } else { // Find home directory. home, err := homedir.Dir() if err != nil { fmt.Println(err) os.Exit(1) } // Search config in home directory with name ".cobra" (without extension). viper.AddConfigPath(home) viper.SetConfigName(".cobra") } if err := viper.ReadInConfig(); err != nil { fmt.Println("Can't read config:", err) os.Exit(1) } } ``` ### Create your main.go With the root command you need to have your main function execute it. Execute should be run on the root for clarity, though it can be called on any command. In a Cobra app, typically the main.go file is very bare. It serves, one purpose, to initialize Cobra. ```go package main import ( "fmt" "os" "{pathToYourApp}/cmd" ) func main() { cmd.Execute() } ``` ### Create additional commands Additional commands can be defined and typically are each given their own file inside of the cmd/ directory. If you wanted to create a version command you would create cmd/version.go and populate it with the following: ```go package cmd import ( "fmt" "github.com/spf13/cobra" ) func init() { rootCmd.AddCommand(versionCmd) } var versionCmd = &cobra.Command{ Use: "version", Short: "Print the version number of Hugo", Long: `All software has versions. This is Hugo's`, Run: func(cmd *cobra.Command, args []string) { fmt.Println("Hugo Static Site Generator v0.9 -- HEAD") }, } ``` ## Working with Flags Flags provide modifiers to control how the action command operates. ### Assign flags to a command Since the flags are defined and used in different locations, we need to define a variable outside with the correct scope to assign the flag to work with. ```go var Verbose bool var Source string ``` There are two different approaches to assign a flag. ### Persistent Flags A flag can be 'persistent' meaning that this flag will be available to the command it's assigned to as well as every command under that command. For global flags, assign a flag as a persistent flag on the root. ```go rootCmd.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "verbose output") ``` ### Local Flags A flag can also be assigned locally which will only apply to that specific command. ```go rootCmd.Flags().StringVarP(&Source, "source", "s", "", "Source directory to read from") ``` ### Local Flag on Parent Commands By default Cobra only parses local flags on the target command, any local flags on parent commands are ignored. By enabling `Command.TraverseChildren` Cobra will parse local flags on each command before executing the target command. ```go command := cobra.Command{ Use: "print [OPTIONS] [COMMANDS]", TraverseChildren: true, } ``` ### Bind Flags with Config You can also bind your flags with [viper](https://github.com/spf13/viper): ```go var author string func init() { rootCmd.PersistentFlags().StringVar(&author, "author", "YOUR NAME", "Author name for copyright attribution") viper.BindPFlag("author", rootCmd.PersistentFlags().Lookup("author")) } ``` In this example the persistent flag `author` is bound with `viper`. **Note**, that the variable `author` will not be set to the value from config, when the `--author` flag is not provided by user. More in [viper documentation](https://github.com/spf13/viper#working-with-flags). ## Positional and Custom Arguments Validation of positional arguments can be specified using the `Args` field of `Command`. The following validators are built in: - `NoArgs` - the command will report an error if there are any positional args. - `ArbitraryArgs` - the command will accept any args. - `OnlyValidArgs` - the command will report an error if there are any positional args that are not in the `ValidArgs` field of `Command`. - `MinimumNArgs(int)` - the command will report an error if there are not at least N positional args. - `MaximumNArgs(int)` - the command will report an error if there are more than N positional args. - `ExactArgs(int)` - the command will report an error if there are not exactly N positional args. - `RangeArgs(min, max)` - the command will report an error if the number of args is not between the minimum and maximum number of expected args. An example of setting the custom validator: ```go var cmd = &cobra.Command{ Short: "hello", Args: func(cmd *cobra.Command, args []string) error { if len(args) < 1 { return errors.New("requires at least one arg") } if myapp.IsValidColor(args[0]) { return nil } return fmt.Errorf("invalid color specified: %s", args[0]) }, Run: func(cmd *cobra.Command, args []string) { fmt.Println("Hello, World!") }, } ``` ## Example In the example below, we have defined three commands. Two are at the top level and one (cmdTimes) is a child of one of the top commands. In this case the root is not executable meaning that a subcommand is required. This is accomplished by not providing a 'Run' for the 'rootCmd'. We have only defined one flag for a single command. More documentation about flags is available at https://github.com/spf13/pflag ```go package main import ( "fmt" "strings" "github.com/spf13/cobra" ) func main() { var echoTimes int var cmdPrint = &cobra.Command{ Use: "print [string to print]", Short: "Print anything to the screen", Long: `print is for printing anything back to the screen. For many years people have printed back to the screen.`, Args: cobra.MinimumNArgs(1), Run: func(cmd *cobra.Command, args []string) { fmt.Println("Print: " + strings.Join(args, " ")) }, } var cmdEcho = &cobra.Command{ Use: "echo [string to echo]", Short: "Echo anything to the screen", Long: `echo is for echoing anything back. Echo works a lot like print, except it has a child command.`, Args: cobra.MinimumNArgs(1), Run: func(cmd *cobra.Command, args []string) { fmt.Println("Print: " + strings.Join(args, " ")) }, } var cmdTimes = &cobra.Command{ Use: "times [# times] [string to echo]", Short: "Echo anything to the screen more times", Long: `echo things multiple times back to the user by providing a count and a string.`, Args: cobra.MinimumNArgs(1), Run: func(cmd *cobra.Command, args []string) { for i := 0; i < echoTimes; i++ { fmt.Println("Echo: " + strings.Join(args, " ")) } }, } cmdTimes.Flags().IntVarP(&echoTimes, "times", "t", 1, "times to echo the input") var rootCmd = &cobra.Command{Use: "app"} rootCmd.AddCommand(cmdPrint, cmdEcho) cmdEcho.AddCommand(cmdTimes) rootCmd.Execute() } ``` For a more complete example of a larger application, please checkout [Hugo](http://gohugo.io/). ## Help Command Cobra automatically adds a help command to your application when you have subcommands. This will be called when a user runs 'app help'. Additionally, help will also support all other commands as input. Say, for instance, you have a command called 'create' without any additional configuration; Cobra will work when 'app help create' is called. Every command will automatically have the '--help' flag added. ### Example The following output is automatically generated by Cobra. Nothing beyond the command and flag definitions are needed. $ cobra help Cobra is a CLI library for Go that empowers applications. This application is a tool to generate the needed files to quickly create a Cobra application. Usage: cobra [command] Available Commands: add Add a command to a Cobra Application help Help about any command init Initialize a Cobra Application Flags: -a, --author string author name for copyright attribution (default "YOUR NAME") --config string config file (default is $HOME/.cobra.yaml) -h, --help help for cobra -l, --license string name of license for the project --viper use Viper for configuration (default true) Use "cobra [command] --help" for more information about a command. Help is just a command like any other. There is no special logic or behavior around it. In fact, you can provide your own if you want. ### Defining your own help You can provide your own Help command or your own template for the default command to use with following functions: ```go cmd.SetHelpCommand(cmd *Command) cmd.SetHelpFunc(f func(*Command, []string)) cmd.SetHelpTemplate(s string) ``` The latter two will also apply to any children commands. ## Usage Message When the user provides an invalid flag or invalid command, Cobra responds by showing the user the 'usage'. ### Example You may recognize this from the help above. That's because the default help embeds the usage as part of its output. $ cobra --invalid Error: unknown flag: --invalid Usage: cobra [command] Available Commands: add Add a command to a Cobra Application help Help about any command init Initialize a Cobra Application Flags: -a, --author string author name for copyright attribution (default "YOUR NAME") --config string config file (default is $HOME/.cobra.yaml) -h, --help help for cobra -l, --license string name of license for the project --viper use Viper for configuration (default true) Use "cobra [command] --help" for more information about a command. ### Defining your own usage You can provide your own usage function or template for Cobra to use. Like help, the function and template are overridable through public methods: ```go cmd.SetUsageFunc(f func(*Command) error) cmd.SetUsageTemplate(s string) ``` ## Version Flag Cobra adds a top-level '--version' flag if the Version field is set on the root command. Running an application with the '--version' flag will print the version to stdout using the version template. The template can be customized using the `cmd.SetVersionTemplate(s string)` function. ## PreRun and PostRun Hooks It is possible to run functions before or after the main `Run` function of your command. The `PersistentPreRun` and `PreRun` functions will be executed before `Run`. `PersistentPostRun` and `PostRun` will be executed after `Run`. The `Persistent*Run` functions will be inherited by children if they do not declare their own. These functions are run in the following order: - `PersistentPreRun` - `PreRun` - `Run` - `PostRun` - `PersistentPostRun` An example of two commands which use all of these features is below. When the subcommand is executed, it will run the root command's `PersistentPreRun` but not the root command's `PersistentPostRun`: ```go package main import ( "fmt" "github.com/spf13/cobra" ) func main() { var rootCmd = &cobra.Command{ Use: "root [sub]", Short: "My root command", PersistentPreRun: func(cmd *cobra.Command, args []string) { fmt.Printf("Inside rootCmd PersistentPreRun with args: %v\n", args) }, PreRun: func(cmd *cobra.Command, args []string) { fmt.Printf("Inside rootCmd PreRun with args: %v\n", args) }, Run: func(cmd *cobra.Command, args []string) { fmt.Printf("Inside rootCmd Run with args: %v\n", args) }, PostRun: func(cmd *cobra.Command, args []string) { fmt.Printf("Inside rootCmd PostRun with args: %v\n", args) }, PersistentPostRun: func(cmd *cobra.Command, args []string) { fmt.Printf("Inside rootCmd PersistentPostRun with args: %v\n", args) }, } var subCmd = &cobra.Command{ Use: "sub [no options!]", Short: "My subcommand", PreRun: func(cmd *cobra.Command, args []string) { fmt.Printf("Inside subCmd PreRun with args: %v\n", args) }, Run: func(cmd *cobra.Command, args []string) { fmt.Printf("Inside subCmd Run with args: %v\n", args) }, PostRun: func(cmd *cobra.Command, args []string) { fmt.Printf("Inside subCmd PostRun with args: %v\n", args) }, PersistentPostRun: func(cmd *cobra.Command, args []string) { fmt.Printf("Inside subCmd PersistentPostRun with args: %v\n", args) }, } rootCmd.AddCommand(subCmd) rootCmd.SetArgs([]string{""}) rootCmd.Execute() fmt.Println() rootCmd.SetArgs([]string{"sub", "arg1", "arg2"}) rootCmd.Execute() } ``` Output: ``` Inside rootCmd PersistentPreRun with args: [] Inside rootCmd PreRun with args: [] Inside rootCmd Run with args: [] Inside rootCmd PostRun with args: [] Inside rootCmd PersistentPostRun with args: [] Inside rootCmd PersistentPreRun with args: [arg1 arg2] Inside subCmd PreRun with args: [arg1 arg2] Inside subCmd Run with args: [arg1 arg2] Inside subCmd PostRun with args: [arg1 arg2] Inside subCmd PersistentPostRun with args: [arg1 arg2] ``` ## Suggestions when "unknown command" happens Cobra will print automatic suggestions when "unknown command" errors happen. This allows Cobra to behave similarly to the `git` command when a typo happens. For example: ``` $ hugo srever Error: unknown command "srever" for "hugo" Did you mean this? server Run 'hugo --help' for usage. ``` Suggestions are automatic based on every subcommand registered and use an implementation of [Levenshtein distance](http://en.wikipedia.org/wiki/Levenshtein_distance). Every registered command that matches a minimum distance of 2 (ignoring case) will be displayed as a suggestion. If you need to disable suggestions or tweak the string distance in your command, use: ```go command.DisableSuggestions = true ``` or ```go command.SuggestionsMinimumDistance = 1 ``` You can also explicitly set names for which a given command will be suggested using the `SuggestFor` attribute. This allows suggestions for strings that are not close in terms of string distance, but makes sense in your set of commands and for some which you don't want aliases. Example: ``` $ kubectl remove Error: unknown command "remove" for "kubectl" Did you mean this? delete Run 'kubectl help' for usage. ``` ## Generating documentation for your command Cobra can generate documentation based on subcommands, flags, etc. in the following formats: - [Markdown](doc/md_docs.md) - [ReStructured Text](doc/rest_docs.md) - [Man Page](doc/man_docs.md) ## Generating bash completions Cobra can generate a bash-completion file. If you add more information to your command, these completions can be amazingly powerful and flexible. Read more about it in [Bash Completions](bash_completions.md). # Contributing 1. Fork it 2. Download your fork to your PC (`git clone https://github.com/your_username/cobra && cd cobra`) 3. Create your feature branch (`git checkout -b my-new-feature`) 4. Make changes and add them (`git add .`) 5. Commit your changes (`git commit -m 'Add some feature'`) 6. Push to the branch (`git push origin my-new-feature`) 7. Create new pull request # License Cobra is released under the Apache 2.0 license. See [LICENSE.txt](https://github.com/spf13/cobra/blob/master/LICENSE.txt) ================================================ FILE: vendor/github.com/spf13/cobra/args.go ================================================ package cobra import ( "fmt" ) type PositionalArgs func(cmd *Command, args []string) error // Legacy arg validation has the following behaviour: // - root commands with no subcommands can take arbitrary arguments // - root commands with subcommands will do subcommand validity checking // - subcommands will always accept arbitrary arguments func legacyArgs(cmd *Command, args []string) error { // no subcommand, always take args if !cmd.HasSubCommands() { return nil } // root command with subcommands, do subcommand checking. if !cmd.HasParent() && len(args) > 0 { return fmt.Errorf("unknown command %q for %q%s", args[0], cmd.CommandPath(), cmd.findSuggestions(args[0])) } return nil } // NoArgs returns an error if any args are included. func NoArgs(cmd *Command, args []string) error { if len(args) > 0 { return fmt.Errorf("unknown command %q for %q", args[0], cmd.CommandPath()) } return nil } // OnlyValidArgs returns an error if any args are not in the list of ValidArgs. func OnlyValidArgs(cmd *Command, args []string) error { if len(cmd.ValidArgs) > 0 { for _, v := range args { if !stringInSlice(v, cmd.ValidArgs) { return fmt.Errorf("invalid argument %q for %q%s", v, cmd.CommandPath(), cmd.findSuggestions(args[0])) } } } return nil } // ArbitraryArgs never returns an error. func ArbitraryArgs(cmd *Command, args []string) error { return nil } // MinimumNArgs returns an error if there is not at least N args. func MinimumNArgs(n int) PositionalArgs { return func(cmd *Command, args []string) error { if len(args) < n { return fmt.Errorf("requires at least %d arg(s), only received %d", n, len(args)) } return nil } } // MaximumNArgs returns an error if there are more than N args. func MaximumNArgs(n int) PositionalArgs { return func(cmd *Command, args []string) error { if len(args) > n { return fmt.Errorf("accepts at most %d arg(s), received %d", n, len(args)) } return nil } } // ExactArgs returns an error if there are not exactly n args. func ExactArgs(n int) PositionalArgs { return func(cmd *Command, args []string) error { if len(args) != n { return fmt.Errorf("accepts %d arg(s), received %d", n, len(args)) } return nil } } // RangeArgs returns an error if the number of args is not within the expected range. func RangeArgs(min int, max int) PositionalArgs { return func(cmd *Command, args []string) error { if len(args) < min || len(args) > max { return fmt.Errorf("accepts between %d and %d arg(s), received %d", min, max, len(args)) } return nil } } ================================================ FILE: vendor/github.com/spf13/cobra/args_test.go ================================================ package cobra import ( "strings" "testing" ) func TestNoArgs(t *testing.T) { c := &Command{Use: "c", Args: NoArgs, Run: emptyRun} output, err := executeCommand(c) if output != "" { t.Errorf("Unexpected string: %v", output) } if err != nil { t.Fatalf("Unexpected error: %v", err) } } func TestNoArgsWithArgs(t *testing.T) { c := &Command{Use: "c", Args: NoArgs, Run: emptyRun} _, err := executeCommand(c, "illegal") if err == nil { t.Fatal("Expected an error") } got := err.Error() expected := `unknown command "illegal" for "c"` if got != expected { t.Errorf("Expected: %q, got: %q", expected, got) } } func TestOnlyValidArgs(t *testing.T) { c := &Command{ Use: "c", Args: OnlyValidArgs, ValidArgs: []string{"one", "two"}, Run: emptyRun, } output, err := executeCommand(c, "one", "two") if output != "" { t.Errorf("Unexpected output: %v", output) } if err != nil { t.Fatalf("Unexpected error: %v", err) } } func TestOnlyValidArgsWithInvalidArgs(t *testing.T) { c := &Command{ Use: "c", Args: OnlyValidArgs, ValidArgs: []string{"one", "two"}, Run: emptyRun, } _, err := executeCommand(c, "three") if err == nil { t.Fatal("Expected an error") } got := err.Error() expected := `invalid argument "three" for "c"` if got != expected { t.Errorf("Expected: %q, got: %q", expected, got) } } func TestArbitraryArgs(t *testing.T) { c := &Command{Use: "c", Args: ArbitraryArgs, Run: emptyRun} output, err := executeCommand(c, "a", "b") if output != "" { t.Errorf("Unexpected output: %v", output) } if err != nil { t.Errorf("Unexpected error: %v", err) } } func TestMinimumNArgs(t *testing.T) { c := &Command{Use: "c", Args: MinimumNArgs(2), Run: emptyRun} output, err := executeCommand(c, "a", "b", "c") if output != "" { t.Errorf("Unexpected output: %v", output) } if err != nil { t.Errorf("Unexpected error: %v", err) } } func TestMinimumNArgsWithLessArgs(t *testing.T) { c := &Command{Use: "c", Args: MinimumNArgs(2), Run: emptyRun} _, err := executeCommand(c, "a") if err == nil { t.Fatal("Expected an error") } got := err.Error() expected := "requires at least 2 arg(s), only received 1" if got != expected { t.Fatalf("Expected %q, got %q", expected, got) } } func TestMaximumNArgs(t *testing.T) { c := &Command{Use: "c", Args: MaximumNArgs(3), Run: emptyRun} output, err := executeCommand(c, "a", "b") if output != "" { t.Errorf("Unexpected output: %v", output) } if err != nil { t.Errorf("Unexpected error: %v", err) } } func TestMaximumNArgsWithMoreArgs(t *testing.T) { c := &Command{Use: "c", Args: MaximumNArgs(2), Run: emptyRun} _, err := executeCommand(c, "a", "b", "c") if err == nil { t.Fatal("Expected an error") } got := err.Error() expected := "accepts at most 2 arg(s), received 3" if got != expected { t.Fatalf("Expected %q, got %q", expected, got) } } func TestExactArgs(t *testing.T) { c := &Command{Use: "c", Args: ExactArgs(3), Run: emptyRun} output, err := executeCommand(c, "a", "b", "c") if output != "" { t.Errorf("Unexpected output: %v", output) } if err != nil { t.Errorf("Unexpected error: %v", err) } } func TestExactArgsWithInvalidCount(t *testing.T) { c := &Command{Use: "c", Args: ExactArgs(2), Run: emptyRun} _, err := executeCommand(c, "a", "b", "c") if err == nil { t.Fatal("Expected an error") } got := err.Error() expected := "accepts 2 arg(s), received 3" if got != expected { t.Fatalf("Expected %q, got %q", expected, got) } } func TestRangeArgs(t *testing.T) { c := &Command{Use: "c", Args: RangeArgs(2, 4), Run: emptyRun} output, err := executeCommand(c, "a", "b", "c") if output != "" { t.Errorf("Unexpected output: %v", output) } if err != nil { t.Errorf("Unexpected error: %v", err) } } func TestRangeArgsWithInvalidCount(t *testing.T) { c := &Command{Use: "c", Args: RangeArgs(2, 4), Run: emptyRun} _, err := executeCommand(c, "a") if err == nil { t.Fatal("Expected an error") } got := err.Error() expected := "accepts between 2 and 4 arg(s), received 1" if got != expected { t.Fatalf("Expected %q, got %q", expected, got) } } func TestRootTakesNoArgs(t *testing.T) { rootCmd := &Command{Use: "root", Run: emptyRun} childCmd := &Command{Use: "child", Run: emptyRun} rootCmd.AddCommand(childCmd) _, err := executeCommand(rootCmd, "illegal", "args") if err == nil { t.Fatal("Expected an error") } got := err.Error() expected := `unknown command "illegal" for "root"` if !strings.Contains(got, expected) { t.Errorf("expected %q, got %q", expected, got) } } func TestRootTakesArgs(t *testing.T) { rootCmd := &Command{Use: "root", Args: ArbitraryArgs, Run: emptyRun} childCmd := &Command{Use: "child", Run: emptyRun} rootCmd.AddCommand(childCmd) _, err := executeCommand(rootCmd, "legal", "args") if err != nil { t.Errorf("Unexpected error: %v", err) } } func TestChildTakesNoArgs(t *testing.T) { rootCmd := &Command{Use: "root", Run: emptyRun} childCmd := &Command{Use: "child", Args: NoArgs, Run: emptyRun} rootCmd.AddCommand(childCmd) _, err := executeCommand(rootCmd, "child", "illegal", "args") if err == nil { t.Fatal("Expected an error") } got := err.Error() expected := `unknown command "illegal" for "root child"` if !strings.Contains(got, expected) { t.Errorf("expected %q, got %q", expected, got) } } func TestChildTakesArgs(t *testing.T) { rootCmd := &Command{Use: "root", Run: emptyRun} childCmd := &Command{Use: "child", Args: ArbitraryArgs, Run: emptyRun} rootCmd.AddCommand(childCmd) _, err := executeCommand(rootCmd, "child", "legal", "args") if err != nil { t.Fatalf("Unexpected error: %v", err) } } ================================================ FILE: vendor/github.com/spf13/cobra/bash_completions.go ================================================ package cobra import ( "bytes" "fmt" "io" "os" "sort" "strings" "github.com/spf13/pflag" ) // Annotations for Bash completion. const ( BashCompFilenameExt = "cobra_annotation_bash_completion_filename_extensions" BashCompCustom = "cobra_annotation_bash_completion_custom" BashCompOneRequiredFlag = "cobra_annotation_bash_completion_one_required_flag" BashCompSubdirsInDir = "cobra_annotation_bash_completion_subdirs_in_dir" ) func writePreamble(buf *bytes.Buffer, name string) { buf.WriteString(fmt.Sprintf("# bash completion for %-36s -*- shell-script -*-\n", name)) buf.WriteString(` __debug() { if [[ -n ${BASH_COMP_DEBUG_FILE} ]]; then echo "$*" >> "${BASH_COMP_DEBUG_FILE}" fi } # Homebrew on Macs have version 1.3 of bash-completion which doesn't include # _init_completion. This is a very minimal version of that function. __my_init_completion() { COMPREPLY=() _get_comp_words_by_ref "$@" cur prev words cword } __index_of_word() { local w word=$1 shift index=0 for w in "$@"; do [[ $w = "$word" ]] && return index=$((index+1)) done index=-1 } __contains_word() { local w word=$1; shift for w in "$@"; do [[ $w = "$word" ]] && return done return 1 } __handle_reply() { __debug "${FUNCNAME[0]}" case $cur in -*) if [[ $(type -t compopt) = "builtin" ]]; then compopt -o nospace fi local allflags if [ ${#must_have_one_flag[@]} -ne 0 ]; then allflags=("${must_have_one_flag[@]}") else allflags=("${flags[*]} ${two_word_flags[*]}") fi COMPREPLY=( $(compgen -W "${allflags[*]}" -- "$cur") ) if [[ $(type -t compopt) = "builtin" ]]; then [[ "${COMPREPLY[0]}" == *= ]] || compopt +o nospace fi # complete after --flag=abc if [[ $cur == *=* ]]; then if [[ $(type -t compopt) = "builtin" ]]; then compopt +o nospace fi local index flag flag="${cur%%=*}" __index_of_word "${flag}" "${flags_with_completion[@]}" COMPREPLY=() if [[ ${index} -ge 0 ]]; then PREFIX="" cur="${cur#*=}" ${flags_completion[${index}]} if [ -n "${ZSH_VERSION}" ]; then # zsh completion needs --flag= prefix eval "COMPREPLY=( \"\${COMPREPLY[@]/#/${flag}=}\" )" fi fi fi return 0; ;; esac # check if we are handling a flag with special work handling local index __index_of_word "${prev}" "${flags_with_completion[@]}" if [[ ${index} -ge 0 ]]; then ${flags_completion[${index}]} return fi # we are parsing a flag and don't have a special handler, no completion if [[ ${cur} != "${words[cword]}" ]]; then return fi local completions completions=("${commands[@]}") if [[ ${#must_have_one_noun[@]} -ne 0 ]]; then completions=("${must_have_one_noun[@]}") fi if [[ ${#must_have_one_flag[@]} -ne 0 ]]; then completions+=("${must_have_one_flag[@]}") fi COMPREPLY=( $(compgen -W "${completions[*]}" -- "$cur") ) if [[ ${#COMPREPLY[@]} -eq 0 && ${#noun_aliases[@]} -gt 0 && ${#must_have_one_noun[@]} -ne 0 ]]; then COMPREPLY=( $(compgen -W "${noun_aliases[*]}" -- "$cur") ) fi if [[ ${#COMPREPLY[@]} -eq 0 ]]; then declare -F __custom_func >/dev/null && __custom_func fi # available in bash-completion >= 2, not always present on macOS if declare -F __ltrim_colon_completions >/dev/null; then __ltrim_colon_completions "$cur" fi } # The arguments should be in the form "ext1|ext2|extn" __handle_filename_extension_flag() { local ext="$1" _filedir "@(${ext})" } __handle_subdirs_in_dir_flag() { local dir="$1" pushd "${dir}" >/dev/null 2>&1 && _filedir -d && popd >/dev/null 2>&1 } __handle_flag() { __debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" # if a command required a flag, and we found it, unset must_have_one_flag() local flagname=${words[c]} local flagvalue # if the word contained an = if [[ ${words[c]} == *"="* ]]; then flagvalue=${flagname#*=} # take in as flagvalue after the = flagname=${flagname%%=*} # strip everything after the = flagname="${flagname}=" # but put the = back fi __debug "${FUNCNAME[0]}: looking for ${flagname}" if __contains_word "${flagname}" "${must_have_one_flag[@]}"; then must_have_one_flag=() fi # if you set a flag which only applies to this command, don't show subcommands if __contains_word "${flagname}" "${local_nonpersistent_flags[@]}"; then commands=() fi # keep flag value with flagname as flaghash if [ -n "${flagvalue}" ] ; then flaghash[${flagname}]=${flagvalue} elif [ -n "${words[ $((c+1)) ]}" ] ; then flaghash[${flagname}]=${words[ $((c+1)) ]} else flaghash[${flagname}]="true" # pad "true" for bool flag fi # skip the argument to a two word flag if __contains_word "${words[c]}" "${two_word_flags[@]}"; then c=$((c+1)) # if we are looking for a flags value, don't show commands if [[ $c -eq $cword ]]; then commands=() fi fi c=$((c+1)) } __handle_noun() { __debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" if __contains_word "${words[c]}" "${must_have_one_noun[@]}"; then must_have_one_noun=() elif __contains_word "${words[c]}" "${noun_aliases[@]}"; then must_have_one_noun=() fi nouns+=("${words[c]}") c=$((c+1)) } __handle_command() { __debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" local next_command if [[ -n ${last_command} ]]; then next_command="_${last_command}_${words[c]//:/__}" else if [[ $c -eq 0 ]]; then next_command="_$(basename "${words[c]//:/__}")" else next_command="_${words[c]//:/__}" fi fi c=$((c+1)) __debug "${FUNCNAME[0]}: looking for ${next_command}" declare -F "$next_command" >/dev/null && $next_command } __handle_word() { if [[ $c -ge $cword ]]; then __handle_reply return fi __debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" if [[ "${words[c]}" == -* ]]; then __handle_flag elif __contains_word "${words[c]}" "${commands[@]}"; then __handle_command elif [[ $c -eq 0 ]] && __contains_word "$(basename "${words[c]}")" "${commands[@]}"; then __handle_command else __handle_noun fi __handle_word } `) } func writePostscript(buf *bytes.Buffer, name string) { name = strings.Replace(name, ":", "__", -1) buf.WriteString(fmt.Sprintf("__start_%s()\n", name)) buf.WriteString(fmt.Sprintf(`{ local cur prev words cword declare -A flaghash 2>/dev/null || : if declare -F _init_completion >/dev/null 2>&1; then _init_completion -s || return else __my_init_completion -n "=" || return fi local c=0 local flags=() local two_word_flags=() local local_nonpersistent_flags=() local flags_with_completion=() local flags_completion=() local commands=("%s") local must_have_one_flag=() local must_have_one_noun=() local last_command local nouns=() __handle_word } `, name)) buf.WriteString(fmt.Sprintf(`if [[ $(type -t compopt) = "builtin" ]]; then complete -o default -F __start_%s %s else complete -o default -o nospace -F __start_%s %s fi `, name, name, name, name)) buf.WriteString("# ex: ts=4 sw=4 et filetype=sh\n") } func writeCommands(buf *bytes.Buffer, cmd *Command) { buf.WriteString(" commands=()\n") for _, c := range cmd.Commands() { if !c.IsAvailableCommand() || c == cmd.helpCommand { continue } buf.WriteString(fmt.Sprintf(" commands+=(%q)\n", c.Name())) } buf.WriteString("\n") } func writeFlagHandler(buf *bytes.Buffer, name string, annotations map[string][]string) { for key, value := range annotations { switch key { case BashCompFilenameExt: buf.WriteString(fmt.Sprintf(" flags_with_completion+=(%q)\n", name)) var ext string if len(value) > 0 { ext = "__handle_filename_extension_flag " + strings.Join(value, "|") } else { ext = "_filedir" } buf.WriteString(fmt.Sprintf(" flags_completion+=(%q)\n", ext)) case BashCompCustom: buf.WriteString(fmt.Sprintf(" flags_with_completion+=(%q)\n", name)) if len(value) > 0 { handlers := strings.Join(value, "; ") buf.WriteString(fmt.Sprintf(" flags_completion+=(%q)\n", handlers)) } else { buf.WriteString(" flags_completion+=(:)\n") } case BashCompSubdirsInDir: buf.WriteString(fmt.Sprintf(" flags_with_completion+=(%q)\n", name)) var ext string if len(value) == 1 { ext = "__handle_subdirs_in_dir_flag " + value[0] } else { ext = "_filedir -d" } buf.WriteString(fmt.Sprintf(" flags_completion+=(%q)\n", ext)) } } } func writeShortFlag(buf *bytes.Buffer, flag *pflag.Flag) { name := flag.Shorthand format := " " if len(flag.NoOptDefVal) == 0 { format += "two_word_" } format += "flags+=(\"-%s\")\n" buf.WriteString(fmt.Sprintf(format, name)) writeFlagHandler(buf, "-"+name, flag.Annotations) } func writeFlag(buf *bytes.Buffer, flag *pflag.Flag) { name := flag.Name format := " flags+=(\"--%s" if len(flag.NoOptDefVal) == 0 { format += "=" } format += "\")\n" buf.WriteString(fmt.Sprintf(format, name)) writeFlagHandler(buf, "--"+name, flag.Annotations) } func writeLocalNonPersistentFlag(buf *bytes.Buffer, flag *pflag.Flag) { name := flag.Name format := " local_nonpersistent_flags+=(\"--%s" if len(flag.NoOptDefVal) == 0 { format += "=" } format += "\")\n" buf.WriteString(fmt.Sprintf(format, name)) } func writeFlags(buf *bytes.Buffer, cmd *Command) { buf.WriteString(` flags=() two_word_flags=() local_nonpersistent_flags=() flags_with_completion=() flags_completion=() `) localNonPersistentFlags := cmd.LocalNonPersistentFlags() cmd.NonInheritedFlags().VisitAll(func(flag *pflag.Flag) { if nonCompletableFlag(flag) { return } writeFlag(buf, flag) if len(flag.Shorthand) > 0 { writeShortFlag(buf, flag) } if localNonPersistentFlags.Lookup(flag.Name) != nil { writeLocalNonPersistentFlag(buf, flag) } }) cmd.InheritedFlags().VisitAll(func(flag *pflag.Flag) { if nonCompletableFlag(flag) { return } writeFlag(buf, flag) if len(flag.Shorthand) > 0 { writeShortFlag(buf, flag) } }) buf.WriteString("\n") } func writeRequiredFlag(buf *bytes.Buffer, cmd *Command) { buf.WriteString(" must_have_one_flag=()\n") flags := cmd.NonInheritedFlags() flags.VisitAll(func(flag *pflag.Flag) { if nonCompletableFlag(flag) { return } for key := range flag.Annotations { switch key { case BashCompOneRequiredFlag: format := " must_have_one_flag+=(\"--%s" if flag.Value.Type() != "bool" { format += "=" } format += "\")\n" buf.WriteString(fmt.Sprintf(format, flag.Name)) if len(flag.Shorthand) > 0 { buf.WriteString(fmt.Sprintf(" must_have_one_flag+=(\"-%s\")\n", flag.Shorthand)) } } } }) } func writeRequiredNouns(buf *bytes.Buffer, cmd *Command) { buf.WriteString(" must_have_one_noun=()\n") sort.Sort(sort.StringSlice(cmd.ValidArgs)) for _, value := range cmd.ValidArgs { buf.WriteString(fmt.Sprintf(" must_have_one_noun+=(%q)\n", value)) } } func writeArgAliases(buf *bytes.Buffer, cmd *Command) { buf.WriteString(" noun_aliases=()\n") sort.Sort(sort.StringSlice(cmd.ArgAliases)) for _, value := range cmd.ArgAliases { buf.WriteString(fmt.Sprintf(" noun_aliases+=(%q)\n", value)) } } func gen(buf *bytes.Buffer, cmd *Command) { for _, c := range cmd.Commands() { if !c.IsAvailableCommand() || c == cmd.helpCommand { continue } gen(buf, c) } commandName := cmd.CommandPath() commandName = strings.Replace(commandName, " ", "_", -1) commandName = strings.Replace(commandName, ":", "__", -1) buf.WriteString(fmt.Sprintf("_%s()\n{\n", commandName)) buf.WriteString(fmt.Sprintf(" last_command=%q\n", commandName)) writeCommands(buf, cmd) writeFlags(buf, cmd) writeRequiredFlag(buf, cmd) writeRequiredNouns(buf, cmd) writeArgAliases(buf, cmd) buf.WriteString("}\n\n") } // GenBashCompletion generates bash completion file and writes to the passed writer. func (c *Command) GenBashCompletion(w io.Writer) error { buf := new(bytes.Buffer) writePreamble(buf, c.Name()) if len(c.BashCompletionFunction) > 0 { buf.WriteString(c.BashCompletionFunction + "\n") } gen(buf, c) writePostscript(buf, c.Name()) _, err := buf.WriteTo(w) return err } func nonCompletableFlag(flag *pflag.Flag) bool { return flag.Hidden || len(flag.Deprecated) > 0 } // GenBashCompletionFile generates bash completion file. func (c *Command) GenBashCompletionFile(filename string) error { outFile, err := os.Create(filename) if err != nil { return err } defer outFile.Close() return c.GenBashCompletion(outFile) } // MarkFlagRequired adds the BashCompOneRequiredFlag annotation to the named flag, if it exists. func (c *Command) MarkFlagRequired(name string) error { return MarkFlagRequired(c.Flags(), name) } // MarkPersistentFlagRequired adds the BashCompOneRequiredFlag annotation to the named persistent flag, if it exists. func (c *Command) MarkPersistentFlagRequired(name string) error { return MarkFlagRequired(c.PersistentFlags(), name) } // MarkFlagRequired adds the BashCompOneRequiredFlag annotation to the named flag in the flag set, if it exists. func MarkFlagRequired(flags *pflag.FlagSet, name string) error { return flags.SetAnnotation(name, BashCompOneRequiredFlag, []string{"true"}) } // MarkFlagFilename adds the BashCompFilenameExt annotation to the named flag, if it exists. // Generated bash autocompletion will select filenames for the flag, limiting to named extensions if provided. func (c *Command) MarkFlagFilename(name string, extensions ...string) error { return MarkFlagFilename(c.Flags(), name, extensions...) } // MarkFlagCustom adds the BashCompCustom annotation to the named flag, if it exists. // Generated bash autocompletion will call the bash function f for the flag. func (c *Command) MarkFlagCustom(name string, f string) error { return MarkFlagCustom(c.Flags(), name, f) } // MarkPersistentFlagFilename adds the BashCompFilenameExt annotation to the named persistent flag, if it exists. // Generated bash autocompletion will select filenames for the flag, limiting to named extensions if provided. func (c *Command) MarkPersistentFlagFilename(name string, extensions ...string) error { return MarkFlagFilename(c.PersistentFlags(), name, extensions...) } // MarkFlagFilename adds the BashCompFilenameExt annotation to the named flag in the flag set, if it exists. // Generated bash autocompletion will select filenames for the flag, limiting to named extensions if provided. func MarkFlagFilename(flags *pflag.FlagSet, name string, extensions ...string) error { return flags.SetAnnotation(name, BashCompFilenameExt, extensions) } // MarkFlagCustom adds the BashCompCustom annotation to the named flag in the flag set, if it exists. // Generated bash autocompletion will call the bash function f for the flag. func MarkFlagCustom(flags *pflag.FlagSet, name string, f string) error { return flags.SetAnnotation(name, BashCompCustom, []string{f}) } ================================================ FILE: vendor/github.com/spf13/cobra/bash_completions.md ================================================ # Generating Bash Completions For Your Own cobra.Command Generating bash completions from a cobra command is incredibly easy. An actual program which does so for the kubernetes kubectl binary is as follows: ```go package main import ( "io/ioutil" "os" "github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl/cmd" ) func main() { kubectl := cmd.NewFactory(nil).NewKubectlCommand(os.Stdin, ioutil.Discard, ioutil.Discard) kubectl.GenBashCompletionFile("out.sh") } ``` `out.sh` will get you completions of subcommands and flags. Copy it to `/etc/bash_completion.d/` as described [here](https://debian-administration.org/article/316/An_introduction_to_bash_completion_part_1) and reset your terminal to use autocompletion. If you make additional annotations to your code, you can get even more intelligent and flexible behavior. ## Creating your own custom functions Some more actual code that works in kubernetes: ```bash const ( bash_completion_func = `__kubectl_parse_get() { local kubectl_output out if kubectl_output=$(kubectl get --no-headers "$1" 2>/dev/null); then out=($(echo "${kubectl_output}" | awk '{print $1}')) COMPREPLY=( $( compgen -W "${out[*]}" -- "$cur" ) ) fi } __kubectl_get_resource() { if [[ ${#nouns[@]} -eq 0 ]]; then return 1 fi __kubectl_parse_get ${nouns[${#nouns[@]} -1]} if [[ $? -eq 0 ]]; then return 0 fi } __custom_func() { case ${last_command} in kubectl_get | kubectl_describe | kubectl_delete | kubectl_stop) __kubectl_get_resource return ;; *) ;; esac } `) ``` And then I set that in my command definition: ```go cmds := &cobra.Command{ Use: "kubectl", Short: "kubectl controls the Kubernetes cluster manager", Long: `kubectl controls the Kubernetes cluster manager. Find more information at https://github.com/GoogleCloudPlatform/kubernetes.`, Run: runHelp, BashCompletionFunction: bash_completion_func, } ``` The `BashCompletionFunction` option is really only valid/useful on the root command. Doing the above will cause `__custom_func()` to be called when the built in processor was unable to find a solution. In the case of kubernetes a valid command might look something like `kubectl get pod [mypod]`. If you type `kubectl get pod [tab][tab]` the `__customc_func()` will run because the cobra.Command only understood "kubectl" and "get." `__custom_func()` will see that the cobra.Command is "kubectl_get" and will thus call another helper `__kubectl_get_resource()`. `__kubectl_get_resource` will look at the 'nouns' collected. In our example the only noun will be `pod`. So it will call `__kubectl_parse_get pod`. `__kubectl_parse_get` will actually call out to kubernetes and get any pods. It will then set `COMPREPLY` to valid pods! ## Have the completions code complete your 'nouns' In the above example "pod" was assumed to already be typed. But if you want `kubectl get [tab][tab]` to show a list of valid "nouns" you have to set them. Simplified code from `kubectl get` looks like: ```go validArgs []string = { "pod", "node", "service", "replicationcontroller" } cmd := &cobra.Command{ Use: "get [(-o|--output=)json|yaml|template|...] (RESOURCE [NAME] | RESOURCE/NAME ...)", Short: "Display one or many resources", Long: get_long, Example: get_example, Run: func(cmd *cobra.Command, args []string) { err := RunGet(f, out, cmd, args) util.CheckErr(err) }, ValidArgs: validArgs, } ``` Notice we put the "ValidArgs" on the "get" subcommand. Doing so will give results like ```bash # kubectl get [tab][tab] node pod replicationcontroller service ``` ## Plural form and shortcuts for nouns If your nouns have a number of aliases, you can define them alongside `ValidArgs` using `ArgAliases`: ```go argAliases []string = { "pods", "nodes", "services", "svc", "replicationcontrollers", "rc" } cmd := &cobra.Command{ ... ValidArgs: validArgs, ArgAliases: argAliases } ``` The aliases are not shown to the user on tab completion, but they are accepted as valid nouns by the completion algorithm if entered manually, e.g. in: ```bash # kubectl get rc [tab][tab] backend frontend database ``` Note that without declaring `rc` as an alias, the completion algorithm would show the list of nouns in this example again instead of the replication controllers. ## Mark flags as required Most of the time completions will only show subcommands. But if a flag is required to make a subcommand work, you probably want it to show up when the user types [tab][tab]. Marking a flag as 'Required' is incredibly easy. ```go cmd.MarkFlagRequired("pod") cmd.MarkFlagRequired("container") ``` and you'll get something like ```bash # kubectl exec [tab][tab][tab] -c --container= -p --pod= ``` # Specify valid filename extensions for flags that take a filename In this example we use --filename= and expect to get a json or yaml file as the argument. To make this easier we annotate the --filename flag with valid filename extensions. ```go annotations := []string{"json", "yaml", "yml"} annotation := make(map[string][]string) annotation[cobra.BashCompFilenameExt] = annotations flag := &pflag.Flag{ Name: "filename", Shorthand: "f", Usage: usage, Value: value, DefValue: value.String(), Annotations: annotation, } cmd.Flags().AddFlag(flag) ``` Now when you run a command with this filename flag you'll get something like ```bash # kubectl create -f test/ example/ rpmbuild/ hello.yml test.json ``` So while there are many other files in the CWD it only shows me subdirs and those with valid extensions. # Specifiy custom flag completion Similar to the filename completion and filtering using cobra.BashCompFilenameExt, you can specifiy a custom flag completion function with cobra.BashCompCustom: ```go annotation := make(map[string][]string) annotation[cobra.BashCompFilenameExt] = []string{"__kubectl_get_namespaces"} flag := &pflag.Flag{ Name: "namespace", Usage: usage, Annotations: annotation, } cmd.Flags().AddFlag(flag) ``` In addition add the `__handle_namespace_flag` implementation in the `BashCompletionFunction` value, e.g.: ```bash __kubectl_get_namespaces() { local template template="{{ range .items }}{{ .metadata.name }} {{ end }}" local kubectl_out if kubectl_out=$(kubectl get -o template --template="${template}" namespace 2>/dev/null); then COMPREPLY=( $( compgen -W "${kubectl_out}[*]" -- "$cur" ) ) fi } ``` ================================================ FILE: vendor/github.com/spf13/cobra/bash_completions_test.go ================================================ package cobra import ( "bytes" "os" "os/exec" "strings" "testing" ) func checkOmit(t *testing.T, found, unexpected string) { if strings.Contains(found, unexpected) { t.Errorf("Got: %q\nBut should not have!\n", unexpected) } } func check(t *testing.T, found, expected string) { if !strings.Contains(found, expected) { t.Errorf("Expecting to contain: \n %q\nGot:\n %q\n", expected, found) } } func runShellCheck(s string) error { excluded := []string{ "SC2034", // PREFIX appears unused. Verify it or export it. } cmd := exec.Command("shellcheck", "-s", "bash", "-", "-e", strings.Join(excluded, ",")) cmd.Stderr = os.Stderr cmd.Stdout = os.Stdout stdin, err := cmd.StdinPipe() if err != nil { return err } go func() { stdin.Write([]byte(s)) stdin.Close() }() return cmd.Run() } // World worst custom function, just keep telling you to enter hello! const bashCompletionFunc = `__custom_func() { COMPREPLY=( "hello" ) } ` func TestBashCompletions(t *testing.T) { rootCmd := &Command{ Use: "root", ArgAliases: []string{"pods", "nodes", "services", "replicationcontrollers", "po", "no", "svc", "rc"}, ValidArgs: []string{"pod", "node", "service", "replicationcontroller"}, BashCompletionFunction: bashCompletionFunc, Run: emptyRun, } rootCmd.Flags().IntP("introot", "i", -1, "help message for flag introot") rootCmd.MarkFlagRequired("introot") // Filename. rootCmd.Flags().String("filename", "", "Enter a filename") rootCmd.MarkFlagFilename("filename", "json", "yaml", "yml") // Persistent filename. rootCmd.PersistentFlags().String("persistent-filename", "", "Enter a filename") rootCmd.MarkPersistentFlagFilename("persistent-filename") rootCmd.MarkPersistentFlagRequired("persistent-filename") // Filename extensions. rootCmd.Flags().String("filename-ext", "", "Enter a filename (extension limited)") rootCmd.MarkFlagFilename("filename-ext") rootCmd.Flags().String("custom", "", "Enter a filename (extension limited)") rootCmd.MarkFlagCustom("custom", "__complete_custom") // Subdirectories in a given directory. rootCmd.Flags().String("theme", "", "theme to use (located in /themes/THEMENAME/)") rootCmd.Flags().SetAnnotation("theme", BashCompSubdirsInDir, []string{"themes"}) echoCmd := &Command{ Use: "echo [string to echo]", Aliases: []string{"say"}, Short: "Echo anything to the screen", Long: "an utterly useless command for testing.", Example: "Just run cobra-test echo", Run: emptyRun, } printCmd := &Command{ Use: "print [string to print]", Args: MinimumNArgs(1), Short: "Print anything to the screen", Long: "an absolutely utterly useless command for testing.", Run: emptyRun, } deprecatedCmd := &Command{ Use: "deprecated [can't do anything here]", Args: NoArgs, Short: "A command which is deprecated", Long: "an absolutely utterly useless command for testing deprecation!.", Deprecated: "Please use echo instead", Run: emptyRun, } colonCmd := &Command{ Use: "cmd:colon", Run: emptyRun, } timesCmd := &Command{ Use: "times [# times] [string to echo]", SuggestFor: []string{"counts"}, Args: OnlyValidArgs, ValidArgs: []string{"one", "two", "three", "four"}, Short: "Echo anything to the screen more times", Long: "a slightly useless command for testing.", Run: emptyRun, } echoCmd.AddCommand(timesCmd) rootCmd.AddCommand(echoCmd, printCmd, deprecatedCmd, colonCmd) buf := new(bytes.Buffer) rootCmd.GenBashCompletion(buf) output := buf.String() check(t, output, "_root") check(t, output, "_root_echo") check(t, output, "_root_echo_times") check(t, output, "_root_print") check(t, output, "_root_cmd__colon") // check for required flags check(t, output, `must_have_one_flag+=("--introot=")`) check(t, output, `must_have_one_flag+=("--persistent-filename=")`) // check for custom completion function check(t, output, `COMPREPLY=( "hello" )`) // check for required nouns check(t, output, `must_have_one_noun+=("pod")`) // check for noun aliases check(t, output, `noun_aliases+=("pods")`) check(t, output, `noun_aliases+=("rc")`) checkOmit(t, output, `must_have_one_noun+=("pods")`) // check for filename extension flags check(t, output, `flags_completion+=("_filedir")`) // check for filename extension flags check(t, output, `must_have_one_noun+=("three")`) // check for filename extension flags check(t, output, `flags_completion+=("__handle_filename_extension_flag json|yaml|yml")`) // check for custom flags check(t, output, `flags_completion+=("__complete_custom")`) // check for subdirs_in_dir flags check(t, output, `flags_completion+=("__handle_subdirs_in_dir_flag themes")`) checkOmit(t, output, deprecatedCmd.Name()) // If available, run shellcheck against the script. if err := exec.Command("which", "shellcheck").Run(); err != nil { return } if err := runShellCheck(output); err != nil { t.Fatalf("shellcheck failed: %v", err) } } func TestBashCompletionHiddenFlag(t *testing.T) { c := &Command{Use: "c", Run: emptyRun} const flagName = "hiddenFlag" c.Flags().Bool(flagName, false, "") c.Flags().MarkHidden(flagName) buf := new(bytes.Buffer) c.GenBashCompletion(buf) output := buf.String() if strings.Contains(output, flagName) { t.Errorf("Expected completion to not include %q flag: Got %v", flagName, output) } } func TestBashCompletionDeprecatedFlag(t *testing.T) { c := &Command{Use: "c", Run: emptyRun} const flagName = "deprecated-flag" c.Flags().Bool(flagName, false, "") c.Flags().MarkDeprecated(flagName, "use --not-deprecated instead") buf := new(bytes.Buffer) c.GenBashCompletion(buf) output := buf.String() if strings.Contains(output, flagName) { t.Errorf("expected completion to not include %q flag: Got %v", flagName, output) } } ================================================ FILE: vendor/github.com/spf13/cobra/cobra.go ================================================ // Copyright © 2013 Steve Francia . // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Commands similar to git, go tools and other modern CLI tools // inspired by go, go-Commander, gh and subcommand package cobra import ( "fmt" "io" "reflect" "strconv" "strings" "text/template" "unicode" ) var templateFuncs = template.FuncMap{ "trim": strings.TrimSpace, "trimRightSpace": trimRightSpace, "trimTrailingWhitespaces": trimRightSpace, "appendIfNotPresent": appendIfNotPresent, "rpad": rpad, "gt": Gt, "eq": Eq, } var initializers []func() // EnablePrefixMatching allows to set automatic prefix matching. Automatic prefix matching can be a dangerous thing // to automatically enable in CLI tools. // Set this to true to enable it. var EnablePrefixMatching = false // EnableCommandSorting controls sorting of the slice of commands, which is turned on by default. // To disable sorting, set it to false. var EnableCommandSorting = true // MousetrapHelpText enables an information splash screen on Windows // if the CLI is started from explorer.exe. // To disable the mousetrap, just set this variable to blank string (""). // Works only on Microsoft Windows. var MousetrapHelpText string = `This is a command line tool. You need to open cmd.exe and run it from there. ` // AddTemplateFunc adds a template function that's available to Usage and Help // template generation. func AddTemplateFunc(name string, tmplFunc interface{}) { templateFuncs[name] = tmplFunc } // AddTemplateFuncs adds multiple template functions that are available to Usage and // Help template generation. func AddTemplateFuncs(tmplFuncs template.FuncMap) { for k, v := range tmplFuncs { templateFuncs[k] = v } } // OnInitialize sets the passed functions to be run when each command's // Execute method is called. func OnInitialize(y ...func()) { initializers = append(initializers, y...) } // FIXME Gt is unused by cobra and should be removed in a version 2. It exists only for compatibility with users of cobra. // Gt takes two types and checks whether the first type is greater than the second. In case of types Arrays, Chans, // Maps and Slices, Gt will compare their lengths. Ints are compared directly while strings are first parsed as // ints and then compared. func Gt(a interface{}, b interface{}) bool { var left, right int64 av := reflect.ValueOf(a) switch av.Kind() { case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice: left = int64(av.Len()) case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: left = av.Int() case reflect.String: left, _ = strconv.ParseInt(av.String(), 10, 64) } bv := reflect.ValueOf(b) switch bv.Kind() { case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice: right = int64(bv.Len()) case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: right = bv.Int() case reflect.String: right, _ = strconv.ParseInt(bv.String(), 10, 64) } return left > right } // FIXME Eq is unused by cobra and should be removed in a version 2. It exists only for compatibility with users of cobra. // Eq takes two types and checks whether they are equal. Supported types are int and string. Unsupported types will panic. func Eq(a interface{}, b interface{}) bool { av := reflect.ValueOf(a) bv := reflect.ValueOf(b) switch av.Kind() { case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice: panic("Eq called on unsupported type") case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return av.Int() == bv.Int() case reflect.String: return av.String() == bv.String() } return false } func trimRightSpace(s string) string { return strings.TrimRightFunc(s, unicode.IsSpace) } // FIXME appendIfNotPresent is unused by cobra and should be removed in a version 2. It exists only for compatibility with users of cobra. // appendIfNotPresent will append stringToAppend to the end of s, but only if it's not yet present in s. func appendIfNotPresent(s, stringToAppend string) string { if strings.Contains(s, stringToAppend) { return s } return s + " " + stringToAppend } // rpad adds padding to the right of a string. func rpad(s string, padding int) string { template := fmt.Sprintf("%%-%ds", padding) return fmt.Sprintf(template, s) } // tmpl executes the given template text on data, writing the result to w. func tmpl(w io.Writer, text string, data interface{}) error { t := template.New("top") t.Funcs(templateFuncs) template.Must(t.Parse(text)) return t.Execute(w, data) } // ld compares two strings and returns the levenshtein distance between them. func ld(s, t string, ignoreCase bool) int { if ignoreCase { s = strings.ToLower(s) t = strings.ToLower(t) } d := make([][]int, len(s)+1) for i := range d { d[i] = make([]int, len(t)+1) } for i := range d { d[i][0] = i } for j := range d[0] { d[0][j] = j } for j := 1; j <= len(t); j++ { for i := 1; i <= len(s); i++ { if s[i-1] == t[j-1] { d[i][j] = d[i-1][j-1] } else { min := d[i-1][j] if d[i][j-1] < min { min = d[i][j-1] } if d[i-1][j-1] < min { min = d[i-1][j-1] } d[i][j] = min + 1 } } } return d[len(s)][len(t)] } func stringInSlice(a string, list []string) bool { for _, b := range list { if b == a { return true } } return false } ================================================ FILE: vendor/github.com/spf13/cobra/cobra_test.go ================================================ package cobra import ( "testing" "text/template" ) func TestAddTemplateFunctions(t *testing.T) { AddTemplateFunc("t", func() bool { return true }) AddTemplateFuncs(template.FuncMap{ "f": func() bool { return false }, "h": func() string { return "Hello," }, "w": func() string { return "world." }}) c := &Command{} c.SetUsageTemplate(`{{if t}}{{h}}{{end}}{{if f}}{{h}}{{end}} {{w}}`) const expected = "Hello, world." if got := c.UsageString(); got != expected { t.Errorf("Expected UsageString: %v\nGot: %v", expected, got) } } ================================================ FILE: vendor/github.com/spf13/cobra/command.go ================================================ // Copyright © 2013 Steve Francia . // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package cobra is a commander providing a simple interface to create powerful modern CLI interfaces. // In addition to providing an interface, Cobra simultaneously provides a controller to organize your application code. package cobra import ( "bytes" "fmt" "io" "os" "path/filepath" "sort" "strings" flag "github.com/spf13/pflag" ) // Command is just that, a command for your application. // E.g. 'go run ...' - 'run' is the command. Cobra requires // you to define the usage and description as part of your command // definition to ensure usability. type Command struct { // Use is the one-line usage message. Use string // Aliases is an array of aliases that can be used instead of the first word in Use. Aliases []string // SuggestFor is an array of command names for which this command will be suggested - // similar to aliases but only suggests. SuggestFor []string // Short is the short description shown in the 'help' output. Short string // Long is the long message shown in the 'help ' output. Long string // Example is examples of how to use the command. Example string // ValidArgs is list of all valid non-flag arguments that are accepted in bash completions ValidArgs []string // Expected arguments Args PositionalArgs // ArgAliases is List of aliases for ValidArgs. // These are not suggested to the user in the bash completion, // but accepted if entered manually. ArgAliases []string // BashCompletionFunction is custom functions used by the bash autocompletion generator. BashCompletionFunction string // Deprecated defines, if this command is deprecated and should print this string when used. Deprecated string // Hidden defines, if this command is hidden and should NOT show up in the list of available commands. Hidden bool // Annotations are key/value pairs that can be used by applications to identify or // group commands. Annotations map[string]string // Version defines the version for this command. If this value is non-empty and the command does not // define a "version" flag, a "version" boolean flag will be added to the command and, if specified, // will print content of the "Version" variable. Version string // The *Run functions are executed in the following order: // * PersistentPreRun() // * PreRun() // * Run() // * PostRun() // * PersistentPostRun() // All functions get the same args, the arguments after the command name. // // PersistentPreRun: children of this command will inherit and execute. PersistentPreRun func(cmd *Command, args []string) // PersistentPreRunE: PersistentPreRun but returns an error. PersistentPreRunE func(cmd *Command, args []string) error // PreRun: children of this command will not inherit. PreRun func(cmd *Command, args []string) // PreRunE: PreRun but returns an error. PreRunE func(cmd *Command, args []string) error // Run: Typically the actual work function. Most commands will only implement this. Run func(cmd *Command, args []string) // RunE: Run but returns an error. RunE func(cmd *Command, args []string) error // PostRun: run after the Run command. PostRun func(cmd *Command, args []string) // PostRunE: PostRun but returns an error. PostRunE func(cmd *Command, args []string) error // PersistentPostRun: children of this command will inherit and execute after PostRun. PersistentPostRun func(cmd *Command, args []string) // PersistentPostRunE: PersistentPostRun but returns an error. PersistentPostRunE func(cmd *Command, args []string) error // SilenceErrors is an option to quiet errors down stream. SilenceErrors bool // SilenceUsage is an option to silence usage when an error occurs. SilenceUsage bool // DisableFlagParsing disables the flag parsing. // If this is true all flags will be passed to the command as arguments. DisableFlagParsing bool // DisableAutoGenTag defines, if gen tag ("Auto generated by spf13/cobra...") // will be printed by generating docs for this command. DisableAutoGenTag bool // DisableFlagsInUseLine will disable the addition of [flags] to the usage // line of a command when printing help or generating docs DisableFlagsInUseLine bool // DisableSuggestions disables the suggestions based on Levenshtein distance // that go along with 'unknown command' messages. DisableSuggestions bool // SuggestionsMinimumDistance defines minimum levenshtein distance to display suggestions. // Must be > 0. SuggestionsMinimumDistance int // TraverseChildren parses flags on all parents before executing child command. TraverseChildren bool // commands is the list of commands supported by this program. commands []*Command // parent is a parent command for this command. parent *Command // Max lengths of commands' string lengths for use in padding. commandsMaxUseLen int commandsMaxCommandPathLen int commandsMaxNameLen int // commandsAreSorted defines, if command slice are sorted or not. commandsAreSorted bool // args is actual args parsed from flags. args []string // flagErrorBuf contains all error messages from pflag. flagErrorBuf *bytes.Buffer // flags is full set of flags. flags *flag.FlagSet // pflags contains persistent flags. pflags *flag.FlagSet // lflags contains local flags. lflags *flag.FlagSet // iflags contains inherited flags. iflags *flag.FlagSet // parentsPflags is all persistent flags of cmd's parents. parentsPflags *flag.FlagSet // globNormFunc is the global normalization function // that we can use on every pflag set and children commands globNormFunc func(f *flag.FlagSet, name string) flag.NormalizedName // output is an output writer defined by user. output io.Writer // usageFunc is usage func defined by user. usageFunc func(*Command) error // usageTemplate is usage template defined by user. usageTemplate string // flagErrorFunc is func defined by user and it's called when the parsing of // flags returns an error. flagErrorFunc func(*Command, error) error // helpTemplate is help template defined by user. helpTemplate string // helpFunc is help func defined by user. helpFunc func(*Command, []string) // helpCommand is command with usage 'help'. If it's not defined by user, // cobra uses default help command. helpCommand *Command // versionTemplate is the version template defined by user. versionTemplate string } // SetArgs sets arguments for the command. It is set to os.Args[1:] by default, if desired, can be overridden // particularly useful when testing. func (c *Command) SetArgs(a []string) { c.args = a } // SetOutput sets the destination for usage and error messages. // If output is nil, os.Stderr is used. func (c *Command) SetOutput(output io.Writer) { c.output = output } // SetUsageFunc sets usage function. Usage can be defined by application. func (c *Command) SetUsageFunc(f func(*Command) error) { c.usageFunc = f } // SetUsageTemplate sets usage template. Can be defined by Application. func (c *Command) SetUsageTemplate(s string) { c.usageTemplate = s } // SetFlagErrorFunc sets a function to generate an error when flag parsing // fails. func (c *Command) SetFlagErrorFunc(f func(*Command, error) error) { c.flagErrorFunc = f } // SetHelpFunc sets help function. Can be defined by Application. func (c *Command) SetHelpFunc(f func(*Command, []string)) { c.helpFunc = f } // SetHelpCommand sets help command. func (c *Command) SetHelpCommand(cmd *Command) { c.helpCommand = cmd } // SetHelpTemplate sets help template to be used. Application can use it to set custom template. func (c *Command) SetHelpTemplate(s string) { c.helpTemplate = s } // SetVersionTemplate sets version template to be used. Application can use it to set custom template. func (c *Command) SetVersionTemplate(s string) { c.versionTemplate = s } // SetGlobalNormalizationFunc sets a normalization function to all flag sets and also to child commands. // The user should not have a cyclic dependency on commands. func (c *Command) SetGlobalNormalizationFunc(n func(f *flag.FlagSet, name string) flag.NormalizedName) { c.Flags().SetNormalizeFunc(n) c.PersistentFlags().SetNormalizeFunc(n) c.globNormFunc = n for _, command := range c.commands { command.SetGlobalNormalizationFunc(n) } } // OutOrStdout returns output to stdout. func (c *Command) OutOrStdout() io.Writer { return c.getOut(os.Stdout) } // OutOrStderr returns output to stderr func (c *Command) OutOrStderr() io.Writer { return c.getOut(os.Stderr) } func (c *Command) getOut(def io.Writer) io.Writer { if c.output != nil { return c.output } if c.HasParent() { return c.parent.getOut(def) } return def } // UsageFunc returns either the function set by SetUsageFunc for this command // or a parent, or it returns a default usage function. func (c *Command) UsageFunc() (f func(*Command) error) { if c.usageFunc != nil { return c.usageFunc } if c.HasParent() { return c.Parent().UsageFunc() } return func(c *Command) error { c.mergePersistentFlags() err := tmpl(c.OutOrStderr(), c.UsageTemplate(), c) if err != nil { c.Println(err) } return err } } // Usage puts out the usage for the command. // Used when a user provides invalid input. // Can be defined by user by overriding UsageFunc. func (c *Command) Usage() error { return c.UsageFunc()(c) } // HelpFunc returns either the function set by SetHelpFunc for this command // or a parent, or it returns a function with default help behavior. func (c *Command) HelpFunc() func(*Command, []string) { if c.helpFunc != nil { return c.helpFunc } if c.HasParent() { return c.Parent().HelpFunc() } return func(c *Command, a []string) { c.mergePersistentFlags() err := tmpl(c.OutOrStdout(), c.HelpTemplate(), c) if err != nil { c.Println(err) } } } // Help puts out the help for the command. // Used when a user calls help [command]. // Can be defined by user by overriding HelpFunc. func (c *Command) Help() error { c.HelpFunc()(c, []string{}) return nil } // UsageString return usage string. func (c *Command) UsageString() string { tmpOutput := c.output bb := new(bytes.Buffer) c.SetOutput(bb) c.Usage() c.output = tmpOutput return bb.String() } // FlagErrorFunc returns either the function set by SetFlagErrorFunc for this // command or a parent, or it returns a function which returns the original // error. func (c *Command) FlagErrorFunc() (f func(*Command, error) error) { if c.flagErrorFunc != nil { return c.flagErrorFunc } if c.HasParent() { return c.parent.FlagErrorFunc() } return func(c *Command, err error) error { return err } } var minUsagePadding = 25 // UsagePadding return padding for the usage. func (c *Command) UsagePadding() int { if c.parent == nil || minUsagePadding > c.parent.commandsMaxUseLen { return minUsagePadding } return c.parent.commandsMaxUseLen } var minCommandPathPadding = 11 // CommandPathPadding return padding for the command path. func (c *Command) CommandPathPadding() int { if c.parent == nil || minCommandPathPadding > c.parent.commandsMaxCommandPathLen { return minCommandPathPadding } return c.parent.commandsMaxCommandPathLen } var minNamePadding = 11 // NamePadding returns padding for the name. func (c *Command) NamePadding() int { if c.parent == nil || minNamePadding > c.parent.commandsMaxNameLen { return minNamePadding } return c.parent.commandsMaxNameLen } // UsageTemplate returns usage template for the command. func (c *Command) UsageTemplate() string { if c.usageTemplate != "" { return c.usageTemplate } if c.HasParent() { return c.parent.UsageTemplate() } return `Usage:{{if .Runnable}} {{.UseLine}}{{end}}{{if .HasAvailableSubCommands}} {{.CommandPath}} [command]{{end}}{{if gt (len .Aliases) 0}} Aliases: {{.NameAndAliases}}{{end}}{{if .HasExample}} Examples: {{.Example}}{{end}}{{if .HasAvailableSubCommands}} Available Commands:{{range .Commands}}{{if (or .IsAvailableCommand (eq .Name "help"))}} {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableLocalFlags}} Flags: {{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}} Global Flags: {{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasHelpSubCommands}} Additional help topics:{{range .Commands}}{{if .IsAdditionalHelpTopicCommand}} {{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableSubCommands}} Use "{{.CommandPath}} [command] --help" for more information about a command.{{end}} ` } // HelpTemplate return help template for the command. func (c *Command) HelpTemplate() string { if c.helpTemplate != "" { return c.helpTemplate } if c.HasParent() { return c.parent.HelpTemplate() } return `{{with (or .Long .Short)}}{{. | trimTrailingWhitespaces}} {{end}}{{if or .Runnable .HasSubCommands}}{{.UsageString}}{{end}}` } // VersionTemplate return version template for the command. func (c *Command) VersionTemplate() string { if c.versionTemplate != "" { return c.versionTemplate } if c.HasParent() { return c.parent.VersionTemplate() } return `{{with .Name}}{{printf "%s " .}}{{end}}{{printf "version %s" .Version}} ` } func hasNoOptDefVal(name string, fs *flag.FlagSet) bool { flag := fs.Lookup(name) if flag == nil { return false } return flag.NoOptDefVal != "" } func shortHasNoOptDefVal(name string, fs *flag.FlagSet) bool { if len(name) == 0 { return false } flag := fs.ShorthandLookup(name[:1]) if flag == nil { return false } return flag.NoOptDefVal != "" } func stripFlags(args []string, c *Command) []string { if len(args) == 0 { return args } c.mergePersistentFlags() commands := []string{} flags := c.Flags() Loop: for len(args) > 0 { s := args[0] args = args[1:] switch { case strings.HasPrefix(s, "--") && !strings.Contains(s, "=") && !hasNoOptDefVal(s[2:], flags): // If '--flag arg' then // delete arg from args. fallthrough // (do the same as below) case strings.HasPrefix(s, "-") && !strings.Contains(s, "=") && len(s) == 2 && !shortHasNoOptDefVal(s[1:], flags): // If '-f arg' then // delete 'arg' from args or break the loop if len(args) <= 1. if len(args) <= 1 { break Loop } else { args = args[1:] continue } case s != "" && !strings.HasPrefix(s, "-"): commands = append(commands, s) } } return commands } // argsMinusFirstX removes only the first x from args. Otherwise, commands that look like // openshift admin policy add-role-to-user admin my-user, lose the admin argument (arg[4]). func argsMinusFirstX(args []string, x string) []string { for i, y := range args { if x == y { ret := []string{} ret = append(ret, args[:i]...) ret = append(ret, args[i+1:]...) return ret } } return args } func isFlagArg(arg string) bool { return ((len(arg) >= 3 && arg[1] == '-') || (len(arg) >= 2 && arg[0] == '-' && arg[1] != '-')) } // Find the target command given the args and command tree // Meant to be run on the highest node. Only searches down. func (c *Command) Find(args []string) (*Command, []string, error) { var innerfind func(*Command, []string) (*Command, []string) innerfind = func(c *Command, innerArgs []string) (*Command, []string) { argsWOflags := stripFlags(innerArgs, c) if len(argsWOflags) == 0 { return c, innerArgs } nextSubCmd := argsWOflags[0] cmd := c.findNext(nextSubCmd) if cmd != nil { return innerfind(cmd, argsMinusFirstX(innerArgs, nextSubCmd)) } return c, innerArgs } commandFound, a := innerfind(c, args) if commandFound.Args == nil { return commandFound, a, legacyArgs(commandFound, stripFlags(a, commandFound)) } return commandFound, a, nil } func (c *Command) findSuggestions(arg string) string { if c.DisableSuggestions { return "" } if c.SuggestionsMinimumDistance <= 0 { c.SuggestionsMinimumDistance = 2 } suggestionsString := "" if suggestions := c.SuggestionsFor(arg); len(suggestions) > 0 { suggestionsString += "\n\nDid you mean this?\n" for _, s := range suggestions { suggestionsString += fmt.Sprintf("\t%v\n", s) } } return suggestionsString } func (c *Command) findNext(next string) *Command { matches := make([]*Command, 0) for _, cmd := range c.commands { if cmd.Name() == next || cmd.HasAlias(next) { return cmd } if EnablePrefixMatching && cmd.hasNameOrAliasPrefix(next) { matches = append(matches, cmd) } } if len(matches) == 1 { return matches[0] } return nil } // Traverse the command tree to find the command, and parse args for // each parent. func (c *Command) Traverse(args []string) (*Command, []string, error) { flags := []string{} inFlag := false for i, arg := range args { switch { // A long flag with a space separated value case strings.HasPrefix(arg, "--") && !strings.Contains(arg, "="): // TODO: this isn't quite right, we should really check ahead for 'true' or 'false' inFlag = !hasNoOptDefVal(arg[2:], c.Flags()) flags = append(flags, arg) continue // A short flag with a space separated value case strings.HasPrefix(arg, "-") && !strings.Contains(arg, "=") && len(arg) == 2 && !shortHasNoOptDefVal(arg[1:], c.Flags()): inFlag = true flags = append(flags, arg) continue // The value for a flag case inFlag: inFlag = false flags = append(flags, arg) continue // A flag without a value, or with an `=` separated value case isFlagArg(arg): flags = append(flags, arg) continue } cmd := c.findNext(arg) if cmd == nil { return c, args, nil } if err := c.ParseFlags(flags); err != nil { return nil, args, err } return cmd.Traverse(args[i+1:]) } return c, args, nil } // SuggestionsFor provides suggestions for the typedName. func (c *Command) SuggestionsFor(typedName string) []string { suggestions := []string{} for _, cmd := range c.commands { if cmd.IsAvailableCommand() { levenshteinDistance := ld(typedName, cmd.Name(), true) suggestByLevenshtein := levenshteinDistance <= c.SuggestionsMinimumDistance suggestByPrefix := strings.HasPrefix(strings.ToLower(cmd.Name()), strings.ToLower(typedName)) if suggestByLevenshtein || suggestByPrefix { suggestions = append(suggestions, cmd.Name()) } for _, explicitSuggestion := range cmd.SuggestFor { if strings.EqualFold(typedName, explicitSuggestion) { suggestions = append(suggestions, cmd.Name()) } } } } return suggestions } // VisitParents visits all parents of the command and invokes fn on each parent. func (c *Command) VisitParents(fn func(*Command)) { if c.HasParent() { fn(c.Parent()) c.Parent().VisitParents(fn) } } // Root finds root command. func (c *Command) Root() *Command { if c.HasParent() { return c.Parent().Root() } return c } // ArgsLenAtDash will return the length of c.Flags().Args at the moment // when a -- was found during args parsing. func (c *Command) ArgsLenAtDash() int { return c.Flags().ArgsLenAtDash() } func (c *Command) execute(a []string) (err error) { if c == nil { return fmt.Errorf("Called Execute() on a nil Command") } if len(c.Deprecated) > 0 { c.Printf("Command %q is deprecated, %s\n", c.Name(), c.Deprecated) } // initialize help and version flag at the last point possible to allow for user // overriding c.InitDefaultHelpFlag() c.InitDefaultVersionFlag() err = c.ParseFlags(a) if err != nil { return c.FlagErrorFunc()(c, err) } // If help is called, regardless of other flags, return we want help. // Also say we need help if the command isn't runnable. helpVal, err := c.Flags().GetBool("help") if err != nil { // should be impossible to get here as we always declare a help // flag in InitDefaultHelpFlag() c.Println("\"help\" flag declared as non-bool. Please correct your code") return err } if helpVal { return flag.ErrHelp } // for back-compat, only add version flag behavior if version is defined if c.Version != "" { versionVal, err := c.Flags().GetBool("version") if err != nil { c.Println("\"version\" flag declared as non-bool. Please correct your code") return err } if versionVal { err := tmpl(c.OutOrStdout(), c.VersionTemplate(), c) if err != nil { c.Println(err) } return err } } if !c.Runnable() { return flag.ErrHelp } c.preRun() argWoFlags := c.Flags().Args() if c.DisableFlagParsing { argWoFlags = a } if err := c.ValidateArgs(argWoFlags); err != nil { return err } for p := c; p != nil; p = p.Parent() { if p.PersistentPreRunE != nil { if err := p.PersistentPreRunE(c, argWoFlags); err != nil { return err } break } else if p.PersistentPreRun != nil { p.PersistentPreRun(c, argWoFlags) break } } if c.PreRunE != nil { if err := c.PreRunE(c, argWoFlags); err != nil { return err } } else if c.PreRun != nil { c.PreRun(c, argWoFlags) } if err := c.validateRequiredFlags(); err != nil { return err } if c.RunE != nil { if err := c.RunE(c, argWoFlags); err != nil { return err } } else { c.Run(c, argWoFlags) } if c.PostRunE != nil { if err := c.PostRunE(c, argWoFlags); err != nil { return err } } else if c.PostRun != nil { c.PostRun(c, argWoFlags) } for p := c; p != nil; p = p.Parent() { if p.PersistentPostRunE != nil { if err := p.PersistentPostRunE(c, argWoFlags); err != nil { return err } break } else if p.PersistentPostRun != nil { p.PersistentPostRun(c, argWoFlags) break } } return nil } func (c *Command) preRun() { for _, x := range initializers { x() } } // Execute uses the args (os.Args[1:] by default) // and run through the command tree finding appropriate matches // for commands and then corresponding flags. func (c *Command) Execute() error { _, err := c.ExecuteC() return err } // ExecuteC executes the command. func (c *Command) ExecuteC() (cmd *Command, err error) { // Regardless of what command execute is called on, run on Root only if c.HasParent() { return c.Root().ExecuteC() } // windows hook if preExecHookFn != nil { preExecHookFn(c) } // initialize help as the last point possible to allow for user // overriding c.InitDefaultHelpCmd() var args []string // Workaround FAIL with "go test -v" or "cobra.test -test.v", see #155 if c.args == nil && filepath.Base(os.Args[0]) != "cobra.test" { args = os.Args[1:] } else { args = c.args } var flags []string if c.TraverseChildren { cmd, flags, err = c.Traverse(args) } else { cmd, flags, err = c.Find(args) } if err != nil { // If found parse to a subcommand and then failed, talk about the subcommand if cmd != nil { c = cmd } if !c.SilenceErrors { c.Println("Error:", err.Error()) c.Printf("Run '%v --help' for usage.\n", c.CommandPath()) } return c, err } err = cmd.execute(flags) if err != nil { // Always show help if requested, even if SilenceErrors is in // effect if err == flag.ErrHelp { cmd.HelpFunc()(cmd, args) return cmd, nil } // If root command has SilentErrors flagged, // all subcommands should respect it if !cmd.SilenceErrors && !c.SilenceErrors { c.Println("Error:", err.Error()) } // If root command has SilentUsage flagged, // all subcommands should respect it if !cmd.SilenceUsage && !c.SilenceUsage { c.Println(cmd.UsageString()) } } return cmd, err } func (c *Command) ValidateArgs(args []string) error { if c.Args == nil { return nil } return c.Args(c, args) } func (c *Command) validateRequiredFlags() error { flags := c.Flags() missingFlagNames := []string{} flags.VisitAll(func(pflag *flag.Flag) { requiredAnnotation, found := pflag.Annotations[BashCompOneRequiredFlag] if !found { return } if (requiredAnnotation[0] == "true") && !pflag.Changed { missingFlagNames = append(missingFlagNames, pflag.Name) } }) if len(missingFlagNames) > 0 { return fmt.Errorf(`required flag(s) "%s" not set`, strings.Join(missingFlagNames, `", "`)) } return nil } // InitDefaultHelpFlag adds default help flag to c. // It is called automatically by executing the c or by calling help and usage. // If c already has help flag, it will do nothing. func (c *Command) InitDefaultHelpFlag() { c.mergePersistentFlags() if c.Flags().Lookup("help") == nil { usage := "help for " if c.Name() == "" { usage += "this command" } else { usage += c.Name() } c.Flags().BoolP("help", "h", false, usage) } } // InitDefaultVersionFlag adds default version flag to c. // It is called automatically by executing the c. // If c already has a version flag, it will do nothing. // If c.Version is empty, it will do nothing. func (c *Command) InitDefaultVersionFlag() { if c.Version == "" { return } c.mergePersistentFlags() if c.Flags().Lookup("version") == nil { usage := "version for " if c.Name() == "" { usage += "this command" } else { usage += c.Name() } c.Flags().Bool("version", false, usage) } } // InitDefaultHelpCmd adds default help command to c. // It is called automatically by executing the c or by calling help and usage. // If c already has help command or c has no subcommands, it will do nothing. func (c *Command) InitDefaultHelpCmd() { if !c.HasSubCommands() { return } if c.helpCommand == nil { c.helpCommand = &Command{ Use: "help [command]", Short: "Help about any command", Long: `Help provides help for any command in the application. Simply type ` + c.Name() + ` help [path to command] for full details.`, Run: func(c *Command, args []string) { cmd, _, e := c.Root().Find(args) if cmd == nil || e != nil { c.Printf("Unknown help topic %#q\n", args) c.Root().Usage() } else { cmd.InitDefaultHelpFlag() // make possible 'help' flag to be shown cmd.Help() } }, } } c.RemoveCommand(c.helpCommand) c.AddCommand(c.helpCommand) } // ResetCommands delete parent, subcommand and help command from c. func (c *Command) ResetCommands() { c.parent = nil c.commands = nil c.helpCommand = nil c.parentsPflags = nil } // Sorts commands by their names. type commandSorterByName []*Command func (c commandSorterByName) Len() int { return len(c) } func (c commandSorterByName) Swap(i, j int) { c[i], c[j] = c[j], c[i] } func (c commandSorterByName) Less(i, j int) bool { return c[i].Name() < c[j].Name() } // Commands returns a sorted slice of child commands. func (c *Command) Commands() []*Command { // do not sort commands if it already sorted or sorting was disabled if EnableCommandSorting && !c.commandsAreSorted { sort.Sort(commandSorterByName(c.commands)) c.commandsAreSorted = true } return c.commands } // AddCommand adds one or more commands to this parent command. func (c *Command) AddCommand(cmds ...*Command) { for i, x := range cmds { if cmds[i] == c { panic("Command can't be a child of itself") } cmds[i].parent = c // update max lengths usageLen := len(x.Use) if usageLen > c.commandsMaxUseLen { c.commandsMaxUseLen = usageLen } commandPathLen := len(x.CommandPath()) if commandPathLen > c.commandsMaxCommandPathLen { c.commandsMaxCommandPathLen = commandPathLen } nameLen := len(x.Name()) if nameLen > c.commandsMaxNameLen { c.commandsMaxNameLen = nameLen } // If global normalization function exists, update all children if c.globNormFunc != nil { x.SetGlobalNormalizationFunc(c.globNormFunc) } c.commands = append(c.commands, x) c.commandsAreSorted = false } } // RemoveCommand removes one or more commands from a parent command. func (c *Command) RemoveCommand(cmds ...*Command) { commands := []*Command{} main: for _, command := range c.commands { for _, cmd := range cmds { if command == cmd { command.parent = nil continue main } } commands = append(commands, command) } c.commands = commands // recompute all lengths c.commandsMaxUseLen = 0 c.commandsMaxCommandPathLen = 0 c.commandsMaxNameLen = 0 for _, command := range c.commands { usageLen := len(command.Use) if usageLen > c.commandsMaxUseLen { c.commandsMaxUseLen = usageLen } commandPathLen := len(command.CommandPath()) if commandPathLen > c.commandsMaxCommandPathLen { c.commandsMaxCommandPathLen = commandPathLen } nameLen := len(command.Name()) if nameLen > c.commandsMaxNameLen { c.commandsMaxNameLen = nameLen } } } // Print is a convenience method to Print to the defined output, fallback to Stderr if not set. func (c *Command) Print(i ...interface{}) { fmt.Fprint(c.OutOrStderr(), i...) } // Println is a convenience method to Println to the defined output, fallback to Stderr if not set. func (c *Command) Println(i ...interface{}) { c.Print(fmt.Sprintln(i...)) } // Printf is a convenience method to Printf to the defined output, fallback to Stderr if not set. func (c *Command) Printf(format string, i ...interface{}) { c.Print(fmt.Sprintf(format, i...)) } // CommandPath returns the full path to this command. func (c *Command) CommandPath() string { if c.HasParent() { return c.Parent().CommandPath() + " " + c.Name() } return c.Name() } // UseLine puts out the full usage for a given command (including parents). func (c *Command) UseLine() string { var useline string if c.HasParent() { useline = c.parent.CommandPath() + " " + c.Use } else { useline = c.Use } if c.DisableFlagsInUseLine { return useline } if c.HasAvailableFlags() && !strings.Contains(useline, "[flags]") { useline += " [flags]" } return useline } // DebugFlags used to determine which flags have been assigned to which commands // and which persist. func (c *Command) DebugFlags() { c.Println("DebugFlags called on", c.Name()) var debugflags func(*Command) debugflags = func(x *Command) { if x.HasFlags() || x.HasPersistentFlags() { c.Println(x.Name()) } if x.HasFlags() { x.flags.VisitAll(func(f *flag.Flag) { if x.HasPersistentFlags() && x.persistentFlag(f.Name) != nil { c.Println(" -"+f.Shorthand+",", "--"+f.Name, "["+f.DefValue+"]", "", f.Value, " [LP]") } else { c.Println(" -"+f.Shorthand+",", "--"+f.Name, "["+f.DefValue+"]", "", f.Value, " [L]") } }) } if x.HasPersistentFlags() { x.pflags.VisitAll(func(f *flag.Flag) { if x.HasFlags() { if x.flags.Lookup(f.Name) == nil { c.Println(" -"+f.Shorthand+",", "--"+f.Name, "["+f.DefValue+"]", "", f.Value, " [P]") } } else { c.Println(" -"+f.Shorthand+",", "--"+f.Name, "["+f.DefValue+"]", "", f.Value, " [P]") } }) } c.Println(x.flagErrorBuf) if x.HasSubCommands() { for _, y := range x.commands { debugflags(y) } } } debugflags(c) } // Name returns the command's name: the first word in the use line. func (c *Command) Name() string { name := c.Use i := strings.Index(name, " ") if i >= 0 { name = name[:i] } return name } // HasAlias determines if a given string is an alias of the command. func (c *Command) HasAlias(s string) bool { for _, a := range c.Aliases { if a == s { return true } } return false } // hasNameOrAliasPrefix returns true if the Name or any of aliases start // with prefix func (c *Command) hasNameOrAliasPrefix(prefix string) bool { if strings.HasPrefix(c.Name(), prefix) { return true } for _, alias := range c.Aliases { if strings.HasPrefix(alias, prefix) { return true } } return false } // NameAndAliases returns a list of the command name and all aliases func (c *Command) NameAndAliases() string { return strings.Join(append([]string{c.Name()}, c.Aliases...), ", ") } // HasExample determines if the command has example. func (c *Command) HasExample() bool { return len(c.Example) > 0 } // Runnable determines if the command is itself runnable. func (c *Command) Runnable() bool { return c.Run != nil || c.RunE != nil } // HasSubCommands determines if the command has children commands. func (c *Command) HasSubCommands() bool { return len(c.commands) > 0 } // IsAvailableCommand determines if a command is available as a non-help command // (this includes all non deprecated/hidden commands). func (c *Command) IsAvailableCommand() bool { if len(c.Deprecated) != 0 || c.Hidden { return false } if c.HasParent() && c.Parent().helpCommand == c { return false } if c.Runnable() || c.HasAvailableSubCommands() { return true } return false } // IsAdditionalHelpTopicCommand determines if a command is an additional // help topic command; additional help topic command is determined by the // fact that it is NOT runnable/hidden/deprecated, and has no sub commands that // are runnable/hidden/deprecated. // Concrete example: https://github.com/spf13/cobra/issues/393#issuecomment-282741924. func (c *Command) IsAdditionalHelpTopicCommand() bool { // if a command is runnable, deprecated, or hidden it is not a 'help' command if c.Runnable() || len(c.Deprecated) != 0 || c.Hidden { return false } // if any non-help sub commands are found, the command is not a 'help' command for _, sub := range c.commands { if !sub.IsAdditionalHelpTopicCommand() { return false } } // the command either has no sub commands, or no non-help sub commands return true } // HasHelpSubCommands determines if a command has any available 'help' sub commands // that need to be shown in the usage/help default template under 'additional help // topics'. func (c *Command) HasHelpSubCommands() bool { // return true on the first found available 'help' sub command for _, sub := range c.commands { if sub.IsAdditionalHelpTopicCommand() { return true } } // the command either has no sub commands, or no available 'help' sub commands return false } // HasAvailableSubCommands determines if a command has available sub commands that // need to be shown in the usage/help default template under 'available commands'. func (c *Command) HasAvailableSubCommands() bool { // return true on the first found available (non deprecated/help/hidden) // sub command for _, sub := range c.commands { if sub.IsAvailableCommand() { return true } } // the command either has no sub commands, or no available (non deprecated/help/hidden) // sub commands return false } // HasParent determines if the command is a child command. func (c *Command) HasParent() bool { return c.parent != nil } // GlobalNormalizationFunc returns the global normalization function or nil if doesn't exists. func (c *Command) GlobalNormalizationFunc() func(f *flag.FlagSet, name string) flag.NormalizedName { return c.globNormFunc } // Flags returns the complete FlagSet that applies // to this command (local and persistent declared here and by all parents). func (c *Command) Flags() *flag.FlagSet { if c.flags == nil { c.flags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) if c.flagErrorBuf == nil { c.flagErrorBuf = new(bytes.Buffer) } c.flags.SetOutput(c.flagErrorBuf) } return c.flags } // LocalNonPersistentFlags are flags specific to this command which will NOT persist to subcommands. func (c *Command) LocalNonPersistentFlags() *flag.FlagSet { persistentFlags := c.PersistentFlags() out := flag.NewFlagSet(c.Name(), flag.ContinueOnError) c.LocalFlags().VisitAll(func(f *flag.Flag) { if persistentFlags.Lookup(f.Name) == nil { out.AddFlag(f) } }) return out } // LocalFlags returns the local FlagSet specifically set in the current command. func (c *Command) LocalFlags() *flag.FlagSet { c.mergePersistentFlags() if c.lflags == nil { c.lflags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) if c.flagErrorBuf == nil { c.flagErrorBuf = new(bytes.Buffer) } c.lflags.SetOutput(c.flagErrorBuf) } c.lflags.SortFlags = c.Flags().SortFlags if c.globNormFunc != nil { c.lflags.SetNormalizeFunc(c.globNormFunc) } addToLocal := func(f *flag.Flag) { if c.lflags.Lookup(f.Name) == nil && c.parentsPflags.Lookup(f.Name) == nil { c.lflags.AddFlag(f) } } c.Flags().VisitAll(addToLocal) c.PersistentFlags().VisitAll(addToLocal) return c.lflags } // InheritedFlags returns all flags which were inherited from parents commands. func (c *Command) InheritedFlags() *flag.FlagSet { c.mergePersistentFlags() if c.iflags == nil { c.iflags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) if c.flagErrorBuf == nil { c.flagErrorBuf = new(bytes.Buffer) } c.iflags.SetOutput(c.flagErrorBuf) } local := c.LocalFlags() if c.globNormFunc != nil { c.iflags.SetNormalizeFunc(c.globNormFunc) } c.parentsPflags.VisitAll(func(f *flag.Flag) { if c.iflags.Lookup(f.Name) == nil && local.Lookup(f.Name) == nil { c.iflags.AddFlag(f) } }) return c.iflags } // NonInheritedFlags returns all flags which were not inherited from parent commands. func (c *Command) NonInheritedFlags() *flag.FlagSet { return c.LocalFlags() } // PersistentFlags returns the persistent FlagSet specifically set in the current command. func (c *Command) PersistentFlags() *flag.FlagSet { if c.pflags == nil { c.pflags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) if c.flagErrorBuf == nil { c.flagErrorBuf = new(bytes.Buffer) } c.pflags.SetOutput(c.flagErrorBuf) } return c.pflags } // ResetFlags deletes all flags from command. func (c *Command) ResetFlags() { c.flagErrorBuf = new(bytes.Buffer) c.flagErrorBuf.Reset() c.flags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) c.flags.SetOutput(c.flagErrorBuf) c.pflags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) c.pflags.SetOutput(c.flagErrorBuf) c.lflags = nil c.iflags = nil c.parentsPflags = nil } // HasFlags checks if the command contains any flags (local plus persistent from the entire structure). func (c *Command) HasFlags() bool { return c.Flags().HasFlags() } // HasPersistentFlags checks if the command contains persistent flags. func (c *Command) HasPersistentFlags() bool { return c.PersistentFlags().HasFlags() } // HasLocalFlags checks if the command has flags specifically declared locally. func (c *Command) HasLocalFlags() bool { return c.LocalFlags().HasFlags() } // HasInheritedFlags checks if the command has flags inherited from its parent command. func (c *Command) HasInheritedFlags() bool { return c.InheritedFlags().HasFlags() } // HasAvailableFlags checks if the command contains any flags (local plus persistent from the entire // structure) which are not hidden or deprecated. func (c *Command) HasAvailableFlags() bool { return c.Flags().HasAvailableFlags() } // HasAvailablePersistentFlags checks if the command contains persistent flags which are not hidden or deprecated. func (c *Command) HasAvailablePersistentFlags() bool { return c.PersistentFlags().HasAvailableFlags() } // HasAvailableLocalFlags checks if the command has flags specifically declared locally which are not hidden // or deprecated. func (c *Command) HasAvailableLocalFlags() bool { return c.LocalFlags().HasAvailableFlags() } // HasAvailableInheritedFlags checks if the command has flags inherited from its parent command which are // not hidden or deprecated. func (c *Command) HasAvailableInheritedFlags() bool { return c.InheritedFlags().HasAvailableFlags() } // Flag climbs up the command tree looking for matching flag. func (c *Command) Flag(name string) (flag *flag.Flag) { flag = c.Flags().Lookup(name) if flag == nil { flag = c.persistentFlag(name) } return } // Recursively find matching persistent flag. func (c *Command) persistentFlag(name string) (flag *flag.Flag) { if c.HasPersistentFlags() { flag = c.PersistentFlags().Lookup(name) } if flag == nil { c.updateParentsPflags() flag = c.parentsPflags.Lookup(name) } return } // ParseFlags parses persistent flag tree and local flags. func (c *Command) ParseFlags(args []string) error { if c.DisableFlagParsing { return nil } if c.flagErrorBuf == nil { c.flagErrorBuf = new(bytes.Buffer) } beforeErrorBufLen := c.flagErrorBuf.Len() c.mergePersistentFlags() err := c.Flags().Parse(args) // Print warnings if they occurred (e.g. deprecated flag messages). if c.flagErrorBuf.Len()-beforeErrorBufLen > 0 && err == nil { c.Print(c.flagErrorBuf.String()) } return err } // Parent returns a commands parent command. func (c *Command) Parent() *Command { return c.parent } // mergePersistentFlags merges c.PersistentFlags() to c.Flags() // and adds missing persistent flags of all parents. func (c *Command) mergePersistentFlags() { c.updateParentsPflags() c.Flags().AddFlagSet(c.PersistentFlags()) c.Flags().AddFlagSet(c.parentsPflags) } // updateParentsPflags updates c.parentsPflags by adding // new persistent flags of all parents. // If c.parentsPflags == nil, it makes new. func (c *Command) updateParentsPflags() { if c.parentsPflags == nil { c.parentsPflags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) c.parentsPflags.SetOutput(c.flagErrorBuf) c.parentsPflags.SortFlags = false } if c.globNormFunc != nil { c.parentsPflags.SetNormalizeFunc(c.globNormFunc) } c.Root().PersistentFlags().AddFlagSet(flag.CommandLine) c.VisitParents(func(parent *Command) { c.parentsPflags.AddFlagSet(parent.PersistentFlags()) }) } ================================================ FILE: vendor/github.com/spf13/cobra/command_notwin.go ================================================ // +build !windows package cobra var preExecHookFn func(*Command) ================================================ FILE: vendor/github.com/spf13/cobra/command_test.go ================================================ package cobra import ( "bytes" "fmt" "os" "reflect" "strings" "testing" "github.com/spf13/pflag" ) func emptyRun(*Command, []string) {} func executeCommand(root *Command, args ...string) (output string, err error) { _, output, err = executeCommandC(root, args...) return output, err } func executeCommandC(root *Command, args ...string) (c *Command, output string, err error) { buf := new(bytes.Buffer) root.SetOutput(buf) root.SetArgs(args) c, err = root.ExecuteC() return c, buf.String(), err } func resetCommandLineFlagSet() { pflag.CommandLine = pflag.NewFlagSet(os.Args[0], pflag.ExitOnError) } func checkStringContains(t *testing.T, got, expected string) { if !strings.Contains(got, expected) { t.Errorf("Expected to contain: \n %v\nGot:\n %v\n", expected, got) } } func checkStringOmits(t *testing.T, got, expected string) { if strings.Contains(got, expected) { t.Errorf("Expected to not contain: \n %v\nGot: %v", expected, got) } } func TestSingleCommand(t *testing.T) { var rootCmdArgs []string rootCmd := &Command{ Use: "root", Args: ExactArgs(2), Run: func(_ *Command, args []string) { rootCmdArgs = args }, } aCmd := &Command{Use: "a", Args: NoArgs, Run: emptyRun} bCmd := &Command{Use: "b", Args: NoArgs, Run: emptyRun} rootCmd.AddCommand(aCmd, bCmd) output, err := executeCommand(rootCmd, "one", "two") if output != "" { t.Errorf("Unexpected output: %v", output) } if err != nil { t.Errorf("Unexpected error: %v", err) } got := strings.Join(rootCmdArgs, " ") expected := "one two" if got != expected { t.Errorf("rootCmdArgs expected: %q, got: %q", expected, got) } } func TestChildCommand(t *testing.T) { var child1CmdArgs []string rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun} child1Cmd := &Command{ Use: "child1", Args: ExactArgs(2), Run: func(_ *Command, args []string) { child1CmdArgs = args }, } child2Cmd := &Command{Use: "child2", Args: NoArgs, Run: emptyRun} rootCmd.AddCommand(child1Cmd, child2Cmd) output, err := executeCommand(rootCmd, "child1", "one", "two") if output != "" { t.Errorf("Unexpected output: %v", output) } if err != nil { t.Errorf("Unexpected error: %v", err) } got := strings.Join(child1CmdArgs, " ") expected := "one two" if got != expected { t.Errorf("child1CmdArgs expected: %q, got: %q", expected, got) } } func TestCallCommandWithoutSubcommands(t *testing.T) { rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun} _, err := executeCommand(rootCmd) if err != nil { t.Errorf("Calling command without subcommands should not have error: %v", err) } } func TestRootExecuteUnknownCommand(t *testing.T) { rootCmd := &Command{Use: "root", Run: emptyRun} rootCmd.AddCommand(&Command{Use: "child", Run: emptyRun}) output, _ := executeCommand(rootCmd, "unknown") expected := "Error: unknown command \"unknown\" for \"root\"\nRun 'root --help' for usage.\n" if output != expected { t.Errorf("Expected:\n %q\nGot:\n %q\n", expected, output) } } func TestSubcommandExecuteC(t *testing.T) { rootCmd := &Command{Use: "root", Run: emptyRun} childCmd := &Command{Use: "child", Run: emptyRun} rootCmd.AddCommand(childCmd) c, output, err := executeCommandC(rootCmd, "child") if output != "" { t.Errorf("Unexpected output: %v", output) } if err != nil { t.Errorf("Unexpected error: %v", err) } if c.Name() != "child" { t.Errorf(`invalid command returned from ExecuteC: expected "child"', got %q`, c.Name()) } } func TestRootUnknownCommandSilenced(t *testing.T) { rootCmd := &Command{Use: "root", Run: emptyRun} rootCmd.SilenceErrors = true rootCmd.SilenceUsage = true rootCmd.AddCommand(&Command{Use: "child", Run: emptyRun}) output, _ := executeCommand(rootCmd, "unknown") if output != "" { t.Errorf("Expected blank output, because of silenced usage.\nGot:\n %q\n", output) } } func TestCommandAlias(t *testing.T) { var timesCmdArgs []string rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun} echoCmd := &Command{ Use: "echo", Aliases: []string{"say", "tell"}, Args: NoArgs, Run: emptyRun, } timesCmd := &Command{ Use: "times", Args: ExactArgs(2), Run: func(_ *Command, args []string) { timesCmdArgs = args }, } echoCmd.AddCommand(timesCmd) rootCmd.AddCommand(echoCmd) output, err := executeCommand(rootCmd, "tell", "times", "one", "two") if output != "" { t.Errorf("Unexpected output: %v", output) } if err != nil { t.Errorf("Unexpected error: %v", err) } got := strings.Join(timesCmdArgs, " ") expected := "one two" if got != expected { t.Errorf("timesCmdArgs expected: %v, got: %v", expected, got) } } func TestEnablePrefixMatching(t *testing.T) { EnablePrefixMatching = true var aCmdArgs []string rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun} aCmd := &Command{ Use: "aCmd", Args: ExactArgs(2), Run: func(_ *Command, args []string) { aCmdArgs = args }, } bCmd := &Command{Use: "bCmd", Args: NoArgs, Run: emptyRun} rootCmd.AddCommand(aCmd, bCmd) output, err := executeCommand(rootCmd, "a", "one", "two") if output != "" { t.Errorf("Unexpected output: %v", output) } if err != nil { t.Errorf("Unexpected error: %v", err) } got := strings.Join(aCmdArgs, " ") expected := "one two" if got != expected { t.Errorf("aCmdArgs expected: %q, got: %q", expected, got) } EnablePrefixMatching = false } func TestAliasPrefixMatching(t *testing.T) { EnablePrefixMatching = true var timesCmdArgs []string rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun} echoCmd := &Command{ Use: "echo", Aliases: []string{"say", "tell"}, Args: NoArgs, Run: emptyRun, } timesCmd := &Command{ Use: "times", Args: ExactArgs(2), Run: func(_ *Command, args []string) { timesCmdArgs = args }, } echoCmd.AddCommand(timesCmd) rootCmd.AddCommand(echoCmd) output, err := executeCommand(rootCmd, "sa", "times", "one", "two") if output != "" { t.Errorf("Unexpected output: %v", output) } if err != nil { t.Errorf("Unexpected error: %v", err) } got := strings.Join(timesCmdArgs, " ") expected := "one two" if got != expected { t.Errorf("timesCmdArgs expected: %v, got: %v", expected, got) } EnablePrefixMatching = false } // TestChildSameName checks the correct behaviour of cobra in cases, // when an application with name "foo" and with subcommand "foo" // is executed with args "foo foo". func TestChildSameName(t *testing.T) { var fooCmdArgs []string rootCmd := &Command{Use: "foo", Args: NoArgs, Run: emptyRun} fooCmd := &Command{ Use: "foo", Args: ExactArgs(2), Run: func(_ *Command, args []string) { fooCmdArgs = args }, } barCmd := &Command{Use: "bar", Args: NoArgs, Run: emptyRun} rootCmd.AddCommand(fooCmd, barCmd) output, err := executeCommand(rootCmd, "foo", "one", "two") if output != "" { t.Errorf("Unexpected output: %v", output) } if err != nil { t.Errorf("Unexpected error: %v", err) } got := strings.Join(fooCmdArgs, " ") expected := "one two" if got != expected { t.Errorf("fooCmdArgs expected: %v, got: %v", expected, got) } } // TestGrandChildSameName checks the correct behaviour of cobra in cases, // when user has a root command and a grand child // with the same name. func TestGrandChildSameName(t *testing.T) { var fooCmdArgs []string rootCmd := &Command{Use: "foo", Args: NoArgs, Run: emptyRun} barCmd := &Command{Use: "bar", Args: NoArgs, Run: emptyRun} fooCmd := &Command{ Use: "foo", Args: ExactArgs(2), Run: func(_ *Command, args []string) { fooCmdArgs = args }, } barCmd.AddCommand(fooCmd) rootCmd.AddCommand(barCmd) output, err := executeCommand(rootCmd, "bar", "foo", "one", "two") if output != "" { t.Errorf("Unexpected output: %v", output) } if err != nil { t.Errorf("Unexpected error: %v", err) } got := strings.Join(fooCmdArgs, " ") expected := "one two" if got != expected { t.Errorf("fooCmdArgs expected: %v, got: %v", expected, got) } } func TestFlagLong(t *testing.T) { var cArgs []string c := &Command{ Use: "c", Args: ArbitraryArgs, Run: func(_ *Command, args []string) { cArgs = args }, } var intFlagValue int var stringFlagValue string c.Flags().IntVar(&intFlagValue, "intf", -1, "") c.Flags().StringVar(&stringFlagValue, "sf", "", "") output, err := executeCommand(c, "--intf=7", "--sf=abc", "one", "--", "two") if output != "" { t.Errorf("Unexpected output: %v", err) } if err != nil { t.Errorf("Unexpected error: %v", err) } if c.ArgsLenAtDash() != 1 { t.Errorf("Expected ArgsLenAtDash: %v but got %v", 1, c.ArgsLenAtDash()) } if intFlagValue != 7 { t.Errorf("Expected intFlagValue: %v, got %v", 7, intFlagValue) } if stringFlagValue != "abc" { t.Errorf("Expected stringFlagValue: %q, got %q", "abc", stringFlagValue) } got := strings.Join(cArgs, " ") expected := "one two" if got != expected { t.Errorf("Expected arguments: %q, got %q", expected, got) } } func TestFlagShort(t *testing.T) { var cArgs []string c := &Command{ Use: "c", Args: ArbitraryArgs, Run: func(_ *Command, args []string) { cArgs = args }, } var intFlagValue int var stringFlagValue string c.Flags().IntVarP(&intFlagValue, "intf", "i", -1, "") c.Flags().StringVarP(&stringFlagValue, "sf", "s", "", "") output, err := executeCommand(c, "-i", "7", "-sabc", "one", "two") if output != "" { t.Errorf("Unexpected output: %v", err) } if err != nil { t.Errorf("Unexpected error: %v", err) } if intFlagValue != 7 { t.Errorf("Expected flag value: %v, got %v", 7, intFlagValue) } if stringFlagValue != "abc" { t.Errorf("Expected stringFlagValue: %q, got %q", "abc", stringFlagValue) } got := strings.Join(cArgs, " ") expected := "one two" if got != expected { t.Errorf("Expected arguments: %q, got %q", expected, got) } } func TestChildFlag(t *testing.T) { rootCmd := &Command{Use: "root", Run: emptyRun} childCmd := &Command{Use: "child", Run: emptyRun} rootCmd.AddCommand(childCmd) var intFlagValue int childCmd.Flags().IntVarP(&intFlagValue, "intf", "i", -1, "") output, err := executeCommand(rootCmd, "child", "-i7") if output != "" { t.Errorf("Unexpected output: %v", err) } if err != nil { t.Errorf("Unexpected error: %v", err) } if intFlagValue != 7 { t.Errorf("Expected flag value: %v, got %v", 7, intFlagValue) } } func TestChildFlagWithParentLocalFlag(t *testing.T) { rootCmd := &Command{Use: "root", Run: emptyRun} childCmd := &Command{Use: "child", Run: emptyRun} rootCmd.AddCommand(childCmd) var intFlagValue int rootCmd.Flags().StringP("sf", "s", "", "") childCmd.Flags().IntVarP(&intFlagValue, "intf", "i", -1, "") _, err := executeCommand(rootCmd, "child", "-i7", "-sabc") if err == nil { t.Errorf("Invalid flag should generate error") } checkStringContains(t, err.Error(), "unknown shorthand") if intFlagValue != 7 { t.Errorf("Expected flag value: %v, got %v", 7, intFlagValue) } } func TestFlagInvalidInput(t *testing.T) { rootCmd := &Command{Use: "root", Run: emptyRun} rootCmd.Flags().IntP("intf", "i", -1, "") _, err := executeCommand(rootCmd, "-iabc") if err == nil { t.Errorf("Invalid flag value should generate error") } checkStringContains(t, err.Error(), "invalid syntax") } func TestFlagBeforeCommand(t *testing.T) { rootCmd := &Command{Use: "root", Run: emptyRun} childCmd := &Command{Use: "child", Run: emptyRun} rootCmd.AddCommand(childCmd) var flagValue int childCmd.Flags().IntVarP(&flagValue, "intf", "i", -1, "") // With short flag. _, err := executeCommand(rootCmd, "-i7", "child") if err != nil { t.Errorf("Unexpected error: %v", err) } if flagValue != 7 { t.Errorf("Expected flag value: %v, got %v", 7, flagValue) } // With long flag. _, err = executeCommand(rootCmd, "--intf=8", "child") if err != nil { t.Errorf("Unexpected error: %v", err) } if flagValue != 8 { t.Errorf("Expected flag value: %v, got %v", 9, flagValue) } } func TestStripFlags(t *testing.T) { tests := []struct { input []string output []string }{ { []string{"foo", "bar"}, []string{"foo", "bar"}, }, { []string{"foo", "--str", "-s"}, []string{"foo"}, }, { []string{"-s", "foo", "--str", "bar"}, []string{}, }, { []string{"-i10", "echo"}, []string{"echo"}, }, { []string{"-i=10", "echo"}, []string{"echo"}, }, { []string{"--int=100", "echo"}, []string{"echo"}, }, { []string{"-ib", "echo", "-sfoo", "baz"}, []string{"echo", "baz"}, }, { []string{"-i=baz", "bar", "-i", "foo", "blah"}, []string{"bar", "blah"}, }, { []string{"--int=baz", "-sbar", "-i", "foo", "blah"}, []string{"blah"}, }, { []string{"--bool", "bar", "-i", "foo", "blah"}, []string{"bar", "blah"}, }, { []string{"-b", "bar", "-i", "foo", "blah"}, []string{"bar", "blah"}, }, { []string{"--persist", "bar"}, []string{"bar"}, }, { []string{"-p", "bar"}, []string{"bar"}, }, } c := &Command{Use: "c", Run: emptyRun} c.PersistentFlags().BoolP("persist", "p", false, "") c.Flags().IntP("int", "i", -1, "") c.Flags().StringP("str", "s", "", "") c.Flags().BoolP("bool", "b", false, "") for i, test := range tests { got := stripFlags(test.input, c) if !reflect.DeepEqual(test.output, got) { t.Errorf("(%v) Expected: %v, got: %v", i, test.output, got) } } } func TestDisableFlagParsing(t *testing.T) { var cArgs []string c := &Command{ Use: "c", DisableFlagParsing: true, Run: func(_ *Command, args []string) { cArgs = args }, } args := []string{"cmd", "-v", "-race", "-file", "foo.go"} output, err := executeCommand(c, args...) if output != "" { t.Errorf("Unexpected output: %v", output) } if err != nil { t.Errorf("Unexpected error: %v", err) } if !reflect.DeepEqual(args, cArgs) { t.Errorf("Expected: %v, got: %v", args, cArgs) } } func TestPersistentFlagsOnSameCommand(t *testing.T) { var rootCmdArgs []string rootCmd := &Command{ Use: "root", Args: ArbitraryArgs, Run: func(_ *Command, args []string) { rootCmdArgs = args }, } var flagValue int rootCmd.PersistentFlags().IntVarP(&flagValue, "intf", "i", -1, "") output, err := executeCommand(rootCmd, "-i7", "one", "two") if output != "" { t.Errorf("Unexpected output: %v", output) } if err != nil { t.Errorf("Unexpected error: %v", err) } got := strings.Join(rootCmdArgs, " ") expected := "one two" if got != expected { t.Errorf("rootCmdArgs expected: %q, got %q", expected, got) } if flagValue != 7 { t.Errorf("flagValue expected: %v, got %v", 7, flagValue) } } // TestEmptyInputs checks, // if flags correctly parsed with blank strings in args. func TestEmptyInputs(t *testing.T) { c := &Command{Use: "c", Run: emptyRun} var flagValue int c.Flags().IntVarP(&flagValue, "intf", "i", -1, "") output, err := executeCommand(c, "", "-i7", "") if output != "" { t.Errorf("Unexpected output: %v", output) } if err != nil { t.Errorf("Unexpected error: %v", err) } if flagValue != 7 { t.Errorf("flagValue expected: %v, got %v", 7, flagValue) } } func TestOverwrittenFlag(t *testing.T) { // TODO: This test fails, but should work. t.Skip() parent := &Command{Use: "parent", Run: emptyRun} child := &Command{Use: "child", Run: emptyRun} parent.PersistentFlags().Bool("boolf", false, "") parent.PersistentFlags().Int("intf", -1, "") child.Flags().String("strf", "", "") child.Flags().Int("intf", -1, "") parent.AddCommand(child) childInherited := child.InheritedFlags() childLocal := child.LocalFlags() if childLocal.Lookup("strf") == nil { t.Error(`LocalFlags expected to contain "strf", got "nil"`) } if childInherited.Lookup("boolf") == nil { t.Error(`InheritedFlags expected to contain "boolf", got "nil"`) } if childInherited.Lookup("intf") != nil { t.Errorf(`InheritedFlags should not contain overwritten flag "intf"`) } if childLocal.Lookup("intf") == nil { t.Error(`LocalFlags expected to contain "intf", got "nil"`) } } func TestPersistentFlagsOnChild(t *testing.T) { var childCmdArgs []string rootCmd := &Command{Use: "root", Run: emptyRun} childCmd := &Command{ Use: "child", Args: ArbitraryArgs, Run: func(_ *Command, args []string) { childCmdArgs = args }, } rootCmd.AddCommand(childCmd) var parentFlagValue int var childFlagValue int rootCmd.PersistentFlags().IntVarP(&parentFlagValue, "parentf", "p", -1, "") childCmd.Flags().IntVarP(&childFlagValue, "childf", "c", -1, "") output, err := executeCommand(rootCmd, "child", "-c7", "-p8", "one", "two") if output != "" { t.Errorf("Unexpected output: %v", output) } if err != nil { t.Errorf("Unexpected error: %v", err) } got := strings.Join(childCmdArgs, " ") expected := "one two" if got != expected { t.Errorf("childCmdArgs expected: %q, got %q", expected, got) } if parentFlagValue != 8 { t.Errorf("parentFlagValue expected: %v, got %v", 8, parentFlagValue) } if childFlagValue != 7 { t.Errorf("childFlagValue expected: %v, got %v", 7, childFlagValue) } } func TestRequiredFlags(t *testing.T) { c := &Command{Use: "c", Run: emptyRun} c.Flags().String("foo1", "", "") c.MarkFlagRequired("foo1") c.Flags().String("foo2", "", "") c.MarkFlagRequired("foo2") c.Flags().String("bar", "", "") expected := fmt.Sprintf("required flag(s) %q, %q not set", "foo1", "foo2") _, err := executeCommand(c) got := err.Error() if got != expected { t.Errorf("Expected error: %q, got: %q", expected, got) } } func TestPersistentRequiredFlags(t *testing.T) { parent := &Command{Use: "parent", Run: emptyRun} parent.PersistentFlags().String("foo1", "", "") parent.MarkPersistentFlagRequired("foo1") parent.PersistentFlags().String("foo2", "", "") parent.MarkPersistentFlagRequired("foo2") parent.Flags().String("foo3", "", "") child := &Command{Use: "child", Run: emptyRun} child.Flags().String("bar1", "", "") child.MarkFlagRequired("bar1") child.Flags().String("bar2", "", "") child.MarkFlagRequired("bar2") child.Flags().String("bar3", "", "") parent.AddCommand(child) expected := fmt.Sprintf("required flag(s) %q, %q, %q, %q not set", "bar1", "bar2", "foo1", "foo2") _, err := executeCommand(parent, "child") if err.Error() != expected { t.Errorf("Expected %q, got %q", expected, err.Error()) } } func TestInitHelpFlagMergesFlags(t *testing.T) { usage := "custom flag" rootCmd := &Command{Use: "root"} rootCmd.PersistentFlags().Bool("help", false, "custom flag") childCmd := &Command{Use: "child"} rootCmd.AddCommand(childCmd) childCmd.InitDefaultHelpFlag() got := childCmd.Flags().Lookup("help").Usage if got != usage { t.Errorf("Expected the help flag from the root command with usage: %v\nGot the default with usage: %v", usage, got) } } func TestHelpCommandExecuted(t *testing.T) { rootCmd := &Command{Use: "root", Long: "Long description", Run: emptyRun} rootCmd.AddCommand(&Command{Use: "child", Run: emptyRun}) output, err := executeCommand(rootCmd, "help") if err != nil { t.Errorf("Unexpected error: %v", err) } checkStringContains(t, output, rootCmd.Long) } func TestHelpCommandExecutedOnChild(t *testing.T) { rootCmd := &Command{Use: "root", Run: emptyRun} childCmd := &Command{Use: "child", Long: "Long description", Run: emptyRun} rootCmd.AddCommand(childCmd) output, err := executeCommand(rootCmd, "help", "child") if err != nil { t.Errorf("Unexpected error: %v", err) } checkStringContains(t, output, childCmd.Long) } func TestSetHelpCommand(t *testing.T) { c := &Command{Use: "c", Run: emptyRun} c.AddCommand(&Command{Use: "empty", Run: emptyRun}) expected := "WORKS" c.SetHelpCommand(&Command{ Use: "help [command]", Short: "Help about any command", Long: `Help provides help for any command in the application. Simply type ` + c.Name() + ` help [path to command] for full details.`, Run: func(c *Command, _ []string) { c.Print(expected) }, }) got, err := executeCommand(c, "help") if err != nil { t.Errorf("Unexpected error: %v", err) } if got != expected { t.Errorf("Expected to contain %q, got %q", expected, got) } } func TestHelpFlagExecuted(t *testing.T) { rootCmd := &Command{Use: "root", Long: "Long description", Run: emptyRun} output, err := executeCommand(rootCmd, "--help") if err != nil { t.Errorf("Unexpected error: %v", err) } checkStringContains(t, output, rootCmd.Long) } func TestHelpFlagExecutedOnChild(t *testing.T) { rootCmd := &Command{Use: "root", Run: emptyRun} childCmd := &Command{Use: "child", Long: "Long description", Run: emptyRun} rootCmd.AddCommand(childCmd) output, err := executeCommand(rootCmd, "child", "--help") if err != nil { t.Errorf("Unexpected error: %v", err) } checkStringContains(t, output, childCmd.Long) } // TestHelpFlagInHelp checks, // if '--help' flag is shown in help for child (executing `parent help child`), // that has no other flags. // Related to https://github.com/spf13/cobra/issues/302. func TestHelpFlagInHelp(t *testing.T) { parentCmd := &Command{Use: "parent", Run: func(*Command, []string) {}} childCmd := &Command{Use: "child", Run: func(*Command, []string) {}} parentCmd.AddCommand(childCmd) output, err := executeCommand(parentCmd, "help", "child") if err != nil { t.Errorf("Unexpected error: %v", err) } checkStringContains(t, output, "[flags]") } func TestFlagsInUsage(t *testing.T) { rootCmd := &Command{Use: "root", Args: NoArgs, Run: func(*Command, []string) {}} output, err := executeCommand(rootCmd, "--help") if err != nil { t.Errorf("Unexpected error: %v", err) } checkStringContains(t, output, "[flags]") } func TestHelpExecutedOnNonRunnableChild(t *testing.T) { rootCmd := &Command{Use: "root", Run: emptyRun} childCmd := &Command{Use: "child", Long: "Long description"} rootCmd.AddCommand(childCmd) output, err := executeCommand(rootCmd, "child") if err != nil { t.Errorf("Unexpected error: %v", err) } checkStringContains(t, output, childCmd.Long) } func TestVersionFlagExecuted(t *testing.T) { rootCmd := &Command{Use: "root", Version: "1.0.0", Run: emptyRun} output, err := executeCommand(rootCmd, "--version", "arg1") if err != nil { t.Errorf("Unexpected error: %v", err) } checkStringContains(t, output, "root version 1.0.0") } func TestVersionTemplate(t *testing.T) { rootCmd := &Command{Use: "root", Version: "1.0.0", Run: emptyRun} rootCmd.SetVersionTemplate(`customized version: {{.Version}}`) output, err := executeCommand(rootCmd, "--version", "arg1") if err != nil { t.Errorf("Unexpected error: %v", err) } checkStringContains(t, output, "customized version: 1.0.0") } func TestVersionFlagExecutedOnSubcommand(t *testing.T) { rootCmd := &Command{Use: "root", Version: "1.0.0"} rootCmd.AddCommand(&Command{Use: "sub", Run: emptyRun}) output, err := executeCommand(rootCmd, "--version", "sub") if err != nil { t.Errorf("Unexpected error: %v", err) } checkStringContains(t, output, "root version 1.0.0") } func TestVersionFlagOnlyAddedToRoot(t *testing.T) { rootCmd := &Command{Use: "root", Version: "1.0.0", Run: emptyRun} rootCmd.AddCommand(&Command{Use: "sub", Run: emptyRun}) _, err := executeCommand(rootCmd, "sub", "--version") if err == nil { t.Errorf("Expected error") } checkStringContains(t, err.Error(), "unknown flag: --version") } func TestVersionFlagOnlyExistsIfVersionNonEmpty(t *testing.T) { rootCmd := &Command{Use: "root", Run: emptyRun} _, err := executeCommand(rootCmd, "--version") if err == nil { t.Errorf("Expected error") } checkStringContains(t, err.Error(), "unknown flag: --version") } func TestUsageIsNotPrintedTwice(t *testing.T) { var cmd = &Command{Use: "root"} var sub = &Command{Use: "sub"} cmd.AddCommand(sub) output, _ := executeCommand(cmd, "") if strings.Count(output, "Usage:") != 1 { t.Error("Usage output is not printed exactly once") } } func TestVisitParents(t *testing.T) { c := &Command{Use: "app"} sub := &Command{Use: "sub"} dsub := &Command{Use: "dsub"} sub.AddCommand(dsub) c.AddCommand(sub) total := 0 add := func(x *Command) { total++ } sub.VisitParents(add) if total != 1 { t.Errorf("Should have visited 1 parent but visited %d", total) } total = 0 dsub.VisitParents(add) if total != 2 { t.Errorf("Should have visited 2 parents but visited %d", total) } total = 0 c.VisitParents(add) if total != 0 { t.Errorf("Should have visited no parents but visited %d", total) } } func TestSuggestions(t *testing.T) { rootCmd := &Command{Use: "root", Run: emptyRun} timesCmd := &Command{ Use: "times", SuggestFor: []string{"counts"}, Run: emptyRun, } rootCmd.AddCommand(timesCmd) templateWithSuggestions := "Error: unknown command \"%s\" for \"root\"\n\nDid you mean this?\n\t%s\n\nRun 'root --help' for usage.\n" templateWithoutSuggestions := "Error: unknown command \"%s\" for \"root\"\nRun 'root --help' for usage.\n" tests := map[string]string{ "time": "times", "tiems": "times", "tims": "times", "timeS": "times", "rimes": "times", "ti": "times", "t": "times", "timely": "times", "ri": "", "timezone": "", "foo": "", "counts": "times", } for typo, suggestion := range tests { for _, suggestionsDisabled := range []bool{true, false} { rootCmd.DisableSuggestions = suggestionsDisabled var expected string output, _ := executeCommand(rootCmd, typo) if suggestion == "" || suggestionsDisabled { expected = fmt.Sprintf(templateWithoutSuggestions, typo) } else { expected = fmt.Sprintf(templateWithSuggestions, typo, suggestion) } if output != expected { t.Errorf("Unexpected response.\nExpected:\n %q\nGot:\n %q\n", expected, output) } } } } func TestRemoveCommand(t *testing.T) { rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun} childCmd := &Command{Use: "child", Run: emptyRun} rootCmd.AddCommand(childCmd) rootCmd.RemoveCommand(childCmd) _, err := executeCommand(rootCmd, "child") if err == nil { t.Error("Expected error on calling removed command. Got nil.") } } func TestReplaceCommandWithRemove(t *testing.T) { childUsed := 0 rootCmd := &Command{Use: "root", Run: emptyRun} child1Cmd := &Command{ Use: "child", Run: func(*Command, []string) { childUsed = 1 }, } child2Cmd := &Command{ Use: "child", Run: func(*Command, []string) { childUsed = 2 }, } rootCmd.AddCommand(child1Cmd) rootCmd.RemoveCommand(child1Cmd) rootCmd.AddCommand(child2Cmd) output, err := executeCommand(rootCmd, "child") if output != "" { t.Errorf("Unexpected output: %v", output) } if err != nil { t.Errorf("Unexpected error: %v", err) } if childUsed == 1 { t.Error("Removed command shouldn't be called") } if childUsed != 2 { t.Error("Replacing command should have been called but didn't") } } func TestDeprecatedCommand(t *testing.T) { rootCmd := &Command{Use: "root", Run: emptyRun} deprecatedCmd := &Command{ Use: "deprecated", Deprecated: "This command is deprecated", Run: emptyRun, } rootCmd.AddCommand(deprecatedCmd) output, err := executeCommand(rootCmd, "deprecated") if err != nil { t.Errorf("Unexpected error: %v", err) } checkStringContains(t, output, deprecatedCmd.Deprecated) } func TestHooks(t *testing.T) { var ( persPreArgs string preArgs string runArgs string postArgs string persPostArgs string ) c := &Command{ Use: "c", PersistentPreRun: func(_ *Command, args []string) { persPreArgs = strings.Join(args, " ") }, PreRun: func(_ *Command, args []string) { preArgs = strings.Join(args, " ") }, Run: func(_ *Command, args []string) { runArgs = strings.Join(args, " ") }, PostRun: func(_ *Command, args []string) { postArgs = strings.Join(args, " ") }, PersistentPostRun: func(_ *Command, args []string) { persPostArgs = strings.Join(args, " ") }, } output, err := executeCommand(c, "one", "two") if output != "" { t.Errorf("Unexpected output: %v", output) } if err != nil { t.Errorf("Unexpected error: %v", err) } if persPreArgs != "one two" { t.Errorf("Expected persPreArgs %q, got %q", "one two", persPreArgs) } if preArgs != "one two" { t.Errorf("Expected preArgs %q, got %q", "one two", preArgs) } if runArgs != "one two" { t.Errorf("Expected runArgs %q, got %q", "one two", runArgs) } if postArgs != "one two" { t.Errorf("Expected postArgs %q, got %q", "one two", postArgs) } if persPostArgs != "one two" { t.Errorf("Expected persPostArgs %q, got %q", "one two", persPostArgs) } } func TestPersistentHooks(t *testing.T) { var ( parentPersPreArgs string parentPreArgs string parentRunArgs string parentPostArgs string parentPersPostArgs string ) var ( childPersPreArgs string childPreArgs string childRunArgs string childPostArgs string childPersPostArgs string ) parentCmd := &Command{ Use: "parent", PersistentPreRun: func(_ *Command, args []string) { parentPersPreArgs = strings.Join(args, " ") }, PreRun: func(_ *Command, args []string) { parentPreArgs = strings.Join(args, " ") }, Run: func(_ *Command, args []string) { parentRunArgs = strings.Join(args, " ") }, PostRun: func(_ *Command, args []string) { parentPostArgs = strings.Join(args, " ") }, PersistentPostRun: func(_ *Command, args []string) { parentPersPostArgs = strings.Join(args, " ") }, } childCmd := &Command{ Use: "child", PersistentPreRun: func(_ *Command, args []string) { childPersPreArgs = strings.Join(args, " ") }, PreRun: func(_ *Command, args []string) { childPreArgs = strings.Join(args, " ") }, Run: func(_ *Command, args []string) { childRunArgs = strings.Join(args, " ") }, PostRun: func(_ *Command, args []string) { childPostArgs = strings.Join(args, " ") }, PersistentPostRun: func(_ *Command, args []string) { childPersPostArgs = strings.Join(args, " ") }, } parentCmd.AddCommand(childCmd) output, err := executeCommand(parentCmd, "child", "one", "two") if output != "" { t.Errorf("Unexpected output: %v", output) } if err != nil { t.Errorf("Unexpected error: %v", err) } // TODO: This test fails, but should not. // Related to https://github.com/spf13/cobra/issues/252. // // if parentPersPreArgs != "one two" { // t.Errorf("Expected parentPersPreArgs %q, got %q", "one two", parentPersPreArgs) // } if parentPreArgs != "" { t.Errorf("Expected blank parentPreArgs, got %q", parentPreArgs) } if parentRunArgs != "" { t.Errorf("Expected blank parentRunArgs, got %q", parentRunArgs) } if parentPostArgs != "" { t.Errorf("Expected blank parentPostArgs, got %q", parentPostArgs) } // TODO: This test fails, but should not. // Related to https://github.com/spf13/cobra/issues/252. // // if parentPersPostArgs != "one two" { // t.Errorf("Expected parentPersPostArgs %q, got %q", "one two", parentPersPostArgs) // } if childPersPreArgs != "one two" { t.Errorf("Expected childPersPreArgs %q, got %q", "one two", childPersPreArgs) } if childPreArgs != "one two" { t.Errorf("Expected childPreArgs %q, got %q", "one two", childPreArgs) } if childRunArgs != "one two" { t.Errorf("Expected childRunArgs %q, got %q", "one two", childRunArgs) } if childPostArgs != "one two" { t.Errorf("Expected childPostArgs %q, got %q", "one two", childPostArgs) } if childPersPostArgs != "one two" { t.Errorf("Expected childPersPostArgs %q, got %q", "one two", childPersPostArgs) } } // Related to https://github.com/spf13/cobra/issues/521. func TestGlobalNormFuncPropagation(t *testing.T) { normFunc := func(f *pflag.FlagSet, name string) pflag.NormalizedName { return pflag.NormalizedName(name) } rootCmd := &Command{Use: "root", Run: emptyRun} childCmd := &Command{Use: "child", Run: emptyRun} rootCmd.AddCommand(childCmd) rootCmd.SetGlobalNormalizationFunc(normFunc) if reflect.ValueOf(normFunc).Pointer() != reflect.ValueOf(rootCmd.GlobalNormalizationFunc()).Pointer() { t.Error("rootCmd seems to have a wrong normalization function") } if reflect.ValueOf(normFunc).Pointer() != reflect.ValueOf(childCmd.GlobalNormalizationFunc()).Pointer() { t.Error("childCmd should have had the normalization function of rootCmd") } } // Related to https://github.com/spf13/cobra/issues/521. func TestNormPassedOnLocal(t *testing.T) { toUpper := func(f *pflag.FlagSet, name string) pflag.NormalizedName { return pflag.NormalizedName(strings.ToUpper(name)) } c := &Command{} c.Flags().Bool("flagname", true, "this is a dummy flag") c.SetGlobalNormalizationFunc(toUpper) if c.LocalFlags().Lookup("flagname") != c.LocalFlags().Lookup("FLAGNAME") { t.Error("Normalization function should be passed on to Local flag set") } } // Related to https://github.com/spf13/cobra/issues/521. func TestNormPassedOnInherited(t *testing.T) { toUpper := func(f *pflag.FlagSet, name string) pflag.NormalizedName { return pflag.NormalizedName(strings.ToUpper(name)) } c := &Command{} c.SetGlobalNormalizationFunc(toUpper) child1 := &Command{} c.AddCommand(child1) c.PersistentFlags().Bool("flagname", true, "") child2 := &Command{} c.AddCommand(child2) inherited := child1.InheritedFlags() if inherited.Lookup("flagname") == nil || inherited.Lookup("flagname") != inherited.Lookup("FLAGNAME") { t.Error("Normalization function should be passed on to inherited flag set in command added before flag") } inherited = child2.InheritedFlags() if inherited.Lookup("flagname") == nil || inherited.Lookup("flagname") != inherited.Lookup("FLAGNAME") { t.Error("Normalization function should be passed on to inherited flag set in command added after flag") } } // Related to https://github.com/spf13/cobra/issues/521. func TestConsistentNormalizedName(t *testing.T) { toUpper := func(f *pflag.FlagSet, name string) pflag.NormalizedName { return pflag.NormalizedName(strings.ToUpper(name)) } n := func(f *pflag.FlagSet, name string) pflag.NormalizedName { return pflag.NormalizedName(name) } c := &Command{} c.Flags().Bool("flagname", true, "") c.SetGlobalNormalizationFunc(toUpper) c.SetGlobalNormalizationFunc(n) if c.LocalFlags().Lookup("flagname") == c.LocalFlags().Lookup("FLAGNAME") { t.Error("Normalizing flag names should not result in duplicate flags") } } func TestFlagOnPflagCommandLine(t *testing.T) { flagName := "flagOnCommandLine" pflag.String(flagName, "", "about my flag") c := &Command{Use: "c", Run: emptyRun} c.AddCommand(&Command{Use: "child", Run: emptyRun}) output, _ := executeCommand(c, "--help") checkStringContains(t, output, flagName) resetCommandLineFlagSet() } // TestHiddenCommandExecutes checks, // if hidden commands run as intended. func TestHiddenCommandExecutes(t *testing.T) { executed := false c := &Command{ Use: "c", Hidden: true, Run: func(*Command, []string) { executed = true }, } output, err := executeCommand(c) if output != "" { t.Errorf("Unexpected output: %v", output) } if err != nil { t.Errorf("Unexpected error: %v", err) } if !executed { t.Error("Hidden command should have been executed") } } // test to ensure hidden commands do not show up in usage/help text func TestHiddenCommandIsHidden(t *testing.T) { c := &Command{Use: "c", Hidden: true, Run: emptyRun} if c.IsAvailableCommand() { t.Errorf("Hidden command should be unavailable") } } func TestCommandsAreSorted(t *testing.T) { EnableCommandSorting = true originalNames := []string{"middle", "zlast", "afirst"} expectedNames := []string{"afirst", "middle", "zlast"} var rootCmd = &Command{Use: "root"} for _, name := range originalNames { rootCmd.AddCommand(&Command{Use: name}) } for i, c := range rootCmd.Commands() { got := c.Name() if expectedNames[i] != got { t.Errorf("Expected: %s, got: %s", expectedNames[i], got) } } EnableCommandSorting = true } func TestEnableCommandSortingIsDisabled(t *testing.T) { EnableCommandSorting = false originalNames := []string{"middle", "zlast", "afirst"} var rootCmd = &Command{Use: "root"} for _, name := range originalNames { rootCmd.AddCommand(&Command{Use: name}) } for i, c := range rootCmd.Commands() { got := c.Name() if originalNames[i] != got { t.Errorf("expected: %s, got: %s", originalNames[i], got) } } EnableCommandSorting = true } func TestSetOutput(t *testing.T) { c := &Command{} c.SetOutput(nil) if out := c.OutOrStdout(); out != os.Stdout { t.Errorf("Expected setting output to nil to revert back to stdout") } } func TestFlagErrorFunc(t *testing.T) { c := &Command{Use: "c", Run: emptyRun} expectedFmt := "This is expected: %v" c.SetFlagErrorFunc(func(_ *Command, err error) error { return fmt.Errorf(expectedFmt, err) }) _, err := executeCommand(c, "--unknown-flag") got := err.Error() expected := fmt.Sprintf(expectedFmt, "unknown flag: --unknown-flag") if got != expected { t.Errorf("Expected %v, got %v", expected, got) } } // TestSortedFlags checks, // if cmd.LocalFlags() is unsorted when cmd.Flags().SortFlags set to false. // Related to https://github.com/spf13/cobra/issues/404. func TestSortedFlags(t *testing.T) { c := &Command{} c.Flags().SortFlags = false names := []string{"C", "B", "A", "D"} for _, name := range names { c.Flags().Bool(name, false, "") } i := 0 c.LocalFlags().VisitAll(func(f *pflag.Flag) { if i == len(names) { return } if stringInSlice(f.Name, names) { if names[i] != f.Name { t.Errorf("Incorrect order. Expected %v, got %v", names[i], f.Name) } i++ } }) } // TestMergeCommandLineToFlags checks, // if pflag.CommandLine is correctly merged to c.Flags() after first call // of c.mergePersistentFlags. // Related to https://github.com/spf13/cobra/issues/443. func TestMergeCommandLineToFlags(t *testing.T) { pflag.Bool("boolflag", false, "") c := &Command{Use: "c", Run: emptyRun} c.mergePersistentFlags() if c.Flags().Lookup("boolflag") == nil { t.Fatal("Expecting to have flag from CommandLine in c.Flags()") } resetCommandLineFlagSet() } // TestUseDeprecatedFlags checks, // if cobra.Execute() prints a message, if a deprecated flag is used. // Related to https://github.com/spf13/cobra/issues/463. func TestUseDeprecatedFlags(t *testing.T) { c := &Command{Use: "c", Run: emptyRun} c.Flags().BoolP("deprecated", "d", false, "deprecated flag") c.Flags().MarkDeprecated("deprecated", "This flag is deprecated") output, err := executeCommand(c, "c", "-d") if err != nil { t.Error("Unexpected error:", err) } checkStringContains(t, output, "This flag is deprecated") } func TestTraverseWithParentFlags(t *testing.T) { rootCmd := &Command{Use: "root", TraverseChildren: true} rootCmd.Flags().String("str", "", "") rootCmd.Flags().BoolP("bool", "b", false, "") childCmd := &Command{Use: "child"} childCmd.Flags().Int("int", -1, "") rootCmd.AddCommand(childCmd) c, args, err := rootCmd.Traverse([]string{"-b", "--str", "ok", "child", "--int"}) if err != nil { t.Errorf("Unexpected error: %v", err) } if len(args) != 1 && args[0] != "--add" { t.Errorf("Wrong args: %v", args) } if c.Name() != childCmd.Name() { t.Errorf("Expected command: %q, got: %q", childCmd.Name(), c.Name()) } } func TestTraverseNoParentFlags(t *testing.T) { rootCmd := &Command{Use: "root", TraverseChildren: true} rootCmd.Flags().String("foo", "", "foo things") childCmd := &Command{Use: "child"} childCmd.Flags().String("str", "", "") rootCmd.AddCommand(childCmd) c, args, err := rootCmd.Traverse([]string{"child"}) if err != nil { t.Errorf("Unexpected error: %v", err) } if len(args) != 0 { t.Errorf("Wrong args %v", args) } if c.Name() != childCmd.Name() { t.Errorf("Expected command: %q, got: %q", childCmd.Name(), c.Name()) } } func TestTraverseWithBadParentFlags(t *testing.T) { rootCmd := &Command{Use: "root", TraverseChildren: true} childCmd := &Command{Use: "child"} childCmd.Flags().String("str", "", "") rootCmd.AddCommand(childCmd) expected := "unknown flag: --str" c, _, err := rootCmd.Traverse([]string{"--str", "ok", "child"}) if err == nil || !strings.Contains(err.Error(), expected) { t.Errorf("Expected error, %q, got %q", expected, err) } if c != nil { t.Errorf("Expected nil command") } } func TestTraverseWithBadChildFlag(t *testing.T) { rootCmd := &Command{Use: "root", TraverseChildren: true} rootCmd.Flags().String("str", "", "") childCmd := &Command{Use: "child"} rootCmd.AddCommand(childCmd) // Expect no error because the last commands args shouldn't be parsed in // Traverse. c, args, err := rootCmd.Traverse([]string{"child", "--str"}) if err != nil { t.Errorf("Unexpected error: %v", err) } if len(args) != 1 && args[0] != "--str" { t.Errorf("Wrong args: %v", args) } if c.Name() != childCmd.Name() { t.Errorf("Expected command %q, got: %q", childCmd.Name(), c.Name()) } } func TestTraverseWithTwoSubcommands(t *testing.T) { rootCmd := &Command{Use: "root", TraverseChildren: true} subCmd := &Command{Use: "sub", TraverseChildren: true} rootCmd.AddCommand(subCmd) subsubCmd := &Command{ Use: "subsub", } subCmd.AddCommand(subsubCmd) c, _, err := rootCmd.Traverse([]string{"sub", "subsub"}) if err != nil { t.Fatalf("Unexpected error: %v", err) } if c.Name() != subsubCmd.Name() { t.Fatalf("Expected command: %q, got %q", subsubCmd.Name(), c.Name()) } } // TestUpdateName checks if c.Name() updates on changed c.Use. // Related to https://github.com/spf13/cobra/pull/422#discussion_r143918343. func TestUpdateName(t *testing.T) { c := &Command{Use: "name xyz"} originalName := c.Name() c.Use = "changedName abc" if originalName == c.Name() || c.Name() != "changedName" { t.Error("c.Name() should be updated on changed c.Use") } } ================================================ FILE: vendor/github.com/spf13/cobra/command_win.go ================================================ // +build windows package cobra import ( "os" "time" "github.com/inconshreveable/mousetrap" ) var preExecHookFn = preExecHook func preExecHook(c *Command) { if MousetrapHelpText != "" && mousetrap.StartedByExplorer() { c.Print(MousetrapHelpText) time.Sleep(5 * time.Second) os.Exit(1) } } ================================================ FILE: vendor/github.com/spf13/cobra/zsh_completions.go ================================================ package cobra import ( "bytes" "fmt" "io" "os" "strings" ) // GenZshCompletionFile generates zsh completion file. func (c *Command) GenZshCompletionFile(filename string) error { outFile, err := os.Create(filename) if err != nil { return err } defer outFile.Close() return c.GenZshCompletion(outFile) } // GenZshCompletion generates a zsh completion file and writes to the passed writer. func (c *Command) GenZshCompletion(w io.Writer) error { buf := new(bytes.Buffer) writeHeader(buf, c) maxDepth := maxDepth(c) writeLevelMapping(buf, maxDepth) writeLevelCases(buf, maxDepth, c) _, err := buf.WriteTo(w) return err } func writeHeader(w io.Writer, cmd *Command) { fmt.Fprintf(w, "#compdef %s\n\n", cmd.Name()) } func maxDepth(c *Command) int { if len(c.Commands()) == 0 { return 0 } maxDepthSub := 0 for _, s := range c.Commands() { subDepth := maxDepth(s) if subDepth > maxDepthSub { maxDepthSub = subDepth } } return 1 + maxDepthSub } func writeLevelMapping(w io.Writer, numLevels int) { fmt.Fprintln(w, `_arguments \`) for i := 1; i <= numLevels; i++ { fmt.Fprintf(w, ` '%d: :->level%d' \`, i, i) fmt.Fprintln(w) } fmt.Fprintf(w, ` '%d: :%s'`, numLevels+1, "_files") fmt.Fprintln(w) } func writeLevelCases(w io.Writer, maxDepth int, root *Command) { fmt.Fprintln(w, "case $state in") defer fmt.Fprintln(w, "esac") for i := 1; i <= maxDepth; i++ { fmt.Fprintf(w, " level%d)\n", i) writeLevel(w, root, i) fmt.Fprintln(w, " ;;") } fmt.Fprintln(w, " *)") fmt.Fprintln(w, " _arguments '*: :_files'") fmt.Fprintln(w, " ;;") } func writeLevel(w io.Writer, root *Command, i int) { fmt.Fprintf(w, " case $words[%d] in\n", i) defer fmt.Fprintln(w, " esac") commands := filterByLevel(root, i) byParent := groupByParent(commands) for p, c := range byParent { names := names(c) fmt.Fprintf(w, " %s)\n", p) fmt.Fprintf(w, " _arguments '%d: :(%s)'\n", i, strings.Join(names, " ")) fmt.Fprintln(w, " ;;") } fmt.Fprintln(w, " *)") fmt.Fprintln(w, " _arguments '*: :_files'") fmt.Fprintln(w, " ;;") } func filterByLevel(c *Command, l int) []*Command { cs := make([]*Command, 0) if l == 0 { cs = append(cs, c) return cs } for _, s := range c.Commands() { cs = append(cs, filterByLevel(s, l-1)...) } return cs } func groupByParent(commands []*Command) map[string][]*Command { m := make(map[string][]*Command) for _, c := range commands { parent := c.Parent() if parent == nil { continue } m[parent.Name()] = append(m[parent.Name()], c) } return m } func names(commands []*Command) []string { ns := make([]string, len(commands)) for i, c := range commands { ns[i] = c.Name() } return ns } ================================================ FILE: vendor/github.com/spf13/cobra/zsh_completions_test.go ================================================ package cobra import ( "bytes" "strings" "testing" ) func TestZshCompletion(t *testing.T) { tcs := []struct { name string root *Command expectedExpressions []string }{ { name: "trivial", root: &Command{Use: "trivialapp"}, expectedExpressions: []string{"#compdef trivial"}, }, { name: "linear", root: func() *Command { r := &Command{Use: "linear"} sub1 := &Command{Use: "sub1"} r.AddCommand(sub1) sub2 := &Command{Use: "sub2"} sub1.AddCommand(sub2) sub3 := &Command{Use: "sub3"} sub2.AddCommand(sub3) return r }(), expectedExpressions: []string{"sub1", "sub2", "sub3"}, }, { name: "flat", root: func() *Command { r := &Command{Use: "flat"} r.AddCommand(&Command{Use: "c1"}) r.AddCommand(&Command{Use: "c2"}) return r }(), expectedExpressions: []string{"(c1 c2)"}, }, { name: "tree", root: func() *Command { r := &Command{Use: "tree"} sub1 := &Command{Use: "sub1"} r.AddCommand(sub1) sub11 := &Command{Use: "sub11"} sub12 := &Command{Use: "sub12"} sub1.AddCommand(sub11) sub1.AddCommand(sub12) sub2 := &Command{Use: "sub2"} r.AddCommand(sub2) sub21 := &Command{Use: "sub21"} sub22 := &Command{Use: "sub22"} sub2.AddCommand(sub21) sub2.AddCommand(sub22) return r }(), expectedExpressions: []string{"(sub11 sub12)", "(sub21 sub22)"}, }, } for _, tc := range tcs { t.Run(tc.name, func(t *testing.T) { buf := new(bytes.Buffer) tc.root.GenZshCompletion(buf) output := buf.String() for _, expectedExpression := range tc.expectedExpressions { if !strings.Contains(output, expectedExpression) { t.Errorf("Expected completion to contain %q somewhere; got %q", expectedExpression, output) } } }) } } ================================================ FILE: vendor/github.com/spf13/pflag/.gitignore ================================================ .idea/* ================================================ FILE: vendor/github.com/spf13/pflag/.travis.yml ================================================ sudo: false language: go go: - 1.7.3 - 1.8.1 - tip matrix: allow_failures: - go: tip install: - go get github.com/golang/lint/golint - export PATH=$GOPATH/bin:$PATH - go install ./... script: - verify/all.sh -v - go test ./... ================================================ FILE: vendor/github.com/spf13/pflag/LICENSE ================================================ Copyright (c) 2012 Alex Ogier. All rights reserved. Copyright (c) 2012 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. ================================================ FILE: vendor/github.com/spf13/pflag/README.md ================================================ [![Build Status](https://travis-ci.org/spf13/pflag.svg?branch=master)](https://travis-ci.org/spf13/pflag) [![Go Report Card](https://goreportcard.com/badge/github.com/spf13/pflag)](https://goreportcard.com/report/github.com/spf13/pflag) [![GoDoc](https://godoc.org/github.com/spf13/pflag?status.svg)](https://godoc.org/github.com/spf13/pflag) ## Description pflag is a drop-in replacement for Go's flag package, implementing POSIX/GNU-style --flags. pflag is compatible with the [GNU extensions to the POSIX recommendations for command-line options][1]. For a more precise description, see the "Command-line flag syntax" section below. [1]: http://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html pflag is available under the same style of BSD license as the Go language, which can be found in the LICENSE file. ## Installation pflag is available using the standard `go get` command. Install by running: go get github.com/spf13/pflag Run tests by running: go test github.com/spf13/pflag ## Usage pflag is a drop-in replacement of Go's native flag package. If you import pflag under the name "flag" then all code should continue to function with no changes. ``` go import flag "github.com/spf13/pflag" ``` There is one exception to this: if you directly instantiate the Flag struct there is one more field "Shorthand" that you will need to set. Most code never instantiates this struct directly, and instead uses functions such as String(), BoolVar(), and Var(), and is therefore unaffected. Define flags using flag.String(), Bool(), Int(), etc. This declares an integer flag, -flagname, stored in the pointer ip, with type *int. ``` go var ip *int = flag.Int("flagname", 1234, "help message for flagname") ``` If you like, you can bind the flag to a variable using the Var() functions. ``` go var flagvar int func init() { flag.IntVar(&flagvar, "flagname", 1234, "help message for flagname") } ``` Or you can create custom flags that satisfy the Value interface (with pointer receivers) and couple them to flag parsing by ``` go flag.Var(&flagVal, "name", "help message for flagname") ``` For such flags, the default value is just the initial value of the variable. After all flags are defined, call ``` go flag.Parse() ``` to parse the command line into the defined flags. Flags may then be used directly. If you're using the flags themselves, they are all pointers; if you bind to variables, they're values. ``` go fmt.Println("ip has value ", *ip) fmt.Println("flagvar has value ", flagvar) ``` There are helpers function to get values later if you have the FlagSet but it was difficult to keep up with all of the flag pointers in your code. If you have a pflag.FlagSet with a flag called 'flagname' of type int you can use GetInt() to get the int value. But notice that 'flagname' must exist and it must be an int. GetString("flagname") will fail. ``` go i, err := flagset.GetInt("flagname") ``` After parsing, the arguments after the flag are available as the slice flag.Args() or individually as flag.Arg(i). The arguments are indexed from 0 through flag.NArg()-1. The pflag package also defines some new functions that are not in flag, that give one-letter shorthands for flags. You can use these by appending 'P' to the name of any function that defines a flag. ``` go var ip = flag.IntP("flagname", "f", 1234, "help message") var flagvar bool func init() { flag.BoolVarP(&flagvar, "boolname", "b", true, "help message") } flag.VarP(&flagVal, "varname", "v", "help message") ``` Shorthand letters can be used with single dashes on the command line. Boolean shorthand flags can be combined with other shorthand flags. The default set of command-line flags is controlled by top-level functions. The FlagSet type allows one to define independent sets of flags, such as to implement subcommands in a command-line interface. The methods of FlagSet are analogous to the top-level functions for the command-line flag set. ## Setting no option default values for flags After you create a flag it is possible to set the pflag.NoOptDefVal for the given flag. Doing this changes the meaning of the flag slightly. If a flag has a NoOptDefVal and the flag is set on the command line without an option the flag will be set to the NoOptDefVal. For example given: ``` go var ip = flag.IntP("flagname", "f", 1234, "help message") flag.Lookup("flagname").NoOptDefVal = "4321" ``` Would result in something like | Parsed Arguments | Resulting Value | | ------------- | ------------- | | --flagname=1357 | ip=1357 | | --flagname | ip=4321 | | [nothing] | ip=1234 | ## Command line flag syntax ``` --flag // boolean flags, or flags with no option default values --flag x // only on flags without a default value --flag=x ``` Unlike the flag package, a single dash before an option means something different than a double dash. Single dashes signify a series of shorthand letters for flags. All but the last shorthand letter must be boolean flags or a flag with a default value ``` // boolean or flags where the 'no option default value' is set -f -f=true -abc but -b true is INVALID // non-boolean and flags without a 'no option default value' -n 1234 -n=1234 -n1234 // mixed -abcs "hello" -absd="hello" -abcs1234 ``` Flag parsing stops after the terminator "--". Unlike the flag package, flags can be interspersed with arguments anywhere on the command line before this terminator. Integer flags accept 1234, 0664, 0x1234 and may be negative. Boolean flags (in their long form) accept 1, 0, t, f, true, false, TRUE, FALSE, True, False. Duration flags accept any input valid for time.ParseDuration. ## Mutating or "Normalizing" Flag names It is possible to set a custom flag name 'normalization function.' It allows flag names to be mutated both when created in the code and when used on the command line to some 'normalized' form. The 'normalized' form is used for comparison. Two examples of using the custom normalization func follow. **Example #1**: You want -, _, and . in flags to compare the same. aka --my-flag == --my_flag == --my.flag ``` go func wordSepNormalizeFunc(f *pflag.FlagSet, name string) pflag.NormalizedName { from := []string{"-", "_"} to := "." for _, sep := range from { name = strings.Replace(name, sep, to, -1) } return pflag.NormalizedName(name) } myFlagSet.SetNormalizeFunc(wordSepNormalizeFunc) ``` **Example #2**: You want to alias two flags. aka --old-flag-name == --new-flag-name ``` go func aliasNormalizeFunc(f *pflag.FlagSet, name string) pflag.NormalizedName { switch name { case "old-flag-name": name = "new-flag-name" break } return pflag.NormalizedName(name) } myFlagSet.SetNormalizeFunc(aliasNormalizeFunc) ``` ## Deprecating a flag or its shorthand It is possible to deprecate a flag, or just its shorthand. Deprecating a flag/shorthand hides it from help text and prints a usage message when the deprecated flag/shorthand is used. **Example #1**: You want to deprecate a flag named "badflag" as well as inform the users what flag they should use instead. ```go // deprecate a flag by specifying its name and a usage message flags.MarkDeprecated("badflag", "please use --good-flag instead") ``` This hides "badflag" from help text, and prints `Flag --badflag has been deprecated, please use --good-flag instead` when "badflag" is used. **Example #2**: You want to keep a flag name "noshorthandflag" but deprecate its shortname "n". ```go // deprecate a flag shorthand by specifying its flag name and a usage message flags.MarkShorthandDeprecated("noshorthandflag", "please use --noshorthandflag only") ``` This hides the shortname "n" from help text, and prints `Flag shorthand -n has been deprecated, please use --noshorthandflag only` when the shorthand "n" is used. Note that usage message is essential here, and it should not be empty. ## Hidden flags It is possible to mark a flag as hidden, meaning it will still function as normal, however will not show up in usage/help text. **Example**: You have a flag named "secretFlag" that you need for internal use only and don't want it showing up in help text, or for its usage text to be available. ```go // hide a flag by specifying its name flags.MarkHidden("secretFlag") ``` ## Disable sorting of flags `pflag` allows you to disable sorting of flags for help and usage message. **Example**: ```go flags.BoolP("verbose", "v", false, "verbose output") flags.String("coolflag", "yeaah", "it's really cool flag") flags.Int("usefulflag", 777, "sometimes it's very useful") flags.SortFlags = false flags.PrintDefaults() ``` **Output**: ``` -v, --verbose verbose output --coolflag string it's really cool flag (default "yeaah") --usefulflag int sometimes it's very useful (default 777) ``` ## Supporting Go flags when using pflag In order to support flags defined using Go's `flag` package, they must be added to the `pflag` flagset. This is usually necessary to support flags defined by third-party dependencies (e.g. `golang/glog`). **Example**: You want to add the Go flags to the `CommandLine` flagset ```go import ( goflag "flag" flag "github.com/spf13/pflag" ) var ip *int = flag.Int("flagname", 1234, "help message for flagname") func main() { flag.CommandLine.AddGoFlagSet(goflag.CommandLine) flag.Parse() } ``` ## More info You can see the full reference documentation of the pflag package [at godoc.org][3], or through go's standard documentation system by running `godoc -http=:6060` and browsing to [http://localhost:6060/pkg/github.com/spf13/pflag][2] after installation. [2]: http://localhost:6060/pkg/github.com/spf13/pflag [3]: http://godoc.org/github.com/spf13/pflag ================================================ FILE: vendor/github.com/spf13/pflag/bool.go ================================================ package pflag import "strconv" // optional interface to indicate boolean flags that can be // supplied without "=value" text type boolFlag interface { Value IsBoolFlag() bool } // -- bool Value type boolValue bool func newBoolValue(val bool, p *bool) *boolValue { *p = val return (*boolValue)(p) } func (b *boolValue) Set(s string) error { v, err := strconv.ParseBool(s) *b = boolValue(v) return err } func (b *boolValue) Type() string { return "bool" } func (b *boolValue) String() string { return strconv.FormatBool(bool(*b)) } func (b *boolValue) IsBoolFlag() bool { return true } func boolConv(sval string) (interface{}, error) { return strconv.ParseBool(sval) } // GetBool return the bool value of a flag with the given name func (f *FlagSet) GetBool(name string) (bool, error) { val, err := f.getFlagType(name, "bool", boolConv) if err != nil { return false, err } return val.(bool), nil } // BoolVar defines a bool flag with specified name, default value, and usage string. // The argument p points to a bool variable in which to store the value of the flag. func (f *FlagSet) BoolVar(p *bool, name string, value bool, usage string) { f.BoolVarP(p, name, "", value, usage) } // BoolVarP is like BoolVar, but accepts a shorthand letter that can be used after a single dash. func (f *FlagSet) BoolVarP(p *bool, name, shorthand string, value bool, usage string) { flag := f.VarPF(newBoolValue(value, p), name, shorthand, usage) flag.NoOptDefVal = "true" } // BoolVar defines a bool flag with specified name, default value, and usage string. // The argument p points to a bool variable in which to store the value of the flag. func BoolVar(p *bool, name string, value bool, usage string) { BoolVarP(p, name, "", value, usage) } // BoolVarP is like BoolVar, but accepts a shorthand letter that can be used after a single dash. func BoolVarP(p *bool, name, shorthand string, value bool, usage string) { flag := CommandLine.VarPF(newBoolValue(value, p), name, shorthand, usage) flag.NoOptDefVal = "true" } // Bool defines a bool flag with specified name, default value, and usage string. // The return value is the address of a bool variable that stores the value of the flag. func (f *FlagSet) Bool(name string, value bool, usage string) *bool { return f.BoolP(name, "", value, usage) } // BoolP is like Bool, but accepts a shorthand letter that can be used after a single dash. func (f *FlagSet) BoolP(name, shorthand string, value bool, usage string) *bool { p := new(bool) f.BoolVarP(p, name, shorthand, value, usage) return p } // Bool defines a bool flag with specified name, default value, and usage string. // The return value is the address of a bool variable that stores the value of the flag. func Bool(name string, value bool, usage string) *bool { return BoolP(name, "", value, usage) } // BoolP is like Bool, but accepts a shorthand letter that can be used after a single dash. func BoolP(name, shorthand string, value bool, usage string) *bool { b := CommandLine.BoolP(name, shorthand, value, usage) return b } ================================================ FILE: vendor/github.com/spf13/pflag/bool_slice.go ================================================ package pflag import ( "io" "strconv" "strings" ) // -- boolSlice Value type boolSliceValue struct { value *[]bool changed bool } func newBoolSliceValue(val []bool, p *[]bool) *boolSliceValue { bsv := new(boolSliceValue) bsv.value = p *bsv.value = val return bsv } // Set converts, and assigns, the comma-separated boolean argument string representation as the []bool value of this flag. // If Set is called on a flag that already has a []bool assigned, the newly converted values will be appended. func (s *boolSliceValue) Set(val string) error { // remove all quote characters rmQuote := strings.NewReplacer(`"`, "", `'`, "", "`", "") // read flag arguments with CSV parser boolStrSlice, err := readAsCSV(rmQuote.Replace(val)) if err != nil && err != io.EOF { return err } // parse boolean values into slice out := make([]bool, 0, len(boolStrSlice)) for _, boolStr := range boolStrSlice { b, err := strconv.ParseBool(strings.TrimSpace(boolStr)) if err != nil { return err } out = append(out, b) } if !s.changed { *s.value = out } else { *s.value = append(*s.value, out...) } s.changed = true return nil } // Type returns a string that uniquely represents this flag's type. func (s *boolSliceValue) Type() string { return "boolSlice" } // String defines a "native" format for this boolean slice flag value. func (s *boolSliceValue) String() string { boolStrSlice := make([]string, len(*s.value)) for i, b := range *s.value { boolStrSlice[i] = strconv.FormatBool(b) } out, _ := writeAsCSV(boolStrSlice) return "[" + out + "]" } func boolSliceConv(val string) (interface{}, error) { val = strings.Trim(val, "[]") // Empty string would cause a slice with one (empty) entry if len(val) == 0 { return []bool{}, nil } ss := strings.Split(val, ",") out := make([]bool, len(ss)) for i, t := range ss { var err error out[i], err = strconv.ParseBool(t) if err != nil { return nil, err } } return out, nil } // GetBoolSlice returns the []bool value of a flag with the given name. func (f *FlagSet) GetBoolSlice(name string) ([]bool, error) { val, err := f.getFlagType(name, "boolSlice", boolSliceConv) if err != nil { return []bool{}, err } return val.([]bool), nil } // BoolSliceVar defines a boolSlice flag with specified name, default value, and usage string. // The argument p points to a []bool variable in which to store the value of the flag. func (f *FlagSet) BoolSliceVar(p *[]bool, name string, value []bool, usage string) { f.VarP(newBoolSliceValue(value, p), name, "", usage) } // BoolSliceVarP is like BoolSliceVar, but accepts a shorthand letter that can be used after a single dash. func (f *FlagSet) BoolSliceVarP(p *[]bool, name, shorthand string, value []bool, usage string) { f.VarP(newBoolSliceValue(value, p), name, shorthand, usage) } // BoolSliceVar defines a []bool flag with specified name, default value, and usage string. // The argument p points to a []bool variable in which to store the value of the flag. func BoolSliceVar(p *[]bool, name string, value []bool, usage string) { CommandLine.VarP(newBoolSliceValue(value, p), name, "", usage) } // BoolSliceVarP is like BoolSliceVar, but accepts a shorthand letter that can be used after a single dash. func BoolSliceVarP(p *[]bool, name, shorthand string, value []bool, usage string) { CommandLine.VarP(newBoolSliceValue(value, p), name, shorthand, usage) } // BoolSlice defines a []bool flag with specified name, default value, and usage string. // The return value is the address of a []bool variable that stores the value of the flag. func (f *FlagSet) BoolSlice(name string, value []bool, usage string) *[]bool { p := []bool{} f.BoolSliceVarP(&p, name, "", value, usage) return &p } // BoolSliceP is like BoolSlice, but accepts a shorthand letter that can be used after a single dash. func (f *FlagSet) BoolSliceP(name, shorthand string, value []bool, usage string) *[]bool { p := []bool{} f.BoolSliceVarP(&p, name, shorthand, value, usage) return &p } // BoolSlice defines a []bool flag with specified name, default value, and usage string. // The return value is the address of a []bool variable that stores the value of the flag. func BoolSlice(name string, value []bool, usage string) *[]bool { return CommandLine.BoolSliceP(name, "", value, usage) } // BoolSliceP is like BoolSlice, but accepts a shorthand letter that can be used after a single dash. func BoolSliceP(name, shorthand string, value []bool, usage string) *[]bool { return CommandLine.BoolSliceP(name, shorthand, value, usage) } ================================================ FILE: vendor/github.com/spf13/pflag/bool_slice_test.go ================================================ package pflag import ( "fmt" "strconv" "strings" "testing" ) func setUpBSFlagSet(bsp *[]bool) *FlagSet { f := NewFlagSet("test", ContinueOnError) f.BoolSliceVar(bsp, "bs", []bool{}, "Command separated list!") return f } func setUpBSFlagSetWithDefault(bsp *[]bool) *FlagSet { f := NewFlagSet("test", ContinueOnError) f.BoolSliceVar(bsp, "bs", []bool{false, true}, "Command separated list!") return f } func TestEmptyBS(t *testing.T) { var bs []bool f := setUpBSFlagSet(&bs) err := f.Parse([]string{}) if err != nil { t.Fatal("expected no error; got", err) } getBS, err := f.GetBoolSlice("bs") if err != nil { t.Fatal("got an error from GetBoolSlice():", err) } if len(getBS) != 0 { t.Fatalf("got bs %v with len=%d but expected length=0", getBS, len(getBS)) } } func TestBS(t *testing.T) { var bs []bool f := setUpBSFlagSet(&bs) vals := []string{"1", "F", "TRUE", "0"} arg := fmt.Sprintf("--bs=%s", strings.Join(vals, ",")) err := f.Parse([]string{arg}) if err != nil { t.Fatal("expected no error; got", err) } for i, v := range bs { b, err := strconv.ParseBool(vals[i]) if err != nil { t.Fatalf("got error: %v", err) } if b != v { t.Fatalf("expected is[%d] to be %s but got: %t", i, vals[i], v) } } getBS, err := f.GetBoolSlice("bs") if err != nil { t.Fatalf("got error: %v", err) } for i, v := range getBS { b, err := strconv.ParseBool(vals[i]) if err != nil { t.Fatalf("got error: %v", err) } if b != v { t.Fatalf("expected bs[%d] to be %s but got: %t from GetBoolSlice", i, vals[i], v) } } } func TestBSDefault(t *testing.T) { var bs []bool f := setUpBSFlagSetWithDefault(&bs) vals := []string{"false", "T"} err := f.Parse([]string{}) if err != nil { t.Fatal("expected no error; got", err) } for i, v := range bs { b, err := strconv.ParseBool(vals[i]) if err != nil { t.Fatalf("got error: %v", err) } if b != v { t.Fatalf("expected bs[%d] to be %t from GetBoolSlice but got: %t", i, b, v) } } getBS, err := f.GetBoolSlice("bs") if err != nil { t.Fatal("got an error from GetBoolSlice():", err) } for i, v := range getBS { b, err := strconv.ParseBool(vals[i]) if err != nil { t.Fatal("got an error from GetBoolSlice():", err) } if b != v { t.Fatalf("expected bs[%d] to be %t from GetBoolSlice but got: %t", i, b, v) } } } func TestBSWithDefault(t *testing.T) { var bs []bool f := setUpBSFlagSetWithDefault(&bs) vals := []string{"FALSE", "1"} arg := fmt.Sprintf("--bs=%s", strings.Join(vals, ",")) err := f.Parse([]string{arg}) if err != nil { t.Fatal("expected no error; got", err) } for i, v := range bs { b, err := strconv.ParseBool(vals[i]) if err != nil { t.Fatalf("got error: %v", err) } if b != v { t.Fatalf("expected bs[%d] to be %t but got: %t", i, b, v) } } getBS, err := f.GetBoolSlice("bs") if err != nil { t.Fatal("got an error from GetBoolSlice():", err) } for i, v := range getBS { b, err := strconv.ParseBool(vals[i]) if err != nil { t.Fatalf("got error: %v", err) } if b != v { t.Fatalf("expected bs[%d] to be %t from GetBoolSlice but got: %t", i, b, v) } } } func TestBSCalledTwice(t *testing.T) { var bs []bool f := setUpBSFlagSet(&bs) in := []string{"T,F", "T"} expected := []bool{true, false, true} argfmt := "--bs=%s" arg1 := fmt.Sprintf(argfmt, in[0]) arg2 := fmt.Sprintf(argfmt, in[1]) err := f.Parse([]string{arg1, arg2}) if err != nil { t.Fatal("expected no error; got", err) } for i, v := range bs { if expected[i] != v { t.Fatalf("expected bs[%d] to be %t but got %t", i, expected[i], v) } } } func TestBSBadQuoting(t *testing.T) { tests := []struct { Want []bool FlagArg []string }{ { Want: []bool{true, false, true}, FlagArg: []string{"1", "0", "true"}, }, { Want: []bool{true, false}, FlagArg: []string{"True", "F"}, }, { Want: []bool{true, false}, FlagArg: []string{"T", "0"}, }, { Want: []bool{true, false}, FlagArg: []string{"1", "0"}, }, { Want: []bool{true, false, false}, FlagArg: []string{"true,false", "false"}, }, { Want: []bool{true, false, false, true, false, true, false}, FlagArg: []string{`"true,false,false,1,0, T"`, " false "}, }, { Want: []bool{false, false, true, false, true, false, true}, FlagArg: []string{`"0, False, T,false , true,F"`, "true"}, }, } for i, test := range tests { var bs []bool f := setUpBSFlagSet(&bs) if err := f.Parse([]string{fmt.Sprintf("--bs=%s", strings.Join(test.FlagArg, ","))}); err != nil { t.Fatalf("flag parsing failed with error: %s\nparsing:\t%#v\nwant:\t\t%#v", err, test.FlagArg, test.Want[i]) } for j, b := range bs { if b != test.Want[j] { t.Fatalf("bad value parsed for test %d on bool %d:\nwant:\t%t\ngot:\t%t", i, j, test.Want[j], b) } } } } ================================================ FILE: vendor/github.com/spf13/pflag/bool_test.go ================================================ // Copyright 2009 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 file. package pflag import ( "bytes" "strconv" "testing" ) // This value can be a boolean ("true", "false") or "maybe" type triStateValue int const ( triStateFalse triStateValue = 0 triStateTrue triStateValue = 1 triStateMaybe triStateValue = 2 ) const strTriStateMaybe = "maybe" func (v *triStateValue) IsBoolFlag() bool { return true } func (v *triStateValue) Get() interface{} { return triStateValue(*v) } func (v *triStateValue) Set(s string) error { if s == strTriStateMaybe { *v = triStateMaybe return nil } boolVal, err := strconv.ParseBool(s) if boolVal { *v = triStateTrue } else { *v = triStateFalse } return err } func (v *triStateValue) String() string { if *v == triStateMaybe { return strTriStateMaybe } return strconv.FormatBool(*v == triStateTrue) } // The type of the flag as required by the pflag.Value interface func (v *triStateValue) Type() string { return "version" } func setUpFlagSet(tristate *triStateValue) *FlagSet { f := NewFlagSet("test", ContinueOnError) *tristate = triStateFalse flag := f.VarPF(tristate, "tristate", "t", "tristate value (true, maybe or false)") flag.NoOptDefVal = "true" return f } func TestExplicitTrue(t *testing.T) { var tristate triStateValue f := setUpFlagSet(&tristate) err := f.Parse([]string{"--tristate=true"}) if err != nil { t.Fatal("expected no error; got", err) } if tristate != triStateTrue { t.Fatal("expected", triStateTrue, "(triStateTrue) but got", tristate, "instead") } } func TestImplicitTrue(t *testing.T) { var tristate triStateValue f := setUpFlagSet(&tristate) err := f.Parse([]string{"--tristate"}) if err != nil { t.Fatal("expected no error; got", err) } if tristate != triStateTrue { t.Fatal("expected", triStateTrue, "(triStateTrue) but got", tristate, "instead") } } func TestShortFlag(t *testing.T) { var tristate triStateValue f := setUpFlagSet(&tristate) err := f.Parse([]string{"-t"}) if err != nil { t.Fatal("expected no error; got", err) } if tristate != triStateTrue { t.Fatal("expected", triStateTrue, "(triStateTrue) but got", tristate, "instead") } } func TestShortFlagExtraArgument(t *testing.T) { var tristate triStateValue f := setUpFlagSet(&tristate) // The"maybe"turns into an arg, since short boolean options will only do true/false err := f.Parse([]string{"-t", "maybe"}) if err != nil { t.Fatal("expected no error; got", err) } if tristate != triStateTrue { t.Fatal("expected", triStateTrue, "(triStateTrue) but got", tristate, "instead") } args := f.Args() if len(args) != 1 || args[0] != "maybe" { t.Fatal("expected an extra 'maybe' argument to stick around") } } func TestExplicitMaybe(t *testing.T) { var tristate triStateValue f := setUpFlagSet(&tristate) err := f.Parse([]string{"--tristate=maybe"}) if err != nil { t.Fatal("expected no error; got", err) } if tristate != triStateMaybe { t.Fatal("expected", triStateMaybe, "(triStateMaybe) but got", tristate, "instead") } } func TestExplicitFalse(t *testing.T) { var tristate triStateValue f := setUpFlagSet(&tristate) err := f.Parse([]string{"--tristate=false"}) if err != nil { t.Fatal("expected no error; got", err) } if tristate != triStateFalse { t.Fatal("expected", triStateFalse, "(triStateFalse) but got", tristate, "instead") } } func TestImplicitFalse(t *testing.T) { var tristate triStateValue f := setUpFlagSet(&tristate) err := f.Parse([]string{}) if err != nil { t.Fatal("expected no error; got", err) } if tristate != triStateFalse { t.Fatal("expected", triStateFalse, "(triStateFalse) but got", tristate, "instead") } } func TestInvalidValue(t *testing.T) { var tristate triStateValue f := setUpFlagSet(&tristate) var buf bytes.Buffer f.SetOutput(&buf) err := f.Parse([]string{"--tristate=invalid"}) if err == nil { t.Fatal("expected an error but did not get any, tristate has value", tristate) } } func TestBoolP(t *testing.T) { b := BoolP("bool", "b", false, "bool value in CommandLine") c := BoolP("c", "c", false, "other bool value") args := []string{"--bool"} if err := CommandLine.Parse(args); err != nil { t.Error("expected no error, got ", err) } if *b != true { t.Errorf("expected b=true got b=%v", *b) } if *c != false { t.Errorf("expect c=false got c=%v", *c) } } ================================================ FILE: vendor/github.com/spf13/pflag/count.go ================================================ package pflag import "strconv" // -- count Value type countValue int func newCountValue(val int, p *int) *countValue { *p = val return (*countValue)(p) } func (i *countValue) Set(s string) error { v, err := strconv.ParseInt(s, 0, 64) // -1 means that no specific value was passed, so increment if v == -1 { *i = countValue(*i + 1) } else { *i = countValue(v) } return err } func (i *countValue) Type() string { return "count" } func (i *countValue) String() string { return strconv.Itoa(int(*i)) } func countConv(sval string) (interface{}, error) { i, err := strconv.Atoi(sval) if err != nil { return nil, err } return i, nil } // GetCount return the int value of a flag with the given name func (f *FlagSet) GetCount(name string) (int, error) { val, err := f.getFlagType(name, "count", countConv) if err != nil { return 0, err } return val.(int), nil } // CountVar defines a count flag with specified name, default value, and usage string. // The argument p points to an int variable in which to store the value of the flag. // A count flag will add 1 to its value evey time it is found on the command line func (f *FlagSet) CountVar(p *int, name string, usage string) { f.CountVarP(p, name, "", usage) } // CountVarP is like CountVar only take a shorthand for the flag name. func (f *FlagSet) CountVarP(p *int, name, shorthand string, usage string) { flag := f.VarPF(newCountValue(0, p), name, shorthand, usage) flag.NoOptDefVal = "-1" } // CountVar like CountVar only the flag is placed on the CommandLine instead of a given flag set func CountVar(p *int, name string, usage string) { CommandLine.CountVar(p, name, usage) } // CountVarP is like CountVar only take a shorthand for the flag name. func CountVarP(p *int, name, shorthand string, usage string) { CommandLine.CountVarP(p, name, shorthand, usage) } // Count defines a count flag with specified name, default value, and usage string. // The return value is the address of an int variable that stores the value of the flag. // A count flag will add 1 to its value evey time it is found on the command line func (f *FlagSet) Count(name string, usage string) *int { p := new(int) f.CountVarP(p, name, "", usage) return p } // CountP is like Count only takes a shorthand for the flag name. func (f *FlagSet) CountP(name, shorthand string, usage string) *int { p := new(int) f.CountVarP(p, name, shorthand, usage) return p } // Count defines a count flag with specified name, default value, and usage string. // The return value is the address of an int variable that stores the value of the flag. // A count flag will add 1 to its value evey time it is found on the command line func Count(name string, usage string) *int { return CommandLine.CountP(name, "", usage) } // CountP is like Count only takes a shorthand for the flag name. func CountP(name, shorthand string, usage string) *int { return CommandLine.CountP(name, shorthand, usage) } ================================================ FILE: vendor/github.com/spf13/pflag/count_test.go ================================================ package pflag import ( "os" "testing" ) func setUpCount(c *int) *FlagSet { f := NewFlagSet("test", ContinueOnError) f.CountVarP(c, "verbose", "v", "a counter") return f } func TestCount(t *testing.T) { testCases := []struct { input []string success bool expected int }{ {[]string{"-vvv"}, true, 3}, {[]string{"-v", "-v", "-v"}, true, 3}, {[]string{"-v", "--verbose", "-v"}, true, 3}, {[]string{"-v=3", "-v"}, true, 4}, {[]string{"-v=a"}, false, 0}, } devnull, _ := os.Open(os.DevNull) os.Stderr = devnull for i := range testCases { var count int f := setUpCount(&count) tc := &testCases[i] err := f.Parse(tc.input) if err != nil && tc.success == true { t.Errorf("expected success, got %q", err) continue } else if err == nil && tc.success == false { t.Errorf("expected failure, got success") continue } else if tc.success { c, err := f.GetCount("verbose") if err != nil { t.Errorf("Got error trying to fetch the counter flag") } if c != tc.expected { t.Errorf("expected %q, got %q", tc.expected, c) } } } } ================================================ FILE: vendor/github.com/spf13/pflag/duration.go ================================================ package pflag import ( "time" ) // -- time.Duration Value type durationValue time.Duration func newDurationValue(val time.Duration, p *time.Duration) *durationValue { *p = val return (*durationValue)(p) } func (d *durationValue) Set(s string) error { v, err := time.ParseDuration(s) *d = durationValue(v) return err } func (d *durationValue) Type() string { return "duration" } func (d *durationValue) String() string { return (*time.Duration)(d).String() } func durationConv(sval string) (interface{}, error) { return time.ParseDuration(sval) } // GetDuration return the duration value of a flag with the given name func (f *FlagSet) GetDuration(name string) (time.Duration, error) { val, err := f.getFlagType(name, "duration", durationConv) if err != nil { return 0, err } return val.(time.Duration), nil } // DurationVar defines a time.Duration flag with specified name, default value, and usage string. // The argument p points to a time.Duration variable in which to store the value of the flag. func (f *FlagSet) DurationVar(p *time.Duration, name string, value time.Duration, usage string) { f.VarP(newDurationValue(value, p), name, "", usage) } // DurationVarP is like DurationVar, but accepts a shorthand letter that can be used after a single dash. func (f *FlagSet) DurationVarP(p *time.Duration, name, shorthand string, value time.Duration, usage string) { f.VarP(newDurationValue(value, p), name, shorthand, usage) } // DurationVar defines a time.Duration flag with specified name, default value, and usage string. // The argument p points to a time.Duration variable in which to store the value of the flag. func DurationVar(p *time.Duration, name string, value time.Duration, usage string) { CommandLine.VarP(newDurationValue(value, p), name, "", usage) } // DurationVarP is like DurationVar, but accepts a shorthand letter that can be used after a single dash. func DurationVarP(p *time.Duration, name, shorthand string, value time.Duration, usage string) { CommandLine.VarP(newDurationValue(value, p), name, shorthand, usage) } // Duration defines a time.Duration flag with specified name, default value, and usage string. // The return value is the address of a time.Duration variable that stores the value of the flag. func (f *FlagSet) Duration(name string, value time.Duration, usage string) *time.Duration { p := new(time.Duration) f.DurationVarP(p, name, "", value, usage) return p } // DurationP is like Duration, but accepts a shorthand letter that can be used after a single dash. func (f *FlagSet) DurationP(name, shorthand string, value time.Duration, usage string) *time.Duration { p := new(time.Duration) f.DurationVarP(p, name, shorthand, value, usage) return p } // Duration defines a time.Duration flag with specified name, default value, and usage string. // The return value is the address of a time.Duration variable that stores the value of the flag. func Duration(name string, value time.Duration, usage string) *time.Duration { return CommandLine.DurationP(name, "", value, usage) } // DurationP is like Duration, but accepts a shorthand letter that can be used after a single dash. func DurationP(name, shorthand string, value time.Duration, usage string) *time.Duration { return CommandLine.DurationP(name, shorthand, value, usage) } ================================================ FILE: vendor/github.com/spf13/pflag/example_test.go ================================================ // Copyright 2012 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 file. package pflag_test import ( "fmt" "github.com/spf13/pflag" ) func ExampleShorthandLookup() { name := "verbose" short := name[:1] pflag.BoolP(name, short, false, "verbose output") // len(short) must be == 1 flag := pflag.ShorthandLookup(short) fmt.Println(flag.Name) } func ExampleFlagSet_ShorthandLookup() { name := "verbose" short := name[:1] fs := pflag.NewFlagSet("Example", pflag.ContinueOnError) fs.BoolP(name, short, false, "verbose output") // len(short) must be == 1 flag := fs.ShorthandLookup(short) fmt.Println(flag.Name) } ================================================ FILE: vendor/github.com/spf13/pflag/export_test.go ================================================ // Copyright 2010 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 file. package pflag import ( "io/ioutil" "os" ) // Additional routines compiled into the package only during testing. // ResetForTesting clears all flag state and sets the usage function as directed. // After calling ResetForTesting, parse errors in flag handling will not // exit the program. func ResetForTesting(usage func()) { CommandLine = &FlagSet{ name: os.Args[0], errorHandling: ContinueOnError, output: ioutil.Discard, } Usage = usage } // GetCommandLine returns the default FlagSet. func GetCommandLine() *FlagSet { return CommandLine } ================================================ FILE: vendor/github.com/spf13/pflag/flag.go ================================================ // Copyright 2009 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 file. /* Package pflag is a drop-in replacement for Go's flag package, implementing POSIX/GNU-style --flags. pflag is compatible with the GNU extensions to the POSIX recommendations for command-line options. See http://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html Usage: pflag is a drop-in replacement of Go's native flag package. If you import pflag under the name "flag" then all code should continue to function with no changes. import flag "github.com/spf13/pflag" There is one exception to this: if you directly instantiate the Flag struct there is one more field "Shorthand" that you will need to set. Most code never instantiates this struct directly, and instead uses functions such as String(), BoolVar(), and Var(), and is therefore unaffected. Define flags using flag.String(), Bool(), Int(), etc. This declares an integer flag, -flagname, stored in the pointer ip, with type *int. var ip = flag.Int("flagname", 1234, "help message for flagname") If you like, you can bind the flag to a variable using the Var() functions. var flagvar int func init() { flag.IntVar(&flagvar, "flagname", 1234, "help message for flagname") } Or you can create custom flags that satisfy the Value interface (with pointer receivers) and couple them to flag parsing by flag.Var(&flagVal, "name", "help message for flagname") For such flags, the default value is just the initial value of the variable. After all flags are defined, call flag.Parse() to parse the command line into the defined flags. Flags may then be used directly. If you're using the flags themselves, they are all pointers; if you bind to variables, they're values. fmt.Println("ip has value ", *ip) fmt.Println("flagvar has value ", flagvar) After parsing, the arguments after the flag are available as the slice flag.Args() or individually as flag.Arg(i). The arguments are indexed from 0 through flag.NArg()-1. The pflag package also defines some new functions that are not in flag, that give one-letter shorthands for flags. You can use these by appending 'P' to the name of any function that defines a flag. var ip = flag.IntP("flagname", "f", 1234, "help message") var flagvar bool func init() { flag.BoolVarP("boolname", "b", true, "help message") } flag.VarP(&flagVar, "varname", "v", 1234, "help message") Shorthand letters can be used with single dashes on the command line. Boolean shorthand flags can be combined with other shorthand flags. Command line flag syntax: --flag // boolean flags only --flag=x Unlike the flag package, a single dash before an option means something different than a double dash. Single dashes signify a series of shorthand letters for flags. All but the last shorthand letter must be boolean flags. // boolean flags -f -abc // non-boolean flags -n 1234 -Ifile // mixed -abcs "hello" -abcn1234 Flag parsing stops after the terminator "--". Unlike the flag package, flags can be interspersed with arguments anywhere on the command line before this terminator. Integer flags accept 1234, 0664, 0x1234 and may be negative. Boolean flags (in their long form) accept 1, 0, t, f, true, false, TRUE, FALSE, True, False. Duration flags accept any input valid for time.ParseDuration. The default set of command-line flags is controlled by top-level functions. The FlagSet type allows one to define independent sets of flags, such as to implement subcommands in a command-line interface. The methods of FlagSet are analogous to the top-level functions for the command-line flag set. */ package pflag import ( "bytes" "errors" "fmt" "io" "os" "sort" "strings" ) // ErrHelp is the error returned if the flag -help is invoked but no such flag is defined. var ErrHelp = errors.New("pflag: help requested") // ErrorHandling defines how to handle flag parsing errors. type ErrorHandling int const ( // ContinueOnError will return an err from Parse() if an error is found ContinueOnError ErrorHandling = iota // ExitOnError will call os.Exit(2) if an error is found when parsing ExitOnError // PanicOnError will panic() if an error is found when parsing flags PanicOnError ) // NormalizedName is a flag name that has been normalized according to rules // for the FlagSet (e.g. making '-' and '_' equivalent). type NormalizedName string // A FlagSet represents a set of defined flags. type FlagSet struct { // Usage is the function called when an error occurs while parsing flags. // The field is a function (not a method) that may be changed to point to // a custom error handler. Usage func() // SortFlags is used to indicate, if user wants to have sorted flags in // help/usage messages. SortFlags bool name string parsed bool actual map[NormalizedName]*Flag orderedActual []*Flag sortedActual []*Flag formal map[NormalizedName]*Flag orderedFormal []*Flag sortedFormal []*Flag shorthands map[byte]*Flag args []string // arguments after flags argsLenAtDash int // len(args) when a '--' was located when parsing, or -1 if no -- errorHandling ErrorHandling output io.Writer // nil means stderr; use out() accessor interspersed bool // allow interspersed option/non-option args normalizeNameFunc func(f *FlagSet, name string) NormalizedName } // A Flag represents the state of a flag. type Flag struct { Name string // name as it appears on command line Shorthand string // one-letter abbreviated flag Usage string // help message Value Value // value as set DefValue string // default value (as text); for usage message Changed bool // If the user set the value (or if left to default) NoOptDefVal string // default value (as text); if the flag is on the command line without any options Deprecated string // If this flag is deprecated, this string is the new or now thing to use Hidden bool // used by cobra.Command to allow flags to be hidden from help/usage text ShorthandDeprecated string // If the shorthand of this flag is deprecated, this string is the new or now thing to use Annotations map[string][]string // used by cobra.Command bash autocomple code } // Value is the interface to the dynamic value stored in a flag. // (The default value is represented as a string.) type Value interface { String() string Set(string) error Type() string } // sortFlags returns the flags as a slice in lexicographical sorted order. func sortFlags(flags map[NormalizedName]*Flag) []*Flag { list := make(sort.StringSlice, len(flags)) i := 0 for k := range flags { list[i] = string(k) i++ } list.Sort() result := make([]*Flag, len(list)) for i, name := range list { result[i] = flags[NormalizedName(name)] } return result } // SetNormalizeFunc allows you to add a function which can translate flag names. // Flags added to the FlagSet will be translated and then when anything tries to // look up the flag that will also be translated. So it would be possible to create // a flag named "getURL" and have it translated to "geturl". A user could then pass // "--getUrl" which may also be translated to "geturl" and everything will work. func (f *FlagSet) SetNormalizeFunc(n func(f *FlagSet, name string) NormalizedName) { f.normalizeNameFunc = n f.sortedFormal = f.sortedFormal[:0] for k, v := range f.orderedFormal { delete(f.formal, NormalizedName(v.Name)) nname := f.normalizeFlagName(v.Name) v.Name = string(nname) f.formal[nname] = v f.orderedFormal[k] = v } } // GetNormalizeFunc returns the previously set NormalizeFunc of a function which // does no translation, if not set previously. func (f *FlagSet) GetNormalizeFunc() func(f *FlagSet, name string) NormalizedName { if f.normalizeNameFunc != nil { return f.normalizeNameFunc } return func(f *FlagSet, name string) NormalizedName { return NormalizedName(name) } } func (f *FlagSet) normalizeFlagName(name string) NormalizedName { n := f.GetNormalizeFunc() return n(f, name) } func (f *FlagSet) out() io.Writer { if f.output == nil { return os.Stderr } return f.output } // SetOutput sets the destination for usage and error messages. // If output is nil, os.Stderr is used. func (f *FlagSet) SetOutput(output io.Writer) { f.output = output } // VisitAll visits the flags in lexicographical order or // in primordial order if f.SortFlags is false, calling fn for each. // It visits all flags, even those not set. func (f *FlagSet) VisitAll(fn func(*Flag)) { if len(f.formal) == 0 { return } var flags []*Flag if f.SortFlags { if len(f.formal) != len(f.sortedFormal) { f.sortedFormal = sortFlags(f.formal) } flags = f.sortedFormal } else { flags = f.orderedFormal } for _, flag := range flags { fn(flag) } } // HasFlags returns a bool to indicate if the FlagSet has any flags definied. func (f *FlagSet) HasFlags() bool { return len(f.formal) > 0 } // HasAvailableFlags returns a bool to indicate if the FlagSet has any flags // definied that are not hidden or deprecated. func (f *FlagSet) HasAvailableFlags() bool { for _, flag := range f.formal { if !flag.Hidden && len(flag.Deprecated) == 0 { return true } } return false } // VisitAll visits the command-line flags in lexicographical order or // in primordial order if f.SortFlags is false, calling fn for each. // It visits all flags, even those not set. func VisitAll(fn func(*Flag)) { CommandLine.VisitAll(fn) } // Visit visits the flags in lexicographical order or // in primordial order if f.SortFlags is false, calling fn for each. // It visits only those flags that have been set. func (f *FlagSet) Visit(fn func(*Flag)) { if len(f.actual) == 0 { return } var flags []*Flag if f.SortFlags { if len(f.actual) != len(f.sortedActual) { f.sortedActual = sortFlags(f.actual) } flags = f.sortedActual } else { flags = f.orderedActual } for _, flag := range flags { fn(flag) } } // Visit visits the command-line flags in lexicographical order or // in primordial order if f.SortFlags is false, calling fn for each. // It visits only those flags that have been set. func Visit(fn func(*Flag)) { CommandLine.Visit(fn) } // Lookup returns the Flag structure of the named flag, returning nil if none exists. func (f *FlagSet) Lookup(name string) *Flag { return f.lookup(f.normalizeFlagName(name)) } // ShorthandLookup returns the Flag structure of the short handed flag, // returning nil if none exists. // It panics, if len(name) > 1. func (f *FlagSet) ShorthandLookup(name string) *Flag { if name == "" { return nil } if len(name) > 1 { msg := fmt.Sprintf("can not look up shorthand which is more than one ASCII character: %q", name) fmt.Fprintf(f.out(), msg) panic(msg) } c := name[0] return f.shorthands[c] } // lookup returns the Flag structure of the named flag, returning nil if none exists. func (f *FlagSet) lookup(name NormalizedName) *Flag { return f.formal[name] } // func to return a given type for a given flag name func (f *FlagSet) getFlagType(name string, ftype string, convFunc func(sval string) (interface{}, error)) (interface{}, error) { flag := f.Lookup(name) if flag == nil { err := fmt.Errorf("flag accessed but not defined: %s", name) return nil, err } if flag.Value.Type() != ftype { err := fmt.Errorf("trying to get %s value of flag of type %s", ftype, flag.Value.Type()) return nil, err } sval := flag.Value.String() result, err := convFunc(sval) if err != nil { return nil, err } return result, nil } // ArgsLenAtDash will return the length of f.Args at the moment when a -- was // found during arg parsing. This allows your program to know which args were // before the -- and which came after. func (f *FlagSet) ArgsLenAtDash() int { return f.argsLenAtDash } // MarkDeprecated indicated that a flag is deprecated in your program. It will // continue to function but will not show up in help or usage messages. Using // this flag will also print the given usageMessage. func (f *FlagSet) MarkDeprecated(name string, usageMessage string) error { flag := f.Lookup(name) if flag == nil { return fmt.Errorf("flag %q does not exist", name) } if usageMessage == "" { return fmt.Errorf("deprecated message for flag %q must be set", name) } flag.Deprecated = usageMessage return nil } // MarkShorthandDeprecated will mark the shorthand of a flag deprecated in your // program. It will continue to function but will not show up in help or usage // messages. Using this flag will also print the given usageMessage. func (f *FlagSet) MarkShorthandDeprecated(name string, usageMessage string) error { flag := f.Lookup(name) if flag == nil { return fmt.Errorf("flag %q does not exist", name) } if usageMessage == "" { return fmt.Errorf("deprecated message for flag %q must be set", name) } flag.ShorthandDeprecated = usageMessage return nil } // MarkHidden sets a flag to 'hidden' in your program. It will continue to // function but will not show up in help or usage messages. func (f *FlagSet) MarkHidden(name string) error { flag := f.Lookup(name) if flag == nil { return fmt.Errorf("flag %q does not exist", name) } flag.Hidden = true return nil } // Lookup returns the Flag structure of the named command-line flag, // returning nil if none exists. func Lookup(name string) *Flag { return CommandLine.Lookup(name) } // ShorthandLookup returns the Flag structure of the short handed flag, // returning nil if none exists. func ShorthandLookup(name string) *Flag { return CommandLine.ShorthandLookup(name) } // Set sets the value of the named flag. func (f *FlagSet) Set(name, value string) error { normalName := f.normalizeFlagName(name) flag, ok := f.formal[normalName] if !ok { return fmt.Errorf("no such flag -%v", name) } err := flag.Value.Set(value) if err != nil { var flagName string if flag.Shorthand != "" && flag.ShorthandDeprecated == "" { flagName = fmt.Sprintf("-%s, --%s", flag.Shorthand, flag.Name) } else { flagName = fmt.Sprintf("--%s", flag.Name) } return fmt.Errorf("invalid argument %q for %q flag: %v", value, flagName, err) } if f.actual == nil { f.actual = make(map[NormalizedName]*Flag) } f.actual[normalName] = flag f.orderedActual = append(f.orderedActual, flag) flag.Changed = true if flag.Deprecated != "" { fmt.Fprintf(f.out(), "Flag --%s has been deprecated, %s\n", flag.Name, flag.Deprecated) } return nil } // SetAnnotation allows one to set arbitrary annotations on a flag in the FlagSet. // This is sometimes used by spf13/cobra programs which want to generate additional // bash completion information. func (f *FlagSet) SetAnnotation(name, key string, values []string) error { normalName := f.normalizeFlagName(name) flag, ok := f.formal[normalName] if !ok { return fmt.Errorf("no such flag -%v", name) } if flag.Annotations == nil { flag.Annotations = map[string][]string{} } flag.Annotations[key] = values return nil } // Changed returns true if the flag was explicitly set during Parse() and false // otherwise func (f *FlagSet) Changed(name string) bool { flag := f.Lookup(name) // If a flag doesn't exist, it wasn't changed.... if flag == nil { return false } return flag.Changed } // Set sets the value of the named command-line flag. func Set(name, value string) error { return CommandLine.Set(name, value) } // PrintDefaults prints, to standard error unless configured // otherwise, the default values of all defined flags in the set. func (f *FlagSet) PrintDefaults() { usages := f.FlagUsages() fmt.Fprint(f.out(), usages) } // defaultIsZeroValue returns true if the default value for this flag represents // a zero value. func (f *Flag) defaultIsZeroValue() bool { switch f.Value.(type) { case boolFlag: return f.DefValue == "false" case *durationValue: // Beginning in Go 1.7, duration zero values are "0s" return f.DefValue == "0" || f.DefValue == "0s" case *intValue, *int8Value, *int32Value, *int64Value, *uintValue, *uint8Value, *uint16Value, *uint32Value, *uint64Value, *countValue, *float32Value, *float64Value: return f.DefValue == "0" case *stringValue: return f.DefValue == "" case *ipValue, *ipMaskValue, *ipNetValue: return f.DefValue == "" case *intSliceValue, *stringSliceValue, *stringArrayValue: return f.DefValue == "[]" default: switch f.Value.String() { case "false": return true case "": return true case "": return true case "0": return true } return false } } // UnquoteUsage extracts a back-quoted name from the usage // string for a flag and returns it and the un-quoted usage. // Given "a `name` to show" it returns ("name", "a name to show"). // If there are no back quotes, the name is an educated guess of the // type of the flag's value, or the empty string if the flag is boolean. func UnquoteUsage(flag *Flag) (name string, usage string) { // Look for a back-quoted name, but avoid the strings package. usage = flag.Usage for i := 0; i < len(usage); i++ { if usage[i] == '`' { for j := i + 1; j < len(usage); j++ { if usage[j] == '`' { name = usage[i+1 : j] usage = usage[:i] + name + usage[j+1:] return name, usage } } break // Only one back quote; use type name. } } name = flag.Value.Type() switch name { case "bool": name = "" case "float64": name = "float" case "int64": name = "int" case "uint64": name = "uint" } return } // Splits the string `s` on whitespace into an initial substring up to // `i` runes in length and the remainder. Will go `slop` over `i` if // that encompasses the entire string (which allows the caller to // avoid short orphan words on the final line). func wrapN(i, slop int, s string) (string, string) { if i+slop > len(s) { return s, "" } w := strings.LastIndexAny(s[:i], " \t") if w <= 0 { return s, "" } return s[:w], s[w+1:] } // Wraps the string `s` to a maximum width `w` with leading indent // `i`. The first line is not indented (this is assumed to be done by // caller). Pass `w` == 0 to do no wrapping func wrap(i, w int, s string) string { if w == 0 { return s } // space between indent i and end of line width w into which // we should wrap the text. wrap := w - i var r, l string // Not enough space for sensible wrapping. Wrap as a block on // the next line instead. if wrap < 24 { i = 16 wrap = w - i r += "\n" + strings.Repeat(" ", i) } // If still not enough space then don't even try to wrap. if wrap < 24 { return s } // Try to avoid short orphan words on the final line, by // allowing wrapN to go a bit over if that would fit in the // remainder of the line. slop := 5 wrap = wrap - slop // Handle first line, which is indented by the caller (or the // special case above) l, s = wrapN(wrap, slop, s) r = r + l // Now wrap the rest for s != "" { var t string t, s = wrapN(wrap, slop, s) r = r + "\n" + strings.Repeat(" ", i) + t } return r } // FlagUsagesWrapped returns a string containing the usage information // for all flags in the FlagSet. Wrapped to `cols` columns (0 for no // wrapping) func (f *FlagSet) FlagUsagesWrapped(cols int) string { buf := new(bytes.Buffer) lines := make([]string, 0, len(f.formal)) maxlen := 0 f.VisitAll(func(flag *Flag) { if flag.Deprecated != "" || flag.Hidden { return } line := "" if flag.Shorthand != "" && flag.ShorthandDeprecated == "" { line = fmt.Sprintf(" -%s, --%s", flag.Shorthand, flag.Name) } else { line = fmt.Sprintf(" --%s", flag.Name) } varname, usage := UnquoteUsage(flag) if varname != "" { line += " " + varname } if flag.NoOptDefVal != "" { switch flag.Value.Type() { case "string": line += fmt.Sprintf("[=\"%s\"]", flag.NoOptDefVal) case "bool": if flag.NoOptDefVal != "true" { line += fmt.Sprintf("[=%s]", flag.NoOptDefVal) } default: line += fmt.Sprintf("[=%s]", flag.NoOptDefVal) } } // This special character will be replaced with spacing once the // correct alignment is calculated line += "\x00" if len(line) > maxlen { maxlen = len(line) } line += usage if !flag.defaultIsZeroValue() { if flag.Value.Type() == "string" { line += fmt.Sprintf(" (default %q)", flag.DefValue) } else { line += fmt.Sprintf(" (default %s)", flag.DefValue) } } lines = append(lines, line) }) for _, line := range lines { sidx := strings.Index(line, "\x00") spacing := strings.Repeat(" ", maxlen-sidx) // maxlen + 2 comes from + 1 for the \x00 and + 1 for the (deliberate) off-by-one in maxlen-sidx fmt.Fprintln(buf, line[:sidx], spacing, wrap(maxlen+2, cols, line[sidx+1:])) } return buf.String() } // FlagUsages returns a string containing the usage information for all flags in // the FlagSet func (f *FlagSet) FlagUsages() string { return f.FlagUsagesWrapped(0) } // PrintDefaults prints to standard error the default values of all defined command-line flags. func PrintDefaults() { CommandLine.PrintDefaults() } // defaultUsage is the default function to print a usage message. func defaultUsage(f *FlagSet) { fmt.Fprintf(f.out(), "Usage of %s:\n", f.name) f.PrintDefaults() } // NOTE: Usage is not just defaultUsage(CommandLine) // because it serves (via godoc flag Usage) as the example // for how to write your own usage function. // Usage prints to standard error a usage message documenting all defined command-line flags. // The function is a variable that may be changed to point to a custom function. // By default it prints a simple header and calls PrintDefaults; for details about the // format of the output and how to control it, see the documentation for PrintDefaults. var Usage = func() { fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0]) PrintDefaults() } // NFlag returns the number of flags that have been set. func (f *FlagSet) NFlag() int { return len(f.actual) } // NFlag returns the number of command-line flags that have been set. func NFlag() int { return len(CommandLine.actual) } // Arg returns the i'th argument. Arg(0) is the first remaining argument // after flags have been processed. func (f *FlagSet) Arg(i int) string { if i < 0 || i >= len(f.args) { return "" } return f.args[i] } // Arg returns the i'th command-line argument. Arg(0) is the first remaining argument // after flags have been processed. func Arg(i int) string { return CommandLine.Arg(i) } // NArg is the number of arguments remaining after flags have been processed. func (f *FlagSet) NArg() int { return len(f.args) } // NArg is the number of arguments remaining after flags have been processed. func NArg() int { return len(CommandLine.args) } // Args returns the non-flag arguments. func (f *FlagSet) Args() []string { return f.args } // Args returns the non-flag command-line arguments. func Args() []string { return CommandLine.args } // Var defines a flag with the specified name and usage string. The type and // value of the flag are represented by the first argument, of type Value, which // typically holds a user-defined implementation of Value. For instance, the // caller could create a flag that turns a comma-separated string into a slice // of strings by giving the slice the methods of Value; in particular, Set would // decompose the comma-separated string into the slice. func (f *FlagSet) Var(value Value, name string, usage string) { f.VarP(value, name, "", usage) } // VarPF is like VarP, but returns the flag created func (f *FlagSet) VarPF(value Value, name, shorthand, usage string) *Flag { // Remember the default value as a string; it won't change. flag := &Flag{ Name: name, Shorthand: shorthand, Usage: usage, Value: value, DefValue: value.String(), } f.AddFlag(flag) return flag } // VarP is like Var, but accepts a shorthand letter that can be used after a single dash. func (f *FlagSet) VarP(value Value, name, shorthand, usage string) { f.VarPF(value, name, shorthand, usage) } // AddFlag will add the flag to the FlagSet func (f *FlagSet) AddFlag(flag *Flag) { normalizedFlagName := f.normalizeFlagName(flag.Name) _, alreadyThere := f.formal[normalizedFlagName] if alreadyThere { msg := fmt.Sprintf("%s flag redefined: %s", f.name, flag.Name) fmt.Fprintln(f.out(), msg) panic(msg) // Happens only if flags are declared with identical names } if f.formal == nil { f.formal = make(map[NormalizedName]*Flag) } flag.Name = string(normalizedFlagName) f.formal[normalizedFlagName] = flag f.orderedFormal = append(f.orderedFormal, flag) if flag.Shorthand == "" { return } if len(flag.Shorthand) > 1 { msg := fmt.Sprintf("%q shorthand is more than one ASCII character", flag.Shorthand) fmt.Fprintf(f.out(), msg) panic(msg) } if f.shorthands == nil { f.shorthands = make(map[byte]*Flag) } c := flag.Shorthand[0] used, alreadyThere := f.shorthands[c] if alreadyThere { msg := fmt.Sprintf("unable to redefine %q shorthand in %q flagset: it's already used for %q flag", c, f.name, used.Name) fmt.Fprintf(f.out(), msg) panic(msg) } f.shorthands[c] = flag } // AddFlagSet adds one FlagSet to another. If a flag is already present in f // the flag from newSet will be ignored. func (f *FlagSet) AddFlagSet(newSet *FlagSet) { if newSet == nil { return } newSet.VisitAll(func(flag *Flag) { if f.Lookup(flag.Name) == nil { f.AddFlag(flag) } }) } // Var defines a flag with the specified name and usage string. The type and // value of the flag are represented by the first argument, of type Value, which // typically holds a user-defined implementation of Value. For instance, the // caller could create a flag that turns a comma-separated string into a slice // of strings by giving the slice the methods of Value; in particular, Set would // decompose the comma-separated string into the slice. func Var(value Value, name string, usage string) { CommandLine.VarP(value, name, "", usage) } // VarP is like Var, but accepts a shorthand letter that can be used after a single dash. func VarP(value Value, name, shorthand, usage string) { CommandLine.VarP(value, name, shorthand, usage) } // failf prints to standard error a formatted error and usage message and // returns the error. func (f *FlagSet) failf(format string, a ...interface{}) error { err := fmt.Errorf(format, a...) fmt.Fprintln(f.out(), err) f.usage() return err } // usage calls the Usage method for the flag set, or the usage function if // the flag set is CommandLine. func (f *FlagSet) usage() { if f == CommandLine { Usage() } else if f.Usage == nil { defaultUsage(f) } else { f.Usage() } } func (f *FlagSet) parseLongArg(s string, args []string, fn parseFunc) (a []string, err error) { a = args name := s[2:] if len(name) == 0 || name[0] == '-' || name[0] == '=' { err = f.failf("bad flag syntax: %s", s) return } split := strings.SplitN(name, "=", 2) name = split[0] flag, exists := f.formal[f.normalizeFlagName(name)] if !exists { if name == "help" { // special case for nice help message. f.usage() return a, ErrHelp } err = f.failf("unknown flag: --%s", name) return } var value string if len(split) == 2 { // '--flag=arg' value = split[1] } else if flag.NoOptDefVal != "" { // '--flag' (arg was optional) value = flag.NoOptDefVal } else if len(a) > 0 { // '--flag arg' value = a[0] a = a[1:] } else { // '--flag' (arg was required) err = f.failf("flag needs an argument: %s", s) return } err = fn(flag, value) return } func (f *FlagSet) parseSingleShortArg(shorthands string, args []string, fn parseFunc) (outShorts string, outArgs []string, err error) { if strings.HasPrefix(shorthands, "test.") { return } outArgs = args outShorts = shorthands[1:] c := shorthands[0] flag, exists := f.shorthands[c] if !exists { if c == 'h' { // special case for nice help message. f.usage() err = ErrHelp return } err = f.failf("unknown shorthand flag: %q in -%s", c, shorthands) return } var value string if len(shorthands) > 2 && shorthands[1] == '=' { // '-f=arg' value = shorthands[2:] outShorts = "" } else if flag.NoOptDefVal != "" { // '-f' (arg was optional) value = flag.NoOptDefVal } else if len(shorthands) > 1 { // '-farg' value = shorthands[1:] outShorts = "" } else if len(args) > 0 { // '-f arg' value = args[0] outArgs = args[1:] } else { // '-f' (arg was required) err = f.failf("flag needs an argument: %q in -%s", c, shorthands) return } if flag.ShorthandDeprecated != "" { fmt.Fprintf(f.out(), "Flag shorthand -%s has been deprecated, %s\n", flag.Shorthand, flag.ShorthandDeprecated) } err = fn(flag, value) return } func (f *FlagSet) parseShortArg(s string, args []string, fn parseFunc) (a []string, err error) { a = args shorthands := s[1:] // "shorthands" can be a series of shorthand letters of flags (e.g. "-vvv"). for len(shorthands) > 0 { shorthands, a, err = f.parseSingleShortArg(shorthands, args, fn) if err != nil { return } } return } func (f *FlagSet) parseArgs(args []string, fn parseFunc) (err error) { for len(args) > 0 { s := args[0] args = args[1:] if len(s) == 0 || s[0] != '-' || len(s) == 1 { if !f.interspersed { f.args = append(f.args, s) f.args = append(f.args, args...) return nil } f.args = append(f.args, s) continue } if s[1] == '-' { if len(s) == 2 { // "--" terminates the flags f.argsLenAtDash = len(f.args) f.args = append(f.args, args...) break } args, err = f.parseLongArg(s, args, fn) } else { args, err = f.parseShortArg(s, args, fn) } if err != nil { return } } return } // Parse parses flag definitions from the argument list, which should not // include the command name. Must be called after all flags in the FlagSet // are defined and before flags are accessed by the program. // The return value will be ErrHelp if -help was set but not defined. func (f *FlagSet) Parse(arguments []string) error { f.parsed = true if len(arguments) < 0 { return nil } f.args = make([]string, 0, len(arguments)) set := func(flag *Flag, value string) error { return f.Set(flag.Name, value) } err := f.parseArgs(arguments, set) if err != nil { switch f.errorHandling { case ContinueOnError: return err case ExitOnError: os.Exit(2) case PanicOnError: panic(err) } } return nil } type parseFunc func(flag *Flag, value string) error // ParseAll parses flag definitions from the argument list, which should not // include the command name. The arguments for fn are flag and value. Must be // called after all flags in the FlagSet are defined and before flags are // accessed by the program. The return value will be ErrHelp if -help was set // but not defined. func (f *FlagSet) ParseAll(arguments []string, fn func(flag *Flag, value string) error) error { f.parsed = true f.args = make([]string, 0, len(arguments)) err := f.parseArgs(arguments, fn) if err != nil { switch f.errorHandling { case ContinueOnError: return err case ExitOnError: os.Exit(2) case PanicOnError: panic(err) } } return nil } // Parsed reports whether f.Parse has been called. func (f *FlagSet) Parsed() bool { return f.parsed } // Parse parses the command-line flags from os.Args[1:]. Must be called // after all flags are defined and before flags are accessed by the program. func Parse() { // Ignore errors; CommandLine is set for ExitOnError. CommandLine.Parse(os.Args[1:]) } // ParseAll parses the command-line flags from os.Args[1:] and called fn for each. // The arguments for fn are flag and value. Must be called after all flags are // defined and before flags are accessed by the program. func ParseAll(fn func(flag *Flag, value string) error) { // Ignore errors; CommandLine is set for ExitOnError. CommandLine.ParseAll(os.Args[1:], fn) } // SetInterspersed sets whether to support interspersed option/non-option arguments. func SetInterspersed(interspersed bool) { CommandLine.SetInterspersed(interspersed) } // Parsed returns true if the command-line flags have been parsed. func Parsed() bool { return CommandLine.Parsed() } // CommandLine is the default set of command-line flags, parsed from os.Args. var CommandLine = NewFlagSet(os.Args[0], ExitOnError) // NewFlagSet returns a new, empty flag set with the specified name, // error handling property and SortFlags set to true. func NewFlagSet(name string, errorHandling ErrorHandling) *FlagSet { f := &FlagSet{ name: name, errorHandling: errorHandling, argsLenAtDash: -1, interspersed: true, SortFlags: true, } return f } // SetInterspersed sets whether to support interspersed option/non-option arguments. func (f *FlagSet) SetInterspersed(interspersed bool) { f.interspersed = interspersed } // Init sets the name and error handling property for a flag set. // By default, the zero FlagSet uses an empty name and the // ContinueOnError error handling policy. func (f *FlagSet) Init(name string, errorHandling ErrorHandling) { f.name = name f.errorHandling = errorHandling f.argsLenAtDash = -1 } ================================================ FILE: vendor/github.com/spf13/pflag/flag_test.go ================================================ // Copyright 2009 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 file. package pflag import ( "bytes" "fmt" "io" "io/ioutil" "net" "os" "reflect" "sort" "strconv" "strings" "testing" "time" ) var ( testBool = Bool("test_bool", false, "bool value") testInt = Int("test_int", 0, "int value") testInt64 = Int64("test_int64", 0, "int64 value") testUint = Uint("test_uint", 0, "uint value") testUint64 = Uint64("test_uint64", 0, "uint64 value") testString = String("test_string", "0", "string value") testFloat = Float64("test_float64", 0, "float64 value") testDuration = Duration("test_duration", 0, "time.Duration value") testOptionalInt = Int("test_optional_int", 0, "optional int value") normalizeFlagNameInvocations = 0 ) func boolString(s string) string { if s == "0" { return "false" } return "true" } func TestEverything(t *testing.T) { m := make(map[string]*Flag) desired := "0" visitor := func(f *Flag) { if len(f.Name) > 5 && f.Name[0:5] == "test_" { m[f.Name] = f ok := false switch { case f.Value.String() == desired: ok = true case f.Name == "test_bool" && f.Value.String() == boolString(desired): ok = true case f.Name == "test_duration" && f.Value.String() == desired+"s": ok = true } if !ok { t.Error("Visit: bad value", f.Value.String(), "for", f.Name) } } } VisitAll(visitor) if len(m) != 9 { t.Error("VisitAll misses some flags") for k, v := range m { t.Log(k, *v) } } m = make(map[string]*Flag) Visit(visitor) if len(m) != 0 { t.Errorf("Visit sees unset flags") for k, v := range m { t.Log(k, *v) } } // Now set all flags Set("test_bool", "true") Set("test_int", "1") Set("test_int64", "1") Set("test_uint", "1") Set("test_uint64", "1") Set("test_string", "1") Set("test_float64", "1") Set("test_duration", "1s") Set("test_optional_int", "1") desired = "1" Visit(visitor) if len(m) != 9 { t.Error("Visit fails after set") for k, v := range m { t.Log(k, *v) } } // Now test they're visited in sort order. var flagNames []string Visit(func(f *Flag) { flagNames = append(flagNames, f.Name) }) if !sort.StringsAreSorted(flagNames) { t.Errorf("flag names not sorted: %v", flagNames) } } func TestUsage(t *testing.T) { called := false ResetForTesting(func() { called = true }) if GetCommandLine().Parse([]string{"--x"}) == nil { t.Error("parse did not fail for unknown flag") } if !called { t.Error("did not call Usage for unknown flag") } } func TestAddFlagSet(t *testing.T) { oldSet := NewFlagSet("old", ContinueOnError) newSet := NewFlagSet("new", ContinueOnError) oldSet.String("flag1", "flag1", "flag1") oldSet.String("flag2", "flag2", "flag2") newSet.String("flag2", "flag2", "flag2") newSet.String("flag3", "flag3", "flag3") oldSet.AddFlagSet(newSet) if len(oldSet.formal) != 3 { t.Errorf("Unexpected result adding a FlagSet to a FlagSet %v", oldSet) } } func TestAnnotation(t *testing.T) { f := NewFlagSet("shorthand", ContinueOnError) if err := f.SetAnnotation("missing-flag", "key", nil); err == nil { t.Errorf("Expected error setting annotation on non-existent flag") } f.StringP("stringa", "a", "", "string value") if err := f.SetAnnotation("stringa", "key", nil); err != nil { t.Errorf("Unexpected error setting new nil annotation: %v", err) } if annotation := f.Lookup("stringa").Annotations["key"]; annotation != nil { t.Errorf("Unexpected annotation: %v", annotation) } f.StringP("stringb", "b", "", "string2 value") if err := f.SetAnnotation("stringb", "key", []string{"value1"}); err != nil { t.Errorf("Unexpected error setting new annotation: %v", err) } if annotation := f.Lookup("stringb").Annotations["key"]; !reflect.DeepEqual(annotation, []string{"value1"}) { t.Errorf("Unexpected annotation: %v", annotation) } if err := f.SetAnnotation("stringb", "key", []string{"value2"}); err != nil { t.Errorf("Unexpected error updating annotation: %v", err) } if annotation := f.Lookup("stringb").Annotations["key"]; !reflect.DeepEqual(annotation, []string{"value2"}) { t.Errorf("Unexpected annotation: %v", annotation) } } func testParse(f *FlagSet, t *testing.T) { if f.Parsed() { t.Error("f.Parse() = true before Parse") } boolFlag := f.Bool("bool", false, "bool value") bool2Flag := f.Bool("bool2", false, "bool2 value") bool3Flag := f.Bool("bool3", false, "bool3 value") intFlag := f.Int("int", 0, "int value") int8Flag := f.Int8("int8", 0, "int value") int32Flag := f.Int32("int32", 0, "int value") int64Flag := f.Int64("int64", 0, "int64 value") uintFlag := f.Uint("uint", 0, "uint value") uint8Flag := f.Uint8("uint8", 0, "uint value") uint16Flag := f.Uint16("uint16", 0, "uint value") uint32Flag := f.Uint32("uint32", 0, "uint value") uint64Flag := f.Uint64("uint64", 0, "uint64 value") stringFlag := f.String("string", "0", "string value") float32Flag := f.Float32("float32", 0, "float32 value") float64Flag := f.Float64("float64", 0, "float64 value") ipFlag := f.IP("ip", net.ParseIP("127.0.0.1"), "ip value") maskFlag := f.IPMask("mask", ParseIPv4Mask("0.0.0.0"), "mask value") durationFlag := f.Duration("duration", 5*time.Second, "time.Duration value") optionalIntNoValueFlag := f.Int("optional-int-no-value", 0, "int value") f.Lookup("optional-int-no-value").NoOptDefVal = "9" optionalIntWithValueFlag := f.Int("optional-int-with-value", 0, "int value") f.Lookup("optional-int-no-value").NoOptDefVal = "9" extra := "one-extra-argument" args := []string{ "--bool", "--bool2=true", "--bool3=false", "--int=22", "--int8=-8", "--int32=-32", "--int64=0x23", "--uint", "24", "--uint8=8", "--uint16=16", "--uint32=32", "--uint64=25", "--string=hello", "--float32=-172e12", "--float64=2718e28", "--ip=10.11.12.13", "--mask=255.255.255.0", "--duration=2m", "--optional-int-no-value", "--optional-int-with-value=42", extra, } if err := f.Parse(args); err != nil { t.Fatal(err) } if !f.Parsed() { t.Error("f.Parse() = false after Parse") } if *boolFlag != true { t.Error("bool flag should be true, is ", *boolFlag) } if v, err := f.GetBool("bool"); err != nil || v != *boolFlag { t.Error("GetBool does not work.") } if *bool2Flag != true { t.Error("bool2 flag should be true, is ", *bool2Flag) } if *bool3Flag != false { t.Error("bool3 flag should be false, is ", *bool2Flag) } if *intFlag != 22 { t.Error("int flag should be 22, is ", *intFlag) } if v, err := f.GetInt("int"); err != nil || v != *intFlag { t.Error("GetInt does not work.") } if *int8Flag != -8 { t.Error("int8 flag should be 0x23, is ", *int8Flag) } if v, err := f.GetInt8("int8"); err != nil || v != *int8Flag { t.Error("GetInt8 does not work.") } if *int32Flag != -32 { t.Error("int32 flag should be 0x23, is ", *int32Flag) } if v, err := f.GetInt32("int32"); err != nil || v != *int32Flag { t.Error("GetInt32 does not work.") } if *int64Flag != 0x23 { t.Error("int64 flag should be 0x23, is ", *int64Flag) } if v, err := f.GetInt64("int64"); err != nil || v != *int64Flag { t.Error("GetInt64 does not work.") } if *uintFlag != 24 { t.Error("uint flag should be 24, is ", *uintFlag) } if v, err := f.GetUint("uint"); err != nil || v != *uintFlag { t.Error("GetUint does not work.") } if *uint8Flag != 8 { t.Error("uint8 flag should be 8, is ", *uint8Flag) } if v, err := f.GetUint8("uint8"); err != nil || v != *uint8Flag { t.Error("GetUint8 does not work.") } if *uint16Flag != 16 { t.Error("uint16 flag should be 16, is ", *uint16Flag) } if v, err := f.GetUint16("uint16"); err != nil || v != *uint16Flag { t.Error("GetUint16 does not work.") } if *uint32Flag != 32 { t.Error("uint32 flag should be 32, is ", *uint32Flag) } if v, err := f.GetUint32("uint32"); err != nil || v != *uint32Flag { t.Error("GetUint32 does not work.") } if *uint64Flag != 25 { t.Error("uint64 flag should be 25, is ", *uint64Flag) } if v, err := f.GetUint64("uint64"); err != nil || v != *uint64Flag { t.Error("GetUint64 does not work.") } if *stringFlag != "hello" { t.Error("string flag should be `hello`, is ", *stringFlag) } if v, err := f.GetString("string"); err != nil || v != *stringFlag { t.Error("GetString does not work.") } if *float32Flag != -172e12 { t.Error("float32 flag should be -172e12, is ", *float32Flag) } if v, err := f.GetFloat32("float32"); err != nil || v != *float32Flag { t.Errorf("GetFloat32 returned %v but float32Flag was %v", v, *float32Flag) } if *float64Flag != 2718e28 { t.Error("float64 flag should be 2718e28, is ", *float64Flag) } if v, err := f.GetFloat64("float64"); err != nil || v != *float64Flag { t.Errorf("GetFloat64 returned %v but float64Flag was %v", v, *float64Flag) } if !(*ipFlag).Equal(net.ParseIP("10.11.12.13")) { t.Error("ip flag should be 10.11.12.13, is ", *ipFlag) } if v, err := f.GetIP("ip"); err != nil || !v.Equal(*ipFlag) { t.Errorf("GetIP returned %v but ipFlag was %v", v, *ipFlag) } if (*maskFlag).String() != ParseIPv4Mask("255.255.255.0").String() { t.Error("mask flag should be 255.255.255.0, is ", (*maskFlag).String()) } if v, err := f.GetIPv4Mask("mask"); err != nil || v.String() != (*maskFlag).String() { t.Errorf("GetIP returned %v maskFlag was %v error was %v", v, *maskFlag, err) } if *durationFlag != 2*time.Minute { t.Error("duration flag should be 2m, is ", *durationFlag) } if v, err := f.GetDuration("duration"); err != nil || v != *durationFlag { t.Error("GetDuration does not work.") } if _, err := f.GetInt("duration"); err == nil { t.Error("GetInt parsed a time.Duration?!?!") } if *optionalIntNoValueFlag != 9 { t.Error("optional int flag should be the default value, is ", *optionalIntNoValueFlag) } if *optionalIntWithValueFlag != 42 { t.Error("optional int flag should be 42, is ", *optionalIntWithValueFlag) } if len(f.Args()) != 1 { t.Error("expected one argument, got", len(f.Args())) } else if f.Args()[0] != extra { t.Errorf("expected argument %q got %q", extra, f.Args()[0]) } } func testParseAll(f *FlagSet, t *testing.T) { if f.Parsed() { t.Error("f.Parse() = true before Parse") } f.BoolP("boola", "a", false, "bool value") f.BoolP("boolb", "b", false, "bool2 value") f.BoolP("boolc", "c", false, "bool3 value") f.BoolP("boold", "d", false, "bool4 value") f.StringP("stringa", "s", "0", "string value") f.StringP("stringz", "z", "0", "string value") f.StringP("stringx", "x", "0", "string value") f.StringP("stringy", "y", "0", "string value") f.Lookup("stringx").NoOptDefVal = "1" args := []string{ "-ab", "-cs=xx", "--stringz=something", "-d=true", "-x", "-y", "ee", } want := []string{ "boola", "true", "boolb", "true", "boolc", "true", "stringa", "xx", "stringz", "something", "boold", "true", "stringx", "1", "stringy", "ee", } got := []string{} store := func(flag *Flag, value string) error { got = append(got, flag.Name) if len(value) > 0 { got = append(got, value) } return nil } if err := f.ParseAll(args, store); err != nil { t.Errorf("expected no error, got %s", err) } if !f.Parsed() { t.Errorf("f.Parse() = false after Parse") } if !reflect.DeepEqual(got, want) { t.Errorf("f.ParseAll() fail to restore the args") t.Errorf("Got: %v", got) t.Errorf("Want: %v", want) } } func TestShorthand(t *testing.T) { f := NewFlagSet("shorthand", ContinueOnError) if f.Parsed() { t.Error("f.Parse() = true before Parse") } boolaFlag := f.BoolP("boola", "a", false, "bool value") boolbFlag := f.BoolP("boolb", "b", false, "bool2 value") boolcFlag := f.BoolP("boolc", "c", false, "bool3 value") booldFlag := f.BoolP("boold", "d", false, "bool4 value") stringaFlag := f.StringP("stringa", "s", "0", "string value") stringzFlag := f.StringP("stringz", "z", "0", "string value") extra := "interspersed-argument" notaflag := "--i-look-like-a-flag" args := []string{ "-ab", extra, "-cs", "hello", "-z=something", "-d=true", "--", notaflag, } f.SetOutput(ioutil.Discard) if err := f.Parse(args); err != nil { t.Error("expected no error, got ", err) } if !f.Parsed() { t.Error("f.Parse() = false after Parse") } if *boolaFlag != true { t.Error("boola flag should be true, is ", *boolaFlag) } if *boolbFlag != true { t.Error("boolb flag should be true, is ", *boolbFlag) } if *boolcFlag != true { t.Error("boolc flag should be true, is ", *boolcFlag) } if *booldFlag != true { t.Error("boold flag should be true, is ", *booldFlag) } if *stringaFlag != "hello" { t.Error("stringa flag should be `hello`, is ", *stringaFlag) } if *stringzFlag != "something" { t.Error("stringz flag should be `something`, is ", *stringzFlag) } if len(f.Args()) != 2 { t.Error("expected one argument, got", len(f.Args())) } else if f.Args()[0] != extra { t.Errorf("expected argument %q got %q", extra, f.Args()[0]) } else if f.Args()[1] != notaflag { t.Errorf("expected argument %q got %q", notaflag, f.Args()[1]) } if f.ArgsLenAtDash() != 1 { t.Errorf("expected argsLenAtDash %d got %d", f.ArgsLenAtDash(), 1) } } func TestShorthandLookup(t *testing.T) { f := NewFlagSet("shorthand", ContinueOnError) if f.Parsed() { t.Error("f.Parse() = true before Parse") } f.BoolP("boola", "a", false, "bool value") f.BoolP("boolb", "b", false, "bool2 value") args := []string{ "-ab", } f.SetOutput(ioutil.Discard) if err := f.Parse(args); err != nil { t.Error("expected no error, got ", err) } if !f.Parsed() { t.Error("f.Parse() = false after Parse") } flag := f.ShorthandLookup("a") if flag == nil { t.Errorf("f.ShorthandLookup(\"a\") returned nil") } if flag.Name != "boola" { t.Errorf("f.ShorthandLookup(\"a\") found %q instead of \"boola\"", flag.Name) } flag = f.ShorthandLookup("") if flag != nil { t.Errorf("f.ShorthandLookup(\"\") did not return nil") } defer func() { recover() }() flag = f.ShorthandLookup("ab") // should NEVER get here. lookup should panic. defer'd func should recover it. t.Errorf("f.ShorthandLookup(\"ab\") did not panic") } func TestParse(t *testing.T) { ResetForTesting(func() { t.Error("bad parse") }) testParse(GetCommandLine(), t) } func TestParseAll(t *testing.T) { ResetForTesting(func() { t.Error("bad parse") }) testParseAll(GetCommandLine(), t) } func TestFlagSetParse(t *testing.T) { testParse(NewFlagSet("test", ContinueOnError), t) } func TestChangedHelper(t *testing.T) { f := NewFlagSet("changedtest", ContinueOnError) f.Bool("changed", false, "changed bool") f.Bool("settrue", true, "true to true") f.Bool("setfalse", false, "false to false") f.Bool("unchanged", false, "unchanged bool") args := []string{"--changed", "--settrue", "--setfalse=false"} if err := f.Parse(args); err != nil { t.Error("f.Parse() = false after Parse") } if !f.Changed("changed") { t.Errorf("--changed wasn't changed!") } if !f.Changed("settrue") { t.Errorf("--settrue wasn't changed!") } if !f.Changed("setfalse") { t.Errorf("--setfalse wasn't changed!") } if f.Changed("unchanged") { t.Errorf("--unchanged was changed!") } if f.Changed("invalid") { t.Errorf("--invalid was changed!") } if f.ArgsLenAtDash() != -1 { t.Errorf("Expected argsLenAtDash: %d but got %d", -1, f.ArgsLenAtDash()) } } func replaceSeparators(name string, from []string, to string) string { result := name for _, sep := range from { result = strings.Replace(result, sep, to, -1) } // Type convert to indicate normalization has been done. return result } func wordSepNormalizeFunc(f *FlagSet, name string) NormalizedName { seps := []string{"-", "_"} name = replaceSeparators(name, seps, ".") normalizeFlagNameInvocations++ return NormalizedName(name) } func testWordSepNormalizedNames(args []string, t *testing.T) { f := NewFlagSet("normalized", ContinueOnError) if f.Parsed() { t.Error("f.Parse() = true before Parse") } withDashFlag := f.Bool("with-dash-flag", false, "bool value") // Set this after some flags have been added and before others. f.SetNormalizeFunc(wordSepNormalizeFunc) withUnderFlag := f.Bool("with_under_flag", false, "bool value") withBothFlag := f.Bool("with-both_flag", false, "bool value") if err := f.Parse(args); err != nil { t.Fatal(err) } if !f.Parsed() { t.Error("f.Parse() = false after Parse") } if *withDashFlag != true { t.Error("withDashFlag flag should be true, is ", *withDashFlag) } if *withUnderFlag != true { t.Error("withUnderFlag flag should be true, is ", *withUnderFlag) } if *withBothFlag != true { t.Error("withBothFlag flag should be true, is ", *withBothFlag) } } func TestWordSepNormalizedNames(t *testing.T) { args := []string{ "--with-dash-flag", "--with-under-flag", "--with-both-flag", } testWordSepNormalizedNames(args, t) args = []string{ "--with_dash_flag", "--with_under_flag", "--with_both_flag", } testWordSepNormalizedNames(args, t) args = []string{ "--with-dash_flag", "--with-under_flag", "--with-both_flag", } testWordSepNormalizedNames(args, t) } func aliasAndWordSepFlagNames(f *FlagSet, name string) NormalizedName { seps := []string{"-", "_"} oldName := replaceSeparators("old-valid_flag", seps, ".") newName := replaceSeparators("valid-flag", seps, ".") name = replaceSeparators(name, seps, ".") switch name { case oldName: name = newName break } return NormalizedName(name) } func TestCustomNormalizedNames(t *testing.T) { f := NewFlagSet("normalized", ContinueOnError) if f.Parsed() { t.Error("f.Parse() = true before Parse") } validFlag := f.Bool("valid-flag", false, "bool value") f.SetNormalizeFunc(aliasAndWordSepFlagNames) someOtherFlag := f.Bool("some-other-flag", false, "bool value") args := []string{"--old_valid_flag", "--some-other_flag"} if err := f.Parse(args); err != nil { t.Fatal(err) } if *validFlag != true { t.Errorf("validFlag is %v even though we set the alias --old_valid_falg", *validFlag) } if *someOtherFlag != true { t.Error("someOtherFlag should be true, is ", *someOtherFlag) } } // Every flag we add, the name (displayed also in usage) should normalized func TestNormalizationFuncShouldChangeFlagName(t *testing.T) { // Test normalization after addition f := NewFlagSet("normalized", ContinueOnError) f.Bool("valid_flag", false, "bool value") if f.Lookup("valid_flag").Name != "valid_flag" { t.Error("The new flag should have the name 'valid_flag' instead of ", f.Lookup("valid_flag").Name) } f.SetNormalizeFunc(wordSepNormalizeFunc) if f.Lookup("valid_flag").Name != "valid.flag" { t.Error("The new flag should have the name 'valid.flag' instead of ", f.Lookup("valid_flag").Name) } // Test normalization before addition f = NewFlagSet("normalized", ContinueOnError) f.SetNormalizeFunc(wordSepNormalizeFunc) f.Bool("valid_flag", false, "bool value") if f.Lookup("valid_flag").Name != "valid.flag" { t.Error("The new flag should have the name 'valid.flag' instead of ", f.Lookup("valid_flag").Name) } } // Declare a user-defined flag type. type flagVar []string func (f *flagVar) String() string { return fmt.Sprint([]string(*f)) } func (f *flagVar) Set(value string) error { *f = append(*f, value) return nil } func (f *flagVar) Type() string { return "flagVar" } func TestUserDefined(t *testing.T) { var flags FlagSet flags.Init("test", ContinueOnError) var v flagVar flags.VarP(&v, "v", "v", "usage") if err := flags.Parse([]string{"--v=1", "-v2", "-v", "3"}); err != nil { t.Error(err) } if len(v) != 3 { t.Fatal("expected 3 args; got ", len(v)) } expect := "[1 2 3]" if v.String() != expect { t.Errorf("expected value %q got %q", expect, v.String()) } } func TestSetOutput(t *testing.T) { var flags FlagSet var buf bytes.Buffer flags.SetOutput(&buf) flags.Init("test", ContinueOnError) flags.Parse([]string{"--unknown"}) if out := buf.String(); !strings.Contains(out, "--unknown") { t.Logf("expected output mentioning unknown; got %q", out) } } // This tests that one can reset the flags. This still works but not well, and is // superseded by FlagSet. func TestChangingArgs(t *testing.T) { ResetForTesting(func() { t.Fatal("bad parse") }) oldArgs := os.Args defer func() { os.Args = oldArgs }() os.Args = []string{"cmd", "--before", "subcmd"} before := Bool("before", false, "") if err := GetCommandLine().Parse(os.Args[1:]); err != nil { t.Fatal(err) } cmd := Arg(0) os.Args = []string{"subcmd", "--after", "args"} after := Bool("after", false, "") Parse() args := Args() if !*before || cmd != "subcmd" || !*after || len(args) != 1 || args[0] != "args" { t.Fatalf("expected true subcmd true [args] got %v %v %v %v", *before, cmd, *after, args) } } // Test that -help invokes the usage message and returns ErrHelp. func TestHelp(t *testing.T) { var helpCalled = false fs := NewFlagSet("help test", ContinueOnError) fs.Usage = func() { helpCalled = true } var flag bool fs.BoolVar(&flag, "flag", false, "regular flag") // Regular flag invocation should work err := fs.Parse([]string{"--flag=true"}) if err != nil { t.Fatal("expected no error; got ", err) } if !flag { t.Error("flag was not set by --flag") } if helpCalled { t.Error("help called for regular flag") helpCalled = false // reset for next test } // Help flag should work as expected. err = fs.Parse([]string{"--help"}) if err == nil { t.Fatal("error expected") } if err != ErrHelp { t.Fatal("expected ErrHelp; got ", err) } if !helpCalled { t.Fatal("help was not called") } // If we define a help flag, that should override. var help bool fs.BoolVar(&help, "help", false, "help flag") helpCalled = false err = fs.Parse([]string{"--help"}) if err != nil { t.Fatal("expected no error for defined --help; got ", err) } if helpCalled { t.Fatal("help was called; should not have been for defined help flag") } } func TestNoInterspersed(t *testing.T) { f := NewFlagSet("test", ContinueOnError) f.SetInterspersed(false) f.Bool("true", true, "always true") f.Bool("false", false, "always false") err := f.Parse([]string{"--true", "break", "--false"}) if err != nil { t.Fatal("expected no error; got ", err) } args := f.Args() if len(args) != 2 || args[0] != "break" || args[1] != "--false" { t.Fatal("expected interspersed options/non-options to fail") } } func TestTermination(t *testing.T) { f := NewFlagSet("termination", ContinueOnError) boolFlag := f.BoolP("bool", "l", false, "bool value") if f.Parsed() { t.Error("f.Parse() = true before Parse") } arg1 := "ls" arg2 := "-l" args := []string{ "--", arg1, arg2, } f.SetOutput(ioutil.Discard) if err := f.Parse(args); err != nil { t.Fatal("expected no error; got ", err) } if !f.Parsed() { t.Error("f.Parse() = false after Parse") } if *boolFlag { t.Error("expected boolFlag=false, got true") } if len(f.Args()) != 2 { t.Errorf("expected 2 arguments, got %d: %v", len(f.Args()), f.Args()) } if f.Args()[0] != arg1 { t.Errorf("expected argument %q got %q", arg1, f.Args()[0]) } if f.Args()[1] != arg2 { t.Errorf("expected argument %q got %q", arg2, f.Args()[1]) } if f.ArgsLenAtDash() != 0 { t.Errorf("expected argsLenAtDash %d got %d", 0, f.ArgsLenAtDash()) } } func TestDeprecatedFlagInDocs(t *testing.T) { f := NewFlagSet("bob", ContinueOnError) f.Bool("badflag", true, "always true") f.MarkDeprecated("badflag", "use --good-flag instead") out := new(bytes.Buffer) f.SetOutput(out) f.PrintDefaults() if strings.Contains(out.String(), "badflag") { t.Errorf("found deprecated flag in usage!") } } func TestDeprecatedFlagShorthandInDocs(t *testing.T) { f := NewFlagSet("bob", ContinueOnError) name := "noshorthandflag" f.BoolP(name, "n", true, "always true") f.MarkShorthandDeprecated("noshorthandflag", fmt.Sprintf("use --%s instead", name)) out := new(bytes.Buffer) f.SetOutput(out) f.PrintDefaults() if strings.Contains(out.String(), "-n,") { t.Errorf("found deprecated flag shorthand in usage!") } } func parseReturnStderr(t *testing.T, f *FlagSet, args []string) (string, error) { oldStderr := os.Stderr r, w, _ := os.Pipe() os.Stderr = w err := f.Parse(args) outC := make(chan string) // copy the output in a separate goroutine so printing can't block indefinitely go func() { var buf bytes.Buffer io.Copy(&buf, r) outC <- buf.String() }() w.Close() os.Stderr = oldStderr out := <-outC return out, err } func TestDeprecatedFlagUsage(t *testing.T) { f := NewFlagSet("bob", ContinueOnError) f.Bool("badflag", true, "always true") usageMsg := "use --good-flag instead" f.MarkDeprecated("badflag", usageMsg) args := []string{"--badflag"} out, err := parseReturnStderr(t, f, args) if err != nil { t.Fatal("expected no error; got ", err) } if !strings.Contains(out, usageMsg) { t.Errorf("usageMsg not printed when using a deprecated flag!") } } func TestDeprecatedFlagShorthandUsage(t *testing.T) { f := NewFlagSet("bob", ContinueOnError) name := "noshorthandflag" f.BoolP(name, "n", true, "always true") usageMsg := fmt.Sprintf("use --%s instead", name) f.MarkShorthandDeprecated(name, usageMsg) args := []string{"-n"} out, err := parseReturnStderr(t, f, args) if err != nil { t.Fatal("expected no error; got ", err) } if !strings.Contains(out, usageMsg) { t.Errorf("usageMsg not printed when using a deprecated flag!") } } func TestDeprecatedFlagUsageNormalized(t *testing.T) { f := NewFlagSet("bob", ContinueOnError) f.Bool("bad-double_flag", true, "always true") f.SetNormalizeFunc(wordSepNormalizeFunc) usageMsg := "use --good-flag instead" f.MarkDeprecated("bad_double-flag", usageMsg) args := []string{"--bad_double_flag"} out, err := parseReturnStderr(t, f, args) if err != nil { t.Fatal("expected no error; got ", err) } if !strings.Contains(out, usageMsg) { t.Errorf("usageMsg not printed when using a deprecated flag!") } } // Name normalization function should be called only once on flag addition func TestMultipleNormalizeFlagNameInvocations(t *testing.T) { normalizeFlagNameInvocations = 0 f := NewFlagSet("normalized", ContinueOnError) f.SetNormalizeFunc(wordSepNormalizeFunc) f.Bool("with_under_flag", false, "bool value") if normalizeFlagNameInvocations != 1 { t.Fatal("Expected normalizeFlagNameInvocations to be 1; got ", normalizeFlagNameInvocations) } } // func TestHiddenFlagInUsage(t *testing.T) { f := NewFlagSet("bob", ContinueOnError) f.Bool("secretFlag", true, "shhh") f.MarkHidden("secretFlag") out := new(bytes.Buffer) f.SetOutput(out) f.PrintDefaults() if strings.Contains(out.String(), "secretFlag") { t.Errorf("found hidden flag in usage!") } } // func TestHiddenFlagUsage(t *testing.T) { f := NewFlagSet("bob", ContinueOnError) f.Bool("secretFlag", true, "shhh") f.MarkHidden("secretFlag") args := []string{"--secretFlag"} out, err := parseReturnStderr(t, f, args) if err != nil { t.Fatal("expected no error; got ", err) } if strings.Contains(out, "shhh") { t.Errorf("usage message printed when using a hidden flag!") } } const defaultOutput = ` --A for bootstrapping, allow 'any' type --Alongflagname disable bounds checking -C, --CCC a boolean defaulting to true (default true) --D path set relative path for local imports -E, --EEE num[=1234] a num with NoOptDefVal (default 4321) --F number a non-zero number (default 2.7) --G float a float that defaults to zero --IP ip IP address with no default --IPMask ipMask Netmask address with no default --IPNet ipNet IP network with no default --Ints intSlice int slice with zero default --N int a non-zero int (default 27) --ND1 string[="bar"] a string with NoOptDefVal (default "foo") --ND2 num[=4321] a num with NoOptDefVal (default 1234) --StringArray stringArray string array with zero default --StringSlice stringSlice string slice with zero default --Z int an int that defaults to zero --custom custom custom Value implementation --customP custom a VarP with default (default 10) --maxT timeout set timeout for dial ` // Custom value that satisfies the Value interface. type customValue int func (cv *customValue) String() string { return fmt.Sprintf("%v", *cv) } func (cv *customValue) Set(s string) error { v, err := strconv.ParseInt(s, 0, 64) *cv = customValue(v) return err } func (cv *customValue) Type() string { return "custom" } func TestPrintDefaults(t *testing.T) { fs := NewFlagSet("print defaults test", ContinueOnError) var buf bytes.Buffer fs.SetOutput(&buf) fs.Bool("A", false, "for bootstrapping, allow 'any' type") fs.Bool("Alongflagname", false, "disable bounds checking") fs.BoolP("CCC", "C", true, "a boolean defaulting to true") fs.String("D", "", "set relative `path` for local imports") fs.Float64("F", 2.7, "a non-zero `number`") fs.Float64("G", 0, "a float that defaults to zero") fs.Int("N", 27, "a non-zero int") fs.IntSlice("Ints", []int{}, "int slice with zero default") fs.IP("IP", nil, "IP address with no default") fs.IPMask("IPMask", nil, "Netmask address with no default") fs.IPNet("IPNet", net.IPNet{}, "IP network with no default") fs.Int("Z", 0, "an int that defaults to zero") fs.Duration("maxT", 0, "set `timeout` for dial") fs.String("ND1", "foo", "a string with NoOptDefVal") fs.Lookup("ND1").NoOptDefVal = "bar" fs.Int("ND2", 1234, "a `num` with NoOptDefVal") fs.Lookup("ND2").NoOptDefVal = "4321" fs.IntP("EEE", "E", 4321, "a `num` with NoOptDefVal") fs.ShorthandLookup("E").NoOptDefVal = "1234" fs.StringSlice("StringSlice", []string{}, "string slice with zero default") fs.StringArray("StringArray", []string{}, "string array with zero default") var cv customValue fs.Var(&cv, "custom", "custom Value implementation") cv2 := customValue(10) fs.VarP(&cv2, "customP", "", "a VarP with default") fs.PrintDefaults() got := buf.String() if got != defaultOutput { fmt.Println("\n" + got) fmt.Println("\n" + defaultOutput) t.Errorf("got %q want %q\n", got, defaultOutput) } } func TestVisitAllFlagOrder(t *testing.T) { fs := NewFlagSet("TestVisitAllFlagOrder", ContinueOnError) fs.SortFlags = false // https://github.com/spf13/pflag/issues/120 fs.SetNormalizeFunc(func(f *FlagSet, name string) NormalizedName { return NormalizedName(name) }) names := []string{"C", "B", "A", "D"} for _, name := range names { fs.Bool(name, false, "") } i := 0 fs.VisitAll(func(f *Flag) { if names[i] != f.Name { t.Errorf("Incorrect order. Expected %v, got %v", names[i], f.Name) } i++ }) } func TestVisitFlagOrder(t *testing.T) { fs := NewFlagSet("TestVisitFlagOrder", ContinueOnError) fs.SortFlags = false names := []string{"C", "B", "A", "D"} for _, name := range names { fs.Bool(name, false, "") fs.Set(name, "true") } i := 0 fs.Visit(func(f *Flag) { if names[i] != f.Name { t.Errorf("Incorrect order. Expected %v, got %v", names[i], f.Name) } i++ }) } ================================================ FILE: vendor/github.com/spf13/pflag/float32.go ================================================ package pflag import "strconv" // -- float32 Value type float32Value float32 func newFloat32Value(val float32, p *float32) *float32Value { *p = val return (*float32Value)(p) } func (f *float32Value) Set(s string) error { v, err := strconv.ParseFloat(s, 32) *f = float32Value(v) return err } func (f *float32Value) Type() string { return "float32" } func (f *float32Value) String() string { return strconv.FormatFloat(float64(*f), 'g', -1, 32) } func float32Conv(sval string) (interface{}, error) { v, err := strconv.ParseFloat(sval, 32) if err != nil { return 0, err } return float32(v), nil } // GetFloat32 return the float32 value of a flag with the given name func (f *FlagSet) GetFloat32(name string) (float32, error) { val, err := f.getFlagType(name, "float32", float32Conv) if err != nil { return 0, err } return val.(float32), nil } // Float32Var defines a float32 flag with specified name, default value, and usage string. // The argument p points to a float32 variable in which to store the value of the flag. func (f *FlagSet) Float32Var(p *float32, name string, value float32, usage string) { f.VarP(newFloat32Value(value, p), name, "", usage) } // Float32VarP is like Float32Var, but accepts a shorthand letter that can be used after a single dash. func (f *FlagSet) Float32VarP(p *float32, name, shorthand string, value float32, usage string) { f.VarP(newFloat32Value(value, p), name, shorthand, usage) } // Float32Var defines a float32 flag with specified name, default value, and usage string. // The argument p points to a float32 variable in which to store the value of the flag. func Float32Var(p *float32, name string, value float32, usage string) { CommandLine.VarP(newFloat32Value(value, p), name, "", usage) } // Float32VarP is like Float32Var, but accepts a shorthand letter that can be used after a single dash. func Float32VarP(p *float32, name, shorthand string, value float32, usage string) { CommandLine.VarP(newFloat32Value(value, p), name, shorthand, usage) } // Float32 defines a float32 flag with specified name, default value, and usage string. // The return value is the address of a float32 variable that stores the value of the flag. func (f *FlagSet) Float32(name string, value float32, usage string) *float32 { p := new(float32) f.Float32VarP(p, name, "", value, usage) return p } // Float32P is like Float32, but accepts a shorthand letter that can be used after a single dash. func (f *FlagSet) Float32P(name, shorthand string, value float32, usage string) *float32 { p := new(float32) f.Float32VarP(p, name, shorthand, value, usage) return p } // Float32 defines a float32 flag with specified name, default value, and usage string. // The return value is the address of a float32 variable that stores the value of the flag. func Float32(name string, value float32, usage string) *float32 { return CommandLine.Float32P(name, "", value, usage) } // Float32P is like Float32, but accepts a shorthand letter that can be used after a single dash. func Float32P(name, shorthand string, value float32, usage string) *float32 { return CommandLine.Float32P(name, shorthand, value, usage) } ================================================ FILE: vendor/github.com/spf13/pflag/float64.go ================================================ package pflag import "strconv" // -- float64 Value type float64Value float64 func newFloat64Value(val float64, p *float64) *float64Value { *p = val return (*float64Value)(p) } func (f *float64Value) Set(s string) error { v, err := strconv.ParseFloat(s, 64) *f = float64Value(v) return err } func (f *float64Value) Type() string { return "float64" } func (f *float64Value) String() string { return strconv.FormatFloat(float64(*f), 'g', -1, 64) } func float64Conv(sval string) (interface{}, error) { return strconv.ParseFloat(sval, 64) } // GetFloat64 return the float64 value of a flag with the given name func (f *FlagSet) GetFloat64(name string) (float64, error) { val, err := f.getFlagType(name, "float64", float64Conv) if err != nil { return 0, err } return val.(float64), nil } // Float64Var defines a float64 flag with specified name, default value, and usage string. // The argument p points to a float64 variable in which to store the value of the flag. func (f *FlagSet) Float64Var(p *float64, name string, value float64, usage string) { f.VarP(newFloat64Value(value, p), name, "", usage) } // Float64VarP is like Float64Var, but accepts a shorthand letter that can be used after a single dash. func (f *FlagSet) Float64VarP(p *float64, name, shorthand string, value float64, usage string) { f.VarP(newFloat64Value(value, p), name, shorthand, usage) } // Float64Var defines a float64 flag with specified name, default value, and usage string. // The argument p points to a float64 variable in which to store the value of the flag. func Float64Var(p *float64, name string, value float64, usage string) { CommandLine.VarP(newFloat64Value(value, p), name, "", usage) } // Float64VarP is like Float64Var, but accepts a shorthand letter that can be used after a single dash. func Float64VarP(p *float64, name, shorthand string, value float64, usage string) { CommandLine.VarP(newFloat64Value(value, p), name, shorthand, usage) } // Float64 defines a float64 flag with specified name, default value, and usage string. // The return value is the address of a float64 variable that stores the value of the flag. func (f *FlagSet) Float64(name string, value float64, usage string) *float64 { p := new(float64) f.Float64VarP(p, name, "", value, usage) return p } // Float64P is like Float64, but accepts a shorthand letter that can be used after a single dash. func (f *FlagSet) Float64P(name, shorthand string, value float64, usage string) *float64 { p := new(float64) f.Float64VarP(p, name, shorthand, value, usage) return p } // Float64 defines a float64 flag with specified name, default value, and usage string. // The return value is the address of a float64 variable that stores the value of the flag. func Float64(name string, value float64, usage string) *float64 { return CommandLine.Float64P(name, "", value, usage) } // Float64P is like Float64, but accepts a shorthand letter that can be used after a single dash. func Float64P(name, shorthand string, value float64, usage string) *float64 { return CommandLine.Float64P(name, shorthand, value, usage) } ================================================ FILE: vendor/github.com/spf13/pflag/golangflag.go ================================================ // Copyright 2009 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 file. package pflag import ( goflag "flag" "reflect" "strings" ) // flagValueWrapper implements pflag.Value around a flag.Value. The main // difference here is the addition of the Type method that returns a string // name of the type. As this is generally unknown, we approximate that with // reflection. type flagValueWrapper struct { inner goflag.Value flagType string } // We are just copying the boolFlag interface out of goflag as that is what // they use to decide if a flag should get "true" when no arg is given. type goBoolFlag interface { goflag.Value IsBoolFlag() bool } func wrapFlagValue(v goflag.Value) Value { // If the flag.Value happens to also be a pflag.Value, just use it directly. if pv, ok := v.(Value); ok { return pv } pv := &flagValueWrapper{ inner: v, } t := reflect.TypeOf(v) if t.Kind() == reflect.Interface || t.Kind() == reflect.Ptr { t = t.Elem() } pv.flagType = strings.TrimSuffix(t.Name(), "Value") return pv } func (v *flagValueWrapper) String() string { return v.inner.String() } func (v *flagValueWrapper) Set(s string) error { return v.inner.Set(s) } func (v *flagValueWrapper) Type() string { return v.flagType } // PFlagFromGoFlag will return a *pflag.Flag given a *flag.Flag // If the *flag.Flag.Name was a single character (ex: `v`) it will be accessiblei // with both `-v` and `--v` in flags. If the golang flag was more than a single // character (ex: `verbose`) it will only be accessible via `--verbose` func PFlagFromGoFlag(goflag *goflag.Flag) *Flag { // Remember the default value as a string; it won't change. flag := &Flag{ Name: goflag.Name, Usage: goflag.Usage, Value: wrapFlagValue(goflag.Value), // Looks like golang flags don't set DefValue correctly :-( //DefValue: goflag.DefValue, DefValue: goflag.Value.String(), } // Ex: if the golang flag was -v, allow both -v and --v to work if len(flag.Name) == 1 { flag.Shorthand = flag.Name } if fv, ok := goflag.Value.(goBoolFlag); ok && fv.IsBoolFlag() { flag.NoOptDefVal = "true" } return flag } // AddGoFlag will add the given *flag.Flag to the pflag.FlagSet func (f *FlagSet) AddGoFlag(goflag *goflag.Flag) { if f.Lookup(goflag.Name) != nil { return } newflag := PFlagFromGoFlag(goflag) f.AddFlag(newflag) } // AddGoFlagSet will add the given *flag.FlagSet to the pflag.FlagSet func (f *FlagSet) AddGoFlagSet(newSet *goflag.FlagSet) { if newSet == nil { return } newSet.VisitAll(func(goflag *goflag.Flag) { f.AddGoFlag(goflag) }) } ================================================ FILE: vendor/github.com/spf13/pflag/golangflag_test.go ================================================ // Copyright 2009 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 file. package pflag import ( goflag "flag" "testing" ) func TestGoflags(t *testing.T) { goflag.String("stringFlag", "stringFlag", "stringFlag") goflag.Bool("boolFlag", false, "boolFlag") f := NewFlagSet("test", ContinueOnError) f.AddGoFlagSet(goflag.CommandLine) err := f.Parse([]string{"--stringFlag=bob", "--boolFlag"}) if err != nil { t.Fatal("expected no error; get", err) } getString, err := f.GetString("stringFlag") if err != nil { t.Fatal("expected no error; get", err) } if getString != "bob" { t.Fatalf("expected getString=bob but got getString=%s", getString) } getBool, err := f.GetBool("boolFlag") if err != nil { t.Fatal("expected no error; get", err) } if getBool != true { t.Fatalf("expected getBool=true but got getBool=%v", getBool) } } ================================================ FILE: vendor/github.com/spf13/pflag/int.go ================================================ package pflag import "strconv" // -- int Value type intValue int func newIntValue(val int, p *int) *intValue { *p = val return (*intValue)(p) } func (i *intValue) Set(s string) error { v, err := strconv.ParseInt(s, 0, 64) *i = intValue(v) return err } func (i *intValue) Type() string { return "int" } func (i *intValue) String() string { return strconv.Itoa(int(*i)) } func intConv(sval string) (interface{}, error) { return strconv.Atoi(sval) } // GetInt return the int value of a flag with the given name func (f *FlagSet) GetInt(name string) (int, error) { val, err := f.getFlagType(name, "int", intConv) if err != nil { return 0, err } return val.(int), nil } // IntVar defines an int flag with specified name, default value, and usage string. // The argument p points to an int variable in which to store the value of the flag. func (f *FlagSet) IntVar(p *int, name string, value int, usage string) { f.VarP(newIntValue(value, p), name, "", usage) } // IntVarP is like IntVar, but accepts a shorthand letter that can be used after a single dash. func (f *FlagSet) IntVarP(p *int, name, shorthand string, value int, usage string) { f.VarP(newIntValue(value, p), name, shorthand, usage) } // IntVar defines an int flag with specified name, default value, and usage string. // The argument p points to an int variable in which to store the value of the flag. func IntVar(p *int, name string, value int, usage string) { CommandLine.VarP(newIntValue(value, p), name, "", usage) } // IntVarP is like IntVar, but accepts a shorthand letter that can be used after a single dash. func IntVarP(p *int, name, shorthand string, value int, usage string) { CommandLine.VarP(newIntValue(value, p), name, shorthand, usage) } // Int defines an int flag with specified name, default value, and usage string. // The return value is the address of an int variable that stores the value of the flag. func (f *FlagSet) Int(name string, value int, usage string) *int { p := new(int) f.IntVarP(p, name, "", value, usage) return p } // IntP is like Int, but accepts a shorthand letter that can be used after a single dash. func (f *FlagSet) IntP(name, shorthand string, value int, usage string) *int { p := new(int) f.IntVarP(p, name, shorthand, value, usage) return p } // Int defines an int flag with specified name, default value, and usage string. // The return value is the address of an int variable that stores the value of the flag. func Int(name string, value int, usage string) *int { return CommandLine.IntP(name, "", value, usage) } // IntP is like Int, but accepts a shorthand letter that can be used after a single dash. func IntP(name, shorthand string, value int, usage string) *int { return CommandLine.IntP(name, shorthand, value, usage) } ================================================ FILE: vendor/github.com/spf13/pflag/int32.go ================================================ package pflag import "strconv" // -- int32 Value type int32Value int32 func newInt32Value(val int32, p *int32) *int32Value { *p = val return (*int32Value)(p) } func (i *int32Value) Set(s string) error { v, err := strconv.ParseInt(s, 0, 32) *i = int32Value(v) return err } func (i *int32Value) Type() string { return "int32" } func (i *int32Value) String() string { return strconv.FormatInt(int64(*i), 10) } func int32Conv(sval string) (interface{}, error) { v, err := strconv.ParseInt(sval, 0, 32) if err != nil { return 0, err } return int32(v), nil } // GetInt32 return the int32 value of a flag with the given name func (f *FlagSet) GetInt32(name string) (int32, error) { val, err := f.getFlagType(name, "int32", int32Conv) if err != nil { return 0, err } return val.(int32), nil } // Int32Var defines an int32 flag with specified name, default value, and usage string. // The argument p points to an int32 variable in which to store the value of the flag. func (f *FlagSet) Int32Var(p *int32, name string, value int32, usage string) { f.VarP(newInt32Value(value, p), name, "", usage) } // Int32VarP is like Int32Var, but accepts a shorthand letter that can be used after a single dash. func (f *FlagSet) Int32VarP(p *int32, name, shorthand string, value int32, usage string) { f.VarP(newInt32Value(value, p), name, shorthand, usage) } // Int32Var defines an int32 flag with specified name, default value, and usage string. // The argument p points to an int32 variable in which to store the value of the flag. func Int32Var(p *int32, name string, value int32, usage string) { CommandLine.VarP(newInt32Value(value, p), name, "", usage) } // Int32VarP is like Int32Var, but accepts a shorthand letter that can be used after a single dash. func Int32VarP(p *int32, name, shorthand string, value int32, usage string) { CommandLine.VarP(newInt32Value(value, p), name, shorthand, usage) } // Int32 defines an int32 flag with specified name, default value, and usage string. // The return value is the address of an int32 variable that stores the value of the flag. func (f *FlagSet) Int32(name string, value int32, usage string) *int32 { p := new(int32) f.Int32VarP(p, name, "", value, usage) return p } // Int32P is like Int32, but accepts a shorthand letter that can be used after a single dash. func (f *FlagSet) Int32P(name, shorthand string, value int32, usage string) *int32 { p := new(int32) f.Int32VarP(p, name, shorthand, value, usage) return p } // Int32 defines an int32 flag with specified name, default value, and usage string. // The return value is the address of an int32 variable that stores the value of the flag. func Int32(name string, value int32, usage string) *int32 { return CommandLine.Int32P(name, "", value, usage) } // Int32P is like Int32, but accepts a shorthand letter that can be used after a single dash. func Int32P(name, shorthand string, value int32, usage string) *int32 { return CommandLine.Int32P(name, shorthand, value, usage) } ================================================ FILE: vendor/github.com/spf13/pflag/int64.go ================================================ package pflag import "strconv" // -- int64 Value type int64Value int64 func newInt64Value(val int64, p *int64) *int64Value { *p = val return (*int64Value)(p) } func (i *int64Value) Set(s string) error { v, err := strconv.ParseInt(s, 0, 64) *i = int64Value(v) return err } func (i *int64Value) Type() string { return "int64" } func (i *int64Value) String() string { return strconv.FormatInt(int64(*i), 10) } func int64Conv(sval string) (interface{}, error) { return strconv.ParseInt(sval, 0, 64) } // GetInt64 return the int64 value of a flag with the given name func (f *FlagSet) GetInt64(name string) (int64, error) { val, err := f.getFlagType(name, "int64", int64Conv) if err != nil { return 0, err } return val.(int64), nil } // Int64Var defines an int64 flag with specified name, default value, and usage string. // The argument p points to an int64 variable in which to store the value of the flag. func (f *FlagSet) Int64Var(p *int64, name string, value int64, usage string) { f.VarP(newInt64Value(value, p), name, "", usage) } // Int64VarP is like Int64Var, but accepts a shorthand letter that can be used after a single dash. func (f *FlagSet) Int64VarP(p *int64, name, shorthand string, value int64, usage string) { f.VarP(newInt64Value(value, p), name, shorthand, usage) } // Int64Var defines an int64 flag with specified name, default value, and usage string. // The argument p points to an int64 variable in which to store the value of the flag. func Int64Var(p *int64, name string, value int64, usage string) { CommandLine.VarP(newInt64Value(value, p), name, "", usage) } // Int64VarP is like Int64Var, but accepts a shorthand letter that can be used after a single dash. func Int64VarP(p *int64, name, shorthand string, value int64, usage string) { CommandLine.VarP(newInt64Value(value, p), name, shorthand, usage) } // Int64 defines an int64 flag with specified name, default value, and usage string. // The return value is the address of an int64 variable that stores the value of the flag. func (f *FlagSet) Int64(name string, value int64, usage string) *int64 { p := new(int64) f.Int64VarP(p, name, "", value, usage) return p } // Int64P is like Int64, but accepts a shorthand letter that can be used after a single dash. func (f *FlagSet) Int64P(name, shorthand string, value int64, usage string) *int64 { p := new(int64) f.Int64VarP(p, name, shorthand, value, usage) return p } // Int64 defines an int64 flag with specified name, default value, and usage string. // The return value is the address of an int64 variable that stores the value of the flag. func Int64(name string, value int64, usage string) *int64 { return CommandLine.Int64P(name, "", value, usage) } // Int64P is like Int64, but accepts a shorthand letter that can be used after a single dash. func Int64P(name, shorthand string, value int64, usage string) *int64 { return CommandLine.Int64P(name, shorthand, value, usage) } ================================================ FILE: vendor/github.com/spf13/pflag/int8.go ================================================ package pflag import "strconv" // -- int8 Value type int8Value int8 func newInt8Value(val int8, p *int8) *int8Value { *p = val return (*int8Value)(p) } func (i *int8Value) Set(s string) error { v, err := strconv.ParseInt(s, 0, 8) *i = int8Value(v) return err } func (i *int8Value) Type() string { return "int8" } func (i *int8Value) String() string { return strconv.FormatInt(int64(*i), 10) } func int8Conv(sval string) (interface{}, error) { v, err := strconv.ParseInt(sval, 0, 8) if err != nil { return 0, err } return int8(v), nil } // GetInt8 return the int8 value of a flag with the given name func (f *FlagSet) GetInt8(name string) (int8, error) { val, err := f.getFlagType(name, "int8", int8Conv) if err != nil { return 0, err } return val.(int8), nil } // Int8Var defines an int8 flag with specified name, default value, and usage string. // The argument p points to an int8 variable in which to store the value of the flag. func (f *FlagSet) Int8Var(p *int8, name string, value int8, usage string) { f.VarP(newInt8Value(value, p), name, "", usage) } // Int8VarP is like Int8Var, but accepts a shorthand letter that can be used after a single dash. func (f *FlagSet) Int8VarP(p *int8, name, shorthand string, value int8, usage string) { f.VarP(newInt8Value(value, p), name, shorthand, usage) } // Int8Var defines an int8 flag with specified name, default value, and usage string. // The argument p points to an int8 variable in which to store the value of the flag. func Int8Var(p *int8, name string, value int8, usage string) { CommandLine.VarP(newInt8Value(value, p), name, "", usage) } // Int8VarP is like Int8Var, but accepts a shorthand letter that can be used after a single dash. func Int8VarP(p *int8, name, shorthand string, value int8, usage string) { CommandLine.VarP(newInt8Value(value, p), name, shorthand, usage) } // Int8 defines an int8 flag with specified name, default value, and usage string. // The return value is the address of an int8 variable that stores the value of the flag. func (f *FlagSet) Int8(name string, value int8, usage string) *int8 { p := new(int8) f.Int8VarP(p, name, "", value, usage) return p } // Int8P is like Int8, but accepts a shorthand letter that can be used after a single dash. func (f *FlagSet) Int8P(name, shorthand string, value int8, usage string) *int8 { p := new(int8) f.Int8VarP(p, name, shorthand, value, usage) return p } // Int8 defines an int8 flag with specified name, default value, and usage string. // The return value is the address of an int8 variable that stores the value of the flag. func Int8(name string, value int8, usage string) *int8 { return CommandLine.Int8P(name, "", value, usage) } // Int8P is like Int8, but accepts a shorthand letter that can be used after a single dash. func Int8P(name, shorthand string, value int8, usage string) *int8 { return CommandLine.Int8P(name, shorthand, value, usage) } ================================================ FILE: vendor/github.com/spf13/pflag/int_slice.go ================================================ package pflag import ( "fmt" "strconv" "strings" ) // -- intSlice Value type intSliceValue struct { value *[]int changed bool } func newIntSliceValue(val []int, p *[]int) *intSliceValue { isv := new(intSliceValue) isv.value = p *isv.value = val return isv } func (s *intSliceValue) Set(val string) error { ss := strings.Split(val, ",") out := make([]int, len(ss)) for i, d := range ss { var err error out[i], err = strconv.Atoi(d) if err != nil { return err } } if !s.changed { *s.value = out } else { *s.value = append(*s.value, out...) } s.changed = true return nil } func (s *intSliceValue) Type() string { return "intSlice" } func (s *intSliceValue) String() string { out := make([]string, len(*s.value)) for i, d := range *s.value { out[i] = fmt.Sprintf("%d", d) } return "[" + strings.Join(out, ",") + "]" } func intSliceConv(val string) (interface{}, error) { val = strings.Trim(val, "[]") // Empty string would cause a slice with one (empty) entry if len(val) == 0 { return []int{}, nil } ss := strings.Split(val, ",") out := make([]int, len(ss)) for i, d := range ss { var err error out[i], err = strconv.Atoi(d) if err != nil { return nil, err } } return out, nil } // GetIntSlice return the []int value of a flag with the given name func (f *FlagSet) GetIntSlice(name string) ([]int, error) { val, err := f.getFlagType(name, "intSlice", intSliceConv) if err != nil { return []int{}, err } return val.([]int), nil } // IntSliceVar defines a intSlice flag with specified name, default value, and usage string. // The argument p points to a []int variable in which to store the value of the flag. func (f *FlagSet) IntSliceVar(p *[]int, name string, value []int, usage string) { f.VarP(newIntSliceValue(value, p), name, "", usage) } // IntSliceVarP is like IntSliceVar, but accepts a shorthand letter that can be used after a single dash. func (f *FlagSet) IntSliceVarP(p *[]int, name, shorthand string, value []int, usage string) { f.VarP(newIntSliceValue(value, p), name, shorthand, usage) } // IntSliceVar defines a int[] flag with specified name, default value, and usage string. // The argument p points to a int[] variable in which to store the value of the flag. func IntSliceVar(p *[]int, name string, value []int, usage string) { CommandLine.VarP(newIntSliceValue(value, p), name, "", usage) } // IntSliceVarP is like IntSliceVar, but accepts a shorthand letter that can be used after a single dash. func IntSliceVarP(p *[]int, name, shorthand string, value []int, usage string) { CommandLine.VarP(newIntSliceValue(value, p), name, shorthand, usage) } // IntSlice defines a []int flag with specified name, default value, and usage string. // The return value is the address of a []int variable that stores the value of the flag. func (f *FlagSet) IntSlice(name string, value []int, usage string) *[]int { p := []int{} f.IntSliceVarP(&p, name, "", value, usage) return &p } // IntSliceP is like IntSlice, but accepts a shorthand letter that can be used after a single dash. func (f *FlagSet) IntSliceP(name, shorthand string, value []int, usage string) *[]int { p := []int{} f.IntSliceVarP(&p, name, shorthand, value, usage) return &p } // IntSlice defines a []int flag with specified name, default value, and usage string. // The return value is the address of a []int variable that stores the value of the flag. func IntSlice(name string, value []int, usage string) *[]int { return CommandLine.IntSliceP(name, "", value, usage) } // IntSliceP is like IntSlice, but accepts a shorthand letter that can be used after a single dash. func IntSliceP(name, shorthand string, value []int, usage string) *[]int { return CommandLine.IntSliceP(name, shorthand, value, usage) } ================================================ FILE: vendor/github.com/spf13/pflag/int_slice_test.go ================================================ // Copyright 2009 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 file. package pflag import ( "fmt" "strconv" "strings" "testing" ) func setUpISFlagSet(isp *[]int) *FlagSet { f := NewFlagSet("test", ContinueOnError) f.IntSliceVar(isp, "is", []int{}, "Command separated list!") return f } func setUpISFlagSetWithDefault(isp *[]int) *FlagSet { f := NewFlagSet("test", ContinueOnError) f.IntSliceVar(isp, "is", []int{0, 1}, "Command separated list!") return f } func TestEmptyIS(t *testing.T) { var is []int f := setUpISFlagSet(&is) err := f.Parse([]string{}) if err != nil { t.Fatal("expected no error; got", err) } getIS, err := f.GetIntSlice("is") if err != nil { t.Fatal("got an error from GetIntSlice():", err) } if len(getIS) != 0 { t.Fatalf("got is %v with len=%d but expected length=0", getIS, len(getIS)) } } func TestIS(t *testing.T) { var is []int f := setUpISFlagSet(&is) vals := []string{"1", "2", "4", "3"} arg := fmt.Sprintf("--is=%s", strings.Join(vals, ",")) err := f.Parse([]string{arg}) if err != nil { t.Fatal("expected no error; got", err) } for i, v := range is { d, err := strconv.Atoi(vals[i]) if err != nil { t.Fatalf("got error: %v", err) } if d != v { t.Fatalf("expected is[%d] to be %s but got: %d", i, vals[i], v) } } getIS, err := f.GetIntSlice("is") if err != nil { t.Fatalf("got error: %v", err) } for i, v := range getIS { d, err := strconv.Atoi(vals[i]) if err != nil { t.Fatalf("got error: %v", err) } if d != v { t.Fatalf("expected is[%d] to be %s but got: %d from GetIntSlice", i, vals[i], v) } } } func TestISDefault(t *testing.T) { var is []int f := setUpISFlagSetWithDefault(&is) vals := []string{"0", "1"} err := f.Parse([]string{}) if err != nil { t.Fatal("expected no error; got", err) } for i, v := range is { d, err := strconv.Atoi(vals[i]) if err != nil { t.Fatalf("got error: %v", err) } if d != v { t.Fatalf("expected is[%d] to be %d but got: %d", i, d, v) } } getIS, err := f.GetIntSlice("is") if err != nil { t.Fatal("got an error from GetIntSlice():", err) } for i, v := range getIS { d, err := strconv.Atoi(vals[i]) if err != nil { t.Fatal("got an error from GetIntSlice():", err) } if d != v { t.Fatalf("expected is[%d] to be %d from GetIntSlice but got: %d", i, d, v) } } } func TestISWithDefault(t *testing.T) { var is []int f := setUpISFlagSetWithDefault(&is) vals := []string{"1", "2"} arg := fmt.Sprintf("--is=%s", strings.Join(vals, ",")) err := f.Parse([]string{arg}) if err != nil { t.Fatal("expected no error; got", err) } for i, v := range is { d, err := strconv.Atoi(vals[i]) if err != nil { t.Fatalf("got error: %v", err) } if d != v { t.Fatalf("expected is[%d] to be %d but got: %d", i, d, v) } } getIS, err := f.GetIntSlice("is") if err != nil { t.Fatal("got an error from GetIntSlice():", err) } for i, v := range getIS { d, err := strconv.Atoi(vals[i]) if err != nil { t.Fatalf("got error: %v", err) } if d != v { t.Fatalf("expected is[%d] to be %d from GetIntSlice but got: %d", i, d, v) } } } func TestISCalledTwice(t *testing.T) { var is []int f := setUpISFlagSet(&is) in := []string{"1,2", "3"} expected := []int{1, 2, 3} argfmt := "--is=%s" arg1 := fmt.Sprintf(argfmt, in[0]) arg2 := fmt.Sprintf(argfmt, in[1]) err := f.Parse([]string{arg1, arg2}) if err != nil { t.Fatal("expected no error; got", err) } for i, v := range is { if expected[i] != v { t.Fatalf("expected is[%d] to be %d but got: %d", i, expected[i], v) } } } ================================================ FILE: vendor/github.com/spf13/pflag/ip.go ================================================ package pflag import ( "fmt" "net" "strings" ) // -- net.IP value type ipValue net.IP func newIPValue(val net.IP, p *net.IP) *ipValue { *p = val return (*ipValue)(p) } func (i *ipValue) String() string { return net.IP(*i).String() } func (i *ipValue) Set(s string) error { ip := net.ParseIP(strings.TrimSpace(s)) if ip == nil { return fmt.Errorf("failed to parse IP: %q", s) } *i = ipValue(ip) return nil } func (i *ipValue) Type() string { return "ip" } func ipConv(sval string) (interface{}, error) { ip := net.ParseIP(sval) if ip != nil { return ip, nil } return nil, fmt.Errorf("invalid string being converted to IP address: %s", sval) } // GetIP return the net.IP value of a flag with the given name func (f *FlagSet) GetIP(name string) (net.IP, error) { val, err := f.getFlagType(name, "ip", ipConv) if err != nil { return nil, err } return val.(net.IP), nil } // IPVar defines an net.IP flag with specified name, default value, and usage string. // The argument p points to an net.IP variable in which to store the value of the flag. func (f *FlagSet) IPVar(p *net.IP, name string, value net.IP, usage string) { f.VarP(newIPValue(value, p), name, "", usage) } // IPVarP is like IPVar, but accepts a shorthand letter that can be used after a single dash. func (f *FlagSet) IPVarP(p *net.IP, name, shorthand string, value net.IP, usage string) { f.VarP(newIPValue(value, p), name, shorthand, usage) } // IPVar defines an net.IP flag with specified name, default value, and usage string. // The argument p points to an net.IP variable in which to store the value of the flag. func IPVar(p *net.IP, name string, value net.IP, usage string) { CommandLine.VarP(newIPValue(value, p), name, "", usage) } // IPVarP is like IPVar, but accepts a shorthand letter that can be used after a single dash. func IPVarP(p *net.IP, name, shorthand string, value net.IP, usage string) { CommandLine.VarP(newIPValue(value, p), name, shorthand, usage) } // IP defines an net.IP flag with specified name, default value, and usage string. // The return value is the address of an net.IP variable that stores the value of the flag. func (f *FlagSet) IP(name string, value net.IP, usage string) *net.IP { p := new(net.IP) f.IPVarP(p, name, "", value, usage) return p } // IPP is like IP, but accepts a shorthand letter that can be used after a single dash. func (f *FlagSet) IPP(name, shorthand string, value net.IP, usage string) *net.IP { p := new(net.IP) f.IPVarP(p, name, shorthand, value, usage) return p } // IP defines an net.IP flag with specified name, default value, and usage string. // The return value is the address of an net.IP variable that stores the value of the flag. func IP(name string, value net.IP, usage string) *net.IP { return CommandLine.IPP(name, "", value, usage) } // IPP is like IP, but accepts a shorthand letter that can be used after a single dash. func IPP(name, shorthand string, value net.IP, usage string) *net.IP { return CommandLine.IPP(name, shorthand, value, usage) } ================================================ FILE: vendor/github.com/spf13/pflag/ip_slice.go ================================================ package pflag import ( "fmt" "io" "net" "strings" ) // -- ipSlice Value type ipSliceValue struct { value *[]net.IP changed bool } func newIPSliceValue(val []net.IP, p *[]net.IP) *ipSliceValue { ipsv := new(ipSliceValue) ipsv.value = p *ipsv.value = val return ipsv } // Set converts, and assigns, the comma-separated IP argument string representation as the []net.IP value of this flag. // If Set is called on a flag that already has a []net.IP assigned, the newly converted values will be appended. func (s *ipSliceValue) Set(val string) error { // remove all quote characters rmQuote := strings.NewReplacer(`"`, "", `'`, "", "`", "") // read flag arguments with CSV parser ipStrSlice, err := readAsCSV(rmQuote.Replace(val)) if err != nil && err != io.EOF { return err } // parse ip values into slice out := make([]net.IP, 0, len(ipStrSlice)) for _, ipStr := range ipStrSlice { ip := net.ParseIP(strings.TrimSpace(ipStr)) if ip == nil { return fmt.Errorf("invalid string being converted to IP address: %s", ipStr) } out = append(out, ip) } if !s.changed { *s.value = out } else { *s.value = append(*s.value, out...) } s.changed = true return nil } // Type returns a string that uniquely represents this flag's type. func (s *ipSliceValue) Type() string { return "ipSlice" } // String defines a "native" format for this net.IP slice flag value. func (s *ipSliceValue) String() string { ipStrSlice := make([]string, len(*s.value)) for i, ip := range *s.value { ipStrSlice[i] = ip.String() } out, _ := writeAsCSV(ipStrSlice) return "[" + out + "]" } func ipSliceConv(val string) (interface{}, error) { val = strings.Trim(val, "[]") // Emtpy string would cause a slice with one (empty) entry if len(val) == 0 { return []net.IP{}, nil } ss := strings.Split(val, ",") out := make([]net.IP, len(ss)) for i, sval := range ss { ip := net.ParseIP(strings.TrimSpace(sval)) if ip == nil { return nil, fmt.Errorf("invalid string being converted to IP address: %s", sval) } out[i] = ip } return out, nil } // GetIPSlice returns the []net.IP value of a flag with the given name func (f *FlagSet) GetIPSlice(name string) ([]net.IP, error) { val, err := f.getFlagType(name, "ipSlice", ipSliceConv) if err != nil { return []net.IP{}, err } return val.([]net.IP), nil } // IPSliceVar defines a ipSlice flag with specified name, default value, and usage string. // The argument p points to a []net.IP variable in which to store the value of the flag. func (f *FlagSet) IPSliceVar(p *[]net.IP, name string, value []net.IP, usage string) { f.VarP(newIPSliceValue(value, p), name, "", usage) } // IPSliceVarP is like IPSliceVar, but accepts a shorthand letter that can be used after a single dash. func (f *FlagSet) IPSliceVarP(p *[]net.IP, name, shorthand string, value []net.IP, usage string) { f.VarP(newIPSliceValue(value, p), name, shorthand, usage) } // IPSliceVar defines a []net.IP flag with specified name, default value, and usage string. // The argument p points to a []net.IP variable in which to store the value of the flag. func IPSliceVar(p *[]net.IP, name string, value []net.IP, usage string) { CommandLine.VarP(newIPSliceValue(value, p), name, "", usage) } // IPSliceVarP is like IPSliceVar, but accepts a shorthand letter that can be used after a single dash. func IPSliceVarP(p *[]net.IP, name, shorthand string, value []net.IP, usage string) { CommandLine.VarP(newIPSliceValue(value, p), name, shorthand, usage) } // IPSlice defines a []net.IP flag with specified name, default value, and usage string. // The return value is the address of a []net.IP variable that stores the value of that flag. func (f *FlagSet) IPSlice(name string, value []net.IP, usage string) *[]net.IP { p := []net.IP{} f.IPSliceVarP(&p, name, "", value, usage) return &p } // IPSliceP is like IPSlice, but accepts a shorthand letter that can be used after a single dash. func (f *FlagSet) IPSliceP(name, shorthand string, value []net.IP, usage string) *[]net.IP { p := []net.IP{} f.IPSliceVarP(&p, name, shorthand, value, usage) return &p } // IPSlice defines a []net.IP flag with specified name, default value, and usage string. // The return value is the address of a []net.IP variable that stores the value of the flag. func IPSlice(name string, value []net.IP, usage string) *[]net.IP { return CommandLine.IPSliceP(name, "", value, usage) } // IPSliceP is like IPSlice, but accepts a shorthand letter that can be used after a single dash. func IPSliceP(name, shorthand string, value []net.IP, usage string) *[]net.IP { return CommandLine.IPSliceP(name, shorthand, value, usage) } ================================================ FILE: vendor/github.com/spf13/pflag/ip_slice_test.go ================================================ package pflag import ( "fmt" "net" "strings" "testing" ) func setUpIPSFlagSet(ipsp *[]net.IP) *FlagSet { f := NewFlagSet("test", ContinueOnError) f.IPSliceVar(ipsp, "ips", []net.IP{}, "Command separated list!") return f } func setUpIPSFlagSetWithDefault(ipsp *[]net.IP) *FlagSet { f := NewFlagSet("test", ContinueOnError) f.IPSliceVar(ipsp, "ips", []net.IP{ net.ParseIP("192.168.1.1"), net.ParseIP("0:0:0:0:0:0:0:1"), }, "Command separated list!") return f } func TestEmptyIP(t *testing.T) { var ips []net.IP f := setUpIPSFlagSet(&ips) err := f.Parse([]string{}) if err != nil { t.Fatal("expected no error; got", err) } getIPS, err := f.GetIPSlice("ips") if err != nil { t.Fatal("got an error from GetIPSlice():", err) } if len(getIPS) != 0 { t.Fatalf("got ips %v with len=%d but expected length=0", getIPS, len(getIPS)) } } func TestIPS(t *testing.T) { var ips []net.IP f := setUpIPSFlagSet(&ips) vals := []string{"192.168.1.1", "10.0.0.1", "0:0:0:0:0:0:0:2"} arg := fmt.Sprintf("--ips=%s", strings.Join(vals, ",")) err := f.Parse([]string{arg}) if err != nil { t.Fatal("expected no error; got", err) } for i, v := range ips { if ip := net.ParseIP(vals[i]); ip == nil { t.Fatalf("invalid string being converted to IP address: %s", vals[i]) } else if !ip.Equal(v) { t.Fatalf("expected ips[%d] to be %s but got: %s from GetIPSlice", i, vals[i], v) } } } func TestIPSDefault(t *testing.T) { var ips []net.IP f := setUpIPSFlagSetWithDefault(&ips) vals := []string{"192.168.1.1", "0:0:0:0:0:0:0:1"} err := f.Parse([]string{}) if err != nil { t.Fatal("expected no error; got", err) } for i, v := range ips { if ip := net.ParseIP(vals[i]); ip == nil { t.Fatalf("invalid string being converted to IP address: %s", vals[i]) } else if !ip.Equal(v) { t.Fatalf("expected ips[%d] to be %s but got: %s", i, vals[i], v) } } getIPS, err := f.GetIPSlice("ips") if err != nil { t.Fatal("got an error from GetIPSlice") } for i, v := range getIPS { if ip := net.ParseIP(vals[i]); ip == nil { t.Fatalf("invalid string being converted to IP address: %s", vals[i]) } else if !ip.Equal(v) { t.Fatalf("expected ips[%d] to be %s but got: %s", i, vals[i], v) } } } func TestIPSWithDefault(t *testing.T) { var ips []net.IP f := setUpIPSFlagSetWithDefault(&ips) vals := []string{"192.168.1.1", "0:0:0:0:0:0:0:1"} arg := fmt.Sprintf("--ips=%s", strings.Join(vals, ",")) err := f.Parse([]string{arg}) if err != nil { t.Fatal("expected no error; got", err) } for i, v := range ips { if ip := net.ParseIP(vals[i]); ip == nil { t.Fatalf("invalid string being converted to IP address: %s", vals[i]) } else if !ip.Equal(v) { t.Fatalf("expected ips[%d] to be %s but got: %s", i, vals[i], v) } } getIPS, err := f.GetIPSlice("ips") if err != nil { t.Fatal("got an error from GetIPSlice") } for i, v := range getIPS { if ip := net.ParseIP(vals[i]); ip == nil { t.Fatalf("invalid string being converted to IP address: %s", vals[i]) } else if !ip.Equal(v) { t.Fatalf("expected ips[%d] to be %s but got: %s", i, vals[i], v) } } } func TestIPSCalledTwice(t *testing.T) { var ips []net.IP f := setUpIPSFlagSet(&ips) in := []string{"192.168.1.2,0:0:0:0:0:0:0:1", "10.0.0.1"} expected := []net.IP{net.ParseIP("192.168.1.2"), net.ParseIP("0:0:0:0:0:0:0:1"), net.ParseIP("10.0.0.1")} argfmt := "ips=%s" arg1 := fmt.Sprintf(argfmt, in[0]) arg2 := fmt.Sprintf(argfmt, in[1]) err := f.Parse([]string{arg1, arg2}) if err != nil { t.Fatal("expected no error; got", err) } for i, v := range ips { if !expected[i].Equal(v) { t.Fatalf("expected ips[%d] to be %s but got: %s", i, expected[i], v) } } } func TestIPSBadQuoting(t *testing.T) { tests := []struct { Want []net.IP FlagArg []string }{ { Want: []net.IP{ net.ParseIP("a4ab:61d:f03e:5d7d:fad7:d4c2:a1a5:568"), net.ParseIP("203.107.49.208"), net.ParseIP("14.57.204.90"), }, FlagArg: []string{ "a4ab:61d:f03e:5d7d:fad7:d4c2:a1a5:568", "203.107.49.208", "14.57.204.90", }, }, { Want: []net.IP{ net.ParseIP("204.228.73.195"), net.ParseIP("86.141.15.94"), }, FlagArg: []string{ "204.228.73.195", "86.141.15.94", }, }, { Want: []net.IP{ net.ParseIP("c70c:db36:3001:890f:c6ea:3f9b:7a39:cc3f"), net.ParseIP("4d17:1d6e:e699:bd7a:88c5:5e7e:ac6a:4472"), }, FlagArg: []string{ "c70c:db36:3001:890f:c6ea:3f9b:7a39:cc3f", "4d17:1d6e:e699:bd7a:88c5:5e7e:ac6a:4472", }, }, { Want: []net.IP{ net.ParseIP("5170:f971:cfac:7be3:512a:af37:952c:bc33"), net.ParseIP("93.21.145.140"), net.ParseIP("2cac:61d3:c5ff:6caf:73e0:1b1a:c336:c1ca"), }, FlagArg: []string{ " 5170:f971:cfac:7be3:512a:af37:952c:bc33 , 93.21.145.140 ", "2cac:61d3:c5ff:6caf:73e0:1b1a:c336:c1ca", }, }, { Want: []net.IP{ net.ParseIP("2e5e:66b2:6441:848:5b74:76ea:574c:3a7b"), net.ParseIP("2e5e:66b2:6441:848:5b74:76ea:574c:3a7b"), net.ParseIP("2e5e:66b2:6441:848:5b74:76ea:574c:3a7b"), net.ParseIP("2e5e:66b2:6441:848:5b74:76ea:574c:3a7b"), }, FlagArg: []string{ `"2e5e:66b2:6441:848:5b74:76ea:574c:3a7b, 2e5e:66b2:6441:848:5b74:76ea:574c:3a7b,2e5e:66b2:6441:848:5b74:76ea:574c:3a7b "`, " 2e5e:66b2:6441:848:5b74:76ea:574c:3a7b"}, }, } for i, test := range tests { var ips []net.IP f := setUpIPSFlagSet(&ips) if err := f.Parse([]string{fmt.Sprintf("--ips=%s", strings.Join(test.FlagArg, ","))}); err != nil { t.Fatalf("flag parsing failed with error: %s\nparsing:\t%#v\nwant:\t\t%s", err, test.FlagArg, test.Want[i]) } for j, b := range ips { if !b.Equal(test.Want[j]) { t.Fatalf("bad value parsed for test %d on net.IP %d:\nwant:\t%s\ngot:\t%s", i, j, test.Want[j], b) } } } } ================================================ FILE: vendor/github.com/spf13/pflag/ip_test.go ================================================ package pflag import ( "fmt" "net" "os" "testing" ) func setUpIP(ip *net.IP) *FlagSet { f := NewFlagSet("test", ContinueOnError) f.IPVar(ip, "address", net.ParseIP("0.0.0.0"), "IP Address") return f } func TestIP(t *testing.T) { testCases := []struct { input string success bool expected string }{ {"0.0.0.0", true, "0.0.0.0"}, {" 0.0.0.0 ", true, "0.0.0.0"}, {"1.2.3.4", true, "1.2.3.4"}, {"127.0.0.1", true, "127.0.0.1"}, {"255.255.255.255", true, "255.255.255.255"}, {"", false, ""}, {"0", false, ""}, {"localhost", false, ""}, {"0.0.0", false, ""}, {"0.0.0.", false, ""}, {"0.0.0.0.", false, ""}, {"0.0.0.256", false, ""}, {"0 . 0 . 0 . 0", false, ""}, } devnull, _ := os.Open(os.DevNull) os.Stderr = devnull for i := range testCases { var addr net.IP f := setUpIP(&addr) tc := &testCases[i] arg := fmt.Sprintf("--address=%s", tc.input) err := f.Parse([]string{arg}) if err != nil && tc.success == true { t.Errorf("expected success, got %q", err) continue } else if err == nil && tc.success == false { t.Errorf("expected failure") continue } else if tc.success { ip, err := f.GetIP("address") if err != nil { t.Errorf("Got error trying to fetch the IP flag: %v", err) } if ip.String() != tc.expected { t.Errorf("expected %q, got %q", tc.expected, ip.String()) } } } } ================================================ FILE: vendor/github.com/spf13/pflag/ipmask.go ================================================ package pflag import ( "fmt" "net" "strconv" ) // -- net.IPMask value type ipMaskValue net.IPMask func newIPMaskValue(val net.IPMask, p *net.IPMask) *ipMaskValue { *p = val return (*ipMaskValue)(p) } func (i *ipMaskValue) String() string { return net.IPMask(*i).String() } func (i *ipMaskValue) Set(s string) error { ip := ParseIPv4Mask(s) if ip == nil { return fmt.Errorf("failed to parse IP mask: %q", s) } *i = ipMaskValue(ip) return nil } func (i *ipMaskValue) Type() string { return "ipMask" } // ParseIPv4Mask written in IP form (e.g. 255.255.255.0). // This function should really belong to the net package. func ParseIPv4Mask(s string) net.IPMask { mask := net.ParseIP(s) if mask == nil { if len(s) != 8 { return nil } // net.IPMask.String() actually outputs things like ffffff00 // so write a horrible parser for that as well :-( m := []int{} for i := 0; i < 4; i++ { b := "0x" + s[2*i:2*i+2] d, err := strconv.ParseInt(b, 0, 0) if err != nil { return nil } m = append(m, int(d)) } s := fmt.Sprintf("%d.%d.%d.%d", m[0], m[1], m[2], m[3]) mask = net.ParseIP(s) if mask == nil { return nil } } return net.IPv4Mask(mask[12], mask[13], mask[14], mask[15]) } func parseIPv4Mask(sval string) (interface{}, error) { mask := ParseIPv4Mask(sval) if mask == nil { return nil, fmt.Errorf("unable to parse %s as net.IPMask", sval) } return mask, nil } // GetIPv4Mask return the net.IPv4Mask value of a flag with the given name func (f *FlagSet) GetIPv4Mask(name string) (net.IPMask, error) { val, err := f.getFlagType(name, "ipMask", parseIPv4Mask) if err != nil { return nil, err } return val.(net.IPMask), nil } // IPMaskVar defines an net.IPMask flag with specified name, default value, and usage string. // The argument p points to an net.IPMask variable in which to store the value of the flag. func (f *FlagSet) IPMaskVar(p *net.IPMask, name string, value net.IPMask, usage string) { f.VarP(newIPMaskValue(value, p), name, "", usage) } // IPMaskVarP is like IPMaskVar, but accepts a shorthand letter that can be used after a single dash. func (f *FlagSet) IPMaskVarP(p *net.IPMask, name, shorthand string, value net.IPMask, usage string) { f.VarP(newIPMaskValue(value, p), name, shorthand, usage) } // IPMaskVar defines an net.IPMask flag with specified name, default value, and usage string. // The argument p points to an net.IPMask variable in which to store the value of the flag. func IPMaskVar(p *net.IPMask, name string, value net.IPMask, usage string) { CommandLine.VarP(newIPMaskValue(value, p), name, "", usage) } // IPMaskVarP is like IPMaskVar, but accepts a shorthand letter that can be used after a single dash. func IPMaskVarP(p *net.IPMask, name, shorthand string, value net.IPMask, usage string) { CommandLine.VarP(newIPMaskValue(value, p), name, shorthand, usage) } // IPMask defines an net.IPMask flag with specified name, default value, and usage string. // The return value is the address of an net.IPMask variable that stores the value of the flag. func (f *FlagSet) IPMask(name string, value net.IPMask, usage string) *net.IPMask { p := new(net.IPMask) f.IPMaskVarP(p, name, "", value, usage) return p } // IPMaskP is like IPMask, but accepts a shorthand letter that can be used after a single dash. func (f *FlagSet) IPMaskP(name, shorthand string, value net.IPMask, usage string) *net.IPMask { p := new(net.IPMask) f.IPMaskVarP(p, name, shorthand, value, usage) return p } // IPMask defines an net.IPMask flag with specified name, default value, and usage string. // The return value is the address of an net.IPMask variable that stores the value of the flag. func IPMask(name string, value net.IPMask, usage string) *net.IPMask { return CommandLine.IPMaskP(name, "", value, usage) } // IPMaskP is like IP, but accepts a shorthand letter that can be used after a single dash. func IPMaskP(name, shorthand string, value net.IPMask, usage string) *net.IPMask { return CommandLine.IPMaskP(name, shorthand, value, usage) } ================================================ FILE: vendor/github.com/spf13/pflag/ipnet.go ================================================ package pflag import ( "fmt" "net" "strings" ) // IPNet adapts net.IPNet for use as a flag. type ipNetValue net.IPNet func (ipnet ipNetValue) String() string { n := net.IPNet(ipnet) return n.String() } func (ipnet *ipNetValue) Set(value string) error { _, n, err := net.ParseCIDR(strings.TrimSpace(value)) if err != nil { return err } *ipnet = ipNetValue(*n) return nil } func (*ipNetValue) Type() string { return "ipNet" } func newIPNetValue(val net.IPNet, p *net.IPNet) *ipNetValue { *p = val return (*ipNetValue)(p) } func ipNetConv(sval string) (interface{}, error) { _, n, err := net.ParseCIDR(strings.TrimSpace(sval)) if err == nil { return *n, nil } return nil, fmt.Errorf("invalid string being converted to IPNet: %s", sval) } // GetIPNet return the net.IPNet value of a flag with the given name func (f *FlagSet) GetIPNet(name string) (net.IPNet, error) { val, err := f.getFlagType(name, "ipNet", ipNetConv) if err != nil { return net.IPNet{}, err } return val.(net.IPNet), nil } // IPNetVar defines an net.IPNet flag with specified name, default value, and usage string. // The argument p points to an net.IPNet variable in which to store the value of the flag. func (f *FlagSet) IPNetVar(p *net.IPNet, name string, value net.IPNet, usage string) { f.VarP(newIPNetValue(value, p), name, "", usage) } // IPNetVarP is like IPNetVar, but accepts a shorthand letter that can be used after a single dash. func (f *FlagSet) IPNetVarP(p *net.IPNet, name, shorthand string, value net.IPNet, usage string) { f.VarP(newIPNetValue(value, p), name, shorthand, usage) } // IPNetVar defines an net.IPNet flag with specified name, default value, and usage string. // The argument p points to an net.IPNet variable in which to store the value of the flag. func IPNetVar(p *net.IPNet, name string, value net.IPNet, usage string) { CommandLine.VarP(newIPNetValue(value, p), name, "", usage) } // IPNetVarP is like IPNetVar, but accepts a shorthand letter that can be used after a single dash. func IPNetVarP(p *net.IPNet, name, shorthand string, value net.IPNet, usage string) { CommandLine.VarP(newIPNetValue(value, p), name, shorthand, usage) } // IPNet defines an net.IPNet flag with specified name, default value, and usage string. // The return value is the address of an net.IPNet variable that stores the value of the flag. func (f *FlagSet) IPNet(name string, value net.IPNet, usage string) *net.IPNet { p := new(net.IPNet) f.IPNetVarP(p, name, "", value, usage) return p } // IPNetP is like IPNet, but accepts a shorthand letter that can be used after a single dash. func (f *FlagSet) IPNetP(name, shorthand string, value net.IPNet, usage string) *net.IPNet { p := new(net.IPNet) f.IPNetVarP(p, name, shorthand, value, usage) return p } // IPNet defines an net.IPNet flag with specified name, default value, and usage string. // The return value is the address of an net.IPNet variable that stores the value of the flag. func IPNet(name string, value net.IPNet, usage string) *net.IPNet { return CommandLine.IPNetP(name, "", value, usage) } // IPNetP is like IPNet, but accepts a shorthand letter that can be used after a single dash. func IPNetP(name, shorthand string, value net.IPNet, usage string) *net.IPNet { return CommandLine.IPNetP(name, shorthand, value, usage) } ================================================ FILE: vendor/github.com/spf13/pflag/ipnet_test.go ================================================ package pflag import ( "fmt" "net" "os" "testing" ) func setUpIPNet(ip *net.IPNet) *FlagSet { f := NewFlagSet("test", ContinueOnError) _, def, _ := net.ParseCIDR("0.0.0.0/0") f.IPNetVar(ip, "address", *def, "IP Address") return f } func TestIPNet(t *testing.T) { testCases := []struct { input string success bool expected string }{ {"0.0.0.0/0", true, "0.0.0.0/0"}, {" 0.0.0.0/0 ", true, "0.0.0.0/0"}, {"1.2.3.4/8", true, "1.0.0.0/8"}, {"127.0.0.1/16", true, "127.0.0.0/16"}, {"255.255.255.255/19", true, "255.255.224.0/19"}, {"255.255.255.255/32", true, "255.255.255.255/32"}, {"", false, ""}, {"/0", false, ""}, {"0", false, ""}, {"0/0", false, ""}, {"localhost/0", false, ""}, {"0.0.0/4", false, ""}, {"0.0.0./8", false, ""}, {"0.0.0.0./12", false, ""}, {"0.0.0.256/16", false, ""}, {"0.0.0.0 /20", false, ""}, {"0.0.0.0/ 24", false, ""}, {"0 . 0 . 0 . 0 / 28", false, ""}, {"0.0.0.0/33", false, ""}, } devnull, _ := os.Open(os.DevNull) os.Stderr = devnull for i := range testCases { var addr net.IPNet f := setUpIPNet(&addr) tc := &testCases[i] arg := fmt.Sprintf("--address=%s", tc.input) err := f.Parse([]string{arg}) if err != nil && tc.success == true { t.Errorf("expected success, got %q", err) continue } else if err == nil && tc.success == false { t.Errorf("expected failure") continue } else if tc.success { ip, err := f.GetIPNet("address") if err != nil { t.Errorf("Got error trying to fetch the IP flag: %v", err) } if ip.String() != tc.expected { t.Errorf("expected %q, got %q", tc.expected, ip.String()) } } } } ================================================ FILE: vendor/github.com/spf13/pflag/string.go ================================================ package pflag // -- string Value type stringValue string func newStringValue(val string, p *string) *stringValue { *p = val return (*stringValue)(p) } func (s *stringValue) Set(val string) error { *s = stringValue(val) return nil } func (s *stringValue) Type() string { return "string" } func (s *stringValue) String() string { return string(*s) } func stringConv(sval string) (interface{}, error) { return sval, nil } // GetString return the string value of a flag with the given name func (f *FlagSet) GetString(name string) (string, error) { val, err := f.getFlagType(name, "string", stringConv) if err != nil { return "", err } return val.(string), nil } // StringVar defines a string flag with specified name, default value, and usage string. // The argument p points to a string variable in which to store the value of the flag. func (f *FlagSet) StringVar(p *string, name string, value string, usage string) { f.VarP(newStringValue(value, p), name, "", usage) } // StringVarP is like StringVar, but accepts a shorthand letter that can be used after a single dash. func (f *FlagSet) StringVarP(p *string, name, shorthand string, value string, usage string) { f.VarP(newStringValue(value, p), name, shorthand, usage) } // StringVar defines a string flag with specified name, default value, and usage string. // The argument p points to a string variable in which to store the value of the flag. func StringVar(p *string, name string, value string, usage string) { CommandLine.VarP(newStringValue(value, p), name, "", usage) } // StringVarP is like StringVar, but accepts a shorthand letter that can be used after a single dash. func StringVarP(p *string, name, shorthand string, value string, usage string) { CommandLine.VarP(newStringValue(value, p), name, shorthand, usage) } // String defines a string flag with specified name, default value, and usage string. // The return value is the address of a string variable that stores the value of the flag. func (f *FlagSet) String(name string, value string, usage string) *string { p := new(string) f.StringVarP(p, name, "", value, usage) return p } // StringP is like String, but accepts a shorthand letter that can be used after a single dash. func (f *FlagSet) StringP(name, shorthand string, value string, usage string) *string { p := new(string) f.StringVarP(p, name, shorthand, value, usage) return p } // String defines a string flag with specified name, default value, and usage string. // The return value is the address of a string variable that stores the value of the flag. func String(name string, value string, usage string) *string { return CommandLine.StringP(name, "", value, usage) } // StringP is like String, but accepts a shorthand letter that can be used after a single dash. func StringP(name, shorthand string, value string, usage string) *string { return CommandLine.StringP(name, shorthand, value, usage) } ================================================ FILE: vendor/github.com/spf13/pflag/string_array.go ================================================ package pflag // -- stringArray Value type stringArrayValue struct { value *[]string changed bool } func newStringArrayValue(val []string, p *[]string) *stringArrayValue { ssv := new(stringArrayValue) ssv.value = p *ssv.value = val return ssv } func (s *stringArrayValue) Set(val string) error { if !s.changed { *s.value = []string{val} s.changed = true } else { *s.value = append(*s.value, val) } return nil } func (s *stringArrayValue) Type() string { return "stringArray" } func (s *stringArrayValue) String() string { str, _ := writeAsCSV(*s.value) return "[" + str + "]" } func stringArrayConv(sval string) (interface{}, error) { sval = sval[1 : len(sval)-1] // An empty string would cause a array with one (empty) string if len(sval) == 0 { return []string{}, nil } return readAsCSV(sval) } // GetStringArray return the []string value of a flag with the given name func (f *FlagSet) GetStringArray(name string) ([]string, error) { val, err := f.getFlagType(name, "stringArray", stringArrayConv) if err != nil { return []string{}, err } return val.([]string), nil } // StringArrayVar defines a string flag with specified name, default value, and usage string. // The argument p points to a []string variable in which to store the values of the multiple flags. // The value of each argument will not try to be separated by comma func (f *FlagSet) StringArrayVar(p *[]string, name string, value []string, usage string) { f.VarP(newStringArrayValue(value, p), name, "", usage) } // StringArrayVarP is like StringArrayVar, but accepts a shorthand letter that can be used after a single dash. func (f *FlagSet) StringArrayVarP(p *[]string, name, shorthand string, value []string, usage string) { f.VarP(newStringArrayValue(value, p), name, shorthand, usage) } // StringArrayVar defines a string flag with specified name, default value, and usage string. // The argument p points to a []string variable in which to store the value of the flag. // The value of each argument will not try to be separated by comma func StringArrayVar(p *[]string, name string, value []string, usage string) { CommandLine.VarP(newStringArrayValue(value, p), name, "", usage) } // StringArrayVarP is like StringArrayVar, but accepts a shorthand letter that can be used after a single dash. func StringArrayVarP(p *[]string, name, shorthand string, value []string, usage string) { CommandLine.VarP(newStringArrayValue(value, p), name, shorthand, usage) } // StringArray defines a string flag with specified name, default value, and usage string. // The return value is the address of a []string variable that stores the value of the flag. // The value of each argument will not try to be separated by comma func (f *FlagSet) StringArray(name string, value []string, usage string) *[]string { p := []string{} f.StringArrayVarP(&p, name, "", value, usage) return &p } // StringArrayP is like StringArray, but accepts a shorthand letter that can be used after a single dash. func (f *FlagSet) StringArrayP(name, shorthand string, value []string, usage string) *[]string { p := []string{} f.StringArrayVarP(&p, name, shorthand, value, usage) return &p } // StringArray defines a string flag with specified name, default value, and usage string. // The return value is the address of a []string variable that stores the value of the flag. // The value of each argument will not try to be separated by comma func StringArray(name string, value []string, usage string) *[]string { return CommandLine.StringArrayP(name, "", value, usage) } // StringArrayP is like StringArray, but accepts a shorthand letter that can be used after a single dash. func StringArrayP(name, shorthand string, value []string, usage string) *[]string { return CommandLine.StringArrayP(name, shorthand, value, usage) } ================================================ FILE: vendor/github.com/spf13/pflag/string_array_test.go ================================================ // Copyright 2009 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 file. package pflag import ( "fmt" "testing" ) func setUpSAFlagSet(sap *[]string) *FlagSet { f := NewFlagSet("test", ContinueOnError) f.StringArrayVar(sap, "sa", []string{}, "Command separated list!") return f } func setUpSAFlagSetWithDefault(sap *[]string) *FlagSet { f := NewFlagSet("test", ContinueOnError) f.StringArrayVar(sap, "sa", []string{"default", "values"}, "Command separated list!") return f } func TestEmptySA(t *testing.T) { var sa []string f := setUpSAFlagSet(&sa) err := f.Parse([]string{}) if err != nil { t.Fatal("expected no error; got", err) } getSA, err := f.GetStringArray("sa") if err != nil { t.Fatal("got an error from GetStringArray():", err) } if len(getSA) != 0 { t.Fatalf("got sa %v with len=%d but expected length=0", getSA, len(getSA)) } } func TestEmptySAValue(t *testing.T) { var sa []string f := setUpSAFlagSet(&sa) err := f.Parse([]string{"--sa="}) if err != nil { t.Fatal("expected no error; got", err) } getSA, err := f.GetStringArray("sa") if err != nil { t.Fatal("got an error from GetStringArray():", err) } if len(getSA) != 0 { t.Fatalf("got sa %v with len=%d but expected length=0", getSA, len(getSA)) } } func TestSADefault(t *testing.T) { var sa []string f := setUpSAFlagSetWithDefault(&sa) vals := []string{"default", "values"} err := f.Parse([]string{}) if err != nil { t.Fatal("expected no error; got", err) } for i, v := range sa { if vals[i] != v { t.Fatalf("expected sa[%d] to be %s but got: %s", i, vals[i], v) } } getSA, err := f.GetStringArray("sa") if err != nil { t.Fatal("got an error from GetStringArray():", err) } for i, v := range getSA { if vals[i] != v { t.Fatalf("expected sa[%d] to be %s from GetStringArray but got: %s", i, vals[i], v) } } } func TestSAWithDefault(t *testing.T) { var sa []string f := setUpSAFlagSetWithDefault(&sa) val := "one" arg := fmt.Sprintf("--sa=%s", val) err := f.Parse([]string{arg}) if err != nil { t.Fatal("expected no error; got", err) } if len(sa) != 1 { t.Fatalf("expected number of values to be %d but %d", 1, len(sa)) } if sa[0] != val { t.Fatalf("expected value to be %s but got: %s", sa[0], val) } getSA, err := f.GetStringArray("sa") if err != nil { t.Fatal("got an error from GetStringArray():", err) } if len(getSA) != 1 { t.Fatalf("expected number of values to be %d but %d", 1, len(getSA)) } if getSA[0] != val { t.Fatalf("expected value to be %s but got: %s", getSA[0], val) } } func TestSACalledTwice(t *testing.T) { var sa []string f := setUpSAFlagSet(&sa) in := []string{"one", "two"} expected := []string{"one", "two"} argfmt := "--sa=%s" arg1 := fmt.Sprintf(argfmt, in[0]) arg2 := fmt.Sprintf(argfmt, in[1]) err := f.Parse([]string{arg1, arg2}) if err != nil { t.Fatal("expected no error; got", err) } if len(expected) != len(sa) { t.Fatalf("expected number of sa to be %d but got: %d", len(expected), len(sa)) } for i, v := range sa { if expected[i] != v { t.Fatalf("expected sa[%d] to be %s but got: %s", i, expected[i], v) } } values, err := f.GetStringArray("sa") if err != nil { t.Fatal("expected no error; got", err) } if len(expected) != len(values) { t.Fatalf("expected number of values to be %d but got: %d", len(expected), len(sa)) } for i, v := range values { if expected[i] != v { t.Fatalf("expected got sa[%d] to be %s but got: %s", i, expected[i], v) } } } func TestSAWithSpecialChar(t *testing.T) { var sa []string f := setUpSAFlagSet(&sa) in := []string{"one,two", `"three"`, `"four,five",six`, "seven eight"} expected := []string{"one,two", `"three"`, `"four,five",six`, "seven eight"} argfmt := "--sa=%s" arg1 := fmt.Sprintf(argfmt, in[0]) arg2 := fmt.Sprintf(argfmt, in[1]) arg3 := fmt.Sprintf(argfmt, in[2]) arg4 := fmt.Sprintf(argfmt, in[3]) err := f.Parse([]string{arg1, arg2, arg3, arg4}) if err != nil { t.Fatal("expected no error; got", err) } if len(expected) != len(sa) { t.Fatalf("expected number of sa to be %d but got: %d", len(expected), len(sa)) } for i, v := range sa { if expected[i] != v { t.Fatalf("expected sa[%d] to be %s but got: %s", i, expected[i], v) } } values, err := f.GetStringArray("sa") if err != nil { t.Fatal("expected no error; got", err) } if len(expected) != len(values) { t.Fatalf("expected number of values to be %d but got: %d", len(expected), len(values)) } for i, v := range values { if expected[i] != v { t.Fatalf("expected got sa[%d] to be %s but got: %s", i, expected[i], v) } } } func TestSAWithSquareBrackets(t *testing.T) { var sa []string f := setUpSAFlagSet(&sa) in := []string{"][]-[", "[a-z]", "[a-z]+"} expected := []string{"][]-[", "[a-z]", "[a-z]+"} argfmt := "--sa=%s" arg1 := fmt.Sprintf(argfmt, in[0]) arg2 := fmt.Sprintf(argfmt, in[1]) arg3 := fmt.Sprintf(argfmt, in[2]) err := f.Parse([]string{arg1, arg2, arg3}) if err != nil { t.Fatal("expected no error; got", err) } if len(expected) != len(sa) { t.Fatalf("expected number of sa to be %d but got: %d", len(expected), len(sa)) } for i, v := range sa { if expected[i] != v { t.Fatalf("expected sa[%d] to be %s but got: %s", i, expected[i], v) } } values, err := f.GetStringArray("sa") if err != nil { t.Fatal("expected no error; got", err) } if len(expected) != len(values) { t.Fatalf("expected number of values to be %d but got: %d", len(expected), len(values)) } for i, v := range values { if expected[i] != v { t.Fatalf("expected got sa[%d] to be %s but got: %s", i, expected[i], v) } } } ================================================ FILE: vendor/github.com/spf13/pflag/string_slice.go ================================================ package pflag import ( "bytes" "encoding/csv" "strings" ) // -- stringSlice Value type stringSliceValue struct { value *[]string changed bool } func newStringSliceValue(val []string, p *[]string) *stringSliceValue { ssv := new(stringSliceValue) ssv.value = p *ssv.value = val return ssv } func readAsCSV(val string) ([]string, error) { if val == "" { return []string{}, nil } stringReader := strings.NewReader(val) csvReader := csv.NewReader(stringReader) return csvReader.Read() } func writeAsCSV(vals []string) (string, error) { b := &bytes.Buffer{} w := csv.NewWriter(b) err := w.Write(vals) if err != nil { return "", err } w.Flush() return strings.TrimSuffix(b.String(), "\n"), nil } func (s *stringSliceValue) Set(val string) error { v, err := readAsCSV(val) if err != nil { return err } if !s.changed { *s.value = v } else { *s.value = append(*s.value, v...) } s.changed = true return nil } func (s *stringSliceValue) Type() string { return "stringSlice" } func (s *stringSliceValue) String() string { str, _ := writeAsCSV(*s.value) return "[" + str + "]" } func stringSliceConv(sval string) (interface{}, error) { sval = sval[1 : len(sval)-1] // An empty string would cause a slice with one (empty) string if len(sval) == 0 { return []string{}, nil } return readAsCSV(sval) } // GetStringSlice return the []string value of a flag with the given name func (f *FlagSet) GetStringSlice(name string) ([]string, error) { val, err := f.getFlagType(name, "stringSlice", stringSliceConv) if err != nil { return []string{}, err } return val.([]string), nil } // StringSliceVar defines a string flag with specified name, default value, and usage string. // The argument p points to a []string variable in which to store the value of the flag. func (f *FlagSet) StringSliceVar(p *[]string, name string, value []string, usage string) { f.VarP(newStringSliceValue(value, p), name, "", usage) } // StringSliceVarP is like StringSliceVar, but accepts a shorthand letter that can be used after a single dash. func (f *FlagSet) StringSliceVarP(p *[]string, name, shorthand string, value []string, usage string) { f.VarP(newStringSliceValue(value, p), name, shorthand, usage) } // StringSliceVar defines a string flag with specified name, default value, and usage string. // The argument p points to a []string variable in which to store the value of the flag. func StringSliceVar(p *[]string, name string, value []string, usage string) { CommandLine.VarP(newStringSliceValue(value, p), name, "", usage) } // StringSliceVarP is like StringSliceVar, but accepts a shorthand letter that can be used after a single dash. func StringSliceVarP(p *[]string, name, shorthand string, value []string, usage string) { CommandLine.VarP(newStringSliceValue(value, p), name, shorthand, usage) } // StringSlice defines a string flag with specified name, default value, and usage string. // The return value is the address of a []string variable that stores the value of the flag. func (f *FlagSet) StringSlice(name string, value []string, usage string) *[]string { p := []string{} f.StringSliceVarP(&p, name, "", value, usage) return &p } // StringSliceP is like StringSlice, but accepts a shorthand letter that can be used after a single dash. func (f *FlagSet) StringSliceP(name, shorthand string, value []string, usage string) *[]string { p := []string{} f.StringSliceVarP(&p, name, shorthand, value, usage) return &p } // StringSlice defines a string flag with specified name, default value, and usage string. // The return value is the address of a []string variable that stores the value of the flag. func StringSlice(name string, value []string, usage string) *[]string { return CommandLine.StringSliceP(name, "", value, usage) } // StringSliceP is like StringSlice, but accepts a shorthand letter that can be used after a single dash. func StringSliceP(name, shorthand string, value []string, usage string) *[]string { return CommandLine.StringSliceP(name, shorthand, value, usage) } ================================================ FILE: vendor/github.com/spf13/pflag/string_slice_test.go ================================================ // Copyright 2009 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 file. package pflag import ( "fmt" "strings" "testing" ) func setUpSSFlagSet(ssp *[]string) *FlagSet { f := NewFlagSet("test", ContinueOnError) f.StringSliceVar(ssp, "ss", []string{}, "Command separated list!") return f } func setUpSSFlagSetWithDefault(ssp *[]string) *FlagSet { f := NewFlagSet("test", ContinueOnError) f.StringSliceVar(ssp, "ss", []string{"default", "values"}, "Command separated list!") return f } func TestEmptySS(t *testing.T) { var ss []string f := setUpSSFlagSet(&ss) err := f.Parse([]string{}) if err != nil { t.Fatal("expected no error; got", err) } getSS, err := f.GetStringSlice("ss") if err != nil { t.Fatal("got an error from GetStringSlice():", err) } if len(getSS) != 0 { t.Fatalf("got ss %v with len=%d but expected length=0", getSS, len(getSS)) } } func TestEmptySSValue(t *testing.T) { var ss []string f := setUpSSFlagSet(&ss) err := f.Parse([]string{"--ss="}) if err != nil { t.Fatal("expected no error; got", err) } getSS, err := f.GetStringSlice("ss") if err != nil { t.Fatal("got an error from GetStringSlice():", err) } if len(getSS) != 0 { t.Fatalf("got ss %v with len=%d but expected length=0", getSS, len(getSS)) } } func TestSS(t *testing.T) { var ss []string f := setUpSSFlagSet(&ss) vals := []string{"one", "two", "4", "3"} arg := fmt.Sprintf("--ss=%s", strings.Join(vals, ",")) err := f.Parse([]string{arg}) if err != nil { t.Fatal("expected no error; got", err) } for i, v := range ss { if vals[i] != v { t.Fatalf("expected ss[%d] to be %s but got: %s", i, vals[i], v) } } getSS, err := f.GetStringSlice("ss") if err != nil { t.Fatal("got an error from GetStringSlice():", err) } for i, v := range getSS { if vals[i] != v { t.Fatalf("expected ss[%d] to be %s from GetStringSlice but got: %s", i, vals[i], v) } } } func TestSSDefault(t *testing.T) { var ss []string f := setUpSSFlagSetWithDefault(&ss) vals := []string{"default", "values"} err := f.Parse([]string{}) if err != nil { t.Fatal("expected no error; got", err) } for i, v := range ss { if vals[i] != v { t.Fatalf("expected ss[%d] to be %s but got: %s", i, vals[i], v) } } getSS, err := f.GetStringSlice("ss") if err != nil { t.Fatal("got an error from GetStringSlice():", err) } for i, v := range getSS { if vals[i] != v { t.Fatalf("expected ss[%d] to be %s from GetStringSlice but got: %s", i, vals[i], v) } } } func TestSSWithDefault(t *testing.T) { var ss []string f := setUpSSFlagSetWithDefault(&ss) vals := []string{"one", "two", "4", "3"} arg := fmt.Sprintf("--ss=%s", strings.Join(vals, ",")) err := f.Parse([]string{arg}) if err != nil { t.Fatal("expected no error; got", err) } for i, v := range ss { if vals[i] != v { t.Fatalf("expected ss[%d] to be %s but got: %s", i, vals[i], v) } } getSS, err := f.GetStringSlice("ss") if err != nil { t.Fatal("got an error from GetStringSlice():", err) } for i, v := range getSS { if vals[i] != v { t.Fatalf("expected ss[%d] to be %s from GetStringSlice but got: %s", i, vals[i], v) } } } func TestSSCalledTwice(t *testing.T) { var ss []string f := setUpSSFlagSet(&ss) in := []string{"one,two", "three"} expected := []string{"one", "two", "three"} argfmt := "--ss=%s" arg1 := fmt.Sprintf(argfmt, in[0]) arg2 := fmt.Sprintf(argfmt, in[1]) err := f.Parse([]string{arg1, arg2}) if err != nil { t.Fatal("expected no error; got", err) } if len(expected) != len(ss) { t.Fatalf("expected number of ss to be %d but got: %d", len(expected), len(ss)) } for i, v := range ss { if expected[i] != v { t.Fatalf("expected ss[%d] to be %s but got: %s", i, expected[i], v) } } values, err := f.GetStringSlice("ss") if err != nil { t.Fatal("expected no error; got", err) } if len(expected) != len(values) { t.Fatalf("expected number of values to be %d but got: %d", len(expected), len(ss)) } for i, v := range values { if expected[i] != v { t.Fatalf("expected got ss[%d] to be %s but got: %s", i, expected[i], v) } } } func TestSSWithComma(t *testing.T) { var ss []string f := setUpSSFlagSet(&ss) in := []string{`"one,two"`, `"three"`, `"four,five",six`} expected := []string{"one,two", "three", "four,five", "six"} argfmt := "--ss=%s" arg1 := fmt.Sprintf(argfmt, in[0]) arg2 := fmt.Sprintf(argfmt, in[1]) arg3 := fmt.Sprintf(argfmt, in[2]) err := f.Parse([]string{arg1, arg2, arg3}) if err != nil { t.Fatal("expected no error; got", err) } if len(expected) != len(ss) { t.Fatalf("expected number of ss to be %d but got: %d", len(expected), len(ss)) } for i, v := range ss { if expected[i] != v { t.Fatalf("expected ss[%d] to be %s but got: %s", i, expected[i], v) } } values, err := f.GetStringSlice("ss") if err != nil { t.Fatal("expected no error; got", err) } if len(expected) != len(values) { t.Fatalf("expected number of values to be %d but got: %d", len(expected), len(values)) } for i, v := range values { if expected[i] != v { t.Fatalf("expected got ss[%d] to be %s but got: %s", i, expected[i], v) } } } func TestSSWithSquareBrackets(t *testing.T) { var ss []string f := setUpSSFlagSet(&ss) in := []string{`"[a-z]"`, `"[a-z]+"`} expected := []string{"[a-z]", "[a-z]+"} argfmt := "--ss=%s" arg1 := fmt.Sprintf(argfmt, in[0]) arg2 := fmt.Sprintf(argfmt, in[1]) err := f.Parse([]string{arg1, arg2}) if err != nil { t.Fatal("expected no error; got", err) } if len(expected) != len(ss) { t.Fatalf("expected number of ss to be %d but got: %d", len(expected), len(ss)) } for i, v := range ss { if expected[i] != v { t.Fatalf("expected ss[%d] to be %s but got: %s", i, expected[i], v) } } values, err := f.GetStringSlice("ss") if err != nil { t.Fatal("expected no error; got", err) } if len(expected) != len(values) { t.Fatalf("expected number of values to be %d but got: %d", len(expected), len(values)) } for i, v := range values { if expected[i] != v { t.Fatalf("expected got ss[%d] to be %s but got: %s", i, expected[i], v) } } } ================================================ FILE: vendor/github.com/spf13/pflag/uint.go ================================================ package pflag import "strconv" // -- uint Value type uintValue uint func newUintValue(val uint, p *uint) *uintValue { *p = val return (*uintValue)(p) } func (i *uintValue) Set(s string) error { v, err := strconv.ParseUint(s, 0, 64) *i = uintValue(v) return err } func (i *uintValue) Type() string { return "uint" } func (i *uintValue) String() string { return strconv.FormatUint(uint64(*i), 10) } func uintConv(sval string) (interface{}, error) { v, err := strconv.ParseUint(sval, 0, 0) if err != nil { return 0, err } return uint(v), nil } // GetUint return the uint value of a flag with the given name func (f *FlagSet) GetUint(name string) (uint, error) { val, err := f.getFlagType(name, "uint", uintConv) if err != nil { return 0, err } return val.(uint), nil } // UintVar defines a uint flag with specified name, default value, and usage string. // The argument p points to a uint variable in which to store the value of the flag. func (f *FlagSet) UintVar(p *uint, name string, value uint, usage string) { f.VarP(newUintValue(value, p), name, "", usage) } // UintVarP is like UintVar, but accepts a shorthand letter that can be used after a single dash. func (f *FlagSet) UintVarP(p *uint, name, shorthand string, value uint, usage string) { f.VarP(newUintValue(value, p), name, shorthand, usage) } // UintVar defines a uint flag with specified name, default value, and usage string. // The argument p points to a uint variable in which to store the value of the flag. func UintVar(p *uint, name string, value uint, usage string) { CommandLine.VarP(newUintValue(value, p), name, "", usage) } // UintVarP is like UintVar, but accepts a shorthand letter that can be used after a single dash. func UintVarP(p *uint, name, shorthand string, value uint, usage string) { CommandLine.VarP(newUintValue(value, p), name, shorthand, usage) } // Uint defines a uint flag with specified name, default value, and usage string. // The return value is the address of a uint variable that stores the value of the flag. func (f *FlagSet) Uint(name string, value uint, usage string) *uint { p := new(uint) f.UintVarP(p, name, "", value, usage) return p } // UintP is like Uint, but accepts a shorthand letter that can be used after a single dash. func (f *FlagSet) UintP(name, shorthand string, value uint, usage string) *uint { p := new(uint) f.UintVarP(p, name, shorthand, value, usage) return p } // Uint defines a uint flag with specified name, default value, and usage string. // The return value is the address of a uint variable that stores the value of the flag. func Uint(name string, value uint, usage string) *uint { return CommandLine.UintP(name, "", value, usage) } // UintP is like Uint, but accepts a shorthand letter that can be used after a single dash. func UintP(name, shorthand string, value uint, usage string) *uint { return CommandLine.UintP(name, shorthand, value, usage) } ================================================ FILE: vendor/github.com/spf13/pflag/uint16.go ================================================ package pflag import "strconv" // -- uint16 value type uint16Value uint16 func newUint16Value(val uint16, p *uint16) *uint16Value { *p = val return (*uint16Value)(p) } func (i *uint16Value) Set(s string) error { v, err := strconv.ParseUint(s, 0, 16) *i = uint16Value(v) return err } func (i *uint16Value) Type() string { return "uint16" } func (i *uint16Value) String() string { return strconv.FormatUint(uint64(*i), 10) } func uint16Conv(sval string) (interface{}, error) { v, err := strconv.ParseUint(sval, 0, 16) if err != nil { return 0, err } return uint16(v), nil } // GetUint16 return the uint16 value of a flag with the given name func (f *FlagSet) GetUint16(name string) (uint16, error) { val, err := f.getFlagType(name, "uint16", uint16Conv) if err != nil { return 0, err } return val.(uint16), nil } // Uint16Var defines a uint flag with specified name, default value, and usage string. // The argument p points to a uint variable in which to store the value of the flag. func (f *FlagSet) Uint16Var(p *uint16, name string, value uint16, usage string) { f.VarP(newUint16Value(value, p), name, "", usage) } // Uint16VarP is like Uint16Var, but accepts a shorthand letter that can be used after a single dash. func (f *FlagSet) Uint16VarP(p *uint16, name, shorthand string, value uint16, usage string) { f.VarP(newUint16Value(value, p), name, shorthand, usage) } // Uint16Var defines a uint flag with specified name, default value, and usage string. // The argument p points to a uint variable in which to store the value of the flag. func Uint16Var(p *uint16, name string, value uint16, usage string) { CommandLine.VarP(newUint16Value(value, p), name, "", usage) } // Uint16VarP is like Uint16Var, but accepts a shorthand letter that can be used after a single dash. func Uint16VarP(p *uint16, name, shorthand string, value uint16, usage string) { CommandLine.VarP(newUint16Value(value, p), name, shorthand, usage) } // Uint16 defines a uint flag with specified name, default value, and usage string. // The return value is the address of a uint variable that stores the value of the flag. func (f *FlagSet) Uint16(name string, value uint16, usage string) *uint16 { p := new(uint16) f.Uint16VarP(p, name, "", value, usage) return p } // Uint16P is like Uint16, but accepts a shorthand letter that can be used after a single dash. func (f *FlagSet) Uint16P(name, shorthand string, value uint16, usage string) *uint16 { p := new(uint16) f.Uint16VarP(p, name, shorthand, value, usage) return p } // Uint16 defines a uint flag with specified name, default value, and usage string. // The return value is the address of a uint variable that stores the value of the flag. func Uint16(name string, value uint16, usage string) *uint16 { return CommandLine.Uint16P(name, "", value, usage) } // Uint16P is like Uint16, but accepts a shorthand letter that can be used after a single dash. func Uint16P(name, shorthand string, value uint16, usage string) *uint16 { return CommandLine.Uint16P(name, shorthand, value, usage) } ================================================ FILE: vendor/github.com/spf13/pflag/uint32.go ================================================ package pflag import "strconv" // -- uint32 value type uint32Value uint32 func newUint32Value(val uint32, p *uint32) *uint32Value { *p = val return (*uint32Value)(p) } func (i *uint32Value) Set(s string) error { v, err := strconv.ParseUint(s, 0, 32) *i = uint32Value(v) return err } func (i *uint32Value) Type() string { return "uint32" } func (i *uint32Value) String() string { return strconv.FormatUint(uint64(*i), 10) } func uint32Conv(sval string) (interface{}, error) { v, err := strconv.ParseUint(sval, 0, 32) if err != nil { return 0, err } return uint32(v), nil } // GetUint32 return the uint32 value of a flag with the given name func (f *FlagSet) GetUint32(name string) (uint32, error) { val, err := f.getFlagType(name, "uint32", uint32Conv) if err != nil { return 0, err } return val.(uint32), nil } // Uint32Var defines a uint32 flag with specified name, default value, and usage string. // The argument p points to a uint32 variable in which to store the value of the flag. func (f *FlagSet) Uint32Var(p *uint32, name string, value uint32, usage string) { f.VarP(newUint32Value(value, p), name, "", usage) } // Uint32VarP is like Uint32Var, but accepts a shorthand letter that can be used after a single dash. func (f *FlagSet) Uint32VarP(p *uint32, name, shorthand string, value uint32, usage string) { f.VarP(newUint32Value(value, p), name, shorthand, usage) } // Uint32Var defines a uint32 flag with specified name, default value, and usage string. // The argument p points to a uint32 variable in which to store the value of the flag. func Uint32Var(p *uint32, name string, value uint32, usage string) { CommandLine.VarP(newUint32Value(value, p), name, "", usage) } // Uint32VarP is like Uint32Var, but accepts a shorthand letter that can be used after a single dash. func Uint32VarP(p *uint32, name, shorthand string, value uint32, usage string) { CommandLine.VarP(newUint32Value(value, p), name, shorthand, usage) } // Uint32 defines a uint32 flag with specified name, default value, and usage string. // The return value is the address of a uint32 variable that stores the value of the flag. func (f *FlagSet) Uint32(name string, value uint32, usage string) *uint32 { p := new(uint32) f.Uint32VarP(p, name, "", value, usage) return p } // Uint32P is like Uint32, but accepts a shorthand letter that can be used after a single dash. func (f *FlagSet) Uint32P(name, shorthand string, value uint32, usage string) *uint32 { p := new(uint32) f.Uint32VarP(p, name, shorthand, value, usage) return p } // Uint32 defines a uint32 flag with specified name, default value, and usage string. // The return value is the address of a uint32 variable that stores the value of the flag. func Uint32(name string, value uint32, usage string) *uint32 { return CommandLine.Uint32P(name, "", value, usage) } // Uint32P is like Uint32, but accepts a shorthand letter that can be used after a single dash. func Uint32P(name, shorthand string, value uint32, usage string) *uint32 { return CommandLine.Uint32P(name, shorthand, value, usage) } ================================================ FILE: vendor/github.com/spf13/pflag/uint64.go ================================================ package pflag import "strconv" // -- uint64 Value type uint64Value uint64 func newUint64Value(val uint64, p *uint64) *uint64Value { *p = val return (*uint64Value)(p) } func (i *uint64Value) Set(s string) error { v, err := strconv.ParseUint(s, 0, 64) *i = uint64Value(v) return err } func (i *uint64Value) Type() string { return "uint64" } func (i *uint64Value) String() string { return strconv.FormatUint(uint64(*i), 10) } func uint64Conv(sval string) (interface{}, error) { v, err := strconv.ParseUint(sval, 0, 64) if err != nil { return 0, err } return uint64(v), nil } // GetUint64 return the uint64 value of a flag with the given name func (f *FlagSet) GetUint64(name string) (uint64, error) { val, err := f.getFlagType(name, "uint64", uint64Conv) if err != nil { return 0, err } return val.(uint64), nil } // Uint64Var defines a uint64 flag with specified name, default value, and usage string. // The argument p points to a uint64 variable in which to store the value of the flag. func (f *FlagSet) Uint64Var(p *uint64, name string, value uint64, usage string) { f.VarP(newUint64Value(value, p), name, "", usage) } // Uint64VarP is like Uint64Var, but accepts a shorthand letter that can be used after a single dash. func (f *FlagSet) Uint64VarP(p *uint64, name, shorthand string, value uint64, usage string) { f.VarP(newUint64Value(value, p), name, shorthand, usage) } // Uint64Var defines a uint64 flag with specified name, default value, and usage string. // The argument p points to a uint64 variable in which to store the value of the flag. func Uint64Var(p *uint64, name string, value uint64, usage string) { CommandLine.VarP(newUint64Value(value, p), name, "", usage) } // Uint64VarP is like Uint64Var, but accepts a shorthand letter that can be used after a single dash. func Uint64VarP(p *uint64, name, shorthand string, value uint64, usage string) { CommandLine.VarP(newUint64Value(value, p), name, shorthand, usage) } // Uint64 defines a uint64 flag with specified name, default value, and usage string. // The return value is the address of a uint64 variable that stores the value of the flag. func (f *FlagSet) Uint64(name string, value uint64, usage string) *uint64 { p := new(uint64) f.Uint64VarP(p, name, "", value, usage) return p } // Uint64P is like Uint64, but accepts a shorthand letter that can be used after a single dash. func (f *FlagSet) Uint64P(name, shorthand string, value uint64, usage string) *uint64 { p := new(uint64) f.Uint64VarP(p, name, shorthand, value, usage) return p } // Uint64 defines a uint64 flag with specified name, default value, and usage string. // The return value is the address of a uint64 variable that stores the value of the flag. func Uint64(name string, value uint64, usage string) *uint64 { return CommandLine.Uint64P(name, "", value, usage) } // Uint64P is like Uint64, but accepts a shorthand letter that can be used after a single dash. func Uint64P(name, shorthand string, value uint64, usage string) *uint64 { return CommandLine.Uint64P(name, shorthand, value, usage) } ================================================ FILE: vendor/github.com/spf13/pflag/uint8.go ================================================ package pflag import "strconv" // -- uint8 Value type uint8Value uint8 func newUint8Value(val uint8, p *uint8) *uint8Value { *p = val return (*uint8Value)(p) } func (i *uint8Value) Set(s string) error { v, err := strconv.ParseUint(s, 0, 8) *i = uint8Value(v) return err } func (i *uint8Value) Type() string { return "uint8" } func (i *uint8Value) String() string { return strconv.FormatUint(uint64(*i), 10) } func uint8Conv(sval string) (interface{}, error) { v, err := strconv.ParseUint(sval, 0, 8) if err != nil { return 0, err } return uint8(v), nil } // GetUint8 return the uint8 value of a flag with the given name func (f *FlagSet) GetUint8(name string) (uint8, error) { val, err := f.getFlagType(name, "uint8", uint8Conv) if err != nil { return 0, err } return val.(uint8), nil } // Uint8Var defines a uint8 flag with specified name, default value, and usage string. // The argument p points to a uint8 variable in which to store the value of the flag. func (f *FlagSet) Uint8Var(p *uint8, name string, value uint8, usage string) { f.VarP(newUint8Value(value, p), name, "", usage) } // Uint8VarP is like Uint8Var, but accepts a shorthand letter that can be used after a single dash. func (f *FlagSet) Uint8VarP(p *uint8, name, shorthand string, value uint8, usage string) { f.VarP(newUint8Value(value, p), name, shorthand, usage) } // Uint8Var defines a uint8 flag with specified name, default value, and usage string. // The argument p points to a uint8 variable in which to store the value of the flag. func Uint8Var(p *uint8, name string, value uint8, usage string) { CommandLine.VarP(newUint8Value(value, p), name, "", usage) } // Uint8VarP is like Uint8Var, but accepts a shorthand letter that can be used after a single dash. func Uint8VarP(p *uint8, name, shorthand string, value uint8, usage string) { CommandLine.VarP(newUint8Value(value, p), name, shorthand, usage) } // Uint8 defines a uint8 flag with specified name, default value, and usage string. // The return value is the address of a uint8 variable that stores the value of the flag. func (f *FlagSet) Uint8(name string, value uint8, usage string) *uint8 { p := new(uint8) f.Uint8VarP(p, name, "", value, usage) return p } // Uint8P is like Uint8, but accepts a shorthand letter that can be used after a single dash. func (f *FlagSet) Uint8P(name, shorthand string, value uint8, usage string) *uint8 { p := new(uint8) f.Uint8VarP(p, name, shorthand, value, usage) return p } // Uint8 defines a uint8 flag with specified name, default value, and usage string. // The return value is the address of a uint8 variable that stores the value of the flag. func Uint8(name string, value uint8, usage string) *uint8 { return CommandLine.Uint8P(name, "", value, usage) } // Uint8P is like Uint8, but accepts a shorthand letter that can be used after a single dash. func Uint8P(name, shorthand string, value uint8, usage string) *uint8 { return CommandLine.Uint8P(name, shorthand, value, usage) } ================================================ FILE: vendor/github.com/spf13/pflag/uint_slice.go ================================================ package pflag import ( "fmt" "strconv" "strings" ) // -- uintSlice Value type uintSliceValue struct { value *[]uint changed bool } func newUintSliceValue(val []uint, p *[]uint) *uintSliceValue { uisv := new(uintSliceValue) uisv.value = p *uisv.value = val return uisv } func (s *uintSliceValue) Set(val string) error { ss := strings.Split(val, ",") out := make([]uint, len(ss)) for i, d := range ss { u, err := strconv.ParseUint(d, 10, 0) if err != nil { return err } out[i] = uint(u) } if !s.changed { *s.value = out } else { *s.value = append(*s.value, out...) } s.changed = true return nil } func (s *uintSliceValue) Type() string { return "uintSlice" } func (s *uintSliceValue) String() string { out := make([]string, len(*s.value)) for i, d := range *s.value { out[i] = fmt.Sprintf("%d", d) } return "[" + strings.Join(out, ",") + "]" } func uintSliceConv(val string) (interface{}, error) { val = strings.Trim(val, "[]") // Empty string would cause a slice with one (empty) entry if len(val) == 0 { return []uint{}, nil } ss := strings.Split(val, ",") out := make([]uint, len(ss)) for i, d := range ss { u, err := strconv.ParseUint(d, 10, 0) if err != nil { return nil, err } out[i] = uint(u) } return out, nil } // GetUintSlice returns the []uint value of a flag with the given name. func (f *FlagSet) GetUintSlice(name string) ([]uint, error) { val, err := f.getFlagType(name, "uintSlice", uintSliceConv) if err != nil { return []uint{}, err } return val.([]uint), nil } // UintSliceVar defines a uintSlice flag with specified name, default value, and usage string. // The argument p points to a []uint variable in which to store the value of the flag. func (f *FlagSet) UintSliceVar(p *[]uint, name string, value []uint, usage string) { f.VarP(newUintSliceValue(value, p), name, "", usage) } // UintSliceVarP is like UintSliceVar, but accepts a shorthand letter that can be used after a single dash. func (f *FlagSet) UintSliceVarP(p *[]uint, name, shorthand string, value []uint, usage string) { f.VarP(newUintSliceValue(value, p), name, shorthand, usage) } // UintSliceVar defines a uint[] flag with specified name, default value, and usage string. // The argument p points to a uint[] variable in which to store the value of the flag. func UintSliceVar(p *[]uint, name string, value []uint, usage string) { CommandLine.VarP(newUintSliceValue(value, p), name, "", usage) } // UintSliceVarP is like the UintSliceVar, but accepts a shorthand letter that can be used after a single dash. func UintSliceVarP(p *[]uint, name, shorthand string, value []uint, usage string) { CommandLine.VarP(newUintSliceValue(value, p), name, shorthand, usage) } // UintSlice defines a []uint flag with specified name, default value, and usage string. // The return value is the address of a []uint variable that stores the value of the flag. func (f *FlagSet) UintSlice(name string, value []uint, usage string) *[]uint { p := []uint{} f.UintSliceVarP(&p, name, "", value, usage) return &p } // UintSliceP is like UintSlice, but accepts a shorthand letter that can be used after a single dash. func (f *FlagSet) UintSliceP(name, shorthand string, value []uint, usage string) *[]uint { p := []uint{} f.UintSliceVarP(&p, name, shorthand, value, usage) return &p } // UintSlice defines a []uint flag with specified name, default value, and usage string. // The return value is the address of a []uint variable that stores the value of the flag. func UintSlice(name string, value []uint, usage string) *[]uint { return CommandLine.UintSliceP(name, "", value, usage) } // UintSliceP is like UintSlice, but accepts a shorthand letter that can be used after a single dash. func UintSliceP(name, shorthand string, value []uint, usage string) *[]uint { return CommandLine.UintSliceP(name, shorthand, value, usage) } ================================================ FILE: vendor/github.com/spf13/pflag/uint_slice_test.go ================================================ package pflag import ( "fmt" "strconv" "strings" "testing" ) func setUpUISFlagSet(uisp *[]uint) *FlagSet { f := NewFlagSet("test", ContinueOnError) f.UintSliceVar(uisp, "uis", []uint{}, "Command separated list!") return f } func setUpUISFlagSetWithDefault(uisp *[]uint) *FlagSet { f := NewFlagSet("test", ContinueOnError) f.UintSliceVar(uisp, "uis", []uint{0, 1}, "Command separated list!") return f } func TestEmptyUIS(t *testing.T) { var uis []uint f := setUpUISFlagSet(&uis) err := f.Parse([]string{}) if err != nil { t.Fatal("expected no error; got", err) } getUIS, err := f.GetUintSlice("uis") if err != nil { t.Fatal("got an error from GetUintSlice():", err) } if len(getUIS) != 0 { t.Fatalf("got is %v with len=%d but expected length=0", getUIS, len(getUIS)) } } func TestUIS(t *testing.T) { var uis []uint f := setUpUISFlagSet(&uis) vals := []string{"1", "2", "4", "3"} arg := fmt.Sprintf("--uis=%s", strings.Join(vals, ",")) err := f.Parse([]string{arg}) if err != nil { t.Fatal("expected no error; got", err) } for i, v := range uis { u, err := strconv.ParseUint(vals[i], 10, 0) if err != nil { t.Fatalf("got error: %v", err) } if uint(u) != v { t.Fatalf("expected uis[%d] to be %s but got %d", i, vals[i], v) } } getUIS, err := f.GetUintSlice("uis") if err != nil { t.Fatalf("got error: %v", err) } for i, v := range getUIS { u, err := strconv.ParseUint(vals[i], 10, 0) if err != nil { t.Fatalf("got error: %v", err) } if uint(u) != v { t.Fatalf("expected uis[%d] to be %s but got: %d from GetUintSlice", i, vals[i], v) } } } func TestUISDefault(t *testing.T) { var uis []uint f := setUpUISFlagSetWithDefault(&uis) vals := []string{"0", "1"} err := f.Parse([]string{}) if err != nil { t.Fatal("expected no error; got", err) } for i, v := range uis { u, err := strconv.ParseUint(vals[i], 10, 0) if err != nil { t.Fatalf("got error: %v", err) } if uint(u) != v { t.Fatalf("expect uis[%d] to be %d but got: %d", i, u, v) } } getUIS, err := f.GetUintSlice("uis") if err != nil { t.Fatal("got an error from GetUintSlice():", err) } for i, v := range getUIS { u, err := strconv.ParseUint(vals[i], 10, 0) if err != nil { t.Fatal("got an error from GetIntSlice():", err) } if uint(u) != v { t.Fatalf("expected uis[%d] to be %d from GetUintSlice but got: %d", i, u, v) } } } func TestUISWithDefault(t *testing.T) { var uis []uint f := setUpUISFlagSetWithDefault(&uis) vals := []string{"1", "2"} arg := fmt.Sprintf("--uis=%s", strings.Join(vals, ",")) err := f.Parse([]string{arg}) if err != nil { t.Fatal("expected no error; got", err) } for i, v := range uis { u, err := strconv.ParseUint(vals[i], 10, 0) if err != nil { t.Fatalf("got error: %v", err) } if uint(u) != v { t.Fatalf("expected uis[%d] to be %d from GetUintSlice but got: %d", i, u, v) } } getUIS, err := f.GetUintSlice("uis") if err != nil { t.Fatal("got an error from GetUintSlice():", err) } for i, v := range getUIS { u, err := strconv.ParseUint(vals[i], 10, 0) if err != nil { t.Fatalf("got error: %v", err) } if uint(u) != v { t.Fatalf("expected uis[%d] to be %d from GetUintSlice but got: %d", i, u, v) } } } func TestUISCalledTwice(t *testing.T) { var uis []uint f := setUpUISFlagSet(&uis) in := []string{"1,2", "3"} expected := []int{1, 2, 3} argfmt := "--uis=%s" arg1 := fmt.Sprintf(argfmt, in[0]) arg2 := fmt.Sprintf(argfmt, in[1]) err := f.Parse([]string{arg1, arg2}) if err != nil { t.Fatal("expected no error; got", err) } for i, v := range uis { if uint(expected[i]) != v { t.Fatalf("expected uis[%d] to be %d but got: %d", i, expected[i], v) } } } ================================================ FILE: vendor/github.com/zmb3/spotify/.travis.yml ================================================ language: go go: - 1.8 - 1.9 ================================================ FILE: vendor/github.com/zmb3/spotify/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright {yyyy} {name of copyright owner} Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: vendor/github.com/zmb3/spotify/README.md ================================================ Spotify ======= [![GoDoc](https://godoc.org/github.com/zmb3/spotify?status.svg)](http://godoc.org/github.com/zmb3/spotify) [![Build status](https://ci.appveyor.com/api/projects/status/1nr9vv0jqq438nj2?svg=true)](https://ci.appveyor.com/project/zmb3/spotify) [![Build Status](https://travis-ci.org/zmb3/spotify.svg)](https://travis-ci.org/zmb3/spotify) This is a Go wrapper for working with Spotify's [Web API](https://developer.spotify.com/web-api/). It aims to support every task listed in the Web API Endpoint Reference, located [here](https://developer.spotify.com/web-api/endpoint-reference/). By using this library you agree to Spotify's [Developer Terms of Use](https://developer.spotify.com/developer-terms-of-use/). ## Installation To install the library, simply `go get github.com/zmb3/spotify` ## Authentication Spotify uses OAuth2 for authentication and authorization. As of May 29, 2017 _all_ Web API endpoints require an access token. You can authenticate using a client credentials flow, but this does not provide any authorization to access a user's private data. For most use cases, you'll want to use the authorization code flow. This package includes an `Authenticator` type to handle the details for you. Start by registering your application at the following page: https://developer.spotify.com/my-applications/. You'll get a __client ID__ and __secret key__ for your application. An easy way to provide this data to your application is to set the SPOTIFY_ID and SPOTIFY_SECRET environment variables. If you choose not to use environment variables, you can provide this data manually. ````Go // the redirect URL must be an exact match of a URL you've registered for your application // scopes determine which permissions the user is prompted to authorize auth := spotify.NewAuthenticator(redirectURL, spotify.ScopeUserReadPrivate) // if you didn't store your ID and secret key in the specified environment variables, // you can set them manually here auth.SetAuthInfo(clientID, secretKey) // get the user to this URL - how you do that is up to you // you should specify a unique state string to identify the session url := auth.AuthURL(state) // the user will eventually be redirected back to your redirect URL // typically you'll have a handler set up like the following: func redirectHandler(w http.ResponseWriter, r *http.Request) { // use the same state string here that you used to generate the URL token, err := auth.Token(state, r) if err != nil { http.Error(w, "Couldn't get token", http.StatusNotFound) return } // create a client using the specified token client := auth.NewClient(token) // the client can now be used to make authenticated requests } ```` You may find the following resources useful: 1. Spotify's Web API Authorization Guide: https://developer.spotify.com/web-api/authorization-guide/ 2. Go's OAuth2 package: https://godoc.org/golang.org/x/oauth2/google ## Helpful Hints ### Optional Parameters Many of the functions in this package come in two forms - a simple version that omits optional parameters and uses reasonable defaults, and a more sophisticated version that accepts additional parameters. The latter is suffixed with `Opt` to indicate that it accepts some optional parameters. ### Automatic Retries The API will throttle your requests if you are sending them too rapidly. The client can be configured to wait and re-attempt the request. To enable this, set the `AutoRetry` field on the `Client` struct to `true`. For more information, see Spotify [rate-limits](https://developer.spotify.com/web-api/user-guide/#rate-limiting). ## API Examples Examples of the API can be found in the [examples](examples) directory. You may find tools such as [Spotify's Web API Console](https://developer.spotify.com/web-api/console/) or [Rapid API](https://rapidapi.com/package/SpotifyPublicAPI/functions?utm_source=SpotifyGitHub&utm_medium=button&utm_content=Vendor_GitHub) valuable for experimenting with the API. ================================================ FILE: vendor/github.com/zmb3/spotify/album.go ================================================ package spotify import ( "errors" "fmt" "net/url" "strconv" "strings" "time" ) // SimpleAlbum contains basic data about an album. type SimpleAlbum struct { // The name of the album. Name string `json:"name"` // A slice of SimpleArtists Artists []SimpleArtist `json:"artists"` // The type of the album: one of "album", // "single", or "compilation". AlbumType string `json:"album_type"` // The SpotifyID for the album. ID ID `json:"id"` // The SpotifyURI for the album. URI URI `json:"uri"` // The markets in which the album is available, // identified using ISO 3166-1 alpha-2 country // codes. Note that al album is considered // available in a market when at least 1 of its // tracks is available in that market. AvailableMarkets []string `json:"available_markets"` // A link to the Web API enpoint providing full // details of the album. Endpoint string `json:"href"` // The cover art for the album in various sizes, // widest first. Images []Image `json:"images"` // Known external URLs for this album. ExternalURLs map[string]string `json:"external_urls"` } // Copyright contains the copyright statement associated with an album. type Copyright struct { // The copyright text for the album. Text string `json:"text"` // The type of copyright. Type string `json:"type"` } // FullAlbum provides extra album data in addition to the data provided by SimpleAlbum. type FullAlbum struct { SimpleAlbum Artists []SimpleArtist `json:"artists"` Copyrights []Copyright `json:"copyrights"` Genres []string `json:"genres"` // The popularity of the album, represented as an integer between 0 and 100, // with 100 being the most popular. Popularity of an album is calculated // from the popularify of the album's individual tracks. Popularity int `json:"popularity"` // The date the album was first released. For example, "1981-12-15". // Depending on the ReleaseDatePrecision, it might be shown as // "1981" or "1981-12". You can use ReleaseDateTime to convert this // to a time.Time value. ReleaseDate string `json:"release_date"` // The precision with which ReleaseDate value is known: "year", "month", or "day" ReleaseDatePrecision string `json:"release_date_precision"` Tracks SimpleTrackPage `json:"tracks"` ExternalIDs map[string]string `json:"external_ids"` } // SavedAlbum provides info about an album saved to an user's account. type SavedAlbum struct { // The date and time the track was saved, represented as an ISO // 8601 UTC timestamp with a zero offset (YYYY-MM-DDTHH:MM:SSZ). // You can use the TimestampLayout constant to convert this to // a time.Time value. AddedAt string `json:"added_at"` FullAlbum `json:"album"` } // ReleaseDateTime converts the album's ReleaseDate to a time.TimeValue. // All of the fields in the result may not be valid. For example, if // f.ReleaseDatePrecision is "month", then only the month and year // (but not the day) of the result are valid. func (f *FullAlbum) ReleaseDateTime() time.Time { if f.ReleaseDatePrecision == "day" { result, _ := time.Parse(DateLayout, f.ReleaseDate) return result } if f.ReleaseDatePrecision == "month" { ym := strings.Split(f.ReleaseDate, "-") year, _ := strconv.Atoi(ym[0]) month, _ := strconv.Atoi(ym[1]) return time.Date(year, time.Month(month), 1, 0, 0, 0, 0, time.UTC) } year, _ := strconv.Atoi(f.ReleaseDate) return time.Date(year, 1, 1, 0, 0, 0, 0, time.UTC) } // GetAlbum gets Spotify catalog information for a single album, given its Spotify ID. func (c *Client) GetAlbum(id ID) (*FullAlbum, error) { spotifyURL := fmt.Sprintf("%salbums/%s", c.baseURL, id) var a FullAlbum err := c.get(spotifyURL, &a) if err != nil { return nil, err } return &a, nil } func toStringSlice(ids []ID) []string { result := make([]string, len(ids)) for i, str := range ids { result[i] = str.String() } return result } // GetAlbums gets Spotify Catalog information for multiple albums, given their // Spotify IDs. It supports up to 20 IDs in a single call. Albums are returned // in the order requested. If an album is not found, that position in the // result slice will be nil. func (c *Client) GetAlbums(ids ...ID) ([]*FullAlbum, error) { if len(ids) > 20 { return nil, errors.New("spotify: exceeded maximum number of albums") } spotifyURL := fmt.Sprintf("%salbums?ids=%s", c.baseURL, strings.Join(toStringSlice(ids), ",")) var a struct { Albums []*FullAlbum `json:"albums"` } err := c.get(spotifyURL, &a) if err != nil { return nil, err } return a.Albums, nil } // AlbumType represents the type of an album. It can be used to filter // results when searching for albums. type AlbumType int // AlbumType values that can be used to filter which types of albums are // searched for. These are flags that can be bitwise OR'd together // to search for multiple types of albums simultaneously. const ( AlbumTypeAlbum AlbumType = 1 << iota AlbumTypeSingle = 1 << iota AlbummTypeAppearsOn = 1 << iota AlbumTypeCompilation = 1 << iota ) func (at AlbumType) encode() string { types := []string{} if at&AlbumTypeAlbum != 0 { types = append(types, "album") } if at&AlbumTypeSingle != 0 { types = append(types, "single") } if at&AlbummTypeAppearsOn != 0 { types = append(types, "appears_on") } if at&AlbumTypeCompilation != 0 { types = append(types, "compilation") } return strings.Join(types, ",") } // GetAlbumTracks gets the tracks for a particular album. // If you only care about the tracks, this call is more efficient // than GetAlbum. func (c *Client) GetAlbumTracks(id ID) (*SimpleTrackPage, error) { return c.GetAlbumTracksOpt(id, -1, -1) } // GetAlbumTracksOpt behaves like GetAlbumTracks, with the exception that it // allows you to specify extra parameters that limit the number of results returned. // The maximum number of results to return is specified by limit. // The offset argument can be used to specify the index of the first track to return. // It can be used along with limit to reqeust the next set of results. func (c *Client) GetAlbumTracksOpt(id ID, limit, offset int) (*SimpleTrackPage, error) { spotifyURL := fmt.Sprintf("%salbums/%s/tracks", c.baseURL, id) v := url.Values{} if limit != -1 { v.Set("limit", strconv.Itoa(limit)) } if offset != -1 { v.Set("offset", strconv.Itoa(offset)) } optional := v.Encode() if optional != "" { spotifyURL = spotifyURL + "?" + optional } var result SimpleTrackPage err := c.get(spotifyURL, &result) if err != nil { return nil, err } return &result, nil } ================================================ FILE: vendor/github.com/zmb3/spotify/album_test.go ================================================ package spotify import ( "net/http" "testing" ) // The example from https://developer.spotify.com/web-api/get-album/ func TestFindAlbum(t *testing.T) { client, server := testClientFile(http.StatusOK, "test_data/find_album.txt") defer server.Close() album, err := client.GetAlbum(ID("0sNOF9WDwhWunNAHPD3Baj")) if err != nil { t.Fatal(err) } if album == nil { t.Fatal("Got nil album") } if album.Name != "She's So Unusual" { t.Error("Got wrong album") } released := album.ReleaseDateTime() if released.Year() != 1983 { t.Errorf("Expected release date 1983, got %d\n", released.Year()) } } func TestFindAlbumBadID(t *testing.T) { client, server := testClientString(http.StatusNotFound, `{ "error": { "status": 404, "message": "non existing id" } }`) defer server.Close() album, err := client.GetAlbum(ID("asdf")) if album != nil { t.Fatal("Expected nil album, got", album.Name) } se, ok := err.(Error) if !ok { t.Error("Expected spotify error, got", err) } if se.Status != 404 { t.Errorf("Expected HTTP 404, got %d. ", se.Status) } if se.Message != "non existing id" { t.Error("Unexpected error message: ", se.Message) } } // The example from https://developer.spotify.com/web-api/get-several-albums/ func TestFindAlbums(t *testing.T) { client, server := testClientFile(http.StatusOK, "test_data/find_albums.txt") defer server.Close() res, err := client.GetAlbums(ID("41MnTivkwTO3UUJ8DrqEJJ"), ID("6JWc4iAiJ9FjyK0B59ABb4"), ID("6UXCm6bOO4gFlDQZV5yL37"), ID("0X8vBD8h1Ga9eLT8jx9VCC")) if err != nil { t.Fatal(err) } if len(res) != 4 { t.Fatalf("Expected 4 albums, got %d", len(res)) } expectedAlbums := []string{ "The Best Of Keane (Deluxe Edition)", "Strangeland", "Night Train", "Mirrored", } for i, name := range expectedAlbums { if res[i].Name != name { t.Error("Expected album", name, "but got", res[i].Name) } } release := res[0].ReleaseDateTime() if release.Year() != 2013 || release.Month() != 11 || release.Day() != 8 { t.Errorf("Expected release 2013-11-08, got %d-%02d-%02d\n", release.Year(), release.Month(), release.Day()) } releaseMonthPrecision := res[3].ReleaseDateTime() if releaseMonthPrecision.Year() != 2007 || releaseMonthPrecision.Month() != 3 || releaseMonthPrecision.Day() != 1 { t.Errorf("Expected release 2007-03-01, got %d-%02d-%02d\n", releaseMonthPrecision.Year(), releaseMonthPrecision.Month(), releaseMonthPrecision.Day()) } } func TestFindAlbumTracks(t *testing.T) { client, server := testClientFile(http.StatusOK, "test_data/find_album_tracks.txt") defer server.Close() res, err := client.GetAlbumTracksOpt(ID("0sNOF9WDwhWunNAHPD3Baj"), 1, 0) if err != nil { t.Fatal(err) } if res.Total != 13 { t.Fatal("Got", res.Total, "results, want 13") } if len(res.Tracks) == 1 { if res.Tracks[0].Name != "Money Changes Everything" { t.Error("Expected track 'Money Changes Everything', got", res.Tracks[0].Name) } } else { t.Error("Expected 1 track, got", len(res.Tracks)) } } ================================================ FILE: vendor/github.com/zmb3/spotify/artist.go ================================================ package spotify import ( "fmt" "net/url" "strconv" "strings" ) // SimpleArtist contains basic info about an artist. type SimpleArtist struct { Name string `json:"name"` ID ID `json:"id"` // The Spotify URI for the artist. URI URI `json:"uri"` // A link to the Web API enpoint providing full details of the artist. Endpoint string `json:"href"` ExternalURLs map[string]string `json:"external_urls"` } // FullArtist provides extra artist data in addition to what is provided by SimpleArtist. type FullArtist struct { SimpleArtist // The popularity of the artist, expressed as an integer between 0 and 100. // The artist's popularity is calculated from the popularity of the artist's tracks. Popularity int `json:"popularity"` // A list of genres the artist is associated with. For example, "Prog Rock" // or "Post-Grunge". If not yet classified, the slice is empty. Genres []string `json:"genres"` Followers Followers // Images of the artist in various sizes, widest first. Images []Image `json:"images"` } // GetArtist gets Spotify catalog information for a single artist, given its Spotify ID. func (c *Client) GetArtist(id ID) (*FullArtist, error) { spotifyURL := fmt.Sprintf("%sartists/%s", c.baseURL, id) var a FullArtist err := c.get(spotifyURL, &a) if err != nil { return nil, err } return &a, nil } // GetArtists gets spotify catalog information for several artists based on their // Spotify IDs. It supports up to 50 artists in a single call. Artists are // returned in the order requested. If an artist is not found, that position // in the result will be nil. Duplicate IDs will result in duplicate artists // in the result. func (c *Client) GetArtists(ids ...ID) ([]*FullArtist, error) { spotifyURL := fmt.Sprintf("%sartists?ids=%s", c.baseURL, strings.Join(toStringSlice(ids), ",")) var a struct { Artists []*FullArtist } err := c.get(spotifyURL, &a) if err != nil { return nil, err } return a.Artists, nil } // GetArtistsTopTracks gets Spotify catalog information about an artist's top // tracks in a particular country. It returns a maximum of 10 tracks. The // country is specified as an ISO 3166-1 alpha-2 country code. func (c *Client) GetArtistsTopTracks(artistID ID, country string) ([]FullTrack, error) { spotifyURL := fmt.Sprintf("%sartists/%s/top-tracks?country=%s", c.baseURL, artistID, country) var t struct { Tracks []FullTrack `json:"tracks"` } err := c.get(spotifyURL, &t) if err != nil { return nil, err } return t.Tracks, nil } // GetRelatedArtists gets Spotify catalog information about artists similar to a // given artist. Similarity is based on analysis of the Spotify community's // listening history. This function returns up to 20 artists that are considered // related to the specified artist. func (c *Client) GetRelatedArtists(id ID) ([]FullArtist, error) { spotifyURL := fmt.Sprintf("%sartists/%s/related-artists", c.baseURL, id) var a struct { Artists []FullArtist `json:"artists"` } err := c.get(spotifyURL, &a) if err != nil { return nil, err } return a.Artists, nil } // GetArtistAlbums gets Spotify catalog information about an artist's albums. // It is equivalent to GetArtistAlbumsOpt(artistID, nil). func (c *Client) GetArtistAlbums(artistID ID) (*SimpleAlbumPage, error) { return c.GetArtistAlbumsOpt(artistID, nil, nil) } // GetArtistAlbumsOpt is just like GetArtistAlbums, but it accepts optional // parameters used to filter and sort the result. // // The AlbumType argument can be used to find a particular type of album. Search // for multiple types by OR-ing the types together. func (c *Client) GetArtistAlbumsOpt(artistID ID, options *Options, t *AlbumType) (*SimpleAlbumPage, error) { spotifyURL := fmt.Sprintf("%sartists/%s/albums", c.baseURL, artistID) // add optional query string if options were specified values := url.Values{} if t != nil { values.Set("album_type", t.encode()) } if options != nil { if options.Country != nil { values.Set("market", *options.Country) } else { // if the market is not specified, Spotify will likely return a lot // of duplicates (one for each market in which the album is available) // - prevent this behavior by falling back to the US by default // TODO: would this ever be the desired behavior? values.Set("market", CountryUSA) } if options.Limit != nil { values.Set("limit", strconv.Itoa(*options.Limit)) } if options.Offset != nil { values.Set("offset", strconv.Itoa(*options.Offset)) } } if query := values.Encode(); query != "" { spotifyURL += "?" + query } var p SimpleAlbumPage err := c.get(spotifyURL, &p) if err != nil { return nil, err } return &p, nil } ================================================ FILE: vendor/github.com/zmb3/spotify/artist_test.go ================================================ // Copyright 2014, 2015 Zac Bergquist // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package spotify import ( "net/http" "testing" ) const albumsResponse = ` { "href" : "https://api.spotify.com/v1/artists/1vCWHaC5f2uS3yhpwWbIA6/albums?offset=0&limit=2&album_type=single", "items" : [ { "album_type" : "single", "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], "external_urls" : { "spotify" : "https://open.spotify.com/album/3ckwyt0bTOcDbXovWbweMp" }, "href" : "https://api.spotify.com/v1/albums/3ckwyt0bTOcDbXovWbweMp", "id" : "3ckwyt0bTOcDbXovWbweMp", "images" : [ { "height" : 640, "url" : "https://i.scdn.co/image/144ac57ad073741e99b5243c59abebe1500ada0a", "width" : 640 }, { "height" : 300, "url" : "https://i.scdn.co/image/4680e5f3af02219fd9e79ce432c1b18f97af6426", "width" : 300 }, { "height" : 64, "url" : "https://i.scdn.co/image/8c803d6cb612b6f2b37a7276deb2ff05f5a77097", "width" : 64 } ], "name" : "The Days / Nights", "type" : "album", "uri" : "spotify:album:3ckwyt0bTOcDbXovWbweMp" }, { "album_type" : "single", "available_markets" : [ "CA", "MX", "US" ], "external_urls" : { "spotify" : "https://open.spotify.com/album/1WXM7DYQRT7QX8AKBJRfK9" }, "href" : "https://api.spotify.com/v1/albums/1WXM7DYQRT7QX8AKBJRfK9", "id" : "1WXM7DYQRT7QX8AKBJRfK9", "images" : [ { "height" : 640, "url" : "https://i.scdn.co/image/590dbe5504d2898c120b942bee2b699404783896", "width" : 640 }, { "height" : 300, "url" : "https://i.scdn.co/image/9a4db24b1930e8683b4dfd19c7bd2a40672c6718", "width" : 300 }, { "height" : 64, "url" : "https://i.scdn.co/image/d5cfc167e03ed328ae7dfa9b56d3628d81b6831b", "width" : 64 } ], "name" : "The Days / Nights", "type" : "album", "uri" : "spotify:album:1WXM7DYQRT7QX8AKBJRfK9" } ], "limit" : 2, "next" : "https://api.spotify.com/v1/artists/1vCWHaC5f2uS3yhpwWbIA6/albums?offset=2&limit=2&album_type=single", "offset" : 0, "previous" : null, "total" : 157 }` func TestFindArtist(t *testing.T) { client, server := testClientFile(http.StatusOK, "test_data/find_artist.txt") defer server.Close() artist, err := client.GetArtist(ID("0TnOYISbd1XYRBk9myaseg")) if err != nil { t.Fatal(err) } if followers := artist.Followers.Count; followers != 2265279 { t.Errorf("Got %d followers, want 2265279\n", followers) } if artist.Name != "Pitbull" { t.Error("Got ", artist.Name, ", wanted Pitbull") } } func TestArtistTopTracks(t *testing.T) { client, server := testClientFile(http.StatusOK, "test_data/artist_top_tracks.txt") defer server.Close() tracks, err := client.GetArtistsTopTracks(ID("43ZHCT0cAZBISjO8DG9PnE"), "SE") if err != nil { t.Fatal(err) } if l := len(tracks); l != 10 { t.Fatalf("Got %d tracks, expected 10\n", l) } track := tracks[9] if track.Name != "(You're The) Devil in Disguise" { t.Error("Incorrect track name") } if track.TrackNumber != 24 { t.Errorf("Track number was %d, expected 24\n", track.TrackNumber) } } func TestRelatedArtists(t *testing.T) { client, server := testClientFile(http.StatusOK, "test_data/related_artists.txt") defer server.Close() artists, err := client.GetRelatedArtists(ID("43ZHCT0cAZBISjO8DG9PnE")) if err != nil { t.Fatal(err) } if count := len(artists); count != 20 { t.Fatalf("Got %d artists, wanted 20\n", count) } a2 := artists[2] if a2.Name != "Carl Perkins" { t.Error("Expected Carl Perkins, got ", a2.Name) } if a2.Popularity != 54 { t.Errorf("Expected popularity 54, got %d\n", a2.Popularity) } } func TestArtistAlbumsFiltered(t *testing.T) { client, server := testClientString(http.StatusOK, albumsResponse) defer server.Close() l := 2 var typ AlbumType = AlbumTypeSingle options := Options{} options.Limit = &l albums, err := client.GetArtistAlbumsOpt(ID("1vCWHaC5f2uS3yhpwWbIA6"), &options, &typ) if err != nil { t.Fatal(err) } if albums == nil { t.Fatal("Result is nil") } // since we didn't specify a country, we got duplicate albums // (the album has a different ID in different regions) if l = len(albums.Albums); l != 2 { t.Fatalf("Expected 2 albums, got %d\n", l) } if albums.Albums[0].Name != "The Days / Nights" { t.Error("Expected 'The Days / Nights', got ", albums.Albums[0].Name) } url := "https://open.spotify.com/album/3ckwyt0bTOcDbXovWbweMp" spotifyURL, ok := albums.Albums[0].ExternalURLs["spotify"] if !ok { t.Error("Missing Spotify external URL") } if spotifyURL != url { t.Errorf("Wrong Spotify external URL: want %s, got %s\n", url, spotifyURL) } } ================================================ FILE: vendor/github.com/zmb3/spotify/audio_analysis.go ================================================ package spotify import ( "fmt" ) // AudioAnalysis contains a detailed audio analysis for a single track // identified by its unique Spotify ID. See: // https://developer.spotify.com/web-api/get-audio-analysis/ type AudioAnalysis struct { Bars []Marker `json:"bars"` Beats []Marker `json:"beats"` Meta AnalysisMeta `json:"meta"` Sections []Section `json:"sections"` Segments []Segment `json:"segments"` Tatums []Marker `json:"tatums"` Track AnalysisTrack `json:"track"` } // Marker represents beats, bars, tatums and are used in segment and section // descriptions. type Marker struct { Start float64 `json:"start"` Duration float64 `json:"duration"` Confidence float64 `json:"confidence"` } // AnalysisMeta describes details about Spotify's audio analysis of the track type AnalysisMeta struct { AnalyzerVersion string `json:"analyzer_version"` Platform string `json:"platform"` DetailedStatus string `json:"detailed_status"` StatusCode int `json:"status"` Timestamp int64 `json:"timestamp"` AnalysisTime float64 `json:"analysis_time"` InputProcess string `json:"input_process"` } // Section represents a large variation in rhythm or timbre, e.g. chorus, verse, // bridge, guitar solo, etc. Each section contains its own descriptions of // tempo, key, mode, time_signature, and loudness. type Section struct { Marker Loudness float64 `json:"loudness"` Tempo float64 `json:"tempo"` TempoConfidence float64 `json:"tempo_confidence"` Key Key `json:"key"` KeyConfidence float64 `json:"key_confidence"` Mode Mode `json:"mode"` ModeConfidence float64 `json:"mode_confidence"` TimeSignature int `json:"time_signature"` TimeSignatureConfidence float64 `json:"time_signature_confidence"` } // Segment is characterized by it's perceptual onset and duration in seconds, // loudness (dB), pitch and timbral content. type Segment struct { Marker LoudnessStart float64 `json:"loudness_start"` LoudnessMaxTime float64 `json:"loudness_max_time"` LoudnessMax float64 `json:"loudness_max"` LoudnessEnd float64 `json:"loudness_end"` Pitches []float64 `json:"pitches"` Timbre []float64 `json:"timbre"` } // AnalysisTrack contains audio analysis data about the track as a whole type AnalysisTrack struct { NumSamples int64 `json:"num_samples"` Duration float64 `json:"duration"` SampleMD5 string `json:"sample_md5"` OffsetSeconds int `json:"offset_seconds"` WindowSeconds int `json:"window_seconds"` AnalysisSampleRate int64 `json:"analysis_sample_rate"` AnalysisChannels int `json:"analysis_channels"` EndOfFadeIn float64 `json:"end_of_fade_in"` StartOfFadeOut float64 `json:"start_of_fade_out"` Loudness float64 `json:"loudness"` Tempo float64 `json:"tempo"` TempoConfidence float64 `json:"tempo_confidence"` TimeSignature int `json:"time_signature"` TimeSignatureConfidence float64 `json:"time_signature_confidence"` Key Key `json:"key"` KeyConfidence float64 `json:"key_confidence"` Mode Mode `json:"mode"` ModeConfidence float64 `json:"mode_confidence"` CodeString string `json:"codestring"` CodeVersion float64 `json:"code_version"` EchoprintString string `json:"echoprintstring"` EchoprintVersion float64 `json:"echoprint_version"` SynchString string `json:"synchstring"` SynchVersion float64 `json:"synch_version"` RhythmString string `json:"rhythmstring"` RhythmVersion float64 `json:"rhythm_version"` } // GetAudioAnalysis queries the Spotify web API for an audio analysis of a // single track. func (c *Client) GetAudioAnalysis(id ID) (*AudioAnalysis, error) { url := fmt.Sprintf("%saudio-analysis/%s", c.baseURL, id) temp := AudioAnalysis{} err := c.get(url, &temp) if err != nil { return nil, err } return &temp, nil } ================================================ FILE: vendor/github.com/zmb3/spotify/audio_analysis_test.go ================================================ package spotify import ( "net/http" "reflect" "testing" ) const fieldsDifferTemplate = "Actual response is not the same as expected response on field %s" var expected = AudioAnalysis{ Bars: []Marker{ { Start: 251.98282, Duration: 0.29765, Confidence: 0.652, }, }, Beats: []Marker{ { Start: 251.98282, Duration: 0.29765, Confidence: 0.652, }, }, Meta: AnalysisMeta{ AnalyzerVersion: "4.0.0", Platform: "Linux", DetailedStatus: "OK", StatusCode: 0, Timestamp: 1456010389, AnalysisTime: 9.1394, InputProcess: "libvorbisfile L+R 44100->22050", }, Sections: []Section{ { Marker: Marker{ Start: 237.02356, Duration: 18.32542, Confidence: 1, }, Loudness: -20.074, Tempo: 98.253, TempoConfidence: 0.767, Key: 5, KeyConfidence: 0.327, Mode: 1, ModeConfidence: 0.566, TimeSignature: 4, TimeSignatureConfidence: 1, }, }, Segments: []Segment{ { Marker: Marker{ Start: 252.15601, Duration: 3.19297, Confidence: 0.522, }, LoudnessStart: -23.356, LoudnessMaxTime: 0.06971, LoudnessMax: -18.121, LoudnessEnd: -60, Pitches: []float64{0.709, 0.092, 0.196, 0.084, 0.352, 0.134, 0.161, 1, 0.17, 0.161, 0.211, 0.15}, Timbre: []float64{23.312, -7.374, -45.719, 294.874, 51.869, -79.384, -89.048, 143.322, -4.676, -51.303, -33.274, -19.037}, }, }, Tatums: []Marker{ { Start: 251.98282, Duration: 0.29765, Confidence: 0.652, }, }, Track: AnalysisTrack{ NumSamples: 100, Duration: 255.34898, SampleMD5: "", OffsetSeconds: 0, WindowSeconds: 0, AnalysisSampleRate: 22050, AnalysisChannels: 1, EndOfFadeIn: 0, StartOfFadeOut: 251.73333, Loudness: -11.84, Tempo: 98.002, TempoConfidence: 0.423, TimeSignature: 4, TimeSignatureConfidence: 1, Key: 5, KeyConfidence: 0.36, Mode: 0, ModeConfidence: 0.414, CodeString: "eJxVnAmS5DgOBL-ST-B9_P9j4x7M6qoxW9tpsZQSCeI...", CodeVersion: 3.15, EchoprintString: "eJzlvQmSHDmStHslxw4cB-v9j_A-tahhVKV0IH9...", EchoprintVersion: 4.12, SynchString: "eJx1mIlx7ToORFNRCCK455_YoE9Dtt-vmrKsK3EBsTY...", SynchVersion: 1, RhythmString: "eJyNXAmOLT2r28pZQuZh_xv7g21Iqu_3pCd160xV...", RhythmVersion: 1, }, } func TestAudioAnalysis(t *testing.T) { c, s := testClientFile(http.StatusOK, "test_data/get_audio_analysis.txt") defer s.Close() analysis, err := c.GetAudioAnalysis("foo") if err != nil { t.Error(err) } if !reflect.DeepEqual(analysis.Bars, expected.Bars) { t.Errorf(fieldsDifferTemplate, "Bars") } if !reflect.DeepEqual(analysis.Beats, expected.Beats) { t.Errorf(fieldsDifferTemplate, "Beats") } if !reflect.DeepEqual(analysis.Meta, expected.Meta) { t.Errorf(fieldsDifferTemplate, "Meta") } if !reflect.DeepEqual(analysis.Sections, expected.Sections) { t.Errorf(fieldsDifferTemplate, "Sections") } if !reflect.DeepEqual(analysis.Segments, expected.Segments) { t.Errorf(fieldsDifferTemplate, "Segments") } if !reflect.DeepEqual(analysis.Track, expected.Track) { t.Errorf(fieldsDifferTemplate, "Track") } if !reflect.DeepEqual(analysis.Tatums, expected.Tatums) { t.Errorf(fieldsDifferTemplate, "Tatums") } } ================================================ FILE: vendor/github.com/zmb3/spotify/audio_features.go ================================================ package spotify import ( "fmt" "strings" ) // AudioFeatures contains various high-level acoustic attributes // for a particular track. type AudioFeatures struct { //Acousticness is a confidence measure from 0.0 to 1.0 of whether // the track is acoustic. A value of 1.0 represents high confidence // that the track is acoustic. Acousticness float32 `json:"acousticness"` // An HTTP URL to access the full audio analysis of the track. // The URL is cryptographically signed and configured to expire // after roughly 10 minutes. Do not store these URLs for later use. AnalysisURL string `json:"analysis_url"` // Danceability describes how suitable a track is for dancing based // on a combination of musical elements including tempo, rhythm stability, // beat strength, and overall regularity. A value of 0.0 is least danceable // and 1.0 is most danceable. Danceability float32 `json:"danceability"` // The length of the track in milliseconds. Duration int `json:"duration_ms"` // Energy is a measure from 0.0 to 1.0 and represents a perceptual mesaure // of intensity and activity. Typically, energetic tracks feel fast, loud, // and noisy. Energy float32 `json:"energy"` // The Spotify ID for the track. ID ID `json:"id"` // Predicts whether a track contains no vocals. "Ooh" and "aah" sounds are // treated as instrumental in this context. Rap or spoken words are clearly // "vocal". The closer the Instrumentalness value is to 1.0, the greater // likelihood the track contains no vocal content. Values above 0.5 are // intended to represent instrumental tracks, but confidence is higher as the // value approaches 1.0. Instrumentalness float32 `json:"instrumentalness"` // The key the track is in. Integers map to pitches using standard Pitch Class notation // (https://en.wikipedia.org/wiki/Pitch_class). Key int `json:"key"` // Detects the presence of an audience in the recording. Higher liveness // values represent an increased probability that the track was performed live. // A value above 0.8 provides strong likelihook that the track is live. Liveness float32 `json:"liveness"` // The overall loudness of a track in decibels (dB). Loudness values are // averaged across the entire track and are useful for comparing the relative // loudness of tracks. Typical values range between -60 and 0 dB. Loudness float32 `json:"loudness"` // Mode indicates the modality (major or minor) of a track. Mode int `json:"mode"` // Detects the presence of spoken words in a track. The more exclusively // speech-like the recording, the closer to 1.0 the speechiness will be. // Values above 0.66 describe tracks that are probably made entirely of // spoken words. Values between 0.33 and 0.66 describe tracks that may // contain both music and speech, including such cases as rap music. // Values below 0.33 most likely represent music and other non-speech-like tracks. Speechiness float32 `json:"speechiness"` // The overall estimated tempo of the track in beats per minute (BPM). Tempo float32 `json:"tempo"` // An estimated overall time signature of a track. The time signature (meter) // is a notational convention to specify how many beats are in each bar (or measure). TimeSignature int `json:"time_signature"` // A link to the Web API endpoint providing full details of the track. TrackURL string `json:"track_href"` // The Spotify URI for the track. URI URI `json:"uri"` // A measure from 0.0 to 1.0 describing the musical positiveness conveyed // by a track. Tracks with high valence sound more positive (e.g. happy, // cheerful, euphoric), while tracks with low valence sound more negative // (e.g. sad, depressed, angry). Valence float32 `json:"valence"` } // Key represents a pitch using Pitch Class notation. type Key int const ( C Key = iota CSharp D DSharp E F FSharp G GSharp A ASharp B DFlat = CSharp EFlat = DSharp GFlat = FSharp AFlat = GSharp BFlat = ASharp ) // Mode indicates the modality (major or minor) of a track. type Mode int const ( Minor Mode = iota Major ) // GetAudioFeatures queries the Spotify Web API for various // high-level acoustic attributes of audio tracks. // Objects are returned in the order requested. If an object // is not found, a nil value is returned in the appropriate position. func (c *Client) GetAudioFeatures(ids ...ID) ([]*AudioFeatures, error) { url := fmt.Sprintf("%saudio-features?ids=%s", c.baseURL, strings.Join(toStringSlice(ids), ",")) temp := struct { F []*AudioFeatures `json:"audio_features"` }{} err := c.get(url, &temp) if err != nil { return nil, err } return temp.F, nil } ================================================ FILE: vendor/github.com/zmb3/spotify/audio_features_test.go ================================================ package spotify import ( "net/http" "testing" ) var response = ` { "audio_features" : [ { "danceability" : 0.808, "energy" : 0.626, "key" : 7, "loudness" : -12.733, "mode" : 1, "speechiness" : 0.168, "acousticness" : 0.00187, "instrumentalness" : 0.159, "liveness" : 0.376, "valence" : 0.369, "tempo" : 123.990, "type" : "audio_features", "id" : "4JpKVNYnVcJ8tuMKjAj50A", "uri" : "spotify:track:4JpKVNYnVcJ8tuMKjAj50A", "track_href" : "https://api.spotify.com/v1/tracks/4JpKVNYnVcJ8tuMKjAj50A", "analysis_url" : "http://echonest-analysis.s3.amazonaws.com/TR/WhpYUARk1kNJ_qP0AdKGcDDFKOQTTgsOoINrqyPQjkUnbteuuBiyj_u94iFCSGzdxGiwqQ6d77f4QLL_8=/3/full.json?AWSAccessKeyId=AKIAJRDFEY23UEVW42BQ&Expires=1459290544&Signature=4P03WGLL1a/%2BXp90jcsLGMfFC3Y%3D", "duration_ms" : 535223, "time_signature" : 4 }, { "danceability" : 0.457, "energy" : 0.815, "key" : 1, "loudness" : -7.199, "mode" : 1, "speechiness" : 0.0340, "acousticness" : 0.102, "instrumentalness" : 0.0319, "liveness" : 0.103, "valence" : 0.382, "tempo" : 96.083, "type" : "audio_features", "id" : "2NRANZE9UCmPAS5XVbXL40", "uri" : "spotify:track:2NRANZE9UCmPAS5XVbXL40", "track_href" : "https://api.spotify.com/v1/tracks/2NRANZE9UCmPAS5XVbXL40", "analysis_url" : "http://echonest-analysis.s3.amazonaws.com/TR/WhuQhwPDhmEg5TO4JjbJu0my-awIhk3eaXkRd1ofoJ7tXogPnMtbxkTyLOeHXu5Jke0FCIt52saKJyfPM=/3/full.json?AWSAccessKeyId=AKIAJRDFEY23UEVW42BQ&Expires=1459290544&Signature=Jsg/GexxC7v06Tq70coL/d2x7kI%3D", "duration_ms" : 187800, "time_signature" : 4 }, null, { "danceability" : 0.281, "energy" : 0.402, "key" : 4, "loudness" : -17.921, "mode" : 1, "speechiness" : 0.0291, "acousticness" : 0.0734, "instrumentalness" : 0.830, "liveness" : 0.0593, "valence" : 0.0748, "tempo" : 115.700, "type" : "audio_features", "id" : "24JygzOLM0EmRQeGtFcIcG", "uri" : "spotify:track:24JygzOLM0EmRQeGtFcIcG", "track_href" : "https://api.spotify.com/v1/tracks/24JygzOLM0EmRQeGtFcIcG", "analysis_url" : "http://echonest-analysis.s3.amazonaws.com/TR/ehbkMg05Ck-FN7p3lV7vd8TUdBCvM6z5mgDiZRv6iSlw8P_b8GYBZ4PRAlOgTl3e5rS34_l3dZGDeYzH4=/3/full.json?AWSAccessKeyId=AKIAJRDFEY23UEVW42BQ&Expires=1459290544&Signature=09T3QyRucjrOMoMutRmdJKLJ7hI%3D", "duration_ms" : 497493, "time_signature" : 3 } ] } ` func TestAudioFeatures(t *testing.T) { c, s := testClientString(http.StatusOK, response) defer s.Close() ids := []ID{ "4JpKVNYnVcJ8tuMKjAj50A", "2NRANZE9UCmPAS5XVbXL40", "abc", // intentionally throw a bad one in "24JygzOLM0EmRQeGtFcIcG", } features, err := c.GetAudioFeatures() if err != nil { t.Error(err) } if len(features) != len(ids) { t.Errorf("Want %d results, got %d\n", len(ids), len(features)) } if features[2] != nil { t.Errorf("Want nil result, got #%v\n", features[2]) } if Key(features[0].Key) != G { t.Errorf("Want key G, got %v\n", features[0].Key) } } ================================================ FILE: vendor/github.com/zmb3/spotify/auth.go ================================================ package spotify import ( "context" "crypto/tls" "errors" "net/http" "os" "golang.org/x/oauth2" ) const ( // AuthURL is the URL to Spotify Accounts Service's OAuth2 endpoint. AuthURL = "https://accounts.spotify.com/authorize" // TokenURL is the URL to the Spotify Accounts Service's OAuth2 // token endpoint. TokenURL = "https://accounts.spotify.com/api/token" ) // Scopes let you specify exactly which types of data your application wants to access. // The set of scopes you pass in your authentication request determines what access the // permissions the user is asked to grant. const ( // ScopeImageUpload seeks permission to upload images to Spotify on your behalf. ScopeImageUpload = "ugc-image-upload" // ScopePlaylistReadPrivate seeks permission to read // a user's private playlists. ScopePlaylistReadPrivate = "playlist-read-private" // ScopePlaylistModifyPublic seeks write access // to a user's public playlists. ScopePlaylistModifyPublic = "playlist-modify-public" // ScopePlaylistModifyPrivate seeks write access to // a user's private playlists. ScopePlaylistModifyPrivate = "playlist-modify-private" // ScopePlaylistReadCollaborative seeks permission to // access a user's collaborative playlists. ScopePlaylistReadCollaborative = "playlist-read-collaborative" // ScopeUserFollowModify seeks write/delete access to // the list of artists and other users that a user follows. ScopeUserFollowModify = "user-follow-modify" // ScopeUserFollowRead seeks read access to the list of // artists and other users that a user follows. ScopeUserFollowRead = "user-follow-read" // ScopeUserLibraryModify seeks write/delete access to a // user's "Your Music" library. ScopeUserLibraryModify = "user-library-modify" // ScopeUserLibraryRead seeks read access to a user's "Your Music" library. ScopeUserLibraryRead = "user-library-read" // ScopeUserReadPrivate seeks read access to a user's // subsription details (type of user account). ScopeUserReadPrivate = "user-read-private" // ScopeUserReadEmail seeks read access to a user's email address. ScopeUserReadEmail = "user-read-email" // ScopeUserReadBirthdate seeks read access to a user's birthdate. ScopeUserReadBirthdate = "user-read-birthdate" // ScopeUserReadCurrentlyPlaying seeks read access to a user's currently playing track ScopeUserReadCurrentlyPlaying = "user-read-currently-playing" // ScopeUserReadPlaybackState seeks read access to the user's current playback state ScopeUserReadPlaybackState = "user-read-playback-state" // ScopeUserModifyPlaybackState seeks write access to the user's current playback state ScopeUserModifyPlaybackState = "user-modify-playback-state" // ScopeUserReadRecentlyPlayed allows access to a user's recently-played songs ScopeUserReadRecentlyPlayed = "user-read-recently-played" // ScopeUserTopRead seeks read access to a user's top tracks and artists ScopeUserTopRead = "user-top-read" ) // Authenticator provides convenience functions for implementing the OAuth2 flow. // You should always use `NewAuthenticator` to make them. // // Example: // // a := spotify.NewAuthenticator(redirectURL, spotify.ScopeUserLibaryRead, spotify.ScopeUserFollowRead) // // direct user to Spotify to log in // http.Redirect(w, r, a.AuthURL("state-string"), http.StatusFound) // // // then, in redirect handler: // token, err := a.Token(state, r) // client := a.NewClient(token) // type Authenticator struct { config *oauth2.Config context context.Context } // NewAuthenticator creates an authenticator which is used to implement the // OAuth2 authorization flow. The redirectURL must exactly match one of the // URLs specified in your Spotify developer account. // // By default, NewAuthenticator pulls your client ID and secret key from the // SPOTIFY_ID and SPOTIFY_SECRET environment variables. If you'd like to provide // them from some other source, you can call `SetAuthInfo(id, key)` on the // returned authenticator. func NewAuthenticator(redirectURL string, scopes ...string) Authenticator { cfg := &oauth2.Config{ ClientID: os.Getenv("SPOTIFY_ID"), ClientSecret: os.Getenv("SPOTIFY_SECRET"), RedirectURL: redirectURL, Scopes: scopes, Endpoint: oauth2.Endpoint{ AuthURL: AuthURL, TokenURL: TokenURL, }, } // disable HTTP/2 for DefaultClient, see: https://github.com/zmb3/spotify/issues/20 tr := &http.Transport{ TLSNextProto: map[string]func(authority string, c *tls.Conn) http.RoundTripper{}, } ctx := context.WithValue(context.Background(), oauth2.HTTPClient, &http.Client{Transport: tr}) return Authenticator{ config: cfg, context: ctx, } } // SetAuthInfo overwrites the client ID and secret key used by the authenticator. // You can use this if you don't want to store this information in environment variables. func (a *Authenticator) SetAuthInfo(clientID, secretKey string) { a.config.ClientID = clientID a.config.ClientSecret = secretKey } // AuthURL returns a URL to the the Spotify Accounts Service's OAuth2 endpoint. // // State is a token to protect the user from CSRF attacks. You should pass the // same state to `Token`, where it will be validated. For more info, refer to // http://tools.ietf.org/html/rfc6749#section-10.12. func (a Authenticator) AuthURL(state string) string { return a.config.AuthCodeURL(state) } // Token pulls an authorization code from an HTTP request and attempts to exchange // it for an access token. The standard use case is to call Token from the handler // that handles requests to your application's redirect URL. func (a Authenticator) Token(state string, r *http.Request) (*oauth2.Token, error) { values := r.URL.Query() if e := values.Get("error"); e != "" { return nil, errors.New("spotify: auth failed - " + e) } code := values.Get("code") if code == "" { return nil, errors.New("spotify: didn't get access code") } actualState := values.Get("state") if actualState != state { return nil, errors.New("spotify: redirect state parameter doesn't match") } return a.config.Exchange(a.context, code) } // Exchange is like Token, except it allows you to manually specify the access // code instead of pulling it out of an HTTP request. func (a Authenticator) Exchange(code string) (*oauth2.Token, error) { return a.config.Exchange(a.context, code) } // NewClient creates a Client that will use the specified access token for its API requests. func (a Authenticator) NewClient(token *oauth2.Token) Client { client := a.config.Client(a.context, token) return Client{ http: client, baseURL: baseAddress, } } // Token gets the client's current token. func (c *Client) Token() (*oauth2.Token, error) { transport, ok := c.http.Transport.(*oauth2.Transport) if !ok { return nil, errors.New("spotify: oauth2 transport type not correct") } t, err := transport.Source.Token() if err != nil { return nil, err } return t, nil } ================================================ FILE: vendor/github.com/zmb3/spotify/category.go ================================================ package spotify import ( "fmt" "net/url" "strconv" ) // Category is used by Spotify to tag items in. For example, on the Spotify // player's "Browse" tab. type Category struct { // A link to the Web API endpoint returning full details of the category Endpoint string `json:"href"` // The category icon, in various sizes Icons []Image `json:"icons"` // The Spotify category ID. This isn't a base-62 Spotify ID, its just // a short string that describes and identifies the category (ie "party"). ID string `json:"id"` // The name of the category Name string `json:"name"` } // GetCategoryOpt is like GetCategory, but it accepts optional arguments. // The country parameter is an ISO 3166-1 alpha-2 country code. It can be // used to ensure that the category exists for a particular country. The // locale argument is an ISO 639 language code and an ISO 3166-1 alpha-2 // country code, separated by an underscore. It can be used to get the // category strings in a particular language (for example: "es_MX" means // get categories in Mexico, returned in Spanish). // // This call requries authorization. func (c *Client) GetCategoryOpt(id, country, locale string) (Category, error) { cat := Category{} spotifyURL := fmt.Sprintf("%sbrowse/categories/%s", c.baseURL, id) values := url.Values{} if country != "" { values.Set("country", country) } if locale != "" { values.Set("locale", locale) } if query := values.Encode(); query != "" { spotifyURL += "?" + query } err := c.get(spotifyURL, &cat) if err != nil { return cat, err } return cat, err } // GetCategory gets a single category used to tag items in Spotify // (on, for example, the Spotify player's Browse tab). func (c *Client) GetCategory(id string) (Category, error) { return c.GetCategoryOpt(id, "", "") } // GetCategoryPlaylists gets a list of Spotify playlists tagged with a paricular category. func (c *Client) GetCategoryPlaylists(catID string) (*SimplePlaylistPage, error) { return c.GetCategoryPlaylistsOpt(catID, nil) } // GetCategoryPlaylistsOpt is like GetCategoryPlaylists, but it accepts optional // arguments. func (c *Client) GetCategoryPlaylistsOpt(catID string, opt *Options) (*SimplePlaylistPage, error) { spotifyURL := fmt.Sprintf("%sbrowse/categories/%s/playlists", c.baseURL, catID) if opt != nil { values := url.Values{} if opt.Country != nil { values.Set("country", *opt.Country) } if opt.Limit != nil { values.Set("limit", strconv.Itoa(*opt.Limit)) } if opt.Offset != nil { values.Set("offset", strconv.Itoa(*opt.Offset)) } if query := values.Encode(); query != "" { spotifyURL += "?" + query } } wrapper := struct { Playlists SimplePlaylistPage `json:"playlists"` }{} err := c.get(spotifyURL, &wrapper) if err != nil { return nil, err } return &wrapper.Playlists, nil } // GetCategories gets a list of categories used to tag items in Spotify // (on, for example, the Spotify player's "Browse" tab). func (c *Client) GetCategories() (*CategoryPage, error) { return c.GetCategoriesOpt(nil, "") } // GetCategoriesOpt is like GetCategories, but it accepts optional parameters. // // The locale option can be used to get the results in a particular language. // It consists of an ISO 639 language code and an ISO 3166-1 alpha-2 country // code, separated by an underscore. Specify the empty string to have results // returned in the Spotify default language (American English). func (c *Client) GetCategoriesOpt(opt *Options, locale string) (*CategoryPage, error) { spotifyURL := c.baseURL + "browse/categories" values := url.Values{} if locale != "" { values.Set("locale", locale) } if opt != nil { if opt.Country != nil { values.Set("country", *opt.Country) } if opt.Limit != nil { values.Set("limit", strconv.Itoa(*opt.Limit)) } if opt.Offset != nil { values.Set("offset", strconv.Itoa(*opt.Offset)) } } if query := values.Encode(); query != "" { spotifyURL += "?" + query } wrapper := struct { Categories CategoryPage `json:"categories"` }{} err := c.get(spotifyURL, &wrapper) if err != nil { return nil, err } return &wrapper.Categories, nil } ================================================ FILE: vendor/github.com/zmb3/spotify/category_test.go ================================================ package spotify import ( "net/http" "testing" ) func TestGetCategories(t *testing.T) { client, server := testClientString(http.StatusOK, getCategories) defer server.Close() page, err := client.GetCategories() if err != nil { t.Fatal(err) } if l := len(page.Categories); l != 2 { t.Fatalf("Expected 2 categories, got %d\n", l) } if name := page.Categories[1].Name; name != "Mood" { t.Errorf("Expected 'Mood', got '%s'", name) } } func TestGetCategory(t *testing.T) { client, server := testClientString(http.StatusOK, getCategory) defer server.Close() cat, err := client.GetCategory("dinner") if err != nil { t.Fatal(err) } if cat.ID != "dinner" || cat.Name != "Dinner" { t.Errorf("Invalid name/id (%s, %s)\n", cat.Name, cat.ID) } } func TestGetCategoryPlaylists(t *testing.T) { client, server := testClientString(http.StatusOK, getCategoryPlaylists) defer server.Close() page, err := client.GetCategoryPlaylists("dinner") if err != nil { t.Fatal(err) } if l := len(page.Playlists); l != 2 { t.Fatalf("Expected 2 playlists, got %d\n", l) } if name := page.Playlists[0].Name; name != "Dinner with Friends" { t.Errorf("Expected 'Dinner with Friends', got '%s'\n", name) } if tracks := page.Playlists[1].Tracks.Total; tracks != 91 { t.Errorf("Expected 'Dinner Music' to have 91 tracks, but got %d\n", tracks) } if page.Total != 36 { t.Errorf("Expected 26 playlists in category 'dinner' - got %d\n", page.Total) } } func TestGetCategoryOpt(t *testing.T) { client, server := testClientString(http.StatusNotFound, "", func(r *http.Request) { // verify that the optional parameters were included in the request values := r.URL.Query() if c := values.Get("country"); c != CountryBrazil { t.Errorf("Expected country '%s', got '%s'\n", CountryBrazil, c) } if l := values.Get("locale"); l != "es_MX" { t.Errorf("Expected locale 'es_MX', got '%s'\n", l) } }) defer server.Close() _, err := client.GetCategoryOpt("id", CountryBrazil, "es_MX") if err == nil { t.Fatal("Expected error") } } func TestGetCategoryPlaylistsOpt(t *testing.T) { client, server := testClientString(http.StatusNotFound, "", func(r *http.Request) { values := r.URL.Query() if c := values.Get("country"); c != "" { t.Errorf("Country should not have been set, got %s\n", c) } if l := values.Get("limit"); l != "5" { t.Errorf("Expected limit 5, got %s\n", l) } if o := values.Get("offset"); o != "10" { t.Errorf("Expected offset 10, got %s\n", o) } }) defer server.Close() opt := &Options{} opt.Limit = new(int) opt.Offset = new(int) *opt.Limit = 5 *opt.Offset = 10 client.GetCategoryPlaylistsOpt("id", opt) } func TestGetCategoriesInvalidToken(t *testing.T) { client, server := testClientString(http.StatusUnauthorized, invalidToken) defer server.Close() _, err := client.GetCategories() if err == nil { t.Fatal("Expected error but didn't get one") } serr, ok := err.(Error) if !ok { t.Fatal("Expected a 'spotify.Error'") } if serr.Status != http.StatusUnauthorized { t.Error("Error didn't have status code 401") } } var getCategories = ` { "categories" : { "href" : "https://api.spotify.com/v1/browse/categories?country=CA&offset=0&limit=2", "items" : [ { "href" : "https://api.spotify.com/v1/browse/categories/toplists", "icons" : [ { "height" : 275, "url" : "https://datsnxq1rwndn.cloudfront.net/media/derived/toplists_11160599e6a04ac5d6f2757f5511778f_0_0_275_275.jpg", "width" : 275 } ], "id" : "toplists", "name" : "Top Lists" }, { "href" : "https://api.spotify.com/v1/browse/categories/mood", "icons" : [ { "height" : 274, "url" : "https://datsnxq1rwndn.cloudfront.net/media/original/mood-274x274_976986a31ac8c49794cbdc7246fd5ad7_274x274.jpg", "width" : 274 } ], "id" : "mood", "name" : "Mood" } ], "limit" : 2, "next" : "https://api.spotify.com/v1/browse/categories?country=CA&offset=2&limit=2", "offset" : 0, "previous" : null, "total" : 31 } }` var getCategory = ` { "href" : "https://api.spotify.com/v1/browse/categories/dinner", "icons" : [ { "height" : 274, "url" : "https://datsnxq1rwndn.cloudfront.net/media/original/dinner_1b6506abba0ba52c54e6d695c8571078_274x274.jpg", "width" : 274 } ], "id" : "dinner", "name" : "Dinner" }` var getCategoryPlaylists = ` { "playlists" : { "href" : "https://api.spotify.com/v1/browse/categories/dinner/playlists?offset=0&limit=2", "items" : [ { "collaborative" : false, "external_urls" : { "spotify" : "http://open.spotify.com/user/spotify/playlist/59ZbFPES4DQwEjBpWHzrtC" }, "href" : "https://api.spotify.com/v1/users/spotify/playlists/59ZbFPES4DQwEjBpWHzrtC", "id" : "59ZbFPES4DQwEjBpWHzrtC", "images" : [ { "height" : 300, "url" : "https://i.scdn.co/image/68b6a65573a55095e9c0c0c33a274b18e0422736", "width" : 300 } ], "name" : "Dinner with Friends", "owner" : { "external_urls" : { "spotify" : "http://open.spotify.com/user/spotify" }, "href" : "https://api.spotify.com/v1/users/spotify", "id" : "spotify", "type" : "user", "uri" : "spotify:user:spotify" }, "public" : null, "tracks" : { "href" : "https://api.spotify.com/v1/users/spotify/playlists/59ZbFPES4DQwEjBpWHzrtC/tracks", "total" : 98 }, "type" : "playlist", "uri" : "spotify:user:spotify:playlist:59ZbFPES4DQwEjBpWHzrtC" }, { "collaborative" : false, "external_urls" : { "spotify" : "http://open.spotify.com/user/spotify/playlist/1WDw5izv4UhpobNdGXQug7" }, "href" : "https://api.spotify.com/v1/users/spotify/playlists/1WDw5izv4UhpobNdGXQug7", "id" : "1WDw5izv4UhpobNdGXQug7", "images" : [ { "height" : 300, "url" : "https://i.scdn.co/image/acdcc5e1aa4e9c1db523d684a35f9c0785e50152", "width" : 300 } ], "name" : "Dinner Music", "owner" : { "external_urls" : { "spotify" : "http://open.spotify.com/user/spotify" }, "href" : "https://api.spotify.com/v1/users/spotify", "id" : "spotify", "type" : "user", "uri" : "spotify:user:spotify" }, "public" : null, "tracks" : { "href" : "https://api.spotify.com/v1/users/spotify/playlists/1WDw5izv4UhpobNdGXQug7/tracks", "total" : 91 }, "type" : "playlist", "uri" : "spotify:user:spotify:playlist:1WDw5izv4UhpobNdGXQug7" } ], "limit" : 2, "next" : "https://api.spotify.com/v1/browse/categories/dinner/playlists?offset=2&limit=2", "offset" : 0, "previous" : null, "total" : 36 } }` var invalidToken = ` { "error": { "status": 401, "message": "Invalid access token" } }` ================================================ FILE: vendor/github.com/zmb3/spotify/countries.go ================================================ package spotify // ISO 3166-1 alpha 2 country codes. // // see: https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2 const ( CountryArgentina = "AR" CountryAustralia = "AU" CountryAustria = "AT" CountryBelarus = "BY" CountryBelgium = "BE" CountryBrazil = "BR" CountryCanada = "CA" CountryChile = "CL" CountryChina = "CN" CountryGermany = "DE" CountryHongKong = "HK" CountryIreland = "IE" CountryIndia = "IN" CountryItaly = "IT" CountryJapan = "JP" CountrySpain = "ES" CountryFinland = "FI" CountryFrance = "FR" CountryMexico = "MX" CountryNewZealand = "NZ" CountryRussia = "RU" CountrySwitzerland = "CH" CountryUnitedArabEmirates = "AE" CountryUnitedKingdom = "GB" CountryUSA = "US" ) ================================================ FILE: vendor/github.com/zmb3/spotify/cursor.go ================================================ package spotify // This file contains the types that implement Spotify's cursor-based // paging object. Like the standard paging object, this object is a // container for a set of items. Unlike the standard paging object, a // cursor-based paging object does not provide random access to the results. // Cursor contains a key that can be used to find the next set // of items. type Cursor struct { After string `json:"after"` } // cursorPage contains all of the fields in a Spotify cursor-based // paging object, except for the actual items. This type is meant // to be embedded in other types that add the Items field. type cursorPage struct { // A link to the Web API endpoint returning the full // result of this request. Endpoint string `json:"href"` // The maximum number of items returned, as set in the query // (or default value if unset). Limit int `json:"limit"` // The URL to the next set of items. Next string `json:"next"` // The total number of items available to return. Total int `json:"total"` // The cursor used to find the next set of items. Cursor Cursor `json:"cursors"` } // FullArtistCursorPage is a cursor-based paging object containing // a set of FullArtist objects. type FullArtistCursorPage struct { cursorPage Artists []FullArtist `json:"items"` } ================================================ FILE: vendor/github.com/zmb3/spotify/full_tests.bat ================================================ @echo off REM - The tests that actually hit the Spotify Web API don't run by default. REM - Use this script to run them in addition to the standard unit tests. cmd /C "set FULLTEST=y && go test %*" ================================================ FILE: vendor/github.com/zmb3/spotify/library.go ================================================ package spotify import ( "errors" "fmt" "net/http" "strings" ) // UserHasTracks checks if one or more tracks are saved to the current user's // "Your Music" library. func (c *Client) UserHasTracks(ids ...ID) ([]bool, error) { if l := len(ids); l == 0 || l > 50 { return nil, errors.New("spotify: UserHasTracks supports 1 to 50 IDs per call") } spotifyURL := fmt.Sprintf("%sme/tracks/contains?ids=%s", c.baseURL, strings.Join(toStringSlice(ids), ",")) var result []bool err := c.get(spotifyURL, &result) if err != nil { return nil, err } return result, err } // AddTracksToLibrary saves one or more tracks to the current user's // "Your Music" library. This call requires the ScopeUserLibraryModify scope. // A track can only be saved once; duplicate IDs are ignored. func (c *Client) AddTracksToLibrary(ids ...ID) error { return c.modifyLibraryTracks(true, ids...) } // RemoveTracksFromLibrary removes one or more tracks from the current user's // "Your Music" library. This call requires the ScopeUserModifyLibrary scope. // Trying to remove a track when you do not have the user's authorization // results in a `spotify.Error` with the status code set to http.StatusUnauthorized. func (c *Client) RemoveTracksFromLibrary(ids ...ID) error { return c.modifyLibraryTracks(false, ids...) } func (c *Client) modifyLibraryTracks(add bool, ids ...ID) error { if l := len(ids); l == 0 || l > 50 { return errors.New("spotify: this call supports 1 to 50 IDs per call") } spotifyURL := fmt.Sprintf("%sme/tracks?ids=%s", c.baseURL, strings.Join(toStringSlice(ids), ",")) method := "DELETE" if add { method = "PUT" } req, err := http.NewRequest(method, spotifyURL, nil) if err != nil { return err } err = c.execute(req, nil) if err != nil { return err } return nil } ================================================ FILE: vendor/github.com/zmb3/spotify/library_test.go ================================================ package spotify import ( "net/http" "testing" ) func TestUserHasTracks(t *testing.T) { client, server := testClientString(http.StatusOK, `[ false, true ]`) defer server.Close() contains, err := client.UserHasTracks("0udZHhCi7p1YzMlvI4fXoK", "55nlbqqFVnSsArIeYSQlqx") if err != nil { t.Error(err) } if l := len(contains); l != 2 { t.Error("Expected 2 results, got", l) } if contains[0] || !contains[1] { t.Error("Expected [false, true], got", contains) } } func TestAddTracksToLibrary(t *testing.T) { client, server := testClientString(http.StatusOK, "") defer server.Close() err := client.AddTracksToLibrary("4iV5W9uYEdYUVa79Axb7Rh", "1301WleyT98MSxVHPZCA6M") if err != nil { t.Error(err) } } func TestAddTracksToLibraryFailure(t *testing.T) { client, server := testClientString(http.StatusUnauthorized, ` { "error": { "status": 401, "message": "Invalid access token" } }`) defer server.Close() err := client.AddTracksToLibrary("4iV5W9uYEdYUVa79Axb7Rh", "1301WleyT98MSxVHPZCA6M") if err == nil { t.Error("Expected error and didn't get one") } } func TestRemoveTracksFromLibrary(t *testing.T) { client, server := testClientString(http.StatusOK, "") defer server.Close() err := client.RemoveTracksFromLibrary("4iV5W9uYEdYUVa79Axb7Rh", "1301WleyT98MSxVHPZCA6M") if err != nil { t.Error(err) } } ================================================ FILE: vendor/github.com/zmb3/spotify/page.go ================================================ package spotify import ( "errors" ) // ErrNoMorePages is the error returned when you attempt to get the next // (or previous) set of data but you've reached the end of the data set. var ErrNoMorePages = errors.New("spotify: no more pages") // This file contains the types that implement Spotify's paging object. // See: https://developer.spotify.com/web-api/object-model/#paging-object // basePage contains all of the fields in a Spotify paging object, except // for the actual items. This type is meant to be embedded in other types // that add the Items field. type basePage struct { // A link to the Web API Endpoint returning the full // result of this request. Endpoint string `json:"href"` // The maximum number of items in the response, as set // in the query (or default value if unset). Limit int `json:"limit"` // The offset of the items returned, as set in the query // (or default value if unset). Offset int `json:"offset"` // The total number of items available to return. Total int `json:"total"` // The URL to the next page of items (if available). Next string `json:"next"` // The URL to the previous page of items (if available). Previous string `json:"previous"` } // FullArtistPage contains FullArtists returned by the Web API. type FullArtistPage struct { basePage Artists []FullArtist `json:"items"` } // SimpleAlbumPage contains SimpleAlbums returned by the Web API. type SimpleAlbumPage struct { basePage Albums []SimpleAlbum `json:"items"` } // SavedAlbumPage contains SavedAlbums returned by the Web API. type SavedAlbumPage struct { basePage Albums []SavedAlbum `json:"items"` } // SimplePlaylistPage contains SimplePlaylists returned by the Web API. type SimplePlaylistPage struct { basePage Playlists []SimplePlaylist `json:"items"` } // SimpleTrackPage contains SimpleTracks returned by the Web API. type SimpleTrackPage struct { basePage Tracks []SimpleTrack `json:"items"` } // FullTrackPage contains FullTracks returned by the Web API. type FullTrackPage struct { basePage Tracks []FullTrack `json:"items"` } // SavedTrackPage contains SavedTracks return by the Web API. type SavedTrackPage struct { basePage Tracks []SavedTrack `json:"items"` } // PlaylistTrackPage contains information about tracks in a playlist. type PlaylistTrackPage struct { basePage Tracks []PlaylistTrack `json:"items"` } // CategoryPage contains Category objects returned by the Web API. type CategoryPage struct { basePage Categories []Category `json:"items"` } ================================================ FILE: vendor/github.com/zmb3/spotify/player.go ================================================ package spotify import ( "bytes" "encoding/json" "net/http" "net/url" "strconv" "time" ) // PlayerDevice contains information about a device that a user can play music on type PlayerDevice struct { // ID of the device. This may be empty. ID ID `json:"id"` // Active If this device is the currently active device. Active bool `json:"is_active"` // Restricted Whether controlling this device is restricted. At present if // this is "true" then no Web API commands will be accepted by this device. Restricted bool `json:"is_restricted"` // Name The name of the device. Name string `json:"name"` // Type of device, such as "Computer", "Smartphone" or "Speaker". Type string `json:"type"` // Volume The current volume in percent. Volume int `json:"volume_percent"` } // PlayerState contains information about the current playback. type PlayerState struct { CurrentlyPlaying // Device The device that is currently active Device PlayerDevice `json:"device"` // ShuffleState Shuffle is on or off ShuffleState bool `json:"shuffle_state"` // RepeatState off, track, context RepeatState string `json:"repeat_state"` } // PlaybackContext is the playback context type PlaybackContext struct { // ExternalURLs of the context, or null if not available. ExternalURLs map[string]string `json:"external_urls"` // Endpoint of the context, or null if not available. Endpoint string `json:"href"` // Type of the item's context. Can be one of album, artist or playlist. Type string `json:"type"` // URI is the Spotify URI for the context. URI URI `json:"uri"` } // CurrentlyPlaying contains the information about currently playing items type CurrentlyPlaying struct { // Timestamp when data was fetched Timestamp int `json:"timestamp"` // PlaybackContext current context PlaybackContext PlaybackContext `json:"context"` // Progress into the currently playing track. Progress int `json:"progress_ms"` // Playing If something is currently playing. Playing bool `json:"is_playing"` // The currently playing track. Can be null. Item *FullTrack `json:"Item"` } type RecentlyPlayedItem struct { // Track is the track information Track SimpleTrack `json:"track"` // PlayedAt is the time that this song was played PlayedAt time.Time `json:"played_at"` // PlaybackContext is the current playback context PlaybackContext PlaybackContext `json:"context"` } type RecentlyPlayedResult struct { Items []RecentlyPlayedItem `json:"items"` } // PlaybackOffset can be specified either by track URI OR Position. If both are present the // request will return 400 BAD REQUEST. If incorrect values are provided for position or uri, // the request may be accepted but with an unpredictable resulting action on playback. type PlaybackOffset struct { // Position is zero based and can’t be negative. Position int `json:"position,omitempty"` // URI is a string representing the uri of the item to start at. URI URI `json:"uri,omitempty"` } type PlayOptions struct { // DeviceID The id of the device this command is targeting. If not // supplied, the user's currently active device is the target. DeviceID *ID `json:"-"` // PlaybackContext Spotify URI of the context to play. // Valid contexts are albums, artists & playlists. PlaybackContext *URI `json:"context_uri,omitempty"` // URIs Array of the Spotify track URIs to play URIs []URI `json:"uris,omitempty"` // PlaybackOffset Indicates from where in the context playback should start. // Only available when context corresponds to an album or playlist // object, or when the URIs parameter is used. PlaybackOffset *PlaybackOffset `json:"offset,omitempty"` } // RecentlyPlayedOptions describes options for the recently-played request. All // fields are optional. Only one of `AfterEpochMs` and `BeforeEpochMs` may be // given. Note that it seems as if Spotify only remembers the fifty most-recent // tracks as of right now. type RecentlyPlayedOptions struct { // Limit is the maximum number of items to return. Must be no greater than // fifty. Limit int // AfterEpochMs is a Unix epoch in milliseconds that describes a time after // which to return songs. AfterEpochMs int // BeforeEpochMs is a Unix epoch in milliseconds that describes a time // before which to return songs. BeforeEpochMs int } // PlayerDevices information about available devices for the current user. // // Requires the ScopeUserReadPlaybackState scope in order to read information func (c *Client) PlayerDevices() ([]PlayerDevice, error) { var result struct { PlayerDevices []PlayerDevice `json:"devices"` } err := c.get(c.baseURL+"me/player/devices", &result) if err != nil { return nil, err } return result.PlayerDevices, nil } // PlayerState gets information about the playing state for the current user // // Requires the ScopeUserReadPlaybackState scope in order to read information func (c *Client) PlayerState() (*PlayerState, error) { return c.PlayerStateOpt(nil) } // PlayerStateOpt is like PlayerState, but it accepts additional // options for sorting and filtering the results. func (c *Client) PlayerStateOpt(opt *Options) (*PlayerState, error) { spotifyURL := c.baseURL + "me/player" if opt != nil { v := url.Values{} if opt.Country != nil { v.Set("market", *opt.Country) } if params := v.Encode(); params != "" { spotifyURL += "?" + params } } var result PlayerState err := c.get(spotifyURL, &result) if err != nil { return nil, err } return &result, nil } // PlayerCurrentlyPlaying gets information about the currently playing status // for the current user. // // Requires the ScopeUserReadCurrentlyPlaying scope or the ScopeUserReadPlaybackState // scope in order to read information func (c *Client) PlayerCurrentlyPlaying() (*CurrentlyPlaying, error) { return c.PlayerCurrentlyPlayingOpt(nil) } // PlayerCurrentlyPlayingOpt is like PlayerCurrentlyPlaying, but it accepts // additional options for sorting and filtering the results. func (c *Client) PlayerCurrentlyPlayingOpt(opt *Options) (*CurrentlyPlaying, error) { spotifyURL := c.baseURL + "me/player/currently-playing" if opt != nil { v := url.Values{} if opt.Country != nil { v.Set("market", *opt.Country) } if params := v.Encode(); params != "" { spotifyURL += "?" + params } } var result CurrentlyPlaying err := c.get(spotifyURL, &result) if err != nil { return nil, err } return &result, nil } // PlayerRecentlyPlayed gets a list of recently-played tracks for the current // user. This call requires ScopeUserReadRecentlyPlayed. func (c *Client) PlayerRecentlyPlayed() ([]RecentlyPlayedItem, error) { return c.PlayerRecentlyPlayedOpt(nil) } // PlayerRecentlyPlayedOpt is like PlayerRecentlyPlayed, but it accepts // additional options for sorting and filtering the results. func (c *Client) PlayerRecentlyPlayedOpt(opt *RecentlyPlayedOptions) ([]RecentlyPlayedItem, error) { spotifyURL := c.baseURL + "me/player/recently-played" if opt != nil { v := url.Values{} if opt.Limit != 0 { v.Set("limit", strconv.FormatInt(int64(opt.Limit), 10)) } if opt.BeforeEpochMs != 0 { v.Set("before", strconv.FormatInt(int64(opt.BeforeEpochMs), 10)) } if opt.AfterEpochMs != 0 { v.Set("after", strconv.FormatInt(int64(opt.AfterEpochMs), 10)) } if params := v.Encode(); params != "" { spotifyURL += "?" + params } } result := RecentlyPlayedResult{} err := c.get(spotifyURL, &result) if err != nil { return nil, err } return result.Items, nil } // TransferPlayback transfers playback to a new device and determine if // it should start playing. // // Note that a value of false for the play parameter when also transferring // to another device_id will not pause playback. To ensure that playback is // paused on the new device you should send a pause command to the currently // active device before transferring to the new device_id. // // Requires the ScopeUserModifyPlaybackState in order to modify the player state func (c *Client) TransferPlayback(deviceID ID, play bool) error { reqData := struct { DeviceID []ID `json:"device_ids"` Play bool `json:"play"` }{ DeviceID: []ID{deviceID}, Play: play, } buf := new(bytes.Buffer) err := json.NewEncoder(buf).Encode(reqData) if err != nil { return err } req, err := http.NewRequest(http.MethodPut, c.baseURL+"me/player", buf) if err != nil { return err } err = c.execute(req, nil, http.StatusNoContent) if err != nil { return err } return nil } // Play Start a new context or resume current playback on the user's active // device. This call requires ScopeUserModifyPlaybackState in order to modify the player state. func (c *Client) Play() error { return c.PlayOpt(nil) } // PlayOpt is like Play but with more options func (c *Client) PlayOpt(opt *PlayOptions) error { spotifyURL := c.baseURL + "me/player/play" buf := new(bytes.Buffer) if opt != nil { v := url.Values{} if opt.DeviceID != nil { v.Set("device_id", opt.DeviceID.String()) } if params := v.Encode(); params != "" { spotifyURL += "?" + params } err := json.NewEncoder(buf).Encode(opt) if err != nil { return err } } req, err := http.NewRequest(http.MethodPut, spotifyURL, buf) if err != nil { return err } err = c.execute(req, nil, http.StatusNoContent) if err != nil { return err } return nil } // Pause Playback on the user's currently active device. // // Requires the ScopeUserModifyPlaybackState in order to modify the player state func (c *Client) Pause() error { return c.PauseOpt(nil) } // PauseOpt is like Pause but with more options // // Only expects PlayOptions.DeviceID, all other options will be ignored func (c *Client) PauseOpt(opt *PlayOptions) error { spotifyURL := c.baseURL + "me/player/pause" if opt != nil { v := url.Values{} if opt.DeviceID != nil { v.Set("device_id", opt.DeviceID.String()) } if params := v.Encode(); params != "" { spotifyURL += "?" + params } } req, err := http.NewRequest(http.MethodPut, spotifyURL, nil) if err != nil { return err } err = c.execute(req, nil, http.StatusNoContent) if err != nil { return err } return nil } // Next skips to the next track in the user's queue in the user's // currently active device. This call requires ScopeUserModifyPlaybackState // in order to modify the player state func (c *Client) Next() error { return c.NextOpt(nil) } // NextOpt is like Next but with more options // // Only expects PlayOptions.DeviceID, all other options will be ignored func (c *Client) NextOpt(opt *PlayOptions) error { spotifyURL := c.baseURL + "me/player/next" if opt != nil { v := url.Values{} if opt.DeviceID != nil { v.Set("device_id", opt.DeviceID.String()) } if params := v.Encode(); params != "" { spotifyURL += "?" + params } } req, err := http.NewRequest(http.MethodPost, spotifyURL, nil) if err != nil { return err } err = c.execute(req, nil, http.StatusNoContent) if err != nil { return err } return nil } // Previous skips to the Previous track in the user's queue in the user's // currently active device. This call requires ScopeUserModifyPlaybackState // in order to modify the player state func (c *Client) Previous() error { return c.PreviousOpt(nil) } // PreviousOpt is like Previous but with more options // // Only expects PlayOptions.DeviceID, all other options will be ignored func (c *Client) PreviousOpt(opt *PlayOptions) error { spotifyURL := c.baseURL + "me/player/previous" if opt != nil { v := url.Values{} if opt.DeviceID != nil { v.Set("device_id", opt.DeviceID.String()) } if params := v.Encode(); params != "" { spotifyURL += "?" + params } } req, err := http.NewRequest(http.MethodPost, spotifyURL, nil) if err != nil { return err } err = c.execute(req, nil, http.StatusNoContent) if err != nil { return err } return nil } // Seek to the given position in the user’s currently playing track. // // The position in milliseconds to seek to. Must be a positive number. // Passing in a position that is greater than the length of the track // will cause the player to start playing the next song. // // Requires the ScopeUserModifyPlaybackState in order to modify the player state func (c *Client) Seek(position int) error { return c.SeekOpt(position, nil) } // SeekOpt is like Seek but with more options // // Only expects PlayOptions.DeviceID, all other options will be ignored func (c *Client) SeekOpt(position int, opt *PlayOptions) error { return c.playerFuncWithOpt( "me/player/seek", url.Values{ "position_ms": []string{strconv.FormatInt(int64(position), 10)}, }, opt, ) } // Repeat Set the repeat mode for the user's playback. // // Options are repeat-track, repeat-context, and off. // // Requires the ScopeUserModifyPlaybackState in order to modify the player state. func (c *Client) Repeat(state string) error { return c.RepeatOpt(state, nil) } // RepeatOpt is like Repeat but with more options // // Only expects PlayOptions.DeviceID, all other options will be ignored. func (c *Client) RepeatOpt(state string, opt *PlayOptions) error { return c.playerFuncWithOpt( "me/player/repeat", url.Values{ "state": []string{state}, }, opt, ) } // Volume set the volume for the user's current playback device. // // Percent is must be a value from 0 to 100 inclusive. // // Requires the ScopeUserModifyPlaybackState in order to modify the player state func (c *Client) Volume(percent int) error { return c.VolumeOpt(percent, nil) } // VolumeOpt is like Volume but with more options // // Only expects PlayOptions.DeviceID, all other options will be ignored func (c *Client) VolumeOpt(percent int, opt *PlayOptions) error { return c.playerFuncWithOpt( "me/player/volume", url.Values{ "volume_percent": []string{strconv.FormatInt(int64(percent), 10)}, }, opt, ) } // Shuffle switches shuffle on or off for user's playback. // // Requires the ScopeUserModifyPlaybackState in order to modify the player state func (c *Client) Shuffle(shuffle bool) error { return c.ShuffleOpt(shuffle, nil) } // ShuffleOpt is like Shuffle but with more options // // Only expects PlayOptions.DeviceID, all other options will be ignored func (c *Client) ShuffleOpt(shuffle bool, opt *PlayOptions) error { return c.playerFuncWithOpt( "me/player/shuffle", url.Values{ "state": []string{strconv.FormatBool(shuffle)}, }, opt, ) } func (c *Client) playerFuncWithOpt(urlSuffix string, values url.Values, opt *PlayOptions) error { spotifyURL := c.baseURL + urlSuffix if opt != nil { if opt.DeviceID != nil { values.Set("device_id", opt.DeviceID.String()) } } if params := values.Encode(); params != "" { spotifyURL += "?" + params } req, err := http.NewRequest(http.MethodPut, spotifyURL, nil) if err != nil { return err } err = c.execute(req, nil, http.StatusNoContent) if err != nil { return err } return nil } ================================================ FILE: vendor/github.com/zmb3/spotify/player_test.go ================================================ package spotify import ( "net/http" "testing" ) func TestTransferPlaybackDeviceUnavailable(t *testing.T) { client, server := testClientString(http.StatusAccepted, "") defer server.Close() err := client.TransferPlayback("newdevice", false) if err == nil { t.Error("expected error since auto retry is disabled") } } func TestTransferPlayback(t *testing.T) { client, server := testClientString(http.StatusNoContent, "") defer server.Close() err := client.TransferPlayback("newdevice", true) if err != nil { t.Error(err) } } func TestVolume(t *testing.T) { client, server := testClientString(http.StatusNoContent, "") defer server.Close() err := client.Volume(50) if err != nil { t.Error(err) } } func TestPlayerDevices(t *testing.T) { client, server := testClientFile(http.StatusOK, "test_data/player_available_devices.txt") defer server.Close() list, err := client.PlayerDevices() if err != nil { t.Error(err) return } if len(list) != 2 { t.Error("Expected two devices") } if list[0].Volume != 100 { t.Error("Expected volume to be 100%") } if list[1].Volume != 0 { t.Error("Expected null becomes 0") } } func TestPlayerState(t *testing.T) { client, server := testClientFile(http.StatusOK, "test_data/player_state.txt") defer server.Close() state, err := client.PlayerState() if err != nil { t.Error(err) return } if len(state.PlaybackContext.ExternalURLs) != 1 { t.Error("Expected one external url") } if state.Item == nil { t.Error("Expected item to be a track") } if state.Timestamp != 1491302708055 { t.Error("Expected timestamp to be 1491302708055") } if state.Progress != 102509 { t.Error("Expected progress to be 102509") } if state.Playing { t.Error("Expected not to be playing") } } func TestPlayerCurrentlyPlaying(t *testing.T) { client, server := testClientFile(http.StatusOK, "test_data/player_currently_playing.txt") defer server.Close() state, err := client.PlayerCurrentlyPlaying() if err != nil { t.Error(err) return } if len(state.PlaybackContext.ExternalURLs) != 1 { t.Error("Expected one external url") } if state.Item == nil { t.Error("Expected item to be a track") } if state.Timestamp != 1491302708055 { t.Error("Expected timestamp to be 1491302708055") } if state.Progress != 102509 { t.Error("Expected progress to be 102509") } if state.Playing { t.Error("Expected not to be playing") } } func TestPlayerRecentlyPlayed(t *testing.T) { client, server := testClientFile(http.StatusOK, "test_data/player_recently_played.txt") defer server.Close() items, err := client.PlayerRecentlyPlayed() if err != nil { t.Fatal(err) } if len(items) != 20 { t.Error("Too few or too many items were returned") } actualTimePhrase := items[0].PlayedAt.Format("2006-01-02T15:04:05.999Z") expectedTimePhrase := "2017-05-27T20:07:54.721Z" if actualTimePhrase != expectedTimePhrase { t.Errorf("Time of first track was not parsed correctly: [%s] != [%s]", actualTimePhrase, expectedTimePhrase) } } func TestPlayArgsError(t *testing.T) { json := `{ "error" : { "status" : 400, "message" : "Only one of either \"context_uri\" or \"uris\" can be specified" } }` client, server := testClientString(http.StatusUnauthorized, json) defer server.Close() err := client.Play() if err == nil { t.Error("Expected an error") } } ================================================ FILE: vendor/github.com/zmb3/spotify/playlist.go ================================================ package spotify import ( "bytes" "encoding/base64" "encoding/json" "fmt" "io" "net/http" "net/url" "strconv" "strings" ) // PlaylistTracks contains details about the tracks in a playlist. type PlaylistTracks struct { // A link to the Web API endpoint where full details of // the playlist's tracks can be retrieved. Endpoint string `json:"href"` // The total number of tracks in the playlist. Total uint `json:"total"` } // SimplePlaylist contains basic info about a Spotify playlist. type SimplePlaylist struct { // Indicates whether the playlist owner allows others to modify the playlist. // Note: only non-collaborative playlists are currently returned by Spotify's Web API. Collaborative bool `json:"collaborative"` ExternalURLs map[string]string `json:"external_urls"` // A link to the Web API endpoint providing full details of the playlist. Endpoint string `json:"href"` ID ID `json:"id"` // The playlist image. Note: this field is only returned for modified, // verified playlists. Otherwise the slice is empty. If returned, the source // URL for the image is temporary and will expire in less than a day. Images []Image `json:"images"` Name string `json:"name"` Owner User `json:"owner"` IsPublic bool `json:"public"` // The version identifier for the current playlist. Can be supplied in other // requests to target a specific playlist version. SnapshotID string `json:"snapshot_id"` // A collection to the Web API endpoint where full details of the playlist's // tracks can be retrieved, along with the total number of tracks in the playlist. Tracks PlaylistTracks `json:"tracks"` URI URI `json:"uri"` } // FullPlaylist provides extra playlist data in addition to the data provided by SimplePlaylist. type FullPlaylist struct { SimplePlaylist // The playlist description. Only returned for modified, verified playlists. Description string `json:"description"` // Information about the followers of this playlist. Followers Followers `json:"followers"` Tracks PlaylistTrackPage `json:"tracks"` } // PlaylistOptions contains optional parameters that can be used when querying // for featured playlists. Only the non-nil fields are used in the request. type PlaylistOptions struct { Options // The desired language, consisting of a lowercase IO 639 // language code and an uppercase ISO 3166-1 alpha-2 // country code, joined by an underscore. Provide this // parameter if you want the results returned in a particular // language. If not specified, the result will be returned // in the Spotify default language (American English). Locale *string // A timestamp in ISO 8601 format (yyyy-MM-ddTHH:mm:ss). // use this paramter to specify the user's local time to // get results tailored for that specific date and time // in the day. If not provided, the response defaults to // the current UTC time. Timestamp *string } // FeaturedPlaylistsOpt gets a list of playlists featured by Spotify. // It accepts a number of optional parameters via the opt argument. func (c *Client) FeaturedPlaylistsOpt(opt *PlaylistOptions) (message string, playlists *SimplePlaylistPage, e error) { spotifyURL := c.baseURL + "browse/featured-playlists" if opt != nil { v := url.Values{} if opt.Locale != nil { v.Set("locale", *opt.Locale) } if opt.Country != nil { v.Set("country", *opt.Country) } if opt.Timestamp != nil { v.Set("timestamp", *opt.Timestamp) } if opt.Limit != nil { v.Set("limit", strconv.Itoa(*opt.Limit)) } if opt.Offset != nil { v.Set("offset", strconv.Itoa(*opt.Offset)) } if params := v.Encode(); params != "" { spotifyURL += "?" + params } } var result struct { Playlists SimplePlaylistPage `json:"playlists"` Message string `json:"message"` } err := c.get(spotifyURL, &result) if err != nil { return "", nil, err } return result.Message, &result.Playlists, nil } // FeaturedPlaylists gets a list of playlists featured by Spotify. // It is equivalent to c.FeaturedPlaylistsOpt(nil). func (c *Client) FeaturedPlaylists() (message string, playlists *SimplePlaylistPage, e error) { return c.FeaturedPlaylistsOpt(nil) } // FollowPlaylist adds the current user as a follower of the specified // playlist. Any playlist can be followed, regardless of its private/public // status, as long as you know the owner and playlist ID. // // If the public argument is true, then the playlist will be included in the // user's public playlists. To be able to follow playlists privately, the user // must have granted the ScopePlaylistModifyPrivate scope. The // ScopePlaylistModifyPublic scope is required to follow playlists publicly. func (c *Client) FollowPlaylist(owner ID, playlist ID, public bool) error { spotifyURL := buildFollowURI(c.baseURL, owner, playlist) body := strings.NewReader(strconv.FormatBool(public)) req, err := http.NewRequest("PUT", spotifyURL, body) if err != nil { return err } req.Header.Set("Content-Type", "application/json") err = c.execute(req, nil) if err != nil { return err } return nil } // UnfollowPlaylist removes the current user as a follower of a playlist. // Unfollowing a publicly followed playlist requires ScopePlaylistModifyPublic. // Unfolowing a privately followed playlist requies ScopePlaylistModifyPrivate. func (c *Client) UnfollowPlaylist(owner, playlist ID) error { spotifyURL := buildFollowURI(c.baseURL, owner, playlist) req, err := http.NewRequest("DELETE", spotifyURL, nil) if err != nil { return err } err = c.execute(req, nil) if err != nil { return err } return nil } func buildFollowURI(url string, owner, playlist ID) string { return fmt.Sprintf("%susers/%s/playlists/%s/followers", url, string(owner), string(playlist)) } // GetPlaylistsForUser gets a list of the playlists owned or followed by a // particular Spotify user. // // Private playlists and collaborative playlists are only retrievable for the // current user. In order to read private playlists, the user must have granted // the ScopePlaylistReadPrivate scope. Note that this scope alone will not // return collaborative playlists, even though they are always private. In // order to read collaborative playlists, the user must have granted the // ScopePlaylistReadCollaborative scope. func (c *Client) GetPlaylistsForUser(userID string) (*SimplePlaylistPage, error) { return c.GetPlaylistsForUserOpt(userID, nil) } // GetPlaylistsForUserOpt is like PlaylistsForUser, but it accepts optional paramters // for filtering the results. func (c *Client) GetPlaylistsForUserOpt(userID string, opt *Options) (*SimplePlaylistPage, error) { spotifyURL := c.baseURL + "users/" + userID + "/playlists" if opt != nil { v := url.Values{} if opt.Limit != nil { v.Set("limit", strconv.Itoa(*opt.Limit)) } if opt.Offset != nil { v.Set("offset", strconv.Itoa(*opt.Offset)) } if params := v.Encode(); params != "" { spotifyURL += "?" + params } } var result SimplePlaylistPage err := c.get(spotifyURL, &result) if err != nil { return nil, err } return &result, err } // GetPlaylist gets a playlist owned by a Spotify user. // Both public and private playlists belonging to any user // are retrievable with a valid access token. func (c *Client) GetPlaylist(userID string, playlistID ID) (*FullPlaylist, error) { return c.GetPlaylistOpt(userID, playlistID, "") } // GetPlaylistOpt is like GetPlaylist, but it accepts an optional fields parameter // that can be used to filter the query. // // fields is a comma-separated list of the fields to return. // See the JSON tags on the FullPlaylist struct for valid field options. // For example, to get just the playlist's description and URI: // fields = "description,uri" // // A dot separator can be used to specify non-reoccurring fields, while // parentheses can be used to specify reoccurring fields within objects. // For example, to get just the added date and the user ID of the adder: // fields = "tracks.items(added_at,added_by.id)" // // Use multiple parentheses to drill down into nested objects, for example: // fields = "tracks.items(track(name,href,album(name,href)))" // // Fields can be excluded by prefixing them with an exclamation mark, for example; // fields = "tracks.items(track(name,href,album(!name,href)))" func (c *Client) GetPlaylistOpt(userID string, playlistID ID, fields string) (*FullPlaylist, error) { spotifyURL := fmt.Sprintf("%susers/%s/playlists/%s", c.baseURL, userID, playlistID) if fields != "" { spotifyURL += "?fields=" + url.QueryEscape(fields) } var playlist FullPlaylist err := c.get(spotifyURL, &playlist) if err != nil { return nil, err } return &playlist, err } // GetPlaylistTracks gets full details of the tracks in a playlist, given the // owner of the playlist and the playlist's Spotify ID. func (c *Client) GetPlaylistTracks(userID string, playlistID ID) (*PlaylistTrackPage, error) { return c.GetPlaylistTracksOpt(userID, playlistID, nil, "") } // GetPlaylistTracksOpt is like GetPlaylistTracks, but it accepts optional parameters // for sorting and filtering the results. // // The field parameter is a comma-separated list of the fields to return. See the // JSON struct tags for the PlaylistTrackPage type for valid field names. // For example, to get just the total number of tracks and the request limit: // fields = "total,limit" // // A dot separator can be used to specify non-reoccurring fields, while parentheses // can be used to specify reoccurring fields within objects. For example, to get // just the added date and user ID of the adder: // fields = "items(added_at,added_by.id // // Use multiple parentheses to drill down into nested objects. For example: // fields = "items(track(name,href,album(name,href)))" // // Fields can be excluded by prefixing them with an exclamation mark. For example: // fields = "items.track.album(!external_urls,images)" func (c *Client) GetPlaylistTracksOpt(userID string, playlistID ID, opt *Options, fields string) (*PlaylistTrackPage, error) { spotifyURL := fmt.Sprintf("%susers/%s/playlists/%s/tracks", c.baseURL, userID, playlistID) v := url.Values{} if fields != "" { v.Set("fields", fields) } if opt != nil { if opt.Limit != nil { v.Set("limit", strconv.Itoa(*opt.Limit)) } if opt.Offset != nil { v.Set("offset", strconv.Itoa(*opt.Offset)) } } if params := v.Encode(); params != "" { spotifyURL += "?" + params } var result PlaylistTrackPage err := c.get(spotifyURL, &result) if err != nil { return nil, err } return &result, err } // CreatePlaylistForUser creates a playlist for a Spotify user. // The playlist will be empty until you add tracks to it. // The playlistName does not need to be unique - a user can have // several playlists with the same name. // // Creating a public playlist for a user requires ScopePlaylistModifyPublic; // creating a private playlist requires ScopePlaylistModifyPrivate. // // On success, the newly created playlist is returned. func (c *Client) CreatePlaylistForUser(userID, playlistName string, public bool) (*FullPlaylist, error) { spotifyURL := fmt.Sprintf("%susers/%s/playlists", c.baseURL, userID) body := struct { Name string `json:"name"` Public bool `json:"public"` }{ playlistName, public, } bodyJSON, err := json.Marshal(body) if err != nil { return nil, err } req, err := http.NewRequest("POST", spotifyURL, bytes.NewReader(bodyJSON)) if err != nil { return nil, err } req.Header.Set("Content-Type", "application/json") var p FullPlaylist err = c.execute(req, &p, http.StatusCreated) if err != nil { return nil, err } return &p, err } // ChangePlaylistName changes the name of a playlist. This call requires that the // user has authorized the ScopePlaylistModifyPublic or ScopePlaylistModifyPrivate // scopes (depending on whether the playlist is public or private). // The current user must own the playlist in order to modify it. func (c *Client) ChangePlaylistName(userID string, playlistID ID, newName string) error { return c.modifyPlaylist(userID, playlistID, newName, nil) } // ChangePlaylistAccess modifies the public/private status of a playlist. This call // requires that the user has authorized the ScopePlaylistModifyPublic or // ScopePlaylistModifyPrivate scopes (depending on whether the playlist is // currently public or private). The current user must own the playlist in order to modify it. func (c *Client) ChangePlaylistAccess(userID string, playlistID ID, public bool) error { return c.modifyPlaylist(userID, playlistID, "", &public) } // ChangePlaylistNameAndAccess combines ChangePlaylistName and ChangePlaylistAccess into // a single Web API call. It requires that the user has authorized the ScopePlaylistModifyPublic // or ScopePlaylistModifyPrivate scopes (depending on whether the playlist is currently // public or private). The current user must own the playlist in order to modify it. func (c *Client) ChangePlaylistNameAndAccess(userID string, playlistID ID, newName string, public bool) error { return c.modifyPlaylist(userID, playlistID, newName, &public) } func (c *Client) modifyPlaylist(userID string, playlistID ID, newName string, public *bool) error { body := struct { Name string `json:"name,omitempty"` Public *bool `json:"public,omitempty"` }{ newName, public, } bodyJSON, err := json.Marshal(body) if err != nil { return err } spotifyURL := fmt.Sprintf("%susers/%s/playlists/%s", c.baseURL, userID, string(playlistID)) req, err := http.NewRequest("PUT", spotifyURL, bytes.NewReader(bodyJSON)) if err != nil { return err } req.Header.Set("Content-Type", "application/json") err = c.execute(req, nil, http.StatusCreated) if err != nil { return err } return nil } // AddTracksToPlaylist adds one or more tracks to a user's playlist. // This call requires ScopePlaylistModifyPublic or ScopePlaylistModifyPrivate. // A maximum of 100 tracks can be added per call. It returns a snapshot ID that // can be used to identify this version (the new version) of the playlist in // future requests. func (c *Client) AddTracksToPlaylist(userID string, playlistID ID, trackIDs ...ID) (snapshotID string, err error) { uris := make([]string, len(trackIDs)) for i, id := range trackIDs { uris[i] = fmt.Sprintf("spotify:track:%s", id) } m := make(map[string]interface{}) m["uris"] = uris spotifyURL := fmt.Sprintf("%susers/%s/playlists/%s/tracks", c.baseURL, userID, string(playlistID)) body, err := json.Marshal(m) if err != nil { return "", err } req, err := http.NewRequest("POST", spotifyURL, bytes.NewReader(body)) if err != nil { return "", err } req.Header.Set("Content-Type", "application/json") result := struct { SnapshotID string `json:"snapshot_id"` }{} err = c.execute(req, &result, http.StatusCreated) if err != nil { return "", err } return result.SnapshotID, nil } // RemoveTracksFromPlaylist removes one or more tracks from a user's playlist. // This call requrles that the user has authorized the ScopePlaylistModifyPublic // or ScopePlaylistModifyPrivate scopes. // // If the track(s) occur multiple times in the specified playlist, then all occurrences // of the track will be removed. If successful, the snapshot ID returned can be used to // identify the playlist version in future requests. func (c *Client) RemoveTracksFromPlaylist(userID string, playlistID ID, trackIDs ...ID) (newSnapshotID string, err error) { tracks := make([]struct { URI string `json:"uri"` }, len(trackIDs)) for i, u := range trackIDs { tracks[i].URI = fmt.Sprintf("spotify:track:%s", u) } return c.removeTracksFromPlaylist(userID, playlistID, tracks, "") } // TrackToRemove specifies a track to be removed from a playlist. // Positions is a slice of 0-based track indices. // TrackToRemove is used with RemoveTracksFromPlaylistOpt. type TrackToRemove struct { URI string `json:"uri"` Positions []int `json:"positions"` } // NewTrackToRemove creates a new TrackToRemove object with the specified // track ID and playlist locations. func NewTrackToRemove(trackID string, positions []int) TrackToRemove { return TrackToRemove{ URI: fmt.Sprintf("spotify:track:%s", trackID), Positions: positions, } } // RemoveTracksFromPlaylistOpt is like RemoveTracksFromPlaylist, but it supports // optional parameters that offer more fine-grained control. Instead of deleting // all occurrences of a track, this function takes an index with each track URI // that indicates the position of the track in the playlist. // // In addition, the snapshotID parameter allows you to specify the snapshot ID // against which you want to make the changes. Spotify will validate that the // specified tracks exist in the specified positions and make the changes, even // if more recent changes have been made to the playlist. If a track in the // specified position is not found, the entire request will fail and no edits // will take place. (Note: the snapshot is optional, pass the empty string if // you don't care about it.) func (c *Client) RemoveTracksFromPlaylistOpt(userID string, playlistID ID, tracks []TrackToRemove, snapshotID string) (newSnapshotID string, err error) { return c.removeTracksFromPlaylist(userID, playlistID, tracks, snapshotID) } func (c *Client) removeTracksFromPlaylist(userID string, playlistID ID, tracks interface{}, snapshotID string) (newSnapshotID string, err error) { m := make(map[string]interface{}) m["tracks"] = tracks if snapshotID != "" { m["snapshot_id"] = snapshotID } spotifyURL := fmt.Sprintf("%susers/%s/playlists/%s/tracks", c.baseURL, userID, string(playlistID)) body, err := json.Marshal(m) if err != nil { return "", err } req, err := http.NewRequest("DELETE", spotifyURL, bytes.NewReader(body)) if err != nil { return "", nil } req.Header.Set("Content-Type", "application/json") result := struct { SnapshotID string `json:"snapshot_id"` }{} err = c.execute(req, &result) if err != nil { return "", nil } return result.SnapshotID, err } // ReplacePlaylistTracks replaces all of the tracks in a playlist, overwriting its // exising tracks This can be useful for replacing or reordering tracks, or for // clearing a playlist. // // Modifying a public playlist requires that the user has authorized the // ScopePlaylistModifyPublic scope. Modifying a private playlist requires the // ScopePlaylistModifyPrivate scope. // // A maximum of 100 tracks is permited in this call. Additional tracks must be // added via AddTracksToPlaylist. func (c *Client) ReplacePlaylistTracks(userID string, playlistID ID, trackIDs ...ID) error { trackURIs := make([]string, len(trackIDs)) for i, u := range trackIDs { trackURIs[i] = fmt.Sprintf("spotify:track:%s", u) } spotifyURL := fmt.Sprintf("%susers/%s/playlists/%s/tracks?uris=%s", c.baseURL, userID, playlistID, strings.Join(trackURIs, ",")) req, err := http.NewRequest("PUT", spotifyURL, nil) if err != nil { return err } err = c.execute(req, nil, http.StatusCreated) if err != nil { return err } return nil } // UserFollowsPlaylist checks if one or more (up to 5) Spotify users are following // a Spotify playlist, given the playlist's owner and ID. // // Checking if a user follows a playlist publicly doesn't require any scopes. // Checking if the user is privately following a playlist is only possible for the // current user when that user has granted access to the ScopePlaylistReadPrivate scope. func (c *Client) UserFollowsPlaylist(ownerID string, playlistID ID, userIDs ...string) ([]bool, error) { spotifyURL := fmt.Sprintf("%susers/%s/playlists/%s/followers/contains?ids=%s", c.baseURL, ownerID, playlistID, strings.Join(userIDs, ",")) follows := make([]bool, len(userIDs)) err := c.get(spotifyURL, &follows) if err != nil { return nil, err } return follows, err } // PlaylistReorderOptions is used with ReorderPlaylistTracks to reorder // a track or group of tracks in a playlist. // // For example, in a playlist with 10 tracks, you can: // // - move the first track to the end of the playlist by setting // RangeStart to 0 and InsertBefore to 10 // - move the last track to the beginning of the playlist by setting // RangeStart to 9 and InsertBefore to 0 // - Move the last 2 tracks to the beginning of the playlist by setting // RangeStart to 8 and RangeLength to 2. type PlaylistReorderOptions struct { // The position of the first track to be reordered. // This field is required. RangeStart int `json:"range_start"` // The amount of tracks to be reordered. This field is optional. If // you don't set it, the value 1 will be used. RangeLength int `json:"range_length,omitempty"` // The position where the tracks should be inserted. To reorder the // tracks to the end of the playlist, simply set this to the position // after the last track. This field is required. InsertBefore int `json:"insert_before"` // The playlist's snapshot ID against which you wish to make the changes. // This field is optional. SnapshotID string `json:"snapshot_id,omitempty"` } // ReorderPlaylistTracks reorders a track or group of tracks in a playlist. It // returns a snapshot ID that can be used to identify the [newly modified] playlist // version in future requests. // // See the docs for PlaylistReorderOptions for information on how the reordering // works. // // Reordering tracks in the current user's public playlist requires ScopePlaylistModifyPublic. // Reordering tracks in the user's private playlists (including collaborative playlists) requires // ScopePlaylistModifyPrivate. func (c *Client) ReorderPlaylistTracks(userID string, playlistID ID, opt PlaylistReorderOptions) (snapshotID string, err error) { spotifyURL := fmt.Sprintf("%susers/%s/playlists/%s/tracks", c.baseURL, userID, playlistID) j, err := json.Marshal(opt) if err != nil { return "", err } req, err := http.NewRequest("PUT", spotifyURL, bytes.NewReader(j)) if err != nil { return "", err } req.Header.Set("Content-Type", "application/json") result := struct { SnapshotID string `json:"snapshot_id"` }{} err = c.execute(req, &result) if err != nil { return "", err } return result.SnapshotID, err } // SetPlaylistImage replaces the image used to represent a playlist. // This action can only be performed by the owner of the playlist, // and requires ScopeImageUpload as well as ScopeModifyPlaylist{Public|Private}.. func (c *Client) SetPlaylistImage(userID string, playlistID ID, img io.Reader) error { spotifyURL := fmt.Sprintf("%susers/%s/playlists/%s/images", c.baseURL, userID, playlistID) // data flow: // img (reader) -> copy into base64 encoder (writer) -> pipe (write end) // pipe (read end) -> request body r, w := io.Pipe() go func() { enc := base64.NewEncoder(base64.StdEncoding, w) _, err := io.Copy(enc, img) enc.Close() w.CloseWithError(err) }() req, err := http.NewRequest("PUT", spotifyURL, r) if err != nil { return err } req.Header.Set("Content-Type", "image/jpeg") return c.execute(req, nil, http.StatusAccepted) } ================================================ FILE: vendor/github.com/zmb3/spotify/playlist_test.go ================================================ package spotify import ( "bytes" "encoding/json" "fmt" "io/ioutil" "net/http" "testing" "time" ) func TestFeaturedPlaylists(t *testing.T) { client, server := testClientFile(http.StatusOK, "test_data/featured_playlists.txt") defer server.Close() country := "SE" opt := PlaylistOptions{} opt.Country = &country msg, p, err := client.FeaturedPlaylistsOpt(&opt) if err != nil { t.Error(err) return } if msg != "Enjoy a mellow afternoon." { t.Errorf("Want 'Enjoy a mellow afternoon.', got'%s'\n", msg) } if p.Playlists == nil || len(p.Playlists) == 0 { t.Fatal("Empty playlists result") } expected := "Hangover Friendly Singer-Songwriter" if name := p.Playlists[0].Name; name != expected { t.Errorf("Want '%s', got '%s'\n", expected, name) } } func TestFeaturedPlaylistsExpiredToken(t *testing.T) { json := `{ "error": { "status": 401, "message": "The access token expired" } }` client, server := testClientString(http.StatusUnauthorized, json) defer server.Close() msg, pl, err := client.FeaturedPlaylists() if msg != "" || pl != nil || err == nil { t.Fatal("Expected an error") } serr, ok := err.(Error) if !ok { t.Fatalf("Expected spotify Error, got %T", err) } if serr.Status != http.StatusUnauthorized { t.Error("Expected HTTP 401") } } func TestPlaylistsForUser(t *testing.T) { client, server := testClientFile(http.StatusOK, "test_data/playlists_for_user.txt") defer server.Close() playlists, err := client.GetPlaylistsForUser("whizler") if err != nil { t.Error(err) } if l := len(playlists.Playlists); l == 0 { t.Fatal("Didn't get any results") } p := playlists.Playlists[0] if p.Name != "Nederlandse Tipparade" { t.Error("Expected Nederlandse Tipparade, got", p.Name) } if p.Tracks.Total != 29 { t.Error("Expected 29 tracks, got", p.Tracks.Total) } } func TestGetPlaylistOpt(t *testing.T) { client, server := testClientFile(http.StatusOK, "test_data/get_playlist_opt.txt") defer server.Close() fields := "href,name,owner(!href,external_urls),tracks.items(added_by.id,track(name,href,album(name,href)))" p, err := client.GetPlaylistOpt("spotify", "59ZbFPES4DQwEjBpWHzrtC", fields) if err != nil { t.Error(err) } if p.Collaborative { t.Error("Playlist shouldn't be collaborative") } if p.Description != "" { t.Error("No description should be included") } if p.Tracks.Total != 10 { t.Error("Expected 10 tracks") } } func TestFollowPlaylistSetsContentType(t *testing.T) { client, server := testClientString(http.StatusOK, "", func(req *http.Request) { if req.Header.Get("Content-Type") != "application/json" { t.Error("Follow playlist request didn't contain Content-Type: application/json") } }) defer server.Close() err := client.FollowPlaylist("ownerID", "playlistID", true) if err != nil { t.Error(err) } } func TestGetPlaylistTracks(t *testing.T) { client, server := testClientFile(http.StatusOK, "test_data/playlist_tracks.txt") defer server.Close() tracks, err := client.GetPlaylistTracks("user", "playlistID") if err != nil { t.Error(err) } if tracks.Total != 47 { t.Errorf("Got %d tracks, expected 47\n", tracks.Total) } if len(tracks.Tracks) == 0 { t.Fatal("No tracks returned") } expected := "Time Of Our Lives" actual := tracks.Tracks[0].Track.Name if expected != actual { t.Errorf("Got '%s', expected '%s'\n", actual, expected) } added := tracks.Tracks[0].AddedAt tm, err := time.Parse(TimestampLayout, added) if err != nil { t.Error(err) } if f := tm.Format(DateLayout); f != "2014-11-25" { t.Errorf("Expected added at 2014-11-25, got %s\n", f) } } func TestUserFollowsPlaylist(t *testing.T) { client, server := testClientString(http.StatusOK, `[ true, false ]`) defer server.Close() follows, err := client.UserFollowsPlaylist("jmperezperez", ID("2v3iNvBS8Ay1Gt2uXtUKUT"), "possan", "elogain") if err != nil { t.Error(err) } if len(follows) != 2 || !follows[0] || follows[1] { t.Errorf("Expected '[true, false]', got %#v\n", follows) } } var newPlaylist = ` { "collaborative": false, "description": null, "external_urls": { "spotify": "http://open.spotify.com/user/thelinmichael/playlist/7d2D2S200NyUE5KYs80PwO" }, "followers": { "href": null, "total": 0 }, "href": "https://api.spotify.com/v1/users/thelinmichael/playlists/7d2D2S200NyUE5KYs80PwO", "id": "7d2D2S200NyUE5KYs80PwO", "images": [ ], "name": "A New Playlist", "owner": { "external_urls": { "spotify": "http://open.spotify.com/user/thelinmichael" }, "href": "https://api.spotify.com/v1/users/thelinmichael", "id": "thelinmichael", "type": "user", "url": "spotify:user:thelinmichael" }, "public": false, "snapshot_id": "s0o3TSuYnRLl2jch+oA4OEbKwq/fNxhGBkSPnvhZdmWjNV0q3uCAWuGIhEx8SHIx", "tracks": { "href": "https://api.spotify.com/v1/users/thelinmichael/playlists/7d2D2S200NyUE5KYs80PwO/tracks", "items": [ ], "limit": 100, "next": null, "offset": 0, "previous": null, "total": 0 }, "type": "playlist", "url": "spotify:user:thelinmichael:playlist:7d2D2S200NyUE5KYs80PwO" }` func TestCreatePlaylist(t *testing.T) { client, server := testClientString(http.StatusCreated, newPlaylist) defer server.Close() p, err := client.CreatePlaylistForUser("thelinmichael", "A New Playlist", false) if err != nil { t.Error(err) } if p.IsPublic { t.Error("Expected private playlist, got public") } if p.Name != "A New Playlist" { t.Errorf("Expected 'A New Playlist', got '%s'\n", p.Name) } if p.Tracks.Total != 0 { t.Error("Expected new playlist to be empty") } } func TestRenamePlaylist(t *testing.T) { client, server := testClientString(http.StatusOK, "") defer server.Close() if err := client.ChangePlaylistName("user", ID("playlist-id"), "new name"); err != nil { t.Error(err) } } func TestChangePlaylistAccess(t *testing.T) { client, server := testClientString(http.StatusOK, "") defer server.Close() if err := client.ChangePlaylistAccess("user", ID("playlist-id"), true); err != nil { t.Error(err) } } func TestChangePlaylistNamdAndAccess(t *testing.T) { client, server := testClientString(http.StatusOK, "") defer server.Close() if err := client.ChangePlaylistNameAndAccess("user", ID("playlist-id"), "new_name", true); err != nil { t.Error(err) } } func TestChangePlaylistNameFailure(t *testing.T) { client, server := testClientString(http.StatusForbidden, "") defer server.Close() if err := client.ChangePlaylistName("user", ID("playlist-id"), "new_name"); err == nil { t.Error("Expected error but didn't get one") } } func TestAddTracksToPlaylist(t *testing.T) { client, server := testClientString(http.StatusCreated, `{ "snapshot_id" : "JbtmHBDBAYu3/bt8BOXKjzKx3i0b6LCa/wVjyl6qQ2Yf6nFXkbmzuEa+ZI/U1yF+" }`) defer server.Close() snapshot, err := client.AddTracksToPlaylist("user", ID("playlist_id"), ID("track1"), ID("track2")) if err != nil { t.Error(err) } if snapshot != "JbtmHBDBAYu3/bt8BOXKjzKx3i0b6LCa/wVjyl6qQ2Yf6nFXkbmzuEa+ZI/U1yF+" { t.Error("Didn't get expected snapshot ID") } } func TestRemoveTracksFromPlaylist(t *testing.T) { client, server := testClientString(http.StatusOK, `{ "snapshot_id" : "JbtmHBDBAYu3/bt8BOXKjzKx3i0b6LCa/wVjyl6qQ2Yf6nFXkbmzuEa+ZI/U1yF+" }`, func(req *http.Request) { requestBody, err := ioutil.ReadAll(req.Body) var body map[string]interface{} err = json.Unmarshal(requestBody, &body) if err != nil { t.Fatal("Error decoding request body:", err) } tracksArray, ok := body["tracks"] if !ok { t.Error("No tracks JSON object in request body") } tracksSlice := tracksArray.([]interface{}) if l := len(tracksSlice); l != 2 { t.Fatalf("Expected 2 tracks, got %d\n", l) } track0 := tracksSlice[0].(map[string]interface{}) trackURI, ok := track0["uri"] if !ok { t.Error("Track object doesn't contain 'uri' field") } if trackURI != "spotify:track:track1" { t.Errorf("Expeced URI: 'spotify:track:track1', got '%s'\n", trackURI) } }) defer server.Close() snapshotID, err := client.RemoveTracksFromPlaylist("userID", "playlistID", "track1", "track2") if err != nil { t.Error(err) } if snapshotID != "JbtmHBDBAYu3/bt8BOXKjzKx3i0b6LCa/wVjyl6qQ2Yf6nFXkbmzuEa+ZI/U1yF+" { t.Error("Incorrect snapshot ID") } } func TestRemoveTracksFromPlaylistOpt(t *testing.T) { client, server := testClientString(http.StatusOK, `{ "snapshot_id" : "JbtmHBDBAYu3/bt8BOXKjzKx3i0b6LCa/wVjyl6qQ2Yf6nFXkbmzuEa+ZI/U1yF+" }`, func(req *http.Request) { requestBody, err := ioutil.ReadAll(req.Body) if err != nil { t.Fatal(err) } var body map[string]interface{} err = json.Unmarshal(requestBody, &body) if err != nil { t.Fatal(err) } if _, ok := body["snapshot_id"]; ok { t.Error("JSON contains snapshot_id field when none was specified") fmt.Println(string(requestBody)) return } jsonTracks := body["tracks"].([]interface{}) if len(jsonTracks) != 3 { t.Fatal("Expected 3 tracks, got", len(jsonTracks)) } track1 := jsonTracks[1].(map[string]interface{}) expected := "spotify:track:track1" if track1["uri"] != expected { t.Fatalf("Want '%s', got '%s'\n", expected, track1["uri"]) } indices := track1["positions"].([]interface{}) if len(indices) != 1 || int(indices[0].(float64)) != 9 { t.Error("Track indices incorrect") } }) defer server.Close() tracks := []TrackToRemove{ NewTrackToRemove("track0", []int{0, 4}), // remove track0 in position 0 and 4 NewTrackToRemove("track1", []int{9}), // remove track1 in position 9... NewTrackToRemove("track2", []int{8}), } // intentionally not passing a snapshot ID here snapshotID, err := client.RemoveTracksFromPlaylistOpt("userID", "playlistID", tracks, "") if err != nil || snapshotID != "JbtmHBDBAYu3/bt8BOXKjzKx3i0b6LCa/wVjyl6qQ2Yf6nFXkbmzuEa+ZI/U1yF+" { t.Fatal("Remove call failed. err=", err) } } func TestReplacePlaylistTracks(t *testing.T) { client, server := testClientString(http.StatusCreated, "") defer server.Close() err := client.ReplacePlaylistTracks("userID", "playlistID", "track1", "track2") if err != nil { t.Error(err) } } func TestReplacePlaylistTracksForbidden(t *testing.T) { client, server := testClientString(http.StatusForbidden, "") defer server.Close() err := client.ReplacePlaylistTracks("userID", "playlistID", "track1", "track2") if err == nil { t.Error("Replace succeeded but shouldn't have") } } func TestReorderPlaylistRequest(t *testing.T) { client, server := testClientString(http.StatusNotFound, "", func(req *http.Request) { if ct := req.Header.Get("Content-Type"); ct != "application/json" { t.Errorf("Expected Content-Type: application/json, got '%s'\n", ct) } if req.Method != "PUT" { t.Errorf("Expected a PUT, got a %s\n", req.Method) } // unmarshal the JSON into a map[string]interface{} // so we can test for existence of certain keys var body map[string]interface{} json.NewDecoder(req.Body).Decode(&body) if start, ok := body["range_start"]; ok { if start != float64(3) { t.Errorf("Expected range_start to be 3, but it was %#v\n", start) } } else { t.Errorf("Required field range_start is missing") } if ib, ok := body["insert_before"]; ok { if ib != float64(8) { t.Errorf("Expected insert_before to be 8, but it was %#v\n", ib) } } else { t.Errorf("Required field insert_before is missing") } if _, ok := body["range_length"]; ok { t.Error("Parameter range_length shouldn't have been in body") } if _, ok := body["snapshot_id"]; ok { t.Error("Parameter snapshot_id shouldn't have been in body") } }) defer server.Close() client.ReorderPlaylistTracks("user", "playlist", PlaylistReorderOptions{ RangeStart: 3, InsertBefore: 8, }) } func TestSetPlaylistImage(t *testing.T) { client, server := testClientString(http.StatusAccepted, "", func(req *http.Request) { if ct := req.Header.Get("Content-Type"); ct != "image/jpeg" { t.Errorf("wrong content type, got %s, want image/jpeg", ct) } if req.Method != "PUT" { t.Errorf("expected a PUT, got a %s\n", req.Method) } body, err := ioutil.ReadAll(req.Body) if err != nil { t.Fatal(err) } if !bytes.Equal(body, []byte("Zm9v")) { t.Errorf("invalid request body: want Zm9v, got %s", string(body)) } }) defer server.Close() err := client.SetPlaylistImage("user", "playlist", bytes.NewReader([]byte("foo"))) if err != nil { t.Fatal(err) } } ================================================ FILE: vendor/github.com/zmb3/spotify/recommendation.go ================================================ package spotify import ( "fmt" "net/url" "strconv" "strings" ) // Seeds contains IDs of artists, genres and/or tracks // to be used as seeds for recommendations type Seeds struct { Artists []ID Tracks []ID Genres []string } // count returns the total number of seeds contained in s func (s Seeds) count() int { return len(s.Artists) + len(s.Tracks) + len(s.Genres) } // Recommendations contains a list of recommended tracks based on seeds type Recommendations struct { Seeds []RecommendationSeed `json:"seeds"` Tracks []SimpleTrack `json:"tracks"` } // RecommendationSeed represents a recommendation seed after // being processed by the Spotify API type RecommendationSeed struct { AfterFilteringSize int `json:"afterFilteringSize"` AfterRelinkingSize int `json:"afterRelinkingSize"` Endpoint string `json:"href"` ID ID `json:"id"` InitialPoolSize int `json:"initialPoolSize"` Type string `json:"type"` } // MaxNumberOfSeeds allowed by Spotify for a recommendation request const MaxNumberOfSeeds = 5 // setSeedValues sets url values into v for each seed in seeds func setSeedValues(seeds Seeds, v url.Values) { if len(seeds.Artists) != 0 { v.Set("seed_artists", strings.Join(toStringSlice(seeds.Artists), ",")) } if len(seeds.Tracks) != 0 { v.Set("seed_tracks", strings.Join(toStringSlice(seeds.Tracks), ",")) } if len(seeds.Genres) != 0 { v.Set("seed_genres", strings.Join(seeds.Genres, ",")) } } // setTrackAttributesValues sets track attributes values to the given url values func setTrackAttributesValues(trackAttributes *TrackAttributes, values url.Values) { if trackAttributes == nil { return } for attr, val := range trackAttributes.intAttributes { values.Set(attr, strconv.Itoa(val)) } for attr, val := range trackAttributes.floatAttributes { values.Set(attr, strconv.FormatFloat(val, 'f', -1, 64)) } } // GetRecommendations returns a list of recommended tracks based on the given seeds. // Recommendations are generated based on the available information for a given seed entity // and matched against similar artists and tracks. If there is sufficient information // about the provided seeds, a list of tracks will be returned together with pool size details. // For artists and tracks that are very new or obscure // there might not be enough data to generate a list of tracks. func (c *Client) GetRecommendations(seeds Seeds, trackAttributes *TrackAttributes, opt *Options) (*Recommendations, error) { v := url.Values{} if seeds.count() == 0 { return nil, fmt.Errorf("spotify: at least one seed is required") } if seeds.count() > MaxNumberOfSeeds { return nil, fmt.Errorf("spotify: exceeded maximum of %d seeds", MaxNumberOfSeeds) } setSeedValues(seeds, v) setTrackAttributesValues(trackAttributes, v) if opt != nil { if opt.Limit != nil { v.Set("limit", strconv.Itoa(*opt.Limit)) } if opt.Country != nil { v.Set("market", *opt.Country) } } spotifyURL := c.baseURL + "recommendations?" + v.Encode() var recommendations Recommendations err := c.get(spotifyURL, &recommendations) if err != nil { return nil, err } return &recommendations, err } // GetAvailableGenreSeeds retrieves a list of available genres seed parameter values for // recommendations. func (c *Client) GetAvailableGenreSeeds() ([]string, error) { spotifyURL := c.baseURL + "recommendations/available-genre-seeds" genreSeeds := make(map[string][]string) err := c.get(spotifyURL, &genreSeeds) if err != nil { return nil, err } return genreSeeds["genres"], nil } ================================================ FILE: vendor/github.com/zmb3/spotify/recommendation_test.go ================================================ package spotify import ( "net/url" "testing" ) func TestGetRecommendations(t *testing.T) { // test data corresponding to Spotify Console web API sample client, server := testClientFile(200, "test_data/recommendations.txt") defer server.Close() seeds := Seeds{ Artists: []ID{"4NHQUGzhtTLFvgF5SZesLK"}, Tracks: []ID{"0c6xIDDpzE81m2q797ordA"}, Genres: []string{"classical", "country"}, } country := "ES" limit := 10 opts := Options{ Country: &country, Limit: &limit, } recommendations, err := client.GetRecommendations(seeds, nil, &opts) if err != nil { t.Fatal(err) } if len(recommendations.Tracks) != 10 { t.Error("Expected 10 recommended tracks") } if recommendations.Tracks[0].Artists[0].Name != "Heinrich Isaac" { t.Error("Expected the artist of the first recommended track to be Heinrich Isaac") } } func TestSetSeedValues(t *testing.T) { expectedValues := "seed_artists=4NHQUGzhtTLFvgF5SZesLK%2C5PHQUGzhtTUIvgF5SZesGY&seed_genres=classical%2Ccountry" v := url.Values{} seeds := Seeds{ Artists: []ID{"4NHQUGzhtTLFvgF5SZesLK", "5PHQUGzhtTUIvgF5SZesGY"}, Genres: []string{"classical", "country"}, } setSeedValues(seeds, v) actualValues := v.Encode() if actualValues != expectedValues { t.Errorf("Expected seed values to be %s but got %s", expectedValues, actualValues) } } func TestSetTrackAttributesValues(t *testing.T) { expectedValues := "max_duration_ms=200&min_duration_ms=20&min_energy=0.45&target_acousticness=0.27&target_duration_ms=160" v := url.Values{} ta := NewTrackAttributes(). MaxDuration(200). MinDuration(20). TargetDuration(160). MinEnergy(0.45). TargetAcousticness(0.27) setTrackAttributesValues(ta, v) actualValues := v.Encode() if actualValues != expectedValues { t.Errorf("Expected track attributes values to be %s but got %s", expectedValues, actualValues) } } func TestSetEmptyTrackAttributesValues(t *testing.T) { expectedValues := "" v := url.Values{} setTrackAttributesValues(nil, v) actualValues := v.Encode() if actualValues != expectedValues { t.Errorf("Expected track attributes values to be empty but got %s", actualValues) } } ================================================ FILE: vendor/github.com/zmb3/spotify/search.go ================================================ package spotify import ( "net/url" "strconv" "strings" ) const ( // MarketFromToken can be used in place of the Market parameter // if the Client has a valid access token. In this case, the // results will be limited to content that is playable in the // country associated with the user's account. The user must have // granted access to the user-read-private scope when the access // token was issued. MarketFromToken = "from_token" ) // SearchType represents the type of a query used in the Search function. type SearchType int // Search type values that can be passed to the Search function. These are flags // that can be bitwise OR'd together to search for multiple types of content simultaneously. const ( SearchTypeAlbum SearchType = 1 << iota SearchTypeArtist = 1 << iota SearchTypePlaylist = 1 << iota SearchTypeTrack = 1 << iota ) func (st SearchType) encode() string { types := []string{} if st&SearchTypeAlbum != 0 { types = append(types, "album") } if st&SearchTypeArtist != 0 { types = append(types, "artist") } if st&SearchTypePlaylist != 0 { types = append(types, "playlist") } if st&SearchTypeTrack != 0 { types = append(types, "track") } return strings.Join(types, ",") } // SearchResult contains the results of a call to Search. // Fields that weren't searched for will be nil pointers. type SearchResult struct { Artists *FullArtistPage `json:"artists"` Albums *SimpleAlbumPage `json:"albums"` Playlists *SimplePlaylistPage `json:"playlists"` Tracks *FullTrackPage `json:"tracks"` } // Search gets Spotify catalog information about artists, albums, tracks, // or playlists that match a keyword string. t is a mask containing one or more // search types. For example, `Search(query, SearchTypeArtist|SearchTypeAlbum)` // will search for artists or albums matching the specified keywords. // // Matching // // Matching of search keywords is NOT case sensitive. Keywords are matched in // any order unless surrounded by double quotes. Searching for playlists will // return results where the query keyword(s) match any part of the playlist's // name or description. Only popular public playlists are returned. // // Operators // // The operator NOT can be used to exclude results. For example, // query = "roadhouse NOT blues" returns items that match "roadhouse" but exludes // those that also contain the keyword "blues". Similarly, the OR operator can // be used to broaden the search. query = "roadhouse OR blues" returns all results // that include either of the terms. Only one OR operator can be used in a query. // // Operators should be specified in uppercase. // // Wildcards // // The asterisk (*) character can, with some limitations, be used as a wildcard // (maximum of 2 per query). It will match a variable number of non-white-space // characters. It cannot be used in a quoted phrase, in a field filter, or as // the first character of a keyword string. // // Field filters // // By default, results are returned when a match is found in any field of the // target object type. Searches can be made more specific by specifying an album, // artist, or track field filter. For example, "album:gold artist:abba type:album" // will only return results with the text "gold" in the album name and the text // "abba" in the artist's name. // // The field filter "year" can be used with album, artist, and track searches to // limit the results to a particular year. For example "bob year:2014" or // "bob year:1980-2020". // // The field filter "tag:new" can be used in album searches to retrieve only // albums released in the last two weeks. The field filter "tag:hipster" can be // used in album searches to retrieve only albums with the lowest 10% popularity. // // Other possible field filters, depending on object types being searched, // include "genre", "upc", and "isrc". For example "damian genre:reggae-pop". func (c *Client) Search(query string, t SearchType) (*SearchResult, error) { return c.SearchOpt(query, t, nil) } // SearchOpt works just like Search, but it accepts additional // parameters for filtering the output. See the documentation for Search more // more information. // // If the Country field is specified in the options, then the results will only // contain artists, albums, and tracks playable in the specified country // (playlist results are not affected by the Country option). Additionally, // the constant MarketFromToken can be used with authenticated clients. // If the client has a valid access token, then the results will only include // content playable in the user's country. func (c *Client) SearchOpt(query string, t SearchType, opt *Options) (*SearchResult, error) { v := url.Values{} v.Set("q", query) v.Set("type", t.encode()) if opt != nil { if opt.Limit != nil { v.Set("limit", strconv.Itoa(*opt.Limit)) } if opt.Country != nil { v.Set("market", *opt.Country) } if opt.Offset != nil { v.Set("offset", strconv.Itoa(*opt.Offset)) } } spotifyURL := c.baseURL + "search?" + v.Encode() var result SearchResult err := c.get(spotifyURL, &result) if err != nil { return nil, err } return &result, err } // NextArtistResults loads the next page of artists into the specified search result. func (c *Client) NextArtistResults(s *SearchResult) error { if s.Artists == nil || s.Artists.Next == "" { return ErrNoMorePages } return c.get(s.Artists.Next, s) } // PreviousArtistResults loads the previous page of artists into the specified search result. func (c *Client) PreviousArtistResults(s *SearchResult) error { if s.Artists == nil || s.Artists.Previous == "" { return ErrNoMorePages } return c.get(s.Artists.Previous, s) } // NextAlbumResults loads the next page of albums into the specified search result. func (c *Client) NextAlbumResults(s *SearchResult) error { if s.Albums == nil || s.Albums.Next == "" { return ErrNoMorePages } return c.get(s.Albums.Next, s) } // PreviousAlbumResults loads the previous page of albums into the specified search result. func (c *Client) PreviousAlbumResults(s *SearchResult) error { if s.Albums == nil || s.Albums.Previous == "" { return ErrNoMorePages } return c.get(s.Albums.Previous, s) } // NextPlaylistResults loads the next page of playlists into the specified search result. func (c *Client) NextPlaylistResults(s *SearchResult) error { if s.Playlists == nil || s.Playlists.Next == "" { return ErrNoMorePages } return c.get(s.Playlists.Next, s) } // PreviousPlaylistResults loads the previous page of playlists into the specified search result. func (c *Client) PreviousPlaylistResults(s *SearchResult) error { if s.Playlists == nil || s.Playlists.Previous == "" { return ErrNoMorePages } return c.get(s.Playlists.Previous, s) } // PreviousTrackResults loads the previous page of tracks into the specified search result. func (c *Client) PreviousTrackResults(s *SearchResult) error { if s.Tracks == nil || s.Tracks.Previous == "" { return ErrNoMorePages } return c.get(s.Tracks.Previous, s) } // NextTrackResults loads the next page of tracks into the specified search result. func (c *Client) NextTrackResults(s *SearchResult) error { if s.Tracks == nil || s.Tracks.Next == "" { return ErrNoMorePages } return c.get(s.Tracks.Next, s) } ================================================ FILE: vendor/github.com/zmb3/spotify/search_test.go ================================================ package spotify import ( "net/http" "testing" ) func TestSearchArtist(t *testing.T) { client, server := testClientFile(http.StatusOK, "test_data/search_artist.txt") defer server.Close() result, err := client.Search("tania bowra", SearchTypeArtist) if err != nil { t.Error(err) } if result.Albums != nil { t.Error("Searched for artists but received album results") } if result.Playlists != nil { t.Error("Searched for artists but received playlist results") } if result.Tracks != nil { t.Error("Searched for artists but received track results") } if result.Artists == nil || len(result.Artists.Artists) == 0 { t.Error("Didn't receive artist results") } if result.Artists.Artists[0].Name != "Tania Bowra" { t.Error("Got wrong artist name") } } func TestSearchTracks(t *testing.T) { client, server := testClientFile(http.StatusOK, "test_data/search_tracks.txt") defer server.Close() result, err := client.Search("uptown", SearchTypeTrack) if err != nil { t.Error(err) } if result.Albums != nil { t.Error("Searched for tracks but got album results") } if result.Playlists != nil { t.Error("Searched for tracks but got playlist results") } if result.Artists != nil { t.Error("Searched for tracks but got artist results") } if result.Tracks == nil || len(result.Tracks.Tracks) == 0 { t.Fatal("Didn't receive track results") } if name := result.Tracks.Tracks[0].Name; name != "Uptown Funk" { t.Errorf("Got %s, wanted Uptown Funk\n", name) } } func TestSearchPlaylistTrack(t *testing.T) { client, server := testClientFile(http.StatusOK, "test_data/search_trackplaylist.txt") defer server.Close() result, err := client.Search("holiday", SearchTypePlaylist|SearchTypeTrack) if err != nil { t.Error(err) } if result.Albums != nil { t.Error("Searched for playlists and tracks but received album results") } if result.Artists != nil { t.Error("Searched for playlists and tracks but received artist results") } if result.Tracks == nil { t.Error("Didn't receive track results") } if result.Playlists == nil { t.Error("Didn't receive playlist results") } } func TestPrevNextSearchPageErrors(t *testing.T) { client, server := testClientString(0, "") defer server.Close() // we expect to get ErrNoMorePages when trying to get the prev/next page // under either of these conditions: // 1) there are no results (nil) nilResults := &SearchResult{nil, nil, nil, nil} if client.NextAlbumResults(nilResults) != ErrNoMorePages || client.NextArtistResults(nilResults) != ErrNoMorePages || client.NextPlaylistResults(nilResults) != ErrNoMorePages || client.NextTrackResults(nilResults) != ErrNoMorePages { t.Error("Next search result page should have failed for nil results") } if client.PreviousAlbumResults(nilResults) != ErrNoMorePages || client.PreviousArtistResults(nilResults) != ErrNoMorePages || client.PreviousPlaylistResults(nilResults) != ErrNoMorePages || client.PreviousTrackResults(nilResults) != ErrNoMorePages { t.Error("Previous search result page should have failed for nil results") } // 2) the prev/next URL is empty emptyURL := &SearchResult{ Artists: new(FullArtistPage), Albums: new(SimpleAlbumPage), Playlists: new(SimplePlaylistPage), Tracks: new(FullTrackPage), } if client.NextAlbumResults(emptyURL) != ErrNoMorePages || client.NextArtistResults(emptyURL) != ErrNoMorePages || client.NextPlaylistResults(emptyURL) != ErrNoMorePages || client.NextTrackResults(emptyURL) != ErrNoMorePages { t.Error("Next search result page should have failed with empty URL") } if client.PreviousAlbumResults(emptyURL) != ErrNoMorePages || client.PreviousArtistResults(emptyURL) != ErrNoMorePages || client.PreviousPlaylistResults(emptyURL) != ErrNoMorePages || client.PreviousTrackResults(emptyURL) != ErrNoMorePages { t.Error("Previous search result page should have failed with empty URL") } } ================================================ FILE: vendor/github.com/zmb3/spotify/spotify.go ================================================ // Package spotify provides utilties for interfacing // with Spotify's Web API. package spotify import ( "bytes" "encoding/json" "errors" "fmt" "io" "io/ioutil" "net/http" "net/url" "strconv" "time" ) // Version is the version of this library. const Version = "1.0.0" const ( // DateLayout can be used with time.Parse to create time.Time values // from Spotify date strings. For example, PrivateUser.Birthdate // uses this format. DateLayout = "2006-01-02" // TimestampLayout can be used with time.Parse to create time.Time // values from SpotifyTimestamp strings. It is an ISO 8601 UTC timestamp // with a zero offset. For example, PlaylistTrack's AddedAt field uses // this format. TimestampLayout = "2006-01-02T15:04:05Z" // defaultRetryDurationS helps us fix an apparent server bug whereby we will // be told to retry but not be given a wait-interval. defaultRetryDuration = time.Second * 5 // rateLimitExceededStatusCode is the code that the server returns when our // request frequency is too high. rateLimitExceededStatusCode = 429 ) const baseAddress = "https://api.spotify.com/v1/" // Client is a client for working with the Spotify Web API. // To create an authenticated client, use the `Authenticator.NewClient` method. type Client struct { http *http.Client baseURL string AutoRetry bool } // URI identifies an artist, album, track, or category. For example, // spotify:track:6rqhFgbbKwnb9MLmUQDhG6 type URI string // ID is a base-62 identifier for an artist, track, album, etc. // It can be found at the end of a spotify.URI. type ID string func (id *ID) String() string { return string(*id) } // Followers contains information about the number of people following a // particular artist or playlist. type Followers struct { // The total number of followers. Count uint `json:"total"` // A link to the Web API endpoint providing full details of the followers, // or the empty string if this data is not available. Endpoint string `json:"href"` } // Image identifies an image associated with an item. type Image struct { // The image height, in pixels. Height int `json:"height"` // The image width, in pixels. Width int `json:"width"` // The source URL of the image. URL string `json:"url"` } // Download downloads the image and writes its data to the specified io.Writer. func (i Image) Download(dst io.Writer) error { resp, err := http.Get(i.URL) if err != nil { return err } defer resp.Body.Close() // TODO: get Content-Type from header? if resp.StatusCode != http.StatusOK { return errors.New("Couldn't download image - HTTP" + strconv.Itoa(resp.StatusCode)) } _, err = io.Copy(dst, resp.Body) return err } // Error represents an error returned by the Spotify Web API. type Error struct { // A short description of the error. Message string `json:"message"` // The HTTP status code. Status int `json:"status"` } func (e Error) Error() string { return e.Message } // decodeError decodes an Error from an io.Reader. func (c *Client) decodeError(resp *http.Response) error { responseBody, err := ioutil.ReadAll(resp.Body) if err != nil { return err } if len(responseBody) == 0 { return fmt.Errorf("spotify: HTTP %d: %s (body empty)", resp.StatusCode, http.StatusText(resp.StatusCode)) } buf := bytes.NewBuffer(responseBody) var e struct { E Error `json:"error"` } err = json.NewDecoder(buf).Decode(&e) if err != nil { return fmt.Errorf("spotify: couldn't decode error: (%d) [%s]", len(responseBody), responseBody) } if e.E.Message == "" { // Some errors will result in there being a useful status-code but an // empty message, which will confuse the user (who only has access to // the message and not the code). An example of this is when we send // some of the arguments directly in the HTTP query and the URL ends-up // being too long. e.E.Message = fmt.Sprintf("spotify: unexpected HTTP %d: %s (empty error)", resp.StatusCode, http.StatusText(resp.StatusCode)) } return e.E } // shouldRetry determines whether the status code indicates that the // previous operation should be retried at a later time func shouldRetry(status int) bool { return status == http.StatusAccepted || status == http.StatusTooManyRequests } // isFailure determines whether the code indicates failure func isFailure(code int, validCodes []int) bool { for _, item := range validCodes { if item == code { return false } } return true } // execute executes a non-GET request. `needsStatus` describes other HTTP status codes // that can represent success. Note that in all current usages of this function, // we need to still allow a 200 even if we'd also like to check for additional // success codes. func (c *Client) execute(req *http.Request, result interface{}, needsStatus ...int) error { for { resp, err := c.http.Do(req) if err != nil { return err } defer resp.Body.Close() if c.AutoRetry && shouldRetry(resp.StatusCode) { time.Sleep(retryDuration(resp)) continue } if resp.StatusCode != http.StatusOK && isFailure(resp.StatusCode, needsStatus) { return c.decodeError(resp) } if result != nil { if err := json.NewDecoder(resp.Body).Decode(result); err != nil { return err } } break } return nil } func retryDuration(resp *http.Response) time.Duration { raw := resp.Header.Get("Retry-After") if raw == "" { return defaultRetryDuration } seconds, err := strconv.ParseInt(raw, 10, 32) if err != nil { return defaultRetryDuration } return time.Duration(seconds) * time.Second } func (c *Client) get(url string, result interface{}) error { for { resp, err := c.http.Get(url) if err != nil { return err } defer resp.Body.Close() if resp.StatusCode == rateLimitExceededStatusCode && c.AutoRetry { time.Sleep(retryDuration(resp)) continue } if resp.StatusCode != http.StatusOK { return c.decodeError(resp) } err = json.NewDecoder(resp.Body).Decode(result) if err != nil { return err } break } return nil } // Options contains optional parameters that can be provided // to various API calls. Only the non-nil fields are used // in queries. type Options struct { // Country is an ISO 3166-1 alpha-2 country code. Provide // this parameter if you want the list of returned items to // be relevant to a particular country. If omitted, the // results will be relevant to all countries. Country *string // Limit is the maximum number of items to return. Limit *int // Offset is the index of the first item to return. Use it // with Limit to get the next set of items. Offset *int // Timerange is the period of time from which to return results // in certain API calls. The three options are the following string // literals: "short", "medium", and "long" Timerange *string } // NewReleasesOpt is like NewReleases, but it accepts optional parameters // for filtering the results. func (c *Client) NewReleasesOpt(opt *Options) (albums *SimpleAlbumPage, err error) { spotifyURL := c.baseURL + "browse/new-releases" if opt != nil { v := url.Values{} if opt.Country != nil { v.Set("country", *opt.Country) } if opt.Limit != nil { v.Set("limit", strconv.Itoa(*opt.Limit)) } if opt.Offset != nil { v.Set("offset", strconv.Itoa(*opt.Offset)) } if params := v.Encode(); params != "" { spotifyURL += "?" + params } } var objmap map[string]*json.RawMessage err = c.get(spotifyURL, &objmap) if err != nil { return nil, err } var result SimpleAlbumPage err = json.Unmarshal(*objmap["albums"], &result) if err != nil { return nil, err } return &result, nil } // NewReleases gets a list of new album releases featured in Spotify. // This call requires bearer authorization. func (c *Client) NewReleases() (albums *SimpleAlbumPage, err error) { return c.NewReleasesOpt(nil) } ================================================ FILE: vendor/github.com/zmb3/spotify/spotify_test.go ================================================ package spotify import ( "io" "net/http" "net/http/httptest" "os" "strings" "testing" ) func testClient(code int, body io.Reader, validators ...func(*http.Request)) (*Client, *httptest.Server) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { for _, v := range validators { v(r) } w.WriteHeader(code) io.Copy(w, body) r.Body.Close() if closer, ok := body.(io.Closer); ok { closer.Close() } })) client := &Client{ http: http.DefaultClient, baseURL: server.URL + "/", } return client, server } // Returns a client whose requests will always return // the specified status code and body. func testClientString(code int, body string, validators ...func(*http.Request)) (*Client, *httptest.Server) { return testClient(code, strings.NewReader(body)) } // Returns a client whose requests will always return // a response with the specified status code and a body // that is read from the specified file. func testClientFile(code int, filename string, validators ...func(*http.Request)) (*Client, *httptest.Server) { f, err := os.Open(filename) if err != nil { panic(err) } return testClient(code, f) } func TestNewReleases(t *testing.T) { c, s := testClientFile(http.StatusOK, "test_data/new_releases.txt") defer s.Close() r, err := c.NewReleases() if err != nil { t.Fatal(err) } if r.Albums[0].ID != "60mvULtYiNSRmpVvoa3RE4" { t.Error("Invalid data:", r.Albums[0].ID) } if r.Albums[0].Name != "We Are One (Ole Ola) [The Official 2014 FIFA World Cup Song]" { t.Error("Invalid data", r.Albums[0].Name) } } func TestNewReleasesRateLimitExceeded(t *testing.T) { t.Parallel() handlers := []http.HandlerFunc{ // first attempt fails http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Retry-After", "2") w.WriteHeader(rateLimitExceededStatusCode) io.WriteString(w, `{ "error": { "message": "slow down", "status": 429 } }`) }), // next attempt succeeds http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { f, err := os.Open("test_data/new_releases.txt") if err != nil { t.Fatal(err) } defer f.Close() _, err = io.Copy(w, f) if err != nil { t.Fatal(err) } }), } i := 0 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { handlers[i](w, r) i++ })) defer server.Close() client := &Client{http: http.DefaultClient, baseURL: server.URL + "/", AutoRetry: true} releases, err := client.NewReleases() if err != nil { t.Fatal(err) } if releases.Albums[0].ID != "60mvULtYiNSRmpVvoa3RE4" { t.Error("Invalid data:", releases.Albums[0].ID) } } ================================================ FILE: vendor/github.com/zmb3/spotify/track.go ================================================ package spotify import ( "errors" "fmt" "strings" "time" ) // SimpleTrack contains basic info about a track. type SimpleTrack struct { Artists []SimpleArtist `json:"artists"` // A list of the countries in which the track can be played, // identified by their ISO 3166-1 alpha-2 codes. AvailableMarkets []string `json:"available_markets"` // The disc number (usually 1 unless the album consists of more than one disc). DiscNumber int `json:"disc_number"` // The length of the track, in milliseconds. Duration int `json:"duration_ms"` // Whether or not the track has explicit lyrics. // true => yes, it does; false => no, it does not. Explicit bool `json:"explicit"` // External URLs for this track. ExternalURLs map[string]string `json:"external_urls"` // A link to the Web API endpoint providing full details for this track. Endpoint string `json:"href"` ID ID `json:"id"` Name string `json:"name"` // A URL to a 30 second preview (MP3) of the track. PreviewURL string `json:"preview_url"` // The number of the track. If an album has several // discs, the track number is the number on the specified // DiscNumber. TrackNumber int `json:"track_number"` URI URI `json:"uri"` } func (st SimpleTrack) String() string { return fmt.Sprintf("TRACK<[%s] [%s]>", st.ID, st.Name) } // FullTrack provides extra track data in addition to what is provided by SimpleTrack. type FullTrack struct { SimpleTrack // The album on which the track appears. The album object includes a link in href to full information about the album. Album SimpleAlbum `json:"album"` // Known external IDs for the track. ExternalIDs map[string]string `json:"external_ids"` // Popularity of the track. The value will be between 0 and 100, // with 100 being the most popular. The popularity is calculated from // both total plays and most recent plays. Popularity int `json:"popularity"` } // PlaylistTrack contains info about a track in a playlist. type PlaylistTrack struct { // The date and time the track was added to the playlist. // You can use the TimestampLayout constant to convert // this field to a time.Time value. // Warning: very old playlists may not populate this value. AddedAt string `json:"added_at"` // The Spotify user who added the track to the playlist. // Warning: vary old playlists may not populate this value. AddedBy User `json:"added_by"` // Information about the track. Track FullTrack `json:"track"` } // SavedTrack provides info about a track saved to a user's account. type SavedTrack struct { // The date and time the track was saved, represented as an ISO // 8601 UTC timestamp with a zero offset (YYYY-MM-DDTHH:MM:SSZ). // You can use the TimestampLayout constant to convert this to // a time.Time value. AddedAt string `json:"added_at"` FullTrack `json:"track"` } // TimeDuration returns the track's duration as a time.Duration value. func (t *SimpleTrack) TimeDuration() time.Duration { return time.Duration(t.Duration) * time.Millisecond } // GetTrack gets Spotify catalog information for // a single track identified by its unique Spotify ID. func (c *Client) GetTrack(id ID) (*FullTrack, error) { spotifyURL := c.baseURL + "tracks/" + string(id) var t FullTrack err := c.get(spotifyURL, &t) if err != nil { return nil, err } return &t, nil } // GetTracks gets Spotify catalog information for multiple tracks based on their // Spotify IDs. It supports up to 50 tracks in a single call. Tracks are // returned in the order requested. If a track is not found, that position in the // result will be nil. Duplicate ids in the query will result in duplicate // tracks in the result. func (c *Client) GetTracks(ids ...ID) ([]*FullTrack, error) { if len(ids) > 50 { return nil, errors.New("spotify: FindTracks supports up to 50 tracks") } spotifyURL := c.baseURL + "tracks?ids=" + strings.Join(toStringSlice(ids), ",") var t struct { Tracks []*FullTrack `jsosn:"tracks"` } err := c.get(spotifyURL, &t) if err != nil { return nil, err } return t.Tracks, nil } ================================================ FILE: vendor/github.com/zmb3/spotify/track_attributes.go ================================================ package spotify // TrackAttributes contains various tuneable parameters that can be used for recommendations. // For each of the tuneable track attributes, target, min and max values may be provided. // Target: // Tracks with the attribute values nearest to the target values will be preferred. // For example, you might request TargetEnergy=0.6 and TargetDanceability=0.8. // All target values will be weighed equally in ranking results. // Max: // A hard ceiling on the selected track attribute’s value can be provided. // For example, MaxInstrumentalness=0.35 would filter out most tracks // that are likely to be instrumental. // Min: // A hard floor on the selected track attribute’s value can be provided. // For example, min_tempo=140 would restrict results to only those tracks // with a tempo of greater than 140 beats per minute. type TrackAttributes struct { intAttributes map[string]int floatAttributes map[string]float64 } // NewTrackAttributes returns a new TrackAttributes instance with no attributes set. // Attributes can then be chained following a builder pattern: // ta := NewTrackAttributes(). // MaxAcousticness(0.15). // TargetPopularity(90) func NewTrackAttributes() *TrackAttributes { return &TrackAttributes{ intAttributes: map[string]int{}, floatAttributes: map[string]float64{}, } } // MaxAcousticness sets the maximum acousticness // Acousticness is a confidence measure from 0.0 to 1.0 of whether // the track is acoustic. A value of 1.0 represents high confidence // that the track is acoustic. func (ta *TrackAttributes) MaxAcousticness(acousticness float64) *TrackAttributes { ta.floatAttributes["max_acousticness"] = acousticness return ta } // MinAcousticness sets the minimum acousticness // Acousticness is a confidence measure from 0.0 to 1.0 of whether // the track is acoustic. A value of 1.0 represents high confidence // that the track is acoustic. func (ta *TrackAttributes) MinAcousticness(acousticness float64) *TrackAttributes { ta.floatAttributes["min_acousticness"] = acousticness return ta } // TargetAcousticness sets the target acousticness // Acousticness is a confidence measure from 0.0 to 1.0 of whether // the track is acoustic. A value of 1.0 represents high confidence // that the track is acoustic. func (ta *TrackAttributes) TargetAcousticness(acousticness float64) *TrackAttributes { ta.floatAttributes["target_acousticness"] = acousticness return ta } // MaxDanceability sets the maximum danceability // Danceability describes how suitable a track is for dancing based on // a combination of musical elements including tempo, rhythm stability, // beat strength, and overall regularity. // A value of 0.0 is least danceable and 1.0 is most danceable. func (ta *TrackAttributes) MaxDanceability(danceability float64) *TrackAttributes { ta.floatAttributes["max_danceability"] = danceability return ta } // MinDanceability sets the minimum danceability // Danceability describes how suitable a track is for dancing based on // a combination of musical elements including tempo, rhythm stability, // beat strength, and overall regularity. // A value of 0.0 is least danceable and 1.0 is most danceable. func (ta *TrackAttributes) MinDanceability(danceability float64) *TrackAttributes { ta.floatAttributes["min_danceability"] = danceability return ta } // TargetDanceability sets the target danceability // Danceability describes how suitable a track is for dancing based on // a combination of musical elements including tempo, rhythm stability, // beat strength, and overall regularity. // A value of 0.0 is least danceable and 1.0 is most danceable. func (ta *TrackAttributes) TargetDanceability(danceability float64) *TrackAttributes { ta.floatAttributes["target_danceability"] = danceability return ta } // MaxDuration sets the maximum length of the track in milliseconds func (ta *TrackAttributes) MaxDuration(duration int) *TrackAttributes { ta.intAttributes["max_duration_ms"] = duration return ta } // MinDuration sets the minimum length of the track in milliseconds func (ta *TrackAttributes) MinDuration(duration int) *TrackAttributes { ta.intAttributes["min_duration_ms"] = duration return ta } // TargetDuration sets the target length of the track in milliseconds func (ta *TrackAttributes) TargetDuration(duration int) *TrackAttributes { ta.intAttributes["target_duration_ms"] = duration return ta } // MaxEnergy sets the maximum energy // Energy is a measure from 0.0 to 1.0 and represents a perceptual mesaure // of intensity and activity. Typically, energetic tracks feel fast, loud, // and noisy. func (ta *TrackAttributes) MaxEnergy(energy float64) *TrackAttributes { ta.floatAttributes["max_energy"] = energy return ta } // MinEnergy sets the minimum energy // Energy is a measure from 0.0 to 1.0 and represents a perceptual mesaure // of intensity and activity. Typically, energetic tracks feel fast, loud, // and noisy. func (ta *TrackAttributes) MinEnergy(energy float64) *TrackAttributes { ta.floatAttributes["min_energy"] = energy return ta } // TargetEnergy sets the target energy // Energy is a measure from 0.0 to 1.0 and represents a perceptual mesaure // of intensity and activity. Typically, energetic tracks feel fast, loud, // and noisy. func (ta *TrackAttributes) TargetEnergy(energy float64) *TrackAttributes { ta.floatAttributes["target_energy"] = energy return ta } // MaxInstrumentalness sets the maximum instrumentalness // Instrumentalness predicts whether a track contains no vocals. // "Ooh" and "aah" sounds are treated as instrumental in this context. // Rap or spoken word tracks are clearly "vocal". // The closer the instrumentalness value is to 1.0, // the greater likelihood the track contains no vocal content. // Values above 0.5 are intended to represent instrumental tracks, // but confidence is higher as the value approaches 1.0. func (ta *TrackAttributes) MaxInstrumentalness(instrumentalness float64) *TrackAttributes { ta.floatAttributes["max_instrumentalness"] = instrumentalness return ta } // MinInstrumentalness sets the minimum instrumentalness // Instrumentalness predicts whether a track contains no vocals. // "Ooh" and "aah" sounds are treated as instrumental in this context. // Rap or spoken word tracks are clearly "vocal". // The closer the instrumentalness value is to 1.0, // the greater likelihood the track contains no vocal content. // Values above 0.5 are intended to represent instrumental tracks, // but confidence is higher as the value approaches 1.0. func (ta *TrackAttributes) MinInstrumentalness(instrumentalness float64) *TrackAttributes { ta.floatAttributes["min_instrumentalness"] = instrumentalness return ta } // TargetInstrumentalness sets the target instrumentalness // Instrumentalness predicts whether a track contains no vocals. // "Ooh" and "aah" sounds are treated as instrumental in this context. // Rap or spoken word tracks are clearly "vocal". // The closer the instrumentalness value is to 1.0, // the greater likelihood the track contains no vocal content. // Values above 0.5 are intended to represent instrumental tracks, // but confidence is higher as the value approaches 1.0. func (ta *TrackAttributes) TargetInstrumentalness(instrumentalness float64) *TrackAttributes { ta.floatAttributes["target_instrumentalness"] = instrumentalness return ta } // MaxKey sets the maximum key // Integers map to pitches using standard Pitch Class notation // (https://en.wikipedia.org/wiki/Pitch_class). func (ta *TrackAttributes) MaxKey(key int) *TrackAttributes { ta.intAttributes["max_key"] = key return ta } // MinKey sets the minimum key // Integers map to pitches using standard Pitch Class notation // (https://en.wikipedia.org/wiki/Pitch_class). func (ta *TrackAttributes) MinKey(key int) *TrackAttributes { ta.intAttributes["min_key"] = key return ta } // TargetKey sets the target key // Integers map to pitches using standard Pitch Class notation // (https://en.wikipedia.org/wiki/Pitch_class). func (ta *TrackAttributes) TargetKey(key int) *TrackAttributes { ta.intAttributes["target_key"] = key return ta } // MaxLiveness sets the maximum liveness // Detects the presence of an audience in the recording. Higher liveness // values represent an increased probability that the track was performed live. // A value above 0.8 provides strong likelihook that the track is live. func (ta *TrackAttributes) MaxLiveness(liveness float64) *TrackAttributes { ta.floatAttributes["max_liveness"] = liveness return ta } // MinLiveness sets the minimum liveness // Detects the presence of an audience in the recording. Higher liveness // values represent an increased probability that the track was performed live. // A value above 0.8 provides strong likelihook that the track is live. func (ta *TrackAttributes) MinLiveness(liveness float64) *TrackAttributes { ta.floatAttributes["min_liveness"] = liveness return ta } // TargetLiveness sets the target liveness // Detects the presence of an audience in the recording. Higher liveness // values represent an increased probability that the track was performed live. // A value above 0.8 provides strong likelihook that the track is live. func (ta *TrackAttributes) TargetLiveness(liveness float64) *TrackAttributes { ta.floatAttributes["target_liveness"] = liveness return ta } // MaxLoudness sets the maximum loudness in decibels (dB) // Loudness values are averaged across the entire track and are // useful for comparing the relative loudness of tracks. // Typical values range between -60 and 0 dB. func (ta *TrackAttributes) MaxLoudness(loudness float64) *TrackAttributes { ta.floatAttributes["max_loudness"] = loudness return ta } // MinLoudness sets the minimum loudness in decibels (dB) // Loudness values are averaged across the entire track and are // useful for comparing the relative loudness of tracks. // Typical values range between -60 and 0 dB. func (ta *TrackAttributes) MinLoudness(loudness float64) *TrackAttributes { ta.floatAttributes["min_loudness"] = loudness return ta } // TargetLoudness sets the target loudness in decibels (dB) // Loudness values are averaged across the entire track and are // useful for comparing the relative loudness of tracks. // Typical values range between -60 and 0 dB. func (ta *TrackAttributes) TargetLoudness(loudness float64) *TrackAttributes { ta.floatAttributes["target_loudness"] = loudness return ta } // MaxMode sets the maximum mode // Mode indicates the modality (major or minor) of a track. func (ta *TrackAttributes) MaxMode(mode int) *TrackAttributes { ta.intAttributes["max_mode"] = mode return ta } // MinMode sets the minimum mode // Mode indicates the modality (major or minor) of a track. func (ta *TrackAttributes) MinMode(mode int) *TrackAttributes { ta.intAttributes["min_mode"] = mode return ta } // TargetMode sets the target mode // Mode indicates the modality (major or minor) of a track. func (ta *TrackAttributes) TargetMode(mode int) *TrackAttributes { ta.intAttributes["target_mode"] = mode return ta } // MaxPopularity sets the maximum popularity. // The value will be between 0 and 100, with 100 being the most popular. // The popularity is calculated by algorithm and is based, in the most part, // on the total number of plays the track has had and how recent those plays are. // Note: When applying track relinking via the market parameter, it is expected to find // relinked tracks with popularities that do not match min_*, max_* and target_* popularities. // These relinked tracks are accurate replacements for unplayable tracks // with the expected popularity scores. Original, non-relinked tracks are // available via the linked_from attribute of the relinked track response. func (ta *TrackAttributes) MaxPopularity(popularity int) *TrackAttributes { ta.intAttributes["max_popularity"] = popularity return ta } // MinPopularity sets the minimum popularity. // The value will be between 0 and 100, with 100 being the most popular. // The popularity is calculated by algorithm and is based, in the most part, // on the total number of plays the track has had and how recent those plays are. // Note: When applying track relinking via the market parameter, it is expected to find // relinked tracks with popularities that do not match min_*, max_* and target_* popularities. // These relinked tracks are accurate replacements for unplayable tracks // with the expected popularity scores. Original, non-relinked tracks are // available via the linked_from attribute of the relinked track response. func (ta *TrackAttributes) MinPopularity(popularity int) *TrackAttributes { ta.intAttributes["min_popularity"] = popularity return ta } // TargetPopularity sets the target popularity. // The value will be between 0 and 100, with 100 being the most popular. // The popularity is calculated by algorithm and is based, in the most part, // on the total number of plays the track has had and how recent those plays are. // Note: When applying track relinking via the market parameter, it is expected to find // relinked tracks with popularities that do not match min_*, max_* and target_* popularities. // These relinked tracks are accurate replacements for unplayable tracks // with the expected popularity scores. Original, non-relinked tracks are // available via the linked_from attribute of the relinked track response. func (ta *TrackAttributes) TargetPopularity(popularity int) *TrackAttributes { ta.intAttributes["target_popularity"] = popularity return ta } // MaxSpeechiness sets the maximum speechiness. // Speechiness detects the presence of spoken words in a track. // The more exclusively speech-like the recording, the closer to 1.0 // the speechiness will be. // Values above 0.66 describe tracks that are probably made entirely of // spoken words. Values between 0.33 and 0.66 describe tracks that may // contain both music and speech, including such cases as rap music. // Values below 0.33 most likely represent music and other non-speech-like tracks. func (ta *TrackAttributes) MaxSpeechiness(speechiness float64) *TrackAttributes { ta.floatAttributes["max_speechiness"] = speechiness return ta } // MinSpeechiness sets the minimum speechiness. // Speechiness detects the presence of spoken words in a track. // The more exclusively speech-like the recording, the closer to 1.0 // the speechiness will be. // Values above 0.66 describe tracks that are probably made entirely of // spoken words. Values between 0.33 and 0.66 describe tracks that may // contain both music and speech, including such cases as rap music. // Values below 0.33 most likely represent music and other non-speech-like tracks. func (ta *TrackAttributes) MinSpeechiness(speechiness float64) *TrackAttributes { ta.floatAttributes["min_speechiness"] = speechiness return ta } // TargetSpeechiness sets the target speechiness. // Speechiness detects the presence of spoken words in a track. // The more exclusively speech-like the recording, the closer to 1.0 // the speechiness will be. // Values above 0.66 describe tracks that are probably made entirely of // spoken words. Values between 0.33 and 0.66 describe tracks that may // contain both music and speech, including such cases as rap music. // Values below 0.33 most likely represent music and other non-speech-like tracks. func (ta *TrackAttributes) TargetSpeechiness(speechiness float64) *TrackAttributes { ta.floatAttributes["target_speechiness"] = speechiness return ta } // MaxTempo sets the maximum tempo in beats per minute (BPM). func (ta *TrackAttributes) MaxTempo(tempo float64) *TrackAttributes { ta.floatAttributes["max_tempo"] = tempo return ta } // MinTempo sets the minimum tempo in beats per minute (BPM). func (ta *TrackAttributes) MinTempo(tempo float64) *TrackAttributes { ta.floatAttributes["min_tempo"] = tempo return ta } // TargetTempo sets the target tempo in beats per minute (BPM). func (ta *TrackAttributes) TargetTempo(tempo float64) *TrackAttributes { ta.floatAttributes["target_tempo"] = tempo return ta } // MaxTimeSignature sets the maximum time signature // The time signature (meter) is a notational convention to // specify how many beats are in each bar (or measure). func (ta *TrackAttributes) MaxTimeSignature(timeSignature int) *TrackAttributes { ta.intAttributes["max_time_signature"] = timeSignature return ta } // MinTimeSignature sets the minimum time signature // The time signature (meter) is a notational convention to // specify how many beats are in each bar (or measure). func (ta *TrackAttributes) MinTimeSignature(timeSignature int) *TrackAttributes { ta.intAttributes["min_time_signature"] = timeSignature return ta } // TargetTimeSignature sets the target time signature // The time signature (meter) is a notational convention to // specify how many beats are in each bar (or measure). func (ta *TrackAttributes) TargetTimeSignature(timeSignature int) *TrackAttributes { ta.intAttributes["target_time_signature"] = timeSignature return ta } // MaxValence sets the maximum valence. // Valence is a measure from 0.0 to 1.0 describing the musical positiveness /// conveyed by a track. // Tracks with high valence sound more positive (e.g. happy, cheerful, euphoric), // while tracks with low valence sound more negative (e.g. sad, depressed, angry). func (ta *TrackAttributes) MaxValence(valence float64) *TrackAttributes { ta.floatAttributes["max_valence"] = valence return ta } // MinValence sets the minimum valence. // Valence is a measure from 0.0 to 1.0 describing the musical positiveness /// conveyed by a track. // Tracks with high valence sound more positive (e.g. happy, cheerful, euphoric), // while tracks with low valence sound more negative (e.g. sad, depressed, angry). func (ta *TrackAttributes) MinValence(valence float64) *TrackAttributes { ta.floatAttributes["min_valence"] = valence return ta } // TargetValence sets the target valence. // Valence is a measure from 0.0 to 1.0 describing the musical positiveness /// conveyed by a track. // Tracks with high valence sound more positive (e.g. happy, cheerful, euphoric), // while tracks with low valence sound more negative (e.g. sad, depressed, angry). func (ta *TrackAttributes) TargetValence(valence float64) *TrackAttributes { ta.floatAttributes["target_valence"] = valence return ta } ================================================ FILE: vendor/github.com/zmb3/spotify/track_test.go ================================================ package spotify import ( "net/http" "testing" ) func TestFindTrack(t *testing.T) { client, server := testClientFile(http.StatusOK, "test_data/find_track.txt") defer server.Close() track, err := client.GetTrack(ID("1zHlj4dQ8ZAtrayhuDDmkY")) if err != nil { t.Error(err) return } if track.Name != "Timber" { t.Errorf("Wanted track Timer, got %s\n", track.Name) } } func TestFindTracksSimple(t *testing.T) { client, server := testClientFile(http.StatusOK, "test_data/find_tracks_simple.txt") defer server.Close() tracks, err := client.GetTracks(ID("0eGsygTp906u18L0Oimnem"), ID("1lDWb6b6ieDQ2xT7ewTC3G")) if err != nil { t.Error(err) return } if l := len(tracks); l != 2 { t.Errorf("Wanted 2 tracks, got %d\n", l) return } } func TestFindTracksNotFound(t *testing.T) { client, server := testClientFile(http.StatusOK, "test_data/find_tracks_notfound.txt") defer server.Close() tracks, err := client.GetTracks(ID("0eGsygTp906u18L0Oimnem"), ID("1lDWb6b6iecccdsdckTC3G")) if err != nil { t.Error(err) return } if l := len(tracks); l != 2 { t.Errorf("Expected 2 results, got %d\n", l) return } if tracks[0].Name != "Mr. Brightside" { t.Errorf("Expected Mr. Brightside, got %s\n", tracks[0].Name) } if tracks[1] != nil { t.Error("Expected nil track (invalid ID) but got valid track") } } ================================================ FILE: vendor/github.com/zmb3/spotify/user.go ================================================ package spotify import ( "errors" "fmt" "net/http" "net/url" "strconv" "strings" ) // User contains the basic, publicly available information about a Spotify user. type User struct { // The name displayed on the user's profile. // Note: Spotify currently fails to populate // this field when querying for a playlist. DisplayName string `json:"display_name"` // Known public external URLs for the user. ExternalURLs map[string]string `json:"external_urls"` // Information about followers of the user. Followers Followers `json:"followers"` // A link to the Web API endpoint for this user. Endpoint string `json:"href"` // The Spotify user ID for the user. ID string `json:"id"` // The user's profile image. Images []Image `json:"images"` // The Spotify URI for the user. URI URI `json:"uri"` } // PrivateUser contains additional information about a user. // This data is private and requires user authentication. type PrivateUser struct { User // The country of the user, as set in the user's account profile. // An ISO 3166-1 alpha-2 country code. This field is only available when the // current user has granted acess to the ScopeUserReadPrivate scope. Country string `json:"country"` // The user's email address, as entered by the user when creating their account. // Note: this email is UNVERIFIED - there is no proof that it actually // belongs to the user. This field is only available when the current user // has granted access to the ScopeUserReadEmail scope. Email string `json:"email"` // The user's Spotify subscription level: "premium", "free", etc. // The subscription level "open" can be considered the same as "free". // This field is only available when the current user has granted access to // the ScopeUserReadPrivate scope. Product string `json:"product"` // The user's date of birth, in the format 'YYYY-MM-DD'. You can use // the DateLayout constant to convert this to a time.Time value. // This field is only available when the current user has granted // access to the ScopeUserReadBirthdate scope. Birthdate string `json:"birthdate"` } // GetUsersPublicProfile gets public profile information about a // Spotify User. It does not require authentication. func (c *Client) GetUsersPublicProfile(userID ID) (*User, error) { spotifyURL := c.baseURL + "users/" + string(userID) var user User err := c.get(spotifyURL, &user) if err != nil { return nil, err } return &user, nil } // CurrentUser gets detailed profile information about the // current user. // // Reading the user's email address requires that the application // has the ScopeUserReadEmail scope. Reading the country, display // name, profile images, and product subscription level requires // that the application has the ScopeUserReadPrivate scope. // // Warning: The email address in the response will be the address // that was entered when the user created their spotify account. // This email address is unverified - do not assume that Spotify has // checked that the email address actually belongs to the user. func (c *Client) CurrentUser() (*PrivateUser, error) { var result PrivateUser err := c.get(c.baseURL+"me", &result) if err != nil { return nil, err } return &result, nil } // CurrentUsersTracks gets a list of songs saved in the current // Spotify user's "Your Music" library. func (c *Client) CurrentUsersTracks() (*SavedTrackPage, error) { return c.CurrentUsersTracksOpt(nil) } // CurrentUsersTracksOpt is like CurrentUsersTracks, but it accepts additional // options for sorting and filtering the results. func (c *Client) CurrentUsersTracksOpt(opt *Options) (*SavedTrackPage, error) { spotifyURL := c.baseURL + "me/tracks" if opt != nil { v := url.Values{} if opt.Country != nil { v.Set("country", *opt.Country) } if opt.Limit != nil { v.Set("limit", strconv.Itoa(*opt.Limit)) } if opt.Offset != nil { v.Set("offset", strconv.Itoa(*opt.Offset)) } if params := v.Encode(); params != "" { spotifyURL += "?" + params } } var result SavedTrackPage err := c.get(spotifyURL, &result) if err != nil { return nil, err } return &result, nil } // FollowUser adds the current user as a follower of one or more // spotify users, identified by their Spotify IDs. // // Modifying the lists of artists or users the current user follows // requires that the application has the ScopeUserFollowModify scope. func (c *Client) FollowUser(ids ...ID) error { return c.modifyFollowers("user", true, ids...) } // FollowArtist adds the current user as a follower of one or more // spotify artists, identified by their Spotify IDs. // // Modifying the lists of artists or users the current user follows // requires that the application has the ScopeUserFollowModify scope. func (c *Client) FollowArtist(ids ...ID) error { return c.modifyFollowers("artist", true, ids...) } // UnfollowUser removes the current user as a follower of one or more // Spotify users. // // Modifying the lists of artists or users the current user follows // requires that the application has the ScopeUserFollowModify scope. func (c *Client) UnfollowUser(ids ...ID) error { return c.modifyFollowers("user", false, ids...) } // UnfollowArtist removes the current user as a follower of one or more // Spotify artists. // // Modifying the lists of artists or users the current user follows // requires that the application has the ScopeUserFollowModify scope. func (c *Client) UnfollowArtist(ids ...ID) error { return c.modifyFollowers("artist", false, ids...) } // CurrentUserFollows checks to see if the current user is following // one or more artists or other Spotify Users. This call requires // ScopeUserFollowRead. // // The t argument indicates the type of the IDs, and must be either // "user" or "artist". // // The result is returned as a slice of bool values in the same order // in which the IDs were specified. func (c *Client) CurrentUserFollows(t string, ids ...ID) ([]bool, error) { if l := len(ids); l == 0 || l > 50 { return nil, errors.New("spotify: UserFollows supports 1 to 50 IDs") } if t != "artist" && t != "user" { return nil, errors.New("spotify: t must be 'artist' or 'user'") } spotifyURL := fmt.Sprintf("%sme/following/contains?type=%s&ids=%s", c.baseURL, t, strings.Join(toStringSlice(ids), ",")) var result []bool err := c.get(spotifyURL, &result) if err != nil { return nil, err } return result, nil } func (c *Client) modifyFollowers(usertype string, follow bool, ids ...ID) error { if l := len(ids); l == 0 || l > 50 { return errors.New("spotify: Follow/Unfollow supports 1 to 50 IDs") } v := url.Values{} v.Add("type", usertype) v.Add("ids", strings.Join(toStringSlice(ids), ",")) spotifyURL := c.baseURL + "me/following?" + v.Encode() method := "PUT" if !follow { method = "DELETE" } req, err := http.NewRequest(method, spotifyURL, nil) if err != nil { return err } err = c.execute(req, nil, http.StatusNoContent) if err != nil { return err } return nil } // CurrentUsersFollowedArtists gets the current user's followed artists. // This call requires that the user has granted the ScopeUserFollowRead scope. func (c *Client) CurrentUsersFollowedArtists() (*FullArtistCursorPage, error) { return c.CurrentUsersFollowedArtistsOpt(-1, "") } // CurrentUsersFollowedArtistsOpt is like CurrentUsersFollowedArtists, // but it accept the optional arguments limit and after. Limit is the // maximum number of items to return (1 <= limit <= 50), and after is // the last artist ID retrieved from the previous request. If you don't // wish to specify either of the parameters, use -1 for limit and the empty // string for after. func (c *Client) CurrentUsersFollowedArtistsOpt(limit int, after string) (*FullArtistCursorPage, error) { spotifyURL := c.baseURL + "me/following" v := url.Values{} v.Set("type", "artist") if limit != -1 { v.Set("limit", strconv.Itoa(limit)) } if after != "" { v.Set("after", after) } if params := v.Encode(); params != "" { spotifyURL += "?" + params } var result struct { A FullArtistCursorPage `json:"artists"` } err := c.get(spotifyURL, &result) if err != nil { return nil, err } return &result.A, nil } // CurrentUsersAlbums gets a list of albums saved in the current // Spotify user's "Your Music" library. func (c *Client) CurrentUsersAlbums() (*SavedAlbumPage, error) { return c.CurrentUsersAlbumsOpt(nil) } // CurrentUsersAlbumsOpt is like CurrentUsersAlbums, but it accepts additional // options for sorting and filtering the results. func (c *Client) CurrentUsersAlbumsOpt(opt *Options) (*SavedAlbumPage, error) { spotifyURL := c.baseURL + "me/albums" if opt != nil { v := url.Values{} if opt.Country != nil { v.Set("market", *opt.Country) } if opt.Limit != nil { v.Set("limit", strconv.Itoa(*opt.Limit)) } if opt.Offset != nil { v.Set("offset", strconv.Itoa(*opt.Offset)) } if params := v.Encode(); params != "" { spotifyURL += "?" + params } } var result SavedAlbumPage err := c.get(spotifyURL, &result) if err != nil { return nil, err } return &result, nil } // CurrentUsersPlaylists gets a list of the playlists owned or followed by // the current spotify user. // // Private playlists require the ScopePlaylistReadPrivate scope. Note that // this scope alone will not return collaborative playlists, even though // they are always private. In order to retrieve collaborative playlists // the user must authorize the ScopePlaylistReadCollaborative scope. func (c *Client) CurrentUsersPlaylists() (*SimplePlaylistPage, error) { return c.CurrentUsersPlaylistsOpt(nil) } // CurrentUsersPlaylistsOpt is like CurrentUsersPlaylists, but it accepts // additional options for sorting and filtering the results. func (c *Client) CurrentUsersPlaylistsOpt(opt *Options) (*SimplePlaylistPage, error) { spotifyURL := c.baseURL + "me/playlists" if opt != nil { v := url.Values{} if opt.Limit != nil { v.Set("limit", strconv.Itoa(*opt.Limit)) } if opt.Offset != nil { v.Set("offset", strconv.Itoa(*opt.Offset)) } if params := v.Encode(); params != "" { spotifyURL += "?" + params } } var result SimplePlaylistPage err := c.get(spotifyURL, &result) if err != nil { return nil, err } return &result, nil } // CurrentUsersTopArtistsOpt gets a list of the top played artists in a given time // range of the current Spotify user. It supports up to 50 artists in a single // call. This call requires ScopeUserTopRead. func (c *Client) CurrentUsersTopArtistsOpt(opt *Options) (*FullArtistPage, error) { spotifyURL := c.baseURL + "me/top/artists" if opt != nil { v := url.Values{} if opt.Limit != nil { v.Set("limit", strconv.Itoa(*opt.Limit)) } if opt.Timerange != nil { v.Set("time_range", *opt.Timerange+"_term") } if params := v.Encode(); params != "" { spotifyURL += "?" + params } } var result FullArtistPage err := c.get(spotifyURL, &result) if err != nil { return nil, err } return &result, nil } // CurrentUsersTopArtists is like CurrentUsersTopArtistsOpt but with // sensible defaults. The default limit is 20 and the default timerange // is medium_term. func (c *Client) CurrentUsersTopArtists() (*FullArtistPage, error) { return c.CurrentUsersTopArtistsOpt(nil) } // CurrentUsersTopTracksOpt gets a list of the top played tracks in a given time // range of the current Spotify user. It supports up to 50 tracks in a single // call. This call requires ScopeUserTopRead. func (c *Client) CurrentUsersTopTracksOpt(opt *Options) (*FullTrackPage, error) { spotifyURL := c.baseURL + "me/top/tracks" if opt != nil { v := url.Values{} if opt.Limit != nil { v.Set("limit", strconv.Itoa(*opt.Limit)) } if opt.Timerange != nil { v.Set("time_range", *opt.Timerange+"_term") } if params := v.Encode(); params != "" { spotifyURL += "?" + params } } var result FullTrackPage err := c.get(spotifyURL, &result) if err != nil { return nil, err } return &result, nil } // CurrentUsersTopTracks is like CurrentUsersTopTracksOpt but with // sensible defaults. The default limit is 20 and the default timerange // is medium_term. func (c *Client) CurrentUsersTopTracks() (*FullTrackPage, error) { return c.CurrentUsersTopTracksOpt(nil) } ================================================ FILE: vendor/github.com/zmb3/spotify/user_test.go ================================================ package spotify import ( "fmt" "io" "net/http" "net/http/httptest" "strings" "testing" ) const userResponse = ` { "display_name" : "Ronald Pompa", "external_urls" : { "spotify" : "https://open.spotify.com/user/wizzler" }, "followers" : { "href" : null, "total" : 3829 }, "href" : "https://api.spotify.com/v1/users/wizzler", "id" : "wizzler", "images" : [ { "height" : null, "url" : "http://profile-images.scdn.co/images/userprofile/default/9d51820e73667ea5f1e97ea601cf0593b558050e", "width" : null } ], "type" : "user", "uri" : "spotify:user:wizzler" }` func TestUserProfile(t *testing.T) { client, server := testClientString(http.StatusOK, userResponse) defer server.Close() user, err := client.GetUsersPublicProfile("wizzler") if err != nil { t.Error(err) return } if user.ID != "wizzler" { t.Error("Expected user wizzler, got ", user.ID) } if f := user.Followers.Count; f != 3829 { t.Errorf("Expected 3829 followers, got %d\n", f) } } func TestCurrentUser(t *testing.T) { json := `{ "country" : "US", "display_name" : null, "email" : "username@domain.com", "external_urls" : { "spotify" : "https://open.spotify.com/user/username" }, "followers" : { "href" : null, "total" : 0 }, "href" : "https://api.spotify.com/v1/users/userame", "id" : "username", "images" : [ ], "product" : "premium", "type" : "user", "uri" : "spotify:user:username", "birthdate" : "1985-05-01" }` client, server := testClientString(http.StatusOK, json) defer server.Close() me, err := client.CurrentUser() if err != nil { t.Error(err) return } if me.Country != CountryUSA || me.Email != "username@domain.com" || me.Product != "premium" { t.Error("Received incorrect response") } if me.Birthdate != "1985-05-01" { t.Errorf("Expected '1985-05-01', got '%s'\n", me.Birthdate) } } func TestFollowUsersMissingScope(t *testing.T) { json := `{ "error": { "status": 403, "message": "Insufficient client scope" } }` client, server := testClientString(http.StatusForbidden, json, func(req *http.Request) { if req.URL.Query().Get("type") != "user" { t.Error("Request made with the wrong type parameter") } }) defer server.Close() err := client.FollowUser(ID("exampleuser01")) serr, ok := err.(Error) if !ok { t.Fatal("Expected insufficient client scope error") } if serr.Status != http.StatusForbidden { t.Error("Expected HTTP 403") } } func TestFollowArtist(t *testing.T) { client, server := testClientString(http.StatusNoContent, "", func(req *http.Request) { if req.URL.Query().Get("type") != "artist" { t.Error("Request made with the wrong type parameter") } }) defer server.Close() if err := client.FollowArtist("3ge4xOaKvWfhRwgx0Rldov"); err != nil { t.Error(err) } } func TestFollowArtistAutoRetry(t *testing.T) { t.Parallel() handlers := []http.HandlerFunc{ // first attempt fails http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Retry-After", "2") w.WriteHeader(rateLimitExceededStatusCode) io.WriteString(w, `{ "error": { "message": "slow down", "status": 429 } }`) }), // next attempt succeeds http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusNoContent) }), } i := 0 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { handlers[i](w, r) i++ })) defer server.Close() client := &Client{http: http.DefaultClient, baseURL: server.URL + "/", AutoRetry: true} if err := client.FollowArtist("3ge4xOaKvWfhRwgx0Rldov"); err != nil { t.Error(err) } } func TestFollowUsersInvalidToken(t *testing.T) { json := `{ "error": { "status": 401, "message": "Invalid access token" } }` client, server := testClientString(http.StatusUnauthorized, json, func(req *http.Request) { if req.URL.Query().Get("type") != "user" { t.Error("Request made with the wrong type parameter") } }) defer server.Close() err := client.FollowUser(ID("dummyID")) serr, ok := err.(Error) if !ok { t.Fatal("Expected invalid token error") } if serr.Status != http.StatusUnauthorized { t.Error("Expected HTTP 401") } } func TestUserFollows(t *testing.T) { json := "[ false, true ]" client, server := testClientString(http.StatusOK, json) defer server.Close() follows, err := client.CurrentUserFollows("artist", ID("74ASZWbe4lXaubB36ztrGX"), ID("08td7MxkoHQkXnWAYD8d6Q")) if err != nil { t.Error(err) return } if len(follows) != 2 || follows[0] || !follows[1] { t.Error("Incorrect result", follows) } } func TestCurrentUsersTracks(t *testing.T) { client, server := testClientFile(http.StatusOK, "test_data/current_users_tracks.txt") defer server.Close() tracks, err := client.CurrentUsersTracks() if err != nil { t.Error(err) return } if tracks.Limit != 20 { t.Errorf("Expected limit 20, got %d\n", tracks.Limit) } if tracks.Endpoint != "https://api.spotify.com/v1/me/tracks?offset=0&limit=20" { t.Error("Endpoint incorrect") } if tracks.Total != 3 { t.Errorf("Expect 3 results, got %d\n", tracks.Total) return } if len(tracks.Tracks) != tracks.Total { t.Error("Didn't get expected number of results") return } expected := "You & I (Nobody In The World)" if tracks.Tracks[0].Name != expected { t.Errorf("Expected '%s', got '%s'\n", expected, tracks.Tracks[0].Name) fmt.Printf("\n%#v\n", tracks.Tracks[0]) } } func TestCurrentUsersAlbums(t *testing.T) { client, server := testClientFile(http.StatusOK, "test_data/current_users_albums.txt") defer server.Close() albums, err := client.CurrentUsersAlbums() if err != nil { t.Error(err) return } if albums.Limit != 20 { t.Errorf("Expected limit 20, got %d\n", albums.Limit) } if albums.Endpoint != "https://api.spotify.com/v1/me/albums?offset=0&limit=20" { t.Error("Endpoint incorrect") } if albums.Total != 2 { t.Errorf("Expect 2 results, got %d\n", albums.Total) return } if len(albums.Albums) != albums.Total { t.Error("Didn't get expected number of results") return } expected := "Love In The Future" if albums.Albums[0].Name != expected { t.Errorf("Expected '%s', got '%s'\n", expected, albums.Albums[0].Name) fmt.Printf("\n%#v\n", albums.Albums[0]) } upc := "886444160742" u, ok := albums.Albums[0].ExternalIDs["upc"] if !ok { t.Error("External IDs missing UPC") } if u != upc { t.Errorf("Wrong UPC: want %s, got %s\n", upc, u) } } func TestCurrentUsersPlaylists(t *testing.T) { client, server := testClientFile(http.StatusOK, "test_data/current_users_playlists.txt") defer server.Close() playlists, err := client.CurrentUsersPlaylists() if err != nil { t.Error(err) } if playlists.Limit != 20 { t.Errorf("Expected limit 20, got %d\n", playlists.Limit) } if playlists.Total != 4 { t.Errorf("Expected 4 playlists, got %d\n", playlists.Total) } tests := []struct { Name string Public bool TrackCount uint }{ {"Discover Weekly", false, 30}, {"Your Favorite Coffeehouse", false, 69}, {"Afternoon Acoustic", false, 99}, {"Yoga and Meditation", true, 31}, } for i := range tests { p := playlists.Playlists[i] if p.Name != tests[i].Name { t.Errorf("Expected '%s', got '%s'\n", tests[i].Name, p.Name) } if p.IsPublic != tests[i].Public { t.Errorf("Expected public to be %#v, got %#v\n", tests[i].Public, p.IsPublic) } if p.Tracks.Total != tests[i].TrackCount { t.Errorf("Expected %d tracks, got %d\n", tests[i].TrackCount, p.Tracks.Total) } } } func TestUsersFollowedArtists(t *testing.T) { json := ` { "artists" : { "items" : [ { "external_urls" : { "spotify" : "https://open.spotify.com/artist/0I2XqVXqHScXjHhk6AYYRe" }, "followers" : { "href" : null, "total" : 7753 }, "genres" : [ "swedish hip hop" ], "href" : "https://api.spotify.com/v1/artists/0I2XqVXqHScXjHhk6AYYRe", "id" : "0I2XqVXqHScXjHhk6AYYRe", "images" : [ { "height" : 640, "url" : "https://i.scdn.co/image/2c8c0cea05bf3d3c070b7498d8d0b957c4cdec20", "width" : 640 }, { "height" : 300, "url" : "https://i.scdn.co/image/394302b42c4b894786943e028cdd46d7baaa29b7", "width" : 300 }, { "height" : 64, "url" : "https://i.scdn.co/image/ca9df7225ade6e5dfc62e7076709ca3409a7cbbf", "width" : 64 } ], "name" : "Afasi & Filthy", "popularity" : 54, "type" : "artist", "uri" : "spotify:artist:0I2XqVXqHScXjHhk6AYYRe" } ], "next" : "https://api.spotify.com/v1/users/thelinmichael/following?type=artist&after=0aV6DOiouImYTqrR5YlIqx&limit=20", "total" : 183, "cursors" : { "after" : "0aV6DOiouImYTqrR5YlIqx" }, "limit" : 20, "href" : "https://api.spotify.com/v1/users/thelinmichael/following?type=artist&limit=20" } }` client, server := testClientString(http.StatusOK, json) defer server.Close() artists, err := client.CurrentUsersFollowedArtists() if err != nil { t.Fatal(err) } exp := 20 if artists.Limit != exp { t.Errorf("Expected limit %d, got %d\n", exp, artists.Limit) } if a := artists.Cursor.After; a != "0aV6DOiouImYTqrR5YlIqx" { t.Error("Invalid 'after' cursor") } if l := len(artists.Artists); l != 1 { t.Fatalf("Expected 1 artist, got %d\n", l) } if n := artists.Artists[0].Name; n != "Afasi & Filthy" { t.Error("Got wrong artist name") } } func TestCurrentUsersFollowedArtistsOpt(t *testing.T) { client, server := testClientString(http.StatusOK, "{}", func(req *http.Request) { if url := req.URL.String(); !strings.HasSuffix(url, "me/following?after=0aV6DOiouImYTqrR5YlIqx&limit=50&type=artist") { t.Error("invalid request url") } }) defer server.Close() client.CurrentUsersFollowedArtistsOpt(50, "0aV6DOiouImYTqrR5YlIqx") } func TestCurrentUsersTopArtists(t *testing.T) { client, server := testClientFile(http.StatusOK, "test_data/current_users_top_artists.txt") defer server.Close() artists, err := client.CurrentUsersTopArtists() if err != nil { t.Error(err) } if artists.Endpoint != "https://api.spotify.com/v1/me/top/artists" { t.Error("Endpoint incorrect") } if artists.Limit != 20 { t.Errorf("Expected limit 20, got %d\n", artists.Limit) } if artists.Total != 10 { t.Errorf("Expected total 10, got %d\n", artists.Total) return } if len(artists.Artists) != artists.Total { t.Error("Didn't get expected number of results") return } if artists.Artists[0].Followers.Count != 8437 { t.Errorf("Expected follower count of 8437, got %d\n", artists.Artists[0].Followers.Count) } name := "insaneintherainmusic" if artists.Artists[0].Name != name { t.Errorf("Expected '%s', got '%s'\n", name, artists.Artists[0].Name) fmt.Printf("\n%#v\n", artists.Artists[0]) } } func TestCurrentUsersTopTracks(t *testing.T) { client, server := testClientFile(http.StatusOK, "test_data/current_users_top_tracks.txt") defer server.Close() tracks, err := client.CurrentUsersTopTracks() if err != nil { t.Error(err) } if tracks.Endpoint != "https://api.spotify.com/v1/me/top/tracks" { t.Error("Endpoint incorrect") } if tracks.Limit != 20 { t.Errorf("Expected limit 20, got %d\n", tracks.Limit) } if tracks.Total != 380 { t.Errorf("Expected total 380, got %d\n", tracks.Total) return } if len(tracks.Tracks) != tracks.Limit { t.Errorf("Didn't get expected number of results") return } name := "Adventure Awaits! (Alola Region Theme)" if tracks.Tracks[0].Name != name { t.Errorf("Expected '%s', got '%s'\n", name, tracks.Tracks[0].Name) fmt.Printf("\n%#v\n", tracks.Tracks[0]) } isrc := "QZ4JJ1764466" i, ok := tracks.Tracks[0].ExternalIDs["isrc"] if !ok { t.Error("External IDs missing ISRC") } if i != isrc { t.Errorf("Wrong ISRC: want %s, got %s\n", isrc, i) } } ================================================ FILE: vendor/golang.org/x/net/.gitattributes ================================================ # Treat all files in this repo as binary, with no git magic updating # line endings. Windows users contributing to Go will need to use a # modern version of git and editors capable of LF line endings. # # We'll prevent accidental CRLF line endings from entering the repo # via the git-review gofmt checks. # # See golang.org/issue/9281 * -text ================================================ FILE: vendor/golang.org/x/net/.gitignore ================================================ # Add no patterns to .hgignore except for files generated by the build. last-change ================================================ FILE: vendor/golang.org/x/net/AUTHORS ================================================ # This source code refers to The Go Authors for copyright purposes. # The master list of authors is in the main Go distribution, # visible at http://tip.golang.org/AUTHORS. ================================================ FILE: vendor/golang.org/x/net/CONTRIBUTING.md ================================================ # Contributing to Go Go is an open source project. It is the work of hundreds of contributors. We appreciate your help! ## Filing issues When [filing an issue](https://golang.org/issue/new), make sure to answer these five questions: 1. What version of Go are you using (`go version`)? 2. What operating system and processor architecture are you using? 3. What did you do? 4. What did you expect to see? 5. What did you see instead? General questions should go to the [golang-nuts mailing list](https://groups.google.com/group/golang-nuts) instead of the issue tracker. The gophers there will answer or ask you to file an issue if you've tripped over a bug. ## Contributing code Please read the [Contribution Guidelines](https://golang.org/doc/contribute.html) before sending patches. **We do not accept GitHub pull requests** (we use [Gerrit](https://code.google.com/p/gerrit/) instead for code review). Unless otherwise noted, the Go source files are distributed under the BSD-style license found in the LICENSE file. ================================================ FILE: vendor/golang.org/x/net/CONTRIBUTORS ================================================ # This source code was written by the Go contributors. # The master list of contributors is in the main Go distribution, # visible at http://tip.golang.org/CONTRIBUTORS. ================================================ FILE: vendor/golang.org/x/net/LICENSE ================================================ Copyright (c) 2009 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. ================================================ FILE: vendor/golang.org/x/net/PATENTS ================================================ Additional IP Rights Grant (Patents) "This implementation" means the copyrightable works distributed by Google as part of the Go project. Google hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, transfer and otherwise run, modify and propagate the contents of this implementation of Go, where such license applies only to those patent claims, both currently owned or controlled by Google and acquired in the future, licensable by Google that are necessarily infringed by this implementation of Go. This grant does not include claims that would be infringed only as a consequence of further modification of this implementation. If you or your agent or exclusive licensee institute or order or agree to the institution of patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that this implementation of Go or any code incorporated within this implementation of Go constitutes direct or contributory patent infringement, or inducement of patent infringement, then any patent rights granted to you under this License for this implementation of Go shall terminate as of the date such litigation is filed. ================================================ FILE: vendor/golang.org/x/net/README.md ================================================ # Go Networking This repository holds supplementary Go networking libraries. ## Download/Install The easiest way to install is to run `go get -u golang.org/x/net`. You can also manually git clone the repository to `$GOPATH/src/golang.org/x/net`. ## Report Issues / Send Patches This repository uses Gerrit for code changes. To learn how to submit changes to this repository, see https://golang.org/doc/contribute.html. The main issue tracker for the net repository is located at https://github.com/golang/go/issues. Prefix your issue with "x/net:" in the subject line, so it is easy to find. ================================================ FILE: vendor/golang.org/x/net/codereview.cfg ================================================ issuerepo: golang/go ================================================ FILE: vendor/golang.org/x/net/context/context.go ================================================ // Copyright 2014 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 file. // Package context defines the Context type, which carries deadlines, // cancelation signals, and other request-scoped values across API boundaries // and between processes. // As of Go 1.7 this package is available in the standard library under the // name context. https://golang.org/pkg/context. // // Incoming requests to a server should create a Context, and outgoing calls to // servers should accept a Context. The chain of function calls between must // propagate the Context, optionally replacing it with a modified copy created // using WithDeadline, WithTimeout, WithCancel, or WithValue. // // Programs that use Contexts should follow these rules to keep interfaces // consistent across packages and enable static analysis tools to check context // propagation: // // Do not store Contexts inside a struct type; instead, pass a Context // explicitly to each function that needs it. The Context should be the first // parameter, typically named ctx: // // func DoSomething(ctx context.Context, arg Arg) error { // // ... use ctx ... // } // // Do not pass a nil Context, even if a function permits it. Pass context.TODO // if you are unsure about which Context to use. // // Use context Values only for request-scoped data that transits processes and // APIs, not for passing optional parameters to functions. // // The same Context may be passed to functions running in different goroutines; // Contexts are safe for simultaneous use by multiple goroutines. // // See http://blog.golang.org/context for example code for a server that uses // Contexts. package context // import "golang.org/x/net/context" // Background returns a non-nil, empty Context. It is never canceled, has no // values, and has no deadline. It is typically used by the main function, // initialization, and tests, and as the top-level Context for incoming // requests. func Background() Context { return background } // TODO returns a non-nil, empty Context. Code should use context.TODO when // it's unclear which Context to use or it is not yet available (because the // surrounding function has not yet been extended to accept a Context // parameter). TODO is recognized by static analysis tools that determine // whether Contexts are propagated correctly in a program. func TODO() Context { return todo } ================================================ FILE: vendor/golang.org/x/net/context/context_test.go ================================================ // Copyright 2014 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 file. // +build !go1.7 package context import ( "fmt" "math/rand" "runtime" "strings" "sync" "testing" "time" ) // otherContext is a Context that's not one of the types defined in context.go. // This lets us test code paths that differ based on the underlying type of the // Context. type otherContext struct { Context } func TestBackground(t *testing.T) { c := Background() if c == nil { t.Fatalf("Background returned nil") } select { case x := <-c.Done(): t.Errorf("<-c.Done() == %v want nothing (it should block)", x) default: } if got, want := fmt.Sprint(c), "context.Background"; got != want { t.Errorf("Background().String() = %q want %q", got, want) } } func TestTODO(t *testing.T) { c := TODO() if c == nil { t.Fatalf("TODO returned nil") } select { case x := <-c.Done(): t.Errorf("<-c.Done() == %v want nothing (it should block)", x) default: } if got, want := fmt.Sprint(c), "context.TODO"; got != want { t.Errorf("TODO().String() = %q want %q", got, want) } } func TestWithCancel(t *testing.T) { c1, cancel := WithCancel(Background()) if got, want := fmt.Sprint(c1), "context.Background.WithCancel"; got != want { t.Errorf("c1.String() = %q want %q", got, want) } o := otherContext{c1} c2, _ := WithCancel(o) contexts := []Context{c1, o, c2} for i, c := range contexts { if d := c.Done(); d == nil { t.Errorf("c[%d].Done() == %v want non-nil", i, d) } if e := c.Err(); e != nil { t.Errorf("c[%d].Err() == %v want nil", i, e) } select { case x := <-c.Done(): t.Errorf("<-c.Done() == %v want nothing (it should block)", x) default: } } cancel() time.Sleep(100 * time.Millisecond) // let cancelation propagate for i, c := range contexts { select { case <-c.Done(): default: t.Errorf("<-c[%d].Done() blocked, but shouldn't have", i) } if e := c.Err(); e != Canceled { t.Errorf("c[%d].Err() == %v want %v", i, e, Canceled) } } } func TestParentFinishesChild(t *testing.T) { // Context tree: // parent -> cancelChild // parent -> valueChild -> timerChild parent, cancel := WithCancel(Background()) cancelChild, stop := WithCancel(parent) defer stop() valueChild := WithValue(parent, "key", "value") timerChild, stop := WithTimeout(valueChild, 10000*time.Hour) defer stop() select { case x := <-parent.Done(): t.Errorf("<-parent.Done() == %v want nothing (it should block)", x) case x := <-cancelChild.Done(): t.Errorf("<-cancelChild.Done() == %v want nothing (it should block)", x) case x := <-timerChild.Done(): t.Errorf("<-timerChild.Done() == %v want nothing (it should block)", x) case x := <-valueChild.Done(): t.Errorf("<-valueChild.Done() == %v want nothing (it should block)", x) default: } // The parent's children should contain the two cancelable children. pc := parent.(*cancelCtx) cc := cancelChild.(*cancelCtx) tc := timerChild.(*timerCtx) pc.mu.Lock() if len(pc.children) != 2 || !pc.children[cc] || !pc.children[tc] { t.Errorf("bad linkage: pc.children = %v, want %v and %v", pc.children, cc, tc) } pc.mu.Unlock() if p, ok := parentCancelCtx(cc.Context); !ok || p != pc { t.Errorf("bad linkage: parentCancelCtx(cancelChild.Context) = %v, %v want %v, true", p, ok, pc) } if p, ok := parentCancelCtx(tc.Context); !ok || p != pc { t.Errorf("bad linkage: parentCancelCtx(timerChild.Context) = %v, %v want %v, true", p, ok, pc) } cancel() pc.mu.Lock() if len(pc.children) != 0 { t.Errorf("pc.cancel didn't clear pc.children = %v", pc.children) } pc.mu.Unlock() // parent and children should all be finished. check := func(ctx Context, name string) { select { case <-ctx.Done(): default: t.Errorf("<-%s.Done() blocked, but shouldn't have", name) } if e := ctx.Err(); e != Canceled { t.Errorf("%s.Err() == %v want %v", name, e, Canceled) } } check(parent, "parent") check(cancelChild, "cancelChild") check(valueChild, "valueChild") check(timerChild, "timerChild") // WithCancel should return a canceled context on a canceled parent. precanceledChild := WithValue(parent, "key", "value") select { case <-precanceledChild.Done(): default: t.Errorf("<-precanceledChild.Done() blocked, but shouldn't have") } if e := precanceledChild.Err(); e != Canceled { t.Errorf("precanceledChild.Err() == %v want %v", e, Canceled) } } func TestChildFinishesFirst(t *testing.T) { cancelable, stop := WithCancel(Background()) defer stop() for _, parent := range []Context{Background(), cancelable} { child, cancel := WithCancel(parent) select { case x := <-parent.Done(): t.Errorf("<-parent.Done() == %v want nothing (it should block)", x) case x := <-child.Done(): t.Errorf("<-child.Done() == %v want nothing (it should block)", x) default: } cc := child.(*cancelCtx) pc, pcok := parent.(*cancelCtx) // pcok == false when parent == Background() if p, ok := parentCancelCtx(cc.Context); ok != pcok || (ok && pc != p) { t.Errorf("bad linkage: parentCancelCtx(cc.Context) = %v, %v want %v, %v", p, ok, pc, pcok) } if pcok { pc.mu.Lock() if len(pc.children) != 1 || !pc.children[cc] { t.Errorf("bad linkage: pc.children = %v, cc = %v", pc.children, cc) } pc.mu.Unlock() } cancel() if pcok { pc.mu.Lock() if len(pc.children) != 0 { t.Errorf("child's cancel didn't remove self from pc.children = %v", pc.children) } pc.mu.Unlock() } // child should be finished. select { case <-child.Done(): default: t.Errorf("<-child.Done() blocked, but shouldn't have") } if e := child.Err(); e != Canceled { t.Errorf("child.Err() == %v want %v", e, Canceled) } // parent should not be finished. select { case x := <-parent.Done(): t.Errorf("<-parent.Done() == %v want nothing (it should block)", x) default: } if e := parent.Err(); e != nil { t.Errorf("parent.Err() == %v want nil", e) } } } func testDeadline(c Context, wait time.Duration, t *testing.T) { select { case <-time.After(wait): t.Fatalf("context should have timed out") case <-c.Done(): } if e := c.Err(); e != DeadlineExceeded { t.Errorf("c.Err() == %v want %v", e, DeadlineExceeded) } } func TestDeadline(t *testing.T) { t.Parallel() const timeUnit = 500 * time.Millisecond c, _ := WithDeadline(Background(), time.Now().Add(1*timeUnit)) if got, prefix := fmt.Sprint(c), "context.Background.WithDeadline("; !strings.HasPrefix(got, prefix) { t.Errorf("c.String() = %q want prefix %q", got, prefix) } testDeadline(c, 2*timeUnit, t) c, _ = WithDeadline(Background(), time.Now().Add(1*timeUnit)) o := otherContext{c} testDeadline(o, 2*timeUnit, t) c, _ = WithDeadline(Background(), time.Now().Add(1*timeUnit)) o = otherContext{c} c, _ = WithDeadline(o, time.Now().Add(3*timeUnit)) testDeadline(c, 2*timeUnit, t) } func TestTimeout(t *testing.T) { t.Parallel() const timeUnit = 500 * time.Millisecond c, _ := WithTimeout(Background(), 1*timeUnit) if got, prefix := fmt.Sprint(c), "context.Background.WithDeadline("; !strings.HasPrefix(got, prefix) { t.Errorf("c.String() = %q want prefix %q", got, prefix) } testDeadline(c, 2*timeUnit, t) c, _ = WithTimeout(Background(), 1*timeUnit) o := otherContext{c} testDeadline(o, 2*timeUnit, t) c, _ = WithTimeout(Background(), 1*timeUnit) o = otherContext{c} c, _ = WithTimeout(o, 3*timeUnit) testDeadline(c, 2*timeUnit, t) } func TestCanceledTimeout(t *testing.T) { t.Parallel() const timeUnit = 500 * time.Millisecond c, _ := WithTimeout(Background(), 2*timeUnit) o := otherContext{c} c, cancel := WithTimeout(o, 4*timeUnit) cancel() time.Sleep(1 * timeUnit) // let cancelation propagate select { case <-c.Done(): default: t.Errorf("<-c.Done() blocked, but shouldn't have") } if e := c.Err(); e != Canceled { t.Errorf("c.Err() == %v want %v", e, Canceled) } } type key1 int type key2 int var k1 = key1(1) var k2 = key2(1) // same int as k1, different type var k3 = key2(3) // same type as k2, different int func TestValues(t *testing.T) { check := func(c Context, nm, v1, v2, v3 string) { if v, ok := c.Value(k1).(string); ok == (len(v1) == 0) || v != v1 { t.Errorf(`%s.Value(k1).(string) = %q, %t want %q, %t`, nm, v, ok, v1, len(v1) != 0) } if v, ok := c.Value(k2).(string); ok == (len(v2) == 0) || v != v2 { t.Errorf(`%s.Value(k2).(string) = %q, %t want %q, %t`, nm, v, ok, v2, len(v2) != 0) } if v, ok := c.Value(k3).(string); ok == (len(v3) == 0) || v != v3 { t.Errorf(`%s.Value(k3).(string) = %q, %t want %q, %t`, nm, v, ok, v3, len(v3) != 0) } } c0 := Background() check(c0, "c0", "", "", "") c1 := WithValue(Background(), k1, "c1k1") check(c1, "c1", "c1k1", "", "") if got, want := fmt.Sprint(c1), `context.Background.WithValue(1, "c1k1")`; got != want { t.Errorf("c.String() = %q want %q", got, want) } c2 := WithValue(c1, k2, "c2k2") check(c2, "c2", "c1k1", "c2k2", "") c3 := WithValue(c2, k3, "c3k3") check(c3, "c2", "c1k1", "c2k2", "c3k3") c4 := WithValue(c3, k1, nil) check(c4, "c4", "", "c2k2", "c3k3") o0 := otherContext{Background()} check(o0, "o0", "", "", "") o1 := otherContext{WithValue(Background(), k1, "c1k1")} check(o1, "o1", "c1k1", "", "") o2 := WithValue(o1, k2, "o2k2") check(o2, "o2", "c1k1", "o2k2", "") o3 := otherContext{c4} check(o3, "o3", "", "c2k2", "c3k3") o4 := WithValue(o3, k3, nil) check(o4, "o4", "", "c2k2", "") } func TestAllocs(t *testing.T) { bg := Background() for _, test := range []struct { desc string f func() limit float64 gccgoLimit float64 }{ { desc: "Background()", f: func() { Background() }, limit: 0, gccgoLimit: 0, }, { desc: fmt.Sprintf("WithValue(bg, %v, nil)", k1), f: func() { c := WithValue(bg, k1, nil) c.Value(k1) }, limit: 3, gccgoLimit: 3, }, { desc: "WithTimeout(bg, 15*time.Millisecond)", f: func() { c, _ := WithTimeout(bg, 15*time.Millisecond) <-c.Done() }, limit: 8, gccgoLimit: 16, }, { desc: "WithCancel(bg)", f: func() { c, cancel := WithCancel(bg) cancel() <-c.Done() }, limit: 5, gccgoLimit: 8, }, { desc: "WithTimeout(bg, 100*time.Millisecond)", f: func() { c, cancel := WithTimeout(bg, 100*time.Millisecond) cancel() <-c.Done() }, limit: 8, gccgoLimit: 25, }, } { limit := test.limit if runtime.Compiler == "gccgo" { // gccgo does not yet do escape analysis. // TODO(iant): Remove this when gccgo does do escape analysis. limit = test.gccgoLimit } if n := testing.AllocsPerRun(100, test.f); n > limit { t.Errorf("%s allocs = %f want %d", test.desc, n, int(limit)) } } } func TestSimultaneousCancels(t *testing.T) { root, cancel := WithCancel(Background()) m := map[Context]CancelFunc{root: cancel} q := []Context{root} // Create a tree of contexts. for len(q) != 0 && len(m) < 100 { parent := q[0] q = q[1:] for i := 0; i < 4; i++ { ctx, cancel := WithCancel(parent) m[ctx] = cancel q = append(q, ctx) } } // Start all the cancels in a random order. var wg sync.WaitGroup wg.Add(len(m)) for _, cancel := range m { go func(cancel CancelFunc) { cancel() wg.Done() }(cancel) } // Wait on all the contexts in a random order. for ctx := range m { select { case <-ctx.Done(): case <-time.After(1 * time.Second): buf := make([]byte, 10<<10) n := runtime.Stack(buf, true) t.Fatalf("timed out waiting for <-ctx.Done(); stacks:\n%s", buf[:n]) } } // Wait for all the cancel functions to return. done := make(chan struct{}) go func() { wg.Wait() close(done) }() select { case <-done: case <-time.After(1 * time.Second): buf := make([]byte, 10<<10) n := runtime.Stack(buf, true) t.Fatalf("timed out waiting for cancel functions; stacks:\n%s", buf[:n]) } } func TestInterlockedCancels(t *testing.T) { parent, cancelParent := WithCancel(Background()) child, cancelChild := WithCancel(parent) go func() { parent.Done() cancelChild() }() cancelParent() select { case <-child.Done(): case <-time.After(1 * time.Second): buf := make([]byte, 10<<10) n := runtime.Stack(buf, true) t.Fatalf("timed out waiting for child.Done(); stacks:\n%s", buf[:n]) } } func TestLayersCancel(t *testing.T) { testLayers(t, time.Now().UnixNano(), false) } func TestLayersTimeout(t *testing.T) { testLayers(t, time.Now().UnixNano(), true) } func testLayers(t *testing.T, seed int64, testTimeout bool) { rand.Seed(seed) errorf := func(format string, a ...interface{}) { t.Errorf(fmt.Sprintf("seed=%d: %s", seed, format), a...) } const ( timeout = 200 * time.Millisecond minLayers = 30 ) type value int var ( vals []*value cancels []CancelFunc numTimers int ctx = Background() ) for i := 0; i < minLayers || numTimers == 0 || len(cancels) == 0 || len(vals) == 0; i++ { switch rand.Intn(3) { case 0: v := new(value) ctx = WithValue(ctx, v, v) vals = append(vals, v) case 1: var cancel CancelFunc ctx, cancel = WithCancel(ctx) cancels = append(cancels, cancel) case 2: var cancel CancelFunc ctx, cancel = WithTimeout(ctx, timeout) cancels = append(cancels, cancel) numTimers++ } } checkValues := func(when string) { for _, key := range vals { if val := ctx.Value(key).(*value); key != val { errorf("%s: ctx.Value(%p) = %p want %p", when, key, val, key) } } } select { case <-ctx.Done(): errorf("ctx should not be canceled yet") default: } if s, prefix := fmt.Sprint(ctx), "context.Background."; !strings.HasPrefix(s, prefix) { t.Errorf("ctx.String() = %q want prefix %q", s, prefix) } t.Log(ctx) checkValues("before cancel") if testTimeout { select { case <-ctx.Done(): case <-time.After(timeout + 100*time.Millisecond): errorf("ctx should have timed out") } checkValues("after timeout") } else { cancel := cancels[rand.Intn(len(cancels))] cancel() select { case <-ctx.Done(): default: errorf("ctx should be canceled") } checkValues("after cancel") } } func TestCancelRemoves(t *testing.T) { checkChildren := func(when string, ctx Context, want int) { if got := len(ctx.(*cancelCtx).children); got != want { t.Errorf("%s: context has %d children, want %d", when, got, want) } } ctx, _ := WithCancel(Background()) checkChildren("after creation", ctx, 0) _, cancel := WithCancel(ctx) checkChildren("with WithCancel child ", ctx, 1) cancel() checkChildren("after cancelling WithCancel child", ctx, 0) ctx, _ = WithCancel(Background()) checkChildren("after creation", ctx, 0) _, cancel = WithTimeout(ctx, 60*time.Minute) checkChildren("with WithTimeout child ", ctx, 1) cancel() checkChildren("after cancelling WithTimeout child", ctx, 0) } ================================================ FILE: vendor/golang.org/x/net/context/ctxhttp/ctxhttp.go ================================================ // Copyright 2016 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 file. // +build go1.7 // Package ctxhttp provides helper functions for performing context-aware HTTP requests. package ctxhttp // import "golang.org/x/net/context/ctxhttp" import ( "io" "net/http" "net/url" "strings" "golang.org/x/net/context" ) // Do sends an HTTP request with the provided http.Client and returns // an HTTP response. // // If the client is nil, http.DefaultClient is used. // // The provided ctx must be non-nil. If it is canceled or times out, // ctx.Err() will be returned. func Do(ctx context.Context, client *http.Client, req *http.Request) (*http.Response, error) { if client == nil { client = http.DefaultClient } resp, err := client.Do(req.WithContext(ctx)) // If we got an error, and the context has been canceled, // the context's error is probably more useful. if err != nil { select { case <-ctx.Done(): err = ctx.Err() default: } } return resp, err } // Get issues a GET request via the Do function. func Get(ctx context.Context, client *http.Client, url string) (*http.Response, error) { req, err := http.NewRequest("GET", url, nil) if err != nil { return nil, err } return Do(ctx, client, req) } // Head issues a HEAD request via the Do function. func Head(ctx context.Context, client *http.Client, url string) (*http.Response, error) { req, err := http.NewRequest("HEAD", url, nil) if err != nil { return nil, err } return Do(ctx, client, req) } // Post issues a POST request via the Do function. func Post(ctx context.Context, client *http.Client, url string, bodyType string, body io.Reader) (*http.Response, error) { req, err := http.NewRequest("POST", url, body) if err != nil { return nil, err } req.Header.Set("Content-Type", bodyType) return Do(ctx, client, req) } // PostForm issues a POST request via the Do function. func PostForm(ctx context.Context, client *http.Client, url string, data url.Values) (*http.Response, error) { return Post(ctx, client, url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode())) } ================================================ FILE: vendor/golang.org/x/net/context/ctxhttp/ctxhttp_17_test.go ================================================ // Copyright 2015 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 file. // +build !plan9,go1.7 package ctxhttp import ( "io" "net/http" "net/http/httptest" "testing" "context" ) func TestGo17Context(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { io.WriteString(w, "ok") })) defer ts.Close() ctx := context.Background() resp, err := Get(ctx, http.DefaultClient, ts.URL) if resp == nil || err != nil { t.Fatalf("error received from client: %v %v", err, resp) } resp.Body.Close() } ================================================ FILE: vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17.go ================================================ // Copyright 2015 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 file. // +build !go1.7 package ctxhttp // import "golang.org/x/net/context/ctxhttp" import ( "io" "net/http" "net/url" "strings" "golang.org/x/net/context" ) func nop() {} var ( testHookContextDoneBeforeHeaders = nop testHookDoReturned = nop testHookDidBodyClose = nop ) // Do sends an HTTP request with the provided http.Client and returns an HTTP response. // If the client is nil, http.DefaultClient is used. // If the context is canceled or times out, ctx.Err() will be returned. func Do(ctx context.Context, client *http.Client, req *http.Request) (*http.Response, error) { if client == nil { client = http.DefaultClient } // TODO(djd): Respect any existing value of req.Cancel. cancel := make(chan struct{}) req.Cancel = cancel type responseAndError struct { resp *http.Response err error } result := make(chan responseAndError, 1) // Make local copies of test hooks closed over by goroutines below. // Prevents data races in tests. testHookDoReturned := testHookDoReturned testHookDidBodyClose := testHookDidBodyClose go func() { resp, err := client.Do(req) testHookDoReturned() result <- responseAndError{resp, err} }() var resp *http.Response select { case <-ctx.Done(): testHookContextDoneBeforeHeaders() close(cancel) // Clean up after the goroutine calling client.Do: go func() { if r := <-result; r.resp != nil { testHookDidBodyClose() r.resp.Body.Close() } }() return nil, ctx.Err() case r := <-result: var err error resp, err = r.resp, r.err if err != nil { return resp, err } } c := make(chan struct{}) go func() { select { case <-ctx.Done(): close(cancel) case <-c: // The response's Body is closed. } }() resp.Body = ¬ifyingReader{resp.Body, c} return resp, nil } // Get issues a GET request via the Do function. func Get(ctx context.Context, client *http.Client, url string) (*http.Response, error) { req, err := http.NewRequest("GET", url, nil) if err != nil { return nil, err } return Do(ctx, client, req) } // Head issues a HEAD request via the Do function. func Head(ctx context.Context, client *http.Client, url string) (*http.Response, error) { req, err := http.NewRequest("HEAD", url, nil) if err != nil { return nil, err } return Do(ctx, client, req) } // Post issues a POST request via the Do function. func Post(ctx context.Context, client *http.Client, url string, bodyType string, body io.Reader) (*http.Response, error) { req, err := http.NewRequest("POST", url, body) if err != nil { return nil, err } req.Header.Set("Content-Type", bodyType) return Do(ctx, client, req) } // PostForm issues a POST request via the Do function. func PostForm(ctx context.Context, client *http.Client, url string, data url.Values) (*http.Response, error) { return Post(ctx, client, url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode())) } // notifyingReader is an io.ReadCloser that closes the notify channel after // Close is called or a Read fails on the underlying ReadCloser. type notifyingReader struct { io.ReadCloser notify chan<- struct{} } func (r *notifyingReader) Read(p []byte) (int, error) { n, err := r.ReadCloser.Read(p) if err != nil && r.notify != nil { close(r.notify) r.notify = nil } return n, err } func (r *notifyingReader) Close() error { err := r.ReadCloser.Close() if r.notify != nil { close(r.notify) r.notify = nil } return err } ================================================ FILE: vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17_test.go ================================================ // Copyright 2015 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 file. // +build !plan9,!go1.7 package ctxhttp import ( "net" "net/http" "net/http/httptest" "sync" "testing" "time" "golang.org/x/net/context" ) // golang.org/issue/14065 func TestClosesResponseBodyOnCancel(t *testing.T) { defer func() { testHookContextDoneBeforeHeaders = nop }() defer func() { testHookDoReturned = nop }() defer func() { testHookDidBodyClose = nop }() ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})) defer ts.Close() ctx, cancel := context.WithCancel(context.Background()) // closed when Do enters select case <-ctx.Done() enteredDonePath := make(chan struct{}) testHookContextDoneBeforeHeaders = func() { close(enteredDonePath) } testHookDoReturned = func() { // We now have the result (the Flush'd headers) at least, // so we can cancel the request. cancel() // But block the client.Do goroutine from sending // until Do enters into the <-ctx.Done() path, since // otherwise if both channels are readable, select // picks a random one. <-enteredDonePath } sawBodyClose := make(chan struct{}) testHookDidBodyClose = func() { close(sawBodyClose) } tr := &http.Transport{} defer tr.CloseIdleConnections() c := &http.Client{Transport: tr} req, _ := http.NewRequest("GET", ts.URL, nil) _, doErr := Do(ctx, c, req) select { case <-sawBodyClose: case <-time.After(5 * time.Second): t.Fatal("timeout waiting for body to close") } if doErr != ctx.Err() { t.Errorf("Do error = %v; want %v", doErr, ctx.Err()) } } type noteCloseConn struct { net.Conn onceClose sync.Once closefn func() } func (c *noteCloseConn) Close() error { c.onceClose.Do(c.closefn) return c.Conn.Close() } ================================================ FILE: vendor/golang.org/x/net/context/ctxhttp/ctxhttp_test.go ================================================ // Copyright 2015 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 file. // +build !plan9 package ctxhttp import ( "io" "io/ioutil" "net/http" "net/http/httptest" "testing" "time" "golang.org/x/net/context" ) const ( requestDuration = 100 * time.Millisecond requestBody = "ok" ) func okHandler(w http.ResponseWriter, r *http.Request) { time.Sleep(requestDuration) io.WriteString(w, requestBody) } func TestNoTimeout(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(okHandler)) defer ts.Close() ctx := context.Background() res, err := Get(ctx, nil, ts.URL) if err != nil { t.Fatal(err) } defer res.Body.Close() slurp, err := ioutil.ReadAll(res.Body) if err != nil { t.Fatal(err) } if string(slurp) != requestBody { t.Errorf("body = %q; want %q", slurp, requestBody) } } func TestCancelBeforeHeaders(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) blockServer := make(chan struct{}) ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { cancel() <-blockServer io.WriteString(w, requestBody) })) defer ts.Close() defer close(blockServer) res, err := Get(ctx, nil, ts.URL) if err == nil { res.Body.Close() t.Fatal("Get returned unexpected nil error") } if err != context.Canceled { t.Errorf("err = %v; want %v", err, context.Canceled) } } func TestCancelAfterHangingRequest(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) w.(http.Flusher).Flush() <-w.(http.CloseNotifier).CloseNotify() })) defer ts.Close() ctx, cancel := context.WithCancel(context.Background()) resp, err := Get(ctx, nil, ts.URL) if err != nil { t.Fatalf("unexpected error in Get: %v", err) } // Cancel befer reading the body. // Reading Request.Body should fail, since the request was // canceled before anything was written. cancel() done := make(chan struct{}) go func() { b, err := ioutil.ReadAll(resp.Body) if len(b) != 0 || err == nil { t.Errorf(`Read got (%q, %v); want ("", error)`, b, err) } close(done) }() select { case <-time.After(1 * time.Second): t.Errorf("Test timed out") case <-done: } } ================================================ FILE: vendor/golang.org/x/net/context/go17.go ================================================ // Copyright 2016 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 file. // +build go1.7 package context import ( "context" // standard library's context, as of Go 1.7 "time" ) var ( todo = context.TODO() background = context.Background() ) // Canceled is the error returned by Context.Err when the context is canceled. var Canceled = context.Canceled // DeadlineExceeded is the error returned by Context.Err when the context's // deadline passes. var DeadlineExceeded = context.DeadlineExceeded // WithCancel returns a copy of parent with a new Done channel. The returned // context's Done channel is closed when the returned cancel function is called // or when the parent context's Done channel is closed, whichever happens first. // // Canceling this context releases resources associated with it, so code should // call cancel as soon as the operations running in this Context complete. func WithCancel(parent Context) (ctx Context, cancel CancelFunc) { ctx, f := context.WithCancel(parent) return ctx, CancelFunc(f) } // WithDeadline returns a copy of the parent context with the deadline adjusted // to be no later than d. If the parent's deadline is already earlier than d, // WithDeadline(parent, d) is semantically equivalent to parent. The returned // context's Done channel is closed when the deadline expires, when the returned // cancel function is called, or when the parent context's Done channel is // closed, whichever happens first. // // Canceling this context releases resources associated with it, so code should // call cancel as soon as the operations running in this Context complete. func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) { ctx, f := context.WithDeadline(parent, deadline) return ctx, CancelFunc(f) } // WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)). // // Canceling this context releases resources associated with it, so code should // call cancel as soon as the operations running in this Context complete: // // func slowOperationWithTimeout(ctx context.Context) (Result, error) { // ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond) // defer cancel() // releases resources if slowOperation completes before timeout elapses // return slowOperation(ctx) // } func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) { return WithDeadline(parent, time.Now().Add(timeout)) } // WithValue returns a copy of parent in which the value associated with key is // val. // // Use context Values only for request-scoped data that transits processes and // APIs, not for passing optional parameters to functions. func WithValue(parent Context, key interface{}, val interface{}) Context { return context.WithValue(parent, key, val) } ================================================ FILE: vendor/golang.org/x/net/context/go19.go ================================================ // 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 file. // +build go1.9 package context import "context" // standard library's context, as of Go 1.7 // A Context carries a deadline, a cancelation signal, and other values across // API boundaries. // // Context's methods may be called by multiple goroutines simultaneously. type Context = context.Context // A CancelFunc tells an operation to abandon its work. // A CancelFunc does not wait for the work to stop. // After the first call, subsequent calls to a CancelFunc do nothing. type CancelFunc = context.CancelFunc ================================================ FILE: vendor/golang.org/x/net/context/pre_go17.go ================================================ // Copyright 2014 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 file. // +build !go1.7 package context import ( "errors" "fmt" "sync" "time" ) // An emptyCtx is never canceled, has no values, and has no deadline. It is not // struct{}, since vars of this type must have distinct addresses. type emptyCtx int func (*emptyCtx) Deadline() (deadline time.Time, ok bool) { return } func (*emptyCtx) Done() <-chan struct{} { return nil } func (*emptyCtx) Err() error { return nil } func (*emptyCtx) Value(key interface{}) interface{} { return nil } func (e *emptyCtx) String() string { switch e { case background: return "context.Background" case todo: return "context.TODO" } return "unknown empty Context" } var ( background = new(emptyCtx) todo = new(emptyCtx) ) // Canceled is the error returned by Context.Err when the context is canceled. var Canceled = errors.New("context canceled") // DeadlineExceeded is the error returned by Context.Err when the context's // deadline passes. var DeadlineExceeded = errors.New("context deadline exceeded") // WithCancel returns a copy of parent with a new Done channel. The returned // context's Done channel is closed when the returned cancel function is called // or when the parent context's Done channel is closed, whichever happens first. // // Canceling this context releases resources associated with it, so code should // call cancel as soon as the operations running in this Context complete. func WithCancel(parent Context) (ctx Context, cancel CancelFunc) { c := newCancelCtx(parent) propagateCancel(parent, c) return c, func() { c.cancel(true, Canceled) } } // newCancelCtx returns an initialized cancelCtx. func newCancelCtx(parent Context) *cancelCtx { return &cancelCtx{ Context: parent, done: make(chan struct{}), } } // propagateCancel arranges for child to be canceled when parent is. func propagateCancel(parent Context, child canceler) { if parent.Done() == nil { return // parent is never canceled } if p, ok := parentCancelCtx(parent); ok { p.mu.Lock() if p.err != nil { // parent has already been canceled child.cancel(false, p.err) } else { if p.children == nil { p.children = make(map[canceler]bool) } p.children[child] = true } p.mu.Unlock() } else { go func() { select { case <-parent.Done(): child.cancel(false, parent.Err()) case <-child.Done(): } }() } } // parentCancelCtx follows a chain of parent references until it finds a // *cancelCtx. This function understands how each of the concrete types in this // package represents its parent. func parentCancelCtx(parent Context) (*cancelCtx, bool) { for { switch c := parent.(type) { case *cancelCtx: return c, true case *timerCtx: return c.cancelCtx, true case *valueCtx: parent = c.Context default: return nil, false } } } // removeChild removes a context from its parent. func removeChild(parent Context, child canceler) { p, ok := parentCancelCtx(parent) if !ok { return } p.mu.Lock() if p.children != nil { delete(p.children, child) } p.mu.Unlock() } // A canceler is a context type that can be canceled directly. The // implementations are *cancelCtx and *timerCtx. type canceler interface { cancel(removeFromParent bool, err error) Done() <-chan struct{} } // A cancelCtx can be canceled. When canceled, it also cancels any children // that implement canceler. type cancelCtx struct { Context done chan struct{} // closed by the first cancel call. mu sync.Mutex children map[canceler]bool // set to nil by the first cancel call err error // set to non-nil by the first cancel call } func (c *cancelCtx) Done() <-chan struct{} { return c.done } func (c *cancelCtx) Err() error { c.mu.Lock() defer c.mu.Unlock() return c.err } func (c *cancelCtx) String() string { return fmt.Sprintf("%v.WithCancel", c.Context) } // cancel closes c.done, cancels each of c's children, and, if // removeFromParent is true, removes c from its parent's children. func (c *cancelCtx) cancel(removeFromParent bool, err error) { if err == nil { panic("context: internal error: missing cancel error") } c.mu.Lock() if c.err != nil { c.mu.Unlock() return // already canceled } c.err = err close(c.done) for child := range c.children { // NOTE: acquiring the child's lock while holding parent's lock. child.cancel(false, err) } c.children = nil c.mu.Unlock() if removeFromParent { removeChild(c.Context, c) } } // WithDeadline returns a copy of the parent context with the deadline adjusted // to be no later than d. If the parent's deadline is already earlier than d, // WithDeadline(parent, d) is semantically equivalent to parent. The returned // context's Done channel is closed when the deadline expires, when the returned // cancel function is called, or when the parent context's Done channel is // closed, whichever happens first. // // Canceling this context releases resources associated with it, so code should // call cancel as soon as the operations running in this Context complete. func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) { if cur, ok := parent.Deadline(); ok && cur.Before(deadline) { // The current deadline is already sooner than the new one. return WithCancel(parent) } c := &timerCtx{ cancelCtx: newCancelCtx(parent), deadline: deadline, } propagateCancel(parent, c) d := deadline.Sub(time.Now()) if d <= 0 { c.cancel(true, DeadlineExceeded) // deadline has already passed return c, func() { c.cancel(true, Canceled) } } c.mu.Lock() defer c.mu.Unlock() if c.err == nil { c.timer = time.AfterFunc(d, func() { c.cancel(true, DeadlineExceeded) }) } return c, func() { c.cancel(true, Canceled) } } // A timerCtx carries a timer and a deadline. It embeds a cancelCtx to // implement Done and Err. It implements cancel by stopping its timer then // delegating to cancelCtx.cancel. type timerCtx struct { *cancelCtx timer *time.Timer // Under cancelCtx.mu. deadline time.Time } func (c *timerCtx) Deadline() (deadline time.Time, ok bool) { return c.deadline, true } func (c *timerCtx) String() string { return fmt.Sprintf("%v.WithDeadline(%s [%s])", c.cancelCtx.Context, c.deadline, c.deadline.Sub(time.Now())) } func (c *timerCtx) cancel(removeFromParent bool, err error) { c.cancelCtx.cancel(false, err) if removeFromParent { // Remove this timerCtx from its parent cancelCtx's children. removeChild(c.cancelCtx.Context, c) } c.mu.Lock() if c.timer != nil { c.timer.Stop() c.timer = nil } c.mu.Unlock() } // WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)). // // Canceling this context releases resources associated with it, so code should // call cancel as soon as the operations running in this Context complete: // // func slowOperationWithTimeout(ctx context.Context) (Result, error) { // ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond) // defer cancel() // releases resources if slowOperation completes before timeout elapses // return slowOperation(ctx) // } func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) { return WithDeadline(parent, time.Now().Add(timeout)) } // WithValue returns a copy of parent in which the value associated with key is // val. // // Use context Values only for request-scoped data that transits processes and // APIs, not for passing optional parameters to functions. func WithValue(parent Context, key interface{}, val interface{}) Context { return &valueCtx{parent, key, val} } // A valueCtx carries a key-value pair. It implements Value for that key and // delegates all other calls to the embedded Context. type valueCtx struct { Context key, val interface{} } func (c *valueCtx) String() string { return fmt.Sprintf("%v.WithValue(%#v, %#v)", c.Context, c.key, c.val) } func (c *valueCtx) Value(key interface{}) interface{} { if c.key == key { return c.val } return c.Context.Value(key) } ================================================ FILE: vendor/golang.org/x/net/context/pre_go19.go ================================================ // Copyright 2014 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 file. // +build !go1.9 package context import "time" // A Context carries a deadline, a cancelation signal, and other values across // API boundaries. // // Context's methods may be called by multiple goroutines simultaneously. type Context interface { // Deadline returns the time when work done on behalf of this context // should be canceled. Deadline returns ok==false when no deadline is // set. Successive calls to Deadline return the same results. Deadline() (deadline time.Time, ok bool) // Done returns a channel that's closed when work done on behalf of this // context should be canceled. Done may return nil if this context can // never be canceled. Successive calls to Done return the same value. // // WithCancel arranges for Done to be closed when cancel is called; // WithDeadline arranges for Done to be closed when the deadline // expires; WithTimeout arranges for Done to be closed when the timeout // elapses. // // Done is provided for use in select statements: // // // Stream generates values with DoSomething and sends them to out // // until DoSomething returns an error or ctx.Done is closed. // func Stream(ctx context.Context, out chan<- Value) error { // for { // v, err := DoSomething(ctx) // if err != nil { // return err // } // select { // case <-ctx.Done(): // return ctx.Err() // case out <- v: // } // } // } // // See http://blog.golang.org/pipelines for more examples of how to use // a Done channel for cancelation. Done() <-chan struct{} // Err returns a non-nil error value after Done is closed. Err returns // Canceled if the context was canceled or DeadlineExceeded if the // context's deadline passed. No other values for Err are defined. // After Done is closed, successive calls to Err return the same value. Err() error // Value returns the value associated with this context for key, or nil // if no value is associated with key. Successive calls to Value with // the same key returns the same result. // // Use context values only for request-scoped data that transits // processes and API boundaries, not for passing optional parameters to // functions. // // A key identifies a specific value in a Context. Functions that wish // to store values in Context typically allocate a key in a global // variable then use that key as the argument to context.WithValue and // Context.Value. A key can be any type that supports equality; // packages should define keys as an unexported type to avoid // collisions. // // Packages that define a Context key should provide type-safe accessors // for the values stores using that key: // // // Package user defines a User type that's stored in Contexts. // package user // // import "golang.org/x/net/context" // // // User is the type of value stored in the Contexts. // type User struct {...} // // // key is an unexported type for keys defined in this package. // // This prevents collisions with keys defined in other packages. // type key int // // // userKey is the key for user.User values in Contexts. It is // // unexported; clients use user.NewContext and user.FromContext // // instead of using this key directly. // var userKey key = 0 // // // NewContext returns a new Context that carries value u. // func NewContext(ctx context.Context, u *User) context.Context { // return context.WithValue(ctx, userKey, u) // } // // // FromContext returns the User value stored in ctx, if any. // func FromContext(ctx context.Context) (*User, bool) { // u, ok := ctx.Value(userKey).(*User) // return u, ok // } Value(key interface{}) interface{} } // A CancelFunc tells an operation to abandon its work. // A CancelFunc does not wait for the work to stop. // After the first call, subsequent calls to a CancelFunc do nothing. type CancelFunc func() ================================================ FILE: vendor/golang.org/x/net/context/withtimeout_test.go ================================================ // Copyright 2014 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 file. package context_test import ( "fmt" "time" "golang.org/x/net/context" ) // This example passes a context with a timeout to tell a blocking function that // it should abandon its work after the timeout elapses. func ExampleWithTimeout() { // Pass a context with a timeout to tell a blocking function that it // should abandon its work after the timeout elapses. ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond) defer cancel() select { case <-time.After(1 * time.Second): fmt.Println("overslept") case <-ctx.Done(): fmt.Println(ctx.Err()) // prints "context deadline exceeded" } // Output: // context deadline exceeded } ================================================ FILE: vendor/golang.org/x/oauth2/.travis.yml ================================================ language: go go: - tip install: - export GOPATH="$HOME/gopath" - mkdir -p "$GOPATH/src/golang.org/x" - mv "$TRAVIS_BUILD_DIR" "$GOPATH/src/golang.org/x/oauth2" - go get -v -t -d golang.org/x/oauth2/... script: - go test -v golang.org/x/oauth2/... ================================================ FILE: vendor/golang.org/x/oauth2/AUTHORS ================================================ # This source code refers to The Go Authors for copyright purposes. # The master list of authors is in the main Go distribution, # visible at http://tip.golang.org/AUTHORS. ================================================ FILE: vendor/golang.org/x/oauth2/CONTRIBUTING.md ================================================ # Contributing to Go Go is an open source project. It is the work of hundreds of contributors. We appreciate your help! ## Filing issues When [filing an issue](https://github.com/golang/oauth2/issues), make sure to answer these five questions: 1. What version of Go are you using (`go version`)? 2. What operating system and processor architecture are you using? 3. What did you do? 4. What did you expect to see? 5. What did you see instead? General questions should go to the [golang-nuts mailing list](https://groups.google.com/group/golang-nuts) instead of the issue tracker. The gophers there will answer or ask you to file an issue if you've tripped over a bug. ## Contributing code Please read the [Contribution Guidelines](https://golang.org/doc/contribute.html) before sending patches. **We do not accept GitHub pull requests** (we use [Gerrit](https://code.google.com/p/gerrit/) instead for code review). Unless otherwise noted, the Go source files are distributed under the BSD-style license found in the LICENSE file. ================================================ FILE: vendor/golang.org/x/oauth2/CONTRIBUTORS ================================================ # This source code was written by the Go contributors. # The master list of contributors is in the main Go distribution, # visible at http://tip.golang.org/CONTRIBUTORS. ================================================ FILE: vendor/golang.org/x/oauth2/LICENSE ================================================ Copyright (c) 2009 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. ================================================ FILE: vendor/golang.org/x/oauth2/README.md ================================================ # OAuth2 for Go [![Build Status](https://travis-ci.org/golang/oauth2.svg?branch=master)](https://travis-ci.org/golang/oauth2) [![GoDoc](https://godoc.org/golang.org/x/oauth2?status.svg)](https://godoc.org/golang.org/x/oauth2) oauth2 package contains a client implementation for OAuth 2.0 spec. ## Installation ~~~~ go get golang.org/x/oauth2 ~~~~ Or you can manually git clone the repository to `$(go env GOPATH)/src/golang.org/x/oauth2`. See godoc for further documentation and examples. * [godoc.org/golang.org/x/oauth2](http://godoc.org/golang.org/x/oauth2) * [godoc.org/golang.org/x/oauth2/google](http://godoc.org/golang.org/x/oauth2/google) ## App Engine In change 96e89be (March 2015), we removed the `oauth2.Context2` type in favor of the [`context.Context`](https://golang.org/x/net/context#Context) type from the `golang.org/x/net/context` package This means it's no longer possible to use the "Classic App Engine" `appengine.Context` type with the `oauth2` package. (You're using Classic App Engine if you import the package `"appengine"`.) To work around this, you may use the new `"google.golang.org/appengine"` package. This package has almost the same API as the `"appengine"` package, but it can be fetched with `go get` and used on "Managed VMs" and well as Classic App Engine. See the [new `appengine` package's readme](https://github.com/golang/appengine#updating-a-go-app-engine-app) for information on updating your app. If you don't want to update your entire app to use the new App Engine packages, you may use both sets of packages in parallel, using only the new packages with the `oauth2` package. ```go import ( "golang.org/x/net/context" "golang.org/x/oauth2" "golang.org/x/oauth2/google" newappengine "google.golang.org/appengine" newurlfetch "google.golang.org/appengine/urlfetch" "appengine" ) func handler(w http.ResponseWriter, r *http.Request) { var c appengine.Context = appengine.NewContext(r) c.Infof("Logging a message with the old package") var ctx context.Context = newappengine.NewContext(r) client := &http.Client{ Transport: &oauth2.Transport{ Source: google.AppEngineTokenSource(ctx, "scope"), Base: &newurlfetch.Transport{Context: ctx}, }, } client.Get("...") } ``` ## Report Issues / Send Patches This repository uses Gerrit for code changes. To learn how to submit changes to this repository, see https://golang.org/doc/contribute.html. The main issue tracker for the oauth2 repository is located at https://github.com/golang/oauth2/issues. ================================================ FILE: vendor/golang.org/x/oauth2/client_appengine.go ================================================ // Copyright 2014 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 file. // +build appengine // App Engine hooks. package oauth2 import ( "net/http" "golang.org/x/net/context" "golang.org/x/oauth2/internal" "google.golang.org/appengine/urlfetch" ) func init() { internal.RegisterContextClientFunc(contextClientAppEngine) } func contextClientAppEngine(ctx context.Context) (*http.Client, error) { return urlfetch.Client(ctx), nil } ================================================ FILE: vendor/golang.org/x/oauth2/example_test.go ================================================ // Copyright 2014 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 file. package oauth2_test import ( "context" "fmt" "log" "net/http" "time" "golang.org/x/oauth2" ) func ExampleConfig() { ctx := context.Background() conf := &oauth2.Config{ ClientID: "YOUR_CLIENT_ID", ClientSecret: "YOUR_CLIENT_SECRET", Scopes: []string{"SCOPE1", "SCOPE2"}, Endpoint: oauth2.Endpoint{ AuthURL: "https://provider.com/o/oauth2/auth", TokenURL: "https://provider.com/o/oauth2/token", }, } // Redirect user to consent page to ask for permission // for the scopes specified above. url := conf.AuthCodeURL("state", oauth2.AccessTypeOffline) fmt.Printf("Visit the URL for the auth dialog: %v", url) // Use the authorization code that is pushed to the redirect // URL. Exchange will do the handshake to retrieve the // initial access token. The HTTP Client returned by // conf.Client will refresh the token as necessary. var code string if _, err := fmt.Scan(&code); err != nil { log.Fatal(err) } tok, err := conf.Exchange(ctx, code) if err != nil { log.Fatal(err) } client := conf.Client(ctx, tok) client.Get("...") } func ExampleConfig_customHTTP() { ctx := context.Background() conf := &oauth2.Config{ ClientID: "YOUR_CLIENT_ID", ClientSecret: "YOUR_CLIENT_SECRET", Scopes: []string{"SCOPE1", "SCOPE2"}, Endpoint: oauth2.Endpoint{ TokenURL: "https://provider.com/o/oauth2/token", AuthURL: "https://provider.com/o/oauth2/auth", }, } // Redirect user to consent page to ask for permission // for the scopes specified above. url := conf.AuthCodeURL("state", oauth2.AccessTypeOffline) fmt.Printf("Visit the URL for the auth dialog: %v", url) // Use the authorization code that is pushed to the redirect // URL. Exchange will do the handshake to retrieve the // initial access token. The HTTP Client returned by // conf.Client will refresh the token as necessary. var code string if _, err := fmt.Scan(&code); err != nil { log.Fatal(err) } // Use the custom HTTP client when requesting a token. httpClient := &http.Client{Timeout: 2 * time.Second} ctx = context.WithValue(ctx, oauth2.HTTPClient, httpClient) tok, err := conf.Exchange(ctx, code) if err != nil { log.Fatal(err) } client := conf.Client(ctx, tok) _ = client } ================================================ FILE: vendor/golang.org/x/oauth2/internal/doc.go ================================================ // 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 file. // Package internal contains support packages for oauth2 package. package internal ================================================ FILE: vendor/golang.org/x/oauth2/internal/oauth2.go ================================================ // Copyright 2014 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 file. package internal import ( "bufio" "crypto/rsa" "crypto/x509" "encoding/pem" "errors" "fmt" "io" "strings" ) // ParseKey converts the binary contents of a private key file // to an *rsa.PrivateKey. It detects whether the private key is in a // PEM container or not. If so, it extracts the the private key // from PEM container before conversion. It only supports PEM // containers with no passphrase. func ParseKey(key []byte) (*rsa.PrivateKey, error) { block, _ := pem.Decode(key) if block != nil { key = block.Bytes } parsedKey, err := x509.ParsePKCS8PrivateKey(key) if err != nil { parsedKey, err = x509.ParsePKCS1PrivateKey(key) if err != nil { return nil, fmt.Errorf("private key should be a PEM or plain PKSC1 or PKCS8; parse error: %v", err) } } parsed, ok := parsedKey.(*rsa.PrivateKey) if !ok { return nil, errors.New("private key is invalid") } return parsed, nil } func ParseINI(ini io.Reader) (map[string]map[string]string, error) { result := map[string]map[string]string{ "": {}, // root section } scanner := bufio.NewScanner(ini) currentSection := "" for scanner.Scan() { line := strings.TrimSpace(scanner.Text()) if strings.HasPrefix(line, ";") { // comment. continue } if strings.HasPrefix(line, "[") && strings.HasSuffix(line, "]") { currentSection = strings.TrimSpace(line[1 : len(line)-1]) result[currentSection] = map[string]string{} continue } parts := strings.SplitN(line, "=", 2) if len(parts) == 2 && parts[0] != "" { result[currentSection][strings.TrimSpace(parts[0])] = strings.TrimSpace(parts[1]) } } if err := scanner.Err(); err != nil { return nil, fmt.Errorf("error scanning ini: %v", err) } return result, nil } func CondVal(v string) []string { if v == "" { return nil } return []string{v} } ================================================ FILE: vendor/golang.org/x/oauth2/internal/oauth2_test.go ================================================ // Copyright 2014 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 file. package internal import ( "reflect" "strings" "testing" ) func TestParseINI(t *testing.T) { tests := []struct { ini string want map[string]map[string]string }{ { `root = toor [foo] bar = hop ini = nin `, map[string]map[string]string{ "": {"root": "toor"}, "foo": {"bar": "hop", "ini": "nin"}, }, }, { `[empty] [section] empty= `, map[string]map[string]string{ "": {}, "empty": {}, "section": {"empty": ""}, }, }, { `ignore [invalid =stuff ;comment=true `, map[string]map[string]string{ "": {}, }, }, } for _, tt := range tests { result, err := ParseINI(strings.NewReader(tt.ini)) if err != nil { t.Errorf("ParseINI(%q) error %v, want: no error", tt.ini, err) continue } if !reflect.DeepEqual(result, tt.want) { t.Errorf("ParseINI(%q) = %#v, want: %#v", tt.ini, result, tt.want) } } } ================================================ FILE: vendor/golang.org/x/oauth2/internal/token.go ================================================ // Copyright 2014 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 file. package internal import ( "encoding/json" "fmt" "io" "io/ioutil" "mime" "net/http" "net/url" "strconv" "strings" "time" "golang.org/x/net/context" "golang.org/x/net/context/ctxhttp" ) // Token represents the credentials used to authorize // the requests to access protected resources on the OAuth 2.0 // provider's backend. // // This type is a mirror of oauth2.Token and exists to break // an otherwise-circular dependency. Other internal packages // should convert this Token into an oauth2.Token before use. type Token struct { // AccessToken is the token that authorizes and authenticates // the requests. AccessToken string // TokenType is the type of token. // The Type method returns either this or "Bearer", the default. TokenType string // RefreshToken is a token that's used by the application // (as opposed to the user) to refresh the access token // if it expires. RefreshToken string // Expiry is the optional expiration time of the access token. // // If zero, TokenSource implementations will reuse the same // token forever and RefreshToken or equivalent // mechanisms for that TokenSource will not be used. Expiry time.Time // Raw optionally contains extra metadata from the server // when updating a token. Raw interface{} } // tokenJSON is the struct representing the HTTP response from OAuth2 // providers returning a token in JSON form. type tokenJSON struct { AccessToken string `json:"access_token"` TokenType string `json:"token_type"` RefreshToken string `json:"refresh_token"` ExpiresIn expirationTime `json:"expires_in"` // at least PayPal returns string, while most return number Expires expirationTime `json:"expires"` // broken Facebook spelling of expires_in } func (e *tokenJSON) expiry() (t time.Time) { if v := e.ExpiresIn; v != 0 { return time.Now().Add(time.Duration(v) * time.Second) } if v := e.Expires; v != 0 { return time.Now().Add(time.Duration(v) * time.Second) } return } type expirationTime int32 func (e *expirationTime) UnmarshalJSON(b []byte) error { var n json.Number err := json.Unmarshal(b, &n) if err != nil { return err } i, err := n.Int64() if err != nil { return err } *e = expirationTime(i) return nil } var brokenAuthHeaderProviders = []string{ "https://accounts.google.com/", "https://api.codeswholesale.com/oauth/token", "https://api.dropbox.com/", "https://api.dropboxapi.com/", "https://api.instagram.com/", "https://api.netatmo.net/", "https://api.odnoklassniki.ru/", "https://api.pushbullet.com/", "https://api.soundcloud.com/", "https://api.twitch.tv/", "https://app.box.com/", "https://connect.stripe.com/", "https://graph.facebook.com", // see https://github.com/golang/oauth2/issues/214 "https://login.microsoftonline.com/", "https://login.salesforce.com/", "https://login.windows.net", "https://login.live.com/", "https://oauth.sandbox.trainingpeaks.com/", "https://oauth.trainingpeaks.com/", "https://oauth.vk.com/", "https://openapi.baidu.com/", "https://slack.com/", "https://test-sandbox.auth.corp.google.com", "https://test.salesforce.com/", "https://user.gini.net/", "https://www.douban.com/", "https://www.googleapis.com/", "https://www.linkedin.com/", "https://www.strava.com/oauth/", "https://www.wunderlist.com/oauth/", "https://api.patreon.com/", "https://sandbox.codeswholesale.com/oauth/token", "https://api.sipgate.com/v1/authorization/oauth", } // brokenAuthHeaderDomains lists broken providers that issue dynamic endpoints. var brokenAuthHeaderDomains = []string{ ".force.com", ".myshopify.com", ".okta.com", ".oktapreview.com", } func RegisterBrokenAuthHeaderProvider(tokenURL string) { brokenAuthHeaderProviders = append(brokenAuthHeaderProviders, tokenURL) } // providerAuthHeaderWorks reports whether the OAuth2 server identified by the tokenURL // implements the OAuth2 spec correctly // See https://code.google.com/p/goauth2/issues/detail?id=31 for background. // In summary: // - Reddit only accepts client secret in the Authorization header // - Dropbox accepts either it in URL param or Auth header, but not both. // - Google only accepts URL param (not spec compliant?), not Auth header // - Stripe only accepts client secret in Auth header with Bearer method, not Basic func providerAuthHeaderWorks(tokenURL string) bool { for _, s := range brokenAuthHeaderProviders { if strings.HasPrefix(tokenURL, s) { // Some sites fail to implement the OAuth2 spec fully. return false } } if u, err := url.Parse(tokenURL); err == nil { for _, s := range brokenAuthHeaderDomains { if strings.HasSuffix(u.Host, s) { return false } } } // Assume the provider implements the spec properly // otherwise. We can add more exceptions as they're // discovered. We will _not_ be adding configurable hooks // to this package to let users select server bugs. return true } func RetrieveToken(ctx context.Context, clientID, clientSecret, tokenURL string, v url.Values) (*Token, error) { hc, err := ContextClient(ctx) if err != nil { return nil, err } bustedAuth := !providerAuthHeaderWorks(tokenURL) if bustedAuth { if clientID != "" { v.Set("client_id", clientID) } if clientSecret != "" { v.Set("client_secret", clientSecret) } } req, err := http.NewRequest("POST", tokenURL, strings.NewReader(v.Encode())) if err != nil { return nil, err } req.Header.Set("Content-Type", "application/x-www-form-urlencoded") if !bustedAuth { req.SetBasicAuth(url.QueryEscape(clientID), url.QueryEscape(clientSecret)) } r, err := ctxhttp.Do(ctx, hc, req) if err != nil { return nil, err } defer r.Body.Close() body, err := ioutil.ReadAll(io.LimitReader(r.Body, 1<<20)) if err != nil { return nil, fmt.Errorf("oauth2: cannot fetch token: %v", err) } if code := r.StatusCode; code < 200 || code > 299 { return nil, &RetrieveError{ Response: r, Body: body, } } var token *Token content, _, _ := mime.ParseMediaType(r.Header.Get("Content-Type")) switch content { case "application/x-www-form-urlencoded", "text/plain": vals, err := url.ParseQuery(string(body)) if err != nil { return nil, err } token = &Token{ AccessToken: vals.Get("access_token"), TokenType: vals.Get("token_type"), RefreshToken: vals.Get("refresh_token"), Raw: vals, } e := vals.Get("expires_in") if e == "" { // TODO(jbd): Facebook's OAuth2 implementation is broken and // returns expires_in field in expires. Remove the fallback to expires, // when Facebook fixes their implementation. e = vals.Get("expires") } expires, _ := strconv.Atoi(e) if expires != 0 { token.Expiry = time.Now().Add(time.Duration(expires) * time.Second) } default: var tj tokenJSON if err = json.Unmarshal(body, &tj); err != nil { return nil, err } token = &Token{ AccessToken: tj.AccessToken, TokenType: tj.TokenType, RefreshToken: tj.RefreshToken, Expiry: tj.expiry(), Raw: make(map[string]interface{}), } json.Unmarshal(body, &token.Raw) // no error checks for optional fields } // Don't overwrite `RefreshToken` with an empty value // if this was a token refreshing request. if token.RefreshToken == "" { token.RefreshToken = v.Get("refresh_token") } return token, nil } type RetrieveError struct { Response *http.Response Body []byte } func (r *RetrieveError) Error() string { return fmt.Sprintf("oauth2: cannot fetch token: %v\nResponse: %s", r.Response.Status, r.Body) } ================================================ FILE: vendor/golang.org/x/oauth2/internal/token_test.go ================================================ // Copyright 2014 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 file. package internal import ( "fmt" "io" "net/http" "net/http/httptest" "net/url" "testing" "golang.org/x/net/context" ) func TestRegisterBrokenAuthHeaderProvider(t *testing.T) { RegisterBrokenAuthHeaderProvider("https://aaa.com/") tokenURL := "https://aaa.com/token" if providerAuthHeaderWorks(tokenURL) { t.Errorf("got %q as unbroken; want broken", tokenURL) } } func TestRetrieveTokenBustedNoSecret(t *testing.T) { const clientID = "client-id" ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if got, want := r.FormValue("client_id"), clientID; got != want { t.Errorf("client_id = %q; want %q", got, want) } if got, want := r.FormValue("client_secret"), ""; got != want { t.Errorf("client_secret = %q; want empty", got) } io.WriteString(w, "{}") // something non-empty, required to set a Content-Type in Go 1.10 })) defer ts.Close() RegisterBrokenAuthHeaderProvider(ts.URL) _, err := RetrieveToken(context.Background(), clientID, "", ts.URL, url.Values{}) if err != nil { t.Errorf("RetrieveToken = %v; want no error", err) } } func Test_providerAuthHeaderWorks(t *testing.T) { for _, p := range brokenAuthHeaderProviders { if providerAuthHeaderWorks(p) { t.Errorf("got %q as unbroken; want broken", p) } p := fmt.Sprintf("%ssomesuffix", p) if providerAuthHeaderWorks(p) { t.Errorf("got %q as unbroken; want broken", p) } } p := "https://api.not-in-the-list-example.com/" if !providerAuthHeaderWorks(p) { t.Errorf("got %q as unbroken; want broken", p) } } func TestProviderAuthHeaderWorksDomain(t *testing.T) { tests := []struct { tokenURL string wantWorks bool }{ {"https://dev-12345.okta.com/token-url", false}, {"https://dev-12345.oktapreview.com/token-url", false}, {"https://dev-12345.okta.org/token-url", true}, {"https://foo.bar.force.com/token-url", false}, {"https://foo.force.com/token-url", false}, {"https://force.com/token-url", true}, } for _, test := range tests { got := providerAuthHeaderWorks(test.tokenURL) if got != test.wantWorks { t.Errorf("providerAuthHeaderWorks(%q) = %v; want %v", test.tokenURL, got, test.wantWorks) } } } func TestRetrieveTokenWithContexts(t *testing.T) { const clientID = "client-id" ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { io.WriteString(w, "{}") // something non-empty, required to set a Content-Type in Go 1.10 })) defer ts.Close() _, err := RetrieveToken(context.Background(), clientID, "", ts.URL, url.Values{}) if err != nil { t.Errorf("RetrieveToken (with background context) = %v; want no error", err) } ctx, cancelfunc := context.WithCancel(context.Background()) cancellingts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { cancelfunc() })) defer cancellingts.Close() _, err = RetrieveToken(ctx, clientID, "", cancellingts.URL, url.Values{}) if err == nil { t.Errorf("RetrieveToken (with cancelled context) = nil; want error") } } ================================================ FILE: vendor/golang.org/x/oauth2/internal/transport.go ================================================ // Copyright 2014 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 file. package internal import ( "net/http" "golang.org/x/net/context" ) // HTTPClient is the context key to use with golang.org/x/net/context's // WithValue function to associate an *http.Client value with a context. var HTTPClient ContextKey // ContextKey is just an empty struct. It exists so HTTPClient can be // an immutable public variable with a unique type. It's immutable // because nobody else can create a ContextKey, being unexported. type ContextKey struct{} // ContextClientFunc is a func which tries to return an *http.Client // given a Context value. If it returns an error, the search stops // with that error. If it returns (nil, nil), the search continues // down the list of registered funcs. type ContextClientFunc func(context.Context) (*http.Client, error) var contextClientFuncs []ContextClientFunc func RegisterContextClientFunc(fn ContextClientFunc) { contextClientFuncs = append(contextClientFuncs, fn) } func ContextClient(ctx context.Context) (*http.Client, error) { if ctx != nil { if hc, ok := ctx.Value(HTTPClient).(*http.Client); ok { return hc, nil } } for _, fn := range contextClientFuncs { c, err := fn(ctx) if err != nil { return nil, err } if c != nil { return c, nil } } return http.DefaultClient, nil } func ContextTransport(ctx context.Context) http.RoundTripper { hc, err := ContextClient(ctx) // This is a rare error case (somebody using nil on App Engine). if err != nil { return ErrorTransport{err} } return hc.Transport } // ErrorTransport returns the specified error on RoundTrip. // This RoundTripper should be used in rare error cases where // error handling can be postponed to response handling time. type ErrorTransport struct{ Err error } func (t ErrorTransport) RoundTrip(*http.Request) (*http.Response, error) { return nil, t.Err } ================================================ FILE: vendor/golang.org/x/oauth2/internal/transport_test.go ================================================ // Copyright 2015 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 file. package internal import ( "net/http" "testing" "golang.org/x/net/context" ) func TestContextClient(t *testing.T) { rc := &http.Client{} RegisterContextClientFunc(func(context.Context) (*http.Client, error) { return rc, nil }) c := &http.Client{} ctx := context.WithValue(context.Background(), HTTPClient, c) hc, err := ContextClient(ctx) if err != nil { t.Fatalf("want valid client; got err = %v", err) } if hc != c { t.Fatalf("want context client = %p; got = %p", c, hc) } hc, err = ContextClient(context.TODO()) if err != nil { t.Fatalf("want valid client; got err = %v", err) } if hc != rc { t.Fatalf("want registered client = %p; got = %p", c, hc) } } ================================================ FILE: vendor/golang.org/x/oauth2/oauth2.go ================================================ // Copyright 2014 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 file. // Package oauth2 provides support for making // OAuth2 authorized and authenticated HTTP requests. // It can additionally grant authorization with Bearer JWT. package oauth2 // import "golang.org/x/oauth2" import ( "bytes" "errors" "net/http" "net/url" "strings" "sync" "golang.org/x/net/context" "golang.org/x/oauth2/internal" ) // NoContext is the default context you should supply if not using // your own context.Context (see https://golang.org/x/net/context). // // Deprecated: Use context.Background() or context.TODO() instead. var NoContext = context.TODO() // RegisterBrokenAuthHeaderProvider registers an OAuth2 server // identified by the tokenURL prefix as an OAuth2 implementation // which doesn't support the HTTP Basic authentication // scheme to authenticate with the authorization server. // Once a server is registered, credentials (client_id and client_secret) // will be passed as query parameters rather than being present // in the Authorization header. // See https://code.google.com/p/goauth2/issues/detail?id=31 for background. func RegisterBrokenAuthHeaderProvider(tokenURL string) { internal.RegisterBrokenAuthHeaderProvider(tokenURL) } // Config describes a typical 3-legged OAuth2 flow, with both the // client application information and the server's endpoint URLs. // For the client credentials 2-legged OAuth2 flow, see the clientcredentials // package (https://golang.org/x/oauth2/clientcredentials). type Config struct { // ClientID is the application's ID. ClientID string // ClientSecret is the application's secret. ClientSecret string // Endpoint contains the resource server's token endpoint // URLs. These are constants specific to each server and are // often available via site-specific packages, such as // google.Endpoint or github.Endpoint. Endpoint Endpoint // RedirectURL is the URL to redirect users going through // the OAuth flow, after the resource owner's URLs. RedirectURL string // Scope specifies optional requested permissions. Scopes []string } // A TokenSource is anything that can return a token. type TokenSource interface { // Token returns a token or an error. // Token must be safe for concurrent use by multiple goroutines. // The returned Token must not be modified. Token() (*Token, error) } // Endpoint contains the OAuth 2.0 provider's authorization and token // endpoint URLs. type Endpoint struct { AuthURL string TokenURL string } var ( // AccessTypeOnline and AccessTypeOffline are options passed // to the Options.AuthCodeURL method. They modify the // "access_type" field that gets sent in the URL returned by // AuthCodeURL. // // Online is the default if neither is specified. If your // application needs to refresh access tokens when the user // is not present at the browser, then use offline. This will // result in your application obtaining a refresh token the // first time your application exchanges an authorization // code for a user. AccessTypeOnline AuthCodeOption = SetAuthURLParam("access_type", "online") AccessTypeOffline AuthCodeOption = SetAuthURLParam("access_type", "offline") // ApprovalForce forces the users to view the consent dialog // and confirm the permissions request at the URL returned // from AuthCodeURL, even if they've already done so. ApprovalForce AuthCodeOption = SetAuthURLParam("approval_prompt", "force") ) // An AuthCodeOption is passed to Config.AuthCodeURL. type AuthCodeOption interface { setValue(url.Values) } type setParam struct{ k, v string } func (p setParam) setValue(m url.Values) { m.Set(p.k, p.v) } // SetAuthURLParam builds an AuthCodeOption which passes key/value parameters // to a provider's authorization endpoint. func SetAuthURLParam(key, value string) AuthCodeOption { return setParam{key, value} } // AuthCodeURL returns a URL to OAuth 2.0 provider's consent page // that asks for permissions for the required scopes explicitly. // // State is a token to protect the user from CSRF attacks. You must // always provide a non-zero string and validate that it matches the // the state query parameter on your redirect callback. // See http://tools.ietf.org/html/rfc6749#section-10.12 for more info. // // Opts may include AccessTypeOnline or AccessTypeOffline, as well // as ApprovalForce. func (c *Config) AuthCodeURL(state string, opts ...AuthCodeOption) string { var buf bytes.Buffer buf.WriteString(c.Endpoint.AuthURL) v := url.Values{ "response_type": {"code"}, "client_id": {c.ClientID}, "redirect_uri": internal.CondVal(c.RedirectURL), "scope": internal.CondVal(strings.Join(c.Scopes, " ")), "state": internal.CondVal(state), } for _, opt := range opts { opt.setValue(v) } if strings.Contains(c.Endpoint.AuthURL, "?") { buf.WriteByte('&') } else { buf.WriteByte('?') } buf.WriteString(v.Encode()) return buf.String() } // PasswordCredentialsToken converts a resource owner username and password // pair into a token. // // Per the RFC, this grant type should only be used "when there is a high // degree of trust between the resource owner and the client (e.g., the client // is part of the device operating system or a highly privileged application), // and when other authorization grant types are not available." // See https://tools.ietf.org/html/rfc6749#section-4.3 for more info. // // The HTTP client to use is derived from the context. // If nil, http.DefaultClient is used. func (c *Config) PasswordCredentialsToken(ctx context.Context, username, password string) (*Token, error) { return retrieveToken(ctx, c, url.Values{ "grant_type": {"password"}, "username": {username}, "password": {password}, "scope": internal.CondVal(strings.Join(c.Scopes, " ")), }) } // Exchange converts an authorization code into a token. // // It is used after a resource provider redirects the user back // to the Redirect URI (the URL obtained from AuthCodeURL). // // The HTTP client to use is derived from the context. // If a client is not provided via the context, http.DefaultClient is used. // // The code will be in the *http.Request.FormValue("code"). Before // calling Exchange, be sure to validate FormValue("state"). func (c *Config) Exchange(ctx context.Context, code string) (*Token, error) { return retrieveToken(ctx, c, url.Values{ "grant_type": {"authorization_code"}, "code": {code}, "redirect_uri": internal.CondVal(c.RedirectURL), }) } // Client returns an HTTP client using the provided token. // The token will auto-refresh as necessary. The underlying // HTTP transport will be obtained using the provided context. // The returned client and its Transport should not be modified. func (c *Config) Client(ctx context.Context, t *Token) *http.Client { return NewClient(ctx, c.TokenSource(ctx, t)) } // TokenSource returns a TokenSource that returns t until t expires, // automatically refreshing it as necessary using the provided context. // // Most users will use Config.Client instead. func (c *Config) TokenSource(ctx context.Context, t *Token) TokenSource { tkr := &tokenRefresher{ ctx: ctx, conf: c, } if t != nil { tkr.refreshToken = t.RefreshToken } return &reuseTokenSource{ t: t, new: tkr, } } // tokenRefresher is a TokenSource that makes "grant_type"=="refresh_token" // HTTP requests to renew a token using a RefreshToken. type tokenRefresher struct { ctx context.Context // used to get HTTP requests conf *Config refreshToken string } // WARNING: Token is not safe for concurrent access, as it // updates the tokenRefresher's refreshToken field. // Within this package, it is used by reuseTokenSource which // synchronizes calls to this method with its own mutex. func (tf *tokenRefresher) Token() (*Token, error) { if tf.refreshToken == "" { return nil, errors.New("oauth2: token expired and refresh token is not set") } tk, err := retrieveToken(tf.ctx, tf.conf, url.Values{ "grant_type": {"refresh_token"}, "refresh_token": {tf.refreshToken}, }) if err != nil { return nil, err } if tf.refreshToken != tk.RefreshToken { tf.refreshToken = tk.RefreshToken } return tk, err } // reuseTokenSource is a TokenSource that holds a single token in memory // and validates its expiry before each call to retrieve it with // Token. If it's expired, it will be auto-refreshed using the // new TokenSource. type reuseTokenSource struct { new TokenSource // called when t is expired. mu sync.Mutex // guards t t *Token } // Token returns the current token if it's still valid, else will // refresh the current token (using r.Context for HTTP client // information) and return the new one. func (s *reuseTokenSource) Token() (*Token, error) { s.mu.Lock() defer s.mu.Unlock() if s.t.Valid() { return s.t, nil } t, err := s.new.Token() if err != nil { return nil, err } s.t = t return t, nil } // StaticTokenSource returns a TokenSource that always returns the same token. // Because the provided token t is never refreshed, StaticTokenSource is only // useful for tokens that never expire. func StaticTokenSource(t *Token) TokenSource { return staticTokenSource{t} } // staticTokenSource is a TokenSource that always returns the same Token. type staticTokenSource struct { t *Token } func (s staticTokenSource) Token() (*Token, error) { return s.t, nil } // HTTPClient is the context key to use with golang.org/x/net/context's // WithValue function to associate an *http.Client value with a context. var HTTPClient internal.ContextKey // NewClient creates an *http.Client from a Context and TokenSource. // The returned client is not valid beyond the lifetime of the context. // // Note that if a custom *http.Client is provided via the Context it // is used only for token acquisition and is not used to configure the // *http.Client returned from NewClient. // // As a special case, if src is nil, a non-OAuth2 client is returned // using the provided context. This exists to support related OAuth2 // packages. func NewClient(ctx context.Context, src TokenSource) *http.Client { if src == nil { c, err := internal.ContextClient(ctx) if err != nil { return &http.Client{Transport: internal.ErrorTransport{Err: err}} } return c } return &http.Client{ Transport: &Transport{ Base: internal.ContextTransport(ctx), Source: ReuseTokenSource(nil, src), }, } } // ReuseTokenSource returns a TokenSource which repeatedly returns the // same token as long as it's valid, starting with t. // When its cached token is invalid, a new token is obtained from src. // // ReuseTokenSource is typically used to reuse tokens from a cache // (such as a file on disk) between runs of a program, rather than // obtaining new tokens unnecessarily. // // The initial token t may be nil, in which case the TokenSource is // wrapped in a caching version if it isn't one already. This also // means it's always safe to wrap ReuseTokenSource around any other // TokenSource without adverse effects. func ReuseTokenSource(t *Token, src TokenSource) TokenSource { // Don't wrap a reuseTokenSource in itself. That would work, // but cause an unnecessary number of mutex operations. // Just build the equivalent one. if rt, ok := src.(*reuseTokenSource); ok { if t == nil { // Just use it directly. return rt } src = rt.new } return &reuseTokenSource{ t: t, new: src, } } ================================================ FILE: vendor/golang.org/x/oauth2/oauth2_test.go ================================================ // Copyright 2014 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 file. package oauth2 import ( "errors" "fmt" "io/ioutil" "net/http" "net/http/httptest" "net/url" "testing" "time" "golang.org/x/net/context" ) type mockTransport struct { rt func(req *http.Request) (resp *http.Response, err error) } func (t *mockTransport) RoundTrip(req *http.Request) (resp *http.Response, err error) { return t.rt(req) } func newConf(url string) *Config { return &Config{ ClientID: "CLIENT_ID", ClientSecret: "CLIENT_SECRET", RedirectURL: "REDIRECT_URL", Scopes: []string{"scope1", "scope2"}, Endpoint: Endpoint{ AuthURL: url + "/auth", TokenURL: url + "/token", }, } } func TestAuthCodeURL(t *testing.T) { conf := newConf("server") url := conf.AuthCodeURL("foo", AccessTypeOffline, ApprovalForce) const want = "server/auth?access_type=offline&approval_prompt=force&client_id=CLIENT_ID&redirect_uri=REDIRECT_URL&response_type=code&scope=scope1+scope2&state=foo" if got := url; got != want { t.Errorf("got auth code URL = %q; want %q", got, want) } } func TestAuthCodeURL_CustomParam(t *testing.T) { conf := newConf("server") param := SetAuthURLParam("foo", "bar") url := conf.AuthCodeURL("baz", param) const want = "server/auth?client_id=CLIENT_ID&foo=bar&redirect_uri=REDIRECT_URL&response_type=code&scope=scope1+scope2&state=baz" if got := url; got != want { t.Errorf("got auth code = %q; want %q", got, want) } } func TestAuthCodeURL_Optional(t *testing.T) { conf := &Config{ ClientID: "CLIENT_ID", Endpoint: Endpoint{ AuthURL: "/auth-url", TokenURL: "/token-url", }, } url := conf.AuthCodeURL("") const want = "/auth-url?client_id=CLIENT_ID&response_type=code" if got := url; got != want { t.Fatalf("got auth code = %q; want %q", got, want) } } func TestURLUnsafeClientConfig(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if got, want := r.Header.Get("Authorization"), "Basic Q0xJRU5UX0lEJTNGJTNGOkNMSUVOVF9TRUNSRVQlM0YlM0Y="; got != want { t.Errorf("Authorization header = %q; want %q", got, want) } w.Header().Set("Content-Type", "application/x-www-form-urlencoded") w.Write([]byte("access_token=90d64460d14870c08c81352a05dedd3465940a7c&scope=user&token_type=bearer")) })) defer ts.Close() conf := newConf(ts.URL) conf.ClientID = "CLIENT_ID??" conf.ClientSecret = "CLIENT_SECRET??" _, err := conf.Exchange(context.Background(), "exchange-code") if err != nil { t.Error(err) } } func TestExchangeRequest(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.String() != "/token" { t.Errorf("Unexpected exchange request URL, %v is found.", r.URL) } headerAuth := r.Header.Get("Authorization") if headerAuth != "Basic Q0xJRU5UX0lEOkNMSUVOVF9TRUNSRVQ=" { t.Errorf("Unexpected authorization header, %v is found.", headerAuth) } headerContentType := r.Header.Get("Content-Type") if headerContentType != "application/x-www-form-urlencoded" { t.Errorf("Unexpected Content-Type header, %v is found.", headerContentType) } body, err := ioutil.ReadAll(r.Body) if err != nil { t.Errorf("Failed reading request body: %s.", err) } if string(body) != "code=exchange-code&grant_type=authorization_code&redirect_uri=REDIRECT_URL" { t.Errorf("Unexpected exchange payload, %v is found.", string(body)) } w.Header().Set("Content-Type", "application/x-www-form-urlencoded") w.Write([]byte("access_token=90d64460d14870c08c81352a05dedd3465940a7c&scope=user&token_type=bearer")) })) defer ts.Close() conf := newConf(ts.URL) tok, err := conf.Exchange(context.Background(), "exchange-code") if err != nil { t.Error(err) } if !tok.Valid() { t.Fatalf("Token invalid. Got: %#v", tok) } if tok.AccessToken != "90d64460d14870c08c81352a05dedd3465940a7c" { t.Errorf("Unexpected access token, %#v.", tok.AccessToken) } if tok.TokenType != "bearer" { t.Errorf("Unexpected token type, %#v.", tok.TokenType) } scope := tok.Extra("scope") if scope != "user" { t.Errorf("Unexpected value for scope: %v", scope) } } func TestExchangeRequest_JSONResponse(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.String() != "/token" { t.Errorf("Unexpected exchange request URL, %v is found.", r.URL) } headerAuth := r.Header.Get("Authorization") if headerAuth != "Basic Q0xJRU5UX0lEOkNMSUVOVF9TRUNSRVQ=" { t.Errorf("Unexpected authorization header, %v is found.", headerAuth) } headerContentType := r.Header.Get("Content-Type") if headerContentType != "application/x-www-form-urlencoded" { t.Errorf("Unexpected Content-Type header, %v is found.", headerContentType) } body, err := ioutil.ReadAll(r.Body) if err != nil { t.Errorf("Failed reading request body: %s.", err) } if string(body) != "code=exchange-code&grant_type=authorization_code&redirect_uri=REDIRECT_URL" { t.Errorf("Unexpected exchange payload, %v is found.", string(body)) } w.Header().Set("Content-Type", "application/json") w.Write([]byte(`{"access_token": "90d64460d14870c08c81352a05dedd3465940a7c", "scope": "user", "token_type": "bearer", "expires_in": 86400}`)) })) defer ts.Close() conf := newConf(ts.URL) tok, err := conf.Exchange(context.Background(), "exchange-code") if err != nil { t.Error(err) } if !tok.Valid() { t.Fatalf("Token invalid. Got: %#v", tok) } if tok.AccessToken != "90d64460d14870c08c81352a05dedd3465940a7c" { t.Errorf("Unexpected access token, %#v.", tok.AccessToken) } if tok.TokenType != "bearer" { t.Errorf("Unexpected token type, %#v.", tok.TokenType) } scope := tok.Extra("scope") if scope != "user" { t.Errorf("Unexpected value for scope: %v", scope) } expiresIn := tok.Extra("expires_in") if expiresIn != float64(86400) { t.Errorf("Unexpected non-numeric value for expires_in: %v", expiresIn) } } func TestExtraValueRetrieval(t *testing.T) { values := url.Values{} kvmap := map[string]string{ "scope": "user", "token_type": "bearer", "expires_in": "86400.92", "server_time": "1443571905.5606415", "referer_ip": "10.0.0.1", "etag": "\"afZYj912P4alikMz_P11982\"", "request_id": "86400", "untrimmed": " untrimmed ", } for key, value := range kvmap { values.Set(key, value) } tok := Token{raw: values} scope := tok.Extra("scope") if got, want := scope, "user"; got != want { t.Errorf("got scope = %q; want %q", got, want) } serverTime := tok.Extra("server_time") if got, want := serverTime, 1443571905.5606415; got != want { t.Errorf("got server_time value = %v; want %v", got, want) } refererIP := tok.Extra("referer_ip") if got, want := refererIP, "10.0.0.1"; got != want { t.Errorf("got referer_ip value = %v, want %v", got, want) } expiresIn := tok.Extra("expires_in") if got, want := expiresIn, 86400.92; got != want { t.Errorf("got expires_in value = %v, want %v", got, want) } requestID := tok.Extra("request_id") if got, want := requestID, int64(86400); got != want { t.Errorf("got request_id value = %v, want %v", got, want) } untrimmed := tok.Extra("untrimmed") if got, want := untrimmed, " untrimmed "; got != want { t.Errorf("got untrimmed = %q; want %q", got, want) } } const day = 24 * time.Hour func TestExchangeRequest_JSONResponse_Expiry(t *testing.T) { seconds := int32(day.Seconds()) for _, c := range []struct { expires string want bool }{ {fmt.Sprintf(`"expires_in": %d`, seconds), true}, {fmt.Sprintf(`"expires_in": "%d"`, seconds), true}, // PayPal case {fmt.Sprintf(`"expires": %d`, seconds), true}, // Facebook case {`"expires": false`, false}, // wrong type {`"expires": {}`, false}, // wrong type {`"expires": "zzz"`, false}, // wrong value } { testExchangeRequest_JSONResponse_expiry(t, c.expires, c.want) } } func testExchangeRequest_JSONResponse_expiry(t *testing.T, exp string, want bool) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.Write([]byte(fmt.Sprintf(`{"access_token": "90d", "scope": "user", "token_type": "bearer", %s}`, exp))) })) defer ts.Close() conf := newConf(ts.URL) t1 := time.Now().Add(day) tok, err := conf.Exchange(context.Background(), "exchange-code") t2 := time.Now().Add(day) if got := (err == nil); got != want { if want { t.Errorf("unexpected error: got %v", err) } else { t.Errorf("unexpected success") } } if !want { return } if !tok.Valid() { t.Fatalf("Token invalid. Got: %#v", tok) } expiry := tok.Expiry if expiry.Before(t1) || expiry.After(t2) { t.Errorf("Unexpected value for Expiry: %v (shold be between %v and %v)", expiry, t1, t2) } } func TestExchangeRequest_BadResponse(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.Write([]byte(`{"scope": "user", "token_type": "bearer"}`)) })) defer ts.Close() conf := newConf(ts.URL) tok, err := conf.Exchange(context.Background(), "code") if err != nil { t.Fatal(err) } if tok.AccessToken != "" { t.Errorf("Unexpected access token, %#v.", tok.AccessToken) } } func TestExchangeRequest_BadResponseType(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.Write([]byte(`{"access_token":123, "scope": "user", "token_type": "bearer"}`)) })) defer ts.Close() conf := newConf(ts.URL) _, err := conf.Exchange(context.Background(), "exchange-code") if err == nil { t.Error("expected error from invalid access_token type") } } func TestExchangeRequest_NonBasicAuth(t *testing.T) { tr := &mockTransport{ rt: func(r *http.Request) (w *http.Response, err error) { headerAuth := r.Header.Get("Authorization") if headerAuth != "" { t.Errorf("Unexpected authorization header, %v is found.", headerAuth) } return nil, errors.New("no response") }, } c := &http.Client{Transport: tr} conf := &Config{ ClientID: "CLIENT_ID", Endpoint: Endpoint{ AuthURL: "https://accounts.google.com/auth", TokenURL: "https://accounts.google.com/token", }, } ctx := context.WithValue(context.Background(), HTTPClient, c) conf.Exchange(ctx, "code") } func TestPasswordCredentialsTokenRequest(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defer r.Body.Close() expected := "/token" if r.URL.String() != expected { t.Errorf("URL = %q; want %q", r.URL, expected) } headerAuth := r.Header.Get("Authorization") expected = "Basic Q0xJRU5UX0lEOkNMSUVOVF9TRUNSRVQ=" if headerAuth != expected { t.Errorf("Authorization header = %q; want %q", headerAuth, expected) } headerContentType := r.Header.Get("Content-Type") expected = "application/x-www-form-urlencoded" if headerContentType != expected { t.Errorf("Content-Type header = %q; want %q", headerContentType, expected) } body, err := ioutil.ReadAll(r.Body) if err != nil { t.Errorf("Failed reading request body: %s.", err) } expected = "grant_type=password&password=password1&scope=scope1+scope2&username=user1" if string(body) != expected { t.Errorf("res.Body = %q; want %q", string(body), expected) } w.Header().Set("Content-Type", "application/x-www-form-urlencoded") w.Write([]byte("access_token=90d64460d14870c08c81352a05dedd3465940a7c&scope=user&token_type=bearer")) })) defer ts.Close() conf := newConf(ts.URL) tok, err := conf.PasswordCredentialsToken(context.Background(), "user1", "password1") if err != nil { t.Error(err) } if !tok.Valid() { t.Fatalf("Token invalid. Got: %#v", tok) } expected := "90d64460d14870c08c81352a05dedd3465940a7c" if tok.AccessToken != expected { t.Errorf("AccessToken = %q; want %q", tok.AccessToken, expected) } expected = "bearer" if tok.TokenType != expected { t.Errorf("TokenType = %q; want %q", tok.TokenType, expected) } } func TestTokenRefreshRequest(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.String() == "/somethingelse" { return } if r.URL.String() != "/token" { t.Errorf("Unexpected token refresh request URL, %v is found.", r.URL) } headerContentType := r.Header.Get("Content-Type") if headerContentType != "application/x-www-form-urlencoded" { t.Errorf("Unexpected Content-Type header, %v is found.", headerContentType) } body, _ := ioutil.ReadAll(r.Body) if string(body) != "grant_type=refresh_token&refresh_token=REFRESH_TOKEN" { t.Errorf("Unexpected refresh token payload, %v is found.", string(body)) } })) defer ts.Close() conf := newConf(ts.URL) c := conf.Client(context.Background(), &Token{RefreshToken: "REFRESH_TOKEN"}) c.Get(ts.URL + "/somethingelse") } func TestFetchWithNoRefreshToken(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.String() == "/somethingelse" { return } if r.URL.String() != "/token" { t.Errorf("Unexpected token refresh request URL, %v is found.", r.URL) } headerContentType := r.Header.Get("Content-Type") if headerContentType != "application/x-www-form-urlencoded" { t.Errorf("Unexpected Content-Type header, %v is found.", headerContentType) } body, _ := ioutil.ReadAll(r.Body) if string(body) != "client_id=CLIENT_ID&grant_type=refresh_token&refresh_token=REFRESH_TOKEN" { t.Errorf("Unexpected refresh token payload, %v is found.", string(body)) } })) defer ts.Close() conf := newConf(ts.URL) c := conf.Client(context.Background(), nil) _, err := c.Get(ts.URL + "/somethingelse") if err == nil { t.Errorf("Fetch should return an error if no refresh token is set") } } func TestTokenRetrieveError(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.String() != "/token" { t.Errorf("Unexpected token refresh request URL, %v is found.", r.URL) } w.Header().Set("Content-type", "application/json") w.WriteHeader(http.StatusBadRequest) w.Write([]byte(`{"error": "invalid_grant"}`)) })) defer ts.Close() conf := newConf(ts.URL) _, err := conf.Exchange(context.Background(), "exchange-code") if err == nil { t.Fatalf("got no error, expected one") } _, ok := err.(*RetrieveError) if !ok { t.Fatalf("got %T error, expected *RetrieveError", err) } // Test error string for backwards compatibility expected := fmt.Sprintf("oauth2: cannot fetch token: %v\nResponse: %s", "400 Bad Request", `{"error": "invalid_grant"}`) if errStr := err.Error(); errStr != expected { t.Fatalf("got %#v, expected %#v", errStr, expected) } } func TestRefreshToken_RefreshTokenReplacement(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.Write([]byte(`{"access_token":"ACCESS_TOKEN", "scope": "user", "token_type": "bearer", "refresh_token": "NEW_REFRESH_TOKEN"}`)) return })) defer ts.Close() conf := newConf(ts.URL) tkr := &tokenRefresher{ conf: conf, ctx: context.Background(), refreshToken: "OLD_REFRESH_TOKEN", } tk, err := tkr.Token() if err != nil { t.Errorf("got err = %v; want none", err) return } if tk.RefreshToken != tkr.refreshToken { t.Errorf("tokenRefresher.refresh_token = %q; want %q", tkr.refreshToken, tk.RefreshToken) } } func TestRefreshToken_RefreshTokenPreservation(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.Write([]byte(`{"access_token":"ACCESS_TOKEN", "scope": "user", "token_type": "bearer"}`)) return })) defer ts.Close() conf := newConf(ts.URL) const oldRefreshToken = "OLD_REFRESH_TOKEN" tkr := &tokenRefresher{ conf: conf, ctx: context.Background(), refreshToken: oldRefreshToken, } _, err := tkr.Token() if err != nil { t.Fatalf("got err = %v; want none", err) } if tkr.refreshToken != oldRefreshToken { t.Errorf("tokenRefresher.refreshToken = %q; want %q", tkr.refreshToken, oldRefreshToken) } } func TestConfigClientWithToken(t *testing.T) { tok := &Token{ AccessToken: "abc123", } ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if got, want := r.Header.Get("Authorization"), fmt.Sprintf("Bearer %s", tok.AccessToken); got != want { t.Errorf("Authorization header = %q; want %q", got, want) } return })) defer ts.Close() conf := newConf(ts.URL) c := conf.Client(context.Background(), tok) req, err := http.NewRequest("GET", ts.URL, nil) if err != nil { t.Error(err) } _, err = c.Do(req) if err != nil { t.Error(err) } } ================================================ FILE: vendor/golang.org/x/oauth2/token.go ================================================ // Copyright 2014 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 file. package oauth2 import ( "fmt" "net/http" "net/url" "strconv" "strings" "time" "golang.org/x/net/context" "golang.org/x/oauth2/internal" ) // expiryDelta determines how earlier a token should be considered // expired than its actual expiration time. It is used to avoid late // expirations due to client-server time mismatches. const expiryDelta = 10 * time.Second // Token represents the credentials used to authorize // the requests to access protected resources on the OAuth 2.0 // provider's backend. // // Most users of this package should not access fields of Token // directly. They're exported mostly for use by related packages // implementing derivative OAuth2 flows. type Token struct { // AccessToken is the token that authorizes and authenticates // the requests. AccessToken string `json:"access_token"` // TokenType is the type of token. // The Type method returns either this or "Bearer", the default. TokenType string `json:"token_type,omitempty"` // RefreshToken is a token that's used by the application // (as opposed to the user) to refresh the access token // if it expires. RefreshToken string `json:"refresh_token,omitempty"` // Expiry is the optional expiration time of the access token. // // If zero, TokenSource implementations will reuse the same // token forever and RefreshToken or equivalent // mechanisms for that TokenSource will not be used. Expiry time.Time `json:"expiry,omitempty"` // raw optionally contains extra metadata from the server // when updating a token. raw interface{} } // Type returns t.TokenType if non-empty, else "Bearer". func (t *Token) Type() string { if strings.EqualFold(t.TokenType, "bearer") { return "Bearer" } if strings.EqualFold(t.TokenType, "mac") { return "MAC" } if strings.EqualFold(t.TokenType, "basic") { return "Basic" } if t.TokenType != "" { return t.TokenType } return "Bearer" } // SetAuthHeader sets the Authorization header to r using the access // token in t. // // This method is unnecessary when using Transport or an HTTP Client // returned by this package. func (t *Token) SetAuthHeader(r *http.Request) { r.Header.Set("Authorization", t.Type()+" "+t.AccessToken) } // WithExtra returns a new Token that's a clone of t, but using the // provided raw extra map. This is only intended for use by packages // implementing derivative OAuth2 flows. func (t *Token) WithExtra(extra interface{}) *Token { t2 := new(Token) *t2 = *t t2.raw = extra return t2 } // Extra returns an extra field. // Extra fields are key-value pairs returned by the server as a // part of the token retrieval response. func (t *Token) Extra(key string) interface{} { if raw, ok := t.raw.(map[string]interface{}); ok { return raw[key] } vals, ok := t.raw.(url.Values) if !ok { return nil } v := vals.Get(key) switch s := strings.TrimSpace(v); strings.Count(s, ".") { case 0: // Contains no "."; try to parse as int if i, err := strconv.ParseInt(s, 10, 64); err == nil { return i } case 1: // Contains a single "."; try to parse as float if f, err := strconv.ParseFloat(s, 64); err == nil { return f } } return v } // expired reports whether the token is expired. // t must be non-nil. func (t *Token) expired() bool { if t.Expiry.IsZero() { return false } return t.Expiry.Round(0).Add(-expiryDelta).Before(time.Now()) } // Valid reports whether t is non-nil, has an AccessToken, and is not expired. func (t *Token) Valid() bool { return t != nil && t.AccessToken != "" && !t.expired() } // tokenFromInternal maps an *internal.Token struct into // a *Token struct. func tokenFromInternal(t *internal.Token) *Token { if t == nil { return nil } return &Token{ AccessToken: t.AccessToken, TokenType: t.TokenType, RefreshToken: t.RefreshToken, Expiry: t.Expiry, raw: t.Raw, } } // retrieveToken takes a *Config and uses that to retrieve an *internal.Token. // This token is then mapped from *internal.Token into an *oauth2.Token which is returned along // with an error.. func retrieveToken(ctx context.Context, c *Config, v url.Values) (*Token, error) { tk, err := internal.RetrieveToken(ctx, c.ClientID, c.ClientSecret, c.Endpoint.TokenURL, v) if err != nil { if rErr, ok := err.(*internal.RetrieveError); ok { return nil, (*RetrieveError)(rErr) } return nil, err } return tokenFromInternal(tk), nil } // RetrieveError is the error returned when the token endpoint returns a // non-2XX HTTP status code. type RetrieveError struct { Response *http.Response // Body is the body that was consumed by reading Response.Body. // It may be truncated. Body []byte } func (r *RetrieveError) Error() string { return fmt.Sprintf("oauth2: cannot fetch token: %v\nResponse: %s", r.Response.Status, r.Body) } ================================================ FILE: vendor/golang.org/x/oauth2/token_test.go ================================================ // Copyright 2014 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 file. package oauth2 import ( "testing" "time" ) func TestTokenExtra(t *testing.T) { type testCase struct { key string val interface{} want interface{} } const key = "extra-key" cases := []testCase{ {key: key, val: "abc", want: "abc"}, {key: key, val: 123, want: 123}, {key: key, val: "", want: ""}, {key: "other-key", val: "def", want: nil}, } for _, tc := range cases { extra := make(map[string]interface{}) extra[tc.key] = tc.val tok := &Token{raw: extra} if got, want := tok.Extra(key), tc.want; got != want { t.Errorf("Extra(%q) = %q; want %q", key, got, want) } } } func TestTokenExpiry(t *testing.T) { now := time.Now() cases := []struct { name string tok *Token want bool }{ {name: "12 seconds", tok: &Token{Expiry: now.Add(12 * time.Second)}, want: false}, {name: "10 seconds", tok: &Token{Expiry: now.Add(expiryDelta)}, want: true}, {name: "-1 hour", tok: &Token{Expiry: now.Add(-1 * time.Hour)}, want: true}, } for _, tc := range cases { if got, want := tc.tok.expired(), tc.want; got != want { t.Errorf("expired (%q) = %v; want %v", tc.name, got, want) } } } func TestTokenTypeMethod(t *testing.T) { cases := []struct { name string tok *Token want string }{ {name: "bearer-mixed_case", tok: &Token{TokenType: "beAREr"}, want: "Bearer"}, {name: "default-bearer", tok: &Token{}, want: "Bearer"}, {name: "basic", tok: &Token{TokenType: "basic"}, want: "Basic"}, {name: "basic-capitalized", tok: &Token{TokenType: "Basic"}, want: "Basic"}, {name: "mac", tok: &Token{TokenType: "mac"}, want: "MAC"}, {name: "mac-caps", tok: &Token{TokenType: "MAC"}, want: "MAC"}, {name: "mac-mixed_case", tok: &Token{TokenType: "mAc"}, want: "MAC"}, } for _, tc := range cases { if got, want := tc.tok.Type(), tc.want; got != want { t.Errorf("TokenType(%q) = %v; want %v", tc.name, got, want) } } } ================================================ FILE: vendor/golang.org/x/oauth2/transport.go ================================================ // Copyright 2014 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 file. package oauth2 import ( "errors" "io" "net/http" "sync" ) // Transport is an http.RoundTripper that makes OAuth 2.0 HTTP requests, // wrapping a base RoundTripper and adding an Authorization header // with a token from the supplied Sources. // // Transport is a low-level mechanism. Most code will use the // higher-level Config.Client method instead. type Transport struct { // Source supplies the token to add to outgoing requests' // Authorization headers. Source TokenSource // Base is the base RoundTripper used to make HTTP requests. // If nil, http.DefaultTransport is used. Base http.RoundTripper mu sync.Mutex // guards modReq modReq map[*http.Request]*http.Request // original -> modified } // RoundTrip authorizes and authenticates the request with an // access token. If no token exists or token is expired, // tries to refresh/fetch a new token. func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) { if t.Source == nil { return nil, errors.New("oauth2: Transport's Source is nil") } token, err := t.Source.Token() if err != nil { return nil, err } req2 := cloneRequest(req) // per RoundTripper contract token.SetAuthHeader(req2) t.setModReq(req, req2) res, err := t.base().RoundTrip(req2) if err != nil { t.setModReq(req, nil) return nil, err } res.Body = &onEOFReader{ rc: res.Body, fn: func() { t.setModReq(req, nil) }, } return res, nil } // CancelRequest cancels an in-flight request by closing its connection. func (t *Transport) CancelRequest(req *http.Request) { type canceler interface { CancelRequest(*http.Request) } if cr, ok := t.base().(canceler); ok { t.mu.Lock() modReq := t.modReq[req] delete(t.modReq, req) t.mu.Unlock() cr.CancelRequest(modReq) } } func (t *Transport) base() http.RoundTripper { if t.Base != nil { return t.Base } return http.DefaultTransport } func (t *Transport) setModReq(orig, mod *http.Request) { t.mu.Lock() defer t.mu.Unlock() if t.modReq == nil { t.modReq = make(map[*http.Request]*http.Request) } if mod == nil { delete(t.modReq, orig) } else { t.modReq[orig] = mod } } // cloneRequest returns a clone of the provided *http.Request. // The clone is a shallow copy of the struct and its Header map. func cloneRequest(r *http.Request) *http.Request { // shallow copy of the struct r2 := new(http.Request) *r2 = *r // deep copy of the Header r2.Header = make(http.Header, len(r.Header)) for k, s := range r.Header { r2.Header[k] = append([]string(nil), s...) } return r2 } type onEOFReader struct { rc io.ReadCloser fn func() } func (r *onEOFReader) Read(p []byte) (n int, err error) { n, err = r.rc.Read(p) if err == io.EOF { r.runFunc() } return } func (r *onEOFReader) Close() error { err := r.rc.Close() r.runFunc() return err } func (r *onEOFReader) runFunc() { if fn := r.fn; fn != nil { fn() r.fn = nil } } ================================================ FILE: vendor/golang.org/x/oauth2/transport_test.go ================================================ package oauth2 import ( "net/http" "net/http/httptest" "testing" "time" ) type tokenSource struct{ token *Token } func (t *tokenSource) Token() (*Token, error) { return t.token, nil } func TestTransportNilTokenSource(t *testing.T) { tr := &Transport{} server := newMockServer(func(w http.ResponseWriter, r *http.Request) {}) defer server.Close() client := &http.Client{Transport: tr} resp, err := client.Get(server.URL) if err == nil { t.Errorf("got no errors, want an error with nil token source") } if resp != nil { t.Errorf("Response = %v; want nil", resp) } } func TestTransportTokenSource(t *testing.T) { ts := &tokenSource{ token: &Token{ AccessToken: "abc", }, } tr := &Transport{ Source: ts, } server := newMockServer(func(w http.ResponseWriter, r *http.Request) { if got, want := r.Header.Get("Authorization"), "Bearer abc"; got != want { t.Errorf("Authorization header = %q; want %q", got, want) } }) defer server.Close() client := &http.Client{Transport: tr} res, err := client.Get(server.URL) if err != nil { t.Fatal(err) } res.Body.Close() } // Test for case-sensitive token types, per https://github.com/golang/oauth2/issues/113 func TestTransportTokenSourceTypes(t *testing.T) { const val = "abc" tests := []struct { key string val string want string }{ {key: "bearer", val: val, want: "Bearer abc"}, {key: "mac", val: val, want: "MAC abc"}, {key: "basic", val: val, want: "Basic abc"}, } for _, tc := range tests { ts := &tokenSource{ token: &Token{ AccessToken: tc.val, TokenType: tc.key, }, } tr := &Transport{ Source: ts, } server := newMockServer(func(w http.ResponseWriter, r *http.Request) { if got, want := r.Header.Get("Authorization"), tc.want; got != want { t.Errorf("Authorization header (%q) = %q; want %q", val, got, want) } }) defer server.Close() client := &http.Client{Transport: tr} res, err := client.Get(server.URL) if err != nil { t.Fatal(err) } res.Body.Close() } } func TestTokenValidNoAccessToken(t *testing.T) { token := &Token{} if token.Valid() { t.Errorf("got valid with no access token; want invalid") } } func TestExpiredWithExpiry(t *testing.T) { token := &Token{ Expiry: time.Now().Add(-5 * time.Hour), } if token.Valid() { t.Errorf("got valid with expired token; want invalid") } } func newMockServer(handler func(w http.ResponseWriter, r *http.Request)) *httptest.Server { return httptest.NewServer(http.HandlerFunc(handler)) } ================================================ FILE: vendor/google.golang.org/appengine/.travis.yml ================================================ language: go go: - 1.6.3 - 1.7.1 install: - go get -v -t -d google.golang.org/appengine/... - mkdir sdk - curl -o sdk.zip "https://storage.googleapis.com/appengine-sdks/featured/go_appengine_sdk_linux_amd64-1.9.40.zip" - unzip -q sdk.zip -d sdk - export APPENGINE_DEV_APPSERVER=$(pwd)/sdk/go_appengine/dev_appserver.py script: - go version - go test -v google.golang.org/appengine/... - go test -v -race google.golang.org/appengine/... - sdk/go_appengine/goapp test -v google.golang.org/appengine/... ================================================ FILE: vendor/google.golang.org/appengine/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: vendor/google.golang.org/appengine/README.md ================================================ # Go App Engine packages [![Build Status](https://travis-ci.org/golang/appengine.svg)](https://travis-ci.org/golang/appengine) This repository supports the Go runtime on App Engine, including both the standard App Engine and the "App Engine flexible environment" (formerly known as "Managed VMs"). It provides APIs for interacting with App Engine services. Its canonical import path is `google.golang.org/appengine`. See https://cloud.google.com/appengine/docs/go/ for more information. File issue reports and feature requests on the [Google App Engine issue tracker](https://code.google.com/p/googleappengine/issues/entry?template=Go%20defect). ## Directory structure The top level directory of this repository is the `appengine` package. It contains the basic APIs (e.g. `appengine.NewContext`) that apply across APIs. Specific API packages are in subdirectories (e.g. `datastore`). There is an `internal` subdirectory that contains service protocol buffers, plus packages required for connectivity to make API calls. App Engine apps should not directly import any package under `internal`. ## Updating a Go App Engine app This section describes how to update an older Go App Engine app to use these packages. A provided tool, `aefix`, can help automate steps 2 and 3 (run `go get google.golang.org/appengine/cmd/aefix` to install it), but read the details below since `aefix` can't perform all the changes. ### 1. Update YAML files (App Engine flexible environment / Managed VMs only) The `app.yaml` file (and YAML files for modules) should have these new lines added: ``` vm: true ``` See https://cloud.google.com/appengine/docs/go/modules/#Go_Instance_scaling_and_class for details. ### 2. Update import paths The import paths for App Engine packages are now fully qualified, based at `google.golang.org/appengine`. You will need to update your code to use import paths starting with that; for instance, code importing `appengine/datastore` will now need to import `google.golang.org/appengine/datastore`. ### 3. Update code using deprecated, removed or modified APIs Most App Engine services are available with exactly the same API. A few APIs were cleaned up, and some are not available yet. This list summarises the differences: * `appengine.Context` has been replaced with the `Context` type from `golang.org/x/net/context`. * Logging methods that were on `appengine.Context` are now functions in `google.golang.org/appengine/log`. * `appengine.Timeout` has been removed. Use `context.WithTimeout` instead. * `appengine.Datacenter` now takes a `context.Context` argument. * `datastore.PropertyLoadSaver` has been simplified to use slices in place of channels. * `delay.Call` now returns an error. * `search.FieldLoadSaver` now handles document metadata. * `urlfetch.Transport` no longer has a Deadline field; set a deadline on the `context.Context` instead. * `aetest` no longer declares its own Context type, and uses the standard one instead. * `taskqueue.QueueStats` no longer takes a maxTasks argument. That argument has been deprecated and unused for a long time. * `appengine.BackendHostname` and `appengine.BackendInstance` were for the deprecated backends feature. Use `appengine.ModuleHostname`and `appengine.ModuleName` instead. * Most of `appengine/file` and parts of `appengine/blobstore` are deprecated. Use [Google Cloud Storage](https://godoc.org/cloud.google.com/go/storage) if the feature you require is not present in the new [blobstore package](https://google.golang.org/appengine/blobstore). * `appengine/socket` is not required on App Engine flexible environment / Managed VMs. Use the standard `net` package instead. ================================================ FILE: vendor/google.golang.org/appengine/appengine.go ================================================ // Copyright 2011 Google Inc. All rights reserved. // Use of this source code is governed by the Apache 2.0 // license that can be found in the LICENSE file. // Package appengine provides basic functionality for Google App Engine. // // For more information on how to write Go apps for Google App Engine, see: // https://cloud.google.com/appengine/docs/go/ package appengine // import "google.golang.org/appengine" import ( "net/http" "github.com/golang/protobuf/proto" "golang.org/x/net/context" "google.golang.org/appengine/internal" ) // The gophers party all night; the rabbits provide the beats. // Main is the principal entry point for an app running in App Engine. // // On App Engine Flexible it installs a trivial health checker if one isn't // already registered, and starts listening on port 8080 (overridden by the // $PORT environment variable). // // See https://cloud.google.com/appengine/docs/flexible/custom-runtimes#health_check_requests // for details on how to do your own health checking. // // Main is not yet supported on App Engine Standard. // // Main never returns. // // Main is designed so that the app's main package looks like this: // // package main // // import ( // "google.golang.org/appengine" // // _ "myapp/package0" // _ "myapp/package1" // ) // // func main() { // appengine.Main() // } // // The "myapp/packageX" packages are expected to register HTTP handlers // in their init functions. func Main() { internal.Main() } // IsDevAppServer reports whether the App Engine app is running in the // development App Server. func IsDevAppServer() bool { return internal.IsDevAppServer() } // NewContext returns a context for an in-flight HTTP request. // This function is cheap. func NewContext(req *http.Request) context.Context { return WithContext(context.Background(), req) } // WithContext returns a copy of the parent context // and associates it with an in-flight HTTP request. // This function is cheap. func WithContext(parent context.Context, req *http.Request) context.Context { return internal.WithContext(parent, req) } // TODO(dsymonds): Add a Call function here? Otherwise other packages can't access internal.Call. // BlobKey is a key for a blobstore blob. // // Conceptually, this type belongs in the blobstore package, but it lives in // the appengine package to avoid a circular dependency: blobstore depends on // datastore, and datastore needs to refer to the BlobKey type. type BlobKey string // GeoPoint represents a location as latitude/longitude in degrees. type GeoPoint struct { Lat, Lng float64 } // Valid returns whether a GeoPoint is within [-90, 90] latitude and [-180, 180] longitude. func (g GeoPoint) Valid() bool { return -90 <= g.Lat && g.Lat <= 90 && -180 <= g.Lng && g.Lng <= 180 } // APICallFunc defines a function type for handling an API call. // See WithCallOverride. type APICallFunc func(ctx context.Context, service, method string, in, out proto.Message) error // WithAPICallFunc returns a copy of the parent context // that will cause API calls to invoke f instead of their normal operation. // // This is intended for advanced users only. func WithAPICallFunc(ctx context.Context, f APICallFunc) context.Context { return internal.WithCallOverride(ctx, internal.CallOverrideFunc(f)) } // APICall performs an API call. // // This is not intended for general use; it is exported for use in conjunction // with WithAPICallFunc. func APICall(ctx context.Context, service, method string, in, out proto.Message) error { return internal.Call(ctx, service, method, in, out) } ================================================ FILE: vendor/google.golang.org/appengine/appengine_test.go ================================================ // Copyright 2014 Google Inc. All rights reserved. // Use of this source code is governed by the Apache 2.0 // license that can be found in the LICENSE file. package appengine import ( "testing" ) func TestValidGeoPoint(t *testing.T) { testCases := []struct { desc string pt GeoPoint want bool }{ { "valid", GeoPoint{67.21, 13.37}, true, }, { "high lat", GeoPoint{-90.01, 13.37}, false, }, { "low lat", GeoPoint{90.01, 13.37}, false, }, { "high lng", GeoPoint{67.21, 182}, false, }, { "low lng", GeoPoint{67.21, -181}, false, }, } for _, tc := range testCases { if got := tc.pt.Valid(); got != tc.want { t.Errorf("%s: got %v, want %v", tc.desc, got, tc.want) } } } ================================================ FILE: vendor/google.golang.org/appengine/appengine_vm.go ================================================ // Copyright 2015 Google Inc. All rights reserved. // Use of this source code is governed by the Apache 2.0 // license that can be found in the LICENSE file. // +build !appengine package appengine import ( "golang.org/x/net/context" "google.golang.org/appengine/internal" ) // BackgroundContext returns a context not associated with a request. // This should only be used when not servicing a request. // This only works in App Engine "flexible environment". func BackgroundContext() context.Context { return internal.BackgroundContext() } ================================================ FILE: vendor/google.golang.org/appengine/errors.go ================================================ // Copyright 2011 Google Inc. All rights reserved. // Use of this source code is governed by the Apache 2.0 // license that can be found in the LICENSE file. // This file provides error functions for common API failure modes. package appengine import ( "fmt" "google.golang.org/appengine/internal" ) // IsOverQuota reports whether err represents an API call failure // due to insufficient available quota. func IsOverQuota(err error) bool { callErr, ok := err.(*internal.CallError) return ok && callErr.Code == 4 } // MultiError is returned by batch operations when there are errors with // particular elements. Errors will be in a one-to-one correspondence with // the input elements; successful elements will have a nil entry. type MultiError []error func (m MultiError) Error() string { s, n := "", 0 for _, e := range m { if e != nil { if n == 0 { s = e.Error() } n++ } } switch n { case 0: return "(0 errors)" case 1: return s case 2: return s + " (and 1 other error)" } return fmt.Sprintf("%s (and %d other errors)", s, n-1) } ================================================ FILE: vendor/google.golang.org/appengine/identity.go ================================================ // Copyright 2011 Google Inc. All rights reserved. // Use of this source code is governed by the Apache 2.0 // license that can be found in the LICENSE file. package appengine import ( "time" "golang.org/x/net/context" "google.golang.org/appengine/internal" pb "google.golang.org/appengine/internal/app_identity" modpb "google.golang.org/appengine/internal/modules" ) // AppID returns the application ID for the current application. // The string will be a plain application ID (e.g. "appid"), with a // domain prefix for custom domain deployments (e.g. "example.com:appid"). func AppID(c context.Context) string { return internal.AppID(c) } // DefaultVersionHostname returns the standard hostname of the default version // of the current application (e.g. "my-app.appspot.com"). This is suitable for // use in constructing URLs. func DefaultVersionHostname(c context.Context) string { return internal.DefaultVersionHostname(c) } // ModuleName returns the module name of the current instance. func ModuleName(c context.Context) string { return internal.ModuleName(c) } // ModuleHostname returns a hostname of a module instance. // If module is the empty string, it refers to the module of the current instance. // If version is empty, it refers to the version of the current instance if valid, // or the default version of the module of the current instance. // If instance is empty, ModuleHostname returns the load-balancing hostname. func ModuleHostname(c context.Context, module, version, instance string) (string, error) { req := &modpb.GetHostnameRequest{} if module != "" { req.Module = &module } if version != "" { req.Version = &version } if instance != "" { req.Instance = &instance } res := &modpb.GetHostnameResponse{} if err := internal.Call(c, "modules", "GetHostname", req, res); err != nil { return "", err } return *res.Hostname, nil } // VersionID returns the version ID for the current application. // It will be of the form "X.Y", where X is specified in app.yaml, // and Y is a number generated when each version of the app is uploaded. // It does not include a module name. func VersionID(c context.Context) string { return internal.VersionID(c) } // InstanceID returns a mostly-unique identifier for this instance. func InstanceID() string { return internal.InstanceID() } // Datacenter returns an identifier for the datacenter that the instance is running in. func Datacenter(c context.Context) string { return internal.Datacenter(c) } // ServerSoftware returns the App Engine release version. // In production, it looks like "Google App Engine/X.Y.Z". // In the development appserver, it looks like "Development/X.Y". func ServerSoftware() string { return internal.ServerSoftware() } // RequestID returns a string that uniquely identifies the request. func RequestID(c context.Context) string { return internal.RequestID(c) } // AccessToken generates an OAuth2 access token for the specified scopes on // behalf of service account of this application. This token will expire after // the returned time. func AccessToken(c context.Context, scopes ...string) (token string, expiry time.Time, err error) { req := &pb.GetAccessTokenRequest{Scope: scopes} res := &pb.GetAccessTokenResponse{} err = internal.Call(c, "app_identity_service", "GetAccessToken", req, res) if err != nil { return "", time.Time{}, err } return res.GetAccessToken(), time.Unix(res.GetExpirationTime(), 0), nil } // Certificate represents a public certificate for the app. type Certificate struct { KeyName string Data []byte // PEM-encoded X.509 certificate } // PublicCertificates retrieves the public certificates for the app. // They can be used to verify a signature returned by SignBytes. func PublicCertificates(c context.Context) ([]Certificate, error) { req := &pb.GetPublicCertificateForAppRequest{} res := &pb.GetPublicCertificateForAppResponse{} if err := internal.Call(c, "app_identity_service", "GetPublicCertificatesForApp", req, res); err != nil { return nil, err } var cs []Certificate for _, pc := range res.PublicCertificateList { cs = append(cs, Certificate{ KeyName: pc.GetKeyName(), Data: []byte(pc.GetX509CertificatePem()), }) } return cs, nil } // ServiceAccount returns a string representing the service account name, in // the form of an email address (typically app_id@appspot.gserviceaccount.com). func ServiceAccount(c context.Context) (string, error) { req := &pb.GetServiceAccountNameRequest{} res := &pb.GetServiceAccountNameResponse{} err := internal.Call(c, "app_identity_service", "GetServiceAccountName", req, res) if err != nil { return "", err } return res.GetServiceAccountName(), err } // SignBytes signs bytes using a private key unique to your application. func SignBytes(c context.Context, bytes []byte) (keyName string, signature []byte, err error) { req := &pb.SignForAppRequest{BytesToSign: bytes} res := &pb.SignForAppResponse{} if err := internal.Call(c, "app_identity_service", "SignForApp", req, res); err != nil { return "", nil, err } return res.GetKeyName(), res.GetSignatureBytes(), nil } func init() { internal.RegisterErrorCodeMap("app_identity_service", pb.AppIdentityServiceError_ErrorCode_name) internal.RegisterErrorCodeMap("modules", modpb.ModulesServiceError_ErrorCode_name) } ================================================ FILE: vendor/google.golang.org/appengine/internal/api.go ================================================ // Copyright 2011 Google Inc. All rights reserved. // Use of this source code is governed by the Apache 2.0 // license that can be found in the LICENSE file. // +build !appengine package internal import ( "bytes" "errors" "fmt" "io/ioutil" "log" "net" "net/http" "net/url" "os" "runtime" "strconv" "strings" "sync" "sync/atomic" "time" "github.com/golang/protobuf/proto" netcontext "golang.org/x/net/context" basepb "google.golang.org/appengine/internal/base" logpb "google.golang.org/appengine/internal/log" remotepb "google.golang.org/appengine/internal/remote_api" ) const ( apiPath = "/rpc_http" ) var ( // Incoming headers. ticketHeader = http.CanonicalHeaderKey("X-AppEngine-API-Ticket") dapperHeader = http.CanonicalHeaderKey("X-Google-DapperTraceInfo") traceHeader = http.CanonicalHeaderKey("X-Cloud-Trace-Context") curNamespaceHeader = http.CanonicalHeaderKey("X-AppEngine-Current-Namespace") userIPHeader = http.CanonicalHeaderKey("X-AppEngine-User-IP") remoteAddrHeader = http.CanonicalHeaderKey("X-AppEngine-Remote-Addr") // Outgoing headers. apiEndpointHeader = http.CanonicalHeaderKey("X-Google-RPC-Service-Endpoint") apiEndpointHeaderValue = []string{"app-engine-apis"} apiMethodHeader = http.CanonicalHeaderKey("X-Google-RPC-Service-Method") apiMethodHeaderValue = []string{"/VMRemoteAPI.CallRemoteAPI"} apiDeadlineHeader = http.CanonicalHeaderKey("X-Google-RPC-Service-Deadline") apiContentType = http.CanonicalHeaderKey("Content-Type") apiContentTypeValue = []string{"application/octet-stream"} logFlushHeader = http.CanonicalHeaderKey("X-AppEngine-Log-Flush-Count") apiHTTPClient = &http.Client{ Transport: &http.Transport{ Proxy: http.ProxyFromEnvironment, Dial: limitDial, }, } ) func apiURL() *url.URL { host, port := "appengine.googleapis.internal", "10001" if h := os.Getenv("API_HOST"); h != "" { host = h } if p := os.Getenv("API_PORT"); p != "" { port = p } return &url.URL{ Scheme: "http", Host: host + ":" + port, Path: apiPath, } } func handleHTTP(w http.ResponseWriter, r *http.Request) { c := &context{ req: r, outHeader: w.Header(), apiURL: apiURL(), } stopFlushing := make(chan int) ctxs.Lock() ctxs.m[r] = c ctxs.Unlock() defer func() { ctxs.Lock() delete(ctxs.m, r) ctxs.Unlock() }() // Patch up RemoteAddr so it looks reasonable. if addr := r.Header.Get(userIPHeader); addr != "" { r.RemoteAddr = addr } else if addr = r.Header.Get(remoteAddrHeader); addr != "" { r.RemoteAddr = addr } else { // Should not normally reach here, but pick a sensible default anyway. r.RemoteAddr = "127.0.0.1" } // The address in the headers will most likely be of these forms: // 123.123.123.123 // 2001:db8::1 // net/http.Request.RemoteAddr is specified to be in "IP:port" form. if _, _, err := net.SplitHostPort(r.RemoteAddr); err != nil { // Assume the remote address is only a host; add a default port. r.RemoteAddr = net.JoinHostPort(r.RemoteAddr, "80") } // Start goroutine responsible for flushing app logs. // This is done after adding c to ctx.m (and stopped before removing it) // because flushing logs requires making an API call. go c.logFlusher(stopFlushing) executeRequestSafely(c, r) c.outHeader = nil // make sure header changes aren't respected any more stopFlushing <- 1 // any logging beyond this point will be dropped // Flush any pending logs asynchronously. c.pendingLogs.Lock() flushes := c.pendingLogs.flushes if len(c.pendingLogs.lines) > 0 { flushes++ } c.pendingLogs.Unlock() go c.flushLog(false) w.Header().Set(logFlushHeader, strconv.Itoa(flushes)) // Avoid nil Write call if c.Write is never called. if c.outCode != 0 { w.WriteHeader(c.outCode) } if c.outBody != nil { w.Write(c.outBody) } } func executeRequestSafely(c *context, r *http.Request) { defer func() { if x := recover(); x != nil { logf(c, 4, "%s", renderPanic(x)) // 4 == critical c.outCode = 500 } }() http.DefaultServeMux.ServeHTTP(c, r) } func renderPanic(x interface{}) string { buf := make([]byte, 16<<10) // 16 KB should be plenty buf = buf[:runtime.Stack(buf, false)] // Remove the first few stack frames: // this func // the recover closure in the caller // That will root the stack trace at the site of the panic. const ( skipStart = "internal.renderPanic" skipFrames = 2 ) start := bytes.Index(buf, []byte(skipStart)) p := start for i := 0; i < skipFrames*2 && p+1 < len(buf); i++ { p = bytes.IndexByte(buf[p+1:], '\n') + p + 1 if p < 0 { break } } if p >= 0 { // buf[start:p+1] is the block to remove. // Copy buf[p+1:] over buf[start:] and shrink buf. copy(buf[start:], buf[p+1:]) buf = buf[:len(buf)-(p+1-start)] } // Add panic heading. head := fmt.Sprintf("panic: %v\n\n", x) if len(head) > len(buf) { // Extremely unlikely to happen. return head } copy(buf[len(head):], buf) copy(buf, head) return string(buf) } var ctxs = struct { sync.Mutex m map[*http.Request]*context bg *context // background context, lazily initialized // dec is used by tests to decorate the netcontext.Context returned // for a given request. This allows tests to add overrides (such as // WithAppIDOverride) to the context. The map is nil outside tests. dec map[*http.Request]func(netcontext.Context) netcontext.Context }{ m: make(map[*http.Request]*context), } // context represents the context of an in-flight HTTP request. // It implements the appengine.Context and http.ResponseWriter interfaces. type context struct { req *http.Request outCode int outHeader http.Header outBody []byte pendingLogs struct { sync.Mutex lines []*logpb.UserAppLogLine flushes int } apiURL *url.URL } var contextKey = "holds a *context" func fromContext(ctx netcontext.Context) *context { c, _ := ctx.Value(&contextKey).(*context) return c } func withContext(parent netcontext.Context, c *context) netcontext.Context { ctx := netcontext.WithValue(parent, &contextKey, c) if ns := c.req.Header.Get(curNamespaceHeader); ns != "" { ctx = withNamespace(ctx, ns) } return ctx } func toContext(c *context) netcontext.Context { return withContext(netcontext.Background(), c) } func IncomingHeaders(ctx netcontext.Context) http.Header { if c := fromContext(ctx); c != nil { return c.req.Header } return nil } func WithContext(parent netcontext.Context, req *http.Request) netcontext.Context { ctxs.Lock() c := ctxs.m[req] d := ctxs.dec[req] ctxs.Unlock() if d != nil { parent = d(parent) } if c == nil { // Someone passed in an http.Request that is not in-flight. // We panic here rather than panicking at a later point // so that stack traces will be more sensible. log.Panic("appengine: NewContext passed an unknown http.Request") } return withContext(parent, c) } func BackgroundContext() netcontext.Context { ctxs.Lock() defer ctxs.Unlock() if ctxs.bg != nil { return toContext(ctxs.bg) } // Compute background security ticket. appID := partitionlessAppID() escAppID := strings.Replace(strings.Replace(appID, ":", "_", -1), ".", "_", -1) majVersion := VersionID(nil) if i := strings.Index(majVersion, "."); i > 0 { majVersion = majVersion[:i] } ticket := fmt.Sprintf("%s/%s.%s.%s", escAppID, ModuleName(nil), majVersion, InstanceID()) ctxs.bg = &context{ req: &http.Request{ Header: http.Header{ ticketHeader: []string{ticket}, }, }, apiURL: apiURL(), } // TODO(dsymonds): Wire up the shutdown handler to do a final flush. go ctxs.bg.logFlusher(make(chan int)) return toContext(ctxs.bg) } // RegisterTestRequest registers the HTTP request req for testing, such that // any API calls are sent to the provided URL. It returns a closure to delete // the registration. // It should only be used by aetest package. func RegisterTestRequest(req *http.Request, apiURL *url.URL, decorate func(netcontext.Context) netcontext.Context) func() { c := &context{ req: req, apiURL: apiURL, } ctxs.Lock() defer ctxs.Unlock() if _, ok := ctxs.m[req]; ok { log.Panic("req already associated with context") } if _, ok := ctxs.dec[req]; ok { log.Panic("req already associated with context") } if ctxs.dec == nil { ctxs.dec = make(map[*http.Request]func(netcontext.Context) netcontext.Context) } ctxs.m[req] = c ctxs.dec[req] = decorate return func() { ctxs.Lock() delete(ctxs.m, req) delete(ctxs.dec, req) ctxs.Unlock() } } var errTimeout = &CallError{ Detail: "Deadline exceeded", Code: int32(remotepb.RpcError_CANCELLED), Timeout: true, } func (c *context) Header() http.Header { return c.outHeader } // Copied from $GOROOT/src/pkg/net/http/transfer.go. Some response status // codes do not permit a response body (nor response entity headers such as // Content-Length, Content-Type, etc). func bodyAllowedForStatus(status int) bool { switch { case status >= 100 && status <= 199: return false case status == 204: return false case status == 304: return false } return true } func (c *context) Write(b []byte) (int, error) { if c.outCode == 0 { c.WriteHeader(http.StatusOK) } if len(b) > 0 && !bodyAllowedForStatus(c.outCode) { return 0, http.ErrBodyNotAllowed } c.outBody = append(c.outBody, b...) return len(b), nil } func (c *context) WriteHeader(code int) { if c.outCode != 0 { logf(c, 3, "WriteHeader called multiple times on request.") // error level return } c.outCode = code } func (c *context) post(body []byte, timeout time.Duration) (b []byte, err error) { hreq := &http.Request{ Method: "POST", URL: c.apiURL, Header: http.Header{ apiEndpointHeader: apiEndpointHeaderValue, apiMethodHeader: apiMethodHeaderValue, apiContentType: apiContentTypeValue, apiDeadlineHeader: []string{strconv.FormatFloat(timeout.Seconds(), 'f', -1, 64)}, }, Body: ioutil.NopCloser(bytes.NewReader(body)), ContentLength: int64(len(body)), Host: c.apiURL.Host, } if info := c.req.Header.Get(dapperHeader); info != "" { hreq.Header.Set(dapperHeader, info) } if info := c.req.Header.Get(traceHeader); info != "" { hreq.Header.Set(traceHeader, info) } tr := apiHTTPClient.Transport.(*http.Transport) var timedOut int32 // atomic; set to 1 if timed out t := time.AfterFunc(timeout, func() { atomic.StoreInt32(&timedOut, 1) tr.CancelRequest(hreq) }) defer t.Stop() defer func() { // Check if timeout was exceeded. if atomic.LoadInt32(&timedOut) != 0 { err = errTimeout } }() hresp, err := apiHTTPClient.Do(hreq) if err != nil { return nil, &CallError{ Detail: fmt.Sprintf("service bridge HTTP failed: %v", err), Code: int32(remotepb.RpcError_UNKNOWN), } } defer hresp.Body.Close() hrespBody, err := ioutil.ReadAll(hresp.Body) if hresp.StatusCode != 200 { return nil, &CallError{ Detail: fmt.Sprintf("service bridge returned HTTP %d (%q)", hresp.StatusCode, hrespBody), Code: int32(remotepb.RpcError_UNKNOWN), } } if err != nil { return nil, &CallError{ Detail: fmt.Sprintf("service bridge response bad: %v", err), Code: int32(remotepb.RpcError_UNKNOWN), } } return hrespBody, nil } func Call(ctx netcontext.Context, service, method string, in, out proto.Message) error { if ns := NamespaceFromContext(ctx); ns != "" { if fn, ok := NamespaceMods[service]; ok { fn(in, ns) } } if f, ctx, ok := callOverrideFromContext(ctx); ok { return f(ctx, service, method, in, out) } // Handle already-done contexts quickly. select { case <-ctx.Done(): return ctx.Err() default: } c := fromContext(ctx) if c == nil { // Give a good error message rather than a panic lower down. return errors.New("not an App Engine context") } // Apply transaction modifications if we're in a transaction. if t := transactionFromContext(ctx); t != nil { if t.finished { return errors.New("transaction context has expired") } applyTransaction(in, &t.transaction) } // Default RPC timeout is 60s. timeout := 60 * time.Second if deadline, ok := ctx.Deadline(); ok { timeout = deadline.Sub(time.Now()) } data, err := proto.Marshal(in) if err != nil { return err } ticket := c.req.Header.Get(ticketHeader) req := &remotepb.Request{ ServiceName: &service, Method: &method, Request: data, RequestId: &ticket, } hreqBody, err := proto.Marshal(req) if err != nil { return err } hrespBody, err := c.post(hreqBody, timeout) if err != nil { return err } res := &remotepb.Response{} if err := proto.Unmarshal(hrespBody, res); err != nil { return err } if res.RpcError != nil { ce := &CallError{ Detail: res.RpcError.GetDetail(), Code: *res.RpcError.Code, } switch remotepb.RpcError_ErrorCode(ce.Code) { case remotepb.RpcError_CANCELLED, remotepb.RpcError_DEADLINE_EXCEEDED: ce.Timeout = true } return ce } if res.ApplicationError != nil { return &APIError{ Service: *req.ServiceName, Detail: res.ApplicationError.GetDetail(), Code: *res.ApplicationError.Code, } } if res.Exception != nil || res.JavaException != nil { // This shouldn't happen, but let's be defensive. return &CallError{ Detail: "service bridge returned exception", Code: int32(remotepb.RpcError_UNKNOWN), } } return proto.Unmarshal(res.Response, out) } func (c *context) Request() *http.Request { return c.req } func (c *context) addLogLine(ll *logpb.UserAppLogLine) { // Truncate long log lines. // TODO(dsymonds): Check if this is still necessary. const lim = 8 << 10 if len(*ll.Message) > lim { suffix := fmt.Sprintf("...(length %d)", len(*ll.Message)) ll.Message = proto.String((*ll.Message)[:lim-len(suffix)] + suffix) } c.pendingLogs.Lock() c.pendingLogs.lines = append(c.pendingLogs.lines, ll) c.pendingLogs.Unlock() } var logLevelName = map[int64]string{ 0: "DEBUG", 1: "INFO", 2: "WARNING", 3: "ERROR", 4: "CRITICAL", } func logf(c *context, level int64, format string, args ...interface{}) { s := fmt.Sprintf(format, args...) s = strings.TrimRight(s, "\n") // Remove any trailing newline characters. c.addLogLine(&logpb.UserAppLogLine{ TimestampUsec: proto.Int64(time.Now().UnixNano() / 1e3), Level: &level, Message: &s, }) log.Print(logLevelName[level] + ": " + s) } // flushLog attempts to flush any pending logs to the appserver. // It should not be called concurrently. func (c *context) flushLog(force bool) (flushed bool) { c.pendingLogs.Lock() // Grab up to 30 MB. We can get away with up to 32 MB, but let's be cautious. n, rem := 0, 30<<20 for ; n < len(c.pendingLogs.lines); n++ { ll := c.pendingLogs.lines[n] // Each log line will require about 3 bytes of overhead. nb := proto.Size(ll) + 3 if nb > rem { break } rem -= nb } lines := c.pendingLogs.lines[:n] c.pendingLogs.lines = c.pendingLogs.lines[n:] c.pendingLogs.Unlock() if len(lines) == 0 && !force { // Nothing to flush. return false } rescueLogs := false defer func() { if rescueLogs { c.pendingLogs.Lock() c.pendingLogs.lines = append(lines, c.pendingLogs.lines...) c.pendingLogs.Unlock() } }() buf, err := proto.Marshal(&logpb.UserAppLogGroup{ LogLine: lines, }) if err != nil { log.Printf("internal.flushLog: marshaling UserAppLogGroup: %v", err) rescueLogs = true return false } req := &logpb.FlushRequest{ Logs: buf, } res := &basepb.VoidProto{} c.pendingLogs.Lock() c.pendingLogs.flushes++ c.pendingLogs.Unlock() if err := Call(toContext(c), "logservice", "Flush", req, res); err != nil { log.Printf("internal.flushLog: Flush RPC: %v", err) rescueLogs = true return false } return true } const ( // Log flushing parameters. flushInterval = 1 * time.Second forceFlushInterval = 60 * time.Second ) func (c *context) logFlusher(stop <-chan int) { lastFlush := time.Now() tick := time.NewTicker(flushInterval) for { select { case <-stop: // Request finished. tick.Stop() return case <-tick.C: force := time.Now().Sub(lastFlush) > forceFlushInterval if c.flushLog(force) { lastFlush = time.Now() } } } } func ContextForTesting(req *http.Request) netcontext.Context { return toContext(&context{req: req}) } ================================================ FILE: vendor/google.golang.org/appengine/internal/api_classic.go ================================================ // Copyright 2015 Google Inc. All rights reserved. // Use of this source code is governed by the Apache 2.0 // license that can be found in the LICENSE file. // +build appengine package internal import ( "errors" "fmt" "net/http" "time" "appengine" "appengine_internal" basepb "appengine_internal/base" "github.com/golang/protobuf/proto" netcontext "golang.org/x/net/context" ) var contextKey = "holds an appengine.Context" func fromContext(ctx netcontext.Context) appengine.Context { c, _ := ctx.Value(&contextKey).(appengine.Context) return c } // This is only for classic App Engine adapters. func ClassicContextFromContext(ctx netcontext.Context) appengine.Context { return fromContext(ctx) } func withContext(parent netcontext.Context, c appengine.Context) netcontext.Context { ctx := netcontext.WithValue(parent, &contextKey, c) s := &basepb.StringProto{} c.Call("__go__", "GetNamespace", &basepb.VoidProto{}, s, nil) if ns := s.GetValue(); ns != "" { ctx = NamespacedContext(ctx, ns) } return ctx } func IncomingHeaders(ctx netcontext.Context) http.Header { if c := fromContext(ctx); c != nil { if req, ok := c.Request().(*http.Request); ok { return req.Header } } return nil } func WithContext(parent netcontext.Context, req *http.Request) netcontext.Context { c := appengine.NewContext(req) return withContext(parent, c) } type testingContext struct { appengine.Context req *http.Request } func (t *testingContext) FullyQualifiedAppID() string { return "dev~testcontext" } func (t *testingContext) Call(service, method string, _, _ appengine_internal.ProtoMessage, _ *appengine_internal.CallOptions) error { if service == "__go__" && method == "GetNamespace" { return nil } return fmt.Errorf("testingContext: unsupported Call") } func (t *testingContext) Request() interface{} { return t.req } func ContextForTesting(req *http.Request) netcontext.Context { return withContext(netcontext.Background(), &testingContext{req: req}) } func Call(ctx netcontext.Context, service, method string, in, out proto.Message) error { if ns := NamespaceFromContext(ctx); ns != "" { if fn, ok := NamespaceMods[service]; ok { fn(in, ns) } } if f, ctx, ok := callOverrideFromContext(ctx); ok { return f(ctx, service, method, in, out) } // Handle already-done contexts quickly. select { case <-ctx.Done(): return ctx.Err() default: } c := fromContext(ctx) if c == nil { // Give a good error message rather than a panic lower down. return errors.New("not an App Engine context") } // Apply transaction modifications if we're in a transaction. if t := transactionFromContext(ctx); t != nil { if t.finished { return errors.New("transaction context has expired") } applyTransaction(in, &t.transaction) } var opts *appengine_internal.CallOptions if d, ok := ctx.Deadline(); ok { opts = &appengine_internal.CallOptions{ Timeout: d.Sub(time.Now()), } } err := c.Call(service, method, in, out, opts) switch v := err.(type) { case *appengine_internal.APIError: return &APIError{ Service: v.Service, Detail: v.Detail, Code: v.Code, } case *appengine_internal.CallError: return &CallError{ Detail: v.Detail, Code: v.Code, Timeout: v.Timeout, } } return err } func handleHTTP(w http.ResponseWriter, r *http.Request) { panic("handleHTTP called; this should be impossible") } func logf(c appengine.Context, level int64, format string, args ...interface{}) { var fn func(format string, args ...interface{}) switch level { case 0: fn = c.Debugf case 1: fn = c.Infof case 2: fn = c.Warningf case 3: fn = c.Errorf case 4: fn = c.Criticalf default: // This shouldn't happen. fn = c.Criticalf } fn(format, args...) } ================================================ FILE: vendor/google.golang.org/appengine/internal/api_common.go ================================================ // Copyright 2015 Google Inc. All rights reserved. // Use of this source code is governed by the Apache 2.0 // license that can be found in the LICENSE file. package internal import ( "github.com/golang/protobuf/proto" netcontext "golang.org/x/net/context" ) type CallOverrideFunc func(ctx netcontext.Context, service, method string, in, out proto.Message) error var callOverrideKey = "holds []CallOverrideFunc" func WithCallOverride(ctx netcontext.Context, f CallOverrideFunc) netcontext.Context { // We avoid appending to any existing call override // so we don't risk overwriting a popped stack below. var cofs []CallOverrideFunc if uf, ok := ctx.Value(&callOverrideKey).([]CallOverrideFunc); ok { cofs = append(cofs, uf...) } cofs = append(cofs, f) return netcontext.WithValue(ctx, &callOverrideKey, cofs) } func callOverrideFromContext(ctx netcontext.Context) (CallOverrideFunc, netcontext.Context, bool) { cofs, _ := ctx.Value(&callOverrideKey).([]CallOverrideFunc) if len(cofs) == 0 { return nil, nil, false } // We found a list of overrides; grab the last, and reconstitute a // context that will hide it. f := cofs[len(cofs)-1] ctx = netcontext.WithValue(ctx, &callOverrideKey, cofs[:len(cofs)-1]) return f, ctx, true } type logOverrideFunc func(level int64, format string, args ...interface{}) var logOverrideKey = "holds a logOverrideFunc" func WithLogOverride(ctx netcontext.Context, f logOverrideFunc) netcontext.Context { return netcontext.WithValue(ctx, &logOverrideKey, f) } var appIDOverrideKey = "holds a string, being the full app ID" func WithAppIDOverride(ctx netcontext.Context, appID string) netcontext.Context { return netcontext.WithValue(ctx, &appIDOverrideKey, appID) } var namespaceKey = "holds the namespace string" func withNamespace(ctx netcontext.Context, ns string) netcontext.Context { return netcontext.WithValue(ctx, &namespaceKey, ns) } func NamespaceFromContext(ctx netcontext.Context) string { // If there's no namespace, return the empty string. ns, _ := ctx.Value(&namespaceKey).(string) return ns } // FullyQualifiedAppID returns the fully-qualified application ID. // This may contain a partition prefix (e.g. "s~" for High Replication apps), // or a domain prefix (e.g. "example.com:"). func FullyQualifiedAppID(ctx netcontext.Context) string { if id, ok := ctx.Value(&appIDOverrideKey).(string); ok { return id } return fullyQualifiedAppID(ctx) } func Logf(ctx netcontext.Context, level int64, format string, args ...interface{}) { if f, ok := ctx.Value(&logOverrideKey).(logOverrideFunc); ok { f(level, format, args...) return } logf(fromContext(ctx), level, format, args...) } // NamespacedContext wraps a Context to support namespaces. func NamespacedContext(ctx netcontext.Context, namespace string) netcontext.Context { return withNamespace(ctx, namespace) } ================================================ FILE: vendor/google.golang.org/appengine/internal/api_race_test.go ================================================ // Copyright 2014 Google Inc. All rights reserved. // Use of this source code is governed by the Apache 2.0 // license that can be found in the LICENSE file. // +build race package internal func init() { raceDetector = true } ================================================ FILE: vendor/google.golang.org/appengine/internal/api_test.go ================================================ // Copyright 2014 Google Inc. All rights reserved. // Use of this source code is governed by the Apache 2.0 // license that can be found in the LICENSE file. // +build !appengine package internal import ( "bufio" "bytes" "fmt" "io" "io/ioutil" "net/http" "net/http/httptest" "net/url" "os" "os/exec" "strings" "sync/atomic" "testing" "time" "github.com/golang/protobuf/proto" netcontext "golang.org/x/net/context" basepb "google.golang.org/appengine/internal/base" remotepb "google.golang.org/appengine/internal/remote_api" ) const testTicketHeader = "X-Magic-Ticket-Header" func init() { ticketHeader = testTicketHeader } type fakeAPIHandler struct { hang chan int // used for RunSlowly RPC LogFlushes int32 // atomic } func (f *fakeAPIHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { writeResponse := func(res *remotepb.Response) { hresBody, err := proto.Marshal(res) if err != nil { http.Error(w, fmt.Sprintf("Failed encoding API response: %v", err), 500) return } w.Write(hresBody) } if r.URL.Path != "/rpc_http" { http.NotFound(w, r) return } hreqBody, err := ioutil.ReadAll(r.Body) if err != nil { http.Error(w, fmt.Sprintf("Bad body: %v", err), 500) return } apiReq := &remotepb.Request{} if err := proto.Unmarshal(hreqBody, apiReq); err != nil { http.Error(w, fmt.Sprintf("Bad encoded API request: %v", err), 500) return } if *apiReq.RequestId != "s3cr3t" { writeResponse(&remotepb.Response{ RpcError: &remotepb.RpcError{ Code: proto.Int32(int32(remotepb.RpcError_SECURITY_VIOLATION)), Detail: proto.String("bad security ticket"), }, }) return } if got, want := r.Header.Get(dapperHeader), "trace-001"; got != want { writeResponse(&remotepb.Response{ RpcError: &remotepb.RpcError{ Code: proto.Int32(int32(remotepb.RpcError_BAD_REQUEST)), Detail: proto.String(fmt.Sprintf("trace info = %q, want %q", got, want)), }, }) return } service, method := *apiReq.ServiceName, *apiReq.Method var resOut proto.Message if service == "actordb" && method == "LookupActor" { req := &basepb.StringProto{} res := &basepb.StringProto{} if err := proto.Unmarshal(apiReq.Request, req); err != nil { http.Error(w, fmt.Sprintf("Bad encoded request: %v", err), 500) return } if *req.Value == "Doctor Who" { res.Value = proto.String("David Tennant") } resOut = res } if service == "errors" { switch method { case "Non200": http.Error(w, "I'm a little teapot.", 418) return case "ShortResponse": w.Header().Set("Content-Length", "100") w.Write([]byte("way too short")) return case "OverQuota": writeResponse(&remotepb.Response{ RpcError: &remotepb.RpcError{ Code: proto.Int32(int32(remotepb.RpcError_OVER_QUOTA)), Detail: proto.String("you are hogging the resources!"), }, }) return case "RunSlowly": // TestAPICallRPCFailure creates f.hang, but does not strobe it // until Call returns with remotepb.RpcError_CANCELLED. // This is here to force a happens-before relationship between // the httptest server handler and shutdown. <-f.hang resOut = &basepb.VoidProto{} } } if service == "logservice" && method == "Flush" { // Pretend log flushing is slow. time.Sleep(50 * time.Millisecond) atomic.AddInt32(&f.LogFlushes, 1) resOut = &basepb.VoidProto{} } encOut, err := proto.Marshal(resOut) if err != nil { http.Error(w, fmt.Sprintf("Failed encoding response: %v", err), 500) return } writeResponse(&remotepb.Response{ Response: encOut, }) } func setup() (f *fakeAPIHandler, c *context, cleanup func()) { f = &fakeAPIHandler{} srv := httptest.NewServer(f) u, err := url.Parse(srv.URL + apiPath) if err != nil { panic(fmt.Sprintf("url.Parse(%q): %v", srv.URL+apiPath, err)) } return f, &context{ req: &http.Request{ Header: http.Header{ ticketHeader: []string{"s3cr3t"}, dapperHeader: []string{"trace-001"}, }, }, apiURL: u, }, srv.Close } func TestAPICall(t *testing.T) { _, c, cleanup := setup() defer cleanup() req := &basepb.StringProto{ Value: proto.String("Doctor Who"), } res := &basepb.StringProto{} err := Call(toContext(c), "actordb", "LookupActor", req, res) if err != nil { t.Fatalf("API call failed: %v", err) } if got, want := *res.Value, "David Tennant"; got != want { t.Errorf("Response is %q, want %q", got, want) } } func TestAPICallRPCFailure(t *testing.T) { f, c, cleanup := setup() defer cleanup() testCases := []struct { method string code remotepb.RpcError_ErrorCode }{ {"Non200", remotepb.RpcError_UNKNOWN}, {"ShortResponse", remotepb.RpcError_UNKNOWN}, {"OverQuota", remotepb.RpcError_OVER_QUOTA}, {"RunSlowly", remotepb.RpcError_CANCELLED}, } f.hang = make(chan int) // only for RunSlowly for _, tc := range testCases { ctx, _ := netcontext.WithTimeout(toContext(c), 100*time.Millisecond) err := Call(ctx, "errors", tc.method, &basepb.VoidProto{}, &basepb.VoidProto{}) ce, ok := err.(*CallError) if !ok { t.Errorf("%s: API call error is %T (%v), want *CallError", tc.method, err, err) continue } if ce.Code != int32(tc.code) { t.Errorf("%s: ce.Code = %d, want %d", tc.method, ce.Code, tc.code) } if tc.method == "RunSlowly" { f.hang <- 1 // release the HTTP handler } } } func TestAPICallDialFailure(t *testing.T) { // See what happens if the API host is unresponsive. // This should time out quickly, not hang forever. _, c, cleanup := setup() defer cleanup() // Reset the URL to the production address so that dialing fails. c.apiURL = apiURL() start := time.Now() err := Call(toContext(c), "foo", "bar", &basepb.VoidProto{}, &basepb.VoidProto{}) const max = 1 * time.Second if taken := time.Since(start); taken > max { t.Errorf("Dial hang took too long: %v > %v", taken, max) } if err == nil { t.Error("Call did not fail") } } func TestDelayedLogFlushing(t *testing.T) { f, c, cleanup := setup() defer cleanup() http.HandleFunc("/quick_log", func(w http.ResponseWriter, r *http.Request) { logC := WithContext(netcontext.Background(), r) fromContext(logC).apiURL = c.apiURL // Otherwise it will try to use the default URL. Logf(logC, 1, "It's a lovely day.") w.WriteHeader(200) w.Write(make([]byte, 100<<10)) // write 100 KB to force HTTP flush }) r := &http.Request{ Method: "GET", URL: &url.URL{ Scheme: "http", Path: "/quick_log", }, Header: c.req.Header, Body: ioutil.NopCloser(bytes.NewReader(nil)), } w := httptest.NewRecorder() // Check that log flushing does not hold up the HTTP response. start := time.Now() handleHTTP(w, r) if d := time.Since(start); d > 10*time.Millisecond { t.Errorf("handleHTTP took %v, want under 10ms", d) } const hdr = "X-AppEngine-Log-Flush-Count" if h := w.HeaderMap.Get(hdr); h != "1" { t.Errorf("%s header = %q, want %q", hdr, h, "1") } if f := atomic.LoadInt32(&f.LogFlushes); f != 0 { t.Errorf("After HTTP response: f.LogFlushes = %d, want 0", f) } // Check that the log flush eventually comes in. time.Sleep(100 * time.Millisecond) if f := atomic.LoadInt32(&f.LogFlushes); f != 1 { t.Errorf("After 100ms: f.LogFlushes = %d, want 1", f) } } func TestRemoteAddr(t *testing.T) { var addr string http.HandleFunc("/remote_addr", func(w http.ResponseWriter, r *http.Request) { addr = r.RemoteAddr }) testCases := []struct { headers http.Header addr string }{ {http.Header{"X-Appengine-User-Ip": []string{"10.5.2.1"}}, "10.5.2.1:80"}, {http.Header{"X-Appengine-Remote-Addr": []string{"1.2.3.4"}}, "1.2.3.4:80"}, {http.Header{"X-Appengine-Remote-Addr": []string{"1.2.3.4:8080"}}, "1.2.3.4:8080"}, { http.Header{"X-Appengine-Remote-Addr": []string{"2401:fa00:9:1:7646:a0ff:fe90:ca66"}}, "[2401:fa00:9:1:7646:a0ff:fe90:ca66]:80", }, { http.Header{"X-Appengine-Remote-Addr": []string{"[::1]:http"}}, "[::1]:http", }, {http.Header{}, "127.0.0.1:80"}, } for _, tc := range testCases { r := &http.Request{ Method: "GET", URL: &url.URL{Scheme: "http", Path: "/remote_addr"}, Header: tc.headers, Body: ioutil.NopCloser(bytes.NewReader(nil)), } handleHTTP(httptest.NewRecorder(), r) if addr != tc.addr { t.Errorf("Header %v, got %q, want %q", tc.headers, addr, tc.addr) } } } func TestPanickingHandler(t *testing.T) { http.HandleFunc("/panic", func(http.ResponseWriter, *http.Request) { panic("whoops!") }) r := &http.Request{ Method: "GET", URL: &url.URL{Scheme: "http", Path: "/panic"}, Body: ioutil.NopCloser(bytes.NewReader(nil)), } rec := httptest.NewRecorder() handleHTTP(rec, r) if rec.Code != 500 { t.Errorf("Panicking handler returned HTTP %d, want HTTP %d", rec.Code, 500) } } var raceDetector = false func TestAPICallAllocations(t *testing.T) { if raceDetector { t.Skip("not running under race detector") } // Run the test API server in a subprocess so we aren't counting its allocations. u, cleanup := launchHelperProcess(t) defer cleanup() c := &context{ req: &http.Request{ Header: http.Header{ ticketHeader: []string{"s3cr3t"}, dapperHeader: []string{"trace-001"}, }, }, apiURL: u, } req := &basepb.StringProto{ Value: proto.String("Doctor Who"), } res := &basepb.StringProto{} var apiErr error avg := testing.AllocsPerRun(100, func() { ctx, _ := netcontext.WithTimeout(toContext(c), 100*time.Millisecond) if err := Call(ctx, "actordb", "LookupActor", req, res); err != nil && apiErr == nil { apiErr = err // get the first error only } }) if apiErr != nil { t.Errorf("API call failed: %v", apiErr) } // Lots of room for improvement... // TODO(djd): Reduce maximum to 85 once the App Engine SDK is based on 1.6. const min, max float64 = 70, 90 if avg < min || max < avg { t.Errorf("Allocations per API call = %g, want in [%g,%g]", avg, min, max) } } func launchHelperProcess(t *testing.T) (apiURL *url.URL, cleanup func()) { cmd := exec.Command(os.Args[0], "-test.run=TestHelperProcess") cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"} stdin, err := cmd.StdinPipe() if err != nil { t.Fatalf("StdinPipe: %v", err) } stdout, err := cmd.StdoutPipe() if err != nil { t.Fatalf("StdoutPipe: %v", err) } if err := cmd.Start(); err != nil { t.Fatalf("Starting helper process: %v", err) } scan := bufio.NewScanner(stdout) var u *url.URL for scan.Scan() { line := scan.Text() if hp := strings.TrimPrefix(line, helperProcessMagic); hp != line { var err error u, err = url.Parse(hp) if err != nil { t.Fatalf("Failed to parse %q: %v", hp, err) } break } } if err := scan.Err(); err != nil { t.Fatalf("Scanning helper process stdout: %v", err) } if u == nil { t.Fatal("Helper process never reported") } return u, func() { stdin.Close() if err := cmd.Wait(); err != nil { t.Errorf("Helper process did not exit cleanly: %v", err) } } } const helperProcessMagic = "A lovely helper process is listening at " // This isn't a real test. It's used as a helper process. func TestHelperProcess(*testing.T) { if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" { return } defer os.Exit(0) f := &fakeAPIHandler{} srv := httptest.NewServer(f) defer srv.Close() fmt.Println(helperProcessMagic + srv.URL + apiPath) // Wait for stdin to be closed. io.Copy(ioutil.Discard, os.Stdin) } func TestBackgroundContext(t *testing.T) { environ := []struct { key, value string }{ {"GAE_LONG_APP_ID", "my-app-id"}, {"GAE_MINOR_VERSION", "067924799508853122"}, {"GAE_MODULE_INSTANCE", "0"}, {"GAE_MODULE_NAME", "default"}, {"GAE_MODULE_VERSION", "20150612t184001"}, } for _, v := range environ { old := os.Getenv(v.key) os.Setenv(v.key, v.value) v.value = old } defer func() { // Restore old environment after the test completes. for _, v := range environ { if v.value == "" { os.Unsetenv(v.key) continue } os.Setenv(v.key, v.value) } }() ctx, key := fromContext(BackgroundContext()), "X-Magic-Ticket-Header" if g, w := ctx.req.Header.Get(key), "my-app-id/default.20150612t184001.0"; g != w { t.Errorf("%v = %q, want %q", key, g, w) } // Check that using the background context doesn't panic. req := &basepb.StringProto{ Value: proto.String("Doctor Who"), } res := &basepb.StringProto{} Call(BackgroundContext(), "actordb", "LookupActor", req, res) // expected to fail } ================================================ FILE: vendor/google.golang.org/appengine/internal/app_id.go ================================================ // Copyright 2011 Google Inc. All rights reserved. // Use of this source code is governed by the Apache 2.0 // license that can be found in the LICENSE file. package internal import ( "strings" ) func parseFullAppID(appid string) (partition, domain, displayID string) { if i := strings.Index(appid, "~"); i != -1 { partition, appid = appid[:i], appid[i+1:] } if i := strings.Index(appid, ":"); i != -1 { domain, appid = appid[:i], appid[i+1:] } return partition, domain, appid } // appID returns "appid" or "domain.com:appid". func appID(fullAppID string) string { _, dom, dis := parseFullAppID(fullAppID) if dom != "" { return dom + ":" + dis } return dis } ================================================ FILE: vendor/google.golang.org/appengine/internal/app_id_test.go ================================================ // Copyright 2011 Google Inc. All Rights Reserved. // Use of this source code is governed by the Apache 2.0 // license that can be found in the LICENSE file. package internal import ( "testing" ) func TestAppIDParsing(t *testing.T) { testCases := []struct { in string partition, domain, displayID string }{ {"simple-app-id", "", "", "simple-app-id"}, {"domain.com:domain-app-id", "", "domain.com", "domain-app-id"}, {"part~partition-app-id", "part", "", "partition-app-id"}, {"part~domain.com:display", "part", "domain.com", "display"}, } for _, tc := range testCases { part, dom, dis := parseFullAppID(tc.in) if part != tc.partition { t.Errorf("partition of %q: got %q, want %q", tc.in, part, tc.partition) } if dom != tc.domain { t.Errorf("domain of %q: got %q, want %q", tc.in, dom, tc.domain) } if dis != tc.displayID { t.Errorf("displayID of %q: got %q, want %q", tc.in, dis, tc.displayID) } } } ================================================ FILE: vendor/google.golang.org/appengine/internal/base/api_base.pb.go ================================================ // Code generated by protoc-gen-go. // source: google.golang.org/appengine/internal/base/api_base.proto // DO NOT EDIT! /* Package base is a generated protocol buffer package. It is generated from these files: google.golang.org/appengine/internal/base/api_base.proto It has these top-level messages: StringProto Integer32Proto Integer64Proto BoolProto DoubleProto BytesProto VoidProto */ package base import proto "github.com/golang/protobuf/proto" import fmt "fmt" import math "math" // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal var _ = fmt.Errorf var _ = math.Inf type StringProto struct { Value *string `protobuf:"bytes,1,req,name=value" json:"value,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *StringProto) Reset() { *m = StringProto{} } func (m *StringProto) String() string { return proto.CompactTextString(m) } func (*StringProto) ProtoMessage() {} func (m *StringProto) GetValue() string { if m != nil && m.Value != nil { return *m.Value } return "" } type Integer32Proto struct { Value *int32 `protobuf:"varint,1,req,name=value" json:"value,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *Integer32Proto) Reset() { *m = Integer32Proto{} } func (m *Integer32Proto) String() string { return proto.CompactTextString(m) } func (*Integer32Proto) ProtoMessage() {} func (m *Integer32Proto) GetValue() int32 { if m != nil && m.Value != nil { return *m.Value } return 0 } type Integer64Proto struct { Value *int64 `protobuf:"varint,1,req,name=value" json:"value,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *Integer64Proto) Reset() { *m = Integer64Proto{} } func (m *Integer64Proto) String() string { return proto.CompactTextString(m) } func (*Integer64Proto) ProtoMessage() {} func (m *Integer64Proto) GetValue() int64 { if m != nil && m.Value != nil { return *m.Value } return 0 } type BoolProto struct { Value *bool `protobuf:"varint,1,req,name=value" json:"value,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *BoolProto) Reset() { *m = BoolProto{} } func (m *BoolProto) String() string { return proto.CompactTextString(m) } func (*BoolProto) ProtoMessage() {} func (m *BoolProto) GetValue() bool { if m != nil && m.Value != nil { return *m.Value } return false } type DoubleProto struct { Value *float64 `protobuf:"fixed64,1,req,name=value" json:"value,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *DoubleProto) Reset() { *m = DoubleProto{} } func (m *DoubleProto) String() string { return proto.CompactTextString(m) } func (*DoubleProto) ProtoMessage() {} func (m *DoubleProto) GetValue() float64 { if m != nil && m.Value != nil { return *m.Value } return 0 } type BytesProto struct { Value []byte `protobuf:"bytes,1,req,name=value" json:"value,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *BytesProto) Reset() { *m = BytesProto{} } func (m *BytesProto) String() string { return proto.CompactTextString(m) } func (*BytesProto) ProtoMessage() {} func (m *BytesProto) GetValue() []byte { if m != nil { return m.Value } return nil } type VoidProto struct { XXX_unrecognized []byte `json:"-"` } func (m *VoidProto) Reset() { *m = VoidProto{} } func (m *VoidProto) String() string { return proto.CompactTextString(m) } func (*VoidProto) ProtoMessage() {} ================================================ FILE: vendor/google.golang.org/appengine/internal/base/api_base.proto ================================================ // Built-in base types for API calls. Primarily useful as return types. syntax = "proto2"; option go_package = "base"; package appengine.base; message StringProto { required string value = 1; } message Integer32Proto { required int32 value = 1; } message Integer64Proto { required int64 value = 1; } message BoolProto { required bool value = 1; } message DoubleProto { required double value = 1; } message BytesProto { required bytes value = 1 [ctype=CORD]; } message VoidProto { } ================================================ FILE: vendor/google.golang.org/appengine/internal/datastore/datastore_v3.pb.go ================================================ // Code generated by protoc-gen-go. // source: google.golang.org/appengine/internal/datastore/datastore_v3.proto // DO NOT EDIT! /* Package datastore is a generated protocol buffer package. It is generated from these files: google.golang.org/appengine/internal/datastore/datastore_v3.proto It has these top-level messages: Action PropertyValue Property Path Reference User EntityProto CompositeProperty Index CompositeIndex IndexPostfix IndexPosition Snapshot InternalHeader Transaction Query CompiledQuery CompiledCursor Cursor Error Cost GetRequest GetResponse PutRequest PutResponse TouchRequest TouchResponse DeleteRequest DeleteResponse NextRequest QueryResult AllocateIdsRequest AllocateIdsResponse CompositeIndices AddActionsRequest AddActionsResponse BeginTransactionRequest CommitResponse */ package datastore import proto "github.com/golang/protobuf/proto" import fmt "fmt" import math "math" // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal var _ = fmt.Errorf var _ = math.Inf type Property_Meaning int32 const ( Property_NO_MEANING Property_Meaning = 0 Property_BLOB Property_Meaning = 14 Property_TEXT Property_Meaning = 15 Property_BYTESTRING Property_Meaning = 16 Property_ATOM_CATEGORY Property_Meaning = 1 Property_ATOM_LINK Property_Meaning = 2 Property_ATOM_TITLE Property_Meaning = 3 Property_ATOM_CONTENT Property_Meaning = 4 Property_ATOM_SUMMARY Property_Meaning = 5 Property_ATOM_AUTHOR Property_Meaning = 6 Property_GD_WHEN Property_Meaning = 7 Property_GD_EMAIL Property_Meaning = 8 Property_GEORSS_POINT Property_Meaning = 9 Property_GD_IM Property_Meaning = 10 Property_GD_PHONENUMBER Property_Meaning = 11 Property_GD_POSTALADDRESS Property_Meaning = 12 Property_GD_RATING Property_Meaning = 13 Property_BLOBKEY Property_Meaning = 17 Property_ENTITY_PROTO Property_Meaning = 19 Property_INDEX_VALUE Property_Meaning = 18 ) var Property_Meaning_name = map[int32]string{ 0: "NO_MEANING", 14: "BLOB", 15: "TEXT", 16: "BYTESTRING", 1: "ATOM_CATEGORY", 2: "ATOM_LINK", 3: "ATOM_TITLE", 4: "ATOM_CONTENT", 5: "ATOM_SUMMARY", 6: "ATOM_AUTHOR", 7: "GD_WHEN", 8: "GD_EMAIL", 9: "GEORSS_POINT", 10: "GD_IM", 11: "GD_PHONENUMBER", 12: "GD_POSTALADDRESS", 13: "GD_RATING", 17: "BLOBKEY", 19: "ENTITY_PROTO", 18: "INDEX_VALUE", } var Property_Meaning_value = map[string]int32{ "NO_MEANING": 0, "BLOB": 14, "TEXT": 15, "BYTESTRING": 16, "ATOM_CATEGORY": 1, "ATOM_LINK": 2, "ATOM_TITLE": 3, "ATOM_CONTENT": 4, "ATOM_SUMMARY": 5, "ATOM_AUTHOR": 6, "GD_WHEN": 7, "GD_EMAIL": 8, "GEORSS_POINT": 9, "GD_IM": 10, "GD_PHONENUMBER": 11, "GD_POSTALADDRESS": 12, "GD_RATING": 13, "BLOBKEY": 17, "ENTITY_PROTO": 19, "INDEX_VALUE": 18, } func (x Property_Meaning) Enum() *Property_Meaning { p := new(Property_Meaning) *p = x return p } func (x Property_Meaning) String() string { return proto.EnumName(Property_Meaning_name, int32(x)) } func (x *Property_Meaning) UnmarshalJSON(data []byte) error { value, err := proto.UnmarshalJSONEnum(Property_Meaning_value, data, "Property_Meaning") if err != nil { return err } *x = Property_Meaning(value) return nil } type Property_FtsTokenizationOption int32 const ( Property_HTML Property_FtsTokenizationOption = 1 Property_ATOM Property_FtsTokenizationOption = 2 ) var Property_FtsTokenizationOption_name = map[int32]string{ 1: "HTML", 2: "ATOM", } var Property_FtsTokenizationOption_value = map[string]int32{ "HTML": 1, "ATOM": 2, } func (x Property_FtsTokenizationOption) Enum() *Property_FtsTokenizationOption { p := new(Property_FtsTokenizationOption) *p = x return p } func (x Property_FtsTokenizationOption) String() string { return proto.EnumName(Property_FtsTokenizationOption_name, int32(x)) } func (x *Property_FtsTokenizationOption) UnmarshalJSON(data []byte) error { value, err := proto.UnmarshalJSONEnum(Property_FtsTokenizationOption_value, data, "Property_FtsTokenizationOption") if err != nil { return err } *x = Property_FtsTokenizationOption(value) return nil } type EntityProto_Kind int32 const ( EntityProto_GD_CONTACT EntityProto_Kind = 1 EntityProto_GD_EVENT EntityProto_Kind = 2 EntityProto_GD_MESSAGE EntityProto_Kind = 3 ) var EntityProto_Kind_name = map[int32]string{ 1: "GD_CONTACT", 2: "GD_EVENT", 3: "GD_MESSAGE", } var EntityProto_Kind_value = map[string]int32{ "GD_CONTACT": 1, "GD_EVENT": 2, "GD_MESSAGE": 3, } func (x EntityProto_Kind) Enum() *EntityProto_Kind { p := new(EntityProto_Kind) *p = x return p } func (x EntityProto_Kind) String() string { return proto.EnumName(EntityProto_Kind_name, int32(x)) } func (x *EntityProto_Kind) UnmarshalJSON(data []byte) error { value, err := proto.UnmarshalJSONEnum(EntityProto_Kind_value, data, "EntityProto_Kind") if err != nil { return err } *x = EntityProto_Kind(value) return nil } type Index_Property_Direction int32 const ( Index_Property_ASCENDING Index_Property_Direction = 1 Index_Property_DESCENDING Index_Property_Direction = 2 ) var Index_Property_Direction_name = map[int32]string{ 1: "ASCENDING", 2: "DESCENDING", } var Index_Property_Direction_value = map[string]int32{ "ASCENDING": 1, "DESCENDING": 2, } func (x Index_Property_Direction) Enum() *Index_Property_Direction { p := new(Index_Property_Direction) *p = x return p } func (x Index_Property_Direction) String() string { return proto.EnumName(Index_Property_Direction_name, int32(x)) } func (x *Index_Property_Direction) UnmarshalJSON(data []byte) error { value, err := proto.UnmarshalJSONEnum(Index_Property_Direction_value, data, "Index_Property_Direction") if err != nil { return err } *x = Index_Property_Direction(value) return nil } type CompositeIndex_State int32 const ( CompositeIndex_WRITE_ONLY CompositeIndex_State = 1 CompositeIndex_READ_WRITE CompositeIndex_State = 2 CompositeIndex_DELETED CompositeIndex_State = 3 CompositeIndex_ERROR CompositeIndex_State = 4 ) var CompositeIndex_State_name = map[int32]string{ 1: "WRITE_ONLY", 2: "READ_WRITE", 3: "DELETED", 4: "ERROR", } var CompositeIndex_State_value = map[string]int32{ "WRITE_ONLY": 1, "READ_WRITE": 2, "DELETED": 3, "ERROR": 4, } func (x CompositeIndex_State) Enum() *CompositeIndex_State { p := new(CompositeIndex_State) *p = x return p } func (x CompositeIndex_State) String() string { return proto.EnumName(CompositeIndex_State_name, int32(x)) } func (x *CompositeIndex_State) UnmarshalJSON(data []byte) error { value, err := proto.UnmarshalJSONEnum(CompositeIndex_State_value, data, "CompositeIndex_State") if err != nil { return err } *x = CompositeIndex_State(value) return nil } type Snapshot_Status int32 const ( Snapshot_INACTIVE Snapshot_Status = 0 Snapshot_ACTIVE Snapshot_Status = 1 ) var Snapshot_Status_name = map[int32]string{ 0: "INACTIVE", 1: "ACTIVE", } var Snapshot_Status_value = map[string]int32{ "INACTIVE": 0, "ACTIVE": 1, } func (x Snapshot_Status) Enum() *Snapshot_Status { p := new(Snapshot_Status) *p = x return p } func (x Snapshot_Status) String() string { return proto.EnumName(Snapshot_Status_name, int32(x)) } func (x *Snapshot_Status) UnmarshalJSON(data []byte) error { value, err := proto.UnmarshalJSONEnum(Snapshot_Status_value, data, "Snapshot_Status") if err != nil { return err } *x = Snapshot_Status(value) return nil } type Query_Hint int32 const ( Query_ORDER_FIRST Query_Hint = 1 Query_ANCESTOR_FIRST Query_Hint = 2 Query_FILTER_FIRST Query_Hint = 3 ) var Query_Hint_name = map[int32]string{ 1: "ORDER_FIRST", 2: "ANCESTOR_FIRST", 3: "FILTER_FIRST", } var Query_Hint_value = map[string]int32{ "ORDER_FIRST": 1, "ANCESTOR_FIRST": 2, "FILTER_FIRST": 3, } func (x Query_Hint) Enum() *Query_Hint { p := new(Query_Hint) *p = x return p } func (x Query_Hint) String() string { return proto.EnumName(Query_Hint_name, int32(x)) } func (x *Query_Hint) UnmarshalJSON(data []byte) error { value, err := proto.UnmarshalJSONEnum(Query_Hint_value, data, "Query_Hint") if err != nil { return err } *x = Query_Hint(value) return nil } type Query_Filter_Operator int32 const ( Query_Filter_LESS_THAN Query_Filter_Operator = 1 Query_Filter_LESS_THAN_OR_EQUAL Query_Filter_Operator = 2 Query_Filter_GREATER_THAN Query_Filter_Operator = 3 Query_Filter_GREATER_THAN_OR_EQUAL Query_Filter_Operator = 4 Query_Filter_EQUAL Query_Filter_Operator = 5 Query_Filter_IN Query_Filter_Operator = 6 Query_Filter_EXISTS Query_Filter_Operator = 7 ) var Query_Filter_Operator_name = map[int32]string{ 1: "LESS_THAN", 2: "LESS_THAN_OR_EQUAL", 3: "GREATER_THAN", 4: "GREATER_THAN_OR_EQUAL", 5: "EQUAL", 6: "IN", 7: "EXISTS", } var Query_Filter_Operator_value = map[string]int32{ "LESS_THAN": 1, "LESS_THAN_OR_EQUAL": 2, "GREATER_THAN": 3, "GREATER_THAN_OR_EQUAL": 4, "EQUAL": 5, "IN": 6, "EXISTS": 7, } func (x Query_Filter_Operator) Enum() *Query_Filter_Operator { p := new(Query_Filter_Operator) *p = x return p } func (x Query_Filter_Operator) String() string { return proto.EnumName(Query_Filter_Operator_name, int32(x)) } func (x *Query_Filter_Operator) UnmarshalJSON(data []byte) error { value, err := proto.UnmarshalJSONEnum(Query_Filter_Operator_value, data, "Query_Filter_Operator") if err != nil { return err } *x = Query_Filter_Operator(value) return nil } type Query_Order_Direction int32 const ( Query_Order_ASCENDING Query_Order_Direction = 1 Query_Order_DESCENDING Query_Order_Direction = 2 ) var Query_Order_Direction_name = map[int32]string{ 1: "ASCENDING", 2: "DESCENDING", } var Query_Order_Direction_value = map[string]int32{ "ASCENDING": 1, "DESCENDING": 2, } func (x Query_Order_Direction) Enum() *Query_Order_Direction { p := new(Query_Order_Direction) *p = x return p } func (x Query_Order_Direction) String() string { return proto.EnumName(Query_Order_Direction_name, int32(x)) } func (x *Query_Order_Direction) UnmarshalJSON(data []byte) error { value, err := proto.UnmarshalJSONEnum(Query_Order_Direction_value, data, "Query_Order_Direction") if err != nil { return err } *x = Query_Order_Direction(value) return nil } type Error_ErrorCode int32 const ( Error_BAD_REQUEST Error_ErrorCode = 1 Error_CONCURRENT_TRANSACTION Error_ErrorCode = 2 Error_INTERNAL_ERROR Error_ErrorCode = 3 Error_NEED_INDEX Error_ErrorCode = 4 Error_TIMEOUT Error_ErrorCode = 5 Error_PERMISSION_DENIED Error_ErrorCode = 6 Error_BIGTABLE_ERROR Error_ErrorCode = 7 Error_COMMITTED_BUT_STILL_APPLYING Error_ErrorCode = 8 Error_CAPABILITY_DISABLED Error_ErrorCode = 9 Error_TRY_ALTERNATE_BACKEND Error_ErrorCode = 10 Error_SAFE_TIME_TOO_OLD Error_ErrorCode = 11 ) var Error_ErrorCode_name = map[int32]string{ 1: "BAD_REQUEST", 2: "CONCURRENT_TRANSACTION", 3: "INTERNAL_ERROR", 4: "NEED_INDEX", 5: "TIMEOUT", 6: "PERMISSION_DENIED", 7: "BIGTABLE_ERROR", 8: "COMMITTED_BUT_STILL_APPLYING", 9: "CAPABILITY_DISABLED", 10: "TRY_ALTERNATE_BACKEND", 11: "SAFE_TIME_TOO_OLD", } var Error_ErrorCode_value = map[string]int32{ "BAD_REQUEST": 1, "CONCURRENT_TRANSACTION": 2, "INTERNAL_ERROR": 3, "NEED_INDEX": 4, "TIMEOUT": 5, "PERMISSION_DENIED": 6, "BIGTABLE_ERROR": 7, "COMMITTED_BUT_STILL_APPLYING": 8, "CAPABILITY_DISABLED": 9, "TRY_ALTERNATE_BACKEND": 10, "SAFE_TIME_TOO_OLD": 11, } func (x Error_ErrorCode) Enum() *Error_ErrorCode { p := new(Error_ErrorCode) *p = x return p } func (x Error_ErrorCode) String() string { return proto.EnumName(Error_ErrorCode_name, int32(x)) } func (x *Error_ErrorCode) UnmarshalJSON(data []byte) error { value, err := proto.UnmarshalJSONEnum(Error_ErrorCode_value, data, "Error_ErrorCode") if err != nil { return err } *x = Error_ErrorCode(value) return nil } type PutRequest_AutoIdPolicy int32 const ( PutRequest_CURRENT PutRequest_AutoIdPolicy = 0 PutRequest_SEQUENTIAL PutRequest_AutoIdPolicy = 1 ) var PutRequest_AutoIdPolicy_name = map[int32]string{ 0: "CURRENT", 1: "SEQUENTIAL", } var PutRequest_AutoIdPolicy_value = map[string]int32{ "CURRENT": 0, "SEQUENTIAL": 1, } func (x PutRequest_AutoIdPolicy) Enum() *PutRequest_AutoIdPolicy { p := new(PutRequest_AutoIdPolicy) *p = x return p } func (x PutRequest_AutoIdPolicy) String() string { return proto.EnumName(PutRequest_AutoIdPolicy_name, int32(x)) } func (x *PutRequest_AutoIdPolicy) UnmarshalJSON(data []byte) error { value, err := proto.UnmarshalJSONEnum(PutRequest_AutoIdPolicy_value, data, "PutRequest_AutoIdPolicy") if err != nil { return err } *x = PutRequest_AutoIdPolicy(value) return nil } type Action struct { XXX_unrecognized []byte `json:"-"` } func (m *Action) Reset() { *m = Action{} } func (m *Action) String() string { return proto.CompactTextString(m) } func (*Action) ProtoMessage() {} type PropertyValue struct { Int64Value *int64 `protobuf:"varint,1,opt,name=int64Value" json:"int64Value,omitempty"` BooleanValue *bool `protobuf:"varint,2,opt,name=booleanValue" json:"booleanValue,omitempty"` StringValue *string `protobuf:"bytes,3,opt,name=stringValue" json:"stringValue,omitempty"` DoubleValue *float64 `protobuf:"fixed64,4,opt,name=doubleValue" json:"doubleValue,omitempty"` Pointvalue *PropertyValue_PointValue `protobuf:"group,5,opt,name=PointValue" json:"pointvalue,omitempty"` Uservalue *PropertyValue_UserValue `protobuf:"group,8,opt,name=UserValue" json:"uservalue,omitempty"` Referencevalue *PropertyValue_ReferenceValue `protobuf:"group,12,opt,name=ReferenceValue" json:"referencevalue,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *PropertyValue) Reset() { *m = PropertyValue{} } func (m *PropertyValue) String() string { return proto.CompactTextString(m) } func (*PropertyValue) ProtoMessage() {} func (m *PropertyValue) GetInt64Value() int64 { if m != nil && m.Int64Value != nil { return *m.Int64Value } return 0 } func (m *PropertyValue) GetBooleanValue() bool { if m != nil && m.BooleanValue != nil { return *m.BooleanValue } return false } func (m *PropertyValue) GetStringValue() string { if m != nil && m.StringValue != nil { return *m.StringValue } return "" } func (m *PropertyValue) GetDoubleValue() float64 { if m != nil && m.DoubleValue != nil { return *m.DoubleValue } return 0 } func (m *PropertyValue) GetPointvalue() *PropertyValue_PointValue { if m != nil { return m.Pointvalue } return nil } func (m *PropertyValue) GetUservalue() *PropertyValue_UserValue { if m != nil { return m.Uservalue } return nil } func (m *PropertyValue) GetReferencevalue() *PropertyValue_ReferenceValue { if m != nil { return m.Referencevalue } return nil } type PropertyValue_PointValue struct { X *float64 `protobuf:"fixed64,6,req,name=x" json:"x,omitempty"` Y *float64 `protobuf:"fixed64,7,req,name=y" json:"y,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *PropertyValue_PointValue) Reset() { *m = PropertyValue_PointValue{} } func (m *PropertyValue_PointValue) String() string { return proto.CompactTextString(m) } func (*PropertyValue_PointValue) ProtoMessage() {} func (m *PropertyValue_PointValue) GetX() float64 { if m != nil && m.X != nil { return *m.X } return 0 } func (m *PropertyValue_PointValue) GetY() float64 { if m != nil && m.Y != nil { return *m.Y } return 0 } type PropertyValue_UserValue struct { Email *string `protobuf:"bytes,9,req,name=email" json:"email,omitempty"` AuthDomain *string `protobuf:"bytes,10,req,name=auth_domain" json:"auth_domain,omitempty"` Nickname *string `protobuf:"bytes,11,opt,name=nickname" json:"nickname,omitempty"` FederatedIdentity *string `protobuf:"bytes,21,opt,name=federated_identity" json:"federated_identity,omitempty"` FederatedProvider *string `protobuf:"bytes,22,opt,name=federated_provider" json:"federated_provider,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *PropertyValue_UserValue) Reset() { *m = PropertyValue_UserValue{} } func (m *PropertyValue_UserValue) String() string { return proto.CompactTextString(m) } func (*PropertyValue_UserValue) ProtoMessage() {} func (m *PropertyValue_UserValue) GetEmail() string { if m != nil && m.Email != nil { return *m.Email } return "" } func (m *PropertyValue_UserValue) GetAuthDomain() string { if m != nil && m.AuthDomain != nil { return *m.AuthDomain } return "" } func (m *PropertyValue_UserValue) GetNickname() string { if m != nil && m.Nickname != nil { return *m.Nickname } return "" } func (m *PropertyValue_UserValue) GetFederatedIdentity() string { if m != nil && m.FederatedIdentity != nil { return *m.FederatedIdentity } return "" } func (m *PropertyValue_UserValue) GetFederatedProvider() string { if m != nil && m.FederatedProvider != nil { return *m.FederatedProvider } return "" } type PropertyValue_ReferenceValue struct { App *string `protobuf:"bytes,13,req,name=app" json:"app,omitempty"` NameSpace *string `protobuf:"bytes,20,opt,name=name_space" json:"name_space,omitempty"` Pathelement []*PropertyValue_ReferenceValue_PathElement `protobuf:"group,14,rep,name=PathElement" json:"pathelement,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *PropertyValue_ReferenceValue) Reset() { *m = PropertyValue_ReferenceValue{} } func (m *PropertyValue_ReferenceValue) String() string { return proto.CompactTextString(m) } func (*PropertyValue_ReferenceValue) ProtoMessage() {} func (m *PropertyValue_ReferenceValue) GetApp() string { if m != nil && m.App != nil { return *m.App } return "" } func (m *PropertyValue_ReferenceValue) GetNameSpace() string { if m != nil && m.NameSpace != nil { return *m.NameSpace } return "" } func (m *PropertyValue_ReferenceValue) GetPathelement() []*PropertyValue_ReferenceValue_PathElement { if m != nil { return m.Pathelement } return nil } type PropertyValue_ReferenceValue_PathElement struct { Type *string `protobuf:"bytes,15,req,name=type" json:"type,omitempty"` Id *int64 `protobuf:"varint,16,opt,name=id" json:"id,omitempty"` Name *string `protobuf:"bytes,17,opt,name=name" json:"name,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *PropertyValue_ReferenceValue_PathElement) Reset() { *m = PropertyValue_ReferenceValue_PathElement{} } func (m *PropertyValue_ReferenceValue_PathElement) String() string { return proto.CompactTextString(m) } func (*PropertyValue_ReferenceValue_PathElement) ProtoMessage() {} func (m *PropertyValue_ReferenceValue_PathElement) GetType() string { if m != nil && m.Type != nil { return *m.Type } return "" } func (m *PropertyValue_ReferenceValue_PathElement) GetId() int64 { if m != nil && m.Id != nil { return *m.Id } return 0 } func (m *PropertyValue_ReferenceValue_PathElement) GetName() string { if m != nil && m.Name != nil { return *m.Name } return "" } type Property struct { Meaning *Property_Meaning `protobuf:"varint,1,opt,name=meaning,enum=appengine.Property_Meaning,def=0" json:"meaning,omitempty"` MeaningUri *string `protobuf:"bytes,2,opt,name=meaning_uri" json:"meaning_uri,omitempty"` Name *string `protobuf:"bytes,3,req,name=name" json:"name,omitempty"` Value *PropertyValue `protobuf:"bytes,5,req,name=value" json:"value,omitempty"` Multiple *bool `protobuf:"varint,4,req,name=multiple" json:"multiple,omitempty"` Searchable *bool `protobuf:"varint,6,opt,name=searchable,def=0" json:"searchable,omitempty"` FtsTokenizationOption *Property_FtsTokenizationOption `protobuf:"varint,8,opt,name=fts_tokenization_option,enum=appengine.Property_FtsTokenizationOption" json:"fts_tokenization_option,omitempty"` Locale *string `protobuf:"bytes,9,opt,name=locale,def=en" json:"locale,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *Property) Reset() { *m = Property{} } func (m *Property) String() string { return proto.CompactTextString(m) } func (*Property) ProtoMessage() {} const Default_Property_Meaning Property_Meaning = Property_NO_MEANING const Default_Property_Searchable bool = false const Default_Property_Locale string = "en" func (m *Property) GetMeaning() Property_Meaning { if m != nil && m.Meaning != nil { return *m.Meaning } return Default_Property_Meaning } func (m *Property) GetMeaningUri() string { if m != nil && m.MeaningUri != nil { return *m.MeaningUri } return "" } func (m *Property) GetName() string { if m != nil && m.Name != nil { return *m.Name } return "" } func (m *Property) GetValue() *PropertyValue { if m != nil { return m.Value } return nil } func (m *Property) GetMultiple() bool { if m != nil && m.Multiple != nil { return *m.Multiple } return false } func (m *Property) GetSearchable() bool { if m != nil && m.Searchable != nil { return *m.Searchable } return Default_Property_Searchable } func (m *Property) GetFtsTokenizationOption() Property_FtsTokenizationOption { if m != nil && m.FtsTokenizationOption != nil { return *m.FtsTokenizationOption } return Property_HTML } func (m *Property) GetLocale() string { if m != nil && m.Locale != nil { return *m.Locale } return Default_Property_Locale } type Path struct { Element []*Path_Element `protobuf:"group,1,rep,name=Element" json:"element,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *Path) Reset() { *m = Path{} } func (m *Path) String() string { return proto.CompactTextString(m) } func (*Path) ProtoMessage() {} func (m *Path) GetElement() []*Path_Element { if m != nil { return m.Element } return nil } type Path_Element struct { Type *string `protobuf:"bytes,2,req,name=type" json:"type,omitempty"` Id *int64 `protobuf:"varint,3,opt,name=id" json:"id,omitempty"` Name *string `protobuf:"bytes,4,opt,name=name" json:"name,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *Path_Element) Reset() { *m = Path_Element{} } func (m *Path_Element) String() string { return proto.CompactTextString(m) } func (*Path_Element) ProtoMessage() {} func (m *Path_Element) GetType() string { if m != nil && m.Type != nil { return *m.Type } return "" } func (m *Path_Element) GetId() int64 { if m != nil && m.Id != nil { return *m.Id } return 0 } func (m *Path_Element) GetName() string { if m != nil && m.Name != nil { return *m.Name } return "" } type Reference struct { App *string `protobuf:"bytes,13,req,name=app" json:"app,omitempty"` NameSpace *string `protobuf:"bytes,20,opt,name=name_space" json:"name_space,omitempty"` Path *Path `protobuf:"bytes,14,req,name=path" json:"path,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *Reference) Reset() { *m = Reference{} } func (m *Reference) String() string { return proto.CompactTextString(m) } func (*Reference) ProtoMessage() {} func (m *Reference) GetApp() string { if m != nil && m.App != nil { return *m.App } return "" } func (m *Reference) GetNameSpace() string { if m != nil && m.NameSpace != nil { return *m.NameSpace } return "" } func (m *Reference) GetPath() *Path { if m != nil { return m.Path } return nil } type User struct { Email *string `protobuf:"bytes,1,req,name=email" json:"email,omitempty"` AuthDomain *string `protobuf:"bytes,2,req,name=auth_domain" json:"auth_domain,omitempty"` Nickname *string `protobuf:"bytes,3,opt,name=nickname" json:"nickname,omitempty"` FederatedIdentity *string `protobuf:"bytes,6,opt,name=federated_identity" json:"federated_identity,omitempty"` FederatedProvider *string `protobuf:"bytes,7,opt,name=federated_provider" json:"federated_provider,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *User) Reset() { *m = User{} } func (m *User) String() string { return proto.CompactTextString(m) } func (*User) ProtoMessage() {} func (m *User) GetEmail() string { if m != nil && m.Email != nil { return *m.Email } return "" } func (m *User) GetAuthDomain() string { if m != nil && m.AuthDomain != nil { return *m.AuthDomain } return "" } func (m *User) GetNickname() string { if m != nil && m.Nickname != nil { return *m.Nickname } return "" } func (m *User) GetFederatedIdentity() string { if m != nil && m.FederatedIdentity != nil { return *m.FederatedIdentity } return "" } func (m *User) GetFederatedProvider() string { if m != nil && m.FederatedProvider != nil { return *m.FederatedProvider } return "" } type EntityProto struct { Key *Reference `protobuf:"bytes,13,req,name=key" json:"key,omitempty"` EntityGroup *Path `protobuf:"bytes,16,req,name=entity_group" json:"entity_group,omitempty"` Owner *User `protobuf:"bytes,17,opt,name=owner" json:"owner,omitempty"` Kind *EntityProto_Kind `protobuf:"varint,4,opt,name=kind,enum=appengine.EntityProto_Kind" json:"kind,omitempty"` KindUri *string `protobuf:"bytes,5,opt,name=kind_uri" json:"kind_uri,omitempty"` Property []*Property `protobuf:"bytes,14,rep,name=property" json:"property,omitempty"` RawProperty []*Property `protobuf:"bytes,15,rep,name=raw_property" json:"raw_property,omitempty"` Rank *int32 `protobuf:"varint,18,opt,name=rank" json:"rank,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *EntityProto) Reset() { *m = EntityProto{} } func (m *EntityProto) String() string { return proto.CompactTextString(m) } func (*EntityProto) ProtoMessage() {} func (m *EntityProto) GetKey() *Reference { if m != nil { return m.Key } return nil } func (m *EntityProto) GetEntityGroup() *Path { if m != nil { return m.EntityGroup } return nil } func (m *EntityProto) GetOwner() *User { if m != nil { return m.Owner } return nil } func (m *EntityProto) GetKind() EntityProto_Kind { if m != nil && m.Kind != nil { return *m.Kind } return EntityProto_GD_CONTACT } func (m *EntityProto) GetKindUri() string { if m != nil && m.KindUri != nil { return *m.KindUri } return "" } func (m *EntityProto) GetProperty() []*Property { if m != nil { return m.Property } return nil } func (m *EntityProto) GetRawProperty() []*Property { if m != nil { return m.RawProperty } return nil } func (m *EntityProto) GetRank() int32 { if m != nil && m.Rank != nil { return *m.Rank } return 0 } type CompositeProperty struct { IndexId *int64 `protobuf:"varint,1,req,name=index_id" json:"index_id,omitempty"` Value []string `protobuf:"bytes,2,rep,name=value" json:"value,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *CompositeProperty) Reset() { *m = CompositeProperty{} } func (m *CompositeProperty) String() string { return proto.CompactTextString(m) } func (*CompositeProperty) ProtoMessage() {} func (m *CompositeProperty) GetIndexId() int64 { if m != nil && m.IndexId != nil { return *m.IndexId } return 0 } func (m *CompositeProperty) GetValue() []string { if m != nil { return m.Value } return nil } type Index struct { EntityType *string `protobuf:"bytes,1,req,name=entity_type" json:"entity_type,omitempty"` Ancestor *bool `protobuf:"varint,5,req,name=ancestor" json:"ancestor,omitempty"` Property []*Index_Property `protobuf:"group,2,rep,name=Property" json:"property,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *Index) Reset() { *m = Index{} } func (m *Index) String() string { return proto.CompactTextString(m) } func (*Index) ProtoMessage() {} func (m *Index) GetEntityType() string { if m != nil && m.EntityType != nil { return *m.EntityType } return "" } func (m *Index) GetAncestor() bool { if m != nil && m.Ancestor != nil { return *m.Ancestor } return false } func (m *Index) GetProperty() []*Index_Property { if m != nil { return m.Property } return nil } type Index_Property struct { Name *string `protobuf:"bytes,3,req,name=name" json:"name,omitempty"` Direction *Index_Property_Direction `protobuf:"varint,4,opt,name=direction,enum=appengine.Index_Property_Direction,def=1" json:"direction,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *Index_Property) Reset() { *m = Index_Property{} } func (m *Index_Property) String() string { return proto.CompactTextString(m) } func (*Index_Property) ProtoMessage() {} const Default_Index_Property_Direction Index_Property_Direction = Index_Property_ASCENDING func (m *Index_Property) GetName() string { if m != nil && m.Name != nil { return *m.Name } return "" } func (m *Index_Property) GetDirection() Index_Property_Direction { if m != nil && m.Direction != nil { return *m.Direction } return Default_Index_Property_Direction } type CompositeIndex struct { AppId *string `protobuf:"bytes,1,req,name=app_id" json:"app_id,omitempty"` Id *int64 `protobuf:"varint,2,req,name=id" json:"id,omitempty"` Definition *Index `protobuf:"bytes,3,req,name=definition" json:"definition,omitempty"` State *CompositeIndex_State `protobuf:"varint,4,req,name=state,enum=appengine.CompositeIndex_State" json:"state,omitempty"` OnlyUseIfRequired *bool `protobuf:"varint,6,opt,name=only_use_if_required,def=0" json:"only_use_if_required,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *CompositeIndex) Reset() { *m = CompositeIndex{} } func (m *CompositeIndex) String() string { return proto.CompactTextString(m) } func (*CompositeIndex) ProtoMessage() {} const Default_CompositeIndex_OnlyUseIfRequired bool = false func (m *CompositeIndex) GetAppId() string { if m != nil && m.AppId != nil { return *m.AppId } return "" } func (m *CompositeIndex) GetId() int64 { if m != nil && m.Id != nil { return *m.Id } return 0 } func (m *CompositeIndex) GetDefinition() *Index { if m != nil { return m.Definition } return nil } func (m *CompositeIndex) GetState() CompositeIndex_State { if m != nil && m.State != nil { return *m.State } return CompositeIndex_WRITE_ONLY } func (m *CompositeIndex) GetOnlyUseIfRequired() bool { if m != nil && m.OnlyUseIfRequired != nil { return *m.OnlyUseIfRequired } return Default_CompositeIndex_OnlyUseIfRequired } type IndexPostfix struct { IndexValue []*IndexPostfix_IndexValue `protobuf:"bytes,1,rep,name=index_value" json:"index_value,omitempty"` Key *Reference `protobuf:"bytes,2,opt,name=key" json:"key,omitempty"` Before *bool `protobuf:"varint,3,opt,name=before,def=1" json:"before,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *IndexPostfix) Reset() { *m = IndexPostfix{} } func (m *IndexPostfix) String() string { return proto.CompactTextString(m) } func (*IndexPostfix) ProtoMessage() {} const Default_IndexPostfix_Before bool = true func (m *IndexPostfix) GetIndexValue() []*IndexPostfix_IndexValue { if m != nil { return m.IndexValue } return nil } func (m *IndexPostfix) GetKey() *Reference { if m != nil { return m.Key } return nil } func (m *IndexPostfix) GetBefore() bool { if m != nil && m.Before != nil { return *m.Before } return Default_IndexPostfix_Before } type IndexPostfix_IndexValue struct { PropertyName *string `protobuf:"bytes,1,req,name=property_name" json:"property_name,omitempty"` Value *PropertyValue `protobuf:"bytes,2,req,name=value" json:"value,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *IndexPostfix_IndexValue) Reset() { *m = IndexPostfix_IndexValue{} } func (m *IndexPostfix_IndexValue) String() string { return proto.CompactTextString(m) } func (*IndexPostfix_IndexValue) ProtoMessage() {} func (m *IndexPostfix_IndexValue) GetPropertyName() string { if m != nil && m.PropertyName != nil { return *m.PropertyName } return "" } func (m *IndexPostfix_IndexValue) GetValue() *PropertyValue { if m != nil { return m.Value } return nil } type IndexPosition struct { Key *string `protobuf:"bytes,1,opt,name=key" json:"key,omitempty"` Before *bool `protobuf:"varint,2,opt,name=before,def=1" json:"before,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *IndexPosition) Reset() { *m = IndexPosition{} } func (m *IndexPosition) String() string { return proto.CompactTextString(m) } func (*IndexPosition) ProtoMessage() {} const Default_IndexPosition_Before bool = true func (m *IndexPosition) GetKey() string { if m != nil && m.Key != nil { return *m.Key } return "" } func (m *IndexPosition) GetBefore() bool { if m != nil && m.Before != nil { return *m.Before } return Default_IndexPosition_Before } type Snapshot struct { Ts *int64 `protobuf:"varint,1,req,name=ts" json:"ts,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *Snapshot) Reset() { *m = Snapshot{} } func (m *Snapshot) String() string { return proto.CompactTextString(m) } func (*Snapshot) ProtoMessage() {} func (m *Snapshot) GetTs() int64 { if m != nil && m.Ts != nil { return *m.Ts } return 0 } type InternalHeader struct { Qos *string `protobuf:"bytes,1,opt,name=qos" json:"qos,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *InternalHeader) Reset() { *m = InternalHeader{} } func (m *InternalHeader) String() string { return proto.CompactTextString(m) } func (*InternalHeader) ProtoMessage() {} func (m *InternalHeader) GetQos() string { if m != nil && m.Qos != nil { return *m.Qos } return "" } type Transaction struct { Header *InternalHeader `protobuf:"bytes,4,opt,name=header" json:"header,omitempty"` Handle *uint64 `protobuf:"fixed64,1,req,name=handle" json:"handle,omitempty"` App *string `protobuf:"bytes,2,req,name=app" json:"app,omitempty"` MarkChanges *bool `protobuf:"varint,3,opt,name=mark_changes,def=0" json:"mark_changes,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *Transaction) Reset() { *m = Transaction{} } func (m *Transaction) String() string { return proto.CompactTextString(m) } func (*Transaction) ProtoMessage() {} const Default_Transaction_MarkChanges bool = false func (m *Transaction) GetHeader() *InternalHeader { if m != nil { return m.Header } return nil } func (m *Transaction) GetHandle() uint64 { if m != nil && m.Handle != nil { return *m.Handle } return 0 } func (m *Transaction) GetApp() string { if m != nil && m.App != nil { return *m.App } return "" } func (m *Transaction) GetMarkChanges() bool { if m != nil && m.MarkChanges != nil { return *m.MarkChanges } return Default_Transaction_MarkChanges } type Query struct { Header *InternalHeader `protobuf:"bytes,39,opt,name=header" json:"header,omitempty"` App *string `protobuf:"bytes,1,req,name=app" json:"app,omitempty"` NameSpace *string `protobuf:"bytes,29,opt,name=name_space" json:"name_space,omitempty"` Kind *string `protobuf:"bytes,3,opt,name=kind" json:"kind,omitempty"` Ancestor *Reference `protobuf:"bytes,17,opt,name=ancestor" json:"ancestor,omitempty"` Filter []*Query_Filter `protobuf:"group,4,rep,name=Filter" json:"filter,omitempty"` SearchQuery *string `protobuf:"bytes,8,opt,name=search_query" json:"search_query,omitempty"` Order []*Query_Order `protobuf:"group,9,rep,name=Order" json:"order,omitempty"` Hint *Query_Hint `protobuf:"varint,18,opt,name=hint,enum=appengine.Query_Hint" json:"hint,omitempty"` Count *int32 `protobuf:"varint,23,opt,name=count" json:"count,omitempty"` Offset *int32 `protobuf:"varint,12,opt,name=offset,def=0" json:"offset,omitempty"` Limit *int32 `protobuf:"varint,16,opt,name=limit" json:"limit,omitempty"` CompiledCursor *CompiledCursor `protobuf:"bytes,30,opt,name=compiled_cursor" json:"compiled_cursor,omitempty"` EndCompiledCursor *CompiledCursor `protobuf:"bytes,31,opt,name=end_compiled_cursor" json:"end_compiled_cursor,omitempty"` CompositeIndex []*CompositeIndex `protobuf:"bytes,19,rep,name=composite_index" json:"composite_index,omitempty"` RequirePerfectPlan *bool `protobuf:"varint,20,opt,name=require_perfect_plan,def=0" json:"require_perfect_plan,omitempty"` KeysOnly *bool `protobuf:"varint,21,opt,name=keys_only,def=0" json:"keys_only,omitempty"` Transaction *Transaction `protobuf:"bytes,22,opt,name=transaction" json:"transaction,omitempty"` Compile *bool `protobuf:"varint,25,opt,name=compile,def=0" json:"compile,omitempty"` FailoverMs *int64 `protobuf:"varint,26,opt,name=failover_ms" json:"failover_ms,omitempty"` Strong *bool `protobuf:"varint,32,opt,name=strong" json:"strong,omitempty"` PropertyName []string `protobuf:"bytes,33,rep,name=property_name" json:"property_name,omitempty"` GroupByPropertyName []string `protobuf:"bytes,34,rep,name=group_by_property_name" json:"group_by_property_name,omitempty"` Distinct *bool `protobuf:"varint,24,opt,name=distinct" json:"distinct,omitempty"` MinSafeTimeSeconds *int64 `protobuf:"varint,35,opt,name=min_safe_time_seconds" json:"min_safe_time_seconds,omitempty"` SafeReplicaName []string `protobuf:"bytes,36,rep,name=safe_replica_name" json:"safe_replica_name,omitempty"` PersistOffset *bool `protobuf:"varint,37,opt,name=persist_offset,def=0" json:"persist_offset,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *Query) Reset() { *m = Query{} } func (m *Query) String() string { return proto.CompactTextString(m) } func (*Query) ProtoMessage() {} const Default_Query_Offset int32 = 0 const Default_Query_RequirePerfectPlan bool = false const Default_Query_KeysOnly bool = false const Default_Query_Compile bool = false const Default_Query_PersistOffset bool = false func (m *Query) GetHeader() *InternalHeader { if m != nil { return m.Header } return nil } func (m *Query) GetApp() string { if m != nil && m.App != nil { return *m.App } return "" } func (m *Query) GetNameSpace() string { if m != nil && m.NameSpace != nil { return *m.NameSpace } return "" } func (m *Query) GetKind() string { if m != nil && m.Kind != nil { return *m.Kind } return "" } func (m *Query) GetAncestor() *Reference { if m != nil { return m.Ancestor } return nil } func (m *Query) GetFilter() []*Query_Filter { if m != nil { return m.Filter } return nil } func (m *Query) GetSearchQuery() string { if m != nil && m.SearchQuery != nil { return *m.SearchQuery } return "" } func (m *Query) GetOrder() []*Query_Order { if m != nil { return m.Order } return nil } func (m *Query) GetHint() Query_Hint { if m != nil && m.Hint != nil { return *m.Hint } return Query_ORDER_FIRST } func (m *Query) GetCount() int32 { if m != nil && m.Count != nil { return *m.Count } return 0 } func (m *Query) GetOffset() int32 { if m != nil && m.Offset != nil { return *m.Offset } return Default_Query_Offset } func (m *Query) GetLimit() int32 { if m != nil && m.Limit != nil { return *m.Limit } return 0 } func (m *Query) GetCompiledCursor() *CompiledCursor { if m != nil { return m.CompiledCursor } return nil } func (m *Query) GetEndCompiledCursor() *CompiledCursor { if m != nil { return m.EndCompiledCursor } return nil } func (m *Query) GetCompositeIndex() []*CompositeIndex { if m != nil { return m.CompositeIndex } return nil } func (m *Query) GetRequirePerfectPlan() bool { if m != nil && m.RequirePerfectPlan != nil { return *m.RequirePerfectPlan } return Default_Query_RequirePerfectPlan } func (m *Query) GetKeysOnly() bool { if m != nil && m.KeysOnly != nil { return *m.KeysOnly } return Default_Query_KeysOnly } func (m *Query) GetTransaction() *Transaction { if m != nil { return m.Transaction } return nil } func (m *Query) GetCompile() bool { if m != nil && m.Compile != nil { return *m.Compile } return Default_Query_Compile } func (m *Query) GetFailoverMs() int64 { if m != nil && m.FailoverMs != nil { return *m.FailoverMs } return 0 } func (m *Query) GetStrong() bool { if m != nil && m.Strong != nil { return *m.Strong } return false } func (m *Query) GetPropertyName() []string { if m != nil { return m.PropertyName } return nil } func (m *Query) GetGroupByPropertyName() []string { if m != nil { return m.GroupByPropertyName } return nil } func (m *Query) GetDistinct() bool { if m != nil && m.Distinct != nil { return *m.Distinct } return false } func (m *Query) GetMinSafeTimeSeconds() int64 { if m != nil && m.MinSafeTimeSeconds != nil { return *m.MinSafeTimeSeconds } return 0 } func (m *Query) GetSafeReplicaName() []string { if m != nil { return m.SafeReplicaName } return nil } func (m *Query) GetPersistOffset() bool { if m != nil && m.PersistOffset != nil { return *m.PersistOffset } return Default_Query_PersistOffset } type Query_Filter struct { Op *Query_Filter_Operator `protobuf:"varint,6,req,name=op,enum=appengine.Query_Filter_Operator" json:"op,omitempty"` Property []*Property `protobuf:"bytes,14,rep,name=property" json:"property,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *Query_Filter) Reset() { *m = Query_Filter{} } func (m *Query_Filter) String() string { return proto.CompactTextString(m) } func (*Query_Filter) ProtoMessage() {} func (m *Query_Filter) GetOp() Query_Filter_Operator { if m != nil && m.Op != nil { return *m.Op } return Query_Filter_LESS_THAN } func (m *Query_Filter) GetProperty() []*Property { if m != nil { return m.Property } return nil } type Query_Order struct { Property *string `protobuf:"bytes,10,req,name=property" json:"property,omitempty"` Direction *Query_Order_Direction `protobuf:"varint,11,opt,name=direction,enum=appengine.Query_Order_Direction,def=1" json:"direction,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *Query_Order) Reset() { *m = Query_Order{} } func (m *Query_Order) String() string { return proto.CompactTextString(m) } func (*Query_Order) ProtoMessage() {} const Default_Query_Order_Direction Query_Order_Direction = Query_Order_ASCENDING func (m *Query_Order) GetProperty() string { if m != nil && m.Property != nil { return *m.Property } return "" } func (m *Query_Order) GetDirection() Query_Order_Direction { if m != nil && m.Direction != nil { return *m.Direction } return Default_Query_Order_Direction } type CompiledQuery struct { Primaryscan *CompiledQuery_PrimaryScan `protobuf:"group,1,req,name=PrimaryScan" json:"primaryscan,omitempty"` Mergejoinscan []*CompiledQuery_MergeJoinScan `protobuf:"group,7,rep,name=MergeJoinScan" json:"mergejoinscan,omitempty"` IndexDef *Index `protobuf:"bytes,21,opt,name=index_def" json:"index_def,omitempty"` Offset *int32 `protobuf:"varint,10,opt,name=offset,def=0" json:"offset,omitempty"` Limit *int32 `protobuf:"varint,11,opt,name=limit" json:"limit,omitempty"` KeysOnly *bool `protobuf:"varint,12,req,name=keys_only" json:"keys_only,omitempty"` PropertyName []string `protobuf:"bytes,24,rep,name=property_name" json:"property_name,omitempty"` DistinctInfixSize *int32 `protobuf:"varint,25,opt,name=distinct_infix_size" json:"distinct_infix_size,omitempty"` Entityfilter *CompiledQuery_EntityFilter `protobuf:"group,13,opt,name=EntityFilter" json:"entityfilter,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *CompiledQuery) Reset() { *m = CompiledQuery{} } func (m *CompiledQuery) String() string { return proto.CompactTextString(m) } func (*CompiledQuery) ProtoMessage() {} const Default_CompiledQuery_Offset int32 = 0 func (m *CompiledQuery) GetPrimaryscan() *CompiledQuery_PrimaryScan { if m != nil { return m.Primaryscan } return nil } func (m *CompiledQuery) GetMergejoinscan() []*CompiledQuery_MergeJoinScan { if m != nil { return m.Mergejoinscan } return nil } func (m *CompiledQuery) GetIndexDef() *Index { if m != nil { return m.IndexDef } return nil } func (m *CompiledQuery) GetOffset() int32 { if m != nil && m.Offset != nil { return *m.Offset } return Default_CompiledQuery_Offset } func (m *CompiledQuery) GetLimit() int32 { if m != nil && m.Limit != nil { return *m.Limit } return 0 } func (m *CompiledQuery) GetKeysOnly() bool { if m != nil && m.KeysOnly != nil { return *m.KeysOnly } return false } func (m *CompiledQuery) GetPropertyName() []string { if m != nil { return m.PropertyName } return nil } func (m *CompiledQuery) GetDistinctInfixSize() int32 { if m != nil && m.DistinctInfixSize != nil { return *m.DistinctInfixSize } return 0 } func (m *CompiledQuery) GetEntityfilter() *CompiledQuery_EntityFilter { if m != nil { return m.Entityfilter } return nil } type CompiledQuery_PrimaryScan struct { IndexName *string `protobuf:"bytes,2,opt,name=index_name" json:"index_name,omitempty"` StartKey *string `protobuf:"bytes,3,opt,name=start_key" json:"start_key,omitempty"` StartInclusive *bool `protobuf:"varint,4,opt,name=start_inclusive" json:"start_inclusive,omitempty"` EndKey *string `protobuf:"bytes,5,opt,name=end_key" json:"end_key,omitempty"` EndInclusive *bool `protobuf:"varint,6,opt,name=end_inclusive" json:"end_inclusive,omitempty"` StartPostfixValue []string `protobuf:"bytes,22,rep,name=start_postfix_value" json:"start_postfix_value,omitempty"` EndPostfixValue []string `protobuf:"bytes,23,rep,name=end_postfix_value" json:"end_postfix_value,omitempty"` EndUnappliedLogTimestampUs *int64 `protobuf:"varint,19,opt,name=end_unapplied_log_timestamp_us" json:"end_unapplied_log_timestamp_us,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *CompiledQuery_PrimaryScan) Reset() { *m = CompiledQuery_PrimaryScan{} } func (m *CompiledQuery_PrimaryScan) String() string { return proto.CompactTextString(m) } func (*CompiledQuery_PrimaryScan) ProtoMessage() {} func (m *CompiledQuery_PrimaryScan) GetIndexName() string { if m != nil && m.IndexName != nil { return *m.IndexName } return "" } func (m *CompiledQuery_PrimaryScan) GetStartKey() string { if m != nil && m.StartKey != nil { return *m.StartKey } return "" } func (m *CompiledQuery_PrimaryScan) GetStartInclusive() bool { if m != nil && m.StartInclusive != nil { return *m.StartInclusive } return false } func (m *CompiledQuery_PrimaryScan) GetEndKey() string { if m != nil && m.EndKey != nil { return *m.EndKey } return "" } func (m *CompiledQuery_PrimaryScan) GetEndInclusive() bool { if m != nil && m.EndInclusive != nil { return *m.EndInclusive } return false } func (m *CompiledQuery_PrimaryScan) GetStartPostfixValue() []string { if m != nil { return m.StartPostfixValue } return nil } func (m *CompiledQuery_PrimaryScan) GetEndPostfixValue() []string { if m != nil { return m.EndPostfixValue } return nil } func (m *CompiledQuery_PrimaryScan) GetEndUnappliedLogTimestampUs() int64 { if m != nil && m.EndUnappliedLogTimestampUs != nil { return *m.EndUnappliedLogTimestampUs } return 0 } type CompiledQuery_MergeJoinScan struct { IndexName *string `protobuf:"bytes,8,req,name=index_name" json:"index_name,omitempty"` PrefixValue []string `protobuf:"bytes,9,rep,name=prefix_value" json:"prefix_value,omitempty"` ValuePrefix *bool `protobuf:"varint,20,opt,name=value_prefix,def=0" json:"value_prefix,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *CompiledQuery_MergeJoinScan) Reset() { *m = CompiledQuery_MergeJoinScan{} } func (m *CompiledQuery_MergeJoinScan) String() string { return proto.CompactTextString(m) } func (*CompiledQuery_MergeJoinScan) ProtoMessage() {} const Default_CompiledQuery_MergeJoinScan_ValuePrefix bool = false func (m *CompiledQuery_MergeJoinScan) GetIndexName() string { if m != nil && m.IndexName != nil { return *m.IndexName } return "" } func (m *CompiledQuery_MergeJoinScan) GetPrefixValue() []string { if m != nil { return m.PrefixValue } return nil } func (m *CompiledQuery_MergeJoinScan) GetValuePrefix() bool { if m != nil && m.ValuePrefix != nil { return *m.ValuePrefix } return Default_CompiledQuery_MergeJoinScan_ValuePrefix } type CompiledQuery_EntityFilter struct { Distinct *bool `protobuf:"varint,14,opt,name=distinct,def=0" json:"distinct,omitempty"` Kind *string `protobuf:"bytes,17,opt,name=kind" json:"kind,omitempty"` Ancestor *Reference `protobuf:"bytes,18,opt,name=ancestor" json:"ancestor,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *CompiledQuery_EntityFilter) Reset() { *m = CompiledQuery_EntityFilter{} } func (m *CompiledQuery_EntityFilter) String() string { return proto.CompactTextString(m) } func (*CompiledQuery_EntityFilter) ProtoMessage() {} const Default_CompiledQuery_EntityFilter_Distinct bool = false func (m *CompiledQuery_EntityFilter) GetDistinct() bool { if m != nil && m.Distinct != nil { return *m.Distinct } return Default_CompiledQuery_EntityFilter_Distinct } func (m *CompiledQuery_EntityFilter) GetKind() string { if m != nil && m.Kind != nil { return *m.Kind } return "" } func (m *CompiledQuery_EntityFilter) GetAncestor() *Reference { if m != nil { return m.Ancestor } return nil } type CompiledCursor struct { Position *CompiledCursor_Position `protobuf:"group,2,opt,name=Position" json:"position,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *CompiledCursor) Reset() { *m = CompiledCursor{} } func (m *CompiledCursor) String() string { return proto.CompactTextString(m) } func (*CompiledCursor) ProtoMessage() {} func (m *CompiledCursor) GetPosition() *CompiledCursor_Position { if m != nil { return m.Position } return nil } type CompiledCursor_Position struct { StartKey *string `protobuf:"bytes,27,opt,name=start_key" json:"start_key,omitempty"` Indexvalue []*CompiledCursor_Position_IndexValue `protobuf:"group,29,rep,name=IndexValue" json:"indexvalue,omitempty"` Key *Reference `protobuf:"bytes,32,opt,name=key" json:"key,omitempty"` StartInclusive *bool `protobuf:"varint,28,opt,name=start_inclusive,def=1" json:"start_inclusive,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *CompiledCursor_Position) Reset() { *m = CompiledCursor_Position{} } func (m *CompiledCursor_Position) String() string { return proto.CompactTextString(m) } func (*CompiledCursor_Position) ProtoMessage() {} const Default_CompiledCursor_Position_StartInclusive bool = true func (m *CompiledCursor_Position) GetStartKey() string { if m != nil && m.StartKey != nil { return *m.StartKey } return "" } func (m *CompiledCursor_Position) GetIndexvalue() []*CompiledCursor_Position_IndexValue { if m != nil { return m.Indexvalue } return nil } func (m *CompiledCursor_Position) GetKey() *Reference { if m != nil { return m.Key } return nil } func (m *CompiledCursor_Position) GetStartInclusive() bool { if m != nil && m.StartInclusive != nil { return *m.StartInclusive } return Default_CompiledCursor_Position_StartInclusive } type CompiledCursor_Position_IndexValue struct { Property *string `protobuf:"bytes,30,opt,name=property" json:"property,omitempty"` Value *PropertyValue `protobuf:"bytes,31,req,name=value" json:"value,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *CompiledCursor_Position_IndexValue) Reset() { *m = CompiledCursor_Position_IndexValue{} } func (m *CompiledCursor_Position_IndexValue) String() string { return proto.CompactTextString(m) } func (*CompiledCursor_Position_IndexValue) ProtoMessage() {} func (m *CompiledCursor_Position_IndexValue) GetProperty() string { if m != nil && m.Property != nil { return *m.Property } return "" } func (m *CompiledCursor_Position_IndexValue) GetValue() *PropertyValue { if m != nil { return m.Value } return nil } type Cursor struct { Cursor *uint64 `protobuf:"fixed64,1,req,name=cursor" json:"cursor,omitempty"` App *string `protobuf:"bytes,2,opt,name=app" json:"app,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *Cursor) Reset() { *m = Cursor{} } func (m *Cursor) String() string { return proto.CompactTextString(m) } func (*Cursor) ProtoMessage() {} func (m *Cursor) GetCursor() uint64 { if m != nil && m.Cursor != nil { return *m.Cursor } return 0 } func (m *Cursor) GetApp() string { if m != nil && m.App != nil { return *m.App } return "" } type Error struct { XXX_unrecognized []byte `json:"-"` } func (m *Error) Reset() { *m = Error{} } func (m *Error) String() string { return proto.CompactTextString(m) } func (*Error) ProtoMessage() {} type Cost struct { IndexWrites *int32 `protobuf:"varint,1,opt,name=index_writes" json:"index_writes,omitempty"` IndexWriteBytes *int32 `protobuf:"varint,2,opt,name=index_write_bytes" json:"index_write_bytes,omitempty"` EntityWrites *int32 `protobuf:"varint,3,opt,name=entity_writes" json:"entity_writes,omitempty"` EntityWriteBytes *int32 `protobuf:"varint,4,opt,name=entity_write_bytes" json:"entity_write_bytes,omitempty"` Commitcost *Cost_CommitCost `protobuf:"group,5,opt,name=CommitCost" json:"commitcost,omitempty"` ApproximateStorageDelta *int32 `protobuf:"varint,8,opt,name=approximate_storage_delta" json:"approximate_storage_delta,omitempty"` IdSequenceUpdates *int32 `protobuf:"varint,9,opt,name=id_sequence_updates" json:"id_sequence_updates,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *Cost) Reset() { *m = Cost{} } func (m *Cost) String() string { return proto.CompactTextString(m) } func (*Cost) ProtoMessage() {} func (m *Cost) GetIndexWrites() int32 { if m != nil && m.IndexWrites != nil { return *m.IndexWrites } return 0 } func (m *Cost) GetIndexWriteBytes() int32 { if m != nil && m.IndexWriteBytes != nil { return *m.IndexWriteBytes } return 0 } func (m *Cost) GetEntityWrites() int32 { if m != nil && m.EntityWrites != nil { return *m.EntityWrites } return 0 } func (m *Cost) GetEntityWriteBytes() int32 { if m != nil && m.EntityWriteBytes != nil { return *m.EntityWriteBytes } return 0 } func (m *Cost) GetCommitcost() *Cost_CommitCost { if m != nil { return m.Commitcost } return nil } func (m *Cost) GetApproximateStorageDelta() int32 { if m != nil && m.ApproximateStorageDelta != nil { return *m.ApproximateStorageDelta } return 0 } func (m *Cost) GetIdSequenceUpdates() int32 { if m != nil && m.IdSequenceUpdates != nil { return *m.IdSequenceUpdates } return 0 } type Cost_CommitCost struct { RequestedEntityPuts *int32 `protobuf:"varint,6,opt,name=requested_entity_puts" json:"requested_entity_puts,omitempty"` RequestedEntityDeletes *int32 `protobuf:"varint,7,opt,name=requested_entity_deletes" json:"requested_entity_deletes,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *Cost_CommitCost) Reset() { *m = Cost_CommitCost{} } func (m *Cost_CommitCost) String() string { return proto.CompactTextString(m) } func (*Cost_CommitCost) ProtoMessage() {} func (m *Cost_CommitCost) GetRequestedEntityPuts() int32 { if m != nil && m.RequestedEntityPuts != nil { return *m.RequestedEntityPuts } return 0 } func (m *Cost_CommitCost) GetRequestedEntityDeletes() int32 { if m != nil && m.RequestedEntityDeletes != nil { return *m.RequestedEntityDeletes } return 0 } type GetRequest struct { Header *InternalHeader `protobuf:"bytes,6,opt,name=header" json:"header,omitempty"` Key []*Reference `protobuf:"bytes,1,rep,name=key" json:"key,omitempty"` Transaction *Transaction `protobuf:"bytes,2,opt,name=transaction" json:"transaction,omitempty"` FailoverMs *int64 `protobuf:"varint,3,opt,name=failover_ms" json:"failover_ms,omitempty"` Strong *bool `protobuf:"varint,4,opt,name=strong" json:"strong,omitempty"` AllowDeferred *bool `protobuf:"varint,5,opt,name=allow_deferred,def=0" json:"allow_deferred,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *GetRequest) Reset() { *m = GetRequest{} } func (m *GetRequest) String() string { return proto.CompactTextString(m) } func (*GetRequest) ProtoMessage() {} const Default_GetRequest_AllowDeferred bool = false func (m *GetRequest) GetHeader() *InternalHeader { if m != nil { return m.Header } return nil } func (m *GetRequest) GetKey() []*Reference { if m != nil { return m.Key } return nil } func (m *GetRequest) GetTransaction() *Transaction { if m != nil { return m.Transaction } return nil } func (m *GetRequest) GetFailoverMs() int64 { if m != nil && m.FailoverMs != nil { return *m.FailoverMs } return 0 } func (m *GetRequest) GetStrong() bool { if m != nil && m.Strong != nil { return *m.Strong } return false } func (m *GetRequest) GetAllowDeferred() bool { if m != nil && m.AllowDeferred != nil { return *m.AllowDeferred } return Default_GetRequest_AllowDeferred } type GetResponse struct { Entity []*GetResponse_Entity `protobuf:"group,1,rep,name=Entity" json:"entity,omitempty"` Deferred []*Reference `protobuf:"bytes,5,rep,name=deferred" json:"deferred,omitempty"` InOrder *bool `protobuf:"varint,6,opt,name=in_order,def=1" json:"in_order,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *GetResponse) Reset() { *m = GetResponse{} } func (m *GetResponse) String() string { return proto.CompactTextString(m) } func (*GetResponse) ProtoMessage() {} const Default_GetResponse_InOrder bool = true func (m *GetResponse) GetEntity() []*GetResponse_Entity { if m != nil { return m.Entity } return nil } func (m *GetResponse) GetDeferred() []*Reference { if m != nil { return m.Deferred } return nil } func (m *GetResponse) GetInOrder() bool { if m != nil && m.InOrder != nil { return *m.InOrder } return Default_GetResponse_InOrder } type GetResponse_Entity struct { Entity *EntityProto `protobuf:"bytes,2,opt,name=entity" json:"entity,omitempty"` Key *Reference `protobuf:"bytes,4,opt,name=key" json:"key,omitempty"` Version *int64 `protobuf:"varint,3,opt,name=version" json:"version,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *GetResponse_Entity) Reset() { *m = GetResponse_Entity{} } func (m *GetResponse_Entity) String() string { return proto.CompactTextString(m) } func (*GetResponse_Entity) ProtoMessage() {} func (m *GetResponse_Entity) GetEntity() *EntityProto { if m != nil { return m.Entity } return nil } func (m *GetResponse_Entity) GetKey() *Reference { if m != nil { return m.Key } return nil } func (m *GetResponse_Entity) GetVersion() int64 { if m != nil && m.Version != nil { return *m.Version } return 0 } type PutRequest struct { Header *InternalHeader `protobuf:"bytes,11,opt,name=header" json:"header,omitempty"` Entity []*EntityProto `protobuf:"bytes,1,rep,name=entity" json:"entity,omitempty"` Transaction *Transaction `protobuf:"bytes,2,opt,name=transaction" json:"transaction,omitempty"` CompositeIndex []*CompositeIndex `protobuf:"bytes,3,rep,name=composite_index" json:"composite_index,omitempty"` Trusted *bool `protobuf:"varint,4,opt,name=trusted,def=0" json:"trusted,omitempty"` Force *bool `protobuf:"varint,7,opt,name=force,def=0" json:"force,omitempty"` MarkChanges *bool `protobuf:"varint,8,opt,name=mark_changes,def=0" json:"mark_changes,omitempty"` Snapshot []*Snapshot `protobuf:"bytes,9,rep,name=snapshot" json:"snapshot,omitempty"` AutoIdPolicy *PutRequest_AutoIdPolicy `protobuf:"varint,10,opt,name=auto_id_policy,enum=appengine.PutRequest_AutoIdPolicy,def=0" json:"auto_id_policy,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *PutRequest) Reset() { *m = PutRequest{} } func (m *PutRequest) String() string { return proto.CompactTextString(m) } func (*PutRequest) ProtoMessage() {} const Default_PutRequest_Trusted bool = false const Default_PutRequest_Force bool = false const Default_PutRequest_MarkChanges bool = false const Default_PutRequest_AutoIdPolicy PutRequest_AutoIdPolicy = PutRequest_CURRENT func (m *PutRequest) GetHeader() *InternalHeader { if m != nil { return m.Header } return nil } func (m *PutRequest) GetEntity() []*EntityProto { if m != nil { return m.Entity } return nil } func (m *PutRequest) GetTransaction() *Transaction { if m != nil { return m.Transaction } return nil } func (m *PutRequest) GetCompositeIndex() []*CompositeIndex { if m != nil { return m.CompositeIndex } return nil } func (m *PutRequest) GetTrusted() bool { if m != nil && m.Trusted != nil { return *m.Trusted } return Default_PutRequest_Trusted } func (m *PutRequest) GetForce() bool { if m != nil && m.Force != nil { return *m.Force } return Default_PutRequest_Force } func (m *PutRequest) GetMarkChanges() bool { if m != nil && m.MarkChanges != nil { return *m.MarkChanges } return Default_PutRequest_MarkChanges } func (m *PutRequest) GetSnapshot() []*Snapshot { if m != nil { return m.Snapshot } return nil } func (m *PutRequest) GetAutoIdPolicy() PutRequest_AutoIdPolicy { if m != nil && m.AutoIdPolicy != nil { return *m.AutoIdPolicy } return Default_PutRequest_AutoIdPolicy } type PutResponse struct { Key []*Reference `protobuf:"bytes,1,rep,name=key" json:"key,omitempty"` Cost *Cost `protobuf:"bytes,2,opt,name=cost" json:"cost,omitempty"` Version []int64 `protobuf:"varint,3,rep,name=version" json:"version,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *PutResponse) Reset() { *m = PutResponse{} } func (m *PutResponse) String() string { return proto.CompactTextString(m) } func (*PutResponse) ProtoMessage() {} func (m *PutResponse) GetKey() []*Reference { if m != nil { return m.Key } return nil } func (m *PutResponse) GetCost() *Cost { if m != nil { return m.Cost } return nil } func (m *PutResponse) GetVersion() []int64 { if m != nil { return m.Version } return nil } type TouchRequest struct { Header *InternalHeader `protobuf:"bytes,10,opt,name=header" json:"header,omitempty"` Key []*Reference `protobuf:"bytes,1,rep,name=key" json:"key,omitempty"` CompositeIndex []*CompositeIndex `protobuf:"bytes,2,rep,name=composite_index" json:"composite_index,omitempty"` Force *bool `protobuf:"varint,3,opt,name=force,def=0" json:"force,omitempty"` Snapshot []*Snapshot `protobuf:"bytes,9,rep,name=snapshot" json:"snapshot,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *TouchRequest) Reset() { *m = TouchRequest{} } func (m *TouchRequest) String() string { return proto.CompactTextString(m) } func (*TouchRequest) ProtoMessage() {} const Default_TouchRequest_Force bool = false func (m *TouchRequest) GetHeader() *InternalHeader { if m != nil { return m.Header } return nil } func (m *TouchRequest) GetKey() []*Reference { if m != nil { return m.Key } return nil } func (m *TouchRequest) GetCompositeIndex() []*CompositeIndex { if m != nil { return m.CompositeIndex } return nil } func (m *TouchRequest) GetForce() bool { if m != nil && m.Force != nil { return *m.Force } return Default_TouchRequest_Force } func (m *TouchRequest) GetSnapshot() []*Snapshot { if m != nil { return m.Snapshot } return nil } type TouchResponse struct { Cost *Cost `protobuf:"bytes,1,opt,name=cost" json:"cost,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *TouchResponse) Reset() { *m = TouchResponse{} } func (m *TouchResponse) String() string { return proto.CompactTextString(m) } func (*TouchResponse) ProtoMessage() {} func (m *TouchResponse) GetCost() *Cost { if m != nil { return m.Cost } return nil } type DeleteRequest struct { Header *InternalHeader `protobuf:"bytes,10,opt,name=header" json:"header,omitempty"` Key []*Reference `protobuf:"bytes,6,rep,name=key" json:"key,omitempty"` Transaction *Transaction `protobuf:"bytes,5,opt,name=transaction" json:"transaction,omitempty"` Trusted *bool `protobuf:"varint,4,opt,name=trusted,def=0" json:"trusted,omitempty"` Force *bool `protobuf:"varint,7,opt,name=force,def=0" json:"force,omitempty"` MarkChanges *bool `protobuf:"varint,8,opt,name=mark_changes,def=0" json:"mark_changes,omitempty"` Snapshot []*Snapshot `protobuf:"bytes,9,rep,name=snapshot" json:"snapshot,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *DeleteRequest) Reset() { *m = DeleteRequest{} } func (m *DeleteRequest) String() string { return proto.CompactTextString(m) } func (*DeleteRequest) ProtoMessage() {} const Default_DeleteRequest_Trusted bool = false const Default_DeleteRequest_Force bool = false const Default_DeleteRequest_MarkChanges bool = false func (m *DeleteRequest) GetHeader() *InternalHeader { if m != nil { return m.Header } return nil } func (m *DeleteRequest) GetKey() []*Reference { if m != nil { return m.Key } return nil } func (m *DeleteRequest) GetTransaction() *Transaction { if m != nil { return m.Transaction } return nil } func (m *DeleteRequest) GetTrusted() bool { if m != nil && m.Trusted != nil { return *m.Trusted } return Default_DeleteRequest_Trusted } func (m *DeleteRequest) GetForce() bool { if m != nil && m.Force != nil { return *m.Force } return Default_DeleteRequest_Force } func (m *DeleteRequest) GetMarkChanges() bool { if m != nil && m.MarkChanges != nil { return *m.MarkChanges } return Default_DeleteRequest_MarkChanges } func (m *DeleteRequest) GetSnapshot() []*Snapshot { if m != nil { return m.Snapshot } return nil } type DeleteResponse struct { Cost *Cost `protobuf:"bytes,1,opt,name=cost" json:"cost,omitempty"` Version []int64 `protobuf:"varint,3,rep,name=version" json:"version,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *DeleteResponse) Reset() { *m = DeleteResponse{} } func (m *DeleteResponse) String() string { return proto.CompactTextString(m) } func (*DeleteResponse) ProtoMessage() {} func (m *DeleteResponse) GetCost() *Cost { if m != nil { return m.Cost } return nil } func (m *DeleteResponse) GetVersion() []int64 { if m != nil { return m.Version } return nil } type NextRequest struct { Header *InternalHeader `protobuf:"bytes,5,opt,name=header" json:"header,omitempty"` Cursor *Cursor `protobuf:"bytes,1,req,name=cursor" json:"cursor,omitempty"` Count *int32 `protobuf:"varint,2,opt,name=count" json:"count,omitempty"` Offset *int32 `protobuf:"varint,4,opt,name=offset,def=0" json:"offset,omitempty"` Compile *bool `protobuf:"varint,3,opt,name=compile,def=0" json:"compile,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *NextRequest) Reset() { *m = NextRequest{} } func (m *NextRequest) String() string { return proto.CompactTextString(m) } func (*NextRequest) ProtoMessage() {} const Default_NextRequest_Offset int32 = 0 const Default_NextRequest_Compile bool = false func (m *NextRequest) GetHeader() *InternalHeader { if m != nil { return m.Header } return nil } func (m *NextRequest) GetCursor() *Cursor { if m != nil { return m.Cursor } return nil } func (m *NextRequest) GetCount() int32 { if m != nil && m.Count != nil { return *m.Count } return 0 } func (m *NextRequest) GetOffset() int32 { if m != nil && m.Offset != nil { return *m.Offset } return Default_NextRequest_Offset } func (m *NextRequest) GetCompile() bool { if m != nil && m.Compile != nil { return *m.Compile } return Default_NextRequest_Compile } type QueryResult struct { Cursor *Cursor `protobuf:"bytes,1,opt,name=cursor" json:"cursor,omitempty"` Result []*EntityProto `protobuf:"bytes,2,rep,name=result" json:"result,omitempty"` SkippedResults *int32 `protobuf:"varint,7,opt,name=skipped_results" json:"skipped_results,omitempty"` MoreResults *bool `protobuf:"varint,3,req,name=more_results" json:"more_results,omitempty"` KeysOnly *bool `protobuf:"varint,4,opt,name=keys_only" json:"keys_only,omitempty"` IndexOnly *bool `protobuf:"varint,9,opt,name=index_only" json:"index_only,omitempty"` SmallOps *bool `protobuf:"varint,10,opt,name=small_ops" json:"small_ops,omitempty"` CompiledQuery *CompiledQuery `protobuf:"bytes,5,opt,name=compiled_query" json:"compiled_query,omitempty"` CompiledCursor *CompiledCursor `protobuf:"bytes,6,opt,name=compiled_cursor" json:"compiled_cursor,omitempty"` Index []*CompositeIndex `protobuf:"bytes,8,rep,name=index" json:"index,omitempty"` Version []int64 `protobuf:"varint,11,rep,name=version" json:"version,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *QueryResult) Reset() { *m = QueryResult{} } func (m *QueryResult) String() string { return proto.CompactTextString(m) } func (*QueryResult) ProtoMessage() {} func (m *QueryResult) GetCursor() *Cursor { if m != nil { return m.Cursor } return nil } func (m *QueryResult) GetResult() []*EntityProto { if m != nil { return m.Result } return nil } func (m *QueryResult) GetSkippedResults() int32 { if m != nil && m.SkippedResults != nil { return *m.SkippedResults } return 0 } func (m *QueryResult) GetMoreResults() bool { if m != nil && m.MoreResults != nil { return *m.MoreResults } return false } func (m *QueryResult) GetKeysOnly() bool { if m != nil && m.KeysOnly != nil { return *m.KeysOnly } return false } func (m *QueryResult) GetIndexOnly() bool { if m != nil && m.IndexOnly != nil { return *m.IndexOnly } return false } func (m *QueryResult) GetSmallOps() bool { if m != nil && m.SmallOps != nil { return *m.SmallOps } return false } func (m *QueryResult) GetCompiledQuery() *CompiledQuery { if m != nil { return m.CompiledQuery } return nil } func (m *QueryResult) GetCompiledCursor() *CompiledCursor { if m != nil { return m.CompiledCursor } return nil } func (m *QueryResult) GetIndex() []*CompositeIndex { if m != nil { return m.Index } return nil } func (m *QueryResult) GetVersion() []int64 { if m != nil { return m.Version } return nil } type AllocateIdsRequest struct { Header *InternalHeader `protobuf:"bytes,4,opt,name=header" json:"header,omitempty"` ModelKey *Reference `protobuf:"bytes,1,opt,name=model_key" json:"model_key,omitempty"` Size *int64 `protobuf:"varint,2,opt,name=size" json:"size,omitempty"` Max *int64 `protobuf:"varint,3,opt,name=max" json:"max,omitempty"` Reserve []*Reference `protobuf:"bytes,5,rep,name=reserve" json:"reserve,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *AllocateIdsRequest) Reset() { *m = AllocateIdsRequest{} } func (m *AllocateIdsRequest) String() string { return proto.CompactTextString(m) } func (*AllocateIdsRequest) ProtoMessage() {} func (m *AllocateIdsRequest) GetHeader() *InternalHeader { if m != nil { return m.Header } return nil } func (m *AllocateIdsRequest) GetModelKey() *Reference { if m != nil { return m.ModelKey } return nil } func (m *AllocateIdsRequest) GetSize() int64 { if m != nil && m.Size != nil { return *m.Size } return 0 } func (m *AllocateIdsRequest) GetMax() int64 { if m != nil && m.Max != nil { return *m.Max } return 0 } func (m *AllocateIdsRequest) GetReserve() []*Reference { if m != nil { return m.Reserve } return nil } type AllocateIdsResponse struct { Start *int64 `protobuf:"varint,1,req,name=start" json:"start,omitempty"` End *int64 `protobuf:"varint,2,req,name=end" json:"end,omitempty"` Cost *Cost `protobuf:"bytes,3,opt,name=cost" json:"cost,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *AllocateIdsResponse) Reset() { *m = AllocateIdsResponse{} } func (m *AllocateIdsResponse) String() string { return proto.CompactTextString(m) } func (*AllocateIdsResponse) ProtoMessage() {} func (m *AllocateIdsResponse) GetStart() int64 { if m != nil && m.Start != nil { return *m.Start } return 0 } func (m *AllocateIdsResponse) GetEnd() int64 { if m != nil && m.End != nil { return *m.End } return 0 } func (m *AllocateIdsResponse) GetCost() *Cost { if m != nil { return m.Cost } return nil } type CompositeIndices struct { Index []*CompositeIndex `protobuf:"bytes,1,rep,name=index" json:"index,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *CompositeIndices) Reset() { *m = CompositeIndices{} } func (m *CompositeIndices) String() string { return proto.CompactTextString(m) } func (*CompositeIndices) ProtoMessage() {} func (m *CompositeIndices) GetIndex() []*CompositeIndex { if m != nil { return m.Index } return nil } type AddActionsRequest struct { Header *InternalHeader `protobuf:"bytes,3,opt,name=header" json:"header,omitempty"` Transaction *Transaction `protobuf:"bytes,1,req,name=transaction" json:"transaction,omitempty"` Action []*Action `protobuf:"bytes,2,rep,name=action" json:"action,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *AddActionsRequest) Reset() { *m = AddActionsRequest{} } func (m *AddActionsRequest) String() string { return proto.CompactTextString(m) } func (*AddActionsRequest) ProtoMessage() {} func (m *AddActionsRequest) GetHeader() *InternalHeader { if m != nil { return m.Header } return nil } func (m *AddActionsRequest) GetTransaction() *Transaction { if m != nil { return m.Transaction } return nil } func (m *AddActionsRequest) GetAction() []*Action { if m != nil { return m.Action } return nil } type AddActionsResponse struct { XXX_unrecognized []byte `json:"-"` } func (m *AddActionsResponse) Reset() { *m = AddActionsResponse{} } func (m *AddActionsResponse) String() string { return proto.CompactTextString(m) } func (*AddActionsResponse) ProtoMessage() {} type BeginTransactionRequest struct { Header *InternalHeader `protobuf:"bytes,3,opt,name=header" json:"header,omitempty"` App *string `protobuf:"bytes,1,req,name=app" json:"app,omitempty"` AllowMultipleEg *bool `protobuf:"varint,2,opt,name=allow_multiple_eg,def=0" json:"allow_multiple_eg,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *BeginTransactionRequest) Reset() { *m = BeginTransactionRequest{} } func (m *BeginTransactionRequest) String() string { return proto.CompactTextString(m) } func (*BeginTransactionRequest) ProtoMessage() {} const Default_BeginTransactionRequest_AllowMultipleEg bool = false func (m *BeginTransactionRequest) GetHeader() *InternalHeader { if m != nil { return m.Header } return nil } func (m *BeginTransactionRequest) GetApp() string { if m != nil && m.App != nil { return *m.App } return "" } func (m *BeginTransactionRequest) GetAllowMultipleEg() bool { if m != nil && m.AllowMultipleEg != nil { return *m.AllowMultipleEg } return Default_BeginTransactionRequest_AllowMultipleEg } type CommitResponse struct { Cost *Cost `protobuf:"bytes,1,opt,name=cost" json:"cost,omitempty"` Version []*CommitResponse_Version `protobuf:"group,3,rep,name=Version" json:"version,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *CommitResponse) Reset() { *m = CommitResponse{} } func (m *CommitResponse) String() string { return proto.CompactTextString(m) } func (*CommitResponse) ProtoMessage() {} func (m *CommitResponse) GetCost() *Cost { if m != nil { return m.Cost } return nil } func (m *CommitResponse) GetVersion() []*CommitResponse_Version { if m != nil { return m.Version } return nil } type CommitResponse_Version struct { RootEntityKey *Reference `protobuf:"bytes,4,req,name=root_entity_key" json:"root_entity_key,omitempty"` Version *int64 `protobuf:"varint,5,req,name=version" json:"version,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *CommitResponse_Version) Reset() { *m = CommitResponse_Version{} } func (m *CommitResponse_Version) String() string { return proto.CompactTextString(m) } func (*CommitResponse_Version) ProtoMessage() {} func (m *CommitResponse_Version) GetRootEntityKey() *Reference { if m != nil { return m.RootEntityKey } return nil } func (m *CommitResponse_Version) GetVersion() int64 { if m != nil && m.Version != nil { return *m.Version } return 0 } func init() { } ================================================ FILE: vendor/google.golang.org/appengine/internal/datastore/datastore_v3.proto ================================================ syntax = "proto2"; option go_package = "datastore"; package appengine; message Action{} message PropertyValue { optional int64 int64Value = 1; optional bool booleanValue = 2; optional string stringValue = 3; optional double doubleValue = 4; optional group PointValue = 5 { required double x = 6; required double y = 7; } optional group UserValue = 8 { required string email = 9; required string auth_domain = 10; optional string nickname = 11; optional string federated_identity = 21; optional string federated_provider = 22; } optional group ReferenceValue = 12 { required string app = 13; optional string name_space = 20; repeated group PathElement = 14 { required string type = 15; optional int64 id = 16; optional string name = 17; } } } message Property { enum Meaning { NO_MEANING = 0; BLOB = 14; TEXT = 15; BYTESTRING = 16; ATOM_CATEGORY = 1; ATOM_LINK = 2; ATOM_TITLE = 3; ATOM_CONTENT = 4; ATOM_SUMMARY = 5; ATOM_AUTHOR = 6; GD_WHEN = 7; GD_EMAIL = 8; GEORSS_POINT = 9; GD_IM = 10; GD_PHONENUMBER = 11; GD_POSTALADDRESS = 12; GD_RATING = 13; BLOBKEY = 17; ENTITY_PROTO = 19; INDEX_VALUE = 18; }; optional Meaning meaning = 1 [default = NO_MEANING]; optional string meaning_uri = 2; required string name = 3; required PropertyValue value = 5; required bool multiple = 4; optional bool searchable = 6 [default=false]; enum FtsTokenizationOption { HTML = 1; ATOM = 2; } optional FtsTokenizationOption fts_tokenization_option = 8; optional string locale = 9 [default = "en"]; } message Path { repeated group Element = 1 { required string type = 2; optional int64 id = 3; optional string name = 4; } } message Reference { required string app = 13; optional string name_space = 20; required Path path = 14; } message User { required string email = 1; required string auth_domain = 2; optional string nickname = 3; optional string federated_identity = 6; optional string federated_provider = 7; } message EntityProto { required Reference key = 13; required Path entity_group = 16; optional User owner = 17; enum Kind { GD_CONTACT = 1; GD_EVENT = 2; GD_MESSAGE = 3; } optional Kind kind = 4; optional string kind_uri = 5; repeated Property property = 14; repeated Property raw_property = 15; optional int32 rank = 18; } message CompositeProperty { required int64 index_id = 1; repeated string value = 2; } message Index { required string entity_type = 1; required bool ancestor = 5; repeated group Property = 2 { required string name = 3; enum Direction { ASCENDING = 1; DESCENDING = 2; } optional Direction direction = 4 [default = ASCENDING]; } } message CompositeIndex { required string app_id = 1; required int64 id = 2; required Index definition = 3; enum State { WRITE_ONLY = 1; READ_WRITE = 2; DELETED = 3; ERROR = 4; } required State state = 4; optional bool only_use_if_required = 6 [default = false]; } message IndexPostfix { message IndexValue { required string property_name = 1; required PropertyValue value = 2; } repeated IndexValue index_value = 1; optional Reference key = 2; optional bool before = 3 [default=true]; } message IndexPosition { optional string key = 1; optional bool before = 2 [default=true]; } message Snapshot { enum Status { INACTIVE = 0; ACTIVE = 1; } required int64 ts = 1; } message InternalHeader { optional string qos = 1; } message Transaction { optional InternalHeader header = 4; required fixed64 handle = 1; required string app = 2; optional bool mark_changes = 3 [default = false]; } message Query { optional InternalHeader header = 39; required string app = 1; optional string name_space = 29; optional string kind = 3; optional Reference ancestor = 17; repeated group Filter = 4 { enum Operator { LESS_THAN = 1; LESS_THAN_OR_EQUAL = 2; GREATER_THAN = 3; GREATER_THAN_OR_EQUAL = 4; EQUAL = 5; IN = 6; EXISTS = 7; } required Operator op = 6; repeated Property property = 14; } optional string search_query = 8; repeated group Order = 9 { enum Direction { ASCENDING = 1; DESCENDING = 2; } required string property = 10; optional Direction direction = 11 [default = ASCENDING]; } enum Hint { ORDER_FIRST = 1; ANCESTOR_FIRST = 2; FILTER_FIRST = 3; } optional Hint hint = 18; optional int32 count = 23; optional int32 offset = 12 [default = 0]; optional int32 limit = 16; optional CompiledCursor compiled_cursor = 30; optional CompiledCursor end_compiled_cursor = 31; repeated CompositeIndex composite_index = 19; optional bool require_perfect_plan = 20 [default = false]; optional bool keys_only = 21 [default = false]; optional Transaction transaction = 22; optional bool compile = 25 [default = false]; optional int64 failover_ms = 26; optional bool strong = 32; repeated string property_name = 33; repeated string group_by_property_name = 34; optional bool distinct = 24; optional int64 min_safe_time_seconds = 35; repeated string safe_replica_name = 36; optional bool persist_offset = 37 [default=false]; } message CompiledQuery { required group PrimaryScan = 1 { optional string index_name = 2; optional string start_key = 3; optional bool start_inclusive = 4; optional string end_key = 5; optional bool end_inclusive = 6; repeated string start_postfix_value = 22; repeated string end_postfix_value = 23; optional int64 end_unapplied_log_timestamp_us = 19; } repeated group MergeJoinScan = 7 { required string index_name = 8; repeated string prefix_value = 9; optional bool value_prefix = 20 [default=false]; } optional Index index_def = 21; optional int32 offset = 10 [default = 0]; optional int32 limit = 11; required bool keys_only = 12; repeated string property_name = 24; optional int32 distinct_infix_size = 25; optional group EntityFilter = 13 { optional bool distinct = 14 [default=false]; optional string kind = 17; optional Reference ancestor = 18; } } message CompiledCursor { optional group Position = 2 { optional string start_key = 27; repeated group IndexValue = 29 { optional string property = 30; required PropertyValue value = 31; } optional Reference key = 32; optional bool start_inclusive = 28 [default=true]; } } message Cursor { required fixed64 cursor = 1; optional string app = 2; } message Error { enum ErrorCode { BAD_REQUEST = 1; CONCURRENT_TRANSACTION = 2; INTERNAL_ERROR = 3; NEED_INDEX = 4; TIMEOUT = 5; PERMISSION_DENIED = 6; BIGTABLE_ERROR = 7; COMMITTED_BUT_STILL_APPLYING = 8; CAPABILITY_DISABLED = 9; TRY_ALTERNATE_BACKEND = 10; SAFE_TIME_TOO_OLD = 11; } } message Cost { optional int32 index_writes = 1; optional int32 index_write_bytes = 2; optional int32 entity_writes = 3; optional int32 entity_write_bytes = 4; optional group CommitCost = 5 { optional int32 requested_entity_puts = 6; optional int32 requested_entity_deletes = 7; }; optional int32 approximate_storage_delta = 8; optional int32 id_sequence_updates = 9; } message GetRequest { optional InternalHeader header = 6; repeated Reference key = 1; optional Transaction transaction = 2; optional int64 failover_ms = 3; optional bool strong = 4; optional bool allow_deferred = 5 [default=false]; } message GetResponse { repeated group Entity = 1 { optional EntityProto entity = 2; optional Reference key = 4; optional int64 version = 3; } repeated Reference deferred = 5; optional bool in_order = 6 [default=true]; } message PutRequest { optional InternalHeader header = 11; repeated EntityProto entity = 1; optional Transaction transaction = 2; repeated CompositeIndex composite_index = 3; optional bool trusted = 4 [default = false]; optional bool force = 7 [default = false]; optional bool mark_changes = 8 [default = false]; repeated Snapshot snapshot = 9; enum AutoIdPolicy { CURRENT = 0; SEQUENTIAL = 1; } optional AutoIdPolicy auto_id_policy = 10 [default = CURRENT]; } message PutResponse { repeated Reference key = 1; optional Cost cost = 2; repeated int64 version = 3; } message TouchRequest { optional InternalHeader header = 10; repeated Reference key = 1; repeated CompositeIndex composite_index = 2; optional bool force = 3 [default = false]; repeated Snapshot snapshot = 9; } message TouchResponse { optional Cost cost = 1; } message DeleteRequest { optional InternalHeader header = 10; repeated Reference key = 6; optional Transaction transaction = 5; optional bool trusted = 4 [default = false]; optional bool force = 7 [default = false]; optional bool mark_changes = 8 [default = false]; repeated Snapshot snapshot = 9; } message DeleteResponse { optional Cost cost = 1; repeated int64 version = 3; } message NextRequest { optional InternalHeader header = 5; required Cursor cursor = 1; optional int32 count = 2; optional int32 offset = 4 [default = 0]; optional bool compile = 3 [default = false]; } message QueryResult { optional Cursor cursor = 1; repeated EntityProto result = 2; optional int32 skipped_results = 7; required bool more_results = 3; optional bool keys_only = 4; optional bool index_only = 9; optional bool small_ops = 10; optional CompiledQuery compiled_query = 5; optional CompiledCursor compiled_cursor = 6; repeated CompositeIndex index = 8; repeated int64 version = 11; } message AllocateIdsRequest { optional InternalHeader header = 4; optional Reference model_key = 1; optional int64 size = 2; optional int64 max = 3; repeated Reference reserve = 5; } message AllocateIdsResponse { required int64 start = 1; required int64 end = 2; optional Cost cost = 3; } message CompositeIndices { repeated CompositeIndex index = 1; } message AddActionsRequest { optional InternalHeader header = 3; required Transaction transaction = 1; repeated Action action = 2; } message AddActionsResponse { } message BeginTransactionRequest { optional InternalHeader header = 3; required string app = 1; optional bool allow_multiple_eg = 2 [default = false]; } message CommitResponse { optional Cost cost = 1; repeated group Version = 3 { required Reference root_entity_key = 4; required int64 version = 5; } } ================================================ FILE: vendor/google.golang.org/appengine/internal/identity.go ================================================ // Copyright 2011 Google Inc. All rights reserved. // Use of this source code is governed by the Apache 2.0 // license that can be found in the LICENSE file. package internal import netcontext "golang.org/x/net/context" // These functions are implementations of the wrapper functions // in ../appengine/identity.go. See that file for commentary. func AppID(c netcontext.Context) string { return appID(FullyQualifiedAppID(c)) } ================================================ FILE: vendor/google.golang.org/appengine/internal/identity_classic.go ================================================ // Copyright 2015 Google Inc. All rights reserved. // Use of this source code is governed by the Apache 2.0 // license that can be found in the LICENSE file. // +build appengine package internal import ( "appengine" netcontext "golang.org/x/net/context" ) func DefaultVersionHostname(ctx netcontext.Context) string { return appengine.DefaultVersionHostname(fromContext(ctx)) } func RequestID(ctx netcontext.Context) string { return appengine.RequestID(fromContext(ctx)) } func Datacenter(_ netcontext.Context) string { return appengine.Datacenter() } func ServerSoftware() string { return appengine.ServerSoftware() } func ModuleName(ctx netcontext.Context) string { return appengine.ModuleName(fromContext(ctx)) } func VersionID(ctx netcontext.Context) string { return appengine.VersionID(fromContext(ctx)) } func InstanceID() string { return appengine.InstanceID() } func IsDevAppServer() bool { return appengine.IsDevAppServer() } func fullyQualifiedAppID(ctx netcontext.Context) string { return fromContext(ctx).FullyQualifiedAppID() } ================================================ FILE: vendor/google.golang.org/appengine/internal/identity_vm.go ================================================ // Copyright 2011 Google Inc. All rights reserved. // Use of this source code is governed by the Apache 2.0 // license that can be found in the LICENSE file. // +build !appengine package internal import ( "net/http" "os" netcontext "golang.org/x/net/context" ) // These functions are implementations of the wrapper functions // in ../appengine/identity.go. See that file for commentary. const ( hDefaultVersionHostname = "X-AppEngine-Default-Version-Hostname" hRequestLogId = "X-AppEngine-Request-Log-Id" hDatacenter = "X-AppEngine-Datacenter" ) func ctxHeaders(ctx netcontext.Context) http.Header { return fromContext(ctx).Request().Header } func DefaultVersionHostname(ctx netcontext.Context) string { return ctxHeaders(ctx).Get(hDefaultVersionHostname) } func RequestID(ctx netcontext.Context) string { return ctxHeaders(ctx).Get(hRequestLogId) } func Datacenter(ctx netcontext.Context) string { return ctxHeaders(ctx).Get(hDatacenter) } func ServerSoftware() string { // TODO(dsymonds): Remove fallback when we've verified this. if s := os.Getenv("SERVER_SOFTWARE"); s != "" { return s } return "Google App Engine/1.x.x" } // TODO(dsymonds): Remove the metadata fetches. func ModuleName(_ netcontext.Context) string { if s := os.Getenv("GAE_MODULE_NAME"); s != "" { return s } return string(mustGetMetadata("instance/attributes/gae_backend_name")) } func VersionID(_ netcontext.Context) string { if s1, s2 := os.Getenv("GAE_MODULE_VERSION"), os.Getenv("GAE_MINOR_VERSION"); s1 != "" && s2 != "" { return s1 + "." + s2 } return string(mustGetMetadata("instance/attributes/gae_backend_version")) + "." + string(mustGetMetadata("instance/attributes/gae_backend_minor_version")) } func InstanceID() string { if s := os.Getenv("GAE_MODULE_INSTANCE"); s != "" { return s } return string(mustGetMetadata("instance/attributes/gae_backend_instance")) } func partitionlessAppID() string { // gae_project has everything except the partition prefix. appID := os.Getenv("GAE_LONG_APP_ID") if appID == "" { appID = string(mustGetMetadata("instance/attributes/gae_project")) } return appID } func fullyQualifiedAppID(_ netcontext.Context) string { appID := partitionlessAppID() part := os.Getenv("GAE_PARTITION") if part == "" { part = string(mustGetMetadata("instance/attributes/gae_partition")) } if part != "" { appID = part + "~" + appID } return appID } func IsDevAppServer() bool { return os.Getenv("RUN_WITH_DEVAPPSERVER") != "" } ================================================ FILE: vendor/google.golang.org/appengine/internal/internal.go ================================================ // Copyright 2011 Google Inc. All rights reserved. // Use of this source code is governed by the Apache 2.0 // license that can be found in the LICENSE file. // Package internal provides support for package appengine. // // Programs should not use this package directly. Its API is not stable. // Use packages appengine and appengine/* instead. package internal import ( "fmt" "github.com/golang/protobuf/proto" remotepb "google.golang.org/appengine/internal/remote_api" ) // errorCodeMaps is a map of service name to the error code map for the service. var errorCodeMaps = make(map[string]map[int32]string) // RegisterErrorCodeMap is called from API implementations to register their // error code map. This should only be called from init functions. func RegisterErrorCodeMap(service string, m map[int32]string) { errorCodeMaps[service] = m } type timeoutCodeKey struct { service string code int32 } // timeoutCodes is the set of service+code pairs that represent timeouts. var timeoutCodes = make(map[timeoutCodeKey]bool) func RegisterTimeoutErrorCode(service string, code int32) { timeoutCodes[timeoutCodeKey{service, code}] = true } // APIError is the type returned by appengine.Context's Call method // when an API call fails in an API-specific way. This may be, for instance, // a taskqueue API call failing with TaskQueueServiceError::UNKNOWN_QUEUE. type APIError struct { Service string Detail string Code int32 // API-specific error code } func (e *APIError) Error() string { if e.Code == 0 { if e.Detail == "" { return "APIError " } return e.Detail } s := fmt.Sprintf("API error %d", e.Code) if m, ok := errorCodeMaps[e.Service]; ok { s += " (" + e.Service + ": " + m[e.Code] + ")" } else { // Shouldn't happen, but provide a bit more detail if it does. s = e.Service + " " + s } if e.Detail != "" { s += ": " + e.Detail } return s } func (e *APIError) IsTimeout() bool { return timeoutCodes[timeoutCodeKey{e.Service, e.Code}] } // CallError is the type returned by appengine.Context's Call method when an // API call fails in a generic way, such as RpcError::CAPABILITY_DISABLED. type CallError struct { Detail string Code int32 // TODO: Remove this if we get a distinguishable error code. Timeout bool } func (e *CallError) Error() string { var msg string switch remotepb.RpcError_ErrorCode(e.Code) { case remotepb.RpcError_UNKNOWN: return e.Detail case remotepb.RpcError_OVER_QUOTA: msg = "Over quota" case remotepb.RpcError_CAPABILITY_DISABLED: msg = "Capability disabled" case remotepb.RpcError_CANCELLED: msg = "Canceled" default: msg = fmt.Sprintf("Call error %d", e.Code) } s := msg + ": " + e.Detail if e.Timeout { s += " (timeout)" } return s } func (e *CallError) IsTimeout() bool { return e.Timeout } // NamespaceMods is a map from API service to a function that will mutate an RPC request to attach a namespace. // The function should be prepared to be called on the same message more than once; it should only modify the // RPC request the first time. var NamespaceMods = make(map[string]func(m proto.Message, namespace string)) ================================================ FILE: vendor/google.golang.org/appengine/internal/internal_vm_test.go ================================================ // Copyright 2014 Google Inc. All rights reserved. // Use of this source code is governed by the Apache 2.0 // license that can be found in the LICENSE file. // +build !appengine package internal import ( "io" "io/ioutil" "net/http" "net/http/httptest" "testing" ) func TestInstallingHealthChecker(t *testing.T) { try := func(desc string, mux *http.ServeMux, wantCode int, wantBody string) { installHealthChecker(mux) srv := httptest.NewServer(mux) defer srv.Close() resp, err := http.Get(srv.URL + "/_ah/health") if err != nil { t.Errorf("%s: http.Get: %v", desc, err) return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { t.Errorf("%s: reading body: %v", desc, err) return } if resp.StatusCode != wantCode { t.Errorf("%s: got HTTP %d, want %d", desc, resp.StatusCode, wantCode) return } if wantBody != "" && string(body) != wantBody { t.Errorf("%s: got HTTP body %q, want %q", desc, body, wantBody) return } } // If there's no handlers, or only a root handler, a health checker should be installed. try("empty mux", http.NewServeMux(), 200, "ok") mux := http.NewServeMux() mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { io.WriteString(w, "root handler") }) try("mux with root handler", mux, 200, "ok") // If there's a custom health check handler, one should not be installed. mux = http.NewServeMux() mux.HandleFunc("/_ah/health", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(418) io.WriteString(w, "I'm short and stout!") }) try("mux with custom health checker", mux, 418, "I'm short and stout!") } ================================================ FILE: vendor/google.golang.org/appengine/internal/log/log_service.pb.go ================================================ // Code generated by protoc-gen-go. // source: google.golang.org/appengine/internal/log/log_service.proto // DO NOT EDIT! /* Package log is a generated protocol buffer package. It is generated from these files: google.golang.org/appengine/internal/log/log_service.proto It has these top-level messages: LogServiceError UserAppLogLine UserAppLogGroup FlushRequest SetStatusRequest LogOffset LogLine RequestLog LogModuleVersion LogReadRequest LogReadResponse LogUsageRecord LogUsageRequest LogUsageResponse */ package log import proto "github.com/golang/protobuf/proto" import fmt "fmt" import math "math" // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal var _ = fmt.Errorf var _ = math.Inf type LogServiceError_ErrorCode int32 const ( LogServiceError_OK LogServiceError_ErrorCode = 0 LogServiceError_INVALID_REQUEST LogServiceError_ErrorCode = 1 LogServiceError_STORAGE_ERROR LogServiceError_ErrorCode = 2 ) var LogServiceError_ErrorCode_name = map[int32]string{ 0: "OK", 1: "INVALID_REQUEST", 2: "STORAGE_ERROR", } var LogServiceError_ErrorCode_value = map[string]int32{ "OK": 0, "INVALID_REQUEST": 1, "STORAGE_ERROR": 2, } func (x LogServiceError_ErrorCode) Enum() *LogServiceError_ErrorCode { p := new(LogServiceError_ErrorCode) *p = x return p } func (x LogServiceError_ErrorCode) String() string { return proto.EnumName(LogServiceError_ErrorCode_name, int32(x)) } func (x *LogServiceError_ErrorCode) UnmarshalJSON(data []byte) error { value, err := proto.UnmarshalJSONEnum(LogServiceError_ErrorCode_value, data, "LogServiceError_ErrorCode") if err != nil { return err } *x = LogServiceError_ErrorCode(value) return nil } type LogServiceError struct { XXX_unrecognized []byte `json:"-"` } func (m *LogServiceError) Reset() { *m = LogServiceError{} } func (m *LogServiceError) String() string { return proto.CompactTextString(m) } func (*LogServiceError) ProtoMessage() {} type UserAppLogLine struct { TimestampUsec *int64 `protobuf:"varint,1,req,name=timestamp_usec" json:"timestamp_usec,omitempty"` Level *int64 `protobuf:"varint,2,req,name=level" json:"level,omitempty"` Message *string `protobuf:"bytes,3,req,name=message" json:"message,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *UserAppLogLine) Reset() { *m = UserAppLogLine{} } func (m *UserAppLogLine) String() string { return proto.CompactTextString(m) } func (*UserAppLogLine) ProtoMessage() {} func (m *UserAppLogLine) GetTimestampUsec() int64 { if m != nil && m.TimestampUsec != nil { return *m.TimestampUsec } return 0 } func (m *UserAppLogLine) GetLevel() int64 { if m != nil && m.Level != nil { return *m.Level } return 0 } func (m *UserAppLogLine) GetMessage() string { if m != nil && m.Message != nil { return *m.Message } return "" } type UserAppLogGroup struct { LogLine []*UserAppLogLine `protobuf:"bytes,2,rep,name=log_line" json:"log_line,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *UserAppLogGroup) Reset() { *m = UserAppLogGroup{} } func (m *UserAppLogGroup) String() string { return proto.CompactTextString(m) } func (*UserAppLogGroup) ProtoMessage() {} func (m *UserAppLogGroup) GetLogLine() []*UserAppLogLine { if m != nil { return m.LogLine } return nil } type FlushRequest struct { Logs []byte `protobuf:"bytes,1,opt,name=logs" json:"logs,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *FlushRequest) Reset() { *m = FlushRequest{} } func (m *FlushRequest) String() string { return proto.CompactTextString(m) } func (*FlushRequest) ProtoMessage() {} func (m *FlushRequest) GetLogs() []byte { if m != nil { return m.Logs } return nil } type SetStatusRequest struct { Status *string `protobuf:"bytes,1,req,name=status" json:"status,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *SetStatusRequest) Reset() { *m = SetStatusRequest{} } func (m *SetStatusRequest) String() string { return proto.CompactTextString(m) } func (*SetStatusRequest) ProtoMessage() {} func (m *SetStatusRequest) GetStatus() string { if m != nil && m.Status != nil { return *m.Status } return "" } type LogOffset struct { RequestId []byte `protobuf:"bytes,1,opt,name=request_id" json:"request_id,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *LogOffset) Reset() { *m = LogOffset{} } func (m *LogOffset) String() string { return proto.CompactTextString(m) } func (*LogOffset) ProtoMessage() {} func (m *LogOffset) GetRequestId() []byte { if m != nil { return m.RequestId } return nil } type LogLine struct { Time *int64 `protobuf:"varint,1,req,name=time" json:"time,omitempty"` Level *int32 `protobuf:"varint,2,req,name=level" json:"level,omitempty"` LogMessage *string `protobuf:"bytes,3,req,name=log_message" json:"log_message,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *LogLine) Reset() { *m = LogLine{} } func (m *LogLine) String() string { return proto.CompactTextString(m) } func (*LogLine) ProtoMessage() {} func (m *LogLine) GetTime() int64 { if m != nil && m.Time != nil { return *m.Time } return 0 } func (m *LogLine) GetLevel() int32 { if m != nil && m.Level != nil { return *m.Level } return 0 } func (m *LogLine) GetLogMessage() string { if m != nil && m.LogMessage != nil { return *m.LogMessage } return "" } type RequestLog struct { AppId *string `protobuf:"bytes,1,req,name=app_id" json:"app_id,omitempty"` ModuleId *string `protobuf:"bytes,37,opt,name=module_id,def=default" json:"module_id,omitempty"` VersionId *string `protobuf:"bytes,2,req,name=version_id" json:"version_id,omitempty"` RequestId []byte `protobuf:"bytes,3,req,name=request_id" json:"request_id,omitempty"` Offset *LogOffset `protobuf:"bytes,35,opt,name=offset" json:"offset,omitempty"` Ip *string `protobuf:"bytes,4,req,name=ip" json:"ip,omitempty"` Nickname *string `protobuf:"bytes,5,opt,name=nickname" json:"nickname,omitempty"` StartTime *int64 `protobuf:"varint,6,req,name=start_time" json:"start_time,omitempty"` EndTime *int64 `protobuf:"varint,7,req,name=end_time" json:"end_time,omitempty"` Latency *int64 `protobuf:"varint,8,req,name=latency" json:"latency,omitempty"` Mcycles *int64 `protobuf:"varint,9,req,name=mcycles" json:"mcycles,omitempty"` Method *string `protobuf:"bytes,10,req,name=method" json:"method,omitempty"` Resource *string `protobuf:"bytes,11,req,name=resource" json:"resource,omitempty"` HttpVersion *string `protobuf:"bytes,12,req,name=http_version" json:"http_version,omitempty"` Status *int32 `protobuf:"varint,13,req,name=status" json:"status,omitempty"` ResponseSize *int64 `protobuf:"varint,14,req,name=response_size" json:"response_size,omitempty"` Referrer *string `protobuf:"bytes,15,opt,name=referrer" json:"referrer,omitempty"` UserAgent *string `protobuf:"bytes,16,opt,name=user_agent" json:"user_agent,omitempty"` UrlMapEntry *string `protobuf:"bytes,17,req,name=url_map_entry" json:"url_map_entry,omitempty"` Combined *string `protobuf:"bytes,18,req,name=combined" json:"combined,omitempty"` ApiMcycles *int64 `protobuf:"varint,19,opt,name=api_mcycles" json:"api_mcycles,omitempty"` Host *string `protobuf:"bytes,20,opt,name=host" json:"host,omitempty"` Cost *float64 `protobuf:"fixed64,21,opt,name=cost" json:"cost,omitempty"` TaskQueueName *string `protobuf:"bytes,22,opt,name=task_queue_name" json:"task_queue_name,omitempty"` TaskName *string `protobuf:"bytes,23,opt,name=task_name" json:"task_name,omitempty"` WasLoadingRequest *bool `protobuf:"varint,24,opt,name=was_loading_request" json:"was_loading_request,omitempty"` PendingTime *int64 `protobuf:"varint,25,opt,name=pending_time" json:"pending_time,omitempty"` ReplicaIndex *int32 `protobuf:"varint,26,opt,name=replica_index,def=-1" json:"replica_index,omitempty"` Finished *bool `protobuf:"varint,27,opt,name=finished,def=1" json:"finished,omitempty"` CloneKey []byte `protobuf:"bytes,28,opt,name=clone_key" json:"clone_key,omitempty"` Line []*LogLine `protobuf:"bytes,29,rep,name=line" json:"line,omitempty"` LinesIncomplete *bool `protobuf:"varint,36,opt,name=lines_incomplete" json:"lines_incomplete,omitempty"` AppEngineRelease []byte `protobuf:"bytes,38,opt,name=app_engine_release" json:"app_engine_release,omitempty"` ExitReason *int32 `protobuf:"varint,30,opt,name=exit_reason" json:"exit_reason,omitempty"` WasThrottledForTime *bool `protobuf:"varint,31,opt,name=was_throttled_for_time" json:"was_throttled_for_time,omitempty"` WasThrottledForRequests *bool `protobuf:"varint,32,opt,name=was_throttled_for_requests" json:"was_throttled_for_requests,omitempty"` ThrottledTime *int64 `protobuf:"varint,33,opt,name=throttled_time" json:"throttled_time,omitempty"` ServerName []byte `protobuf:"bytes,34,opt,name=server_name" json:"server_name,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *RequestLog) Reset() { *m = RequestLog{} } func (m *RequestLog) String() string { return proto.CompactTextString(m) } func (*RequestLog) ProtoMessage() {} const Default_RequestLog_ModuleId string = "default" const Default_RequestLog_ReplicaIndex int32 = -1 const Default_RequestLog_Finished bool = true func (m *RequestLog) GetAppId() string { if m != nil && m.AppId != nil { return *m.AppId } return "" } func (m *RequestLog) GetModuleId() string { if m != nil && m.ModuleId != nil { return *m.ModuleId } return Default_RequestLog_ModuleId } func (m *RequestLog) GetVersionId() string { if m != nil && m.VersionId != nil { return *m.VersionId } return "" } func (m *RequestLog) GetRequestId() []byte { if m != nil { return m.RequestId } return nil } func (m *RequestLog) GetOffset() *LogOffset { if m != nil { return m.Offset } return nil } func (m *RequestLog) GetIp() string { if m != nil && m.Ip != nil { return *m.Ip } return "" } func (m *RequestLog) GetNickname() string { if m != nil && m.Nickname != nil { return *m.Nickname } return "" } func (m *RequestLog) GetStartTime() int64 { if m != nil && m.StartTime != nil { return *m.StartTime } return 0 } func (m *RequestLog) GetEndTime() int64 { if m != nil && m.EndTime != nil { return *m.EndTime } return 0 } func (m *RequestLog) GetLatency() int64 { if m != nil && m.Latency != nil { return *m.Latency } return 0 } func (m *RequestLog) GetMcycles() int64 { if m != nil && m.Mcycles != nil { return *m.Mcycles } return 0 } func (m *RequestLog) GetMethod() string { if m != nil && m.Method != nil { return *m.Method } return "" } func (m *RequestLog) GetResource() string { if m != nil && m.Resource != nil { return *m.Resource } return "" } func (m *RequestLog) GetHttpVersion() string { if m != nil && m.HttpVersion != nil { return *m.HttpVersion } return "" } func (m *RequestLog) GetStatus() int32 { if m != nil && m.Status != nil { return *m.Status } return 0 } func (m *RequestLog) GetResponseSize() int64 { if m != nil && m.ResponseSize != nil { return *m.ResponseSize } return 0 } func (m *RequestLog) GetReferrer() string { if m != nil && m.Referrer != nil { return *m.Referrer } return "" } func (m *RequestLog) GetUserAgent() string { if m != nil && m.UserAgent != nil { return *m.UserAgent } return "" } func (m *RequestLog) GetUrlMapEntry() string { if m != nil && m.UrlMapEntry != nil { return *m.UrlMapEntry } return "" } func (m *RequestLog) GetCombined() string { if m != nil && m.Combined != nil { return *m.Combined } return "" } func (m *RequestLog) GetApiMcycles() int64 { if m != nil && m.ApiMcycles != nil { return *m.ApiMcycles } return 0 } func (m *RequestLog) GetHost() string { if m != nil && m.Host != nil { return *m.Host } return "" } func (m *RequestLog) GetCost() float64 { if m != nil && m.Cost != nil { return *m.Cost } return 0 } func (m *RequestLog) GetTaskQueueName() string { if m != nil && m.TaskQueueName != nil { return *m.TaskQueueName } return "" } func (m *RequestLog) GetTaskName() string { if m != nil && m.TaskName != nil { return *m.TaskName } return "" } func (m *RequestLog) GetWasLoadingRequest() bool { if m != nil && m.WasLoadingRequest != nil { return *m.WasLoadingRequest } return false } func (m *RequestLog) GetPendingTime() int64 { if m != nil && m.PendingTime != nil { return *m.PendingTime } return 0 } func (m *RequestLog) GetReplicaIndex() int32 { if m != nil && m.ReplicaIndex != nil { return *m.ReplicaIndex } return Default_RequestLog_ReplicaIndex } func (m *RequestLog) GetFinished() bool { if m != nil && m.Finished != nil { return *m.Finished } return Default_RequestLog_Finished } func (m *RequestLog) GetCloneKey() []byte { if m != nil { return m.CloneKey } return nil } func (m *RequestLog) GetLine() []*LogLine { if m != nil { return m.Line } return nil } func (m *RequestLog) GetLinesIncomplete() bool { if m != nil && m.LinesIncomplete != nil { return *m.LinesIncomplete } return false } func (m *RequestLog) GetAppEngineRelease() []byte { if m != nil { return m.AppEngineRelease } return nil } func (m *RequestLog) GetExitReason() int32 { if m != nil && m.ExitReason != nil { return *m.ExitReason } return 0 } func (m *RequestLog) GetWasThrottledForTime() bool { if m != nil && m.WasThrottledForTime != nil { return *m.WasThrottledForTime } return false } func (m *RequestLog) GetWasThrottledForRequests() bool { if m != nil && m.WasThrottledForRequests != nil { return *m.WasThrottledForRequests } return false } func (m *RequestLog) GetThrottledTime() int64 { if m != nil && m.ThrottledTime != nil { return *m.ThrottledTime } return 0 } func (m *RequestLog) GetServerName() []byte { if m != nil { return m.ServerName } return nil } type LogModuleVersion struct { ModuleId *string `protobuf:"bytes,1,opt,name=module_id,def=default" json:"module_id,omitempty"` VersionId *string `protobuf:"bytes,2,opt,name=version_id" json:"version_id,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *LogModuleVersion) Reset() { *m = LogModuleVersion{} } func (m *LogModuleVersion) String() string { return proto.CompactTextString(m) } func (*LogModuleVersion) ProtoMessage() {} const Default_LogModuleVersion_ModuleId string = "default" func (m *LogModuleVersion) GetModuleId() string { if m != nil && m.ModuleId != nil { return *m.ModuleId } return Default_LogModuleVersion_ModuleId } func (m *LogModuleVersion) GetVersionId() string { if m != nil && m.VersionId != nil { return *m.VersionId } return "" } type LogReadRequest struct { AppId *string `protobuf:"bytes,1,req,name=app_id" json:"app_id,omitempty"` VersionId []string `protobuf:"bytes,2,rep,name=version_id" json:"version_id,omitempty"` ModuleVersion []*LogModuleVersion `protobuf:"bytes,19,rep,name=module_version" json:"module_version,omitempty"` StartTime *int64 `protobuf:"varint,3,opt,name=start_time" json:"start_time,omitempty"` EndTime *int64 `protobuf:"varint,4,opt,name=end_time" json:"end_time,omitempty"` Offset *LogOffset `protobuf:"bytes,5,opt,name=offset" json:"offset,omitempty"` RequestId [][]byte `protobuf:"bytes,6,rep,name=request_id" json:"request_id,omitempty"` MinimumLogLevel *int32 `protobuf:"varint,7,opt,name=minimum_log_level" json:"minimum_log_level,omitempty"` IncludeIncomplete *bool `protobuf:"varint,8,opt,name=include_incomplete" json:"include_incomplete,omitempty"` Count *int64 `protobuf:"varint,9,opt,name=count" json:"count,omitempty"` CombinedLogRegex *string `protobuf:"bytes,14,opt,name=combined_log_regex" json:"combined_log_regex,omitempty"` HostRegex *string `protobuf:"bytes,15,opt,name=host_regex" json:"host_regex,omitempty"` ReplicaIndex *int32 `protobuf:"varint,16,opt,name=replica_index" json:"replica_index,omitempty"` IncludeAppLogs *bool `protobuf:"varint,10,opt,name=include_app_logs" json:"include_app_logs,omitempty"` AppLogsPerRequest *int32 `protobuf:"varint,17,opt,name=app_logs_per_request" json:"app_logs_per_request,omitempty"` IncludeHost *bool `protobuf:"varint,11,opt,name=include_host" json:"include_host,omitempty"` IncludeAll *bool `protobuf:"varint,12,opt,name=include_all" json:"include_all,omitempty"` CacheIterator *bool `protobuf:"varint,13,opt,name=cache_iterator" json:"cache_iterator,omitempty"` NumShards *int32 `protobuf:"varint,18,opt,name=num_shards" json:"num_shards,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *LogReadRequest) Reset() { *m = LogReadRequest{} } func (m *LogReadRequest) String() string { return proto.CompactTextString(m) } func (*LogReadRequest) ProtoMessage() {} func (m *LogReadRequest) GetAppId() string { if m != nil && m.AppId != nil { return *m.AppId } return "" } func (m *LogReadRequest) GetVersionId() []string { if m != nil { return m.VersionId } return nil } func (m *LogReadRequest) GetModuleVersion() []*LogModuleVersion { if m != nil { return m.ModuleVersion } return nil } func (m *LogReadRequest) GetStartTime() int64 { if m != nil && m.StartTime != nil { return *m.StartTime } return 0 } func (m *LogReadRequest) GetEndTime() int64 { if m != nil && m.EndTime != nil { return *m.EndTime } return 0 } func (m *LogReadRequest) GetOffset() *LogOffset { if m != nil { return m.Offset } return nil } func (m *LogReadRequest) GetRequestId() [][]byte { if m != nil { return m.RequestId } return nil } func (m *LogReadRequest) GetMinimumLogLevel() int32 { if m != nil && m.MinimumLogLevel != nil { return *m.MinimumLogLevel } return 0 } func (m *LogReadRequest) GetIncludeIncomplete() bool { if m != nil && m.IncludeIncomplete != nil { return *m.IncludeIncomplete } return false } func (m *LogReadRequest) GetCount() int64 { if m != nil && m.Count != nil { return *m.Count } return 0 } func (m *LogReadRequest) GetCombinedLogRegex() string { if m != nil && m.CombinedLogRegex != nil { return *m.CombinedLogRegex } return "" } func (m *LogReadRequest) GetHostRegex() string { if m != nil && m.HostRegex != nil { return *m.HostRegex } return "" } func (m *LogReadRequest) GetReplicaIndex() int32 { if m != nil && m.ReplicaIndex != nil { return *m.ReplicaIndex } return 0 } func (m *LogReadRequest) GetIncludeAppLogs() bool { if m != nil && m.IncludeAppLogs != nil { return *m.IncludeAppLogs } return false } func (m *LogReadRequest) GetAppLogsPerRequest() int32 { if m != nil && m.AppLogsPerRequest != nil { return *m.AppLogsPerRequest } return 0 } func (m *LogReadRequest) GetIncludeHost() bool { if m != nil && m.IncludeHost != nil { return *m.IncludeHost } return false } func (m *LogReadRequest) GetIncludeAll() bool { if m != nil && m.IncludeAll != nil { return *m.IncludeAll } return false } func (m *LogReadRequest) GetCacheIterator() bool { if m != nil && m.CacheIterator != nil { return *m.CacheIterator } return false } func (m *LogReadRequest) GetNumShards() int32 { if m != nil && m.NumShards != nil { return *m.NumShards } return 0 } type LogReadResponse struct { Log []*RequestLog `protobuf:"bytes,1,rep,name=log" json:"log,omitempty"` Offset *LogOffset `protobuf:"bytes,2,opt,name=offset" json:"offset,omitempty"` LastEndTime *int64 `protobuf:"varint,3,opt,name=last_end_time" json:"last_end_time,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *LogReadResponse) Reset() { *m = LogReadResponse{} } func (m *LogReadResponse) String() string { return proto.CompactTextString(m) } func (*LogReadResponse) ProtoMessage() {} func (m *LogReadResponse) GetLog() []*RequestLog { if m != nil { return m.Log } return nil } func (m *LogReadResponse) GetOffset() *LogOffset { if m != nil { return m.Offset } return nil } func (m *LogReadResponse) GetLastEndTime() int64 { if m != nil && m.LastEndTime != nil { return *m.LastEndTime } return 0 } type LogUsageRecord struct { VersionId *string `protobuf:"bytes,1,opt,name=version_id" json:"version_id,omitempty"` StartTime *int32 `protobuf:"varint,2,opt,name=start_time" json:"start_time,omitempty"` EndTime *int32 `protobuf:"varint,3,opt,name=end_time" json:"end_time,omitempty"` Count *int64 `protobuf:"varint,4,opt,name=count" json:"count,omitempty"` TotalSize *int64 `protobuf:"varint,5,opt,name=total_size" json:"total_size,omitempty"` Records *int32 `protobuf:"varint,6,opt,name=records" json:"records,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *LogUsageRecord) Reset() { *m = LogUsageRecord{} } func (m *LogUsageRecord) String() string { return proto.CompactTextString(m) } func (*LogUsageRecord) ProtoMessage() {} func (m *LogUsageRecord) GetVersionId() string { if m != nil && m.VersionId != nil { return *m.VersionId } return "" } func (m *LogUsageRecord) GetStartTime() int32 { if m != nil && m.StartTime != nil { return *m.StartTime } return 0 } func (m *LogUsageRecord) GetEndTime() int32 { if m != nil && m.EndTime != nil { return *m.EndTime } return 0 } func (m *LogUsageRecord) GetCount() int64 { if m != nil && m.Count != nil { return *m.Count } return 0 } func (m *LogUsageRecord) GetTotalSize() int64 { if m != nil && m.TotalSize != nil { return *m.TotalSize } return 0 } func (m *LogUsageRecord) GetRecords() int32 { if m != nil && m.Records != nil { return *m.Records } return 0 } type LogUsageRequest struct { AppId *string `protobuf:"bytes,1,req,name=app_id" json:"app_id,omitempty"` VersionId []string `protobuf:"bytes,2,rep,name=version_id" json:"version_id,omitempty"` StartTime *int32 `protobuf:"varint,3,opt,name=start_time" json:"start_time,omitempty"` EndTime *int32 `protobuf:"varint,4,opt,name=end_time" json:"end_time,omitempty"` ResolutionHours *uint32 `protobuf:"varint,5,opt,name=resolution_hours,def=1" json:"resolution_hours,omitempty"` CombineVersions *bool `protobuf:"varint,6,opt,name=combine_versions" json:"combine_versions,omitempty"` UsageVersion *int32 `protobuf:"varint,7,opt,name=usage_version" json:"usage_version,omitempty"` VersionsOnly *bool `protobuf:"varint,8,opt,name=versions_only" json:"versions_only,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *LogUsageRequest) Reset() { *m = LogUsageRequest{} } func (m *LogUsageRequest) String() string { return proto.CompactTextString(m) } func (*LogUsageRequest) ProtoMessage() {} const Default_LogUsageRequest_ResolutionHours uint32 = 1 func (m *LogUsageRequest) GetAppId() string { if m != nil && m.AppId != nil { return *m.AppId } return "" } func (m *LogUsageRequest) GetVersionId() []string { if m != nil { return m.VersionId } return nil } func (m *LogUsageRequest) GetStartTime() int32 { if m != nil && m.StartTime != nil { return *m.StartTime } return 0 } func (m *LogUsageRequest) GetEndTime() int32 { if m != nil && m.EndTime != nil { return *m.EndTime } return 0 } func (m *LogUsageRequest) GetResolutionHours() uint32 { if m != nil && m.ResolutionHours != nil { return *m.ResolutionHours } return Default_LogUsageRequest_ResolutionHours } func (m *LogUsageRequest) GetCombineVersions() bool { if m != nil && m.CombineVersions != nil { return *m.CombineVersions } return false } func (m *LogUsageRequest) GetUsageVersion() int32 { if m != nil && m.UsageVersion != nil { return *m.UsageVersion } return 0 } func (m *LogUsageRequest) GetVersionsOnly() bool { if m != nil && m.VersionsOnly != nil { return *m.VersionsOnly } return false } type LogUsageResponse struct { Usage []*LogUsageRecord `protobuf:"bytes,1,rep,name=usage" json:"usage,omitempty"` Summary *LogUsageRecord `protobuf:"bytes,2,opt,name=summary" json:"summary,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *LogUsageResponse) Reset() { *m = LogUsageResponse{} } func (m *LogUsageResponse) String() string { return proto.CompactTextString(m) } func (*LogUsageResponse) ProtoMessage() {} func (m *LogUsageResponse) GetUsage() []*LogUsageRecord { if m != nil { return m.Usage } return nil } func (m *LogUsageResponse) GetSummary() *LogUsageRecord { if m != nil { return m.Summary } return nil } func init() { } ================================================ FILE: vendor/google.golang.org/appengine/internal/log/log_service.proto ================================================ syntax = "proto2"; option go_package = "log"; package appengine; message LogServiceError { enum ErrorCode { OK = 0; INVALID_REQUEST = 1; STORAGE_ERROR = 2; } } message UserAppLogLine { required int64 timestamp_usec = 1; required int64 level = 2; required string message = 3; } message UserAppLogGroup { repeated UserAppLogLine log_line = 2; } message FlushRequest { optional bytes logs = 1; } message SetStatusRequest { required string status = 1; } message LogOffset { optional bytes request_id = 1; } message LogLine { required int64 time = 1; required int32 level = 2; required string log_message = 3; } message RequestLog { required string app_id = 1; optional string module_id = 37 [default="default"]; required string version_id = 2; required bytes request_id = 3; optional LogOffset offset = 35; required string ip = 4; optional string nickname = 5; required int64 start_time = 6; required int64 end_time = 7; required int64 latency = 8; required int64 mcycles = 9; required string method = 10; required string resource = 11; required string http_version = 12; required int32 status = 13; required int64 response_size = 14; optional string referrer = 15; optional string user_agent = 16; required string url_map_entry = 17; required string combined = 18; optional int64 api_mcycles = 19; optional string host = 20; optional double cost = 21; optional string task_queue_name = 22; optional string task_name = 23; optional bool was_loading_request = 24; optional int64 pending_time = 25; optional int32 replica_index = 26 [default = -1]; optional bool finished = 27 [default = true]; optional bytes clone_key = 28; repeated LogLine line = 29; optional bool lines_incomplete = 36; optional bytes app_engine_release = 38; optional int32 exit_reason = 30; optional bool was_throttled_for_time = 31; optional bool was_throttled_for_requests = 32; optional int64 throttled_time = 33; optional bytes server_name = 34; } message LogModuleVersion { optional string module_id = 1 [default="default"]; optional string version_id = 2; } message LogReadRequest { required string app_id = 1; repeated string version_id = 2; repeated LogModuleVersion module_version = 19; optional int64 start_time = 3; optional int64 end_time = 4; optional LogOffset offset = 5; repeated bytes request_id = 6; optional int32 minimum_log_level = 7; optional bool include_incomplete = 8; optional int64 count = 9; optional string combined_log_regex = 14; optional string host_regex = 15; optional int32 replica_index = 16; optional bool include_app_logs = 10; optional int32 app_logs_per_request = 17; optional bool include_host = 11; optional bool include_all = 12; optional bool cache_iterator = 13; optional int32 num_shards = 18; } message LogReadResponse { repeated RequestLog log = 1; optional LogOffset offset = 2; optional int64 last_end_time = 3; } message LogUsageRecord { optional string version_id = 1; optional int32 start_time = 2; optional int32 end_time = 3; optional int64 count = 4; optional int64 total_size = 5; optional int32 records = 6; } message LogUsageRequest { required string app_id = 1; repeated string version_id = 2; optional int32 start_time = 3; optional int32 end_time = 4; optional uint32 resolution_hours = 5 [default = 1]; optional bool combine_versions = 6; optional int32 usage_version = 7; optional bool versions_only = 8; } message LogUsageResponse { repeated LogUsageRecord usage = 1; optional LogUsageRecord summary = 2; } ================================================ FILE: vendor/google.golang.org/appengine/internal/main.go ================================================ // Copyright 2011 Google Inc. All rights reserved. // Use of this source code is governed by the Apache 2.0 // license that can be found in the LICENSE file. // +build appengine package internal import ( "appengine_internal" ) func Main() { appengine_internal.Main() } ================================================ FILE: vendor/google.golang.org/appengine/internal/main_vm.go ================================================ // Copyright 2011 Google Inc. All rights reserved. // Use of this source code is governed by the Apache 2.0 // license that can be found in the LICENSE file. // +build !appengine package internal import ( "io" "log" "net/http" "net/url" "os" ) func Main() { installHealthChecker(http.DefaultServeMux) port := "8080" if s := os.Getenv("PORT"); s != "" { port = s } if err := http.ListenAndServe(":"+port, http.HandlerFunc(handleHTTP)); err != nil { log.Fatalf("http.ListenAndServe: %v", err) } } func installHealthChecker(mux *http.ServeMux) { // If no health check handler has been installed by this point, add a trivial one. const healthPath = "/_ah/health" hreq := &http.Request{ Method: "GET", URL: &url.URL{ Path: healthPath, }, } if _, pat := mux.Handler(hreq); pat != healthPath { mux.HandleFunc(healthPath, func(w http.ResponseWriter, r *http.Request) { io.WriteString(w, "ok") }) } } ================================================ FILE: vendor/google.golang.org/appengine/internal/metadata.go ================================================ // Copyright 2014 Google Inc. All rights reserved. // Use of this source code is governed by the Apache 2.0 // license that can be found in the LICENSE file. package internal // This file has code for accessing metadata. // // References: // https://cloud.google.com/compute/docs/metadata import ( "fmt" "io/ioutil" "log" "net/http" "net/url" ) const ( metadataHost = "metadata" metadataPath = "/computeMetadata/v1/" ) var ( metadataRequestHeaders = http.Header{ "Metadata-Flavor": []string{"Google"}, } ) // TODO(dsymonds): Do we need to support default values, like Python? func mustGetMetadata(key string) []byte { b, err := getMetadata(key) if err != nil { log.Fatalf("Metadata fetch failed: %v", err) } return b } func getMetadata(key string) ([]byte, error) { // TODO(dsymonds): May need to use url.Parse to support keys with query args. req := &http.Request{ Method: "GET", URL: &url.URL{ Scheme: "http", Host: metadataHost, Path: metadataPath + key, }, Header: metadataRequestHeaders, Host: metadataHost, } resp, err := http.DefaultClient.Do(req) if err != nil { return nil, err } defer resp.Body.Close() if resp.StatusCode != 200 { return nil, fmt.Errorf("metadata server returned HTTP %d", resp.StatusCode) } return ioutil.ReadAll(resp.Body) } ================================================ FILE: vendor/google.golang.org/appengine/internal/net.go ================================================ // Copyright 2014 Google Inc. All rights reserved. // Use of this source code is governed by the Apache 2.0 // license that can be found in the LICENSE file. package internal // This file implements a network dialer that limits the number of concurrent connections. // It is only used for API calls. import ( "log" "net" "runtime" "sync" "time" ) var limitSem = make(chan int, 100) // TODO(dsymonds): Use environment variable. func limitRelease() { // non-blocking select { case <-limitSem: default: // This should not normally happen. log.Print("appengine: unbalanced limitSem release!") } } func limitDial(network, addr string) (net.Conn, error) { limitSem <- 1 // Dial with a timeout in case the API host is MIA. // The connection should normally be very fast. conn, err := net.DialTimeout(network, addr, 500*time.Millisecond) if err != nil { limitRelease() return nil, err } lc := &limitConn{Conn: conn} runtime.SetFinalizer(lc, (*limitConn).Close) // shouldn't usually be required return lc, nil } type limitConn struct { close sync.Once net.Conn } func (lc *limitConn) Close() error { defer lc.close.Do(func() { limitRelease() runtime.SetFinalizer(lc, nil) }) return lc.Conn.Close() } ================================================ FILE: vendor/google.golang.org/appengine/internal/net_test.go ================================================ // Copyright 2014 Google Inc. All rights reserved. // Use of this source code is governed by the Apache 2.0 // license that can be found in the LICENSE file. // +build !appengine package internal import ( "sync" "testing" "time" netcontext "golang.org/x/net/context" basepb "google.golang.org/appengine/internal/base" ) func TestDialLimit(t *testing.T) { // Fill up semaphore with false acquisitions to permit only two TCP connections at a time. // We don't replace limitSem because that results in a data race when net/http lazily closes connections. nFake := cap(limitSem) - 2 for i := 0; i < nFake; i++ { limitSem <- 1 } defer func() { for i := 0; i < nFake; i++ { <-limitSem } }() f, c, cleanup := setup() // setup is in api_test.go defer cleanup() f.hang = make(chan int) // If we make two RunSlowly RPCs (which will wait for f.hang to be strobed), // then the simple Non200 RPC should hang. var wg sync.WaitGroup wg.Add(2) for i := 0; i < 2; i++ { go func() { defer wg.Done() Call(toContext(c), "errors", "RunSlowly", &basepb.VoidProto{}, &basepb.VoidProto{}) }() } time.Sleep(50 * time.Millisecond) // let those two RPCs start ctx, _ := netcontext.WithTimeout(toContext(c), 50*time.Millisecond) err := Call(ctx, "errors", "Non200", &basepb.VoidProto{}, &basepb.VoidProto{}) if err != errTimeout { t.Errorf("Non200 RPC returned with err %v, want errTimeout", err) } // Drain the two RunSlowly calls. f.hang <- 1 f.hang <- 1 wg.Wait() } ================================================ FILE: vendor/google.golang.org/appengine/internal/regen.sh ================================================ #!/bin/bash -e # # This script rebuilds the generated code for the protocol buffers. # To run this you will need protoc and goprotobuf installed; # see https://github.com/golang/protobuf for instructions. PKG=google.golang.org/appengine function die() { echo 1>&2 $* exit 1 } # Sanity check that the right tools are accessible. for tool in go protoc protoc-gen-go; do q=$(which $tool) || die "didn't find $tool" echo 1>&2 "$tool: $q" done echo -n 1>&2 "finding package dir... " pkgdir=$(go list -f '{{.Dir}}' $PKG) echo 1>&2 $pkgdir base=$(echo $pkgdir | sed "s,/$PKG\$,,") echo 1>&2 "base: $base" cd $base # Run protoc once per package. for dir in $(find $PKG/internal -name '*.proto' | xargs dirname | sort | uniq); do echo 1>&2 "* $dir" protoc --go_out=. $dir/*.proto done for f in $(find $PKG/internal -name '*.pb.go'); do # Remove proto.RegisterEnum calls. # These cause duplicate registration panics when these packages # are used on classic App Engine. proto.RegisterEnum only affects # parsing the text format; we don't care about that. # https://code.google.com/p/googleappengine/issues/detail?id=11670#c17 sed -i '/proto.RegisterEnum/d' $f done ================================================ FILE: vendor/google.golang.org/appengine/internal/remote_api/remote_api.pb.go ================================================ // Code generated by protoc-gen-go. // source: google.golang.org/appengine/internal/remote_api/remote_api.proto // DO NOT EDIT! /* Package remote_api is a generated protocol buffer package. It is generated from these files: google.golang.org/appengine/internal/remote_api/remote_api.proto It has these top-level messages: Request ApplicationError RpcError Response */ package remote_api import proto "github.com/golang/protobuf/proto" import fmt "fmt" import math "math" // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal var _ = fmt.Errorf var _ = math.Inf type RpcError_ErrorCode int32 const ( RpcError_UNKNOWN RpcError_ErrorCode = 0 RpcError_CALL_NOT_FOUND RpcError_ErrorCode = 1 RpcError_PARSE_ERROR RpcError_ErrorCode = 2 RpcError_SECURITY_VIOLATION RpcError_ErrorCode = 3 RpcError_OVER_QUOTA RpcError_ErrorCode = 4 RpcError_REQUEST_TOO_LARGE RpcError_ErrorCode = 5 RpcError_CAPABILITY_DISABLED RpcError_ErrorCode = 6 RpcError_FEATURE_DISABLED RpcError_ErrorCode = 7 RpcError_BAD_REQUEST RpcError_ErrorCode = 8 RpcError_RESPONSE_TOO_LARGE RpcError_ErrorCode = 9 RpcError_CANCELLED RpcError_ErrorCode = 10 RpcError_REPLAY_ERROR RpcError_ErrorCode = 11 RpcError_DEADLINE_EXCEEDED RpcError_ErrorCode = 12 ) var RpcError_ErrorCode_name = map[int32]string{ 0: "UNKNOWN", 1: "CALL_NOT_FOUND", 2: "PARSE_ERROR", 3: "SECURITY_VIOLATION", 4: "OVER_QUOTA", 5: "REQUEST_TOO_LARGE", 6: "CAPABILITY_DISABLED", 7: "FEATURE_DISABLED", 8: "BAD_REQUEST", 9: "RESPONSE_TOO_LARGE", 10: "CANCELLED", 11: "REPLAY_ERROR", 12: "DEADLINE_EXCEEDED", } var RpcError_ErrorCode_value = map[string]int32{ "UNKNOWN": 0, "CALL_NOT_FOUND": 1, "PARSE_ERROR": 2, "SECURITY_VIOLATION": 3, "OVER_QUOTA": 4, "REQUEST_TOO_LARGE": 5, "CAPABILITY_DISABLED": 6, "FEATURE_DISABLED": 7, "BAD_REQUEST": 8, "RESPONSE_TOO_LARGE": 9, "CANCELLED": 10, "REPLAY_ERROR": 11, "DEADLINE_EXCEEDED": 12, } func (x RpcError_ErrorCode) Enum() *RpcError_ErrorCode { p := new(RpcError_ErrorCode) *p = x return p } func (x RpcError_ErrorCode) String() string { return proto.EnumName(RpcError_ErrorCode_name, int32(x)) } func (x *RpcError_ErrorCode) UnmarshalJSON(data []byte) error { value, err := proto.UnmarshalJSONEnum(RpcError_ErrorCode_value, data, "RpcError_ErrorCode") if err != nil { return err } *x = RpcError_ErrorCode(value) return nil } type Request struct { ServiceName *string `protobuf:"bytes,2,req,name=service_name" json:"service_name,omitempty"` Method *string `protobuf:"bytes,3,req,name=method" json:"method,omitempty"` Request []byte `protobuf:"bytes,4,req,name=request" json:"request,omitempty"` RequestId *string `protobuf:"bytes,5,opt,name=request_id" json:"request_id,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *Request) Reset() { *m = Request{} } func (m *Request) String() string { return proto.CompactTextString(m) } func (*Request) ProtoMessage() {} func (m *Request) GetServiceName() string { if m != nil && m.ServiceName != nil { return *m.ServiceName } return "" } func (m *Request) GetMethod() string { if m != nil && m.Method != nil { return *m.Method } return "" } func (m *Request) GetRequest() []byte { if m != nil { return m.Request } return nil } func (m *Request) GetRequestId() string { if m != nil && m.RequestId != nil { return *m.RequestId } return "" } type ApplicationError struct { Code *int32 `protobuf:"varint,1,req,name=code" json:"code,omitempty"` Detail *string `protobuf:"bytes,2,req,name=detail" json:"detail,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *ApplicationError) Reset() { *m = ApplicationError{} } func (m *ApplicationError) String() string { return proto.CompactTextString(m) } func (*ApplicationError) ProtoMessage() {} func (m *ApplicationError) GetCode() int32 { if m != nil && m.Code != nil { return *m.Code } return 0 } func (m *ApplicationError) GetDetail() string { if m != nil && m.Detail != nil { return *m.Detail } return "" } type RpcError struct { Code *int32 `protobuf:"varint,1,req,name=code" json:"code,omitempty"` Detail *string `protobuf:"bytes,2,opt,name=detail" json:"detail,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *RpcError) Reset() { *m = RpcError{} } func (m *RpcError) String() string { return proto.CompactTextString(m) } func (*RpcError) ProtoMessage() {} func (m *RpcError) GetCode() int32 { if m != nil && m.Code != nil { return *m.Code } return 0 } func (m *RpcError) GetDetail() string { if m != nil && m.Detail != nil { return *m.Detail } return "" } type Response struct { Response []byte `protobuf:"bytes,1,opt,name=response" json:"response,omitempty"` Exception []byte `protobuf:"bytes,2,opt,name=exception" json:"exception,omitempty"` ApplicationError *ApplicationError `protobuf:"bytes,3,opt,name=application_error" json:"application_error,omitempty"` JavaException []byte `protobuf:"bytes,4,opt,name=java_exception" json:"java_exception,omitempty"` RpcError *RpcError `protobuf:"bytes,5,opt,name=rpc_error" json:"rpc_error,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *Response) Reset() { *m = Response{} } func (m *Response) String() string { return proto.CompactTextString(m) } func (*Response) ProtoMessage() {} func (m *Response) GetResponse() []byte { if m != nil { return m.Response } return nil } func (m *Response) GetException() []byte { if m != nil { return m.Exception } return nil } func (m *Response) GetApplicationError() *ApplicationError { if m != nil { return m.ApplicationError } return nil } func (m *Response) GetJavaException() []byte { if m != nil { return m.JavaException } return nil } func (m *Response) GetRpcError() *RpcError { if m != nil { return m.RpcError } return nil } func init() { } ================================================ FILE: vendor/google.golang.org/appengine/internal/remote_api/remote_api.proto ================================================ syntax = "proto2"; option go_package = "remote_api"; package remote_api; message Request { required string service_name = 2; required string method = 3; required bytes request = 4; optional string request_id = 5; } message ApplicationError { required int32 code = 1; required string detail = 2; } message RpcError { enum ErrorCode { UNKNOWN = 0; CALL_NOT_FOUND = 1; PARSE_ERROR = 2; SECURITY_VIOLATION = 3; OVER_QUOTA = 4; REQUEST_TOO_LARGE = 5; CAPABILITY_DISABLED = 6; FEATURE_DISABLED = 7; BAD_REQUEST = 8; RESPONSE_TOO_LARGE = 9; CANCELLED = 10; REPLAY_ERROR = 11; DEADLINE_EXCEEDED = 12; } required int32 code = 1; optional string detail = 2; } message Response { optional bytes response = 1; optional bytes exception = 2; optional ApplicationError application_error = 3; optional bytes java_exception = 4; optional RpcError rpc_error = 5; } ================================================ FILE: vendor/google.golang.org/appengine/internal/transaction.go ================================================ // Copyright 2014 Google Inc. All rights reserved. // Use of this source code is governed by the Apache 2.0 // license that can be found in the LICENSE file. package internal // This file implements hooks for applying datastore transactions. import ( "errors" "reflect" "github.com/golang/protobuf/proto" netcontext "golang.org/x/net/context" basepb "google.golang.org/appengine/internal/base" pb "google.golang.org/appengine/internal/datastore" ) var transactionSetters = make(map[reflect.Type]reflect.Value) // RegisterTransactionSetter registers a function that sets transaction information // in a protocol buffer message. f should be a function with two arguments, // the first being a protocol buffer type, and the second being *datastore.Transaction. func RegisterTransactionSetter(f interface{}) { v := reflect.ValueOf(f) transactionSetters[v.Type().In(0)] = v } // applyTransaction applies the transaction t to message pb // by using the relevant setter passed to RegisterTransactionSetter. func applyTransaction(pb proto.Message, t *pb.Transaction) { v := reflect.ValueOf(pb) if f, ok := transactionSetters[v.Type()]; ok { f.Call([]reflect.Value{v, reflect.ValueOf(t)}) } } var transactionKey = "used for *Transaction" func transactionFromContext(ctx netcontext.Context) *transaction { t, _ := ctx.Value(&transactionKey).(*transaction) return t } func withTransaction(ctx netcontext.Context, t *transaction) netcontext.Context { return netcontext.WithValue(ctx, &transactionKey, t) } type transaction struct { transaction pb.Transaction finished bool } var ErrConcurrentTransaction = errors.New("internal: concurrent transaction") func RunTransactionOnce(c netcontext.Context, f func(netcontext.Context) error, xg bool) error { if transactionFromContext(c) != nil { return errors.New("nested transactions are not supported") } // Begin the transaction. t := &transaction{} req := &pb.BeginTransactionRequest{ App: proto.String(FullyQualifiedAppID(c)), } if xg { req.AllowMultipleEg = proto.Bool(true) } if err := Call(c, "datastore_v3", "BeginTransaction", req, &t.transaction); err != nil { return err } // Call f, rolling back the transaction if f returns a non-nil error, or panics. // The panic is not recovered. defer func() { if t.finished { return } t.finished = true // Ignore the error return value, since we are already returning a non-nil // error (or we're panicking). Call(c, "datastore_v3", "Rollback", &t.transaction, &basepb.VoidProto{}) }() if err := f(withTransaction(c, t)); err != nil { return err } t.finished = true // Commit the transaction. res := &pb.CommitResponse{} err := Call(c, "datastore_v3", "Commit", &t.transaction, res) if ae, ok := err.(*APIError); ok { /* TODO: restore this conditional if appengine.IsDevAppServer() { */ // The Python Dev AppServer raises an ApplicationError with error code 2 (which is // Error.CONCURRENT_TRANSACTION) and message "Concurrency exception.". if ae.Code == int32(pb.Error_BAD_REQUEST) && ae.Detail == "ApplicationError: 2 Concurrency exception." { return ErrConcurrentTransaction } if ae.Code == int32(pb.Error_CONCURRENT_TRANSACTION) { return ErrConcurrentTransaction } } return err } ================================================ FILE: vendor/google.golang.org/appengine/internal/urlfetch/urlfetch_service.pb.go ================================================ // Code generated by protoc-gen-go. // source: google.golang.org/appengine/internal/urlfetch/urlfetch_service.proto // DO NOT EDIT! /* Package urlfetch is a generated protocol buffer package. It is generated from these files: google.golang.org/appengine/internal/urlfetch/urlfetch_service.proto It has these top-level messages: URLFetchServiceError URLFetchRequest URLFetchResponse */ package urlfetch import proto "github.com/golang/protobuf/proto" import fmt "fmt" import math "math" // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal var _ = fmt.Errorf var _ = math.Inf type URLFetchServiceError_ErrorCode int32 const ( URLFetchServiceError_OK URLFetchServiceError_ErrorCode = 0 URLFetchServiceError_INVALID_URL URLFetchServiceError_ErrorCode = 1 URLFetchServiceError_FETCH_ERROR URLFetchServiceError_ErrorCode = 2 URLFetchServiceError_UNSPECIFIED_ERROR URLFetchServiceError_ErrorCode = 3 URLFetchServiceError_RESPONSE_TOO_LARGE URLFetchServiceError_ErrorCode = 4 URLFetchServiceError_DEADLINE_EXCEEDED URLFetchServiceError_ErrorCode = 5 URLFetchServiceError_SSL_CERTIFICATE_ERROR URLFetchServiceError_ErrorCode = 6 URLFetchServiceError_DNS_ERROR URLFetchServiceError_ErrorCode = 7 URLFetchServiceError_CLOSED URLFetchServiceError_ErrorCode = 8 URLFetchServiceError_INTERNAL_TRANSIENT_ERROR URLFetchServiceError_ErrorCode = 9 URLFetchServiceError_TOO_MANY_REDIRECTS URLFetchServiceError_ErrorCode = 10 URLFetchServiceError_MALFORMED_REPLY URLFetchServiceError_ErrorCode = 11 URLFetchServiceError_CONNECTION_ERROR URLFetchServiceError_ErrorCode = 12 ) var URLFetchServiceError_ErrorCode_name = map[int32]string{ 0: "OK", 1: "INVALID_URL", 2: "FETCH_ERROR", 3: "UNSPECIFIED_ERROR", 4: "RESPONSE_TOO_LARGE", 5: "DEADLINE_EXCEEDED", 6: "SSL_CERTIFICATE_ERROR", 7: "DNS_ERROR", 8: "CLOSED", 9: "INTERNAL_TRANSIENT_ERROR", 10: "TOO_MANY_REDIRECTS", 11: "MALFORMED_REPLY", 12: "CONNECTION_ERROR", } var URLFetchServiceError_ErrorCode_value = map[string]int32{ "OK": 0, "INVALID_URL": 1, "FETCH_ERROR": 2, "UNSPECIFIED_ERROR": 3, "RESPONSE_TOO_LARGE": 4, "DEADLINE_EXCEEDED": 5, "SSL_CERTIFICATE_ERROR": 6, "DNS_ERROR": 7, "CLOSED": 8, "INTERNAL_TRANSIENT_ERROR": 9, "TOO_MANY_REDIRECTS": 10, "MALFORMED_REPLY": 11, "CONNECTION_ERROR": 12, } func (x URLFetchServiceError_ErrorCode) Enum() *URLFetchServiceError_ErrorCode { p := new(URLFetchServiceError_ErrorCode) *p = x return p } func (x URLFetchServiceError_ErrorCode) String() string { return proto.EnumName(URLFetchServiceError_ErrorCode_name, int32(x)) } func (x *URLFetchServiceError_ErrorCode) UnmarshalJSON(data []byte) error { value, err := proto.UnmarshalJSONEnum(URLFetchServiceError_ErrorCode_value, data, "URLFetchServiceError_ErrorCode") if err != nil { return err } *x = URLFetchServiceError_ErrorCode(value) return nil } type URLFetchRequest_RequestMethod int32 const ( URLFetchRequest_GET URLFetchRequest_RequestMethod = 1 URLFetchRequest_POST URLFetchRequest_RequestMethod = 2 URLFetchRequest_HEAD URLFetchRequest_RequestMethod = 3 URLFetchRequest_PUT URLFetchRequest_RequestMethod = 4 URLFetchRequest_DELETE URLFetchRequest_RequestMethod = 5 URLFetchRequest_PATCH URLFetchRequest_RequestMethod = 6 ) var URLFetchRequest_RequestMethod_name = map[int32]string{ 1: "GET", 2: "POST", 3: "HEAD", 4: "PUT", 5: "DELETE", 6: "PATCH", } var URLFetchRequest_RequestMethod_value = map[string]int32{ "GET": 1, "POST": 2, "HEAD": 3, "PUT": 4, "DELETE": 5, "PATCH": 6, } func (x URLFetchRequest_RequestMethod) Enum() *URLFetchRequest_RequestMethod { p := new(URLFetchRequest_RequestMethod) *p = x return p } func (x URLFetchRequest_RequestMethod) String() string { return proto.EnumName(URLFetchRequest_RequestMethod_name, int32(x)) } func (x *URLFetchRequest_RequestMethod) UnmarshalJSON(data []byte) error { value, err := proto.UnmarshalJSONEnum(URLFetchRequest_RequestMethod_value, data, "URLFetchRequest_RequestMethod") if err != nil { return err } *x = URLFetchRequest_RequestMethod(value) return nil } type URLFetchServiceError struct { XXX_unrecognized []byte `json:"-"` } func (m *URLFetchServiceError) Reset() { *m = URLFetchServiceError{} } func (m *URLFetchServiceError) String() string { return proto.CompactTextString(m) } func (*URLFetchServiceError) ProtoMessage() {} type URLFetchRequest struct { Method *URLFetchRequest_RequestMethod `protobuf:"varint,1,req,name=Method,enum=appengine.URLFetchRequest_RequestMethod" json:"Method,omitempty"` Url *string `protobuf:"bytes,2,req,name=Url" json:"Url,omitempty"` Header []*URLFetchRequest_Header `protobuf:"group,3,rep,name=Header" json:"header,omitempty"` Payload []byte `protobuf:"bytes,6,opt,name=Payload" json:"Payload,omitempty"` FollowRedirects *bool `protobuf:"varint,7,opt,name=FollowRedirects,def=1" json:"FollowRedirects,omitempty"` Deadline *float64 `protobuf:"fixed64,8,opt,name=Deadline" json:"Deadline,omitempty"` MustValidateServerCertificate *bool `protobuf:"varint,9,opt,name=MustValidateServerCertificate,def=1" json:"MustValidateServerCertificate,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *URLFetchRequest) Reset() { *m = URLFetchRequest{} } func (m *URLFetchRequest) String() string { return proto.CompactTextString(m) } func (*URLFetchRequest) ProtoMessage() {} const Default_URLFetchRequest_FollowRedirects bool = true const Default_URLFetchRequest_MustValidateServerCertificate bool = true func (m *URLFetchRequest) GetMethod() URLFetchRequest_RequestMethod { if m != nil && m.Method != nil { return *m.Method } return URLFetchRequest_GET } func (m *URLFetchRequest) GetUrl() string { if m != nil && m.Url != nil { return *m.Url } return "" } func (m *URLFetchRequest) GetHeader() []*URLFetchRequest_Header { if m != nil { return m.Header } return nil } func (m *URLFetchRequest) GetPayload() []byte { if m != nil { return m.Payload } return nil } func (m *URLFetchRequest) GetFollowRedirects() bool { if m != nil && m.FollowRedirects != nil { return *m.FollowRedirects } return Default_URLFetchRequest_FollowRedirects } func (m *URLFetchRequest) GetDeadline() float64 { if m != nil && m.Deadline != nil { return *m.Deadline } return 0 } func (m *URLFetchRequest) GetMustValidateServerCertificate() bool { if m != nil && m.MustValidateServerCertificate != nil { return *m.MustValidateServerCertificate } return Default_URLFetchRequest_MustValidateServerCertificate } type URLFetchRequest_Header struct { Key *string `protobuf:"bytes,4,req,name=Key" json:"Key,omitempty"` Value *string `protobuf:"bytes,5,req,name=Value" json:"Value,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *URLFetchRequest_Header) Reset() { *m = URLFetchRequest_Header{} } func (m *URLFetchRequest_Header) String() string { return proto.CompactTextString(m) } func (*URLFetchRequest_Header) ProtoMessage() {} func (m *URLFetchRequest_Header) GetKey() string { if m != nil && m.Key != nil { return *m.Key } return "" } func (m *URLFetchRequest_Header) GetValue() string { if m != nil && m.Value != nil { return *m.Value } return "" } type URLFetchResponse struct { Content []byte `protobuf:"bytes,1,opt,name=Content" json:"Content,omitempty"` StatusCode *int32 `protobuf:"varint,2,req,name=StatusCode" json:"StatusCode,omitempty"` Header []*URLFetchResponse_Header `protobuf:"group,3,rep,name=Header" json:"header,omitempty"` ContentWasTruncated *bool `protobuf:"varint,6,opt,name=ContentWasTruncated,def=0" json:"ContentWasTruncated,omitempty"` ExternalBytesSent *int64 `protobuf:"varint,7,opt,name=ExternalBytesSent" json:"ExternalBytesSent,omitempty"` ExternalBytesReceived *int64 `protobuf:"varint,8,opt,name=ExternalBytesReceived" json:"ExternalBytesReceived,omitempty"` FinalUrl *string `protobuf:"bytes,9,opt,name=FinalUrl" json:"FinalUrl,omitempty"` ApiCpuMilliseconds *int64 `protobuf:"varint,10,opt,name=ApiCpuMilliseconds,def=0" json:"ApiCpuMilliseconds,omitempty"` ApiBytesSent *int64 `protobuf:"varint,11,opt,name=ApiBytesSent,def=0" json:"ApiBytesSent,omitempty"` ApiBytesReceived *int64 `protobuf:"varint,12,opt,name=ApiBytesReceived,def=0" json:"ApiBytesReceived,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *URLFetchResponse) Reset() { *m = URLFetchResponse{} } func (m *URLFetchResponse) String() string { return proto.CompactTextString(m) } func (*URLFetchResponse) ProtoMessage() {} const Default_URLFetchResponse_ContentWasTruncated bool = false const Default_URLFetchResponse_ApiCpuMilliseconds int64 = 0 const Default_URLFetchResponse_ApiBytesSent int64 = 0 const Default_URLFetchResponse_ApiBytesReceived int64 = 0 func (m *URLFetchResponse) GetContent() []byte { if m != nil { return m.Content } return nil } func (m *URLFetchResponse) GetStatusCode() int32 { if m != nil && m.StatusCode != nil { return *m.StatusCode } return 0 } func (m *URLFetchResponse) GetHeader() []*URLFetchResponse_Header { if m != nil { return m.Header } return nil } func (m *URLFetchResponse) GetContentWasTruncated() bool { if m != nil && m.ContentWasTruncated != nil { return *m.ContentWasTruncated } return Default_URLFetchResponse_ContentWasTruncated } func (m *URLFetchResponse) GetExternalBytesSent() int64 { if m != nil && m.ExternalBytesSent != nil { return *m.ExternalBytesSent } return 0 } func (m *URLFetchResponse) GetExternalBytesReceived() int64 { if m != nil && m.ExternalBytesReceived != nil { return *m.ExternalBytesReceived } return 0 } func (m *URLFetchResponse) GetFinalUrl() string { if m != nil && m.FinalUrl != nil { return *m.FinalUrl } return "" } func (m *URLFetchResponse) GetApiCpuMilliseconds() int64 { if m != nil && m.ApiCpuMilliseconds != nil { return *m.ApiCpuMilliseconds } return Default_URLFetchResponse_ApiCpuMilliseconds } func (m *URLFetchResponse) GetApiBytesSent() int64 { if m != nil && m.ApiBytesSent != nil { return *m.ApiBytesSent } return Default_URLFetchResponse_ApiBytesSent } func (m *URLFetchResponse) GetApiBytesReceived() int64 { if m != nil && m.ApiBytesReceived != nil { return *m.ApiBytesReceived } return Default_URLFetchResponse_ApiBytesReceived } type URLFetchResponse_Header struct { Key *string `protobuf:"bytes,4,req,name=Key" json:"Key,omitempty"` Value *string `protobuf:"bytes,5,req,name=Value" json:"Value,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *URLFetchResponse_Header) Reset() { *m = URLFetchResponse_Header{} } func (m *URLFetchResponse_Header) String() string { return proto.CompactTextString(m) } func (*URLFetchResponse_Header) ProtoMessage() {} func (m *URLFetchResponse_Header) GetKey() string { if m != nil && m.Key != nil { return *m.Key } return "" } func (m *URLFetchResponse_Header) GetValue() string { if m != nil && m.Value != nil { return *m.Value } return "" } func init() { } ================================================ FILE: vendor/google.golang.org/appengine/internal/urlfetch/urlfetch_service.proto ================================================ syntax = "proto2"; option go_package = "urlfetch"; package appengine; message URLFetchServiceError { enum ErrorCode { OK = 0; INVALID_URL = 1; FETCH_ERROR = 2; UNSPECIFIED_ERROR = 3; RESPONSE_TOO_LARGE = 4; DEADLINE_EXCEEDED = 5; SSL_CERTIFICATE_ERROR = 6; DNS_ERROR = 7; CLOSED = 8; INTERNAL_TRANSIENT_ERROR = 9; TOO_MANY_REDIRECTS = 10; MALFORMED_REPLY = 11; CONNECTION_ERROR = 12; } } message URLFetchRequest { enum RequestMethod { GET = 1; POST = 2; HEAD = 3; PUT = 4; DELETE = 5; PATCH = 6; } required RequestMethod Method = 1; required string Url = 2; repeated group Header = 3 { required string Key = 4; required string Value = 5; } optional bytes Payload = 6 [ctype=CORD]; optional bool FollowRedirects = 7 [default=true]; optional double Deadline = 8; optional bool MustValidateServerCertificate = 9 [default=true]; } message URLFetchResponse { optional bytes Content = 1; required int32 StatusCode = 2; repeated group Header = 3 { required string Key = 4; required string Value = 5; } optional bool ContentWasTruncated = 6 [default=false]; optional int64 ExternalBytesSent = 7; optional int64 ExternalBytesReceived = 8; optional string FinalUrl = 9; optional int64 ApiCpuMilliseconds = 10 [default=0]; optional int64 ApiBytesSent = 11 [default=0]; optional int64 ApiBytesReceived = 12 [default=0]; } ================================================ FILE: vendor/google.golang.org/appengine/namespace.go ================================================ // Copyright 2012 Google Inc. All rights reserved. // Use of this source code is governed by the Apache 2.0 // license that can be found in the LICENSE file. package appengine import ( "fmt" "regexp" "golang.org/x/net/context" "google.golang.org/appengine/internal" ) // Namespace returns a replacement context that operates within the given namespace. func Namespace(c context.Context, namespace string) (context.Context, error) { if !validNamespace.MatchString(namespace) { return nil, fmt.Errorf("appengine: namespace %q does not match /%s/", namespace, validNamespace) } return internal.NamespacedContext(c, namespace), nil } // validNamespace matches valid namespace names. var validNamespace = regexp.MustCompile(`^[0-9A-Za-z._-]{0,100}$`) ================================================ FILE: vendor/google.golang.org/appengine/namespace_test.go ================================================ // Copyright 2014 Google Inc. All rights reserved. // Use of this source code is governed by the Apache 2.0 // license that can be found in the LICENSE file. package appengine import ( "testing" "golang.org/x/net/context" ) func TestNamespaceValidity(t *testing.T) { testCases := []struct { namespace string ok bool }{ // data from Python's namespace_manager_test.py {"", true}, {"__a.namespace.123__", true}, {"-_A....NAMESPACE-_", true}, {"-", true}, {".", true}, {".-", true}, {"?", false}, {"+", false}, {"!", false}, {" ", false}, } for _, tc := range testCases { _, err := Namespace(context.Background(), tc.namespace) if err == nil && !tc.ok { t.Errorf("Namespace %q should be rejected, but wasn't", tc.namespace) } else if err != nil && tc.ok { t.Errorf("Namespace %q should be accepted, but wasn't", tc.namespace) } } } ================================================ FILE: vendor/google.golang.org/appengine/timeout.go ================================================ // Copyright 2013 Google Inc. All rights reserved. // Use of this source code is governed by the Apache 2.0 // license that can be found in the LICENSE file. package appengine import "golang.org/x/net/context" // IsTimeoutError reports whether err is a timeout error. func IsTimeoutError(err error) bool { if err == context.DeadlineExceeded { return true } if t, ok := err.(interface { IsTimeout() bool }); ok { return t.IsTimeout() } return false } ================================================ FILE: vendor/google.golang.org/appengine/urlfetch/urlfetch.go ================================================ // Copyright 2011 Google Inc. All rights reserved. // Use of this source code is governed by the Apache 2.0 // license that can be found in the LICENSE file. // Package urlfetch provides an http.RoundTripper implementation // for fetching URLs via App Engine's urlfetch service. package urlfetch // import "google.golang.org/appengine/urlfetch" import ( "errors" "fmt" "io" "io/ioutil" "net/http" "net/url" "strconv" "strings" "time" "github.com/golang/protobuf/proto" "golang.org/x/net/context" "google.golang.org/appengine/internal" pb "google.golang.org/appengine/internal/urlfetch" ) // Transport is an implementation of http.RoundTripper for // App Engine. Users should generally create an http.Client using // this transport and use the Client rather than using this transport // directly. type Transport struct { Context context.Context // Controls whether the application checks the validity of SSL certificates // over HTTPS connections. A value of false (the default) instructs the // application to send a request to the server only if the certificate is // valid and signed by a trusted certificate authority (CA), and also // includes a hostname that matches the certificate. A value of true // instructs the application to perform no certificate validation. AllowInvalidServerCertificate bool } // Verify statically that *Transport implements http.RoundTripper. var _ http.RoundTripper = (*Transport)(nil) // Client returns an *http.Client using a default urlfetch Transport. This // client will have the default deadline of 5 seconds, and will check the // validity of SSL certificates. // // Any deadline of the provided context will be used for requests through this client; // if the client does not have a deadline then a 5 second default is used. func Client(ctx context.Context) *http.Client { return &http.Client{ Transport: &Transport{ Context: ctx, }, } } type bodyReader struct { content []byte truncated bool closed bool } // ErrTruncatedBody is the error returned after the final Read() from a // response's Body if the body has been truncated by App Engine's proxy. var ErrTruncatedBody = errors.New("urlfetch: truncated body") func statusCodeToText(code int) string { if t := http.StatusText(code); t != "" { return t } return strconv.Itoa(code) } func (br *bodyReader) Read(p []byte) (n int, err error) { if br.closed { if br.truncated { return 0, ErrTruncatedBody } return 0, io.EOF } n = copy(p, br.content) if n > 0 { br.content = br.content[n:] return } if br.truncated { br.closed = true return 0, ErrTruncatedBody } return 0, io.EOF } func (br *bodyReader) Close() error { br.closed = true br.content = nil return nil } // A map of the URL Fetch-accepted methods that take a request body. var methodAcceptsRequestBody = map[string]bool{ "POST": true, "PUT": true, "PATCH": true, } // urlString returns a valid string given a URL. This function is necessary because // the String method of URL doesn't correctly handle URLs with non-empty Opaque values. // See http://code.google.com/p/go/issues/detail?id=4860. func urlString(u *url.URL) string { if u.Opaque == "" || strings.HasPrefix(u.Opaque, "//") { return u.String() } aux := *u aux.Opaque = "//" + aux.Host + aux.Opaque return aux.String() } // RoundTrip issues a single HTTP request and returns its response. Per the // http.RoundTripper interface, RoundTrip only returns an error if there // was an unsupported request or the URL Fetch proxy fails. // Note that HTTP response codes such as 5xx, 403, 404, etc are not // errors as far as the transport is concerned and will be returned // with err set to nil. func (t *Transport) RoundTrip(req *http.Request) (res *http.Response, err error) { methNum, ok := pb.URLFetchRequest_RequestMethod_value[req.Method] if !ok { return nil, fmt.Errorf("urlfetch: unsupported HTTP method %q", req.Method) } method := pb.URLFetchRequest_RequestMethod(methNum) freq := &pb.URLFetchRequest{ Method: &method, Url: proto.String(urlString(req.URL)), FollowRedirects: proto.Bool(false), // http.Client's responsibility MustValidateServerCertificate: proto.Bool(!t.AllowInvalidServerCertificate), } if deadline, ok := t.Context.Deadline(); ok { freq.Deadline = proto.Float64(deadline.Sub(time.Now()).Seconds()) } for k, vals := range req.Header { for _, val := range vals { freq.Header = append(freq.Header, &pb.URLFetchRequest_Header{ Key: proto.String(k), Value: proto.String(val), }) } } if methodAcceptsRequestBody[req.Method] && req.Body != nil { // Avoid a []byte copy if req.Body has a Bytes method. switch b := req.Body.(type) { case interface { Bytes() []byte }: freq.Payload = b.Bytes() default: freq.Payload, err = ioutil.ReadAll(req.Body) if err != nil { return nil, err } } } fres := &pb.URLFetchResponse{} if err := internal.Call(t.Context, "urlfetch", "Fetch", freq, fres); err != nil { return nil, err } res = &http.Response{} res.StatusCode = int(*fres.StatusCode) res.Status = fmt.Sprintf("%d %s", res.StatusCode, statusCodeToText(res.StatusCode)) res.Header = make(http.Header) res.Request = req // Faked: res.ProtoMajor = 1 res.ProtoMinor = 1 res.Proto = "HTTP/1.1" res.Close = true for _, h := range fres.Header { hkey := http.CanonicalHeaderKey(*h.Key) hval := *h.Value if hkey == "Content-Length" { // Will get filled in below for all but HEAD requests. if req.Method == "HEAD" { res.ContentLength, _ = strconv.ParseInt(hval, 10, 64) } continue } res.Header.Add(hkey, hval) } if req.Method != "HEAD" { res.ContentLength = int64(len(fres.Content)) } truncated := fres.GetContentWasTruncated() res.Body = &bodyReader{content: fres.Content, truncated: truncated} return } func init() { internal.RegisterErrorCodeMap("urlfetch", pb.URLFetchServiceError_ErrorCode_name) internal.RegisterTimeoutErrorCode("urlfetch", int32(pb.URLFetchServiceError_DEADLINE_EXCEEDED)) }