├── .circleci ├── config.yml └── images │ └── primary │ └── Dockerfile ├── .gitignore ├── Dockerfile ├── LICENSE.md ├── Makefile ├── README.md ├── db └── migrations │ ├── 001_contacts.down.sql │ └── 001_contacts.up.sql ├── main.go ├── service ├── client.go ├── contacts.go ├── database.go ├── service.go └── service_test.go ├── test ├── contacts.go └── setup.go └── vendor ├── github.com ├── davecgh │ └── go-spew │ │ ├── LICENSE │ │ └── spew │ │ ├── bypass.go │ │ ├── bypasssafe.go │ │ ├── common.go │ │ ├── config.go │ │ ├── doc.go │ │ ├── dump.go │ │ ├── format.go │ │ └── spew.go ├── julienschmidt │ └── httprouter │ │ ├── LICENSE │ │ ├── README.md │ │ ├── path.go │ │ ├── router.go │ │ └── tree.go ├── lib │ └── pq │ │ ├── CONTRIBUTING.md │ │ ├── LICENSE.md │ │ ├── README.md │ │ ├── array.go │ │ ├── buf.go │ │ ├── conn.go │ │ ├── conn_go18.go │ │ ├── copy.go │ │ ├── doc.go │ │ ├── encode.go │ │ ├── error.go │ │ ├── notify.go │ │ ├── oid │ │ ├── doc.go │ │ ├── gen.go │ │ └── types.go │ │ ├── ssl.go │ │ ├── ssl_go1.7.go │ │ ├── ssl_permissions.go │ │ ├── ssl_renegotiation.go │ │ ├── ssl_windows.go │ │ ├── url.go │ │ ├── user_posix.go │ │ ├── user_windows.go │ │ └── uuid.go ├── mattes │ └── migrate │ │ ├── LICENSE │ │ ├── driver │ │ ├── driver.go │ │ ├── postgres │ │ │ ├── README.md │ │ │ └── postgres.go │ │ └── registry.go │ │ ├── file │ │ └── file.go │ │ ├── migrate │ │ ├── direction │ │ │ └── direction.go │ │ └── migrate.go │ │ └── pipe │ │ └── pipe.go ├── pmezard │ └── go-difflib │ │ ├── LICENSE │ │ └── difflib │ │ └── difflib.go └── stretchr │ └── testify │ ├── LICENSE │ ├── assert │ ├── assertion_forward.go │ ├── assertion_forward.go.tmpl │ ├── assertions.go │ ├── doc.go │ ├── errors.go │ ├── forward_assertions.go │ └── http_assertions.go │ └── require │ ├── doc.go │ ├── forward_requirements.go │ ├── require.go │ ├── require.go.tmpl │ ├── require_forward.go │ ├── require_forward.go.tmpl │ └── requirements.go └── vendor.json /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | jobs: 3 | build: 4 | docker: 5 | # using custom image, see .circleci/images/primary/Dockerfile 6 | - image: circleci/cci-demo-docker-primary:0.0.2 7 | - image: postgres:9.4.1 8 | environment: 9 | POSTGRES_USER: ubuntu 10 | POSTGRES_DB: contacts 11 | working_directory: /go/src/github.com/circleci/cci-demo-docker 12 | 13 | environment: 14 | TEST_RESULTS: /tmp/test-results 15 | 16 | steps: 17 | - checkout 18 | 19 | - run: 20 | name: Waiting for Postgres to be ready 21 | command: | 22 | for i in `seq 1 10`; 23 | do 24 | nc -z localhost 5432 && echo Success && exit 0 25 | echo -n . 26 | sleep 1 27 | done 28 | echo Failed waiting for Postgress && exit 1 29 | 30 | - run: mkdir -p $TEST_RESULTS 31 | 32 | - run: 33 | name: Run unit tests 34 | environment: 35 | DATABASE_URL: "postgres://ubuntu@localhost:5432/contacts?sslmode=disable" 36 | DB_MIGRATIONS: /go/src/github.com/circleci/cci-demo-docker/db/migrations 37 | command: | 38 | set -ou pipefail 39 | trap "go-junit-report <${TEST_RESULTS}/go-test.out > ${TEST_RESULTS}/go-test-report.xml" EXIT 40 | # Notice this `set -o pipefail`, this will cause script to fail if `make test` fails 41 | # without this option script will return success regardless of testing result due to pipe after test command 42 | make test | tee ${TEST_RESULTS}/go-test.out 43 | 44 | - setup_remote_docker 45 | 46 | # This should go into custom primary image, here's only for the sake of explanation 47 | - run: 48 | name: Install Docker client 49 | command: | 50 | set -x 51 | VER="17.03.0-ce" 52 | curl -L -o /tmp/docker-$VER.tgz https://get.docker.com/builds/Linux/x86_64/docker-$VER.tgz 53 | tar -xz -C /tmp -f /tmp/docker-$VER.tgz 54 | mv /tmp/docker/* /usr/bin 55 | 56 | - run: 57 | name: Build service 58 | command: make 59 | 60 | - run: 61 | name: Build and push Docker image 62 | command: | 63 | TAG="0.1.${CIRCLE_BUILD_NUM}" 64 | docker build -t circleci/cci-demo-docker:$TAG . 65 | docker login -u $DOCKER_LOGIN -p $DOCKER_PASSWORD 66 | docker push circleci/cci-demo-docker:$TAG 67 | 68 | - store_artifacts: 69 | path: /tmp/test-results 70 | destination: raw-test-output 71 | 72 | - store_test_results: 73 | path: /tmp/test-results 74 | -------------------------------------------------------------------------------- /.circleci/images/primary/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.8.0 2 | 3 | RUN apt-get update && apt-get install -y netcat 4 | RUN go get github.com/jstemmer/go-junit-report 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | report.xml 2 | .DS_Store 3 | 4 | /workdir 5 | 6 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 7 | *.o 8 | *.a 9 | *.so 10 | 11 | # Folders 12 | _obj 13 | _test 14 | 15 | # Architecture specific extensions/prefixes 16 | *.[568vq] 17 | [568vq].out 18 | 19 | *.cgo1.go 20 | *.cgo2.c 21 | _cgo_defun.c 22 | _cgo_gotypes.go 23 | _cgo_export.* 24 | 25 | _testmain.go 26 | 27 | *.exe 28 | *.test 29 | *.prof 30 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.5 2 | 3 | ADD ./workdir/contacts /usr/bin/contacts 4 | ADD ./db/migrations /migrations 5 | 6 | ENTRYPOINT contacts -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 CircleCI 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CIRCLE_BUILD_NUM ?= 0 2 | TAG = 0.0.$(CIRCLE_BUILD_NUM)-$(shell git rev-parse --short HEAD) 3 | 4 | GOFILES = $(shell find . -name '*.go' -not -path './vendor/*') 5 | GOPACKAGES = $(shell go list ./... | grep -v /vendor/) 6 | 7 | default: build 8 | 9 | workdir: 10 | mkdir -p workdir 11 | 12 | build: workdir/contacts 13 | 14 | build-native: $(GOFILES) 15 | go build -o workdir/native-contacts . 16 | 17 | workdir/contacts: $(GOFILES) 18 | GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o workdir/contacts . 19 | 20 | test: test-all 21 | 22 | test-all: 23 | @go test -v $(GOPACKAGES) 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CircleCI 2.0 Demo Application: Building Docker image [![CircleCI Build Status](https://circleci.com/gh/circleci/cci-demo-docker.svg?style=shield)](https://circleci.com/gh/circleci/cci-demo-docker) [![MIT Licensed](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/circleci/cci-demo-react/master/LICENSE) 2 | 3 | This is an example application showcasing how to build Docker images in CircleCI 2.0. 4 | 5 | You can follow along with this project by reading the following doc: https://circleci.com/docs/2.0/building-docker-images 6 | -------------------------------------------------------------------------------- /db/migrations/001_contacts.down.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE contacts; -------------------------------------------------------------------------------- /db/migrations/001_contacts.up.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS contacts ( 2 | id SERIAL PRIMARY KEY, 3 | email varchar(255) UNIQUE NOT NULL, 4 | name varchar(255) NOT NULL 5 | ); 6 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "database/sql" 5 | "fmt" 6 | "net/http" 7 | "os" 8 | 9 | "github.com/circleci/cci-demo-docker/service" 10 | _ "github.com/mattes/migrate/driver/postgres" 11 | "github.com/mattes/migrate/migrate" 12 | ) 13 | 14 | func main() { 15 | db := SetupDB() 16 | server := service.NewServer(db) 17 | http.HandleFunc("/", server.ServeHTTP) 18 | http.ListenAndServe(":8080", nil) 19 | } 20 | 21 | func SetupDB() *service.Database { 22 | databaseUrl := os.Getenv("CONTACTS_DB_URL") 23 | if databaseUrl == "" { 24 | panic("CONTACTS_DB_URL must be set!") 25 | } 26 | 27 | sqlFiles := "./db/migrations" 28 | if sqlFilesEnv := os.Getenv("CONTACTS_DB_MIGRATIONS"); sqlFilesEnv != "" { 29 | sqlFiles = sqlFilesEnv 30 | } 31 | allErrors, ok := migrate.ResetSync(databaseUrl, sqlFiles) 32 | if !ok { 33 | panic(fmt.Sprintf("%+v", allErrors)) 34 | } 35 | 36 | db, err := sql.Open("postgres", databaseUrl) 37 | if err != nil { 38 | panic(fmt.Sprintf("Unable to open DB connection: %+v", err)) 39 | } 40 | 41 | return &service.Database{db} 42 | } 43 | -------------------------------------------------------------------------------- /service/client.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "fmt" 7 | "io" 8 | "io/ioutil" 9 | "net/http" 10 | "net/url" 11 | ) 12 | 13 | // Client defines the interface exposed by our API. 14 | type Client interface { 15 | AddContact(contact AddContactRequest) (*Contact, error) 16 | GetContactByEmail(email string) (*Contact, error) 17 | } 18 | 19 | // ErrorResponse is returned by our service when an error occurs. 20 | type ErrorResponse struct { 21 | StatusCode int `json:"status_code"` 22 | Message string `json:"message"` 23 | } 24 | 25 | func (e ErrorResponse) Error() string { 26 | return fmt.Sprintf("%v: %v", e.StatusCode, e.Message) 27 | } 28 | 29 | // NewClient creates a Client that accesses a service at the given base URL. 30 | func NewClient(baseURL string) Client { 31 | httpClient := http.DefaultClient 32 | return &DefaultClient{ 33 | http: httpClient, 34 | BaseURL: baseURL, 35 | } 36 | } 37 | 38 | // ===== DefaultClient ================================================================================================= 39 | 40 | // DefaultClient provides an implementation of the Client interface. 41 | type DefaultClient struct { 42 | http *http.Client 43 | BaseURL string 44 | } 45 | 46 | // performRequestMethod constructs a request and uses `performRequest` to execute it. 47 | func (c *DefaultClient) performRequestMethod(method string, path string, headers map[string]string, data interface{}, response interface{}) error { 48 | 49 | req, err := c.newRequest(method, path, headers, data) 50 | if err != nil { 51 | return err 52 | } 53 | 54 | return c.performRequest(req, response) 55 | } 56 | 57 | // performRequest executes the given request, and uses `response` to parse the JSON response. 58 | func (c *DefaultClient) performRequest(req *http.Request, response interface{}) error { 59 | // perform the request 60 | httpResponse, err := c.http.Do(req) 61 | if err != nil { 62 | return err 63 | } 64 | 65 | defer httpResponse.Body.Close() 66 | 67 | // read the response 68 | var responseBody []byte 69 | if responseBody, err = ioutil.ReadAll(httpResponse.Body); err != nil { 70 | return err 71 | } 72 | 73 | if httpResponse.StatusCode >= 400 { 74 | contentTypeHeader := httpResponse.Header["Content-Type"] 75 | if len(contentTypeHeader) != 0 && contentTypeHeader[0] == "application/json" { 76 | var errResponse ErrorResponse 77 | err := json.Unmarshal(responseBody, &errResponse) 78 | if err == nil { 79 | return errResponse 80 | } 81 | } 82 | 83 | return &ErrorResponse{ 84 | StatusCode: httpResponse.StatusCode, 85 | Message: httpResponse.Status, 86 | } 87 | } 88 | 89 | // map the response to an object value 90 | if err := json.Unmarshal(responseBody, &response); err != nil { 91 | return err 92 | } 93 | 94 | return nil 95 | } 96 | 97 | // newRequest builds a new request using the given parameters. 98 | func (c *DefaultClient) newRequest(method string, path string, headers map[string]string, data interface{}) (*http.Request, error) { 99 | 100 | // Construct request body 101 | var body io.Reader 102 | if data != nil { 103 | requestJSON, err := json.Marshal(data) 104 | if err != nil { 105 | return nil, err 106 | } 107 | 108 | body = bytes.NewReader(requestJSON) 109 | } 110 | 111 | // construct the request 112 | req, err := http.NewRequest(method, c.BaseURL+path, body) 113 | if err != nil { 114 | return nil, err 115 | } 116 | 117 | if body != nil { 118 | req.Header.Set("Content-Type", "application/json") 119 | } 120 | 121 | for k, v := range headers { 122 | req.Header.Set(k, v) 123 | } 124 | 125 | return req, nil 126 | } 127 | 128 | 129 | 130 | // ----- Add Contact --------------------------------------------------------------------------------------------------- 131 | 132 | type AddContactRequest struct { 133 | Email string `json:"email"` 134 | Name string `json:"name"` 135 | } 136 | 137 | type ContactResponse struct { 138 | Contact *Contact `json:"contact"` 139 | } 140 | 141 | func (c *DefaultClient) AddContact(contact AddContactRequest) (*Contact, error) { 142 | var response ContactResponse 143 | err := c.performRequestMethod(http.MethodPost, "/contacts", nil, contact, &response) 144 | if err != nil { 145 | return nil, err 146 | } 147 | 148 | return response.Contact, nil 149 | } 150 | 151 | func (c *DefaultClient) GetContactByEmail(email string) (*Contact, error) { 152 | var response ContactResponse 153 | var path = fmt.Sprintf("/contacts/%v", url.QueryEscape(email)) 154 | err := c.performRequestMethod(http.MethodGet, path, nil, nil, &response) 155 | if err != nil { 156 | return nil, err 157 | } 158 | 159 | return response.Contact, nil 160 | } 161 | -------------------------------------------------------------------------------- /service/contacts.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import "database/sql" 4 | 5 | // Contact describes a contact in our database. 6 | type Contact struct { 7 | Id int `json:"id"` 8 | Email string `json:"email"` 9 | Name string `json:"name"` 10 | } 11 | 12 | // ===== ADD CONTACT =================================================================================================== 13 | 14 | // AddContact inserts a new contact into the database. 15 | func (db *Database) AddContact(c Contact) (int, error) { 16 | var contactId int 17 | err := db.Write(func(tx *Transaction) { 18 | contactId = tx.AddContact(c) 19 | }) 20 | 21 | return contactId, err 22 | } 23 | 24 | // AddContact inserts a new contact within the transaction. 25 | func (tx *Transaction) AddContact(c Contact) int { 26 | row := tx.QueryRow( 27 | "INSERT INTO contacts (email, name) VALUES ($1, $2) RETURNING id", 28 | c.Email, 29 | c.Name, 30 | ) 31 | 32 | var id int 33 | if err := row.Scan(&id); err != nil { 34 | panic(err) 35 | } 36 | 37 | return id 38 | } 39 | 40 | // ===== GET CONTACT =================================================================================================== 41 | 42 | // GetContactByEmail reads a Contact from the Database. 43 | func (db *Database) GetContactByEmail(email string) (*Contact, error) { 44 | var contact *Contact 45 | err := db.Read(func(tx *Transaction) { 46 | contact = tx.GetContactByEmail(email) 47 | }) 48 | 49 | return contact, err 50 | } 51 | 52 | // GetContactByEmail finds a contact given an email address. `nil` is returned if the Contact doesn't exist in the DB. 53 | func (tx *Transaction) GetContactByEmail(email string) *Contact { 54 | row := tx.QueryRow( 55 | "SELECT id, email, name FROM contacts WHERE email = $1", 56 | email, 57 | ) 58 | 59 | var contact Contact 60 | err := row.Scan(&contact.Id, &contact.Email, &contact.Name) 61 | if err == nil { 62 | return &contact 63 | } else if err == sql.ErrNoRows { 64 | return nil 65 | } else { 66 | panic(err) 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /service/database.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "database/sql" 5 | "fmt" 6 | "log" 7 | ) 8 | 9 | // Database wraps our SQL database. Defining our own type allows us to define helper functions on the Database. 10 | type Database struct { 11 | DB *sql.DB 12 | } 13 | 14 | func (db *Database) Close() { 15 | db.DB.Close() 16 | } 17 | 18 | // ===== TRANSACTIONS ================================================================================================== 19 | 20 | // Transaction wraps a SQL transaction. Defining our own type allows functions to be defined on the Transaction. 21 | type Transaction struct { 22 | *sql.Tx 23 | db *Database 24 | } 25 | 26 | type TransactionFunc func(*Transaction) 27 | 28 | func (db *Database) begin() (*Transaction, error) { 29 | tx, err := db.DB.Begin() 30 | if err != nil { 31 | return nil, err 32 | } 33 | 34 | return &Transaction{tx, db}, nil 35 | } 36 | 37 | // Read begins a read-only transaction and passes it to the given function. The transaction will be rolled back after 38 | // the function returns. Any panics will be handled, and returned as an error. 39 | func (db *Database) Read(reader TransactionFunc) (err error) { 40 | tx, err := db.begin() 41 | if err != nil { 42 | return err 43 | } 44 | 45 | // A read should always rollback the transaction 46 | defer func() { 47 | if rollbackErr := tx.Rollback(); rollbackErr != nil { 48 | // Ignore errors rolling back 49 | log.Println(rollbackErr.Error()) 50 | } 51 | }() 52 | 53 | // recover any panics during the transaction, and return it as an error to the caller 54 | defer func() { 55 | if r := recover(); r != nil { 56 | var ok bool 57 | err, ok = r.(error) 58 | if !ok { 59 | err = fmt.Errorf("Database.Read: %v", r) 60 | } 61 | } 62 | }() 63 | 64 | // Mark the transaction as read only 65 | _, err = tx.Exec("SET TRANSACTION ISOLATION LEVEL REPEATABLE READ, READ ONLY") 66 | if err != nil { 67 | panic(fmt.Errorf("Unable to mark transaction read-only")) 68 | } 69 | 70 | reader(tx) // Code in this function can panic 71 | return err 72 | } 73 | 74 | // Write begins a transaction and passes it to the given function. The transaction will be committed when the function 75 | // returns. If the function panics, the transaction is rolled back, and the error provided to panic is returned. 76 | func (db *Database) Write(writer TransactionFunc) (err error) { 77 | tx, err := db.begin() 78 | if err != nil { 79 | return err 80 | } 81 | 82 | didPanic := false 83 | 84 | // write operations commit or rollback the transaction 85 | defer func() { 86 | if didPanic { 87 | if rollbackErr := tx.Rollback(); rollbackErr != nil { 88 | // Ignore errors rolling back 89 | log.Println(rollbackErr.Error()) 90 | } 91 | } else { 92 | if commitErr := tx.Commit(); commitErr != nil { 93 | err = commitErr 94 | } 95 | } 96 | }() 97 | 98 | // recover any panics during the transaction, and return it as an error to the caller 99 | defer func() { 100 | if r := recover(); r != nil { 101 | didPanic = true 102 | 103 | var ok bool 104 | err, ok = r.(error) 105 | if !ok { 106 | err = fmt.Errorf("Database.Write: %v", r) 107 | } 108 | } 109 | }() 110 | 111 | writer(tx) // If the function panics, the transaction will be rolled back 112 | 113 | return err 114 | } 115 | -------------------------------------------------------------------------------- /service/service.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "encoding/json" 5 | "log" 6 | "net/http" 7 | "net/url" 8 | "strings" 9 | 10 | "github.com/julienschmidt/httprouter" 11 | ) 12 | 13 | // NewServer initializes the service with the given Database, and sets up appropriate routes. 14 | func NewServer(db *Database) *Server { 15 | router := httprouter.New() 16 | server := &Server{ 17 | router: router, 18 | db: db, 19 | } 20 | 21 | server.setupRoutes() 22 | return server 23 | } 24 | 25 | // Server contains all that is needed to respond to incoming requests, like a database. Other services like a mail, 26 | // redis, or S3 server could also be added. 27 | type Server struct { 28 | router *httprouter.Router 29 | db *Database 30 | } 31 | 32 | // The ServerError type allows errors to provide an appropriate HTTP status code and message. The Server checks for 33 | // this interface when recovering from a panic inside a handler. 34 | type ServerError interface { 35 | HttpStatusCode() int 36 | HttpStatusMessage() string 37 | } 38 | 39 | func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { 40 | s.router.ServeHTTP(w, r) 41 | } 42 | 43 | func (s *Server) setupRoutes() { 44 | s.router.POST("/contacts", s.AddContact) 45 | s.router.GET("/contacts/:email", s.GetContactByEmail) 46 | 47 | // By default the router will handle errors. But the service should always return JSON if possible, so these 48 | // custom handlers are added. 49 | 50 | s.router.NotFound = http.HandlerFunc( 51 | func(w http.ResponseWriter, r *http.Request) { 52 | writeJSONError(w, http.StatusNotFound, "") 53 | }, 54 | ) 55 | 56 | s.router.HandleMethodNotAllowed = true 57 | s.router.MethodNotAllowed = http.HandlerFunc( 58 | func(w http.ResponseWriter, r *http.Request) { 59 | writeJSONError(w, http.StatusMethodNotAllowed, "") 60 | }, 61 | ) 62 | 63 | s.router.PanicHandler = func(w http.ResponseWriter, r *http.Request, e interface{}) { 64 | serverError, ok := e.(ServerError) 65 | if ok { 66 | writeJSONError(w, serverError.HttpStatusCode(), serverError.HttpStatusMessage()) 67 | } else { 68 | log.Printf("Panic during request: %v", e) 69 | writeJSONError(w, http.StatusInternalServerError, "") 70 | } 71 | } 72 | } 73 | 74 | // AddContact handles HTTP requests to add a Contact. 75 | func (s *Server) AddContact(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { 76 | var contact Contact 77 | 78 | decoder := json.NewDecoder(r.Body) 79 | if err := decoder.Decode(&contact); err != nil { 80 | writeJSONError(w, http.StatusBadRequest, "Error decoding JSON") 81 | return 82 | } 83 | 84 | contactId, err := s.db.AddContact(contact) 85 | if err != nil { 86 | panic(err) 87 | return 88 | } 89 | contact.Id = contactId 90 | 91 | writeJSON( 92 | w, 93 | http.StatusCreated, 94 | &ContactResponse{ 95 | Contact: &contact, 96 | }, 97 | ) 98 | } 99 | 100 | // AddContact handles HTTP requests to GET a Contact by an email address. 101 | func (s *Server) GetContactByEmail(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { 102 | email, err := url.QueryUnescape(ps.ByName("email")) 103 | if err != nil { 104 | writeJSONError(w, http.StatusBadRequest, "Invalid email.") 105 | return 106 | } 107 | 108 | email = strings.TrimSpace(email) 109 | if email == "" { 110 | writeJSONError(w, http.StatusBadRequest, "Expected a single email.") 111 | return 112 | } 113 | 114 | contact, err := s.db.GetContactByEmail(email) 115 | if err != nil { 116 | writeUnexpectedError(w, err) 117 | } else if contact == nil { 118 | writeJSONNotFound(w) 119 | } else { 120 | writeJSON( 121 | w, 122 | http.StatusOK, 123 | &ContactResponse{ 124 | Contact: contact, 125 | }, 126 | ) 127 | } 128 | } 129 | 130 | // ===== JSON HELPERS ================================================================================================== 131 | 132 | func writeJSON(w http.ResponseWriter, statusCode int, response interface{}) { 133 | w.Header().Set("Content-Type", "application/json") 134 | w.WriteHeader(statusCode) 135 | 136 | encoder := json.NewEncoder(w) 137 | encoder.Encode(response) 138 | } 139 | 140 | func writeJSONError(w http.ResponseWriter, statusCode int, message string) { 141 | if message == "" { 142 | message = http.StatusText(statusCode) 143 | } 144 | 145 | writeJSON( 146 | w, 147 | statusCode, 148 | &ErrorResponse{ 149 | StatusCode: statusCode, 150 | Message: message, 151 | }, 152 | ) 153 | } 154 | 155 | func writeJSONNotFound(w http.ResponseWriter) { 156 | writeJSONError(w, http.StatusNotFound, "") 157 | } 158 | 159 | func writeUnexpectedError(w http.ResponseWriter, err error) { 160 | writeJSONError(w, http.StatusInternalServerError, err.Error()) 161 | } 162 | -------------------------------------------------------------------------------- /service/service_test.go: -------------------------------------------------------------------------------- 1 | package service_test 2 | 3 | import ( 4 | "net/http" 5 | "testing" 6 | 7 | "github.com/circleci/cci-demo-docker/service" 8 | "github.com/circleci/cci-demo-docker/test" 9 | "github.com/stretchr/testify/assert" 10 | "github.com/stretchr/testify/require" 11 | ) 12 | 13 | // Test_AddContact shows how to structure a basic service test. Notice the 'SETUP', 'TEST', and 'VERIFY' steps that 14 | // nearly all tests should have. 15 | func Test_AddContact(t *testing.T) { 16 | // SETUP: 17 | // A standard Env. defer is used to ensure the env is cleaned up after the test. 18 | env := test.SetupEnv(t) 19 | defer env.Close() 20 | 21 | // TEST: Adding a contact via the API. 22 | contact, err := env.Client.AddContact(service.AddContactRequest{ 23 | Email: "alice@example.xyz", 24 | Name: "Alice Zulu", 25 | }) 26 | 27 | // VERIFY: Response contains the contact 28 | require.NoError(t, err, "Unable to get contact via API") 29 | require.NotEmpty(t, contact, "Contact not found") 30 | assert.True(t, contact.Id > 0, "Contact ID is missing") 31 | assert.Equal(t, contact.Email, "alice@example.xyz") 32 | assert.Equal(t, contact.Name, "Alice Zulu") 33 | 34 | // VERIFY: Contact is added to the database properly. 35 | dbContact := env.ReadContactWithEmail("alice@example.xyz") 36 | require.NotEmpty(t, dbContact, "Contact not found") 37 | assert.Equal(t, dbContact.Email, "alice@example.xyz") 38 | assert.Equal(t, dbContact.Name, "Alice Zulu") 39 | } 40 | 41 | func Test_GetContactByEmail(t *testing.T) { 42 | env := test.SetupEnv(t) 43 | defer env.Close() 44 | 45 | // SETUP: 46 | env.SetupContact("alice@example.xyz", "Alice Zulu") 47 | 48 | // ------------------------------------------------------------------------------------------------------------- 49 | // TEST: when contact exists 50 | { 51 | // Using braces like this can help isolate different test cases. 52 | 53 | contact, err := env.Client.GetContactByEmail("alice@example.xyz") 54 | 55 | // VERIFY: Response contains the contact 56 | require.NoError(t, err, "Unable to get contact via API") 57 | require.NotEmpty(t, contact, "Contact not found") 58 | assert.True(t, contact.Id > 0, "Contact ID is missing") 59 | assert.Equal(t, contact.Email, "alice@example.xyz") 60 | assert.Equal(t, contact.Name, "Alice Zulu") 61 | } 62 | 63 | // ------------------------------------------------------------------------------------------------------------- 64 | // TEST: when contact doesn't exist 65 | { 66 | contact, err := env.Client.GetContactByEmail("bob@example.xyz") 67 | 68 | // VERIFY: 404 Not Found returned 69 | require.Error(t, err) 70 | require.IsType(t, service.ErrorResponse{}, err) 71 | 72 | assert.Equal(t, http.StatusNotFound, err.(service.ErrorResponse).StatusCode) 73 | 74 | assert.Nil(t, contact) 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /test/contacts.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "github.com/circleci/cci-demo-docker/service" 5 | "github.com/stretchr/testify/require" 6 | ) 7 | 8 | // SetupContact creates a Contact for use in tests. How it creates the contact is an implementation detail, but it 9 | // should record an error if the resulting contact would be invalid. 10 | func (env *Env) SetupContact(email string, name string) *service.Contact { 11 | contact, err := env.Client.AddContact(service.AddContactRequest{ 12 | Email: email, 13 | Name: name, 14 | }) 15 | 16 | // VERIFY: Response contains the contact 17 | require.NoError(env.T, err, "Unable to get contact via API") 18 | require.NotEmpty(env.T, contact, "Contact not found") 19 | 20 | return contact 21 | } 22 | 23 | // ReadContactWithEmail reads a contact from the test database with the given email. Helpers like this make it easy to 24 | // verify the state of the database as part of a test. 25 | func (env *Env) ReadContactWithEmail(email string) *service.Contact { 26 | contact, err := env.DB.GetContactByEmail(email) 27 | require.NoError(env.T, err) 28 | 29 | return contact 30 | } 31 | -------------------------------------------------------------------------------- /test/setup.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "database/sql" 5 | "net/http/httptest" 6 | "os" 7 | "testing" 8 | 9 | "github.com/circleci/cci-demo-docker/service" 10 | _ "github.com/mattes/migrate/driver/postgres" 11 | "github.com/mattes/migrate/migrate" 12 | "github.com/stretchr/testify/require" 13 | ) 14 | 15 | // Env provides access to all services used in tests, like the database, our server, and an HTTP client for performing 16 | // HTTP requests against the test server. 17 | type Env struct { 18 | T *testing.T 19 | DB *service.Database 20 | Server *service.Server 21 | HttpServer *httptest.Server 22 | Client service.Client 23 | } 24 | 25 | // Close must be called after each test to ensure the Env is properly destroyed. 26 | func (env *Env) Close() { 27 | env.HttpServer.Close() 28 | env.DB.Close() 29 | } 30 | 31 | // SetupEnv creates a new test environment, including a clean database and an instance of our HTTP service. 32 | func SetupEnv(t *testing.T) *Env { 33 | db := SetupDB(t) 34 | server := service.NewServer(db) 35 | httpServer := httptest.NewServer(server) 36 | return &Env{ 37 | T: t, 38 | DB: db, 39 | Server: server, 40 | HttpServer: httpServer, 41 | Client: service.NewClient(httpServer.URL), 42 | } 43 | } 44 | 45 | // SetupDB initializes a test database, performing all migrations. 46 | func SetupDB(t *testing.T) *service.Database { 47 | databaseUrl := os.Getenv("DATABASE_URL") 48 | require.NotEmpty(t, databaseUrl, "DATABASE_URL must be set!") 49 | 50 | sqlFiles := "./db/migrations" 51 | if sqlFilesEnv := os.Getenv("DB_MIGRATIONS"); sqlFilesEnv != "" { 52 | sqlFiles = sqlFilesEnv 53 | } 54 | allErrors, ok := migrate.ResetSync(databaseUrl, sqlFiles) 55 | require.True(t, ok, "Failed to migrate database %v", allErrors) 56 | 57 | db, err := sql.Open("postgres", databaseUrl) 58 | require.NoError(t, err, "Error opening database") 59 | 60 | return &service.Database{db} 61 | } 62 | -------------------------------------------------------------------------------- /vendor/github.com/davecgh/go-spew/LICENSE: -------------------------------------------------------------------------------- 1 | ISC License 2 | 3 | Copyright (c) 2012-2013 Dave Collins 4 | 5 | Permission to use, copy, modify, and distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | -------------------------------------------------------------------------------- /vendor/github.com/davecgh/go-spew/spew/bypass.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Dave Collins 2 | // 3 | // Permission to use, copy, modify, and distribute this software for any 4 | // purpose with or without fee is hereby granted, provided that the above 5 | // copyright notice and this permission notice appear in all copies. 6 | // 7 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | // NOTE: Due to the following build constraints, this file will only be compiled 16 | // when the code is not running on Google App Engine, compiled by GopherJS, and 17 | // "-tags safe" is not added to the go build command line. The "disableunsafe" 18 | // tag is deprecated and thus should not be used. 19 | // +build !js,!appengine,!safe,!disableunsafe 20 | 21 | package spew 22 | 23 | import ( 24 | "reflect" 25 | "unsafe" 26 | ) 27 | 28 | const ( 29 | // UnsafeDisabled is a build-time constant which specifies whether or 30 | // not access to the unsafe package is available. 31 | UnsafeDisabled = false 32 | 33 | // ptrSize is the size of a pointer on the current arch. 34 | ptrSize = unsafe.Sizeof((*byte)(nil)) 35 | ) 36 | 37 | var ( 38 | // offsetPtr, offsetScalar, and offsetFlag are the offsets for the 39 | // internal reflect.Value fields. These values are valid before golang 40 | // commit ecccf07e7f9d which changed the format. The are also valid 41 | // after commit 82f48826c6c7 which changed the format again to mirror 42 | // the original format. Code in the init function updates these offsets 43 | // as necessary. 44 | offsetPtr = uintptr(ptrSize) 45 | offsetScalar = uintptr(0) 46 | offsetFlag = uintptr(ptrSize * 2) 47 | 48 | // flagKindWidth and flagKindShift indicate various bits that the 49 | // reflect package uses internally to track kind information. 50 | // 51 | // flagRO indicates whether or not the value field of a reflect.Value is 52 | // read-only. 53 | // 54 | // flagIndir indicates whether the value field of a reflect.Value is 55 | // the actual data or a pointer to the data. 56 | // 57 | // These values are valid before golang commit 90a7c3c86944 which 58 | // changed their positions. Code in the init function updates these 59 | // flags as necessary. 60 | flagKindWidth = uintptr(5) 61 | flagKindShift = uintptr(flagKindWidth - 1) 62 | flagRO = uintptr(1 << 0) 63 | flagIndir = uintptr(1 << 1) 64 | ) 65 | 66 | func init() { 67 | // Older versions of reflect.Value stored small integers directly in the 68 | // ptr field (which is named val in the older versions). Versions 69 | // between commits ecccf07e7f9d and 82f48826c6c7 added a new field named 70 | // scalar for this purpose which unfortunately came before the flag 71 | // field, so the offset of the flag field is different for those 72 | // versions. 73 | // 74 | // This code constructs a new reflect.Value from a known small integer 75 | // and checks if the size of the reflect.Value struct indicates it has 76 | // the scalar field. When it does, the offsets are updated accordingly. 77 | vv := reflect.ValueOf(0xf00) 78 | if unsafe.Sizeof(vv) == (ptrSize * 4) { 79 | offsetScalar = ptrSize * 2 80 | offsetFlag = ptrSize * 3 81 | } 82 | 83 | // Commit 90a7c3c86944 changed the flag positions such that the low 84 | // order bits are the kind. This code extracts the kind from the flags 85 | // field and ensures it's the correct type. When it's not, the flag 86 | // order has been changed to the newer format, so the flags are updated 87 | // accordingly. 88 | upf := unsafe.Pointer(uintptr(unsafe.Pointer(&vv)) + offsetFlag) 89 | upfv := *(*uintptr)(upf) 90 | flagKindMask := uintptr((1<>flagKindShift != uintptr(reflect.Int) { 92 | flagKindShift = 0 93 | flagRO = 1 << 5 94 | flagIndir = 1 << 6 95 | 96 | // Commit adf9b30e5594 modified the flags to separate the 97 | // flagRO flag into two bits which specifies whether or not the 98 | // field is embedded. This causes flagIndir to move over a bit 99 | // and means that flagRO is the combination of either of the 100 | // original flagRO bit and the new bit. 101 | // 102 | // This code detects the change by extracting what used to be 103 | // the indirect bit to ensure it's set. When it's not, the flag 104 | // order has been changed to the newer format, so the flags are 105 | // updated accordingly. 106 | if upfv&flagIndir == 0 { 107 | flagRO = 3 << 5 108 | flagIndir = 1 << 7 109 | } 110 | } 111 | } 112 | 113 | // unsafeReflectValue converts the passed reflect.Value into a one that bypasses 114 | // the typical safety restrictions preventing access to unaddressable and 115 | // unexported data. It works by digging the raw pointer to the underlying 116 | // value out of the protected value and generating a new unprotected (unsafe) 117 | // reflect.Value to it. 118 | // 119 | // This allows us to check for implementations of the Stringer and error 120 | // interfaces to be used for pretty printing ordinarily unaddressable and 121 | // inaccessible values such as unexported struct fields. 122 | func unsafeReflectValue(v reflect.Value) (rv reflect.Value) { 123 | indirects := 1 124 | vt := v.Type() 125 | upv := unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetPtr) 126 | rvf := *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetFlag)) 127 | if rvf&flagIndir != 0 { 128 | vt = reflect.PtrTo(v.Type()) 129 | indirects++ 130 | } else if offsetScalar != 0 { 131 | // The value is in the scalar field when it's not one of the 132 | // reference types. 133 | switch vt.Kind() { 134 | case reflect.Uintptr: 135 | case reflect.Chan: 136 | case reflect.Func: 137 | case reflect.Map: 138 | case reflect.Ptr: 139 | case reflect.UnsafePointer: 140 | default: 141 | upv = unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + 142 | offsetScalar) 143 | } 144 | } 145 | 146 | pv := reflect.NewAt(vt, upv) 147 | rv = pv 148 | for i := 0; i < indirects; i++ { 149 | rv = rv.Elem() 150 | } 151 | return rv 152 | } 153 | -------------------------------------------------------------------------------- /vendor/github.com/davecgh/go-spew/spew/bypasssafe.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Dave Collins 2 | // 3 | // Permission to use, copy, modify, and distribute this software for any 4 | // purpose with or without fee is hereby granted, provided that the above 5 | // copyright notice and this permission notice appear in all copies. 6 | // 7 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | // NOTE: Due to the following build constraints, this file will only be compiled 16 | // when the code is running on Google App Engine, compiled by GopherJS, or 17 | // "-tags safe" is added to the go build command line. The "disableunsafe" 18 | // tag is deprecated and thus should not be used. 19 | // +build js appengine safe disableunsafe 20 | 21 | package spew 22 | 23 | import "reflect" 24 | 25 | const ( 26 | // UnsafeDisabled is a build-time constant which specifies whether or 27 | // not access to the unsafe package is available. 28 | UnsafeDisabled = true 29 | ) 30 | 31 | // unsafeReflectValue typically converts the passed reflect.Value into a one 32 | // that bypasses the typical safety restrictions preventing access to 33 | // unaddressable and unexported data. However, doing this relies on access to 34 | // the unsafe package. This is a stub version which simply returns the passed 35 | // reflect.Value when the unsafe package is not available. 36 | func unsafeReflectValue(v reflect.Value) reflect.Value { 37 | return v 38 | } 39 | -------------------------------------------------------------------------------- /vendor/github.com/davecgh/go-spew/spew/common.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 Dave Collins 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | package spew 18 | 19 | import ( 20 | "bytes" 21 | "fmt" 22 | "io" 23 | "reflect" 24 | "sort" 25 | "strconv" 26 | ) 27 | 28 | // Some constants in the form of bytes to avoid string overhead. This mirrors 29 | // the technique used in the fmt package. 30 | var ( 31 | panicBytes = []byte("(PANIC=") 32 | plusBytes = []byte("+") 33 | iBytes = []byte("i") 34 | trueBytes = []byte("true") 35 | falseBytes = []byte("false") 36 | interfaceBytes = []byte("(interface {})") 37 | commaNewlineBytes = []byte(",\n") 38 | newlineBytes = []byte("\n") 39 | openBraceBytes = []byte("{") 40 | openBraceNewlineBytes = []byte("{\n") 41 | closeBraceBytes = []byte("}") 42 | asteriskBytes = []byte("*") 43 | colonBytes = []byte(":") 44 | colonSpaceBytes = []byte(": ") 45 | openParenBytes = []byte("(") 46 | closeParenBytes = []byte(")") 47 | spaceBytes = []byte(" ") 48 | pointerChainBytes = []byte("->") 49 | nilAngleBytes = []byte("") 50 | maxNewlineBytes = []byte("\n") 51 | maxShortBytes = []byte("") 52 | circularBytes = []byte("") 53 | circularShortBytes = []byte("") 54 | invalidAngleBytes = []byte("") 55 | openBracketBytes = []byte("[") 56 | closeBracketBytes = []byte("]") 57 | percentBytes = []byte("%") 58 | precisionBytes = []byte(".") 59 | openAngleBytes = []byte("<") 60 | closeAngleBytes = []byte(">") 61 | openMapBytes = []byte("map[") 62 | closeMapBytes = []byte("]") 63 | lenEqualsBytes = []byte("len=") 64 | capEqualsBytes = []byte("cap=") 65 | ) 66 | 67 | // hexDigits is used to map a decimal value to a hex digit. 68 | var hexDigits = "0123456789abcdef" 69 | 70 | // catchPanic handles any panics that might occur during the handleMethods 71 | // calls. 72 | func catchPanic(w io.Writer, v reflect.Value) { 73 | if err := recover(); err != nil { 74 | w.Write(panicBytes) 75 | fmt.Fprintf(w, "%v", err) 76 | w.Write(closeParenBytes) 77 | } 78 | } 79 | 80 | // handleMethods attempts to call the Error and String methods on the underlying 81 | // type the passed reflect.Value represents and outputes the result to Writer w. 82 | // 83 | // It handles panics in any called methods by catching and displaying the error 84 | // as the formatted value. 85 | func handleMethods(cs *ConfigState, w io.Writer, v reflect.Value) (handled bool) { 86 | // We need an interface to check if the type implements the error or 87 | // Stringer interface. However, the reflect package won't give us an 88 | // interface on certain things like unexported struct fields in order 89 | // to enforce visibility rules. We use unsafe, when it's available, 90 | // to bypass these restrictions since this package does not mutate the 91 | // values. 92 | if !v.CanInterface() { 93 | if UnsafeDisabled { 94 | return false 95 | } 96 | 97 | v = unsafeReflectValue(v) 98 | } 99 | 100 | // Choose whether or not to do error and Stringer interface lookups against 101 | // the base type or a pointer to the base type depending on settings. 102 | // Technically calling one of these methods with a pointer receiver can 103 | // mutate the value, however, types which choose to satisify an error or 104 | // Stringer interface with a pointer receiver should not be mutating their 105 | // state inside these interface methods. 106 | if !cs.DisablePointerMethods && !UnsafeDisabled && !v.CanAddr() { 107 | v = unsafeReflectValue(v) 108 | } 109 | if v.CanAddr() { 110 | v = v.Addr() 111 | } 112 | 113 | // Is it an error or Stringer? 114 | switch iface := v.Interface().(type) { 115 | case error: 116 | defer catchPanic(w, v) 117 | if cs.ContinueOnMethod { 118 | w.Write(openParenBytes) 119 | w.Write([]byte(iface.Error())) 120 | w.Write(closeParenBytes) 121 | w.Write(spaceBytes) 122 | return false 123 | } 124 | 125 | w.Write([]byte(iface.Error())) 126 | return true 127 | 128 | case fmt.Stringer: 129 | defer catchPanic(w, v) 130 | if cs.ContinueOnMethod { 131 | w.Write(openParenBytes) 132 | w.Write([]byte(iface.String())) 133 | w.Write(closeParenBytes) 134 | w.Write(spaceBytes) 135 | return false 136 | } 137 | w.Write([]byte(iface.String())) 138 | return true 139 | } 140 | return false 141 | } 142 | 143 | // printBool outputs a boolean value as true or false to Writer w. 144 | func printBool(w io.Writer, val bool) { 145 | if val { 146 | w.Write(trueBytes) 147 | } else { 148 | w.Write(falseBytes) 149 | } 150 | } 151 | 152 | // printInt outputs a signed integer value to Writer w. 153 | func printInt(w io.Writer, val int64, base int) { 154 | w.Write([]byte(strconv.FormatInt(val, base))) 155 | } 156 | 157 | // printUint outputs an unsigned integer value to Writer w. 158 | func printUint(w io.Writer, val uint64, base int) { 159 | w.Write([]byte(strconv.FormatUint(val, base))) 160 | } 161 | 162 | // printFloat outputs a floating point value using the specified precision, 163 | // which is expected to be 32 or 64bit, to Writer w. 164 | func printFloat(w io.Writer, val float64, precision int) { 165 | w.Write([]byte(strconv.FormatFloat(val, 'g', -1, precision))) 166 | } 167 | 168 | // printComplex outputs a complex value using the specified float precision 169 | // for the real and imaginary parts to Writer w. 170 | func printComplex(w io.Writer, c complex128, floatPrecision int) { 171 | r := real(c) 172 | w.Write(openParenBytes) 173 | w.Write([]byte(strconv.FormatFloat(r, 'g', -1, floatPrecision))) 174 | i := imag(c) 175 | if i >= 0 { 176 | w.Write(plusBytes) 177 | } 178 | w.Write([]byte(strconv.FormatFloat(i, 'g', -1, floatPrecision))) 179 | w.Write(iBytes) 180 | w.Write(closeParenBytes) 181 | } 182 | 183 | // printHexPtr outputs a uintptr formatted as hexidecimal with a leading '0x' 184 | // prefix to Writer w. 185 | func printHexPtr(w io.Writer, p uintptr) { 186 | // Null pointer. 187 | num := uint64(p) 188 | if num == 0 { 189 | w.Write(nilAngleBytes) 190 | return 191 | } 192 | 193 | // Max uint64 is 16 bytes in hex + 2 bytes for '0x' prefix 194 | buf := make([]byte, 18) 195 | 196 | // It's simpler to construct the hex string right to left. 197 | base := uint64(16) 198 | i := len(buf) - 1 199 | for num >= base { 200 | buf[i] = hexDigits[num%base] 201 | num /= base 202 | i-- 203 | } 204 | buf[i] = hexDigits[num] 205 | 206 | // Add '0x' prefix. 207 | i-- 208 | buf[i] = 'x' 209 | i-- 210 | buf[i] = '0' 211 | 212 | // Strip unused leading bytes. 213 | buf = buf[i:] 214 | w.Write(buf) 215 | } 216 | 217 | // valuesSorter implements sort.Interface to allow a slice of reflect.Value 218 | // elements to be sorted. 219 | type valuesSorter struct { 220 | values []reflect.Value 221 | strings []string // either nil or same len and values 222 | cs *ConfigState 223 | } 224 | 225 | // newValuesSorter initializes a valuesSorter instance, which holds a set of 226 | // surrogate keys on which the data should be sorted. It uses flags in 227 | // ConfigState to decide if and how to populate those surrogate keys. 228 | func newValuesSorter(values []reflect.Value, cs *ConfigState) sort.Interface { 229 | vs := &valuesSorter{values: values, cs: cs} 230 | if canSortSimply(vs.values[0].Kind()) { 231 | return vs 232 | } 233 | if !cs.DisableMethods { 234 | vs.strings = make([]string, len(values)) 235 | for i := range vs.values { 236 | b := bytes.Buffer{} 237 | if !handleMethods(cs, &b, vs.values[i]) { 238 | vs.strings = nil 239 | break 240 | } 241 | vs.strings[i] = b.String() 242 | } 243 | } 244 | if vs.strings == nil && cs.SpewKeys { 245 | vs.strings = make([]string, len(values)) 246 | for i := range vs.values { 247 | vs.strings[i] = Sprintf("%#v", vs.values[i].Interface()) 248 | } 249 | } 250 | return vs 251 | } 252 | 253 | // canSortSimply tests whether a reflect.Kind is a primitive that can be sorted 254 | // directly, or whether it should be considered for sorting by surrogate keys 255 | // (if the ConfigState allows it). 256 | func canSortSimply(kind reflect.Kind) bool { 257 | // This switch parallels valueSortLess, except for the default case. 258 | switch kind { 259 | case reflect.Bool: 260 | return true 261 | case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: 262 | return true 263 | case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: 264 | return true 265 | case reflect.Float32, reflect.Float64: 266 | return true 267 | case reflect.String: 268 | return true 269 | case reflect.Uintptr: 270 | return true 271 | case reflect.Array: 272 | return true 273 | } 274 | return false 275 | } 276 | 277 | // Len returns the number of values in the slice. It is part of the 278 | // sort.Interface implementation. 279 | func (s *valuesSorter) Len() int { 280 | return len(s.values) 281 | } 282 | 283 | // Swap swaps the values at the passed indices. It is part of the 284 | // sort.Interface implementation. 285 | func (s *valuesSorter) Swap(i, j int) { 286 | s.values[i], s.values[j] = s.values[j], s.values[i] 287 | if s.strings != nil { 288 | s.strings[i], s.strings[j] = s.strings[j], s.strings[i] 289 | } 290 | } 291 | 292 | // valueSortLess returns whether the first value should sort before the second 293 | // value. It is used by valueSorter.Less as part of the sort.Interface 294 | // implementation. 295 | func valueSortLess(a, b reflect.Value) bool { 296 | switch a.Kind() { 297 | case reflect.Bool: 298 | return !a.Bool() && b.Bool() 299 | case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: 300 | return a.Int() < b.Int() 301 | case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: 302 | return a.Uint() < b.Uint() 303 | case reflect.Float32, reflect.Float64: 304 | return a.Float() < b.Float() 305 | case reflect.String: 306 | return a.String() < b.String() 307 | case reflect.Uintptr: 308 | return a.Uint() < b.Uint() 309 | case reflect.Array: 310 | // Compare the contents of both arrays. 311 | l := a.Len() 312 | for i := 0; i < l; i++ { 313 | av := a.Index(i) 314 | bv := b.Index(i) 315 | if av.Interface() == bv.Interface() { 316 | continue 317 | } 318 | return valueSortLess(av, bv) 319 | } 320 | } 321 | return a.String() < b.String() 322 | } 323 | 324 | // Less returns whether the value at index i should sort before the 325 | // value at index j. It is part of the sort.Interface implementation. 326 | func (s *valuesSorter) Less(i, j int) bool { 327 | if s.strings == nil { 328 | return valueSortLess(s.values[i], s.values[j]) 329 | } 330 | return s.strings[i] < s.strings[j] 331 | } 332 | 333 | // sortValues is a sort function that handles both native types and any type that 334 | // can be converted to error or Stringer. Other inputs are sorted according to 335 | // their Value.String() value to ensure display stability. 336 | func sortValues(values []reflect.Value, cs *ConfigState) { 337 | if len(values) == 0 { 338 | return 339 | } 340 | sort.Sort(newValuesSorter(values, cs)) 341 | } 342 | -------------------------------------------------------------------------------- /vendor/github.com/davecgh/go-spew/spew/config.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 Dave Collins 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | package spew 18 | 19 | import ( 20 | "bytes" 21 | "fmt" 22 | "io" 23 | "os" 24 | ) 25 | 26 | // ConfigState houses the configuration options used by spew to format and 27 | // display values. There is a global instance, Config, that is used to control 28 | // all top-level Formatter and Dump functionality. Each ConfigState instance 29 | // provides methods equivalent to the top-level functions. 30 | // 31 | // The zero value for ConfigState provides no indentation. You would typically 32 | // want to set it to a space or a tab. 33 | // 34 | // Alternatively, you can use NewDefaultConfig to get a ConfigState instance 35 | // with default settings. See the documentation of NewDefaultConfig for default 36 | // values. 37 | type ConfigState struct { 38 | // Indent specifies the string to use for each indentation level. The 39 | // global config instance that all top-level functions use set this to a 40 | // single space by default. If you would like more indentation, you might 41 | // set this to a tab with "\t" or perhaps two spaces with " ". 42 | Indent string 43 | 44 | // MaxDepth controls the maximum number of levels to descend into nested 45 | // data structures. The default, 0, means there is no limit. 46 | // 47 | // NOTE: Circular data structures are properly detected, so it is not 48 | // necessary to set this value unless you specifically want to limit deeply 49 | // nested data structures. 50 | MaxDepth int 51 | 52 | // DisableMethods specifies whether or not error and Stringer interfaces are 53 | // invoked for types that implement them. 54 | DisableMethods bool 55 | 56 | // DisablePointerMethods specifies whether or not to check for and invoke 57 | // error and Stringer interfaces on types which only accept a pointer 58 | // receiver when the current type is not a pointer. 59 | // 60 | // NOTE: This might be an unsafe action since calling one of these methods 61 | // with a pointer receiver could technically mutate the value, however, 62 | // in practice, types which choose to satisify an error or Stringer 63 | // interface with a pointer receiver should not be mutating their state 64 | // inside these interface methods. As a result, this option relies on 65 | // access to the unsafe package, so it will not have any effect when 66 | // running in environments without access to the unsafe package such as 67 | // Google App Engine or with the "safe" build tag specified. 68 | DisablePointerMethods bool 69 | 70 | // DisablePointerAddresses specifies whether to disable the printing of 71 | // pointer addresses. This is useful when diffing data structures in tests. 72 | DisablePointerAddresses bool 73 | 74 | // DisableCapacities specifies whether to disable the printing of capacities 75 | // for arrays, slices, maps and channels. This is useful when diffing 76 | // data structures in tests. 77 | DisableCapacities bool 78 | 79 | // ContinueOnMethod specifies whether or not recursion should continue once 80 | // a custom error or Stringer interface is invoked. The default, false, 81 | // means it will print the results of invoking the custom error or Stringer 82 | // interface and return immediately instead of continuing to recurse into 83 | // the internals of the data type. 84 | // 85 | // NOTE: This flag does not have any effect if method invocation is disabled 86 | // via the DisableMethods or DisablePointerMethods options. 87 | ContinueOnMethod bool 88 | 89 | // SortKeys specifies map keys should be sorted before being printed. Use 90 | // this to have a more deterministic, diffable output. Note that only 91 | // native types (bool, int, uint, floats, uintptr and string) and types 92 | // that support the error or Stringer interfaces (if methods are 93 | // enabled) are supported, with other types sorted according to the 94 | // reflect.Value.String() output which guarantees display stability. 95 | SortKeys bool 96 | 97 | // SpewKeys specifies that, as a last resort attempt, map keys should 98 | // be spewed to strings and sorted by those strings. This is only 99 | // considered if SortKeys is true. 100 | SpewKeys bool 101 | } 102 | 103 | // Config is the active configuration of the top-level functions. 104 | // The configuration can be changed by modifying the contents of spew.Config. 105 | var Config = ConfigState{Indent: " "} 106 | 107 | // Errorf is a wrapper for fmt.Errorf that treats each argument as if it were 108 | // passed with a Formatter interface returned by c.NewFormatter. It returns 109 | // the formatted string as a value that satisfies error. See NewFormatter 110 | // for formatting details. 111 | // 112 | // This function is shorthand for the following syntax: 113 | // 114 | // fmt.Errorf(format, c.NewFormatter(a), c.NewFormatter(b)) 115 | func (c *ConfigState) Errorf(format string, a ...interface{}) (err error) { 116 | return fmt.Errorf(format, c.convertArgs(a)...) 117 | } 118 | 119 | // Fprint is a wrapper for fmt.Fprint that treats each argument as if it were 120 | // passed with a Formatter interface returned by c.NewFormatter. It returns 121 | // the number of bytes written and any write error encountered. See 122 | // NewFormatter for formatting details. 123 | // 124 | // This function is shorthand for the following syntax: 125 | // 126 | // fmt.Fprint(w, c.NewFormatter(a), c.NewFormatter(b)) 127 | func (c *ConfigState) Fprint(w io.Writer, a ...interface{}) (n int, err error) { 128 | return fmt.Fprint(w, c.convertArgs(a)...) 129 | } 130 | 131 | // Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were 132 | // passed with a Formatter interface returned by c.NewFormatter. It returns 133 | // the number of bytes written and any write error encountered. See 134 | // NewFormatter for formatting details. 135 | // 136 | // This function is shorthand for the following syntax: 137 | // 138 | // fmt.Fprintf(w, format, c.NewFormatter(a), c.NewFormatter(b)) 139 | func (c *ConfigState) Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) { 140 | return fmt.Fprintf(w, format, c.convertArgs(a)...) 141 | } 142 | 143 | // Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it 144 | // passed with a Formatter interface returned by c.NewFormatter. See 145 | // NewFormatter for formatting details. 146 | // 147 | // This function is shorthand for the following syntax: 148 | // 149 | // fmt.Fprintln(w, c.NewFormatter(a), c.NewFormatter(b)) 150 | func (c *ConfigState) Fprintln(w io.Writer, a ...interface{}) (n int, err error) { 151 | return fmt.Fprintln(w, c.convertArgs(a)...) 152 | } 153 | 154 | // Print is a wrapper for fmt.Print that treats each argument as if it were 155 | // passed with a Formatter interface returned by c.NewFormatter. It returns 156 | // the number of bytes written and any write error encountered. See 157 | // NewFormatter for formatting details. 158 | // 159 | // This function is shorthand for the following syntax: 160 | // 161 | // fmt.Print(c.NewFormatter(a), c.NewFormatter(b)) 162 | func (c *ConfigState) Print(a ...interface{}) (n int, err error) { 163 | return fmt.Print(c.convertArgs(a)...) 164 | } 165 | 166 | // Printf is a wrapper for fmt.Printf that treats each argument as if it were 167 | // passed with a Formatter interface returned by c.NewFormatter. It returns 168 | // the number of bytes written and any write error encountered. See 169 | // NewFormatter for formatting details. 170 | // 171 | // This function is shorthand for the following syntax: 172 | // 173 | // fmt.Printf(format, c.NewFormatter(a), c.NewFormatter(b)) 174 | func (c *ConfigState) Printf(format string, a ...interface{}) (n int, err error) { 175 | return fmt.Printf(format, c.convertArgs(a)...) 176 | } 177 | 178 | // Println is a wrapper for fmt.Println that treats each argument as if it were 179 | // passed with a Formatter interface returned by c.NewFormatter. It returns 180 | // the number of bytes written and any write error encountered. See 181 | // NewFormatter for formatting details. 182 | // 183 | // This function is shorthand for the following syntax: 184 | // 185 | // fmt.Println(c.NewFormatter(a), c.NewFormatter(b)) 186 | func (c *ConfigState) Println(a ...interface{}) (n int, err error) { 187 | return fmt.Println(c.convertArgs(a)...) 188 | } 189 | 190 | // Sprint is a wrapper for fmt.Sprint that treats each argument as if it were 191 | // passed with a Formatter interface returned by c.NewFormatter. It returns 192 | // the resulting string. See NewFormatter for formatting details. 193 | // 194 | // This function is shorthand for the following syntax: 195 | // 196 | // fmt.Sprint(c.NewFormatter(a), c.NewFormatter(b)) 197 | func (c *ConfigState) Sprint(a ...interface{}) string { 198 | return fmt.Sprint(c.convertArgs(a)...) 199 | } 200 | 201 | // Sprintf is a wrapper for fmt.Sprintf that treats each argument as if it were 202 | // passed with a Formatter interface returned by c.NewFormatter. It returns 203 | // the resulting string. See NewFormatter for formatting details. 204 | // 205 | // This function is shorthand for the following syntax: 206 | // 207 | // fmt.Sprintf(format, c.NewFormatter(a), c.NewFormatter(b)) 208 | func (c *ConfigState) Sprintf(format string, a ...interface{}) string { 209 | return fmt.Sprintf(format, c.convertArgs(a)...) 210 | } 211 | 212 | // Sprintln is a wrapper for fmt.Sprintln that treats each argument as if it 213 | // were passed with a Formatter interface returned by c.NewFormatter. It 214 | // returns the resulting string. See NewFormatter for formatting details. 215 | // 216 | // This function is shorthand for the following syntax: 217 | // 218 | // fmt.Sprintln(c.NewFormatter(a), c.NewFormatter(b)) 219 | func (c *ConfigState) Sprintln(a ...interface{}) string { 220 | return fmt.Sprintln(c.convertArgs(a)...) 221 | } 222 | 223 | /* 224 | NewFormatter returns a custom formatter that satisfies the fmt.Formatter 225 | interface. As a result, it integrates cleanly with standard fmt package 226 | printing functions. The formatter is useful for inline printing of smaller data 227 | types similar to the standard %v format specifier. 228 | 229 | The custom formatter only responds to the %v (most compact), %+v (adds pointer 230 | addresses), %#v (adds types), and %#+v (adds types and pointer addresses) verb 231 | combinations. Any other verbs such as %x and %q will be sent to the the 232 | standard fmt package for formatting. In addition, the custom formatter ignores 233 | the width and precision arguments (however they will still work on the format 234 | specifiers not handled by the custom formatter). 235 | 236 | Typically this function shouldn't be called directly. It is much easier to make 237 | use of the custom formatter by calling one of the convenience functions such as 238 | c.Printf, c.Println, or c.Printf. 239 | */ 240 | func (c *ConfigState) NewFormatter(v interface{}) fmt.Formatter { 241 | return newFormatter(c, v) 242 | } 243 | 244 | // Fdump formats and displays the passed arguments to io.Writer w. It formats 245 | // exactly the same as Dump. 246 | func (c *ConfigState) Fdump(w io.Writer, a ...interface{}) { 247 | fdump(c, w, a...) 248 | } 249 | 250 | /* 251 | Dump displays the passed parameters to standard out with newlines, customizable 252 | indentation, and additional debug information such as complete types and all 253 | pointer addresses used to indirect to the final value. It provides the 254 | following features over the built-in printing facilities provided by the fmt 255 | package: 256 | 257 | * Pointers are dereferenced and followed 258 | * Circular data structures are detected and handled properly 259 | * Custom Stringer/error interfaces are optionally invoked, including 260 | on unexported types 261 | * Custom types which only implement the Stringer/error interfaces via 262 | a pointer receiver are optionally invoked when passing non-pointer 263 | variables 264 | * Byte arrays and slices are dumped like the hexdump -C command which 265 | includes offsets, byte values in hex, and ASCII output 266 | 267 | The configuration options are controlled by modifying the public members 268 | of c. See ConfigState for options documentation. 269 | 270 | See Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to 271 | get the formatted result as a string. 272 | */ 273 | func (c *ConfigState) Dump(a ...interface{}) { 274 | fdump(c, os.Stdout, a...) 275 | } 276 | 277 | // Sdump returns a string with the passed arguments formatted exactly the same 278 | // as Dump. 279 | func (c *ConfigState) Sdump(a ...interface{}) string { 280 | var buf bytes.Buffer 281 | fdump(c, &buf, a...) 282 | return buf.String() 283 | } 284 | 285 | // convertArgs accepts a slice of arguments and returns a slice of the same 286 | // length with each argument converted to a spew Formatter interface using 287 | // the ConfigState associated with s. 288 | func (c *ConfigState) convertArgs(args []interface{}) (formatters []interface{}) { 289 | formatters = make([]interface{}, len(args)) 290 | for index, arg := range args { 291 | formatters[index] = newFormatter(c, arg) 292 | } 293 | return formatters 294 | } 295 | 296 | // NewDefaultConfig returns a ConfigState with the following default settings. 297 | // 298 | // Indent: " " 299 | // MaxDepth: 0 300 | // DisableMethods: false 301 | // DisablePointerMethods: false 302 | // ContinueOnMethod: false 303 | // SortKeys: false 304 | func NewDefaultConfig() *ConfigState { 305 | return &ConfigState{Indent: " "} 306 | } 307 | -------------------------------------------------------------------------------- /vendor/github.com/davecgh/go-spew/spew/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 Dave Collins 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* 18 | Package spew implements a deep pretty printer for Go data structures to aid in 19 | debugging. 20 | 21 | A quick overview of the additional features spew provides over the built-in 22 | printing facilities for Go data types are as follows: 23 | 24 | * Pointers are dereferenced and followed 25 | * Circular data structures are detected and handled properly 26 | * Custom Stringer/error interfaces are optionally invoked, including 27 | on unexported types 28 | * Custom types which only implement the Stringer/error interfaces via 29 | a pointer receiver are optionally invoked when passing non-pointer 30 | variables 31 | * Byte arrays and slices are dumped like the hexdump -C command which 32 | includes offsets, byte values in hex, and ASCII output (only when using 33 | Dump style) 34 | 35 | There are two different approaches spew allows for dumping Go data structures: 36 | 37 | * Dump style which prints with newlines, customizable indentation, 38 | and additional debug information such as types and all pointer addresses 39 | used to indirect to the final value 40 | * A custom Formatter interface that integrates cleanly with the standard fmt 41 | package and replaces %v, %+v, %#v, and %#+v to provide inline printing 42 | similar to the default %v while providing the additional functionality 43 | outlined above and passing unsupported format verbs such as %x and %q 44 | along to fmt 45 | 46 | Quick Start 47 | 48 | This section demonstrates how to quickly get started with spew. See the 49 | sections below for further details on formatting and configuration options. 50 | 51 | To dump a variable with full newlines, indentation, type, and pointer 52 | information use Dump, Fdump, or Sdump: 53 | spew.Dump(myVar1, myVar2, ...) 54 | spew.Fdump(someWriter, myVar1, myVar2, ...) 55 | str := spew.Sdump(myVar1, myVar2, ...) 56 | 57 | Alternatively, if you would prefer to use format strings with a compacted inline 58 | printing style, use the convenience wrappers Printf, Fprintf, etc with 59 | %v (most compact), %+v (adds pointer addresses), %#v (adds types), or 60 | %#+v (adds types and pointer addresses): 61 | spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2) 62 | spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) 63 | spew.Fprintf(someWriter, "myVar1: %v -- myVar2: %+v", myVar1, myVar2) 64 | spew.Fprintf(someWriter, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) 65 | 66 | Configuration Options 67 | 68 | Configuration of spew is handled by fields in the ConfigState type. For 69 | convenience, all of the top-level functions use a global state available 70 | via the spew.Config global. 71 | 72 | It is also possible to create a ConfigState instance that provides methods 73 | equivalent to the top-level functions. This allows concurrent configuration 74 | options. See the ConfigState documentation for more details. 75 | 76 | The following configuration options are available: 77 | * Indent 78 | String to use for each indentation level for Dump functions. 79 | It is a single space by default. A popular alternative is "\t". 80 | 81 | * MaxDepth 82 | Maximum number of levels to descend into nested data structures. 83 | There is no limit by default. 84 | 85 | * DisableMethods 86 | Disables invocation of error and Stringer interface methods. 87 | Method invocation is enabled by default. 88 | 89 | * DisablePointerMethods 90 | Disables invocation of error and Stringer interface methods on types 91 | which only accept pointer receivers from non-pointer variables. 92 | Pointer method invocation is enabled by default. 93 | 94 | * ContinueOnMethod 95 | Enables recursion into types after invoking error and Stringer interface 96 | methods. Recursion after method invocation is disabled by default. 97 | 98 | * SortKeys 99 | Specifies map keys should be sorted before being printed. Use 100 | this to have a more deterministic, diffable output. Note that 101 | only native types (bool, int, uint, floats, uintptr and string) 102 | and types which implement error or Stringer interfaces are 103 | supported with other types sorted according to the 104 | reflect.Value.String() output which guarantees display 105 | stability. Natural map order is used by default. 106 | 107 | * SpewKeys 108 | Specifies that, as a last resort attempt, map keys should be 109 | spewed to strings and sorted by those strings. This is only 110 | considered if SortKeys is true. 111 | 112 | Dump Usage 113 | 114 | Simply call spew.Dump with a list of variables you want to dump: 115 | 116 | spew.Dump(myVar1, myVar2, ...) 117 | 118 | You may also call spew.Fdump if you would prefer to output to an arbitrary 119 | io.Writer. For example, to dump to standard error: 120 | 121 | spew.Fdump(os.Stderr, myVar1, myVar2, ...) 122 | 123 | A third option is to call spew.Sdump to get the formatted output as a string: 124 | 125 | str := spew.Sdump(myVar1, myVar2, ...) 126 | 127 | Sample Dump Output 128 | 129 | See the Dump example for details on the setup of the types and variables being 130 | shown here. 131 | 132 | (main.Foo) { 133 | unexportedField: (*main.Bar)(0xf84002e210)({ 134 | flag: (main.Flag) flagTwo, 135 | data: (uintptr) 136 | }), 137 | ExportedField: (map[interface {}]interface {}) (len=1) { 138 | (string) (len=3) "one": (bool) true 139 | } 140 | } 141 | 142 | Byte (and uint8) arrays and slices are displayed uniquely like the hexdump -C 143 | command as shown. 144 | ([]uint8) (len=32 cap=32) { 145 | 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 |............... | 146 | 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 |!"#$%&'()*+,-./0| 147 | 00000020 31 32 |12| 148 | } 149 | 150 | Custom Formatter 151 | 152 | Spew provides a custom formatter that implements the fmt.Formatter interface 153 | so that it integrates cleanly with standard fmt package printing functions. The 154 | formatter is useful for inline printing of smaller data types similar to the 155 | standard %v format specifier. 156 | 157 | The custom formatter only responds to the %v (most compact), %+v (adds pointer 158 | addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb 159 | combinations. Any other verbs such as %x and %q will be sent to the the 160 | standard fmt package for formatting. In addition, the custom formatter ignores 161 | the width and precision arguments (however they will still work on the format 162 | specifiers not handled by the custom formatter). 163 | 164 | Custom Formatter Usage 165 | 166 | The simplest way to make use of the spew custom formatter is to call one of the 167 | convenience functions such as spew.Printf, spew.Println, or spew.Printf. The 168 | functions have syntax you are most likely already familiar with: 169 | 170 | spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2) 171 | spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) 172 | spew.Println(myVar, myVar2) 173 | spew.Fprintf(os.Stderr, "myVar1: %v -- myVar2: %+v", myVar1, myVar2) 174 | spew.Fprintf(os.Stderr, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) 175 | 176 | See the Index for the full list convenience functions. 177 | 178 | Sample Formatter Output 179 | 180 | Double pointer to a uint8: 181 | %v: <**>5 182 | %+v: <**>(0xf8400420d0->0xf8400420c8)5 183 | %#v: (**uint8)5 184 | %#+v: (**uint8)(0xf8400420d0->0xf8400420c8)5 185 | 186 | Pointer to circular struct with a uint8 field and a pointer to itself: 187 | %v: <*>{1 <*>} 188 | %+v: <*>(0xf84003e260){ui8:1 c:<*>(0xf84003e260)} 189 | %#v: (*main.circular){ui8:(uint8)1 c:(*main.circular)} 190 | %#+v: (*main.circular)(0xf84003e260){ui8:(uint8)1 c:(*main.circular)(0xf84003e260)} 191 | 192 | See the Printf example for details on the setup of variables being shown 193 | here. 194 | 195 | Errors 196 | 197 | Since it is possible for custom Stringer/error interfaces to panic, spew 198 | detects them and handles them internally by printing the panic information 199 | inline with the output. Since spew is intended to provide deep pretty printing 200 | capabilities on structures, it intentionally does not return any errors. 201 | */ 202 | package spew 203 | -------------------------------------------------------------------------------- /vendor/github.com/davecgh/go-spew/spew/format.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 Dave Collins 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | package spew 18 | 19 | import ( 20 | "bytes" 21 | "fmt" 22 | "reflect" 23 | "strconv" 24 | "strings" 25 | ) 26 | 27 | // supportedFlags is a list of all the character flags supported by fmt package. 28 | const supportedFlags = "0-+# " 29 | 30 | // formatState implements the fmt.Formatter interface and contains information 31 | // about the state of a formatting operation. The NewFormatter function can 32 | // be used to get a new Formatter which can be used directly as arguments 33 | // in standard fmt package printing calls. 34 | type formatState struct { 35 | value interface{} 36 | fs fmt.State 37 | depth int 38 | pointers map[uintptr]int 39 | ignoreNextType bool 40 | cs *ConfigState 41 | } 42 | 43 | // buildDefaultFormat recreates the original format string without precision 44 | // and width information to pass in to fmt.Sprintf in the case of an 45 | // unrecognized type. Unless new types are added to the language, this 46 | // function won't ever be called. 47 | func (f *formatState) buildDefaultFormat() (format string) { 48 | buf := bytes.NewBuffer(percentBytes) 49 | 50 | for _, flag := range supportedFlags { 51 | if f.fs.Flag(int(flag)) { 52 | buf.WriteRune(flag) 53 | } 54 | } 55 | 56 | buf.WriteRune('v') 57 | 58 | format = buf.String() 59 | return format 60 | } 61 | 62 | // constructOrigFormat recreates the original format string including precision 63 | // and width information to pass along to the standard fmt package. This allows 64 | // automatic deferral of all format strings this package doesn't support. 65 | func (f *formatState) constructOrigFormat(verb rune) (format string) { 66 | buf := bytes.NewBuffer(percentBytes) 67 | 68 | for _, flag := range supportedFlags { 69 | if f.fs.Flag(int(flag)) { 70 | buf.WriteRune(flag) 71 | } 72 | } 73 | 74 | if width, ok := f.fs.Width(); ok { 75 | buf.WriteString(strconv.Itoa(width)) 76 | } 77 | 78 | if precision, ok := f.fs.Precision(); ok { 79 | buf.Write(precisionBytes) 80 | buf.WriteString(strconv.Itoa(precision)) 81 | } 82 | 83 | buf.WriteRune(verb) 84 | 85 | format = buf.String() 86 | return format 87 | } 88 | 89 | // unpackValue returns values inside of non-nil interfaces when possible and 90 | // ensures that types for values which have been unpacked from an interface 91 | // are displayed when the show types flag is also set. 92 | // This is useful for data types like structs, arrays, slices, and maps which 93 | // can contain varying types packed inside an interface. 94 | func (f *formatState) unpackValue(v reflect.Value) reflect.Value { 95 | if v.Kind() == reflect.Interface { 96 | f.ignoreNextType = false 97 | if !v.IsNil() { 98 | v = v.Elem() 99 | } 100 | } 101 | return v 102 | } 103 | 104 | // formatPtr handles formatting of pointers by indirecting them as necessary. 105 | func (f *formatState) formatPtr(v reflect.Value) { 106 | // Display nil if top level pointer is nil. 107 | showTypes := f.fs.Flag('#') 108 | if v.IsNil() && (!showTypes || f.ignoreNextType) { 109 | f.fs.Write(nilAngleBytes) 110 | return 111 | } 112 | 113 | // Remove pointers at or below the current depth from map used to detect 114 | // circular refs. 115 | for k, depth := range f.pointers { 116 | if depth >= f.depth { 117 | delete(f.pointers, k) 118 | } 119 | } 120 | 121 | // Keep list of all dereferenced pointers to possibly show later. 122 | pointerChain := make([]uintptr, 0) 123 | 124 | // Figure out how many levels of indirection there are by derferencing 125 | // pointers and unpacking interfaces down the chain while detecting circular 126 | // references. 127 | nilFound := false 128 | cycleFound := false 129 | indirects := 0 130 | ve := v 131 | for ve.Kind() == reflect.Ptr { 132 | if ve.IsNil() { 133 | nilFound = true 134 | break 135 | } 136 | indirects++ 137 | addr := ve.Pointer() 138 | pointerChain = append(pointerChain, addr) 139 | if pd, ok := f.pointers[addr]; ok && pd < f.depth { 140 | cycleFound = true 141 | indirects-- 142 | break 143 | } 144 | f.pointers[addr] = f.depth 145 | 146 | ve = ve.Elem() 147 | if ve.Kind() == reflect.Interface { 148 | if ve.IsNil() { 149 | nilFound = true 150 | break 151 | } 152 | ve = ve.Elem() 153 | } 154 | } 155 | 156 | // Display type or indirection level depending on flags. 157 | if showTypes && !f.ignoreNextType { 158 | f.fs.Write(openParenBytes) 159 | f.fs.Write(bytes.Repeat(asteriskBytes, indirects)) 160 | f.fs.Write([]byte(ve.Type().String())) 161 | f.fs.Write(closeParenBytes) 162 | } else { 163 | if nilFound || cycleFound { 164 | indirects += strings.Count(ve.Type().String(), "*") 165 | } 166 | f.fs.Write(openAngleBytes) 167 | f.fs.Write([]byte(strings.Repeat("*", indirects))) 168 | f.fs.Write(closeAngleBytes) 169 | } 170 | 171 | // Display pointer information depending on flags. 172 | if f.fs.Flag('+') && (len(pointerChain) > 0) { 173 | f.fs.Write(openParenBytes) 174 | for i, addr := range pointerChain { 175 | if i > 0 { 176 | f.fs.Write(pointerChainBytes) 177 | } 178 | printHexPtr(f.fs, addr) 179 | } 180 | f.fs.Write(closeParenBytes) 181 | } 182 | 183 | // Display dereferenced value. 184 | switch { 185 | case nilFound == true: 186 | f.fs.Write(nilAngleBytes) 187 | 188 | case cycleFound == true: 189 | f.fs.Write(circularShortBytes) 190 | 191 | default: 192 | f.ignoreNextType = true 193 | f.format(ve) 194 | } 195 | } 196 | 197 | // format is the main workhorse for providing the Formatter interface. It 198 | // uses the passed reflect value to figure out what kind of object we are 199 | // dealing with and formats it appropriately. It is a recursive function, 200 | // however circular data structures are detected and handled properly. 201 | func (f *formatState) format(v reflect.Value) { 202 | // Handle invalid reflect values immediately. 203 | kind := v.Kind() 204 | if kind == reflect.Invalid { 205 | f.fs.Write(invalidAngleBytes) 206 | return 207 | } 208 | 209 | // Handle pointers specially. 210 | if kind == reflect.Ptr { 211 | f.formatPtr(v) 212 | return 213 | } 214 | 215 | // Print type information unless already handled elsewhere. 216 | if !f.ignoreNextType && f.fs.Flag('#') { 217 | f.fs.Write(openParenBytes) 218 | f.fs.Write([]byte(v.Type().String())) 219 | f.fs.Write(closeParenBytes) 220 | } 221 | f.ignoreNextType = false 222 | 223 | // Call Stringer/error interfaces if they exist and the handle methods 224 | // flag is enabled. 225 | if !f.cs.DisableMethods { 226 | if (kind != reflect.Invalid) && (kind != reflect.Interface) { 227 | if handled := handleMethods(f.cs, f.fs, v); handled { 228 | return 229 | } 230 | } 231 | } 232 | 233 | switch kind { 234 | case reflect.Invalid: 235 | // Do nothing. We should never get here since invalid has already 236 | // been handled above. 237 | 238 | case reflect.Bool: 239 | printBool(f.fs, v.Bool()) 240 | 241 | case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: 242 | printInt(f.fs, v.Int(), 10) 243 | 244 | case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: 245 | printUint(f.fs, v.Uint(), 10) 246 | 247 | case reflect.Float32: 248 | printFloat(f.fs, v.Float(), 32) 249 | 250 | case reflect.Float64: 251 | printFloat(f.fs, v.Float(), 64) 252 | 253 | case reflect.Complex64: 254 | printComplex(f.fs, v.Complex(), 32) 255 | 256 | case reflect.Complex128: 257 | printComplex(f.fs, v.Complex(), 64) 258 | 259 | case reflect.Slice: 260 | if v.IsNil() { 261 | f.fs.Write(nilAngleBytes) 262 | break 263 | } 264 | fallthrough 265 | 266 | case reflect.Array: 267 | f.fs.Write(openBracketBytes) 268 | f.depth++ 269 | if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) { 270 | f.fs.Write(maxShortBytes) 271 | } else { 272 | numEntries := v.Len() 273 | for i := 0; i < numEntries; i++ { 274 | if i > 0 { 275 | f.fs.Write(spaceBytes) 276 | } 277 | f.ignoreNextType = true 278 | f.format(f.unpackValue(v.Index(i))) 279 | } 280 | } 281 | f.depth-- 282 | f.fs.Write(closeBracketBytes) 283 | 284 | case reflect.String: 285 | f.fs.Write([]byte(v.String())) 286 | 287 | case reflect.Interface: 288 | // The only time we should get here is for nil interfaces due to 289 | // unpackValue calls. 290 | if v.IsNil() { 291 | f.fs.Write(nilAngleBytes) 292 | } 293 | 294 | case reflect.Ptr: 295 | // Do nothing. We should never get here since pointers have already 296 | // been handled above. 297 | 298 | case reflect.Map: 299 | // nil maps should be indicated as different than empty maps 300 | if v.IsNil() { 301 | f.fs.Write(nilAngleBytes) 302 | break 303 | } 304 | 305 | f.fs.Write(openMapBytes) 306 | f.depth++ 307 | if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) { 308 | f.fs.Write(maxShortBytes) 309 | } else { 310 | keys := v.MapKeys() 311 | if f.cs.SortKeys { 312 | sortValues(keys, f.cs) 313 | } 314 | for i, key := range keys { 315 | if i > 0 { 316 | f.fs.Write(spaceBytes) 317 | } 318 | f.ignoreNextType = true 319 | f.format(f.unpackValue(key)) 320 | f.fs.Write(colonBytes) 321 | f.ignoreNextType = true 322 | f.format(f.unpackValue(v.MapIndex(key))) 323 | } 324 | } 325 | f.depth-- 326 | f.fs.Write(closeMapBytes) 327 | 328 | case reflect.Struct: 329 | numFields := v.NumField() 330 | f.fs.Write(openBraceBytes) 331 | f.depth++ 332 | if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) { 333 | f.fs.Write(maxShortBytes) 334 | } else { 335 | vt := v.Type() 336 | for i := 0; i < numFields; i++ { 337 | if i > 0 { 338 | f.fs.Write(spaceBytes) 339 | } 340 | vtf := vt.Field(i) 341 | if f.fs.Flag('+') || f.fs.Flag('#') { 342 | f.fs.Write([]byte(vtf.Name)) 343 | f.fs.Write(colonBytes) 344 | } 345 | f.format(f.unpackValue(v.Field(i))) 346 | } 347 | } 348 | f.depth-- 349 | f.fs.Write(closeBraceBytes) 350 | 351 | case reflect.Uintptr: 352 | printHexPtr(f.fs, uintptr(v.Uint())) 353 | 354 | case reflect.UnsafePointer, reflect.Chan, reflect.Func: 355 | printHexPtr(f.fs, v.Pointer()) 356 | 357 | // There were not any other types at the time this code was written, but 358 | // fall back to letting the default fmt package handle it if any get added. 359 | default: 360 | format := f.buildDefaultFormat() 361 | if v.CanInterface() { 362 | fmt.Fprintf(f.fs, format, v.Interface()) 363 | } else { 364 | fmt.Fprintf(f.fs, format, v.String()) 365 | } 366 | } 367 | } 368 | 369 | // Format satisfies the fmt.Formatter interface. See NewFormatter for usage 370 | // details. 371 | func (f *formatState) Format(fs fmt.State, verb rune) { 372 | f.fs = fs 373 | 374 | // Use standard formatting for verbs that are not v. 375 | if verb != 'v' { 376 | format := f.constructOrigFormat(verb) 377 | fmt.Fprintf(fs, format, f.value) 378 | return 379 | } 380 | 381 | if f.value == nil { 382 | if fs.Flag('#') { 383 | fs.Write(interfaceBytes) 384 | } 385 | fs.Write(nilAngleBytes) 386 | return 387 | } 388 | 389 | f.format(reflect.ValueOf(f.value)) 390 | } 391 | 392 | // newFormatter is a helper function to consolidate the logic from the various 393 | // public methods which take varying config states. 394 | func newFormatter(cs *ConfigState, v interface{}) fmt.Formatter { 395 | fs := &formatState{value: v, cs: cs} 396 | fs.pointers = make(map[uintptr]int) 397 | return fs 398 | } 399 | 400 | /* 401 | NewFormatter returns a custom formatter that satisfies the fmt.Formatter 402 | interface. As a result, it integrates cleanly with standard fmt package 403 | printing functions. The formatter is useful for inline printing of smaller data 404 | types similar to the standard %v format specifier. 405 | 406 | The custom formatter only responds to the %v (most compact), %+v (adds pointer 407 | addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb 408 | combinations. Any other verbs such as %x and %q will be sent to the the 409 | standard fmt package for formatting. In addition, the custom formatter ignores 410 | the width and precision arguments (however they will still work on the format 411 | specifiers not handled by the custom formatter). 412 | 413 | Typically this function shouldn't be called directly. It is much easier to make 414 | use of the custom formatter by calling one of the convenience functions such as 415 | Printf, Println, or Fprintf. 416 | */ 417 | func NewFormatter(v interface{}) fmt.Formatter { 418 | return newFormatter(&Config, v) 419 | } 420 | -------------------------------------------------------------------------------- /vendor/github.com/davecgh/go-spew/spew/spew.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 Dave Collins 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | package spew 18 | 19 | import ( 20 | "fmt" 21 | "io" 22 | ) 23 | 24 | // Errorf is a wrapper for fmt.Errorf that treats each argument as if it were 25 | // passed with a default Formatter interface returned by NewFormatter. It 26 | // returns the formatted string as a value that satisfies error. See 27 | // NewFormatter for formatting details. 28 | // 29 | // This function is shorthand for the following syntax: 30 | // 31 | // fmt.Errorf(format, spew.NewFormatter(a), spew.NewFormatter(b)) 32 | func Errorf(format string, a ...interface{}) (err error) { 33 | return fmt.Errorf(format, convertArgs(a)...) 34 | } 35 | 36 | // Fprint is a wrapper for fmt.Fprint that treats each argument as if it were 37 | // passed with a default Formatter interface returned by NewFormatter. It 38 | // returns the number of bytes written and any write error encountered. See 39 | // NewFormatter for formatting details. 40 | // 41 | // This function is shorthand for the following syntax: 42 | // 43 | // fmt.Fprint(w, spew.NewFormatter(a), spew.NewFormatter(b)) 44 | func Fprint(w io.Writer, a ...interface{}) (n int, err error) { 45 | return fmt.Fprint(w, convertArgs(a)...) 46 | } 47 | 48 | // Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were 49 | // passed with a default Formatter interface returned by NewFormatter. It 50 | // returns the number of bytes written and any write error encountered. See 51 | // NewFormatter for formatting details. 52 | // 53 | // This function is shorthand for the following syntax: 54 | // 55 | // fmt.Fprintf(w, format, spew.NewFormatter(a), spew.NewFormatter(b)) 56 | func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) { 57 | return fmt.Fprintf(w, format, convertArgs(a)...) 58 | } 59 | 60 | // Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it 61 | // passed with a default Formatter interface returned by NewFormatter. See 62 | // NewFormatter for formatting details. 63 | // 64 | // This function is shorthand for the following syntax: 65 | // 66 | // fmt.Fprintln(w, spew.NewFormatter(a), spew.NewFormatter(b)) 67 | func Fprintln(w io.Writer, a ...interface{}) (n int, err error) { 68 | return fmt.Fprintln(w, convertArgs(a)...) 69 | } 70 | 71 | // Print is a wrapper for fmt.Print that treats each argument as if it were 72 | // passed with a default Formatter interface returned by NewFormatter. It 73 | // returns the number of bytes written and any write error encountered. See 74 | // NewFormatter for formatting details. 75 | // 76 | // This function is shorthand for the following syntax: 77 | // 78 | // fmt.Print(spew.NewFormatter(a), spew.NewFormatter(b)) 79 | func Print(a ...interface{}) (n int, err error) { 80 | return fmt.Print(convertArgs(a)...) 81 | } 82 | 83 | // Printf is a wrapper for fmt.Printf that treats each argument as if it were 84 | // passed with a default Formatter interface returned by NewFormatter. It 85 | // returns the number of bytes written and any write error encountered. See 86 | // NewFormatter for formatting details. 87 | // 88 | // This function is shorthand for the following syntax: 89 | // 90 | // fmt.Printf(format, spew.NewFormatter(a), spew.NewFormatter(b)) 91 | func Printf(format string, a ...interface{}) (n int, err error) { 92 | return fmt.Printf(format, convertArgs(a)...) 93 | } 94 | 95 | // Println is a wrapper for fmt.Println that treats each argument as if it were 96 | // passed with a default Formatter interface returned by NewFormatter. It 97 | // returns the number of bytes written and any write error encountered. See 98 | // NewFormatter for formatting details. 99 | // 100 | // This function is shorthand for the following syntax: 101 | // 102 | // fmt.Println(spew.NewFormatter(a), spew.NewFormatter(b)) 103 | func Println(a ...interface{}) (n int, err error) { 104 | return fmt.Println(convertArgs(a)...) 105 | } 106 | 107 | // Sprint is a wrapper for fmt.Sprint that treats each argument as if it were 108 | // passed with a default Formatter interface returned by NewFormatter. It 109 | // returns the resulting string. See NewFormatter for formatting details. 110 | // 111 | // This function is shorthand for the following syntax: 112 | // 113 | // fmt.Sprint(spew.NewFormatter(a), spew.NewFormatter(b)) 114 | func Sprint(a ...interface{}) string { 115 | return fmt.Sprint(convertArgs(a)...) 116 | } 117 | 118 | // Sprintf is a wrapper for fmt.Sprintf that treats each argument as if it were 119 | // passed with a default Formatter interface returned by NewFormatter. It 120 | // returns the resulting string. See NewFormatter for formatting details. 121 | // 122 | // This function is shorthand for the following syntax: 123 | // 124 | // fmt.Sprintf(format, spew.NewFormatter(a), spew.NewFormatter(b)) 125 | func Sprintf(format string, a ...interface{}) string { 126 | return fmt.Sprintf(format, convertArgs(a)...) 127 | } 128 | 129 | // Sprintln is a wrapper for fmt.Sprintln that treats each argument as if it 130 | // were passed with a default Formatter interface returned by NewFormatter. It 131 | // returns the resulting string. See NewFormatter for formatting details. 132 | // 133 | // This function is shorthand for the following syntax: 134 | // 135 | // fmt.Sprintln(spew.NewFormatter(a), spew.NewFormatter(b)) 136 | func Sprintln(a ...interface{}) string { 137 | return fmt.Sprintln(convertArgs(a)...) 138 | } 139 | 140 | // convertArgs accepts a slice of arguments and returns a slice of the same 141 | // length with each argument converted to a default spew Formatter interface. 142 | func convertArgs(args []interface{}) (formatters []interface{}) { 143 | formatters = make([]interface{}, len(args)) 144 | for index, arg := range args { 145 | formatters[index] = NewFormatter(arg) 146 | } 147 | return formatters 148 | } 149 | -------------------------------------------------------------------------------- /vendor/github.com/julienschmidt/httprouter/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Julien Schmidt. All rights reserved. 2 | 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | * The names of the contributors may not be used to endorse or promote 12 | products derived from this software without specific prior written 13 | permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL JULIEN SCHMIDT BE LIABLE FOR ANY 19 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /vendor/github.com/julienschmidt/httprouter/path.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Julien Schmidt. All rights reserved. 2 | // Based on the path package, Copyright 2009 The Go Authors. 3 | // Use of this source code is governed by a BSD-style license that can be found 4 | // in the LICENSE file. 5 | 6 | package httprouter 7 | 8 | // CleanPath is the URL version of path.Clean, it returns a canonical URL path 9 | // for p, eliminating . and .. elements. 10 | // 11 | // The following rules are applied iteratively until no further processing can 12 | // be done: 13 | // 1. Replace multiple slashes with a single slash. 14 | // 2. Eliminate each . path name element (the current directory). 15 | // 3. Eliminate each inner .. path name element (the parent directory) 16 | // along with the non-.. element that precedes it. 17 | // 4. Eliminate .. elements that begin a rooted path: 18 | // that is, replace "/.." by "/" at the beginning of a path. 19 | // 20 | // If the result of this process is an empty string, "/" is returned 21 | func CleanPath(p string) string { 22 | // Turn empty string into "/" 23 | if p == "" { 24 | return "/" 25 | } 26 | 27 | n := len(p) 28 | var buf []byte 29 | 30 | // Invariants: 31 | // reading from path; r is index of next byte to process. 32 | // writing to buf; w is index of next byte to write. 33 | 34 | // path must start with '/' 35 | r := 1 36 | w := 1 37 | 38 | if p[0] != '/' { 39 | r = 0 40 | buf = make([]byte, n+1) 41 | buf[0] = '/' 42 | } 43 | 44 | trailing := n > 2 && p[n-1] == '/' 45 | 46 | // A bit more clunky without a 'lazybuf' like the path package, but the loop 47 | // gets completely inlined (bufApp). So in contrast to the path package this 48 | // loop has no expensive function calls (except 1x make) 49 | 50 | for r < n { 51 | switch { 52 | case p[r] == '/': 53 | // empty path element, trailing slash is added after the end 54 | r++ 55 | 56 | case p[r] == '.' && r+1 == n: 57 | trailing = true 58 | r++ 59 | 60 | case p[r] == '.' && p[r+1] == '/': 61 | // . element 62 | r++ 63 | 64 | case p[r] == '.' && p[r+1] == '.' && (r+2 == n || p[r+2] == '/'): 65 | // .. element: remove to last / 66 | r += 2 67 | 68 | if w > 1 { 69 | // can backtrack 70 | w-- 71 | 72 | if buf == nil { 73 | for w > 1 && p[w] != '/' { 74 | w-- 75 | } 76 | } else { 77 | for w > 1 && buf[w] != '/' { 78 | w-- 79 | } 80 | } 81 | } 82 | 83 | default: 84 | // real path element. 85 | // add slash if needed 86 | if w > 1 { 87 | bufApp(&buf, p, w, '/') 88 | w++ 89 | } 90 | 91 | // copy element 92 | for r < n && p[r] != '/' { 93 | bufApp(&buf, p, w, p[r]) 94 | w++ 95 | r++ 96 | } 97 | } 98 | } 99 | 100 | // re-append trailing slash 101 | if trailing && w > 1 { 102 | bufApp(&buf, p, w, '/') 103 | w++ 104 | } 105 | 106 | if buf == nil { 107 | return p[:w] 108 | } 109 | return string(buf[:w]) 110 | } 111 | 112 | // internal helper to lazily create a buffer if necessary 113 | func bufApp(buf *[]byte, s string, w int, c byte) { 114 | if *buf == nil { 115 | if s[w] == c { 116 | return 117 | } 118 | 119 | *buf = make([]byte, len(s)) 120 | copy(*buf, s[:w]) 121 | } 122 | (*buf)[w] = c 123 | } 124 | -------------------------------------------------------------------------------- /vendor/github.com/julienschmidt/httprouter/router.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Julien Schmidt. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be found 3 | // in the LICENSE file. 4 | 5 | // Package httprouter is a trie based high performance HTTP request router. 6 | // 7 | // A trivial example is: 8 | // 9 | // package main 10 | // 11 | // import ( 12 | // "fmt" 13 | // "github.com/julienschmidt/httprouter" 14 | // "net/http" 15 | // "log" 16 | // ) 17 | // 18 | // func Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { 19 | // fmt.Fprint(w, "Welcome!\n") 20 | // } 21 | // 22 | // func Hello(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { 23 | // fmt.Fprintf(w, "hello, %s!\n", ps.ByName("name")) 24 | // } 25 | // 26 | // func main() { 27 | // router := httprouter.New() 28 | // router.GET("/", Index) 29 | // router.GET("/hello/:name", Hello) 30 | // 31 | // log.Fatal(http.ListenAndServe(":8080", router)) 32 | // } 33 | // 34 | // The router matches incoming requests by the request method and the path. 35 | // If a handle is registered for this path and method, the router delegates the 36 | // request to that function. 37 | // For the methods GET, POST, PUT, PATCH and DELETE shortcut functions exist to 38 | // register handles, for all other methods router.Handle can be used. 39 | // 40 | // The registered path, against which the router matches incoming requests, can 41 | // contain two types of parameters: 42 | // Syntax Type 43 | // :name named parameter 44 | // *name catch-all parameter 45 | // 46 | // Named parameters are dynamic path segments. They match anything until the 47 | // next '/' or the path end: 48 | // Path: /blog/:category/:post 49 | // 50 | // Requests: 51 | // /blog/go/request-routers match: category="go", post="request-routers" 52 | // /blog/go/request-routers/ no match, but the router would redirect 53 | // /blog/go/ no match 54 | // /blog/go/request-routers/comments no match 55 | // 56 | // Catch-all parameters match anything until the path end, including the 57 | // directory index (the '/' before the catch-all). Since they match anything 58 | // until the end, catch-all parameters must always be the final path element. 59 | // Path: /files/*filepath 60 | // 61 | // Requests: 62 | // /files/ match: filepath="/" 63 | // /files/LICENSE match: filepath="/LICENSE" 64 | // /files/templates/article.html match: filepath="/templates/article.html" 65 | // /files no match, but the router would redirect 66 | // 67 | // The value of parameters is saved as a slice of the Param struct, consisting 68 | // each of a key and a value. The slice is passed to the Handle func as a third 69 | // parameter. 70 | // There are two ways to retrieve the value of a parameter: 71 | // // by the name of the parameter 72 | // user := ps.ByName("user") // defined by :user or *user 73 | // 74 | // // by the index of the parameter. This way you can also get the name (key) 75 | // thirdKey := ps[2].Key // the name of the 3rd parameter 76 | // thirdValue := ps[2].Value // the value of the 3rd parameter 77 | package httprouter 78 | 79 | import ( 80 | "net/http" 81 | ) 82 | 83 | // Handle is a function that can be registered to a route to handle HTTP 84 | // requests. Like http.HandlerFunc, but has a third parameter for the values of 85 | // wildcards (variables). 86 | type Handle func(http.ResponseWriter, *http.Request, Params) 87 | 88 | // Param is a single URL parameter, consisting of a key and a value. 89 | type Param struct { 90 | Key string 91 | Value string 92 | } 93 | 94 | // Params is a Param-slice, as returned by the router. 95 | // The slice is ordered, the first URL parameter is also the first slice value. 96 | // It is therefore safe to read values by the index. 97 | type Params []Param 98 | 99 | // ByName returns the value of the first Param which key matches the given name. 100 | // If no matching Param is found, an empty string is returned. 101 | func (ps Params) ByName(name string) string { 102 | for i := range ps { 103 | if ps[i].Key == name { 104 | return ps[i].Value 105 | } 106 | } 107 | return "" 108 | } 109 | 110 | // Router is a http.Handler which can be used to dispatch requests to different 111 | // handler functions via configurable routes 112 | type Router struct { 113 | trees map[string]*node 114 | 115 | // Enables automatic redirection if the current route can't be matched but a 116 | // handler for the path with (without) the trailing slash exists. 117 | // For example if /foo/ is requested but a route only exists for /foo, the 118 | // client is redirected to /foo with http status code 301 for GET requests 119 | // and 307 for all other request methods. 120 | RedirectTrailingSlash bool 121 | 122 | // If enabled, the router tries to fix the current request path, if no 123 | // handle is registered for it. 124 | // First superfluous path elements like ../ or // are removed. 125 | // Afterwards the router does a case-insensitive lookup of the cleaned path. 126 | // If a handle can be found for this route, the router makes a redirection 127 | // to the corrected path with status code 301 for GET requests and 307 for 128 | // all other request methods. 129 | // For example /FOO and /..//Foo could be redirected to /foo. 130 | // RedirectTrailingSlash is independent of this option. 131 | RedirectFixedPath bool 132 | 133 | // If enabled, the router checks if another method is allowed for the 134 | // current route, if the current request can not be routed. 135 | // If this is the case, the request is answered with 'Method Not Allowed' 136 | // and HTTP status code 405. 137 | // If no other Method is allowed, the request is delegated to the NotFound 138 | // handler. 139 | HandleMethodNotAllowed bool 140 | 141 | // If enabled, the router automatically replies to OPTIONS requests. 142 | // Custom OPTIONS handlers take priority over automatic replies. 143 | HandleOPTIONS bool 144 | 145 | // Configurable http.Handler which is called when no matching route is 146 | // found. If it is not set, http.NotFound is used. 147 | NotFound http.Handler 148 | 149 | // Configurable http.Handler which is called when a request 150 | // cannot be routed and HandleMethodNotAllowed is true. 151 | // If it is not set, http.Error with http.StatusMethodNotAllowed is used. 152 | // The "Allow" header with allowed request methods is set before the handler 153 | // is called. 154 | MethodNotAllowed http.Handler 155 | 156 | // Function to handle panics recovered from http handlers. 157 | // It should be used to generate a error page and return the http error code 158 | // 500 (Internal Server Error). 159 | // The handler can be used to keep your server from crashing because of 160 | // unrecovered panics. 161 | PanicHandler func(http.ResponseWriter, *http.Request, interface{}) 162 | } 163 | 164 | // Make sure the Router conforms with the http.Handler interface 165 | var _ http.Handler = New() 166 | 167 | // New returns a new initialized Router. 168 | // Path auto-correction, including trailing slashes, is enabled by default. 169 | func New() *Router { 170 | return &Router{ 171 | RedirectTrailingSlash: true, 172 | RedirectFixedPath: true, 173 | HandleMethodNotAllowed: true, 174 | HandleOPTIONS: true, 175 | } 176 | } 177 | 178 | // GET is a shortcut for router.Handle("GET", path, handle) 179 | func (r *Router) GET(path string, handle Handle) { 180 | r.Handle("GET", path, handle) 181 | } 182 | 183 | // HEAD is a shortcut for router.Handle("HEAD", path, handle) 184 | func (r *Router) HEAD(path string, handle Handle) { 185 | r.Handle("HEAD", path, handle) 186 | } 187 | 188 | // OPTIONS is a shortcut for router.Handle("OPTIONS", path, handle) 189 | func (r *Router) OPTIONS(path string, handle Handle) { 190 | r.Handle("OPTIONS", path, handle) 191 | } 192 | 193 | // POST is a shortcut for router.Handle("POST", path, handle) 194 | func (r *Router) POST(path string, handle Handle) { 195 | r.Handle("POST", path, handle) 196 | } 197 | 198 | // PUT is a shortcut for router.Handle("PUT", path, handle) 199 | func (r *Router) PUT(path string, handle Handle) { 200 | r.Handle("PUT", path, handle) 201 | } 202 | 203 | // PATCH is a shortcut for router.Handle("PATCH", path, handle) 204 | func (r *Router) PATCH(path string, handle Handle) { 205 | r.Handle("PATCH", path, handle) 206 | } 207 | 208 | // DELETE is a shortcut for router.Handle("DELETE", path, handle) 209 | func (r *Router) DELETE(path string, handle Handle) { 210 | r.Handle("DELETE", path, handle) 211 | } 212 | 213 | // Handle registers a new request handle with the given path and method. 214 | // 215 | // For GET, POST, PUT, PATCH and DELETE requests the respective shortcut 216 | // functions can be used. 217 | // 218 | // This function is intended for bulk loading and to allow the usage of less 219 | // frequently used, non-standardized or custom methods (e.g. for internal 220 | // communication with a proxy). 221 | func (r *Router) Handle(method, path string, handle Handle) { 222 | if path[0] != '/' { 223 | panic("path must begin with '/' in path '" + path + "'") 224 | } 225 | 226 | if r.trees == nil { 227 | r.trees = make(map[string]*node) 228 | } 229 | 230 | root := r.trees[method] 231 | if root == nil { 232 | root = new(node) 233 | r.trees[method] = root 234 | } 235 | 236 | root.addRoute(path, handle) 237 | } 238 | 239 | // Handler is an adapter which allows the usage of an http.Handler as a 240 | // request handle. 241 | func (r *Router) Handler(method, path string, handler http.Handler) { 242 | r.Handle(method, path, 243 | func(w http.ResponseWriter, req *http.Request, _ Params) { 244 | handler.ServeHTTP(w, req) 245 | }, 246 | ) 247 | } 248 | 249 | // HandlerFunc is an adapter which allows the usage of an http.HandlerFunc as a 250 | // request handle. 251 | func (r *Router) HandlerFunc(method, path string, handler http.HandlerFunc) { 252 | r.Handler(method, path, handler) 253 | } 254 | 255 | // ServeFiles serves files from the given file system root. 256 | // The path must end with "/*filepath", files are then served from the local 257 | // path /defined/root/dir/*filepath. 258 | // For example if root is "/etc" and *filepath is "passwd", the local file 259 | // "/etc/passwd" would be served. 260 | // Internally a http.FileServer is used, therefore http.NotFound is used instead 261 | // of the Router's NotFound handler. 262 | // To use the operating system's file system implementation, 263 | // use http.Dir: 264 | // router.ServeFiles("/src/*filepath", http.Dir("/var/www")) 265 | func (r *Router) ServeFiles(path string, root http.FileSystem) { 266 | if len(path) < 10 || path[len(path)-10:] != "/*filepath" { 267 | panic("path must end with /*filepath in path '" + path + "'") 268 | } 269 | 270 | fileServer := http.FileServer(root) 271 | 272 | r.GET(path, func(w http.ResponseWriter, req *http.Request, ps Params) { 273 | req.URL.Path = ps.ByName("filepath") 274 | fileServer.ServeHTTP(w, req) 275 | }) 276 | } 277 | 278 | func (r *Router) recv(w http.ResponseWriter, req *http.Request) { 279 | if rcv := recover(); rcv != nil { 280 | r.PanicHandler(w, req, rcv) 281 | } 282 | } 283 | 284 | // Lookup allows the manual lookup of a method + path combo. 285 | // This is e.g. useful to build a framework around this router. 286 | // If the path was found, it returns the handle function and the path parameter 287 | // values. Otherwise the third return value indicates whether a redirection to 288 | // the same path with an extra / without the trailing slash should be performed. 289 | func (r *Router) Lookup(method, path string) (Handle, Params, bool) { 290 | if root := r.trees[method]; root != nil { 291 | return root.getValue(path) 292 | } 293 | return nil, nil, false 294 | } 295 | 296 | func (r *Router) allowed(path, reqMethod string) (allow string) { 297 | if path == "*" { // server-wide 298 | for method := range r.trees { 299 | if method == "OPTIONS" { 300 | continue 301 | } 302 | 303 | // add request method to list of allowed methods 304 | if len(allow) == 0 { 305 | allow = method 306 | } else { 307 | allow += ", " + method 308 | } 309 | } 310 | } else { // specific path 311 | for method := range r.trees { 312 | // Skip the requested method - we already tried this one 313 | if method == reqMethod || method == "OPTIONS" { 314 | continue 315 | } 316 | 317 | handle, _, _ := r.trees[method].getValue(path) 318 | if handle != nil { 319 | // add request method to list of allowed methods 320 | if len(allow) == 0 { 321 | allow = method 322 | } else { 323 | allow += ", " + method 324 | } 325 | } 326 | } 327 | } 328 | if len(allow) > 0 { 329 | allow += ", OPTIONS" 330 | } 331 | return 332 | } 333 | 334 | // ServeHTTP makes the router implement the http.Handler interface. 335 | func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) { 336 | if r.PanicHandler != nil { 337 | defer r.recv(w, req) 338 | } 339 | 340 | path := req.URL.Path 341 | 342 | if root := r.trees[req.Method]; root != nil { 343 | if handle, ps, tsr := root.getValue(path); handle != nil { 344 | handle(w, req, ps) 345 | return 346 | } else if req.Method != "CONNECT" && path != "/" { 347 | code := 301 // Permanent redirect, request with GET method 348 | if req.Method != "GET" { 349 | // Temporary redirect, request with same method 350 | // As of Go 1.3, Go does not support status code 308. 351 | code = 307 352 | } 353 | 354 | if tsr && r.RedirectTrailingSlash { 355 | if len(path) > 1 && path[len(path)-1] == '/' { 356 | req.URL.Path = path[:len(path)-1] 357 | } else { 358 | req.URL.Path = path + "/" 359 | } 360 | http.Redirect(w, req, req.URL.String(), code) 361 | return 362 | } 363 | 364 | // Try to fix the request path 365 | if r.RedirectFixedPath { 366 | fixedPath, found := root.findCaseInsensitivePath( 367 | CleanPath(path), 368 | r.RedirectTrailingSlash, 369 | ) 370 | if found { 371 | req.URL.Path = string(fixedPath) 372 | http.Redirect(w, req, req.URL.String(), code) 373 | return 374 | } 375 | } 376 | } 377 | } 378 | 379 | if req.Method == "OPTIONS" { 380 | // Handle OPTIONS requests 381 | if r.HandleOPTIONS { 382 | if allow := r.allowed(path, req.Method); len(allow) > 0 { 383 | w.Header().Set("Allow", allow) 384 | return 385 | } 386 | } 387 | } else { 388 | // Handle 405 389 | if r.HandleMethodNotAllowed { 390 | if allow := r.allowed(path, req.Method); len(allow) > 0 { 391 | w.Header().Set("Allow", allow) 392 | if r.MethodNotAllowed != nil { 393 | r.MethodNotAllowed.ServeHTTP(w, req) 394 | } else { 395 | http.Error(w, 396 | http.StatusText(http.StatusMethodNotAllowed), 397 | http.StatusMethodNotAllowed, 398 | ) 399 | } 400 | return 401 | } 402 | } 403 | } 404 | 405 | // Handle 404 406 | if r.NotFound != nil { 407 | r.NotFound.ServeHTTP(w, req) 408 | } else { 409 | http.NotFound(w, req) 410 | } 411 | } 412 | -------------------------------------------------------------------------------- /vendor/github.com/lib/pq/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Contributing to pq 2 | 3 | `pq` has a backlog of pull requests, but contributions are still very 4 | much welcome. You can help with patch review, submitting bug reports, 5 | or adding new functionality. There is no formal style guide, but 6 | please conform to the style of existing code and general Go formatting 7 | conventions when submitting patches. 8 | 9 | ### Patch review 10 | 11 | Help review existing open pull requests by commenting on the code or 12 | proposed functionality. 13 | 14 | ### Bug reports 15 | 16 | We appreciate any bug reports, but especially ones with self-contained 17 | (doesn't depend on code outside of pq), minimal (can't be simplified 18 | further) test cases. It's especially helpful if you can submit a pull 19 | request with just the failing test case (you'll probably want to 20 | pattern it after the tests in 21 | [conn_test.go](https://github.com/lib/pq/blob/master/conn_test.go). 22 | 23 | ### New functionality 24 | 25 | There are a number of pending patches for new functionality, so 26 | additional feature patches will take a while to merge. Still, patches 27 | are generally reviewed based on usefulness and complexity in addition 28 | to time-in-queue, so if you have a knockout idea, take a shot. Feel 29 | free to open an issue discussion your proposed patch beforehand. 30 | -------------------------------------------------------------------------------- /vendor/github.com/lib/pq/LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011-2013, 'pq' Contributors 2 | Portions Copyright (C) 2011 Blake Mizerany 3 | 4 | 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: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | 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. 9 | -------------------------------------------------------------------------------- /vendor/github.com/lib/pq/README.md: -------------------------------------------------------------------------------- 1 | # pq - A pure Go postgres driver for Go's database/sql package 2 | 3 | [![Build Status](https://travis-ci.org/lib/pq.svg?branch=master)](https://travis-ci.org/lib/pq) 4 | 5 | ## Install 6 | 7 | go get github.com/lib/pq 8 | 9 | ## Docs 10 | 11 | For detailed documentation and basic usage examples, please see the package 12 | documentation at . 13 | 14 | ## Tests 15 | 16 | `go test` is used for testing. A running PostgreSQL server is 17 | required, with the ability to log in. The default database to connect 18 | to test with is "pqgotest," but it can be overridden using environment 19 | variables. 20 | 21 | Example: 22 | 23 | PGHOST=/run/postgresql go test github.com/lib/pq 24 | 25 | Optionally, a benchmark suite can be run as part of the tests: 26 | 27 | PGHOST=/run/postgresql go test -bench . 28 | 29 | ## Features 30 | 31 | * SSL 32 | * Handles bad connections for `database/sql` 33 | * Scan `time.Time` correctly (i.e. `timestamp[tz]`, `time[tz]`, `date`) 34 | * Scan binary blobs correctly (i.e. `bytea`) 35 | * Package for `hstore` support 36 | * COPY FROM support 37 | * pq.ParseURL for converting urls to connection strings for sql.Open. 38 | * Many libpq compatible environment variables 39 | * Unix socket support 40 | * Notifications: `LISTEN`/`NOTIFY` 41 | * pgpass support 42 | 43 | ## Future / Things you can help with 44 | 45 | * Better COPY FROM / COPY TO (see discussion in #181) 46 | 47 | ## Thank you (alphabetical) 48 | 49 | Some of these contributors are from the original library `bmizerany/pq.go` whose 50 | code still exists in here. 51 | 52 | * Andy Balholm (andybalholm) 53 | * Ben Berkert (benburkert) 54 | * Benjamin Heatwole (bheatwole) 55 | * Bill Mill (llimllib) 56 | * Bjørn Madsen (aeons) 57 | * Blake Gentry (bgentry) 58 | * Brad Fitzpatrick (bradfitz) 59 | * Charlie Melbye (cmelbye) 60 | * Chris Bandy (cbandy) 61 | * Chris Gilling (cgilling) 62 | * Chris Walsh (cwds) 63 | * Dan Sosedoff (sosedoff) 64 | * Daniel Farina (fdr) 65 | * Eric Chlebek (echlebek) 66 | * Eric Garrido (minusnine) 67 | * Eric Urban (hydrogen18) 68 | * Everyone at The Go Team 69 | * Evan Shaw (edsrzf) 70 | * Ewan Chou (coocood) 71 | * Fazal Majid (fazalmajid) 72 | * Federico Romero (federomero) 73 | * Fumin (fumin) 74 | * Gary Burd (garyburd) 75 | * Heroku (heroku) 76 | * James Pozdena (jpoz) 77 | * Jason McVetta (jmcvetta) 78 | * Jeremy Jay (pbnjay) 79 | * Joakim Sernbrant (serbaut) 80 | * John Gallagher (jgallagher) 81 | * Jonathan Rudenberg (titanous) 82 | * Joël Stemmer (jstemmer) 83 | * Kamil Kisiel (kisielk) 84 | * Kelly Dunn (kellydunn) 85 | * Keith Rarick (kr) 86 | * Kir Shatrov (kirs) 87 | * Lann Martin (lann) 88 | * Maciek Sakrejda (uhoh-itsmaciek) 89 | * Marc Brinkmann (mbr) 90 | * Marko Tiikkaja (johto) 91 | * Matt Newberry (MattNewberry) 92 | * Matt Robenolt (mattrobenolt) 93 | * Martin Olsen (martinolsen) 94 | * Mike Lewis (mikelikespie) 95 | * Nicolas Patry (Narsil) 96 | * Oliver Tonnhofer (olt) 97 | * Patrick Hayes (phayes) 98 | * Paul Hammond (paulhammond) 99 | * Ryan Smith (ryandotsmith) 100 | * Samuel Stauffer (samuel) 101 | * Timothée Peignier (cyberdelia) 102 | * Travis Cline (tmc) 103 | * TruongSinh Tran-Nguyen (truongsinh) 104 | * Yaismel Miranda (ympons) 105 | * notedit (notedit) 106 | -------------------------------------------------------------------------------- /vendor/github.com/lib/pq/buf.go: -------------------------------------------------------------------------------- 1 | package pq 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | 7 | "github.com/lib/pq/oid" 8 | ) 9 | 10 | type readBuf []byte 11 | 12 | func (b *readBuf) int32() (n int) { 13 | n = int(int32(binary.BigEndian.Uint32(*b))) 14 | *b = (*b)[4:] 15 | return 16 | } 17 | 18 | func (b *readBuf) oid() (n oid.Oid) { 19 | n = oid.Oid(binary.BigEndian.Uint32(*b)) 20 | *b = (*b)[4:] 21 | return 22 | } 23 | 24 | // N.B: this is actually an unsigned 16-bit integer, unlike int32 25 | func (b *readBuf) int16() (n int) { 26 | n = int(binary.BigEndian.Uint16(*b)) 27 | *b = (*b)[2:] 28 | return 29 | } 30 | 31 | func (b *readBuf) string() string { 32 | i := bytes.IndexByte(*b, 0) 33 | if i < 0 { 34 | errorf("invalid message format; expected string terminator") 35 | } 36 | s := (*b)[:i] 37 | *b = (*b)[i+1:] 38 | return string(s) 39 | } 40 | 41 | func (b *readBuf) next(n int) (v []byte) { 42 | v = (*b)[:n] 43 | *b = (*b)[n:] 44 | return 45 | } 46 | 47 | func (b *readBuf) byte() byte { 48 | return b.next(1)[0] 49 | } 50 | 51 | type writeBuf struct { 52 | buf []byte 53 | pos int 54 | } 55 | 56 | func (b *writeBuf) int32(n int) { 57 | x := make([]byte, 4) 58 | binary.BigEndian.PutUint32(x, uint32(n)) 59 | b.buf = append(b.buf, x...) 60 | } 61 | 62 | func (b *writeBuf) int16(n int) { 63 | x := make([]byte, 2) 64 | binary.BigEndian.PutUint16(x, uint16(n)) 65 | b.buf = append(b.buf, x...) 66 | } 67 | 68 | func (b *writeBuf) string(s string) { 69 | b.buf = append(b.buf, (s + "\000")...) 70 | } 71 | 72 | func (b *writeBuf) byte(c byte) { 73 | b.buf = append(b.buf, c) 74 | } 75 | 76 | func (b *writeBuf) bytes(v []byte) { 77 | b.buf = append(b.buf, v...) 78 | } 79 | 80 | func (b *writeBuf) wrap() []byte { 81 | p := b.buf[b.pos:] 82 | binary.BigEndian.PutUint32(p, uint32(len(p))) 83 | return b.buf 84 | } 85 | 86 | func (b *writeBuf) next(c byte) { 87 | p := b.buf[b.pos:] 88 | binary.BigEndian.PutUint32(p, uint32(len(p))) 89 | b.pos = len(b.buf) + 1 90 | b.buf = append(b.buf, c, 0, 0, 0, 0) 91 | } 92 | -------------------------------------------------------------------------------- /vendor/github.com/lib/pq/conn_go18.go: -------------------------------------------------------------------------------- 1 | // +build go1.8 2 | 3 | package pq 4 | 5 | import ( 6 | "context" 7 | "database/sql/driver" 8 | "errors" 9 | ) 10 | 11 | // Implement the "QueryerContext" interface 12 | func (cn *conn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) { 13 | list := make([]driver.Value, len(args)) 14 | for i, nv := range args { 15 | list[i] = nv.Value 16 | } 17 | closed := cn.watchCancel(ctx) 18 | r, err := cn.query(query, list) 19 | if err != nil { 20 | return nil, err 21 | } 22 | r.closed = closed 23 | return r, nil 24 | } 25 | 26 | // Implement the "ExecerContext" interface 27 | func (cn *conn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) { 28 | list := make([]driver.Value, len(args)) 29 | for i, nv := range args { 30 | list[i] = nv.Value 31 | } 32 | 33 | if closed := cn.watchCancel(ctx); closed != nil { 34 | defer close(closed) 35 | } 36 | 37 | return cn.Exec(query, list) 38 | } 39 | 40 | // Implement the "ConnBeginTx" interface 41 | func (cn *conn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) { 42 | if opts.Isolation != 0 { 43 | return nil, errors.New("isolation levels not supported") 44 | } 45 | if opts.ReadOnly { 46 | return nil, errors.New("read-only transactions not supported") 47 | } 48 | tx, err := cn.Begin() 49 | if err != nil { 50 | return nil, err 51 | } 52 | cn.txnClosed = cn.watchCancel(ctx) 53 | return tx, nil 54 | } 55 | 56 | func (cn *conn) watchCancel(ctx context.Context) chan<- struct{} { 57 | if done := ctx.Done(); done != nil { 58 | closed := make(chan struct{}) 59 | go func() { 60 | select { 61 | case <-done: 62 | cn.cancel() 63 | case <-closed: 64 | } 65 | }() 66 | return closed 67 | } 68 | return nil 69 | } 70 | 71 | func (cn *conn) cancel() { 72 | var err error 73 | can := &conn{} 74 | can.c, err = dial(cn.dialer, cn.opts) 75 | if err != nil { 76 | return 77 | } 78 | can.ssl(cn.opts) 79 | 80 | defer can.errRecover(&err) 81 | 82 | w := can.writeBuf(0) 83 | w.int32(80877102) // cancel request code 84 | w.int32(cn.processID) 85 | w.int32(cn.secretKey) 86 | 87 | can.sendStartupPacket(w) 88 | _ = can.c.Close() 89 | } 90 | -------------------------------------------------------------------------------- /vendor/github.com/lib/pq/copy.go: -------------------------------------------------------------------------------- 1 | package pq 2 | 3 | import ( 4 | "database/sql/driver" 5 | "encoding/binary" 6 | "errors" 7 | "fmt" 8 | "sync" 9 | ) 10 | 11 | var ( 12 | errCopyInClosed = errors.New("pq: copyin statement has already been closed") 13 | errBinaryCopyNotSupported = errors.New("pq: only text format supported for COPY") 14 | errCopyToNotSupported = errors.New("pq: COPY TO is not supported") 15 | errCopyNotSupportedOutsideTxn = errors.New("pq: COPY is only allowed inside a transaction") 16 | errCopyInProgress = errors.New("pq: COPY in progress") 17 | ) 18 | 19 | // CopyIn creates a COPY FROM statement which can be prepared with 20 | // Tx.Prepare(). The target table should be visible in search_path. 21 | func CopyIn(table string, columns ...string) string { 22 | stmt := "COPY " + QuoteIdentifier(table) + " (" 23 | for i, col := range columns { 24 | if i != 0 { 25 | stmt += ", " 26 | } 27 | stmt += QuoteIdentifier(col) 28 | } 29 | stmt += ") FROM STDIN" 30 | return stmt 31 | } 32 | 33 | // CopyInSchema creates a COPY FROM statement which can be prepared with 34 | // Tx.Prepare(). 35 | func CopyInSchema(schema, table string, columns ...string) string { 36 | stmt := "COPY " + QuoteIdentifier(schema) + "." + QuoteIdentifier(table) + " (" 37 | for i, col := range columns { 38 | if i != 0 { 39 | stmt += ", " 40 | } 41 | stmt += QuoteIdentifier(col) 42 | } 43 | stmt += ") FROM STDIN" 44 | return stmt 45 | } 46 | 47 | type copyin struct { 48 | cn *conn 49 | buffer []byte 50 | rowData chan []byte 51 | done chan bool 52 | 53 | closed bool 54 | 55 | sync.Mutex // guards err 56 | err error 57 | } 58 | 59 | const ciBufferSize = 64 * 1024 60 | 61 | // flush buffer before the buffer is filled up and needs reallocation 62 | const ciBufferFlushSize = 63 * 1024 63 | 64 | func (cn *conn) prepareCopyIn(q string) (_ driver.Stmt, err error) { 65 | if !cn.isInTransaction() { 66 | return nil, errCopyNotSupportedOutsideTxn 67 | } 68 | 69 | ci := ©in{ 70 | cn: cn, 71 | buffer: make([]byte, 0, ciBufferSize), 72 | rowData: make(chan []byte), 73 | done: make(chan bool, 1), 74 | } 75 | // add CopyData identifier + 4 bytes for message length 76 | ci.buffer = append(ci.buffer, 'd', 0, 0, 0, 0) 77 | 78 | b := cn.writeBuf('Q') 79 | b.string(q) 80 | cn.send(b) 81 | 82 | awaitCopyInResponse: 83 | for { 84 | t, r := cn.recv1() 85 | switch t { 86 | case 'G': 87 | if r.byte() != 0 { 88 | err = errBinaryCopyNotSupported 89 | break awaitCopyInResponse 90 | } 91 | go ci.resploop() 92 | return ci, nil 93 | case 'H': 94 | err = errCopyToNotSupported 95 | break awaitCopyInResponse 96 | case 'E': 97 | err = parseError(r) 98 | case 'Z': 99 | if err == nil { 100 | ci.setBad() 101 | errorf("unexpected ReadyForQuery in response to COPY") 102 | } 103 | cn.processReadyForQuery(r) 104 | return nil, err 105 | default: 106 | ci.setBad() 107 | errorf("unknown response for copy query: %q", t) 108 | } 109 | } 110 | 111 | // something went wrong, abort COPY before we return 112 | b = cn.writeBuf('f') 113 | b.string(err.Error()) 114 | cn.send(b) 115 | 116 | for { 117 | t, r := cn.recv1() 118 | switch t { 119 | case 'c', 'C', 'E': 120 | case 'Z': 121 | // correctly aborted, we're done 122 | cn.processReadyForQuery(r) 123 | return nil, err 124 | default: 125 | ci.setBad() 126 | errorf("unknown response for CopyFail: %q", t) 127 | } 128 | } 129 | } 130 | 131 | func (ci *copyin) flush(buf []byte) { 132 | // set message length (without message identifier) 133 | binary.BigEndian.PutUint32(buf[1:], uint32(len(buf)-1)) 134 | 135 | _, err := ci.cn.c.Write(buf) 136 | if err != nil { 137 | panic(err) 138 | } 139 | } 140 | 141 | func (ci *copyin) resploop() { 142 | for { 143 | var r readBuf 144 | t, err := ci.cn.recvMessage(&r) 145 | if err != nil { 146 | ci.setBad() 147 | ci.setError(err) 148 | ci.done <- true 149 | return 150 | } 151 | switch t { 152 | case 'C': 153 | // complete 154 | case 'N': 155 | // NoticeResponse 156 | case 'Z': 157 | ci.cn.processReadyForQuery(&r) 158 | ci.done <- true 159 | return 160 | case 'E': 161 | err := parseError(&r) 162 | ci.setError(err) 163 | default: 164 | ci.setBad() 165 | ci.setError(fmt.Errorf("unknown response during CopyIn: %q", t)) 166 | ci.done <- true 167 | return 168 | } 169 | } 170 | } 171 | 172 | func (ci *copyin) setBad() { 173 | ci.Lock() 174 | ci.cn.bad = true 175 | ci.Unlock() 176 | } 177 | 178 | func (ci *copyin) isBad() bool { 179 | ci.Lock() 180 | b := ci.cn.bad 181 | ci.Unlock() 182 | return b 183 | } 184 | 185 | func (ci *copyin) isErrorSet() bool { 186 | ci.Lock() 187 | isSet := (ci.err != nil) 188 | ci.Unlock() 189 | return isSet 190 | } 191 | 192 | // setError() sets ci.err if one has not been set already. Caller must not be 193 | // holding ci.Mutex. 194 | func (ci *copyin) setError(err error) { 195 | ci.Lock() 196 | if ci.err == nil { 197 | ci.err = err 198 | } 199 | ci.Unlock() 200 | } 201 | 202 | func (ci *copyin) NumInput() int { 203 | return -1 204 | } 205 | 206 | func (ci *copyin) Query(v []driver.Value) (r driver.Rows, err error) { 207 | return nil, ErrNotSupported 208 | } 209 | 210 | // Exec inserts values into the COPY stream. The insert is asynchronous 211 | // and Exec can return errors from previous Exec calls to the same 212 | // COPY stmt. 213 | // 214 | // You need to call Exec(nil) to sync the COPY stream and to get any 215 | // errors from pending data, since Stmt.Close() doesn't return errors 216 | // to the user. 217 | func (ci *copyin) Exec(v []driver.Value) (r driver.Result, err error) { 218 | if ci.closed { 219 | return nil, errCopyInClosed 220 | } 221 | 222 | if ci.isBad() { 223 | return nil, driver.ErrBadConn 224 | } 225 | defer ci.cn.errRecover(&err) 226 | 227 | if ci.isErrorSet() { 228 | return nil, ci.err 229 | } 230 | 231 | if len(v) == 0 { 232 | return nil, ci.Close() 233 | } 234 | 235 | numValues := len(v) 236 | for i, value := range v { 237 | ci.buffer = appendEncodedText(&ci.cn.parameterStatus, ci.buffer, value) 238 | if i < numValues-1 { 239 | ci.buffer = append(ci.buffer, '\t') 240 | } 241 | } 242 | 243 | ci.buffer = append(ci.buffer, '\n') 244 | 245 | if len(ci.buffer) > ciBufferFlushSize { 246 | ci.flush(ci.buffer) 247 | // reset buffer, keep bytes for message identifier and length 248 | ci.buffer = ci.buffer[:5] 249 | } 250 | 251 | return driver.RowsAffected(0), nil 252 | } 253 | 254 | func (ci *copyin) Close() (err error) { 255 | if ci.closed { // Don't do anything, we're already closed 256 | return nil 257 | } 258 | ci.closed = true 259 | 260 | if ci.isBad() { 261 | return driver.ErrBadConn 262 | } 263 | defer ci.cn.errRecover(&err) 264 | 265 | if len(ci.buffer) > 0 { 266 | ci.flush(ci.buffer) 267 | } 268 | // Avoid touching the scratch buffer as resploop could be using it. 269 | err = ci.cn.sendSimpleMessage('c') 270 | if err != nil { 271 | return err 272 | } 273 | 274 | <-ci.done 275 | ci.cn.inCopy = false 276 | 277 | if ci.isErrorSet() { 278 | err = ci.err 279 | return err 280 | } 281 | return nil 282 | } 283 | -------------------------------------------------------------------------------- /vendor/github.com/lib/pq/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package pq is a pure Go Postgres driver for the database/sql package. 3 | 4 | In most cases clients will use the database/sql package instead of 5 | using this package directly. For example: 6 | 7 | import ( 8 | "database/sql" 9 | 10 | _ "github.com/lib/pq" 11 | ) 12 | 13 | func main() { 14 | db, err := sql.Open("postgres", "user=pqgotest dbname=pqgotest sslmode=verify-full") 15 | if err != nil { 16 | log.Fatal(err) 17 | } 18 | 19 | age := 21 20 | rows, err := db.Query("SELECT name FROM users WHERE age = $1", age) 21 | … 22 | } 23 | 24 | You can also connect to a database using a URL. For example: 25 | 26 | db, err := sql.Open("postgres", "postgres://pqgotest:password@localhost/pqgotest?sslmode=verify-full") 27 | 28 | 29 | Connection String Parameters 30 | 31 | 32 | Similarly to libpq, when establishing a connection using pq you are expected to 33 | supply a connection string containing zero or more parameters. 34 | A subset of the connection parameters supported by libpq are also supported by pq. 35 | Additionally, pq also lets you specify run-time parameters (such as search_path or work_mem) 36 | directly in the connection string. This is different from libpq, which does not allow 37 | run-time parameters in the connection string, instead requiring you to supply 38 | them in the options parameter. 39 | 40 | For compatibility with libpq, the following special connection parameters are 41 | supported: 42 | 43 | * dbname - The name of the database to connect to 44 | * user - The user to sign in as 45 | * password - The user's password 46 | * host - The host to connect to. Values that start with / are for unix domain sockets. (default is localhost) 47 | * port - The port to bind to. (default is 5432) 48 | * sslmode - Whether or not to use SSL (default is require, this is not the default for libpq) 49 | * fallback_application_name - An application_name to fall back to if one isn't provided. 50 | * connect_timeout - Maximum wait for connection, in seconds. Zero or not specified means wait indefinitely. 51 | * sslcert - Cert file location. The file must contain PEM encoded data. 52 | * sslkey - Key file location. The file must contain PEM encoded data. 53 | * sslrootcert - The location of the root certificate file. The file must contain PEM encoded data. 54 | 55 | Valid values for sslmode are: 56 | 57 | * disable - No SSL 58 | * require - Always SSL (skip verification) 59 | * verify-ca - Always SSL (verify that the certificate presented by the server was signed by a trusted CA) 60 | * verify-full - Always SSL (verify that the certification presented by the server was signed by a trusted CA and the server host name matches the one in the certificate) 61 | 62 | See http://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-CONNSTRING 63 | for more information about connection string parameters. 64 | 65 | Use single quotes for values that contain whitespace: 66 | 67 | "user=pqgotest password='with spaces'" 68 | 69 | A backslash will escape the next character in values: 70 | 71 | "user=space\ man password='it\'s valid' 72 | 73 | Note that the connection parameter client_encoding (which sets the 74 | text encoding for the connection) may be set but must be "UTF8", 75 | matching with the same rules as Postgres. It is an error to provide 76 | any other value. 77 | 78 | In addition to the parameters listed above, any run-time parameter that can be 79 | set at backend start time can be set in the connection string. For more 80 | information, see 81 | http://www.postgresql.org/docs/current/static/runtime-config.html. 82 | 83 | Most environment variables as specified at http://www.postgresql.org/docs/current/static/libpq-envars.html 84 | supported by libpq are also supported by pq. If any of the environment 85 | variables not supported by pq are set, pq will panic during connection 86 | establishment. Environment variables have a lower precedence than explicitly 87 | provided connection parameters. 88 | 89 | The pgpass mechanism as described in http://www.postgresql.org/docs/current/static/libpq-pgpass.html 90 | is supported, but on Windows PGPASSFILE must be specified explicitly. 91 | 92 | 93 | Queries 94 | 95 | 96 | database/sql does not dictate any specific format for parameter 97 | markers in query strings, and pq uses the Postgres-native ordinal markers, 98 | as shown above. The same marker can be reused for the same parameter: 99 | 100 | rows, err := db.Query(`SELECT name FROM users WHERE favorite_fruit = $1 101 | OR age BETWEEN $2 AND $2 + 3`, "orange", 64) 102 | 103 | pq does not support the LastInsertId() method of the Result type in database/sql. 104 | To return the identifier of an INSERT (or UPDATE or DELETE), use the Postgres 105 | RETURNING clause with a standard Query or QueryRow call: 106 | 107 | var userid int 108 | err := db.QueryRow(`INSERT INTO users(name, favorite_fruit, age) 109 | VALUES('beatrice', 'starfruit', 93) RETURNING id`).Scan(&userid) 110 | 111 | For more details on RETURNING, see the Postgres documentation: 112 | 113 | http://www.postgresql.org/docs/current/static/sql-insert.html 114 | http://www.postgresql.org/docs/current/static/sql-update.html 115 | http://www.postgresql.org/docs/current/static/sql-delete.html 116 | 117 | For additional instructions on querying see the documentation for the database/sql package. 118 | 119 | 120 | Data Types 121 | 122 | 123 | Parameters pass through driver.DefaultParameterConverter before they are handled 124 | by this package. When the binary_parameters connection option is enabled, 125 | []byte values are sent directly to the backend as data in binary format. 126 | 127 | This package returns the following types for values from the PostgreSQL backend: 128 | 129 | - integer types smallint, integer, and bigint are returned as int64 130 | - floating-point types real and double precision are returned as float64 131 | - character types char, varchar, and text are returned as string 132 | - temporal types date, time, timetz, timestamp, and timestamptz are returned as time.Time 133 | - the boolean type is returned as bool 134 | - the bytea type is returned as []byte 135 | 136 | All other types are returned directly from the backend as []byte values in text format. 137 | 138 | 139 | Errors 140 | 141 | 142 | pq may return errors of type *pq.Error which can be interrogated for error details: 143 | 144 | if err, ok := err.(*pq.Error); ok { 145 | fmt.Println("pq error:", err.Code.Name()) 146 | } 147 | 148 | See the pq.Error type for details. 149 | 150 | 151 | Bulk imports 152 | 153 | You can perform bulk imports by preparing a statement returned by pq.CopyIn (or 154 | pq.CopyInSchema) in an explicit transaction (sql.Tx). The returned statement 155 | handle can then be repeatedly "executed" to copy data into the target table. 156 | After all data has been processed you should call Exec() once with no arguments 157 | to flush all buffered data. Any call to Exec() might return an error which 158 | should be handled appropriately, but because of the internal buffering an error 159 | returned by Exec() might not be related to the data passed in the call that 160 | failed. 161 | 162 | CopyIn uses COPY FROM internally. It is not possible to COPY outside of an 163 | explicit transaction in pq. 164 | 165 | Usage example: 166 | 167 | txn, err := db.Begin() 168 | if err != nil { 169 | log.Fatal(err) 170 | } 171 | 172 | stmt, err := txn.Prepare(pq.CopyIn("users", "name", "age")) 173 | if err != nil { 174 | log.Fatal(err) 175 | } 176 | 177 | for _, user := range users { 178 | _, err = stmt.Exec(user.Name, int64(user.Age)) 179 | if err != nil { 180 | log.Fatal(err) 181 | } 182 | } 183 | 184 | _, err = stmt.Exec() 185 | if err != nil { 186 | log.Fatal(err) 187 | } 188 | 189 | err = stmt.Close() 190 | if err != nil { 191 | log.Fatal(err) 192 | } 193 | 194 | err = txn.Commit() 195 | if err != nil { 196 | log.Fatal(err) 197 | } 198 | 199 | 200 | Notifications 201 | 202 | 203 | PostgreSQL supports a simple publish/subscribe model over database 204 | connections. See http://www.postgresql.org/docs/current/static/sql-notify.html 205 | for more information about the general mechanism. 206 | 207 | To start listening for notifications, you first have to open a new connection 208 | to the database by calling NewListener. This connection can not be used for 209 | anything other than LISTEN / NOTIFY. Calling Listen will open a "notification 210 | channel"; once a notification channel is open, a notification generated on that 211 | channel will effect a send on the Listener.Notify channel. A notification 212 | channel will remain open until Unlisten is called, though connection loss might 213 | result in some notifications being lost. To solve this problem, Listener sends 214 | a nil pointer over the Notify channel any time the connection is re-established 215 | following a connection loss. The application can get information about the 216 | state of the underlying connection by setting an event callback in the call to 217 | NewListener. 218 | 219 | A single Listener can safely be used from concurrent goroutines, which means 220 | that there is often no need to create more than one Listener in your 221 | application. However, a Listener is always connected to a single database, so 222 | you will need to create a new Listener instance for every database you want to 223 | receive notifications in. 224 | 225 | The channel name in both Listen and Unlisten is case sensitive, and can contain 226 | any characters legal in an identifier (see 227 | http://www.postgresql.org/docs/current/static/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS 228 | for more information). Note that the channel name will be truncated to 63 229 | bytes by the PostgreSQL server. 230 | 231 | You can find a complete, working example of Listener usage at 232 | http://godoc.org/github.com/lib/pq/listen_example. 233 | 234 | */ 235 | package pq 236 | -------------------------------------------------------------------------------- /vendor/github.com/lib/pq/oid/doc.go: -------------------------------------------------------------------------------- 1 | // Package oid contains OID constants 2 | // as defined by the Postgres server. 3 | package oid 4 | 5 | // Oid is a Postgres Object ID. 6 | type Oid uint32 7 | -------------------------------------------------------------------------------- /vendor/github.com/lib/pq/oid/gen.go: -------------------------------------------------------------------------------- 1 | // +build ignore 2 | 3 | // Generate the table of OID values 4 | // Run with 'go run gen.go'. 5 | package main 6 | 7 | import ( 8 | "database/sql" 9 | "fmt" 10 | "log" 11 | "os" 12 | "os/exec" 13 | 14 | _ "github.com/lib/pq" 15 | ) 16 | 17 | func main() { 18 | datname := os.Getenv("PGDATABASE") 19 | sslmode := os.Getenv("PGSSLMODE") 20 | 21 | if datname == "" { 22 | os.Setenv("PGDATABASE", "pqgotest") 23 | } 24 | 25 | if sslmode == "" { 26 | os.Setenv("PGSSLMODE", "disable") 27 | } 28 | 29 | db, err := sql.Open("postgres", "") 30 | if err != nil { 31 | log.Fatal(err) 32 | } 33 | cmd := exec.Command("gofmt") 34 | cmd.Stderr = os.Stderr 35 | w, err := cmd.StdinPipe() 36 | if err != nil { 37 | log.Fatal(err) 38 | } 39 | f, err := os.Create("types.go") 40 | if err != nil { 41 | log.Fatal(err) 42 | } 43 | cmd.Stdout = f 44 | err = cmd.Start() 45 | if err != nil { 46 | log.Fatal(err) 47 | } 48 | fmt.Fprintln(w, "// generated by 'go run gen.go'; do not edit") 49 | fmt.Fprintln(w, "\npackage oid") 50 | fmt.Fprintln(w, "const (") 51 | rows, err := db.Query(` 52 | SELECT typname, oid 53 | FROM pg_type WHERE oid < 10000 54 | ORDER BY oid; 55 | `) 56 | if err != nil { 57 | log.Fatal(err) 58 | } 59 | var name string 60 | var oid int 61 | for rows.Next() { 62 | err = rows.Scan(&name, &oid) 63 | if err != nil { 64 | log.Fatal(err) 65 | } 66 | fmt.Fprintf(w, "T_%s Oid = %d\n", name, oid) 67 | } 68 | if err = rows.Err(); err != nil { 69 | log.Fatal(err) 70 | } 71 | fmt.Fprintln(w, ")") 72 | w.Close() 73 | cmd.Wait() 74 | } 75 | -------------------------------------------------------------------------------- /vendor/github.com/lib/pq/oid/types.go: -------------------------------------------------------------------------------- 1 | // generated by 'go run gen.go'; do not edit 2 | 3 | package oid 4 | 5 | const ( 6 | T_bool Oid = 16 7 | T_bytea Oid = 17 8 | T_char Oid = 18 9 | T_name Oid = 19 10 | T_int8 Oid = 20 11 | T_int2 Oid = 21 12 | T_int2vector Oid = 22 13 | T_int4 Oid = 23 14 | T_regproc Oid = 24 15 | T_text Oid = 25 16 | T_oid Oid = 26 17 | T_tid Oid = 27 18 | T_xid Oid = 28 19 | T_cid Oid = 29 20 | T_oidvector Oid = 30 21 | T_pg_ddl_command Oid = 32 22 | T_pg_type Oid = 71 23 | T_pg_attribute Oid = 75 24 | T_pg_proc Oid = 81 25 | T_pg_class Oid = 83 26 | T_json Oid = 114 27 | T_xml Oid = 142 28 | T__xml Oid = 143 29 | T_pg_node_tree Oid = 194 30 | T__json Oid = 199 31 | T_smgr Oid = 210 32 | T_index_am_handler Oid = 325 33 | T_point Oid = 600 34 | T_lseg Oid = 601 35 | T_path Oid = 602 36 | T_box Oid = 603 37 | T_polygon Oid = 604 38 | T_line Oid = 628 39 | T__line Oid = 629 40 | T_cidr Oid = 650 41 | T__cidr Oid = 651 42 | T_float4 Oid = 700 43 | T_float8 Oid = 701 44 | T_abstime Oid = 702 45 | T_reltime Oid = 703 46 | T_tinterval Oid = 704 47 | T_unknown Oid = 705 48 | T_circle Oid = 718 49 | T__circle Oid = 719 50 | T_money Oid = 790 51 | T__money Oid = 791 52 | T_macaddr Oid = 829 53 | T_inet Oid = 869 54 | T__bool Oid = 1000 55 | T__bytea Oid = 1001 56 | T__char Oid = 1002 57 | T__name Oid = 1003 58 | T__int2 Oid = 1005 59 | T__int2vector Oid = 1006 60 | T__int4 Oid = 1007 61 | T__regproc Oid = 1008 62 | T__text Oid = 1009 63 | T__tid Oid = 1010 64 | T__xid Oid = 1011 65 | T__cid Oid = 1012 66 | T__oidvector Oid = 1013 67 | T__bpchar Oid = 1014 68 | T__varchar Oid = 1015 69 | T__int8 Oid = 1016 70 | T__point Oid = 1017 71 | T__lseg Oid = 1018 72 | T__path Oid = 1019 73 | T__box Oid = 1020 74 | T__float4 Oid = 1021 75 | T__float8 Oid = 1022 76 | T__abstime Oid = 1023 77 | T__reltime Oid = 1024 78 | T__tinterval Oid = 1025 79 | T__polygon Oid = 1027 80 | T__oid Oid = 1028 81 | T_aclitem Oid = 1033 82 | T__aclitem Oid = 1034 83 | T__macaddr Oid = 1040 84 | T__inet Oid = 1041 85 | T_bpchar Oid = 1042 86 | T_varchar Oid = 1043 87 | T_date Oid = 1082 88 | T_time Oid = 1083 89 | T_timestamp Oid = 1114 90 | T__timestamp Oid = 1115 91 | T__date Oid = 1182 92 | T__time Oid = 1183 93 | T_timestamptz Oid = 1184 94 | T__timestamptz Oid = 1185 95 | T_interval Oid = 1186 96 | T__interval Oid = 1187 97 | T__numeric Oid = 1231 98 | T_pg_database Oid = 1248 99 | T__cstring Oid = 1263 100 | T_timetz Oid = 1266 101 | T__timetz Oid = 1270 102 | T_bit Oid = 1560 103 | T__bit Oid = 1561 104 | T_varbit Oid = 1562 105 | T__varbit Oid = 1563 106 | T_numeric Oid = 1700 107 | T_refcursor Oid = 1790 108 | T__refcursor Oid = 2201 109 | T_regprocedure Oid = 2202 110 | T_regoper Oid = 2203 111 | T_regoperator Oid = 2204 112 | T_regclass Oid = 2205 113 | T_regtype Oid = 2206 114 | T__regprocedure Oid = 2207 115 | T__regoper Oid = 2208 116 | T__regoperator Oid = 2209 117 | T__regclass Oid = 2210 118 | T__regtype Oid = 2211 119 | T_record Oid = 2249 120 | T_cstring Oid = 2275 121 | T_any Oid = 2276 122 | T_anyarray Oid = 2277 123 | T_void Oid = 2278 124 | T_trigger Oid = 2279 125 | T_language_handler Oid = 2280 126 | T_internal Oid = 2281 127 | T_opaque Oid = 2282 128 | T_anyelement Oid = 2283 129 | T__record Oid = 2287 130 | T_anynonarray Oid = 2776 131 | T_pg_authid Oid = 2842 132 | T_pg_auth_members Oid = 2843 133 | T__txid_snapshot Oid = 2949 134 | T_uuid Oid = 2950 135 | T__uuid Oid = 2951 136 | T_txid_snapshot Oid = 2970 137 | T_fdw_handler Oid = 3115 138 | T_pg_lsn Oid = 3220 139 | T__pg_lsn Oid = 3221 140 | T_tsm_handler Oid = 3310 141 | T_anyenum Oid = 3500 142 | T_tsvector Oid = 3614 143 | T_tsquery Oid = 3615 144 | T_gtsvector Oid = 3642 145 | T__tsvector Oid = 3643 146 | T__gtsvector Oid = 3644 147 | T__tsquery Oid = 3645 148 | T_regconfig Oid = 3734 149 | T__regconfig Oid = 3735 150 | T_regdictionary Oid = 3769 151 | T__regdictionary Oid = 3770 152 | T_jsonb Oid = 3802 153 | T__jsonb Oid = 3807 154 | T_anyrange Oid = 3831 155 | T_event_trigger Oid = 3838 156 | T_int4range Oid = 3904 157 | T__int4range Oid = 3905 158 | T_numrange Oid = 3906 159 | T__numrange Oid = 3907 160 | T_tsrange Oid = 3908 161 | T__tsrange Oid = 3909 162 | T_tstzrange Oid = 3910 163 | T__tstzrange Oid = 3911 164 | T_daterange Oid = 3912 165 | T__daterange Oid = 3913 166 | T_int8range Oid = 3926 167 | T__int8range Oid = 3927 168 | T_pg_shseclabel Oid = 4066 169 | T_regnamespace Oid = 4089 170 | T__regnamespace Oid = 4090 171 | T_regrole Oid = 4096 172 | T__regrole Oid = 4097 173 | ) 174 | -------------------------------------------------------------------------------- /vendor/github.com/lib/pq/ssl.go: -------------------------------------------------------------------------------- 1 | package pq 2 | 3 | import ( 4 | "crypto/tls" 5 | "crypto/x509" 6 | "io/ioutil" 7 | "net" 8 | "os" 9 | "os/user" 10 | "path/filepath" 11 | ) 12 | 13 | // ssl generates a function to upgrade a net.Conn based on the "sslmode" and 14 | // related settings. The function is nil when no upgrade should take place. 15 | func ssl(o values) func(net.Conn) net.Conn { 16 | verifyCaOnly := false 17 | tlsConf := tls.Config{} 18 | switch mode := o["sslmode"]; mode { 19 | // "require" is the default. 20 | case "", "require": 21 | // We must skip TLS's own verification since it requires full 22 | // verification since Go 1.3. 23 | tlsConf.InsecureSkipVerify = true 24 | 25 | // From http://www.postgresql.org/docs/current/static/libpq-ssl.html: 26 | // 27 | // Note: For backwards compatibility with earlier versions of 28 | // PostgreSQL, if a root CA file exists, the behavior of 29 | // sslmode=require will be the same as that of verify-ca, meaning the 30 | // server certificate is validated against the CA. Relying on this 31 | // behavior is discouraged, and applications that need certificate 32 | // validation should always use verify-ca or verify-full. 33 | if sslrootcert, ok := o["sslrootcert"]; ok { 34 | if _, err := os.Stat(sslrootcert); err == nil { 35 | verifyCaOnly = true 36 | } else { 37 | delete(o, "sslrootcert") 38 | } 39 | } 40 | case "verify-ca": 41 | // We must skip TLS's own verification since it requires full 42 | // verification since Go 1.3. 43 | tlsConf.InsecureSkipVerify = true 44 | verifyCaOnly = true 45 | case "verify-full": 46 | tlsConf.ServerName = o["host"] 47 | case "disable": 48 | return nil 49 | default: 50 | errorf(`unsupported sslmode %q; only "require" (default), "verify-full", "verify-ca", and "disable" supported`, mode) 51 | } 52 | 53 | sslClientCertificates(&tlsConf, o) 54 | sslCertificateAuthority(&tlsConf, o) 55 | sslRenegotiation(&tlsConf) 56 | 57 | return func(conn net.Conn) net.Conn { 58 | client := tls.Client(conn, &tlsConf) 59 | if verifyCaOnly { 60 | sslVerifyCertificateAuthority(client, &tlsConf) 61 | } 62 | return client 63 | } 64 | } 65 | 66 | // sslClientCertificates adds the certificate specified in the "sslcert" and 67 | // "sslkey" settings, or if they aren't set, from the .postgresql directory 68 | // in the user's home directory. The configured files must exist and have 69 | // the correct permissions. 70 | func sslClientCertificates(tlsConf *tls.Config, o values) { 71 | // user.Current() might fail when cross-compiling. We have to ignore the 72 | // error and continue without home directory defaults, since we wouldn't 73 | // know from where to load them. 74 | user, _ := user.Current() 75 | 76 | // In libpq, the client certificate is only loaded if the setting is not blank. 77 | // 78 | // https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L1036-L1037 79 | sslcert := o["sslcert"] 80 | if len(sslcert) == 0 && user != nil { 81 | sslcert = filepath.Join(user.HomeDir, ".postgresql", "postgresql.crt") 82 | } 83 | // https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L1045 84 | if len(sslcert) == 0 { 85 | return 86 | } 87 | // https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L1050:L1054 88 | if _, err := os.Stat(sslcert); os.IsNotExist(err) { 89 | return 90 | } else if err != nil { 91 | panic(err) 92 | } 93 | 94 | // In libpq, the ssl key is only loaded if the setting is not blank. 95 | // 96 | // https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L1123-L1222 97 | sslkey := o["sslkey"] 98 | if len(sslkey) == 0 && user != nil { 99 | sslkey = filepath.Join(user.HomeDir, ".postgresql", "postgresql.key") 100 | } 101 | 102 | if len(sslkey) > 0 { 103 | if err := sslKeyPermissions(sslkey); err != nil { 104 | panic(err) 105 | } 106 | } 107 | 108 | cert, err := tls.LoadX509KeyPair(sslcert, sslkey) 109 | if err != nil { 110 | panic(err) 111 | } 112 | tlsConf.Certificates = []tls.Certificate{cert} 113 | } 114 | 115 | // sslCertificateAuthority adds the RootCA specified in the "sslrootcert" setting. 116 | func sslCertificateAuthority(tlsConf *tls.Config, o values) { 117 | // In libpq, the root certificate is only loaded if the setting is not blank. 118 | // 119 | // https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L950-L951 120 | if sslrootcert := o["sslrootcert"]; len(sslrootcert) > 0 { 121 | tlsConf.RootCAs = x509.NewCertPool() 122 | 123 | cert, err := ioutil.ReadFile(sslrootcert) 124 | if err != nil { 125 | panic(err) 126 | } 127 | 128 | if !tlsConf.RootCAs.AppendCertsFromPEM(cert) { 129 | errorf("couldn't parse pem in sslrootcert") 130 | } 131 | } 132 | } 133 | 134 | // sslVerifyCertificateAuthority carries out a TLS handshake to the server and 135 | // verifies the presented certificate against the CA, i.e. the one specified in 136 | // sslrootcert or the system CA if sslrootcert was not specified. 137 | func sslVerifyCertificateAuthority(client *tls.Conn, tlsConf *tls.Config) { 138 | err := client.Handshake() 139 | if err != nil { 140 | panic(err) 141 | } 142 | certs := client.ConnectionState().PeerCertificates 143 | opts := x509.VerifyOptions{ 144 | DNSName: client.ConnectionState().ServerName, 145 | Intermediates: x509.NewCertPool(), 146 | Roots: tlsConf.RootCAs, 147 | } 148 | for i, cert := range certs { 149 | if i == 0 { 150 | continue 151 | } 152 | opts.Intermediates.AddCert(cert) 153 | } 154 | _, err = certs[0].Verify(opts) 155 | if err != nil { 156 | panic(err) 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /vendor/github.com/lib/pq/ssl_go1.7.go: -------------------------------------------------------------------------------- 1 | // +build go1.7 2 | 3 | package pq 4 | 5 | import "crypto/tls" 6 | 7 | // Accept renegotiation requests initiated by the backend. 8 | // 9 | // Renegotiation was deprecated then removed from PostgreSQL 9.5, but 10 | // the default configuration of older versions has it enabled. Redshift 11 | // also initiates renegotiations and cannot be reconfigured. 12 | func sslRenegotiation(conf *tls.Config) { 13 | conf.Renegotiation = tls.RenegotiateFreelyAsClient 14 | } 15 | -------------------------------------------------------------------------------- /vendor/github.com/lib/pq/ssl_permissions.go: -------------------------------------------------------------------------------- 1 | // +build !windows 2 | 3 | package pq 4 | 5 | import "os" 6 | 7 | // sslKeyPermissions checks the permissions on user-supplied ssl key files. 8 | // The key file should have very little access. 9 | // 10 | // libpq does not check key file permissions on Windows. 11 | func sslKeyPermissions(sslkey string) error { 12 | info, err := os.Stat(sslkey) 13 | if err != nil { 14 | return err 15 | } 16 | if info.Mode().Perm()&0077 != 0 { 17 | return ErrSSLKeyHasWorldPermissions 18 | } 19 | return nil 20 | } 21 | -------------------------------------------------------------------------------- /vendor/github.com/lib/pq/ssl_renegotiation.go: -------------------------------------------------------------------------------- 1 | // +build !go1.7 2 | 3 | package pq 4 | 5 | import "crypto/tls" 6 | 7 | // Renegotiation is not supported by crypto/tls until Go 1.7. 8 | func sslRenegotiation(*tls.Config) {} 9 | -------------------------------------------------------------------------------- /vendor/github.com/lib/pq/ssl_windows.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package pq 4 | 5 | // sslKeyPermissions checks the permissions on user-supplied ssl key files. 6 | // The key file should have very little access. 7 | // 8 | // libpq does not check key file permissions on Windows. 9 | func sslKeyPermissions(string) error { return nil } 10 | -------------------------------------------------------------------------------- /vendor/github.com/lib/pq/url.go: -------------------------------------------------------------------------------- 1 | package pq 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | nurl "net/url" 7 | "sort" 8 | "strings" 9 | ) 10 | 11 | // ParseURL no longer needs to be used by clients of this library since supplying a URL as a 12 | // connection string to sql.Open() is now supported: 13 | // 14 | // sql.Open("postgres", "postgres://bob:secret@1.2.3.4:5432/mydb?sslmode=verify-full") 15 | // 16 | // It remains exported here for backwards-compatibility. 17 | // 18 | // ParseURL converts a url to a connection string for driver.Open. 19 | // Example: 20 | // 21 | // "postgres://bob:secret@1.2.3.4:5432/mydb?sslmode=verify-full" 22 | // 23 | // converts to: 24 | // 25 | // "user=bob password=secret host=1.2.3.4 port=5432 dbname=mydb sslmode=verify-full" 26 | // 27 | // A minimal example: 28 | // 29 | // "postgres://" 30 | // 31 | // This will be blank, causing driver.Open to use all of the defaults 32 | func ParseURL(url string) (string, error) { 33 | u, err := nurl.Parse(url) 34 | if err != nil { 35 | return "", err 36 | } 37 | 38 | if u.Scheme != "postgres" && u.Scheme != "postgresql" { 39 | return "", fmt.Errorf("invalid connection protocol: %s", u.Scheme) 40 | } 41 | 42 | var kvs []string 43 | escaper := strings.NewReplacer(` `, `\ `, `'`, `\'`, `\`, `\\`) 44 | accrue := func(k, v string) { 45 | if v != "" { 46 | kvs = append(kvs, k+"="+escaper.Replace(v)) 47 | } 48 | } 49 | 50 | if u.User != nil { 51 | v := u.User.Username() 52 | accrue("user", v) 53 | 54 | v, _ = u.User.Password() 55 | accrue("password", v) 56 | } 57 | 58 | if host, port, err := net.SplitHostPort(u.Host); err != nil { 59 | accrue("host", u.Host) 60 | } else { 61 | accrue("host", host) 62 | accrue("port", port) 63 | } 64 | 65 | if u.Path != "" { 66 | accrue("dbname", u.Path[1:]) 67 | } 68 | 69 | q := u.Query() 70 | for k := range q { 71 | accrue(k, q.Get(k)) 72 | } 73 | 74 | sort.Strings(kvs) // Makes testing easier (not a performance concern) 75 | return strings.Join(kvs, " "), nil 76 | } 77 | -------------------------------------------------------------------------------- /vendor/github.com/lib/pq/user_posix.go: -------------------------------------------------------------------------------- 1 | // Package pq is a pure Go Postgres driver for the database/sql package. 2 | 3 | // +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris rumprun 4 | 5 | package pq 6 | 7 | import ( 8 | "os" 9 | "os/user" 10 | ) 11 | 12 | func userCurrent() (string, error) { 13 | u, err := user.Current() 14 | if err == nil { 15 | return u.Username, nil 16 | } 17 | 18 | name := os.Getenv("USER") 19 | if name != "" { 20 | return name, nil 21 | } 22 | 23 | return "", ErrCouldNotDetectUsername 24 | } 25 | -------------------------------------------------------------------------------- /vendor/github.com/lib/pq/user_windows.go: -------------------------------------------------------------------------------- 1 | // Package pq is a pure Go Postgres driver for the database/sql package. 2 | package pq 3 | 4 | import ( 5 | "path/filepath" 6 | "syscall" 7 | ) 8 | 9 | // Perform Windows user name lookup identically to libpq. 10 | // 11 | // The PostgreSQL code makes use of the legacy Win32 function 12 | // GetUserName, and that function has not been imported into stock Go. 13 | // GetUserNameEx is available though, the difference being that a 14 | // wider range of names are available. To get the output to be the 15 | // same as GetUserName, only the base (or last) component of the 16 | // result is returned. 17 | func userCurrent() (string, error) { 18 | pw_name := make([]uint16, 128) 19 | pwname_size := uint32(len(pw_name)) - 1 20 | err := syscall.GetUserNameEx(syscall.NameSamCompatible, &pw_name[0], &pwname_size) 21 | if err != nil { 22 | return "", ErrCouldNotDetectUsername 23 | } 24 | s := syscall.UTF16ToString(pw_name) 25 | u := filepath.Base(s) 26 | return u, nil 27 | } 28 | -------------------------------------------------------------------------------- /vendor/github.com/lib/pq/uuid.go: -------------------------------------------------------------------------------- 1 | package pq 2 | 3 | import ( 4 | "encoding/hex" 5 | "fmt" 6 | ) 7 | 8 | // decodeUUIDBinary interprets the binary format of a uuid, returning it in text format. 9 | func decodeUUIDBinary(src []byte) ([]byte, error) { 10 | if len(src) != 16 { 11 | return nil, fmt.Errorf("pq: unable to decode uuid; bad length: %d", len(src)) 12 | } 13 | 14 | dst := make([]byte, 36) 15 | dst[8], dst[13], dst[18], dst[23] = '-', '-', '-', '-' 16 | hex.Encode(dst[0:], src[0:4]) 17 | hex.Encode(dst[9:], src[4:6]) 18 | hex.Encode(dst[14:], src[6:8]) 19 | hex.Encode(dst[19:], src[8:10]) 20 | hex.Encode(dst[24:], src[10:16]) 21 | 22 | return dst, nil 23 | } 24 | -------------------------------------------------------------------------------- /vendor/github.com/mattes/migrate/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Matthias Kadenbach 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /vendor/github.com/mattes/migrate/driver/driver.go: -------------------------------------------------------------------------------- 1 | // Package driver holds the driver interface. 2 | package driver 3 | 4 | import ( 5 | "fmt" 6 | neturl "net/url" // alias to allow `url string` func signature in New 7 | 8 | "github.com/mattes/migrate/file" 9 | ) 10 | 11 | // Driver is the interface type that needs to implemented by all drivers. 12 | type Driver interface { 13 | 14 | // Initialize is the first function to be called. 15 | // Check the url string and open and verify any connection 16 | // that has to be made. 17 | Initialize(url string) error 18 | 19 | // Close is the last function to be called. 20 | // Close any open connection here. 21 | Close() error 22 | 23 | // FilenameExtension returns the extension of the migration files. 24 | // The returned string must not begin with a dot. 25 | FilenameExtension() string 26 | 27 | // Migrate is the heart of the driver. 28 | // It will receive a file which the driver should apply 29 | // to its backend or whatever. The migration function should use 30 | // the pipe channel to return any errors or other useful information. 31 | Migrate(file file.File, pipe chan interface{}) 32 | 33 | // Version returns the current migration version. 34 | Version() (uint64, error) 35 | } 36 | 37 | // New returns Driver and calls Initialize on it 38 | func New(url string) (Driver, error) { 39 | u, err := neturl.Parse(url) 40 | if err != nil { 41 | return nil, err 42 | } 43 | 44 | d := GetDriver(u.Scheme) 45 | if d == nil { 46 | return nil, fmt.Errorf("Driver '%s' not found", u.Scheme) 47 | } 48 | verifyFilenameExtension(u.Scheme, d) 49 | if err := d.Initialize(url); err != nil { 50 | return nil, err 51 | } 52 | 53 | return d, nil 54 | } 55 | 56 | // FilenameExtensionFromURL return extension for migration files. Used for create migrations 57 | func FilenameExtensionFromURL(url string) (string, error) { 58 | u, err := neturl.Parse(url) 59 | if err != nil { 60 | return "", err 61 | } 62 | 63 | d := GetDriver(u.Scheme) 64 | if d == nil { 65 | return "", fmt.Errorf("Driver '%s' not found", u.Scheme) 66 | } 67 | verifyFilenameExtension(u.Scheme, d) 68 | 69 | return d.FilenameExtension(), nil 70 | } 71 | 72 | // verifyFilenameExtension panics if the driver's filename extension 73 | // is not correct or empty. 74 | func verifyFilenameExtension(driverName string, d Driver) { 75 | f := d.FilenameExtension() 76 | if f == "" { 77 | panic(fmt.Sprintf("%s.FilenameExtension() returns empty string.", driverName)) 78 | } 79 | if f[0:1] == "." { 80 | panic(fmt.Sprintf("%s.FilenameExtension() returned string must not start with a dot.", driverName)) 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /vendor/github.com/mattes/migrate/driver/postgres/README.md: -------------------------------------------------------------------------------- 1 | # PostgreSQL Driver 2 | 3 | * Runs migrations in transactions. 4 | That means that if a migration fails, it will be safely rolled back. 5 | * Tries to return helpful error messages. 6 | * Stores migration version details in table ``schema_migrations``. 7 | This table will be auto-generated. 8 | 9 | 10 | ## Usage 11 | 12 | ```bash 13 | migrate -url postgres://user@host:port/database -path ./db/migrations create add_field_to_table 14 | migrate -url postgres://user@host:port/database -path ./db/migrations up 15 | migrate help # for more info 16 | 17 | # TODO(mattes): thinking about adding some custom flag to allow migration within schemas: 18 | -url="postgres://user@host:port/database?schema=name" 19 | 20 | # see more docs: https://godoc.org/github.com/lib/pq#hdr-Connection_String_Parameters 21 | ``` 22 | 23 | ## Authors 24 | 25 | * Matthias Kadenbach, https://github.com/mattes 26 | -------------------------------------------------------------------------------- /vendor/github.com/mattes/migrate/driver/postgres/postgres.go: -------------------------------------------------------------------------------- 1 | // Package postgres implements the Driver interface. 2 | package postgres 3 | 4 | import ( 5 | "database/sql" 6 | "errors" 7 | "fmt" 8 | "strconv" 9 | 10 | "github.com/lib/pq" 11 | "github.com/mattes/migrate/driver" 12 | "github.com/mattes/migrate/file" 13 | "github.com/mattes/migrate/migrate/direction" 14 | ) 15 | 16 | type Driver struct { 17 | db *sql.DB 18 | } 19 | 20 | const tableName = "schema_migrations" 21 | 22 | func (driver *Driver) Initialize(url string) error { 23 | db, err := sql.Open("postgres", url) 24 | if err != nil { 25 | return err 26 | } 27 | if err := db.Ping(); err != nil { 28 | return err 29 | } 30 | driver.db = db 31 | 32 | if err := driver.ensureVersionTableExists(); err != nil { 33 | return err 34 | } 35 | return nil 36 | } 37 | 38 | func (driver *Driver) Close() error { 39 | if err := driver.db.Close(); err != nil { 40 | return err 41 | } 42 | return nil 43 | } 44 | 45 | func (driver *Driver) ensureVersionTableExists() error { 46 | r := driver.db.QueryRow("SELECT count(*) FROM information_schema.tables WHERE table_name = $1 AND table_schema = (SELECT current_schema());", tableName) 47 | c := 0 48 | if err := r.Scan(&c); err != nil { 49 | return err 50 | } 51 | if c > 0 { 52 | return nil 53 | } 54 | if _, err := driver.db.Exec("CREATE TABLE IF NOT EXISTS " + tableName + " (version bigint not null primary key);"); err != nil { 55 | return err 56 | } 57 | return nil 58 | } 59 | 60 | func (driver *Driver) FilenameExtension() string { 61 | return "sql" 62 | } 63 | 64 | func (driver *Driver) Migrate(f file.File, pipe chan interface{}) { 65 | defer close(pipe) 66 | pipe <- f 67 | 68 | tx, err := driver.db.Begin() 69 | if err != nil { 70 | pipe <- err 71 | return 72 | } 73 | 74 | if f.Direction == direction.Up { 75 | if _, err := tx.Exec("INSERT INTO "+tableName+" (version) VALUES ($1)", f.Version); err != nil { 76 | pipe <- err 77 | if err := tx.Rollback(); err != nil { 78 | pipe <- err 79 | } 80 | return 81 | } 82 | } else if f.Direction == direction.Down { 83 | if _, err := tx.Exec("DELETE FROM "+tableName+" WHERE version=$1", f.Version); err != nil { 84 | pipe <- err 85 | if err := tx.Rollback(); err != nil { 86 | pipe <- err 87 | } 88 | return 89 | } 90 | } 91 | 92 | if err := f.ReadContent(); err != nil { 93 | pipe <- err 94 | return 95 | } 96 | 97 | if _, err := tx.Exec(string(f.Content)); err != nil { 98 | switch pqErr := err.(type) { 99 | case *pq.Error: 100 | offset, err := strconv.Atoi(pqErr.Position) 101 | if err == nil && offset >= 0 { 102 | lineNo, columnNo := file.LineColumnFromOffset(f.Content, offset-1) 103 | errorPart := file.LinesBeforeAndAfter(f.Content, lineNo, 5, 5, true) 104 | pipe <- errors.New(fmt.Sprintf("%s %v: %s in line %v, column %v:\n\n%s", pqErr.Severity, pqErr.Code, pqErr.Message, lineNo, columnNo, string(errorPart))) 105 | } else { 106 | pipe <- errors.New(fmt.Sprintf("%s %v: %s", pqErr.Severity, pqErr.Code, pqErr.Message)) 107 | } 108 | 109 | if err := tx.Rollback(); err != nil { 110 | pipe <- err 111 | } 112 | return 113 | default: 114 | pipe <- err 115 | if err := tx.Rollback(); err != nil { 116 | pipe <- err 117 | } 118 | return 119 | } 120 | } 121 | 122 | if err := tx.Commit(); err != nil { 123 | pipe <- err 124 | return 125 | } 126 | } 127 | 128 | func (driver *Driver) Version() (uint64, error) { 129 | var version uint64 130 | err := driver.db.QueryRow("SELECT version FROM " + tableName + " ORDER BY version DESC LIMIT 1").Scan(&version) 131 | switch { 132 | case err == sql.ErrNoRows: 133 | return 0, nil 134 | case err != nil: 135 | return 0, err 136 | default: 137 | return version, nil 138 | } 139 | } 140 | 141 | func init() { 142 | driver.RegisterDriver("postgres", &Driver{}) 143 | } 144 | -------------------------------------------------------------------------------- /vendor/github.com/mattes/migrate/driver/registry.go: -------------------------------------------------------------------------------- 1 | package driver 2 | 3 | import ( 4 | "sort" 5 | "sync" 6 | ) 7 | 8 | var driversMu sync.Mutex 9 | var drivers = make(map[string]Driver) 10 | 11 | // RegisterDriver register a driver so it can be created from its name. Drivers should 12 | // call this from an init() function so that they registers themselves on 13 | // import 14 | func RegisterDriver(name string, driver Driver) { 15 | driversMu.Lock() 16 | defer driversMu.Unlock() 17 | if driver == nil { 18 | panic("driver: Register driver is nil") 19 | } 20 | if _, dup := drivers[name]; dup { 21 | panic("sql: Register called twice for driver " + name) 22 | } 23 | drivers[name] = driver 24 | } 25 | 26 | // GetDriver retrieves a registered driver by name 27 | func GetDriver(name string) Driver { 28 | driversMu.Lock() 29 | defer driversMu.Unlock() 30 | driver := drivers[name] 31 | return driver 32 | } 33 | 34 | // Drivers returns a sorted list of the names of the registered drivers. 35 | func Drivers() []string { 36 | driversMu.Lock() 37 | defer driversMu.Unlock() 38 | var list []string 39 | for name := range drivers { 40 | list = append(list, name) 41 | } 42 | sort.Strings(list) 43 | return list 44 | } 45 | -------------------------------------------------------------------------------- /vendor/github.com/mattes/migrate/file/file.go: -------------------------------------------------------------------------------- 1 | // Package file contains functions for low-level migration files handling. 2 | package file 3 | 4 | import ( 5 | "bytes" 6 | "errors" 7 | "fmt" 8 | "go/token" 9 | "io/ioutil" 10 | "path" 11 | "regexp" 12 | "sort" 13 | "strconv" 14 | "strings" 15 | 16 | "github.com/mattes/migrate/migrate/direction" 17 | ) 18 | 19 | var filenameRegex = `^([0-9]+)_(.*)\.(up|down)\.%s$` 20 | 21 | // FilenameRegex builds regular expression stmt with given 22 | // filename extension from driver. 23 | func FilenameRegex(filenameExtension string) *regexp.Regexp { 24 | return regexp.MustCompile(fmt.Sprintf(filenameRegex, filenameExtension)) 25 | } 26 | 27 | // File represents one file on disk. 28 | // Example: 001_initial_plan_to_do_sth.up.sql 29 | type File struct { 30 | // absolute path to file 31 | Path string 32 | 33 | // the name of the file 34 | FileName string 35 | 36 | // version parsed from filename 37 | Version uint64 38 | 39 | // the actual migration name parsed from filename 40 | Name string 41 | 42 | // content of the file 43 | Content []byte 44 | 45 | // UP or DOWN migration 46 | Direction direction.Direction 47 | } 48 | 49 | // Files is a slice of Files 50 | type Files []File 51 | 52 | // MigrationFile represents both the UP and the DOWN migration file. 53 | type MigrationFile struct { 54 | // version of the migration file, parsed from the filenames 55 | Version uint64 56 | 57 | // reference to the *up* migration file 58 | UpFile *File 59 | 60 | // reference to the *down* migration file 61 | DownFile *File 62 | } 63 | 64 | // MigrationFiles is a slice of MigrationFiles 65 | type MigrationFiles []MigrationFile 66 | 67 | // ReadContent reads the file's content if the content is empty 68 | func (f *File) ReadContent() error { 69 | if len(f.Content) == 0 { 70 | content, err := ioutil.ReadFile(path.Join(f.Path, f.FileName)) 71 | if err != nil { 72 | return err 73 | } 74 | f.Content = content 75 | } 76 | return nil 77 | } 78 | 79 | // ToFirstFrom fetches all (down) migration files including the migration file 80 | // of the current version to the very first migration file. 81 | func (mf *MigrationFiles) ToFirstFrom(version uint64) (Files, error) { 82 | sort.Sort(sort.Reverse(mf)) 83 | files := make(Files, 0) 84 | for _, migrationFile := range *mf { 85 | if migrationFile.Version <= version && migrationFile.DownFile != nil { 86 | files = append(files, *migrationFile.DownFile) 87 | } 88 | } 89 | return files, nil 90 | } 91 | 92 | // ToLastFrom fetches all (up) migration files to the most recent migration file. 93 | // The migration file of the current version is not included. 94 | func (mf *MigrationFiles) ToLastFrom(version uint64) (Files, error) { 95 | sort.Sort(mf) 96 | files := make(Files, 0) 97 | for _, migrationFile := range *mf { 98 | if migrationFile.Version > version && migrationFile.UpFile != nil { 99 | files = append(files, *migrationFile.UpFile) 100 | } 101 | } 102 | return files, nil 103 | } 104 | 105 | // From travels relatively through migration files. 106 | // 107 | // +1 will fetch the next up migration file 108 | // +2 will fetch the next two up migration files 109 | // +n will fetch ... 110 | // -1 will fetch the the previous down migration file 111 | // -2 will fetch the next two previous down migration files 112 | // -n will fetch ... 113 | func (mf *MigrationFiles) From(version uint64, relativeN int) (Files, error) { 114 | var d direction.Direction 115 | if relativeN > 0 { 116 | d = direction.Up 117 | } else if relativeN < 0 { 118 | d = direction.Down 119 | } else { // relativeN == 0 120 | return nil, nil 121 | } 122 | 123 | if d == direction.Down { 124 | sort.Sort(sort.Reverse(mf)) 125 | } else { 126 | sort.Sort(mf) 127 | } 128 | 129 | files := make(Files, 0) 130 | 131 | counter := relativeN 132 | if relativeN < 0 { 133 | counter = relativeN * -1 134 | } 135 | 136 | for _, migrationFile := range *mf { 137 | if counter > 0 { 138 | 139 | if d == direction.Up && migrationFile.Version > version && migrationFile.UpFile != nil { 140 | files = append(files, *migrationFile.UpFile) 141 | counter-- 142 | } else if d == direction.Down && migrationFile.Version <= version && migrationFile.DownFile != nil { 143 | files = append(files, *migrationFile.DownFile) 144 | counter-- 145 | } 146 | } else { 147 | break 148 | } 149 | } 150 | return files, nil 151 | } 152 | 153 | // ReadMigrationFiles reads all migration files from a given path 154 | func ReadMigrationFiles(path string, filenameRegex *regexp.Regexp) (files MigrationFiles, err error) { 155 | // find all migration files in path 156 | ioFiles, err := ioutil.ReadDir(path) 157 | if err != nil { 158 | return nil, err 159 | } 160 | type tmpFile struct { 161 | version uint64 162 | name string 163 | filename string 164 | d direction.Direction 165 | } 166 | tmpFiles := make([]*tmpFile, 0) 167 | tmpFileMap := map[uint64]map[direction.Direction]tmpFile{} 168 | for _, file := range ioFiles { 169 | version, name, d, err := parseFilenameSchema(file.Name(), filenameRegex) 170 | if err == nil { 171 | if _, ok := tmpFileMap[version]; !ok { 172 | tmpFileMap[version] = map[direction.Direction]tmpFile{} 173 | } 174 | if existing, ok := tmpFileMap[version][d]; !ok { 175 | tmpFileMap[version][d] = tmpFile{version: version, name: name, filename: file.Name(), d: d} 176 | } else { 177 | return nil, fmt.Errorf("duplicate migration file version %d : %q and %q", version, existing.filename, file.Name()) 178 | } 179 | tmpFiles = append(tmpFiles, &tmpFile{version, name, file.Name(), d}) 180 | } 181 | } 182 | 183 | // put tmpFiles into MigrationFile struct 184 | parsedVersions := make(map[uint64]bool) 185 | newFiles := make(MigrationFiles, 0) 186 | for _, file := range tmpFiles { 187 | if _, ok := parsedVersions[file.version]; !ok { 188 | migrationFile := MigrationFile{ 189 | Version: file.version, 190 | } 191 | 192 | var lookFordirection direction.Direction 193 | switch file.d { 194 | case direction.Up: 195 | migrationFile.UpFile = &File{ 196 | Path: path, 197 | FileName: file.filename, 198 | Version: file.version, 199 | Name: file.name, 200 | Content: nil, 201 | Direction: direction.Up, 202 | } 203 | lookFordirection = direction.Down 204 | case direction.Down: 205 | migrationFile.DownFile = &File{ 206 | Path: path, 207 | FileName: file.filename, 208 | Version: file.version, 209 | Name: file.name, 210 | Content: nil, 211 | Direction: direction.Down, 212 | } 213 | lookFordirection = direction.Up 214 | default: 215 | return nil, errors.New("Unsupported direction.Direction Type") 216 | } 217 | 218 | for _, file2 := range tmpFiles { 219 | if file2.version == file.version && file2.d == lookFordirection { 220 | switch lookFordirection { 221 | case direction.Up: 222 | migrationFile.UpFile = &File{ 223 | Path: path, 224 | FileName: file2.filename, 225 | Version: file.version, 226 | Name: file2.name, 227 | Content: nil, 228 | Direction: direction.Up, 229 | } 230 | case direction.Down: 231 | migrationFile.DownFile = &File{ 232 | Path: path, 233 | FileName: file2.filename, 234 | Version: file.version, 235 | Name: file2.name, 236 | Content: nil, 237 | Direction: direction.Down, 238 | } 239 | } 240 | break 241 | } 242 | } 243 | 244 | newFiles = append(newFiles, migrationFile) 245 | parsedVersions[file.version] = true 246 | } 247 | } 248 | 249 | sort.Sort(newFiles) 250 | return newFiles, nil 251 | } 252 | 253 | // parseFilenameSchema parses the filename 254 | func parseFilenameSchema(filename string, filenameRegex *regexp.Regexp) (version uint64, name string, d direction.Direction, err error) { 255 | matches := filenameRegex.FindStringSubmatch(filename) 256 | if len(matches) != 4 { 257 | return 0, "", 0, errors.New("Unable to parse filename schema") 258 | } 259 | 260 | version, err = strconv.ParseUint(matches[1], 10, 0) 261 | if err != nil { 262 | return 0, "", 0, fmt.Errorf("Unable to parse version '%v' in filename schema", matches[0]) 263 | } 264 | 265 | if matches[3] == "up" { 266 | d = direction.Up 267 | } else if matches[3] == "down" { 268 | d = direction.Down 269 | } else { 270 | return 0, "", 0, fmt.Errorf("Unable to parse up|down '%v' in filename schema", matches[3]) 271 | } 272 | 273 | return version, matches[2], d, nil 274 | } 275 | 276 | // Len is the number of elements in the collection. 277 | // Required by Sort Interface{} 278 | func (mf MigrationFiles) Len() int { 279 | return len(mf) 280 | } 281 | 282 | // Less reports whether the element with 283 | // index i should sort before the element with index j. 284 | // Required by Sort Interface{} 285 | func (mf MigrationFiles) Less(i, j int) bool { 286 | return mf[i].Version < mf[j].Version 287 | } 288 | 289 | // Swap swaps the elements with indexes i and j. 290 | // Required by Sort Interface{} 291 | func (mf MigrationFiles) Swap(i, j int) { 292 | mf[i], mf[j] = mf[j], mf[i] 293 | } 294 | 295 | // LineColumnFromOffset reads data and returns line and column integer 296 | // for a given offset. 297 | func LineColumnFromOffset(data []byte, offset int) (line, column int) { 298 | // TODO is there a better way? 299 | fs := token.NewFileSet() 300 | tf := fs.AddFile("", fs.Base(), len(data)) 301 | tf.SetLinesForContent(data) 302 | pos := tf.Position(tf.Pos(offset)) 303 | return pos.Line, pos.Column 304 | } 305 | 306 | // LinesBeforeAndAfter reads n lines before and after a given line. 307 | // Set lineNumbers to true, to prepend line numbers. 308 | func LinesBeforeAndAfter(data []byte, line, before, after int, lineNumbers bool) []byte { 309 | // TODO(mattes): Trim empty lines at the beginning and at the end 310 | // TODO(mattes): Trim offset whitespace at the beginning of each line, so that indentation is preserved 311 | startLine := line - before 312 | endLine := line + after 313 | lines := bytes.SplitN(data, []byte("\n"), endLine+1) 314 | 315 | if startLine < 0 { 316 | startLine = 0 317 | } 318 | if endLine > len(lines) { 319 | endLine = len(lines) 320 | } 321 | 322 | selectLines := lines[startLine:endLine] 323 | newLines := make([][]byte, 0) 324 | lineCounter := startLine + 1 325 | lineNumberDigits := len(strconv.Itoa(len(selectLines))) 326 | for _, l := range selectLines { 327 | lineCounterStr := strconv.Itoa(lineCounter) 328 | if len(lineCounterStr)%lineNumberDigits != 0 { 329 | lineCounterStr = strings.Repeat(" ", lineNumberDigits-len(lineCounterStr)%lineNumberDigits) + lineCounterStr 330 | } 331 | 332 | lNew := l 333 | if lineNumbers { 334 | lNew = append([]byte(lineCounterStr+": "), lNew...) 335 | } 336 | newLines = append(newLines, lNew) 337 | lineCounter++ 338 | } 339 | 340 | return bytes.Join(newLines, []byte("\n")) 341 | } 342 | -------------------------------------------------------------------------------- /vendor/github.com/mattes/migrate/migrate/direction/direction.go: -------------------------------------------------------------------------------- 1 | // Package direction just holds convenience constants for Up and Down migrations. 2 | package direction 3 | 4 | // Direction - type that indicates direction of migration(up or down) 5 | type Direction int 6 | 7 | const ( 8 | // Up - up migration 9 | Up Direction = +1 10 | // Down - down migration 11 | Down Direction = -1 12 | ) 13 | -------------------------------------------------------------------------------- /vendor/github.com/mattes/migrate/migrate/migrate.go: -------------------------------------------------------------------------------- 1 | // Package migrate is imported by other Go code. 2 | // It is the entry point to all migration functions. 3 | package migrate 4 | 5 | import ( 6 | "fmt" 7 | "io/ioutil" 8 | "os" 9 | "os/signal" 10 | "path" 11 | "strconv" 12 | "strings" 13 | "time" 14 | 15 | "github.com/mattes/migrate/driver" 16 | "github.com/mattes/migrate/file" 17 | "github.com/mattes/migrate/migrate/direction" 18 | pipep "github.com/mattes/migrate/pipe" 19 | ) 20 | 21 | // Up applies all available migrations 22 | func Up(pipe chan interface{}, url, migrationsPath string) { 23 | d, files, version, err := initDriverAndReadMigrationFilesAndGetVersion(url, migrationsPath) 24 | if err != nil { 25 | go pipep.Close(pipe, err) 26 | return 27 | } 28 | 29 | applyMigrationFiles, err := files.ToLastFrom(version) 30 | if err != nil { 31 | if err2 := d.Close(); err2 != nil { 32 | pipe <- err2 33 | } 34 | go pipep.Close(pipe, err) 35 | return 36 | } 37 | 38 | signals := handleInterrupts() 39 | defer signal.Stop(signals) 40 | 41 | if len(applyMigrationFiles) > 0 { 42 | for _, f := range applyMigrationFiles { 43 | pipe1 := pipep.New() 44 | go d.Migrate(f, pipe1) 45 | if ok := pipep.WaitAndRedirect(pipe1, pipe, signals); !ok { 46 | break 47 | } 48 | } 49 | if err := d.Close(); err != nil { 50 | pipe <- err 51 | } 52 | go pipep.Close(pipe, nil) 53 | return 54 | } 55 | if err := d.Close(); err != nil { 56 | pipe <- err 57 | } 58 | go pipep.Close(pipe, nil) 59 | return 60 | } 61 | 62 | // UpSync is synchronous version of Up 63 | func UpSync(url, migrationsPath string) (err []error, ok bool) { 64 | pipe := pipep.New() 65 | go Up(pipe, url, migrationsPath) 66 | err = pipep.ReadErrors(pipe) 67 | return err, len(err) == 0 68 | } 69 | 70 | // Down rolls back all migrations 71 | func Down(pipe chan interface{}, url, migrationsPath string) { 72 | d, files, version, err := initDriverAndReadMigrationFilesAndGetVersion(url, migrationsPath) 73 | if err != nil { 74 | go pipep.Close(pipe, err) 75 | return 76 | } 77 | 78 | applyMigrationFiles, err := files.ToFirstFrom(version) 79 | if err != nil { 80 | if err2 := d.Close(); err2 != nil { 81 | pipe <- err2 82 | } 83 | go pipep.Close(pipe, err) 84 | return 85 | } 86 | 87 | signals := handleInterrupts() 88 | defer signal.Stop(signals) 89 | 90 | if len(applyMigrationFiles) > 0 { 91 | for _, f := range applyMigrationFiles { 92 | pipe1 := pipep.New() 93 | go d.Migrate(f, pipe1) 94 | if ok := pipep.WaitAndRedirect(pipe1, pipe, signals); !ok { 95 | break 96 | } 97 | } 98 | if err2 := d.Close(); err2 != nil { 99 | pipe <- err2 100 | } 101 | go pipep.Close(pipe, nil) 102 | return 103 | } 104 | if err2 := d.Close(); err2 != nil { 105 | pipe <- err2 106 | } 107 | go pipep.Close(pipe, nil) 108 | return 109 | } 110 | 111 | // DownSync is synchronous version of Down 112 | func DownSync(url, migrationsPath string) (err []error, ok bool) { 113 | pipe := pipep.New() 114 | go Down(pipe, url, migrationsPath) 115 | err = pipep.ReadErrors(pipe) 116 | return err, len(err) == 0 117 | } 118 | 119 | // Redo rolls back the most recently applied migration, then runs it again. 120 | func Redo(pipe chan interface{}, url, migrationsPath string) { 121 | pipe1 := pipep.New() 122 | go Migrate(pipe1, url, migrationsPath, -1) 123 | 124 | signals := handleInterrupts() 125 | defer signal.Stop(signals) 126 | 127 | if ok := pipep.WaitAndRedirect(pipe1, pipe, signals); !ok { 128 | go pipep.Close(pipe, nil) 129 | return 130 | } 131 | go Migrate(pipe, url, migrationsPath, +1) 132 | } 133 | 134 | // RedoSync is synchronous version of Redo 135 | func RedoSync(url, migrationsPath string) (err []error, ok bool) { 136 | pipe := pipep.New() 137 | go Redo(pipe, url, migrationsPath) 138 | err = pipep.ReadErrors(pipe) 139 | return err, len(err) == 0 140 | } 141 | 142 | // Reset runs the down and up migration function 143 | func Reset(pipe chan interface{}, url, migrationsPath string) { 144 | pipe1 := pipep.New() 145 | go Down(pipe1, url, migrationsPath) 146 | 147 | signals := handleInterrupts() 148 | defer signal.Stop(signals) 149 | 150 | if ok := pipep.WaitAndRedirect(pipe1, pipe, signals); !ok { 151 | go pipep.Close(pipe, nil) 152 | return 153 | } 154 | go Up(pipe, url, migrationsPath) 155 | } 156 | 157 | // ResetSync is synchronous version of Reset 158 | func ResetSync(url, migrationsPath string) (err []error, ok bool) { 159 | pipe := pipep.New() 160 | go Reset(pipe, url, migrationsPath) 161 | err = pipep.ReadErrors(pipe) 162 | return err, len(err) == 0 163 | } 164 | 165 | // Migrate applies relative +n/-n migrations 166 | func Migrate(pipe chan interface{}, url, migrationsPath string, relativeN int) { 167 | d, files, version, err := initDriverAndReadMigrationFilesAndGetVersion(url, migrationsPath) 168 | if err != nil { 169 | go pipep.Close(pipe, err) 170 | return 171 | } 172 | 173 | applyMigrationFiles, err := files.From(version, relativeN) 174 | if err != nil { 175 | if err2 := d.Close(); err2 != nil { 176 | pipe <- err2 177 | } 178 | go pipep.Close(pipe, err) 179 | return 180 | } 181 | 182 | signals := handleInterrupts() 183 | defer signal.Stop(signals) 184 | 185 | if len(applyMigrationFiles) > 0 && relativeN != 0 { 186 | for _, f := range applyMigrationFiles { 187 | pipe1 := pipep.New() 188 | go d.Migrate(f, pipe1) 189 | if ok := pipep.WaitAndRedirect(pipe1, pipe, signals); !ok { 190 | break 191 | } 192 | } 193 | if err2 := d.Close(); err2 != nil { 194 | pipe <- err2 195 | } 196 | go pipep.Close(pipe, nil) 197 | return 198 | } 199 | if err2 := d.Close(); err2 != nil { 200 | pipe <- err2 201 | } 202 | go pipep.Close(pipe, nil) 203 | return 204 | } 205 | 206 | // MigrateSync is synchronous version of Migrate 207 | func MigrateSync(url, migrationsPath string, relativeN int) (err []error, ok bool) { 208 | pipe := pipep.New() 209 | go Migrate(pipe, url, migrationsPath, relativeN) 210 | err = pipep.ReadErrors(pipe) 211 | return err, len(err) == 0 212 | } 213 | 214 | // Version returns the current migration version 215 | func Version(url, migrationsPath string) (version uint64, err error) { 216 | d, err := driver.New(url) 217 | if err != nil { 218 | return 0, err 219 | } 220 | defer func() { 221 | err = d.Close() 222 | }() 223 | return d.Version() 224 | } 225 | 226 | // Create creates new migration files on disk 227 | func Create(url, migrationsPath, name string) (*file.MigrationFile, error) { 228 | ext, err := driver.FilenameExtensionFromURL(url) 229 | if err != nil { 230 | return nil, err 231 | } 232 | 233 | files, err := file.ReadMigrationFiles(migrationsPath, file.FilenameRegex(ext)) 234 | if err != nil { 235 | return nil, err 236 | } 237 | 238 | version := uint64(time.Now().Unix()) 239 | 240 | for _, f := range files { 241 | if f.Version == version { 242 | version++ 243 | } 244 | } 245 | 246 | versionStr := strconv.FormatUint(version, 10) 247 | 248 | length := 10 249 | if len(versionStr)%length != 0 { 250 | versionStr = strings.Repeat("0", length-len(versionStr)%length) + versionStr 251 | } 252 | 253 | filenamef := "%s_%s.%s.%s" 254 | name = strings.Replace(name, " ", "_", -1) 255 | 256 | mfile := &file.MigrationFile{ 257 | Version: version, 258 | UpFile: &file.File{ 259 | Path: migrationsPath, 260 | FileName: fmt.Sprintf(filenamef, versionStr, name, "up", ext), 261 | Name: name, 262 | Content: []byte(""), 263 | Direction: direction.Up, 264 | }, 265 | DownFile: &file.File{ 266 | Path: migrationsPath, 267 | FileName: fmt.Sprintf(filenamef, versionStr, name, "down", ext), 268 | Name: name, 269 | Content: []byte(""), 270 | Direction: direction.Down, 271 | }, 272 | } 273 | 274 | if err := ioutil.WriteFile(path.Join(mfile.UpFile.Path, mfile.UpFile.FileName), mfile.UpFile.Content, 0644); err != nil { 275 | return nil, err 276 | } 277 | if err := ioutil.WriteFile(path.Join(mfile.DownFile.Path, mfile.DownFile.FileName), mfile.DownFile.Content, 0644); err != nil { 278 | return nil, err 279 | } 280 | 281 | return mfile, nil 282 | } 283 | 284 | // initDriverAndReadMigrationFilesAndGetVersion is a small helper 285 | // function that is common to most of the migration funcs 286 | func initDriverAndReadMigrationFilesAndGetVersion(url, migrationsPath string) (driver.Driver, *file.MigrationFiles, uint64, error) { 287 | d, err := driver.New(url) 288 | if err != nil { 289 | return nil, nil, 0, err 290 | } 291 | files, err := file.ReadMigrationFiles(migrationsPath, file.FilenameRegex(d.FilenameExtension())) 292 | if err != nil { 293 | d.Close() // TODO what happens with errors from this func? 294 | return nil, nil, 0, err 295 | } 296 | version, err := d.Version() 297 | if err != nil { 298 | d.Close() // TODO what happens with errors from this func? 299 | return nil, nil, 0, err 300 | } 301 | return d, &files, version, nil 302 | } 303 | 304 | // NewPipe is a convenience function for pipe.New(). 305 | // This is helpful if the user just wants to import this package and nothing else. 306 | func NewPipe() chan interface{} { 307 | return pipep.New() 308 | } 309 | 310 | // interrupts is an internal variable that holds the state of 311 | // interrupt handling 312 | var interrupts = true 313 | 314 | // Graceful enables interrupts checking. Once the first ^C is received 315 | // it will finish the currently running migration and abort execution 316 | // of the next migration. If ^C is received twice, it will stop 317 | // execution immediately. 318 | func Graceful() { 319 | interrupts = true 320 | } 321 | 322 | // NonGraceful disables interrupts checking. The first received ^C will 323 | // stop execution immediately. 324 | func NonGraceful() { 325 | interrupts = false 326 | } 327 | 328 | // interrupts returns a signal channel if interrupts checking is 329 | // enabled. nil otherwise. 330 | func handleInterrupts() chan os.Signal { 331 | if interrupts { 332 | c := make(chan os.Signal, 1) 333 | signal.Notify(c, os.Interrupt) 334 | return c 335 | } 336 | return nil 337 | } 338 | -------------------------------------------------------------------------------- /vendor/github.com/mattes/migrate/pipe/pipe.go: -------------------------------------------------------------------------------- 1 | // Package pipe has functions for pipe channel handling. 2 | package pipe 3 | 4 | import ( 5 | "os" 6 | "os/signal" 7 | ) 8 | 9 | // New creates a new pipe. A pipe is basically a channel. 10 | func New() chan interface{} { 11 | return make(chan interface{}, 0) 12 | } 13 | 14 | // Close closes a pipe and optionally sends an error 15 | func Close(pipe chan interface{}, err error) { 16 | if err != nil { 17 | pipe <- err 18 | } 19 | close(pipe) 20 | } 21 | 22 | // WaitAndRedirect waits for pipe to be closed and 23 | // redirects all messages from pipe to redirectPipe 24 | // while it waits. It also checks if there was an 25 | // interrupt send and will quit gracefully if yes. 26 | func WaitAndRedirect(pipe, redirectPipe chan interface{}, interrupt chan os.Signal) (ok bool) { 27 | errorReceived := false 28 | interruptsReceived := 0 29 | defer stopNotifyInterruptChannel(interrupt) 30 | if pipe != nil && redirectPipe != nil { 31 | for { 32 | select { 33 | 34 | case <-interrupt: 35 | interruptsReceived++ 36 | if interruptsReceived > 1 { 37 | os.Exit(5) 38 | } else { 39 | // add white space at beginning for ^C splitting 40 | redirectPipe <- " Aborting after this migration ... Hit again to force quit." 41 | } 42 | 43 | case item, ok := <-pipe: 44 | if !ok { 45 | return !errorReceived && interruptsReceived == 0 46 | } 47 | redirectPipe <- item 48 | switch item.(type) { 49 | case error: 50 | errorReceived = true 51 | } 52 | } 53 | } 54 | } 55 | return !errorReceived && interruptsReceived == 0 56 | } 57 | 58 | // ReadErrors selects all received errors and returns them. 59 | // This is helpful for synchronous migration functions. 60 | func ReadErrors(pipe chan interface{}) []error { 61 | err := make([]error, 0) 62 | if pipe != nil { 63 | for { 64 | select { 65 | case item, ok := <-pipe: 66 | if !ok { 67 | return err 68 | } 69 | switch item.(type) { 70 | case error: 71 | err = append(err, item.(error)) 72 | } 73 | } 74 | } 75 | } 76 | return err 77 | } 78 | 79 | func stopNotifyInterruptChannel(interruptChannel chan os.Signal) { 80 | if interruptChannel != nil { 81 | signal.Stop(interruptChannel) 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /vendor/github.com/pmezard/go-difflib/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013, Patrick Mezard 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | The names of its contributors may not be used to endorse or promote 14 | products derived from this software without specific prior written 15 | permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 18 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 19 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 20 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 23 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 24 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 25 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 26 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 - 2013 Mat Ryer and Tyler Bunnell 2 | 3 | Please consider promoting this project if you find it useful. 4 | 5 | Permission is hereby granted, free of charge, to any person 6 | obtaining a copy of this software and associated documentation 7 | files (the "Software"), to deal in the Software without restriction, 8 | including without limitation the rights to use, copy, modify, merge, 9 | publish, distribute, sublicense, and/or sell copies of the Software, 10 | and to permit persons to whom the Software is furnished to do so, 11 | subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included 14 | in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 18 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 20 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT 21 | OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 22 | OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/assertion_forward.go.tmpl: -------------------------------------------------------------------------------- 1 | {{.CommentWithoutT "a"}} 2 | func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) bool { 3 | return {{.DocInfo.Name}}(a.t, {{.ForwardedParams}}) 4 | } 5 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/doc.go: -------------------------------------------------------------------------------- 1 | // Package assert provides a set of comprehensive testing tools for use with the normal Go testing system. 2 | // 3 | // Example Usage 4 | // 5 | // The following is a complete example using assert in a standard test function: 6 | // import ( 7 | // "testing" 8 | // "github.com/stretchr/testify/assert" 9 | // ) 10 | // 11 | // func TestSomething(t *testing.T) { 12 | // 13 | // var a string = "Hello" 14 | // var b string = "Hello" 15 | // 16 | // assert.Equal(t, a, b, "The two words should be the same.") 17 | // 18 | // } 19 | // 20 | // if you assert many times, use the format below: 21 | // 22 | // import ( 23 | // "testing" 24 | // "github.com/stretchr/testify/assert" 25 | // ) 26 | // 27 | // func TestSomething(t *testing.T) { 28 | // assert := assert.New(t) 29 | // 30 | // var a string = "Hello" 31 | // var b string = "Hello" 32 | // 33 | // assert.Equal(a, b, "The two words should be the same.") 34 | // } 35 | // 36 | // Assertions 37 | // 38 | // Assertions allow you to easily write test code, and are global funcs in the `assert` package. 39 | // All assertion functions take, as the first argument, the `*testing.T` object provided by the 40 | // testing framework. This allows the assertion funcs to write the failings and other details to 41 | // the correct place. 42 | // 43 | // Every assertion function also takes an optional string message as the final argument, 44 | // allowing custom error messages to be appended to the message the assertion method outputs. 45 | package assert 46 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/errors.go: -------------------------------------------------------------------------------- 1 | package assert 2 | 3 | import ( 4 | "errors" 5 | ) 6 | 7 | // AnError is an error instance useful for testing. If the code does not care 8 | // about error specifics, and only needs to return the error for example, this 9 | // error should be used to make the test code more readable. 10 | var AnError = errors.New("assert.AnError general error for testing") 11 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/forward_assertions.go: -------------------------------------------------------------------------------- 1 | package assert 2 | 3 | // Assertions provides assertion methods around the 4 | // TestingT interface. 5 | type Assertions struct { 6 | t TestingT 7 | } 8 | 9 | // New makes a new Assertions object for the specified TestingT. 10 | func New(t TestingT) *Assertions { 11 | return &Assertions{ 12 | t: t, 13 | } 14 | } 15 | 16 | //go:generate go run ../_codegen/main.go -output-package=assert -template=assertion_forward.go.tmpl 17 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/http_assertions.go: -------------------------------------------------------------------------------- 1 | package assert 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | "net/http/httptest" 7 | "net/url" 8 | "strings" 9 | ) 10 | 11 | // httpCode is a helper that returns HTTP code of the response. It returns -1 12 | // if building a new request fails. 13 | func httpCode(handler http.HandlerFunc, method, url string, values url.Values) int { 14 | w := httptest.NewRecorder() 15 | req, err := http.NewRequest(method, url+"?"+values.Encode(), nil) 16 | if err != nil { 17 | return -1 18 | } 19 | handler(w, req) 20 | return w.Code 21 | } 22 | 23 | // HTTPSuccess asserts that a specified handler returns a success status code. 24 | // 25 | // assert.HTTPSuccess(t, myHandler, "POST", "http://www.google.com", nil) 26 | // 27 | // Returns whether the assertion was successful (true) or not (false). 28 | func HTTPSuccess(t TestingT, handler http.HandlerFunc, method, url string, values url.Values) bool { 29 | code := httpCode(handler, method, url, values) 30 | if code == -1 { 31 | return false 32 | } 33 | return code >= http.StatusOK && code <= http.StatusPartialContent 34 | } 35 | 36 | // HTTPRedirect asserts that a specified handler returns a redirect status code. 37 | // 38 | // assert.HTTPRedirect(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} 39 | // 40 | // Returns whether the assertion was successful (true) or not (false). 41 | func HTTPRedirect(t TestingT, handler http.HandlerFunc, method, url string, values url.Values) bool { 42 | code := httpCode(handler, method, url, values) 43 | if code == -1 { 44 | return false 45 | } 46 | return code >= http.StatusMultipleChoices && code <= http.StatusTemporaryRedirect 47 | } 48 | 49 | // HTTPError asserts that a specified handler returns an error status code. 50 | // 51 | // assert.HTTPError(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} 52 | // 53 | // Returns whether the assertion was successful (true) or not (false). 54 | func HTTPError(t TestingT, handler http.HandlerFunc, method, url string, values url.Values) bool { 55 | code := httpCode(handler, method, url, values) 56 | if code == -1 { 57 | return false 58 | } 59 | return code >= http.StatusBadRequest 60 | } 61 | 62 | // HTTPBody is a helper that returns HTTP body of the response. It returns 63 | // empty string if building a new request fails. 64 | func HTTPBody(handler http.HandlerFunc, method, url string, values url.Values) string { 65 | w := httptest.NewRecorder() 66 | req, err := http.NewRequest(method, url+"?"+values.Encode(), nil) 67 | if err != nil { 68 | return "" 69 | } 70 | handler(w, req) 71 | return w.Body.String() 72 | } 73 | 74 | // HTTPBodyContains asserts that a specified handler returns a 75 | // body that contains a string. 76 | // 77 | // assert.HTTPBodyContains(t, myHandler, "www.google.com", nil, "I'm Feeling Lucky") 78 | // 79 | // Returns whether the assertion was successful (true) or not (false). 80 | func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}) bool { 81 | body := HTTPBody(handler, method, url, values) 82 | 83 | contains := strings.Contains(body, fmt.Sprint(str)) 84 | if !contains { 85 | Fail(t, fmt.Sprintf("Expected response body for \"%s\" to contain \"%s\" but found \"%s\"", url+"?"+values.Encode(), str, body)) 86 | } 87 | 88 | return contains 89 | } 90 | 91 | // HTTPBodyNotContains asserts that a specified handler returns a 92 | // body that does not contain a string. 93 | // 94 | // assert.HTTPBodyNotContains(t, myHandler, "www.google.com", nil, "I'm Feeling Lucky") 95 | // 96 | // Returns whether the assertion was successful (true) or not (false). 97 | func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}) bool { 98 | body := HTTPBody(handler, method, url, values) 99 | 100 | contains := strings.Contains(body, fmt.Sprint(str)) 101 | if contains { 102 | Fail(t, fmt.Sprintf("Expected response body for \"%s\" to NOT contain \"%s\" but found \"%s\"", url+"?"+values.Encode(), str, body)) 103 | } 104 | 105 | return !contains 106 | } 107 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/require/doc.go: -------------------------------------------------------------------------------- 1 | // Package require implements the same assertions as the `assert` package but 2 | // stops test execution when a test fails. 3 | // 4 | // Example Usage 5 | // 6 | // The following is a complete example using require in a standard test function: 7 | // import ( 8 | // "testing" 9 | // "github.com/stretchr/testify/require" 10 | // ) 11 | // 12 | // func TestSomething(t *testing.T) { 13 | // 14 | // var a string = "Hello" 15 | // var b string = "Hello" 16 | // 17 | // require.Equal(t, a, b, "The two words should be the same.") 18 | // 19 | // } 20 | // 21 | // Assertions 22 | // 23 | // The `require` package have same global functions as in the `assert` package, 24 | // but instead of returning a boolean result they call `t.FailNow()`. 25 | // 26 | // Every assertion function also takes an optional string message as the final argument, 27 | // allowing custom error messages to be appended to the message the assertion method outputs. 28 | package require 29 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/require/forward_requirements.go: -------------------------------------------------------------------------------- 1 | package require 2 | 3 | // Assertions provides assertion methods around the 4 | // TestingT interface. 5 | type Assertions struct { 6 | t TestingT 7 | } 8 | 9 | // New makes a new Assertions object for the specified TestingT. 10 | func New(t TestingT) *Assertions { 11 | return &Assertions{ 12 | t: t, 13 | } 14 | } 15 | 16 | //go:generate go run ../_codegen/main.go -output-package=require -template=require_forward.go.tmpl 17 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/require/require.go.tmpl: -------------------------------------------------------------------------------- 1 | {{.Comment}} 2 | func {{.DocInfo.Name}}(t TestingT, {{.Params}}) { 3 | if !assert.{{.DocInfo.Name}}(t, {{.ForwardedParams}}) { 4 | t.FailNow() 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/require/require_forward.go: -------------------------------------------------------------------------------- 1 | /* 2 | * CODE GENERATED AUTOMATICALLY WITH github.com/stretchr/testify/_codegen 3 | * THIS FILE MUST NOT BE EDITED BY HAND 4 | */ 5 | 6 | package require 7 | 8 | import ( 9 | assert "github.com/stretchr/testify/assert" 10 | http "net/http" 11 | url "net/url" 12 | time "time" 13 | ) 14 | 15 | // Condition uses a Comparison to assert a complex condition. 16 | func (a *Assertions) Condition(comp assert.Comparison, msgAndArgs ...interface{}) { 17 | Condition(a.t, comp, msgAndArgs...) 18 | } 19 | 20 | // Contains asserts that the specified string, list(array, slice...) or map contains the 21 | // specified substring or element. 22 | // 23 | // a.Contains("Hello World", "World", "But 'Hello World' does contain 'World'") 24 | // a.Contains(["Hello", "World"], "World", "But ["Hello", "World"] does contain 'World'") 25 | // a.Contains({"Hello": "World"}, "Hello", "But {'Hello': 'World'} does contain 'Hello'") 26 | // 27 | // Returns whether the assertion was successful (true) or not (false). 28 | func (a *Assertions) Contains(s interface{}, contains interface{}, msgAndArgs ...interface{}) { 29 | Contains(a.t, s, contains, msgAndArgs...) 30 | } 31 | 32 | // Empty asserts that the specified object is empty. I.e. nil, "", false, 0 or either 33 | // a slice or a channel with len == 0. 34 | // 35 | // a.Empty(obj) 36 | // 37 | // Returns whether the assertion was successful (true) or not (false). 38 | func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) { 39 | Empty(a.t, object, msgAndArgs...) 40 | } 41 | 42 | // Equal asserts that two objects are equal. 43 | // 44 | // a.Equal(123, 123, "123 and 123 should be equal") 45 | // 46 | // Returns whether the assertion was successful (true) or not (false). 47 | // 48 | // Pointer variable equality is determined based on the equality of the 49 | // referenced values (as opposed to the memory addresses). 50 | func (a *Assertions) Equal(expected interface{}, actual interface{}, msgAndArgs ...interface{}) { 51 | Equal(a.t, expected, actual, msgAndArgs...) 52 | } 53 | 54 | // EqualError asserts that a function returned an error (i.e. not `nil`) 55 | // and that it is equal to the provided error. 56 | // 57 | // actualObj, err := SomeFunction() 58 | // a.EqualError(err, expectedErrorString, "An error was expected") 59 | // 60 | // Returns whether the assertion was successful (true) or not (false). 61 | func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ...interface{}) { 62 | EqualError(a.t, theError, errString, msgAndArgs...) 63 | } 64 | 65 | // EqualValues asserts that two objects are equal or convertable to the same types 66 | // and equal. 67 | // 68 | // a.EqualValues(uint32(123), int32(123), "123 and 123 should be equal") 69 | // 70 | // Returns whether the assertion was successful (true) or not (false). 71 | func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) { 72 | EqualValues(a.t, expected, actual, msgAndArgs...) 73 | } 74 | 75 | // Error asserts that a function returned an error (i.e. not `nil`). 76 | // 77 | // actualObj, err := SomeFunction() 78 | // if a.Error(err, "An error was expected") { 79 | // assert.Equal(t, err, expectedError) 80 | // } 81 | // 82 | // Returns whether the assertion was successful (true) or not (false). 83 | func (a *Assertions) Error(err error, msgAndArgs ...interface{}) { 84 | Error(a.t, err, msgAndArgs...) 85 | } 86 | 87 | // Exactly asserts that two objects are equal is value and type. 88 | // 89 | // a.Exactly(int32(123), int64(123), "123 and 123 should NOT be equal") 90 | // 91 | // Returns whether the assertion was successful (true) or not (false). 92 | func (a *Assertions) Exactly(expected interface{}, actual interface{}, msgAndArgs ...interface{}) { 93 | Exactly(a.t, expected, actual, msgAndArgs...) 94 | } 95 | 96 | // Fail reports a failure through 97 | func (a *Assertions) Fail(failureMessage string, msgAndArgs ...interface{}) { 98 | Fail(a.t, failureMessage, msgAndArgs...) 99 | } 100 | 101 | // FailNow fails test 102 | func (a *Assertions) FailNow(failureMessage string, msgAndArgs ...interface{}) { 103 | FailNow(a.t, failureMessage, msgAndArgs...) 104 | } 105 | 106 | // False asserts that the specified value is false. 107 | // 108 | // a.False(myBool, "myBool should be false") 109 | // 110 | // Returns whether the assertion was successful (true) or not (false). 111 | func (a *Assertions) False(value bool, msgAndArgs ...interface{}) { 112 | False(a.t, value, msgAndArgs...) 113 | } 114 | 115 | // HTTPBodyContains asserts that a specified handler returns a 116 | // body that contains a string. 117 | // 118 | // a.HTTPBodyContains(myHandler, "www.google.com", nil, "I'm Feeling Lucky") 119 | // 120 | // Returns whether the assertion was successful (true) or not (false). 121 | func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}) { 122 | HTTPBodyContains(a.t, handler, method, url, values, str) 123 | } 124 | 125 | // HTTPBodyNotContains asserts that a specified handler returns a 126 | // body that does not contain a string. 127 | // 128 | // a.HTTPBodyNotContains(myHandler, "www.google.com", nil, "I'm Feeling Lucky") 129 | // 130 | // Returns whether the assertion was successful (true) or not (false). 131 | func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}) { 132 | HTTPBodyNotContains(a.t, handler, method, url, values, str) 133 | } 134 | 135 | // HTTPError asserts that a specified handler returns an error status code. 136 | // 137 | // a.HTTPError(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} 138 | // 139 | // Returns whether the assertion was successful (true) or not (false). 140 | func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url string, values url.Values) { 141 | HTTPError(a.t, handler, method, url, values) 142 | } 143 | 144 | // HTTPRedirect asserts that a specified handler returns a redirect status code. 145 | // 146 | // a.HTTPRedirect(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} 147 | // 148 | // Returns whether the assertion was successful (true) or not (false). 149 | func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url string, values url.Values) { 150 | HTTPRedirect(a.t, handler, method, url, values) 151 | } 152 | 153 | // HTTPSuccess asserts that a specified handler returns a success status code. 154 | // 155 | // a.HTTPSuccess(myHandler, "POST", "http://www.google.com", nil) 156 | // 157 | // Returns whether the assertion was successful (true) or not (false). 158 | func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method string, url string, values url.Values) { 159 | HTTPSuccess(a.t, handler, method, url, values) 160 | } 161 | 162 | // Implements asserts that an object is implemented by the specified interface. 163 | // 164 | // a.Implements((*MyInterface)(nil), new(MyObject), "MyObject") 165 | func (a *Assertions) Implements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) { 166 | Implements(a.t, interfaceObject, object, msgAndArgs...) 167 | } 168 | 169 | // InDelta asserts that the two numerals are within delta of each other. 170 | // 171 | // a.InDelta(math.Pi, (22 / 7.0), 0.01) 172 | // 173 | // Returns whether the assertion was successful (true) or not (false). 174 | func (a *Assertions) InDelta(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) { 175 | InDelta(a.t, expected, actual, delta, msgAndArgs...) 176 | } 177 | 178 | // InDeltaSlice is the same as InDelta, except it compares two slices. 179 | func (a *Assertions) InDeltaSlice(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) { 180 | InDeltaSlice(a.t, expected, actual, delta, msgAndArgs...) 181 | } 182 | 183 | // InEpsilon asserts that expected and actual have a relative error less than epsilon 184 | // 185 | // Returns whether the assertion was successful (true) or not (false). 186 | func (a *Assertions) InEpsilon(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) { 187 | InEpsilon(a.t, expected, actual, epsilon, msgAndArgs...) 188 | } 189 | 190 | // InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices. 191 | func (a *Assertions) InEpsilonSlice(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) { 192 | InEpsilonSlice(a.t, expected, actual, epsilon, msgAndArgs...) 193 | } 194 | 195 | // IsType asserts that the specified objects are of the same type. 196 | func (a *Assertions) IsType(expectedType interface{}, object interface{}, msgAndArgs ...interface{}) { 197 | IsType(a.t, expectedType, object, msgAndArgs...) 198 | } 199 | 200 | // JSONEq asserts that two JSON strings are equivalent. 201 | // 202 | // a.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) 203 | // 204 | // Returns whether the assertion was successful (true) or not (false). 205 | func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ...interface{}) { 206 | JSONEq(a.t, expected, actual, msgAndArgs...) 207 | } 208 | 209 | // Len asserts that the specified object has specific length. 210 | // Len also fails if the object has a type that len() not accept. 211 | // 212 | // a.Len(mySlice, 3, "The size of slice is not 3") 213 | // 214 | // Returns whether the assertion was successful (true) or not (false). 215 | func (a *Assertions) Len(object interface{}, length int, msgAndArgs ...interface{}) { 216 | Len(a.t, object, length, msgAndArgs...) 217 | } 218 | 219 | // Nil asserts that the specified object is nil. 220 | // 221 | // a.Nil(err, "err should be nothing") 222 | // 223 | // Returns whether the assertion was successful (true) or not (false). 224 | func (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) { 225 | Nil(a.t, object, msgAndArgs...) 226 | } 227 | 228 | // NoError asserts that a function returned no error (i.e. `nil`). 229 | // 230 | // actualObj, err := SomeFunction() 231 | // if a.NoError(err) { 232 | // assert.Equal(t, actualObj, expectedObj) 233 | // } 234 | // 235 | // Returns whether the assertion was successful (true) or not (false). 236 | func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) { 237 | NoError(a.t, err, msgAndArgs...) 238 | } 239 | 240 | // NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the 241 | // specified substring or element. 242 | // 243 | // a.NotContains("Hello World", "Earth", "But 'Hello World' does NOT contain 'Earth'") 244 | // a.NotContains(["Hello", "World"], "Earth", "But ['Hello', 'World'] does NOT contain 'Earth'") 245 | // a.NotContains({"Hello": "World"}, "Earth", "But {'Hello': 'World'} does NOT contain 'Earth'") 246 | // 247 | // Returns whether the assertion was successful (true) or not (false). 248 | func (a *Assertions) NotContains(s interface{}, contains interface{}, msgAndArgs ...interface{}) { 249 | NotContains(a.t, s, contains, msgAndArgs...) 250 | } 251 | 252 | // NotEmpty asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either 253 | // a slice or a channel with len == 0. 254 | // 255 | // if a.NotEmpty(obj) { 256 | // assert.Equal(t, "two", obj[1]) 257 | // } 258 | // 259 | // Returns whether the assertion was successful (true) or not (false). 260 | func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) { 261 | NotEmpty(a.t, object, msgAndArgs...) 262 | } 263 | 264 | // NotEqual asserts that the specified values are NOT equal. 265 | // 266 | // a.NotEqual(obj1, obj2, "two objects shouldn't be equal") 267 | // 268 | // Returns whether the assertion was successful (true) or not (false). 269 | // 270 | // Pointer variable equality is determined based on the equality of the 271 | // referenced values (as opposed to the memory addresses). 272 | func (a *Assertions) NotEqual(expected interface{}, actual interface{}, msgAndArgs ...interface{}) { 273 | NotEqual(a.t, expected, actual, msgAndArgs...) 274 | } 275 | 276 | // NotNil asserts that the specified object is not nil. 277 | // 278 | // a.NotNil(err, "err should be something") 279 | // 280 | // Returns whether the assertion was successful (true) or not (false). 281 | func (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{}) { 282 | NotNil(a.t, object, msgAndArgs...) 283 | } 284 | 285 | // NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic. 286 | // 287 | // a.NotPanics(func(){ 288 | // RemainCalm() 289 | // }, "Calling RemainCalm() should NOT panic") 290 | // 291 | // Returns whether the assertion was successful (true) or not (false). 292 | func (a *Assertions) NotPanics(f assert.PanicTestFunc, msgAndArgs ...interface{}) { 293 | NotPanics(a.t, f, msgAndArgs...) 294 | } 295 | 296 | // NotRegexp asserts that a specified regexp does not match a string. 297 | // 298 | // a.NotRegexp(regexp.MustCompile("starts"), "it's starting") 299 | // a.NotRegexp("^start", "it's not starting") 300 | // 301 | // Returns whether the assertion was successful (true) or not (false). 302 | func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) { 303 | NotRegexp(a.t, rx, str, msgAndArgs...) 304 | } 305 | 306 | // NotZero asserts that i is not the zero value for its type and returns the truth. 307 | func (a *Assertions) NotZero(i interface{}, msgAndArgs ...interface{}) { 308 | NotZero(a.t, i, msgAndArgs...) 309 | } 310 | 311 | // Panics asserts that the code inside the specified PanicTestFunc panics. 312 | // 313 | // a.Panics(func(){ 314 | // GoCrazy() 315 | // }, "Calling GoCrazy() should panic") 316 | // 317 | // Returns whether the assertion was successful (true) or not (false). 318 | func (a *Assertions) Panics(f assert.PanicTestFunc, msgAndArgs ...interface{}) { 319 | Panics(a.t, f, msgAndArgs...) 320 | } 321 | 322 | // Regexp asserts that a specified regexp matches a string. 323 | // 324 | // a.Regexp(regexp.MustCompile("start"), "it's starting") 325 | // a.Regexp("start...$", "it's not starting") 326 | // 327 | // Returns whether the assertion was successful (true) or not (false). 328 | func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) { 329 | Regexp(a.t, rx, str, msgAndArgs...) 330 | } 331 | 332 | // True asserts that the specified value is true. 333 | // 334 | // a.True(myBool, "myBool should be true") 335 | // 336 | // Returns whether the assertion was successful (true) or not (false). 337 | func (a *Assertions) True(value bool, msgAndArgs ...interface{}) { 338 | True(a.t, value, msgAndArgs...) 339 | } 340 | 341 | // WithinDuration asserts that the two times are within duration delta of each other. 342 | // 343 | // a.WithinDuration(time.Now(), time.Now(), 10*time.Second, "The difference should not be more than 10s") 344 | // 345 | // Returns whether the assertion was successful (true) or not (false). 346 | func (a *Assertions) WithinDuration(expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) { 347 | WithinDuration(a.t, expected, actual, delta, msgAndArgs...) 348 | } 349 | 350 | // Zero asserts that i is the zero value for its type and returns the truth. 351 | func (a *Assertions) Zero(i interface{}, msgAndArgs ...interface{}) { 352 | Zero(a.t, i, msgAndArgs...) 353 | } 354 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/require/require_forward.go.tmpl: -------------------------------------------------------------------------------- 1 | {{.CommentWithoutT "a"}} 2 | func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) { 3 | {{.DocInfo.Name}}(a.t, {{.ForwardedParams}}) 4 | } 5 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/require/requirements.go: -------------------------------------------------------------------------------- 1 | package require 2 | 3 | // TestingT is an interface wrapper around *testing.T 4 | type TestingT interface { 5 | Errorf(format string, args ...interface{}) 6 | FailNow() 7 | } 8 | 9 | //go:generate go run ../_codegen/main.go -output-package=require -template=require.go.tmpl 10 | -------------------------------------------------------------------------------- /vendor/vendor.json: -------------------------------------------------------------------------------- 1 | { 2 | "comment": "", 3 | "ignore": "test", 4 | "package": [ 5 | { 6 | "checksumSHA1": "OFu4xJEIjiI8Suu+j/gabfp+y6Q=", 7 | "origin": "github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/spew", 8 | "path": "github.com/davecgh/go-spew/spew", 9 | "revision": "4d4bfba8f1d1027c4fdbe371823030df51419987", 10 | "revisionTime": "2017-01-30T11:31:45Z" 11 | }, 12 | { 13 | "checksumSHA1": "Y3U6on66N0BszKXYvb2Q+qpG6f4=", 14 | "path": "github.com/julienschmidt/httprouter", 15 | "revision": "8a45e95fc75cb77048068a62daed98cc22fdac7c", 16 | "revisionTime": "2017-01-04T18:58:16Z" 17 | }, 18 | { 19 | "checksumSHA1": "JQG/9gSl4PjB+gde5cRTKimE4qE=", 20 | "path": "github.com/lib/pq", 21 | "revision": "e4af84aab01e159ca479940dbde304519e8e8811", 22 | "revisionTime": "2017-03-09T16:49:12Z" 23 | }, 24 | { 25 | "checksumSHA1": "Gk3jTNQ5uGDUE0WMJFWcYz9PMps=", 26 | "path": "github.com/lib/pq/oid", 27 | "revision": "e4af84aab01e159ca479940dbde304519e8e8811", 28 | "revisionTime": "2017-03-09T16:49:12Z" 29 | }, 30 | { 31 | "checksumSHA1": "TQVUJKDIG3XUeRoHwjIHHKKc6ng=", 32 | "path": "github.com/mattes/migrate/driver", 33 | "revision": "305a63a4472b883b8af8e0d71132e98d83a69e4d", 34 | "revisionTime": "2017-03-02T21:39:55Z" 35 | }, 36 | { 37 | "checksumSHA1": "+nObsJCowmMDcsKLmjBA4P7kWf4=", 38 | "path": "github.com/mattes/migrate/driver/postgres", 39 | "revision": "305a63a4472b883b8af8e0d71132e98d83a69e4d", 40 | "revisionTime": "2017-03-02T21:39:55Z" 41 | }, 42 | { 43 | "checksumSHA1": "HN+eI9IMaO9vQA37gCo87l/1F+A=", 44 | "path": "github.com/mattes/migrate/file", 45 | "revision": "305a63a4472b883b8af8e0d71132e98d83a69e4d", 46 | "revisionTime": "2017-03-02T21:39:55Z" 47 | }, 48 | { 49 | "checksumSHA1": "BPqvXY8XCn7cIUZaW+mgbzHreHg=", 50 | "path": "github.com/mattes/migrate/migrate", 51 | "revision": "305a63a4472b883b8af8e0d71132e98d83a69e4d", 52 | "revisionTime": "2017-03-02T21:39:55Z" 53 | }, 54 | { 55 | "checksumSHA1": "bIOgGoax/uGQnXHQPb+O6jC/42A=", 56 | "path": "github.com/mattes/migrate/migrate/direction", 57 | "revision": "305a63a4472b883b8af8e0d71132e98d83a69e4d", 58 | "revisionTime": "2017-03-02T21:39:55Z" 59 | }, 60 | { 61 | "checksumSHA1": "yCWDml36DkeshgojaiAktWBt+ZQ=", 62 | "path": "github.com/mattes/migrate/pipe", 63 | "revision": "305a63a4472b883b8af8e0d71132e98d83a69e4d", 64 | "revisionTime": "2017-03-02T21:39:55Z" 65 | }, 66 | { 67 | "checksumSHA1": "zKKp5SZ3d3ycKe4EKMNT0BqAWBw=", 68 | "origin": "github.com/stretchr/testify/vendor/github.com/pmezard/go-difflib/difflib", 69 | "path": "github.com/pmezard/go-difflib/difflib", 70 | "revision": "4d4bfba8f1d1027c4fdbe371823030df51419987", 71 | "revisionTime": "2017-01-30T11:31:45Z" 72 | }, 73 | { 74 | "checksumSHA1": "JXUVA1jky8ZX8w09p2t5KLs97Nc=", 75 | "path": "github.com/stretchr/testify/assert", 76 | "revision": "4d4bfba8f1d1027c4fdbe371823030df51419987", 77 | "revisionTime": "2017-01-30T11:31:45Z" 78 | }, 79 | { 80 | "checksumSHA1": "2PpOCNkWnshDrXeCVH2kp3VHhIM=", 81 | "path": "github.com/stretchr/testify/require", 82 | "revision": "4d4bfba8f1d1027c4fdbe371823030df51419987", 83 | "revisionTime": "2017-01-30T11:31:45Z" 84 | } 85 | ], 86 | "rootPath": "github.com/circleci/cci-demo-docker" 87 | } 88 | --------------------------------------------------------------------------------