├── .gitignore ├── Makefile ├── README.md ├── VERSION ├── conf └── conf.go ├── datastore ├── context.go ├── database │ ├── database.go │ ├── person.go │ └── util.go ├── datastore.go ├── migrate │ ├── migrate.go │ └── version.go └── person.go ├── handler ├── api │ └── person.go ├── context.go └── frontend │ ├── layouts │ ├── .gitignore │ └── base.tmpl │ ├── person.go │ ├── templates │ ├── .gitignore │ ├── index.tmpl │ ├── person_list.tmpl │ └── person_show.tmpl │ └── util.go ├── main.go ├── middleware ├── header.go ├── json.go ├── log.go ├── options.go ├── recover.go ├── request_id.go └── writer_proxy.go ├── model └── person.go ├── rename.sh ├── router └── router.go ├── static ├── .gitignore └── robots.txt └── vendor ├── github.com ├── BurntSushi │ └── migration │ │ ├── Makefile │ │ ├── README.md │ │ ├── UNLICENSE │ │ ├── doc.go │ │ ├── migration.go │ │ └── session.vim ├── codegangsta │ └── negroni │ │ ├── LICENSE │ │ ├── README.md │ │ ├── doc.go │ │ ├── logger.go │ │ ├── logger_test.go │ │ ├── negroni.go │ │ ├── negroni_test.go │ │ ├── recovery.go │ │ ├── recovery_test.go │ │ ├── response_writer.go │ │ ├── response_writer_test.go │ │ ├── static.go │ │ ├── static_test.go │ │ └── translations │ │ └── README_pt_br.md ├── comail │ └── colog │ │ ├── LICENSE │ │ ├── README.md │ │ ├── colog.go │ │ ├── colog_bench_test.go │ │ ├── colog_test.go │ │ ├── interfaces.go │ │ ├── json_formatter.go │ │ ├── json_formatter_test.go │ │ ├── std_extractor.go │ │ ├── std_extractor_test.go │ │ ├── std_formatter.go │ │ ├── std_formatter_test.go │ │ ├── tty.go │ │ ├── tty_bsd.go │ │ ├── tty_linux.go │ │ └── tty_windows.go ├── go-sql-driver │ └── mysql │ │ ├── AUTHORS │ │ ├── CHANGELOG.md │ │ ├── CONTRIBUTING.md │ │ ├── ISSUE_TEMPLATE.md │ │ ├── LICENSE │ │ ├── PULL_REQUEST_TEMPLATE.md │ │ ├── README.md │ │ ├── appengine.go │ │ ├── benchmark_test.go │ │ ├── buffer.go │ │ ├── collations.go │ │ ├── connection.go │ │ ├── const.go │ │ ├── driver.go │ │ ├── driver_test.go │ │ ├── dsn.go │ │ ├── dsn_test.go │ │ ├── errors.go │ │ ├── errors_test.go │ │ ├── infile.go │ │ ├── packets.go │ │ ├── result.go │ │ ├── rows.go │ │ ├── statement.go │ │ ├── transaction.go │ │ ├── utils.go │ │ └── utils_test.go ├── goji │ └── context │ │ ├── README.md │ │ ├── bridge.go │ │ ├── context.go │ │ └── middleware.go ├── jmoiron │ └── sqlx │ │ ├── LICENSE │ │ ├── README.md │ │ ├── bind.go │ │ ├── doc.go │ │ ├── named.go │ │ ├── named_test.go │ │ ├── reflectx │ │ ├── README.md │ │ ├── reflect.go │ │ └── reflect_test.go │ │ ├── sqlx.go │ │ ├── sqlx_test.go │ │ └── types │ │ ├── README.md │ │ ├── types.go │ │ └── types_test.go ├── lib │ └── pq │ │ ├── CONTRIBUTING.md │ │ ├── LICENSE.md │ │ ├── README.md │ │ ├── bench_test.go │ │ ├── buf.go │ │ ├── certs │ │ ├── README │ │ ├── postgresql.crt │ │ ├── postgresql.key │ │ ├── root.crt │ │ ├── server.crt │ │ └── server.key │ │ ├── conn.go │ │ ├── conn_test.go │ │ ├── copy.go │ │ ├── copy_test.go │ │ ├── doc.go │ │ ├── encode.go │ │ ├── encode_test.go │ │ ├── error.go │ │ ├── hstore │ │ ├── hstore.go │ │ └── hstore_test.go │ │ ├── listen_example │ │ └── doc.go │ │ ├── notify.go │ │ ├── notify_test.go │ │ ├── oid │ │ ├── doc.go │ │ ├── gen.go │ │ └── types.go │ │ ├── ssl_test.go │ │ ├── url.go │ │ ├── url_test.go │ │ ├── user_posix.go │ │ └── user_windows.go ├── mattn │ └── go-sqlite3 │ │ ├── LICENSE │ │ ├── README.md │ │ ├── _example │ │ ├── custom_func │ │ │ └── main.go │ │ ├── hook │ │ │ └── hook.go │ │ ├── mod_regexp │ │ │ ├── Makefile │ │ │ ├── extension.go │ │ │ └── sqlite3_mod_regexp.c │ │ ├── mod_vtable │ │ │ ├── Makefile │ │ │ ├── extension.go │ │ │ ├── picojson.h │ │ │ └── sqlite3_mod_vtable.cc │ │ └── simple │ │ │ └── simple.go │ │ ├── backup.go │ │ ├── callback.go │ │ ├── callback_test.go │ │ ├── code │ │ ├── sqlite3-binding.c │ │ ├── sqlite3-binding.h │ │ └── sqlite3ext.h │ │ ├── doc.go │ │ ├── error.go │ │ ├── error_test.go │ │ ├── sqlite3-binding.c │ │ ├── sqlite3-binding.h │ │ ├── sqlite3.go │ │ ├── sqlite3_fts3_test.go │ │ ├── sqlite3_icu.go │ │ ├── sqlite3_json1.go │ │ ├── sqlite3_libsqlite3.go │ │ ├── sqlite3_load_extension.go │ │ ├── sqlite3_omit_load_extension.go │ │ ├── sqlite3_other.go │ │ ├── sqlite3_test.go │ │ ├── sqlite3_test │ │ └── sqltest.go │ │ └── sqlite3_windows.go ├── oxtoacart │ └── bpool │ │ ├── LICENSE │ │ ├── README.md │ │ ├── bpool.go │ │ ├── bufferpool.go │ │ ├── bufferpool_test.go │ │ ├── bytepool.go │ │ ├── bytepool_test.go │ │ ├── sizedbufferpool.go │ │ └── sizedbufferpool_test.go └── tylerb │ └── graceful │ ├── LICENSE │ ├── README.md │ ├── graceful.go │ ├── graceful_test.go │ └── tests │ └── main.go ├── goji.io ├── LICENSE ├── README.md ├── dispatch.go ├── dispatch_test.go ├── goji.go ├── goji_test.go ├── handle.go ├── handle_test.go ├── internal │ ├── context.go │ ├── http.go │ ├── http_test.go │ └── internal.go ├── middleware.go ├── middleware │ ├── middleware.go │ └── middleware_test.go ├── middleware_test.go ├── mux.go ├── mux_test.go ├── pat │ ├── match.go │ ├── match_test.go │ ├── methods.go │ ├── methods_test.go │ ├── pat.go │ ├── pat_test.go │ ├── url.go │ └── url_test.go ├── pattern.go ├── pattern │ ├── pattern.go │ └── pattern_test.go ├── router.go ├── router_simple.go ├── router_test.go ├── router_trie.go └── util_test.go ├── golang.org └── x │ └── net │ ├── context │ ├── context.go │ ├── context_test.go │ ├── ctxhttp │ │ ├── cancelreq.go │ │ ├── cancelreq_go14.go │ │ ├── ctxhttp.go │ │ └── ctxhttp_test.go │ └── withtimeout_test.go │ └── netutil │ ├── listen.go │ └── listen_test.go └── manifest /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | *.test 24 | *.prof 25 | 26 | # Database 27 | *.db 28 | 29 | # OS X stuff 30 | .DS_Store 31 | ._* 32 | 33 | # Final binary 34 | /skeleton 35 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Configuration 2 | NAME := skeleton 3 | IMPORT := github.com/andrew-d/go-webapp-skeleton 4 | RELEASE ?= false 5 | 6 | # Computed variables 7 | SHA := $(shell git rev-parse --short HEAD) 8 | VERSION := $(shell cat VERSION) 9 | BUILD_VARS := \ 10 | -X $(IMPORT)/conf.Revision=$(SHA) \ 11 | -X $(IMPORT)/conf.Version=$(VERSION) \ 12 | -X $(IMPORT)/conf.ProjectName=$(NAME) 13 | 14 | ifeq ($(RELEASE),true) 15 | BINDATA_FLAGS := 16 | else 17 | BINDATA_FLAGS := -debug 18 | endif 19 | 20 | # Lists of files 21 | LAYOUT_FILES := $(shell find handler/frontend/layouts -type f -name '*.tmpl') 22 | TEMPLATE_FILES := $(shell find handler/frontend/templates -type f -name '*.tmpl') 23 | STATIC_FILES := $(shell find static -type f | grep -v '.gitignore$$' | grep -v 'bindata.go$$') 24 | 25 | # Targets 26 | all: build 27 | 28 | .PHONY: check-deps 29 | check-deps: bindata-exists 30 | 31 | .PHONY: bindata-exists 32 | bindata-exists: 33 | @which go-bindata >/dev/null 34 | 35 | .PHONY: build 36 | build: check-deps static/bindata.go handler/frontend/layouts/bindata.go handler/frontend/templates/bindata.go 37 | env GO15VENDOREXPERIMENT=1 go build \ 38 | -o $(NAME) \ 39 | -v \ 40 | -ldflags "$(BUILD_VARS)" \ 41 | . 42 | 43 | static/bindata.go: $(STATIC_FILES) 44 | go-bindata \ 45 | $(BINDATA_FLAGS) \ 46 | -ignore='(\.gitignore$$|\.map$$|bindata\.go$$)' \ 47 | -prefix=$(dir $@) \ 48 | -pkg=static \ 49 | -o $@ \ 50 | $(dir $@) 51 | 52 | handler/frontend/layouts/bindata.go: $(LAYOUT_FILES) 53 | go-bindata \ 54 | $(BINDATA_FLAGS) \ 55 | -ignore='(\.gitignore$$|\.go$$)' \ 56 | -prefix=$(dir $@) \ 57 | -pkg=layouts \ 58 | -o $@ \ 59 | $(dir $@) 60 | 61 | handler/frontend/templates/bindata.go: $(TEMPLATE_FILES) 62 | go-bindata \ 63 | $(BINDATA_FLAGS) \ 64 | -ignore='(\.gitignore$$|\.go$$)' \ 65 | -prefix=$(dir $@) \ 66 | -pkg=templates \ 67 | -o $@ \ 68 | $(dir $@) 69 | 70 | .PHONY: clean 71 | clean: 72 | $(RM) \ 73 | ./$(NAME) \ 74 | static/bindata.go \ 75 | handler/frontend/layouts/bindata.go \ 76 | handler/frontend/templates/bindata.go 77 | 78 | .PHONY: env 79 | env: 80 | @echo "STATIC_FILES = $(STATIC_FILES)" 81 | @echo "LAYOUT_FILES = $(LAYOUT_FILES)" 82 | @echo "TEMPLATE_FILES = $(TEMPLATE_FILES)" 83 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # go-webapp-skeleton 2 | 3 | This repo contains a skeleton of a Go webapp. It has some useful features, 4 | mostly cribbed from other, similar projects around the Internet: 5 | 6 | - [Automatic migration handling][migrate] 7 | - [Embedded static files][efiles] and [templates][etmpls], including 8 | [layout support][elayouts]. 9 | - [Graceful shutdown support][graceful] 10 | - Robust logging 11 | 12 | All tied together with a useful set of tooling. See below for more information. 13 | 14 | 15 | ## Usage 16 | 17 | 1. Clone this repository into your project's location: 18 | `git clone https://github.com/andrew-d/go-webapp-skeleton.git $GOPATH/github.com/your-user/your-project` 19 | 1. Run the `rename.sh` script in order to rename this project and point it at 20 | the new import path. 21 | 1. Type `make clean all` in order to clean the project and rebuild it. 22 | *Note*: you need [`go-bindata`][bindata] installed and in your `$PATH` in 23 | order for the build to complete. 24 | 25 | 26 | ## Tooling 27 | 28 | This project uses [gvt][gvt] in order to manage dependencies. It comes with 29 | all the dependencies already vendored as part of the repository. In order to 30 | update a given dependency, you can run `gvt update path/to/dep`. 31 | 32 | 33 | ## Organization 34 | 35 | **Note**: somewhat of a work in progress 36 | 37 | - The base of the project can be found in the `main.go` file, which imports 38 | most of the other packages and kicks everything off. You probably won't need 39 | to modify this as much. 40 | - The `model` directory contains database models. These models should not 41 | interact directly with the database. 42 | - The `datastore` directory is responsible for mapping the models to the 43 | database in use. It defines interfaces which provide the interface to 44 | interact with the underlying, concrete, datastore. 45 | - The `datastore/database` directory contains the actual code that is 46 | responsible for interacting with the underlying database. 47 | - The `datastore/migrate` directory contains the SQL code for migrations 48 | performed by the app upon startup. 49 | - The `handler` directory contains useful functions that are generic between 50 | API and frontend routes. 51 | - The `handler/api` directory contains the API route handler functions. 52 | - The `handler/frontend` directory contains the frontend route handler 53 | functions. 54 | - The `router` directory contains the main router, which registers each of the 55 | handler functions on their respective routes. 56 | 57 | 58 | 59 | 60 | [migrate]: https://github.com/andrew-d/go-webapp-skeleton/blob/master/datastore/migrate/migrate.go 61 | [efiles]: https://github.com/andrew-d/go-webapp-skeleton/tree/master/static 62 | [etmpls]: https://github.com/andrew-d/go-webapp-skeleton/tree/master/handler/frontend/templates 63 | [elayouts]: https://github.com/andrew-d/go-webapp-skeleton/tree/master/handler/frontend/layouts 64 | [graceful]: https://github.com/andrew-d/go-webapp-skeleton/blob/master/main.go#L113 65 | [bindata]: https://github.com/jteeuwen/go-bindata 66 | [gvt]: https://github.com/FiloSottile/gvt 67 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 0.0.1-dev 2 | -------------------------------------------------------------------------------- /conf/conf.go: -------------------------------------------------------------------------------- 1 | package conf 2 | 3 | import ( 4 | "crypto/rand" 5 | "encoding/hex" 6 | "encoding/json" 7 | "fmt" 8 | "log" 9 | "os" 10 | "path/filepath" 11 | "strings" 12 | 13 | "github.com/comail/colog" 14 | ) 15 | 16 | var ( 17 | // Name of the project 18 | ProjectName string 19 | 20 | // Commit SHA and version for the current build, set by the 21 | // compile process. 22 | Version string 23 | Revision string 24 | ) 25 | 26 | type Config struct { 27 | // Current environment (e.g. 'production', 'debug'). This is set from 28 | // an environment variable. 29 | Environment string `json:"-"` 30 | 31 | // Web configuration 32 | Host string `json:"host"` 33 | Port uint16 `json:"port"` 34 | SessionSecret string `json:"session_secret"` 35 | 36 | // DB configuration 37 | DbType string `json:"dbtype"` 38 | DbConn string `json:"dbconn"` 39 | } 40 | 41 | func (c *Config) HostString() string { 42 | return fmt.Sprintf("%s:%d", c.Host, c.Port) 43 | } 44 | 45 | func (c *Config) IsDebug() bool { 46 | return c.Environment == "debug" 47 | } 48 | 49 | func (c *Config) IsProduction() bool { 50 | return c.Environment == "production" || c.Environment == "prod" 51 | } 52 | 53 | var ( 54 | ConfigPath = filepath.Join(".", "config.json") 55 | configPathGiven bool 56 | 57 | C = &Config{} 58 | ) 59 | 60 | func init() { 61 | if ProjectName == "" { 62 | panic("no project name set - did you use the Makefile to build?") 63 | } 64 | 65 | // Set defaults 66 | C.Environment = "debug" 67 | C.Host = "localhost" 68 | C.Port = 3001 69 | C.DbType = "sqlite3" 70 | C.DbConn = ":memory:" 71 | 72 | // Load the environment 73 | C.Environment = os.Getenv("ENVIRONMENT") 74 | 75 | // Register colog to handle the standard logger output 76 | colog.Register() 77 | colog.SetFlags(0) 78 | colog.ParseFields(true) 79 | 80 | // Set up logger 81 | if C.IsDebug() { 82 | colog.SetMinLevel(colog.LDebug) 83 | } else { 84 | colog.SetMinLevel(colog.LInfo) 85 | colog.SetFormatter(&colog.JSONFormatter{}) 86 | } 87 | 88 | // Generate a random session secret. 89 | buf := make([]byte, 20) 90 | if _, err := rand.Read(buf); err != nil { 91 | log.Printf("error: could not generate random secret: %s\n", err) 92 | os.Exit(1) 93 | return 94 | } 95 | C.SessionSecret = hex.EncodeToString(buf) 96 | 97 | // Let the user override the config file path. 98 | if cpath := os.Getenv(strings.ToUpper(ProjectName) + "_CONFIG_PATH"); cpath != "" { 99 | ConfigPath = cpath 100 | configPathGiven = true 101 | } 102 | 103 | // Read the configuration file, if present. 104 | f, err := os.Open(ConfigPath) 105 | if err != nil { 106 | // We don't print an error if the user did not give a config path, and 107 | // the default config file does not exist. 108 | if !configPathGiven && os.IsNotExist(err) { 109 | // Do nothing 110 | } else { 111 | log.Printf("error: could not read configuration file `%s`: %s\n", ConfigPath, err) 112 | } 113 | return 114 | } 115 | defer f.Close() 116 | 117 | if err := json.NewDecoder(f).Decode(C); err != nil { 118 | log.Printf("error: could not decode configuration file: %s\n", err) 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /datastore/context.go: -------------------------------------------------------------------------------- 1 | package datastore 2 | 3 | import ( 4 | "golang.org/x/net/context" 5 | ) 6 | 7 | type private struct{} 8 | 9 | var contextKey private 10 | 11 | func NewContext(parent context.Context, ds Datastore) context.Context { 12 | return context.WithValue(parent, contextKey, ds) 13 | } 14 | 15 | func FromContext(c context.Context) Datastore { 16 | return c.Value(contextKey).(Datastore) 17 | } 18 | -------------------------------------------------------------------------------- /datastore/database/database.go: -------------------------------------------------------------------------------- 1 | package database 2 | 3 | import ( 4 | "github.com/BurntSushi/migration" 5 | "github.com/jmoiron/sqlx" 6 | 7 | "github.com/andrew-d/go-webapp-skeleton/datastore" 8 | "github.com/andrew-d/go-webapp-skeleton/datastore/migrate" 9 | 10 | _ "github.com/go-sql-driver/mysql" 11 | _ "github.com/lib/pq" 12 | _ "github.com/mattn/go-sqlite3" 13 | ) 14 | 15 | func Connect(driver, conn string) (*sqlx.DB, error) { 16 | migrator := migrate.Migrator{driver} 17 | 18 | migration.DefaultGetVersion = migrator.GetVersion 19 | migration.DefaultSetVersion = migrator.SetVersion 20 | 21 | migrations := []migration.Migrator{ 22 | migrator.Setup, 23 | migrator.CreateDefaultPerson, 24 | } 25 | 26 | db, err := migration.Open(driver, conn, migrations) 27 | if err != nil { 28 | return nil, err 29 | } 30 | 31 | if err := db.Ping(); err != nil { 32 | return nil, err 33 | } 34 | 35 | return sqlx.NewDb(db, driver), nil 36 | } 37 | 38 | func MustConnect(driver, conn string) *sqlx.DB { 39 | db, err := Connect(driver, conn) 40 | if err != nil { 41 | panic(err) 42 | } 43 | return db 44 | } 45 | 46 | func NewDatastore(db *sqlx.DB) datastore.Datastore { 47 | return struct { 48 | *PeopleStore 49 | }{ 50 | NewPeopleStore(db), 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /datastore/database/person.go: -------------------------------------------------------------------------------- 1 | package database 2 | 3 | import ( 4 | "github.com/jmoiron/sqlx" 5 | 6 | "github.com/andrew-d/go-webapp-skeleton/model" 7 | ) 8 | 9 | type PeopleStore struct { 10 | db *sqlx.DB 11 | } 12 | 13 | func NewPeopleStore(db *sqlx.DB) *PeopleStore { 14 | return &PeopleStore{db} 15 | } 16 | 17 | func (s *PeopleStore) ListPeople(limit, offset int) ([]*model.Person, error) { 18 | people := []*model.Person{} 19 | err := s.db.Select(&people, s.db.Rebind(personListQuery), limit, offset) 20 | return people, err 21 | } 22 | 23 | func (s *PeopleStore) GetPerson(id int64) (*model.Person, error) { 24 | person := &model.Person{} 25 | err := s.db.Get(person, s.db.Rebind(personGetQuery), id) 26 | return person, err 27 | } 28 | 29 | func (s *PeopleStore) CreatePerson(person *model.Person) error { 30 | ret, err := s.db.Exec(RebindInsert(s.db, personInsertQuery), person.Name) 31 | if err != nil { 32 | return err 33 | } 34 | 35 | person.ID, _ = ret.LastInsertId() 36 | return nil 37 | } 38 | 39 | func (s *PeopleStore) DeletePerson(id int64) (err error) { 40 | var tx *sqlx.Tx 41 | 42 | tx, err = s.db.Beginx() 43 | if err != nil { 44 | return 45 | } 46 | 47 | // Automatically rollback/commit if there's an error. 48 | defer func() { 49 | if err != nil { 50 | tx.Rollback() 51 | } else { 52 | tx.Commit() 53 | } 54 | }() 55 | 56 | // Remove the given Person 57 | if _, err = tx.Exec(s.db.Rebind(personDeleteQuery), id); err != nil { 58 | return 59 | } 60 | 61 | // Done! 62 | return nil 63 | } 64 | 65 | const personListQuery = ` 66 | SELECT * 67 | FROM people 68 | ORDER BY id DESC 69 | LIMIT ? OFFSET ? 70 | ` 71 | 72 | const personGetQuery = ` 73 | SELECT * 74 | FROM people 75 | WHERE id = ? 76 | ` 77 | 78 | const personInsertQuery = ` 79 | INSERT 80 | INTO people ( 81 | name 82 | ) 83 | VALUES (?) 84 | ` 85 | 86 | const personDeleteQuery = ` 87 | DELETE 88 | FROM people 89 | WHERE id = ? 90 | ` 91 | -------------------------------------------------------------------------------- /datastore/database/util.go: -------------------------------------------------------------------------------- 1 | package database 2 | 3 | import ( 4 | "strings" 5 | 6 | "github.com/jmoiron/sqlx" 7 | ) 8 | 9 | func RebindInsert(db *sqlx.DB, q string) string { 10 | q = db.Rebind(q) 11 | q = strings.TrimRight(q, " \t\n;") 12 | if db.DriverName() == "postgres" { 13 | q = q + " RETURNING id" 14 | } 15 | 16 | return q 17 | } 18 | -------------------------------------------------------------------------------- /datastore/datastore.go: -------------------------------------------------------------------------------- 1 | package datastore 2 | 3 | type Datastore interface { 4 | PeopleStore 5 | } 6 | -------------------------------------------------------------------------------- /datastore/migrate/migrate.go: -------------------------------------------------------------------------------- 1 | package migrate 2 | 3 | import ( 4 | "github.com/BurntSushi/migration" 5 | "github.com/jmoiron/sqlx" 6 | ) 7 | 8 | type Migrator struct { 9 | DbType string 10 | } 11 | 12 | func (m Migrator) rebind(s string) string { 13 | return sqlx.Rebind(sqlx.BindType(m.DbType), s) 14 | } 15 | 16 | // Setup will create all necessary tables and indexes in the database. 17 | func (m Migrator) Setup(tx migration.LimitedTx) error { 18 | stmts := []string{ 19 | peopleTable, 20 | } 21 | 22 | for _, stmt := range stmts { 23 | if _, err := tx.Exec(stmt); err != nil { 24 | return err 25 | } 26 | } 27 | 28 | return nil 29 | } 30 | 31 | // CreateDefaultPerson will insert a default (empty) list into the database. 32 | func (m Migrator) CreateDefaultPerson(tx migration.LimitedTx) error { 33 | _, err := tx.Exec(createDefaultPerson) 34 | return err 35 | } 36 | 37 | const peopleTable = ` 38 | CREATE TABLE IF NOT EXISTS people ( 39 | id INTEGER PRIMARY KEY AUTOINCREMENT 40 | ,name TEXT NOT NULL 41 | ) 42 | ` 43 | 44 | const createDefaultPerson = ` 45 | INSERT INTO people(name) 46 | VALUES ("Joe Smith") 47 | ` 48 | -------------------------------------------------------------------------------- /datastore/migrate/version.go: -------------------------------------------------------------------------------- 1 | package migrate 2 | 3 | import ( 4 | "github.com/BurntSushi/migration" 5 | ) 6 | 7 | // GetVersion gets the migration version from the database, creating the 8 | // migration table if it does not already exist. 9 | func (m Migrator) GetVersion(tx migration.LimitedTx) (int, error) { 10 | v, err := m.getVersion(tx) 11 | if err != nil { 12 | if err := m.createVersionTable(tx); err != nil { 13 | return 0, err 14 | } 15 | return m.getVersion(tx) 16 | } 17 | return v, nil 18 | } 19 | 20 | // SetVersion sets the migration version in the database, creating the 21 | // migration table if it does not already exist. 22 | func (m Migrator) SetVersion(tx migration.LimitedTx, version int) error { 23 | if err := m.setVersion(tx, version); err != nil { 24 | if err := m.createVersionTable(tx); err != nil { 25 | return err 26 | } 27 | return m.setVersion(tx, version) 28 | } 29 | return nil 30 | } 31 | 32 | // setVersion updates the migration version in the database. 33 | func (m Migrator) setVersion(tx migration.LimitedTx, version int) error { 34 | _, err := tx.Exec(m.rebind("UPDATE migration_version SET version = ?"), version) 35 | return err 36 | } 37 | 38 | // getVersion gets the migration version in the database. 39 | func (m Migrator) getVersion(tx migration.LimitedTx) (int, error) { 40 | var version int 41 | row := tx.QueryRow("SELECT version FROM migration_version") 42 | if err := row.Scan(&version); err != nil { 43 | return 0, err 44 | } 45 | return version, nil 46 | } 47 | 48 | // createVersionTable creates the version table and inserts the initial 49 | // value (0) into the database. 50 | func (m Migrator) createVersionTable(tx migration.LimitedTx) error { 51 | _, err := tx.Exec("CREATE TABLE migration_version ( version INTEGER )") 52 | if err != nil { 53 | return err 54 | } 55 | _, err = tx.Exec("INSERT INTO migration_version (version) VALUES (0)") 56 | return err 57 | } 58 | -------------------------------------------------------------------------------- /datastore/person.go: -------------------------------------------------------------------------------- 1 | package datastore 2 | 3 | import ( 4 | "golang.org/x/net/context" 5 | 6 | "github.com/andrew-d/go-webapp-skeleton/model" 7 | ) 8 | 9 | type PeopleStore interface { 10 | // ListPeople retrieves all people from the database, possibly with an 11 | // offset or limit provided. 12 | ListPeople(limit, offset int) ([]*model.Person, error) 13 | 14 | // GetPerson retrieves a person from the datastore for the given ID. 15 | GetPerson(id int64) (*model.Person, error) 16 | 17 | // CreatePerson saves a new person in the datastore. 18 | CreatePerson(person *model.Person) error 19 | 20 | // DeletePerson removes a person from the datastore. 21 | DeletePerson(id int64) error 22 | } 23 | 24 | func ListPeople(c context.Context, limit, offset int) ([]*model.Person, error) { 25 | return FromContext(c).ListPeople(limit, offset) 26 | } 27 | 28 | func GetPerson(c context.Context, id int64) (*model.Person, error) { 29 | return FromContext(c).GetPerson(id) 30 | } 31 | 32 | func CreatePerson(c context.Context, person *model.Person) error { 33 | return FromContext(c).CreatePerson(person) 34 | } 35 | 36 | func DeletePerson(c context.Context, id int64) error { 37 | return FromContext(c).DeletePerson(id) 38 | } 39 | -------------------------------------------------------------------------------- /handler/api/person.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "encoding/json" 5 | "log" 6 | "net/http" 7 | "strconv" 8 | 9 | "goji.io/pat" 10 | "golang.org/x/net/context" 11 | 12 | "github.com/andrew-d/go-webapp-skeleton/datastore" 13 | "github.com/andrew-d/go-webapp-skeleton/handler" 14 | "github.com/andrew-d/go-webapp-skeleton/model" 15 | ) 16 | 17 | // ListPeople accepts a request to retrieve a list of people. 18 | // 19 | // GET /api/people 20 | // 21 | func ListPeople(ctx context.Context, w http.ResponseWriter, r *http.Request) { 22 | var ( 23 | limit = handler.ToLimit(r) 24 | offset = handler.ToOffset(r) 25 | ) 26 | 27 | people, err := datastore.ListPeople(ctx, limit, offset) 28 | if err != nil { 29 | log.Printf("error: error listing people err=%q", err) 30 | w.WriteHeader(http.StatusNotFound) 31 | return 32 | } 33 | 34 | json.NewEncoder(w).Encode(people) 35 | } 36 | 37 | // GetPerson accepts a request to retrieve information about a particular person. 38 | // 39 | // GET /api/people/:person 40 | // 41 | func GetPerson(ctx context.Context, w http.ResponseWriter, r *http.Request) { 42 | var ( 43 | idStr = pat.Param(ctx, "person") 44 | ) 45 | 46 | id, err := strconv.ParseInt(idStr, 10, 64) 47 | if err != nil { 48 | w.WriteHeader(http.StatusBadRequest) 49 | return 50 | } 51 | 52 | person, err := datastore.GetPerson(ctx, id) 53 | if err != nil { 54 | log.Printf("error: error getting person err=%q", err) 55 | w.WriteHeader(http.StatusNotFound) 56 | return 57 | } 58 | 59 | json.NewEncoder(w).Encode(person) 60 | } 61 | 62 | // DeletePerson accepts a request to delete a person. 63 | // 64 | // DELETE /api/people/:person 65 | // 66 | func DeletePerson(ctx context.Context, w http.ResponseWriter, r *http.Request) { 67 | var ( 68 | idStr = pat.Param(ctx, "person") 69 | ) 70 | 71 | id, err := strconv.ParseInt(idStr, 10, 64) 72 | if err != nil { 73 | w.WriteHeader(http.StatusBadRequest) 74 | return 75 | } 76 | 77 | err = datastore.DeletePerson(ctx, id) 78 | if err != nil { 79 | log.Printf("error: error deleting person err=%q", err) 80 | w.WriteHeader(http.StatusNotFound) 81 | return 82 | } 83 | 84 | w.WriteHeader(http.StatusNoContent) 85 | } 86 | 87 | // CreatePerson accepts a request to add a new person. 88 | // 89 | // POST /api/people 90 | // 91 | func CreatePerson(ctx context.Context, w http.ResponseWriter, r *http.Request) { 92 | // Unmarshal the person from the payload 93 | defer r.Body.Close() 94 | in := struct { 95 | Name string `json:"name"` 96 | }{} 97 | if err := json.NewDecoder(r.Body).Decode(&in); err != nil { 98 | http.Error(w, err.Error(), http.StatusBadRequest) 99 | return 100 | } 101 | 102 | // Validate input 103 | if len(in.Name) < 1 { 104 | http.Error(w, "no name given", http.StatusBadRequest) 105 | return 106 | } 107 | 108 | // Create our 'normal' model. 109 | person := &model.Person{Name: in.Name} 110 | err := datastore.CreatePerson(ctx, person) 111 | if err != nil { 112 | http.Error(w, err.Error(), http.StatusInternalServerError) 113 | return 114 | } 115 | 116 | w.WriteHeader(http.StatusCreated) 117 | json.NewEncoder(w).Encode(person) 118 | } 119 | -------------------------------------------------------------------------------- /handler/context.go: -------------------------------------------------------------------------------- 1 | package handler 2 | 3 | import ( 4 | "net/http" 5 | "strconv" 6 | ) 7 | 8 | const ( 9 | DEFAULT_LIMIT = 20 10 | MAXIMUM_LIMIT = 100 11 | ) 12 | 13 | // ToLimit returns the Limit from the current request. 14 | // 15 | // If the limit is not present, it will be set to DEFAULT_LIMIT. Limits are 16 | // capped at MAXIMUM_LIMIT. 17 | func ToLimit(r *http.Request) int { 18 | if len(r.FormValue("limit")) == 0 { 19 | return DEFAULT_LIMIT 20 | } 21 | 22 | limit, err := strconv.Atoi(r.FormValue("limit")) 23 | if err != nil { 24 | return DEFAULT_LIMIT 25 | } 26 | 27 | if limit > MAXIMUM_LIMIT { 28 | return MAXIMUM_LIMIT 29 | } 30 | 31 | return limit 32 | } 33 | 34 | // ToOffset returns the Offset from current request 35 | // query if offset doesn't present set default offset 36 | // equal to 0 37 | func ToOffset(r *http.Request) int { 38 | if len(r.FormValue("offset")) == 0 { 39 | return 0 40 | } 41 | 42 | offset, err := strconv.Atoi(r.FormValue("offset")) 43 | if err != nil { 44 | return 0 45 | } 46 | 47 | return offset 48 | } 49 | -------------------------------------------------------------------------------- /handler/frontend/layouts/.gitignore: -------------------------------------------------------------------------------- 1 | bindata.go 2 | -------------------------------------------------------------------------------- /handler/frontend/layouts/base.tmpl: -------------------------------------------------------------------------------- 1 | {{ define "base" }} 2 | 3 | 4 | {{ template "title" . }} 5 | 6 | 7 | {{ template "content" . }} 8 | {{ template "scripts" . }} 9 | 10 | 11 | {{ end }} 12 | 13 | // We define empty blocks for optional content so we don't have to define a 14 | // block in child templates that don't need them 15 | {{ define "scripts" }}{{ end }} 16 | -------------------------------------------------------------------------------- /handler/frontend/person.go: -------------------------------------------------------------------------------- 1 | package frontend 2 | 3 | import ( 4 | "log" 5 | "net/http" 6 | "strconv" 7 | 8 | "goji.io/pat" 9 | "golang.org/x/net/context" 10 | 11 | "github.com/andrew-d/go-webapp-skeleton/datastore" 12 | "github.com/andrew-d/go-webapp-skeleton/handler" 13 | ) 14 | 15 | // ListPeople shows a list of all people 16 | // 17 | // GET /people 18 | // 19 | func ListPeople(ctx context.Context, w http.ResponseWriter, r *http.Request) { 20 | var ( 21 | limit = handler.ToLimit(r) 22 | offset = handler.ToOffset(r) 23 | ) 24 | 25 | people, err := datastore.ListPeople(ctx, limit, offset) 26 | if err != nil { 27 | log.Printf("error: error listing people err=%q", err) 28 | w.WriteHeader(http.StatusNotFound) 29 | return 30 | } 31 | 32 | renderTemplate(ctx, w, "person_list.tmpl", M{ 33 | "People": people, 34 | }) 35 | } 36 | 37 | // GetPerson accepts a request to retrieve information about a particular person. 38 | // 39 | // GET /people/:person 40 | // 41 | func GetPerson(ctx context.Context, w http.ResponseWriter, r *http.Request) { 42 | var ( 43 | idStr = pat.Param(ctx, "person") 44 | ) 45 | 46 | id, err := strconv.ParseInt(idStr, 10, 64) 47 | if err != nil { 48 | w.WriteHeader(http.StatusBadRequest) 49 | return 50 | } 51 | 52 | person, err := datastore.GetPerson(ctx, id) 53 | if err != nil { 54 | log.Printf("error: error getting person err=%q", err) 55 | w.WriteHeader(http.StatusNotFound) 56 | return 57 | } 58 | 59 | renderTemplate(ctx, w, "person_show.tmpl", M{ 60 | "Person": person, 61 | }) 62 | } 63 | -------------------------------------------------------------------------------- /handler/frontend/templates/.gitignore: -------------------------------------------------------------------------------- 1 | bindata.go 2 | -------------------------------------------------------------------------------- /handler/frontend/templates/index.tmpl: -------------------------------------------------------------------------------- 1 | {{ define "title"}}Index Page{{ end }} 2 | 3 | {{ define "content" }} 4 |

Skeleton

5 | {{ end }} 6 | -------------------------------------------------------------------------------- /handler/frontend/templates/person_list.tmpl: -------------------------------------------------------------------------------- 1 | {{ define "title"}}Listing People{{ end }} 2 | 3 | {{ define "content" }} 4 |

All People

5 | 6 | 13 | {{ end }} 14 | -------------------------------------------------------------------------------- /handler/frontend/templates/person_show.tmpl: -------------------------------------------------------------------------------- 1 | {{ define "title"}}Showing Person{{ end }} 2 | 3 | {{ define "content" }} 4 |

Showing Person

5 | 6 |
7 | Name: {{.Person.Name}} 8 |
9 | {{ end }} 10 | -------------------------------------------------------------------------------- /handler/frontend/util.go: -------------------------------------------------------------------------------- 1 | package frontend 2 | 3 | import ( 4 | "fmt" 5 | "html/template" 6 | "log" 7 | "net/http" 8 | "path/filepath" 9 | 10 | "github.com/oxtoacart/bpool" 11 | "golang.org/x/net/context" 12 | 13 | "github.com/andrew-d/go-webapp-skeleton/handler/frontend/layouts" 14 | "github.com/andrew-d/go-webapp-skeleton/handler/frontend/templates" 15 | ) 16 | 17 | type M map[string]interface{} 18 | 19 | var ( 20 | // Buffer pool for rendering templates 21 | bufpool *bpool.BufferPool 22 | 23 | // Map of templates 24 | templatesMap map[string]*template.Template 25 | 26 | // Extra functions 27 | templateFuncs = template.FuncMap{} 28 | ) 29 | 30 | func init() { 31 | // Create buffer pool 32 | bufpool = bpool.NewBufferPool(64) 33 | 34 | // Get the contents of all layouts. 35 | layoutData := make(map[string]string) 36 | for _, lname := range layouts.AssetNames() { 37 | d, _ := layouts.Asset(lname) 38 | layoutData[lname] = string(d) 39 | } 40 | 41 | // For each template, we parse it. 42 | templatesMap = make(map[string]*template.Template) 43 | for _, aname := range templates.AssetNames() { 44 | tname := filepath.Base(aname) 45 | 46 | // Create new template with functions 47 | tmpl := template.New(tname).Funcs(templateFuncs) 48 | 49 | // Get the template's data 50 | d, _ := templates.Asset(aname) 51 | 52 | // Parse the main template, then all the layouts. 53 | tmpl = template.Must(tmpl.Parse(string(d))) 54 | for _, layout := range layouts.AssetNames() { 55 | tmpl = template.Must(tmpl.Parse(layoutData[layout])) 56 | } 57 | 58 | // Insert 59 | templatesMap[tname] = tmpl 60 | } 61 | } 62 | 63 | // renderTemplate is a wrapper around template.ExecuteTemplate. It writes into 64 | // a bytes.Buffer before writing to the http.ResponseWriter to catch any errors 65 | // resulting from populating the template. 66 | func renderTemplate(ctx context.Context, w http.ResponseWriter, name string, data map[string]interface{}) error { 67 | // Ensure the template exists in the map. 68 | tmpl, ok := templatesMap[name] 69 | if !ok { 70 | log.Printf("error: template does not exist name=%q", name) 71 | return fmt.Errorf("The template %s does not exist", name) 72 | } 73 | 74 | // Create a buffer to temporarily write to and check if any errors were encounted. 75 | buf := bufpool.Get() 76 | defer bufpool.Put(buf) 77 | 78 | err := tmpl.ExecuteTemplate(buf, "base", data) 79 | if err != nil { 80 | log.Printf("error: could not render template err=%q name=%q", err, name) 81 | return err 82 | } 83 | 84 | // Set the header and write the buffer to the http.ResponseWriter 85 | w.Header().Set("Content-Type", "text/html; charset=utf-8") 86 | buf.WriteTo(w) 87 | return nil 88 | } 89 | -------------------------------------------------------------------------------- /middleware/header.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "net/http" 5 | "time" 6 | ) 7 | 8 | func SetHeaders(h http.Handler) http.Handler { 9 | fn := func(w http.ResponseWriter, r *http.Request) { 10 | // Allow XHR 11 | w.Header().Add("Access-Control-Allow-Origin", "*") 12 | 13 | // Security headers 14 | w.Header().Add("X-Frame-Options", "DENY") 15 | w.Header().Add("X-Content-Type-Options", "nosniff") 16 | w.Header().Add("X-XSS-Protection", "1; mode=block") 17 | 18 | // Disable all caching 19 | w.Header().Add("Cache-Control", "no-cache") 20 | w.Header().Add("Cache-Control", "no-store") 21 | w.Header().Add("Cache-Control", "max-age=0") 22 | w.Header().Add("Cache-Control", "must-revalidate") 23 | w.Header().Add("Cache-Control", "value") 24 | w.Header().Set("Last-Modified", time.Now().UTC().Format(http.TimeFormat)) 25 | w.Header().Set("Expires", "Thu, 01 Jan 1970 00:00:00 GMT") 26 | 27 | // HSTS for TLS connections. 28 | if r.TLS != nil { 29 | w.Header().Add("Strict-Transport-Security", "max-age=31536000") 30 | } 31 | 32 | h.ServeHTTP(w, r) 33 | } 34 | return http.HandlerFunc(fn) 35 | } 36 | -------------------------------------------------------------------------------- /middleware/json.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "net/http" 5 | ) 6 | 7 | // JSON sets the Content-Type to 'application/json' and sets the 8 | // 'Access-Control-Allow-Origin' to allow all requests. 9 | func JSON(h http.Handler) http.Handler { 10 | fn := func(w http.ResponseWriter, r *http.Request) { 11 | w.Header().Set("Access-Control-Allow-Origin", "*") 12 | w.Header().Set("Content-Type", "application/json; charset=utf-8") 13 | h.ServeHTTP(w, r) 14 | } 15 | return http.HandlerFunc(fn) 16 | } 17 | -------------------------------------------------------------------------------- /middleware/log.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "log" 7 | "net/http" 8 | "time" 9 | 10 | "goji.io" 11 | "golang.org/x/net/context" 12 | ) 13 | 14 | // Logger is a middleware that will log each request recieved, along with 15 | // some useful information, using the 'log' package. 16 | func Logger(h goji.Handler) goji.Handler { 17 | fn := func(ctx context.Context, w http.ResponseWriter, r *http.Request) { 18 | // Generate per-request fields 19 | var fieldsBuf bytes.Buffer 20 | if id := GetRequestID(ctx); id != "" { 21 | fmt.Fprintf(&fieldsBuf, " request_id=%q", id) 22 | } 23 | 24 | fmt.Fprintf(&fieldsBuf, 25 | " method=%s url=%q remote_addr=%q", 26 | r.Method, 27 | r.URL.String(), 28 | r.RemoteAddr) 29 | 30 | // Print the pre-request log 31 | log.Printf("request started%s", fieldsBuf.String()) 32 | 33 | // Wrap the writer so we can track data written, status, etc. 34 | wh := WrapWriter(w) 35 | 36 | // Dispatch to the underlying handler. 37 | start := time.Now() 38 | h.ServeHTTPC(ctx, wh, r) 39 | 40 | // Ensure that we've started flushing data to the client before 41 | // we stop the timer. 42 | if wh.Status() == 0 { 43 | wh.WriteHeader(http.StatusOK) 44 | } 45 | took := time.Since(start) 46 | 47 | // Fill in remainder of the request fields 48 | fmt.Fprintf(&fieldsBuf, 49 | " bytes_written=%d status=%d took=%q", 50 | wh.BytesWritten(), 51 | wh.Status(), 52 | took) 53 | 54 | // Log final information. 55 | log.Printf("request finished%s", fieldsBuf.String()) 56 | } 57 | 58 | return goji.HandlerFunc(fn) 59 | } 60 | -------------------------------------------------------------------------------- /middleware/options.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "net/http" 5 | ) 6 | 7 | // Options automatically return an appropriate "Allow" header when the 8 | // request method is OPTIONS and the request would have otherwise been 404'd. 9 | func Options(h http.Handler) http.Handler { 10 | fn := func(w http.ResponseWriter, r *http.Request) { 11 | if r.Method == "OPTIONS" { 12 | w.Header().Set("Access-Control-Allow-Origin", "*") 13 | w.Header().Set("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE,OPTIONS") 14 | w.Header().Set("Access-Control-Allow-Headers", "Authorization") 15 | w.Header().Set("Allow", "HEAD,GET,POST,PUT,DELETE,OPTIONS") 16 | w.Header().Set("Content-Type", "application/json") 17 | w.WriteHeader(http.StatusOK) 18 | return 19 | } 20 | 21 | h.ServeHTTP(w, r) 22 | } 23 | return http.HandlerFunc(fn) 24 | } 25 | -------------------------------------------------------------------------------- /middleware/recover.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "bytes" 5 | "log" 6 | "net/http" 7 | "os" 8 | "runtime" 9 | 10 | "goji.io" 11 | "golang.org/x/net/context" 12 | 13 | "github.com/andrew-d/go-webapp-skeleton/conf" 14 | ) 15 | 16 | func Recoverer(h goji.Handler) goji.Handler { 17 | f := func(ctx context.Context, w http.ResponseWriter, r *http.Request) { 18 | id := GetRequestID(ctx) 19 | 20 | defer func() { 21 | if err := recover(); err != nil { 22 | w.WriteHeader(http.StatusInternalServerError) 23 | 24 | // Get the stack (from here, so we don't have 25 | // an extraneous call) 26 | stack := make([]byte, 8*1024) 27 | stack = stack[:runtime.Stack(stack, false)] 28 | 29 | // Handle the panic 30 | handlePanic(id, err, stack) 31 | } 32 | }() 33 | 34 | h.ServeHTTPC(ctx, w, r) 35 | } 36 | return goji.HandlerFunc(f) 37 | } 38 | 39 | func handlePanic(requestId string, err interface{}, stack []byte) { 40 | log.Printf( 41 | "error: recovered from panic request_id=%q err=%q", 42 | requestId, 43 | err) 44 | 45 | if conf.C.IsDebug() { 46 | // Split the stack by newlines, prepend a tab to each line, and then re-join 47 | deSpaced := bytes.TrimRight(stack, "\r\n ") 48 | lines := bytes.Split(deSpaced, []byte{'\n'}) 49 | prettyStack := bytes.Join(lines, []byte{'\n', '\t'}) 50 | prettyStack = append([]byte{'\t'}, prettyStack...) 51 | prettyStack = append(prettyStack, '\n') 52 | 53 | os.Stderr.Write(prettyStack) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /middleware/request_id.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "crypto/rand" 5 | "encoding/base64" 6 | "fmt" 7 | "net/http" 8 | "os" 9 | "strings" 10 | "sync/atomic" 11 | 12 | "goji.io" 13 | "golang.org/x/net/context" 14 | ) 15 | 16 | type private struct{} 17 | 18 | var requestIdKey private 19 | 20 | var ( 21 | prefix string 22 | reqid uint64 23 | ) 24 | 25 | func init() { 26 | hostname, err := os.Hostname() 27 | if hostname == "" || err != nil { 28 | hostname = "localhost" 29 | } 30 | 31 | var buf [12]byte 32 | var b64 string 33 | for len(b64) < 10 { 34 | rand.Read(buf[:]) 35 | b64 = base64.StdEncoding.EncodeToString(buf[:]) 36 | b64 = strings.NewReplacer("+", "", "/", "").Replace(b64) 37 | } 38 | 39 | prefix = fmt.Sprintf("%s/%s", hostname, b64[0:10]) 40 | } 41 | 42 | // RequestID is a middleware that injects a request ID into the headers of each 43 | // request. A request ID is a string of the form "host.example.com/random-0001", 44 | // where "random" is a base62 random string that uniquely identifies this go 45 | // process, and where the last number is an atomically incremented request 46 | // counter. 47 | // 48 | // Note: this middleware is adapted from goji: 49 | // https://github.com/zenazn/goji/blob/master/web/middleware/request_id.go 50 | func RequestID(h goji.Handler) goji.Handler { 51 | fn := func(ctx context.Context, w http.ResponseWriter, r *http.Request) { 52 | ctr := atomic.AddUint64(&reqid, 1) 53 | id := fmt.Sprintf("%s-%06d", prefix, ctr) 54 | 55 | ctx = context.WithValue(ctx, requestIdKey, id) 56 | h.ServeHTTPC(ctx, w, r) 57 | } 58 | 59 | return goji.HandlerFunc(fn) 60 | } 61 | 62 | // GetRequestID retrieves the request ID (if any) from the given context. It 63 | // will return the empty string ("") if none was set. 64 | func GetRequestID(ctx context.Context) string { 65 | val := ctx.Value(requestIdKey) 66 | if val != nil { 67 | return val.(string) 68 | } 69 | 70 | return "" 71 | } 72 | -------------------------------------------------------------------------------- /model/person.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type Person struct { 4 | ID int64 `db:"id" json:"id"` 5 | Name string `db:"name" json:"name"` 6 | } 7 | -------------------------------------------------------------------------------- /rename.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | set -u 5 | 6 | main() { 7 | while true; do 8 | printf "Do you want to run the rename script (y/n)? " 9 | read answer 10 | 11 | if echo "$answer" | grep -iq "^y$"; then 12 | break 13 | elif echo "$answer" | grep -iq "^n$"; then 14 | echo "Cancelled" 15 | exit 16 | else 17 | echo "Please answer 'y' or 'n'" 18 | fi 19 | done 20 | 21 | printf "Please enter the name of the project: " 22 | read new_name 23 | printf "Please enter the new import path of the project: " 24 | read new_path 25 | 26 | echo "Renaming..." 27 | 28 | # Rename the project name and import path in the Makefile 29 | sed -i .bak \ 30 | -e "s|github.com/andrew-d/go-webapp-skeleton|$new_path|g" \ 31 | -e "s|NAME.*=.*skeleton|NAME := $new_name|g" \ 32 | Makefile 33 | 34 | # Rename all the import paths in Go files 35 | find . -type f -name '*.go' \ 36 | | grep -v '/vendor/' \ 37 | | xargs sed -i .bak -e "s|github.com/andrew-d/go-webapp-skeleton|$new_path|g" 38 | 39 | # All done! 40 | echo "Done!" 41 | } 42 | 43 | main 44 | -------------------------------------------------------------------------------- /router/router.go: -------------------------------------------------------------------------------- 1 | package router 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | 7 | "goji.io" 8 | "goji.io/pat" 9 | 10 | "github.com/andrew-d/go-webapp-skeleton/handler/api" 11 | "github.com/andrew-d/go-webapp-skeleton/handler/frontend" 12 | ) 13 | 14 | func API() *goji.Mux { 15 | mux := goji.SubMux() 16 | 17 | // We pass the routes as relative to the point where the API router 18 | // will be mounted. The super-router will strip any prefix off for us. 19 | mux.HandleFuncC(pat.Get("/people"), api.ListPeople) 20 | mux.HandleFuncC(pat.Post("/people"), api.CreatePerson) 21 | mux.HandleFuncC(pat.Get("/people/:person"), api.GetPerson) 22 | mux.HandleFuncC(pat.Delete("/people/:person"), api.DeletePerson) 23 | 24 | // Add default 'not found' route that responds with JSON 25 | mux.HandleFunc(pat.New("/*"), func(w http.ResponseWriter, r *http.Request) { 26 | w.WriteHeader(404) 27 | fmt.Fprint(w, `{"error":"not found"}`) 28 | }) 29 | 30 | return mux 31 | } 32 | 33 | func Web() *goji.Mux { 34 | mux := goji.SubMux() 35 | 36 | mux.HandleFuncC(pat.Get("/people"), frontend.ListPeople) 37 | mux.HandleFuncC(pat.Get("/people/:person"), frontend.GetPerson) 38 | 39 | return mux 40 | } 41 | -------------------------------------------------------------------------------- /static/.gitignore: -------------------------------------------------------------------------------- 1 | bindata.go 2 | -------------------------------------------------------------------------------- /static/robots.txt: -------------------------------------------------------------------------------- 1 | # Put allow/disallow rules here. For example: 2 | # 3 | #User-agent: * 4 | #Disallow: / 5 | -------------------------------------------------------------------------------- /vendor/github.com/BurntSushi/migration/Makefile: -------------------------------------------------------------------------------- 1 | build: 2 | go build 3 | 4 | push: 5 | git push origin master 6 | git push github master 7 | 8 | -------------------------------------------------------------------------------- /vendor/github.com/BurntSushi/migration/README.md: -------------------------------------------------------------------------------- 1 | Package migration for Golang automatically handles versioning of a database 2 | schema by applying a series of migrations supplied by the client. It uses 3 | features only from the database/sql package, so it tries to be driver 4 | independent. However, to track the version of the database, it is necessary to 5 | execute some SQL. I've made an effort to keep those queries simple, but if they 6 | don't work with your database, you may override them. 7 | 8 | This package works by applying a series of migrations to a database. Once a 9 | migration is created, it should never be changed. Every time a database is 10 | opened with this package, all necessary migrations are executed in a single 11 | transaction. If any part of the process fails, an error is returned and the 12 | transaction is rolled back so that the database is left untouched. (Note that 13 | for this to be useful, you'll need to use a database that supports rolling back 14 | changes to your schema. Notably, MySQL does not support this, although SQLite 15 | and PostgreSQL do.) 16 | 17 | The version of a database is defined as the number of migrations applied to it. 18 | 19 | 20 | ### Installation 21 | 22 | If you have Go installed and 23 | [your GOPATH is setup](http://golang.org/doc/code.html#GOPATH), then 24 | `migration` can be installed with `go get`: 25 | 26 | go get github.com/BurntSushi/migration 27 | 28 | 29 | ### Documentation 30 | 31 | Documentation is available at 32 | [godoc.org/github.com/BurntSushi/migration](http://godoc.org/github.com/BurntSushi/migration). 33 | 34 | 35 | ### Unstable 36 | 37 | At the moment, I'm still experimenting with the public API, so I may still 38 | introduce breaking changes. In general though, I am happy with the overall 39 | architecture. 40 | 41 | -------------------------------------------------------------------------------- /vendor/github.com/BurntSushi/migration/UNLICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /vendor/github.com/BurntSushi/migration/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package migration automatically handles versioning of a database 3 | schema by applying a series of migrations supplied by the client. It uses 4 | features only from the database/sql package, so it tries to be driver 5 | independent. However, to track the version of the database, it is necessary to 6 | execute some SQL. I've made an effort to keep those queries simple, but if they 7 | don't work with your database, you may override them. 8 | 9 | This package works by applying a series of migrations to a database. Once a 10 | migration is created, it should never be changed. Every time a database is 11 | opened with this package, all necessary migrations are executed in a single 12 | transaction. If any part of the process fails, an error is returned and the 13 | transaction is rolled back so that the database is left untouched. (Note that 14 | for this to be useful, you'll need to use a database that supports rolling back 15 | changes to your schema. Notably, MySQL does not support this, although SQLite 16 | and PostgreSQL do.) 17 | 18 | The version of a database is defined as the number of migrations applied to it. 19 | */ 20 | package migration 21 | -------------------------------------------------------------------------------- /vendor/github.com/BurntSushi/migration/session.vim: -------------------------------------------------------------------------------- 1 | au BufWritePost *.go silent!make tags > /dev/null 2>&1 2 | -------------------------------------------------------------------------------- /vendor/github.com/codegangsta/negroni/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Jeremy Saenz 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 | -------------------------------------------------------------------------------- /vendor/github.com/codegangsta/negroni/doc.go: -------------------------------------------------------------------------------- 1 | // Package negroni is an idiomatic approach to web middleware in Go. It is tiny, non-intrusive, and encourages use of net/http Handlers. 2 | // 3 | // If you like the idea of Martini, but you think it contains too much magic, then Negroni is a great fit. 4 | // 5 | // For a full guide visit http://github.com/codegangsta/negroni 6 | // 7 | // package main 8 | // 9 | // import ( 10 | // "github.com/codegangsta/negroni" 11 | // "net/http" 12 | // "fmt" 13 | // ) 14 | // 15 | // func main() { 16 | // mux := http.NewServeMux() 17 | // mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) { 18 | // fmt.Fprintf(w, "Welcome to the home page!") 19 | // }) 20 | // 21 | // n := negroni.Classic() 22 | // n.UseHandler(mux) 23 | // n.Run(":3000") 24 | // } 25 | package negroni 26 | -------------------------------------------------------------------------------- /vendor/github.com/codegangsta/negroni/logger.go: -------------------------------------------------------------------------------- 1 | package negroni 2 | 3 | import ( 4 | "log" 5 | "net/http" 6 | "os" 7 | "time" 8 | ) 9 | 10 | // Logger is a middleware handler that logs the request as it goes in and the response as it goes out. 11 | type Logger struct { 12 | // Logger inherits from log.Logger used to log messages with the Logger middleware 13 | *log.Logger 14 | } 15 | 16 | // NewLogger returns a new Logger instance 17 | func NewLogger() *Logger { 18 | return &Logger{log.New(os.Stdout, "[negroni] ", 0)} 19 | } 20 | 21 | func (l *Logger) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { 22 | start := time.Now() 23 | l.Printf("Started %s %s", r.Method, r.URL.Path) 24 | 25 | next(rw, r) 26 | 27 | res := rw.(ResponseWriter) 28 | l.Printf("Completed %v %s in %v", res.Status(), http.StatusText(res.Status()), time.Since(start)) 29 | } 30 | -------------------------------------------------------------------------------- /vendor/github.com/codegangsta/negroni/logger_test.go: -------------------------------------------------------------------------------- 1 | package negroni 2 | 3 | import ( 4 | "bytes" 5 | "log" 6 | "net/http" 7 | "net/http/httptest" 8 | "testing" 9 | ) 10 | 11 | func Test_Logger(t *testing.T) { 12 | buff := bytes.NewBufferString("") 13 | recorder := httptest.NewRecorder() 14 | 15 | l := NewLogger() 16 | l.Logger = log.New(buff, "[negroni] ", 0) 17 | 18 | n := New() 19 | // replace log for testing 20 | n.Use(l) 21 | n.UseHandler(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { 22 | rw.WriteHeader(http.StatusNotFound) 23 | })) 24 | 25 | req, err := http.NewRequest("GET", "http://localhost:3000/foobar", nil) 26 | if err != nil { 27 | t.Error(err) 28 | } 29 | 30 | n.ServeHTTP(recorder, req) 31 | expect(t, recorder.Code, http.StatusNotFound) 32 | refute(t, len(buff.String()), 0) 33 | } 34 | -------------------------------------------------------------------------------- /vendor/github.com/codegangsta/negroni/negroni_test.go: -------------------------------------------------------------------------------- 1 | package negroni 2 | 3 | import ( 4 | "net/http" 5 | "net/http/httptest" 6 | "reflect" 7 | "testing" 8 | ) 9 | 10 | /* Test Helpers */ 11 | func expect(t *testing.T, a interface{}, b interface{}) { 12 | if a != b { 13 | t.Errorf("Expected %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a)) 14 | } 15 | } 16 | 17 | func refute(t *testing.T, a interface{}, b interface{}) { 18 | if a == b { 19 | t.Errorf("Did not expect %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a)) 20 | } 21 | } 22 | 23 | func TestNegroniRun(t *testing.T) { 24 | // just test that Run doesn't bomb 25 | go New().Run(":3000") 26 | } 27 | 28 | func TestNegroniServeHTTP(t *testing.T) { 29 | result := "" 30 | response := httptest.NewRecorder() 31 | 32 | n := New() 33 | n.Use(HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { 34 | result += "foo" 35 | next(rw, r) 36 | result += "ban" 37 | })) 38 | n.Use(HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { 39 | result += "bar" 40 | next(rw, r) 41 | result += "baz" 42 | })) 43 | n.Use(HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { 44 | result += "bat" 45 | rw.WriteHeader(http.StatusBadRequest) 46 | })) 47 | 48 | n.ServeHTTP(response, (*http.Request)(nil)) 49 | 50 | expect(t, result, "foobarbatbazban") 51 | expect(t, response.Code, http.StatusBadRequest) 52 | } 53 | 54 | // Ensures that a Negroni middleware chain 55 | // can correctly return all of its handlers. 56 | func TestHandlers(t *testing.T) { 57 | response := httptest.NewRecorder() 58 | n := New() 59 | handlers := n.Handlers() 60 | expect(t, 0, len(handlers)) 61 | 62 | n.Use(HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { 63 | rw.WriteHeader(http.StatusOK) 64 | })) 65 | 66 | // Expects the length of handlers to be exactly 1 67 | // after adding exactly one handler to the middleware chain 68 | handlers = n.Handlers() 69 | expect(t, 1, len(handlers)) 70 | 71 | // Ensures that the first handler that is in sequence behaves 72 | // exactly the same as the one that was registered earlier 73 | handlers[0].ServeHTTP(response, (*http.Request)(nil), nil) 74 | expect(t, response.Code, http.StatusOK) 75 | } -------------------------------------------------------------------------------- /vendor/github.com/codegangsta/negroni/recovery.go: -------------------------------------------------------------------------------- 1 | package negroni 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/http" 7 | "os" 8 | "runtime" 9 | ) 10 | 11 | // Recovery is a Negroni middleware that recovers from any panics and writes a 500 if there was one. 12 | type Recovery struct { 13 | Logger *log.Logger 14 | PrintStack bool 15 | StackAll bool 16 | StackSize int 17 | } 18 | 19 | // NewRecovery returns a new instance of Recovery 20 | func NewRecovery() *Recovery { 21 | return &Recovery{ 22 | Logger: log.New(os.Stdout, "[negroni] ", 0), 23 | PrintStack: true, 24 | StackAll: false, 25 | StackSize: 1024 * 8, 26 | } 27 | } 28 | 29 | func (rec *Recovery) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { 30 | defer func() { 31 | if err := recover(); err != nil { 32 | rw.WriteHeader(http.StatusInternalServerError) 33 | stack := make([]byte, rec.StackSize) 34 | stack = stack[:runtime.Stack(stack, rec.StackAll)] 35 | 36 | f := "PANIC: %s\n%s" 37 | rec.Logger.Printf(f, err, stack) 38 | 39 | if rec.PrintStack { 40 | fmt.Fprintf(rw, f, err, stack) 41 | } 42 | } 43 | }() 44 | 45 | next(rw, r) 46 | } 47 | -------------------------------------------------------------------------------- /vendor/github.com/codegangsta/negroni/recovery_test.go: -------------------------------------------------------------------------------- 1 | package negroni 2 | 3 | import ( 4 | "bytes" 5 | "log" 6 | "net/http" 7 | "net/http/httptest" 8 | "testing" 9 | ) 10 | 11 | func TestRecovery(t *testing.T) { 12 | buff := bytes.NewBufferString("") 13 | recorder := httptest.NewRecorder() 14 | 15 | rec := NewRecovery() 16 | rec.Logger = log.New(buff, "[negroni] ", 0) 17 | 18 | n := New() 19 | // replace log for testing 20 | n.Use(rec) 21 | n.UseHandler(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) { 22 | panic("here is a panic!") 23 | })) 24 | n.ServeHTTP(recorder, (*http.Request)(nil)) 25 | expect(t, recorder.Code, http.StatusInternalServerError) 26 | refute(t, recorder.Body.Len(), 0) 27 | refute(t, len(buff.String()), 0) 28 | } 29 | -------------------------------------------------------------------------------- /vendor/github.com/codegangsta/negroni/response_writer.go: -------------------------------------------------------------------------------- 1 | package negroni 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "net" 7 | "net/http" 8 | ) 9 | 10 | // ResponseWriter is a wrapper around http.ResponseWriter that provides extra information about 11 | // the response. It is recommended that middleware handlers use this construct to wrap a responsewriter 12 | // if the functionality calls for it. 13 | type ResponseWriter interface { 14 | http.ResponseWriter 15 | http.Flusher 16 | // Status returns the status code of the response or 0 if the response has not been written. 17 | Status() int 18 | // Written returns whether or not the ResponseWriter has been written. 19 | Written() bool 20 | // Size returns the size of the response body. 21 | Size() int 22 | // Before allows for a function to be called before the ResponseWriter has been written to. This is 23 | // useful for setting headers or any other operations that must happen before a response has been written. 24 | Before(func(ResponseWriter)) 25 | } 26 | 27 | type beforeFunc func(ResponseWriter) 28 | 29 | // NewResponseWriter creates a ResponseWriter that wraps an http.ResponseWriter 30 | func NewResponseWriter(rw http.ResponseWriter) ResponseWriter { 31 | return &responseWriter{rw, 0, 0, nil} 32 | } 33 | 34 | type responseWriter struct { 35 | http.ResponseWriter 36 | status int 37 | size int 38 | beforeFuncs []beforeFunc 39 | } 40 | 41 | func (rw *responseWriter) WriteHeader(s int) { 42 | rw.status = s 43 | rw.callBefore() 44 | rw.ResponseWriter.WriteHeader(s) 45 | } 46 | 47 | func (rw *responseWriter) Write(b []byte) (int, error) { 48 | if !rw.Written() { 49 | // The status will be StatusOK if WriteHeader has not been called yet 50 | rw.WriteHeader(http.StatusOK) 51 | } 52 | size, err := rw.ResponseWriter.Write(b) 53 | rw.size += size 54 | return size, err 55 | } 56 | 57 | func (rw *responseWriter) Status() int { 58 | return rw.status 59 | } 60 | 61 | func (rw *responseWriter) Size() int { 62 | return rw.size 63 | } 64 | 65 | func (rw *responseWriter) Written() bool { 66 | return rw.status != 0 67 | } 68 | 69 | func (rw *responseWriter) Before(before func(ResponseWriter)) { 70 | rw.beforeFuncs = append(rw.beforeFuncs, before) 71 | } 72 | 73 | func (rw *responseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) { 74 | hijacker, ok := rw.ResponseWriter.(http.Hijacker) 75 | if !ok { 76 | return nil, nil, fmt.Errorf("the ResponseWriter doesn't support the Hijacker interface") 77 | } 78 | return hijacker.Hijack() 79 | } 80 | 81 | func (rw *responseWriter) CloseNotify() <-chan bool { 82 | return rw.ResponseWriter.(http.CloseNotifier).CloseNotify() 83 | } 84 | 85 | func (rw *responseWriter) callBefore() { 86 | for i := len(rw.beforeFuncs) - 1; i >= 0; i-- { 87 | rw.beforeFuncs[i](rw) 88 | } 89 | } 90 | 91 | func (rw *responseWriter) Flush() { 92 | flusher, ok := rw.ResponseWriter.(http.Flusher) 93 | if ok { 94 | flusher.Flush() 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /vendor/github.com/codegangsta/negroni/static.go: -------------------------------------------------------------------------------- 1 | package negroni 2 | 3 | import ( 4 | "net/http" 5 | "path" 6 | "strings" 7 | ) 8 | 9 | // Static is a middleware handler that serves static files in the given directory/filesystem. 10 | type Static struct { 11 | // Dir is the directory to serve static files from 12 | Dir http.FileSystem 13 | // Prefix is the optional prefix used to serve the static directory content 14 | Prefix string 15 | // IndexFile defines which file to serve as index if it exists. 16 | IndexFile string 17 | } 18 | 19 | // NewStatic returns a new instance of Static 20 | func NewStatic(directory http.FileSystem) *Static { 21 | return &Static{ 22 | Dir: directory, 23 | Prefix: "", 24 | IndexFile: "index.html", 25 | } 26 | } 27 | 28 | func (s *Static) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { 29 | if r.Method != "GET" && r.Method != "HEAD" { 30 | next(rw, r) 31 | return 32 | } 33 | file := r.URL.Path 34 | // if we have a prefix, filter requests by stripping the prefix 35 | if s.Prefix != "" { 36 | if !strings.HasPrefix(file, s.Prefix) { 37 | next(rw, r) 38 | return 39 | } 40 | file = file[len(s.Prefix):] 41 | if file != "" && file[0] != '/' { 42 | next(rw, r) 43 | return 44 | } 45 | } 46 | f, err := s.Dir.Open(file) 47 | if err != nil { 48 | // discard the error? 49 | next(rw, r) 50 | return 51 | } 52 | defer f.Close() 53 | 54 | fi, err := f.Stat() 55 | if err != nil { 56 | next(rw, r) 57 | return 58 | } 59 | 60 | // try to serve index file 61 | if fi.IsDir() { 62 | // redirect if missing trailing slash 63 | if !strings.HasSuffix(r.URL.Path, "/") { 64 | http.Redirect(rw, r, r.URL.Path+"/", http.StatusFound) 65 | return 66 | } 67 | 68 | file = path.Join(file, s.IndexFile) 69 | f, err = s.Dir.Open(file) 70 | if err != nil { 71 | next(rw, r) 72 | return 73 | } 74 | defer f.Close() 75 | 76 | fi, err = f.Stat() 77 | if err != nil || fi.IsDir() { 78 | next(rw, r) 79 | return 80 | } 81 | } 82 | 83 | http.ServeContent(rw, r, file, fi.ModTime(), f) 84 | } 85 | -------------------------------------------------------------------------------- /vendor/github.com/codegangsta/negroni/static_test.go: -------------------------------------------------------------------------------- 1 | package negroni 2 | 3 | import ( 4 | "bytes" 5 | "net/http" 6 | "net/http/httptest" 7 | "testing" 8 | ) 9 | 10 | func TestStatic(t *testing.T) { 11 | response := httptest.NewRecorder() 12 | response.Body = new(bytes.Buffer) 13 | 14 | n := New() 15 | n.Use(NewStatic(http.Dir("."))) 16 | 17 | req, err := http.NewRequest("GET", "http://localhost:3000/negroni.go", nil) 18 | if err != nil { 19 | t.Error(err) 20 | } 21 | n.ServeHTTP(response, req) 22 | expect(t, response.Code, http.StatusOK) 23 | expect(t, response.Header().Get("Expires"), "") 24 | if response.Body.Len() == 0 { 25 | t.Errorf("Got empty body for GET request") 26 | } 27 | } 28 | 29 | func TestStaticHead(t *testing.T) { 30 | response := httptest.NewRecorder() 31 | response.Body = new(bytes.Buffer) 32 | 33 | n := New() 34 | n.Use(NewStatic(http.Dir("."))) 35 | n.UseHandler(http.NotFoundHandler()) 36 | 37 | req, err := http.NewRequest("HEAD", "http://localhost:3000/negroni.go", nil) 38 | if err != nil { 39 | t.Error(err) 40 | } 41 | 42 | n.ServeHTTP(response, req) 43 | expect(t, response.Code, http.StatusOK) 44 | if response.Body.Len() != 0 { 45 | t.Errorf("Got non-empty body for HEAD request") 46 | } 47 | } 48 | 49 | func TestStaticAsPost(t *testing.T) { 50 | response := httptest.NewRecorder() 51 | 52 | n := New() 53 | n.Use(NewStatic(http.Dir("."))) 54 | n.UseHandler(http.NotFoundHandler()) 55 | 56 | req, err := http.NewRequest("POST", "http://localhost:3000/negroni.go", nil) 57 | if err != nil { 58 | t.Error(err) 59 | } 60 | 61 | n.ServeHTTP(response, req) 62 | expect(t, response.Code, http.StatusNotFound) 63 | } 64 | 65 | func TestStaticBadDir(t *testing.T) { 66 | response := httptest.NewRecorder() 67 | 68 | n := Classic() 69 | n.UseHandler(http.NotFoundHandler()) 70 | 71 | req, err := http.NewRequest("GET", "http://localhost:3000/negroni.go", nil) 72 | if err != nil { 73 | t.Error(err) 74 | } 75 | 76 | n.ServeHTTP(response, req) 77 | refute(t, response.Code, http.StatusOK) 78 | } 79 | 80 | func TestStaticOptionsServeIndex(t *testing.T) { 81 | response := httptest.NewRecorder() 82 | 83 | n := New() 84 | s := NewStatic(http.Dir(".")) 85 | s.IndexFile = "negroni.go" 86 | n.Use(s) 87 | 88 | req, err := http.NewRequest("GET", "http://localhost:3000/", nil) 89 | if err != nil { 90 | t.Error(err) 91 | } 92 | 93 | n.ServeHTTP(response, req) 94 | expect(t, response.Code, http.StatusOK) 95 | } 96 | 97 | func TestStaticOptionsPrefix(t *testing.T) { 98 | response := httptest.NewRecorder() 99 | 100 | n := New() 101 | s := NewStatic(http.Dir(".")) 102 | s.Prefix = "/public" 103 | n.Use(s) 104 | 105 | // Check file content behaviour 106 | req, err := http.NewRequest("GET", "http://localhost:3000/public/negroni.go", nil) 107 | if err != nil { 108 | t.Error(err) 109 | } 110 | 111 | n.ServeHTTP(response, req) 112 | expect(t, response.Code, http.StatusOK) 113 | } 114 | -------------------------------------------------------------------------------- /vendor/github.com/comail/colog/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 comail 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 | 23 | -------------------------------------------------------------------------------- /vendor/github.com/comail/colog/colog_bench_test.go: -------------------------------------------------------------------------------- 1 | package colog 2 | 3 | import ( 4 | "log" 5 | "testing" 6 | ) 7 | 8 | func BenchmarkLoggerNoFlags(b *testing.B) { 9 | logger := log.New(new(nilWriter), "", 0) 10 | for i := 0; i <= b.N; i++ { 11 | logger.Println("error: benchmark") 12 | } 13 | } 14 | 15 | func BenchmarkLoggerWithFlags(b *testing.B) { 16 | logger := log.New(new(nilWriter), "", log.Llongfile|log.Ldate) 17 | for i := 0; i <= b.N; i++ { 18 | logger.Println("error: benchmark") 19 | } 20 | } 21 | 22 | func BenchmarkCoLogPlainNoFlags(b *testing.B) { 23 | doBench(b, "error: benchmark", 0, false, false) 24 | } 25 | 26 | func BenchmarkCoLogPlainWithFlags(b *testing.B) { 27 | doBench(b, "error: benchmark", log.Llongfile|log.Ldate, false, false) 28 | } 29 | 30 | func BenchmarkCoLogPlainWithFlagsAndFields(b *testing.B) { 31 | doBench(b, "error: benchmark KeyName1='Key Value1'", log.Llongfile|log.Ldate, true, false) 32 | } 33 | 34 | func BenchmarkCoLogColorNoFlags(b *testing.B) { 35 | doBench(b, "error: benchmark", 0, false, true) 36 | } 37 | 38 | func BenchmarkCoLogColorWithFlags(b *testing.B) { 39 | doBench(b, "error: benchmark", log.Llongfile|log.Ldate, false, true) 40 | } 41 | 42 | func BenchmarkCoLogColorWithFlagsAndFields(b *testing.B) { 43 | doBench(b, "error: benchmark KeyName1='Key Value1'", log.Llongfile|log.Ldate, true, true) 44 | } 45 | 46 | func doBench(b *testing.B, message string, flag int, fields bool, colors bool) { 47 | cl := NewCoLog(new(nilWriter), "", flag) 48 | cl.ParseFields(fields) 49 | cl.SetFormatter(&StdFormatter{Flag: flag, Colors: colors}) 50 | // fmt.Printf("flags %d \n", cl.formatter.Flags()) 51 | logger := cl.NewLogger() 52 | for i := 0; i <= b.N; i++ { 53 | logger.Println(message) 54 | } 55 | } 56 | 57 | type nilWriter struct{} 58 | 59 | func (nw *nilWriter) Write(p []byte) (n int, err error) { return 0, nil } 60 | -------------------------------------------------------------------------------- /vendor/github.com/comail/colog/interfaces.go: -------------------------------------------------------------------------------- 1 | package colog 2 | 3 | // Hook is the interface to be implemented by event hooks 4 | type Hook interface { 5 | Levels() []Level // returns the set of levels for which the hook should be triggered 6 | Fire(*Entry) error // triggers the hook, this function will be called for every eligible log entry 7 | } 8 | 9 | // Formatter interface must be implemented by message formatters 10 | // Format(*Entry) will be called and the resulting bytes sent to output 11 | type Formatter interface { 12 | Format(*Entry) ([]byte, error) // The actual formatter called every time 13 | SetFlags(flags int) // Like the standard log.SetFlags(flags int) 14 | Flags() int // Like the standard log.Flags() int 15 | } 16 | 17 | // ColorFormatter interface can be implemented by formatters 18 | // to get notifications on whether the output supports color 19 | type ColorFormatter interface { 20 | Formatter 21 | ColorSupported(yes bool) 22 | } 23 | 24 | // ColorSupporter interface can be implemented by "smart" 25 | // outputs that want to handle color display themselves 26 | type ColorSupporter interface { 27 | ColorSupported() bool 28 | } 29 | 30 | // Extractor interface must be implemented by data extractors 31 | // the extractor reads the message and tries to extract key-value 32 | // pairs from the message and sets the in the entry 33 | type Extractor interface { 34 | Extract(*Entry) error 35 | } 36 | -------------------------------------------------------------------------------- /vendor/github.com/comail/colog/json_formatter.go: -------------------------------------------------------------------------------- 1 | package colog 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "log" 7 | "strconv" 8 | "sync" 9 | ) 10 | 11 | // JSONFormatter serializes entries to JSON 12 | // TimeFormat can be any Go time format, if empty 13 | // it will mimic the standard logger format 14 | // LevelAsNum will use a numeric string "1", "2",... 15 | // for as levels instead of "trace", "debug", .. 16 | type JSONFormatter struct { 17 | mu sync.Mutex 18 | TimeFormat string 19 | LevelAsNum bool 20 | Flag int 21 | } 22 | 23 | // JSONEntry is an entry with the final JSON field types 24 | // We can not just implement the Marshaller interface since 25 | // some of the process depends on runtime options 26 | type JSONEntry struct { 27 | Level string `json:"level,omitempty"` 28 | Time string `json:"time,omitempty"` 29 | Host string `json:"host,omitempty"` 30 | Prefix string `json:"prefix,omitempty"` 31 | File string `json:"file,omitempty"` 32 | Line int `json:"line,omitempty"` 33 | Message string `json:"message,omitempty"` 34 | Fields Fields `json:"fields,omitempty"` 35 | } 36 | 37 | // Format takes and entry and returns the formatted output in bytes 38 | func (jf *JSONFormatter) Format(e *Entry) ([]byte, error) { 39 | 40 | file, line := jf.fileLine(e) 41 | date := jf.date(e) 42 | 43 | var level string 44 | if jf.LevelAsNum { 45 | level = strconv.Itoa(int(e.Level)) 46 | } else { 47 | level = e.Level.String() 48 | } 49 | 50 | je := &JSONEntry{ 51 | Level: level, 52 | Time: date, 53 | Host: e.Host, 54 | Prefix: e.Prefix, 55 | File: file, 56 | Line: line, 57 | Message: string(e.Message), 58 | Fields: e.Fields, 59 | } 60 | 61 | data, err := json.Marshal(je) 62 | return append(data, '\n'), err 63 | } 64 | 65 | // Flags returns the output flags for the formatter. 66 | func (jf *JSONFormatter) Flags() int { 67 | return jf.Flag 68 | } 69 | 70 | // SetFlags sets the output flags for the formatter. 71 | func (jf *JSONFormatter) SetFlags(flags int) { 72 | jf.Flag = flags 73 | } 74 | 75 | func (jf *JSONFormatter) fileLine(e *Entry) (file string, line int) { 76 | if jf.Flag&(log.Lshortfile|log.Llongfile) == 0 { 77 | return 78 | } 79 | 80 | file = e.File 81 | line = e.Line 82 | if jf.Flag&log.Lshortfile != 0 { 83 | short := file 84 | for i := len(file) - 1; i > 0; i-- { 85 | if file[i] == '/' { 86 | short = file[i+1:] 87 | break 88 | } 89 | } 90 | file = short 91 | } 92 | 93 | return file, line 94 | } 95 | 96 | func (jf *JSONFormatter) date(e *Entry) (date string) { 97 | if jf.TimeFormat != "" { 98 | return e.Time.Format(jf.TimeFormat) 99 | } 100 | 101 | if jf.Flag&(log.Ldate|log.Ltime|log.Lmicroseconds) == 0 { 102 | return "" 103 | } 104 | 105 | if jf.Flag&log.Ldate != 0 { 106 | year, month, day := e.Time.Date() 107 | date = fmt.Sprintf("%d/%d/%d", year, month, day) 108 | } 109 | 110 | if jf.Flag&(log.Ltime|log.Lmicroseconds) != 0 { 111 | hour, min, sec := e.Time.Clock() 112 | date = fmt.Sprintf("%s %d:%d:%d", date, hour, min, sec) 113 | if jf.Flag&log.Lmicroseconds != 0 { 114 | date = fmt.Sprintf("%s.%d", date, e.Time.Nanosecond()) 115 | 116 | } 117 | } 118 | 119 | return date 120 | } 121 | -------------------------------------------------------------------------------- /vendor/github.com/comail/colog/std_extractor.go: -------------------------------------------------------------------------------- 1 | package colog 2 | 3 | import ( 4 | "bytes" 5 | "regexp" 6 | ) 7 | 8 | // regex to extract key-value (or quoted value) from the logged message 9 | // if you can do this better please make a pull request 10 | // this is just the result of lots of trial and error 11 | var fieldsRegex = `(?P([\pL0-9_]+))\s*=\s*((?P([\pL0-9_]+))|(?P("[^"]*"|'[^']*')))` 12 | 13 | // StdExtractor implements a regex based extractor for key-value pairs 14 | // both unquoted foo=bar and quoted foo="some bar" are supported 15 | type StdExtractor struct { 16 | rxFields *regexp.Regexp 17 | } 18 | 19 | // Extract finds key-value pairs in the message and sets them as Fields 20 | // in the entry removing the pairs from the message. 21 | func (se *StdExtractor) Extract(e *Entry) error { 22 | if se.rxFields == nil { 23 | se.rxFields = regexp.MustCompile(fieldsRegex) 24 | } 25 | matches := se.rxFields.FindAllSubmatch(e.Message, -1) 26 | if matches == nil { 27 | return nil 28 | } 29 | 30 | var key, value []byte 31 | captures := make(map[string]interface{}) 32 | 33 | // Look for positions with: fmt.Printf("%#v \n", rxFields.SubexpNames()) 34 | // Will find positions []string{"", "key", "", "", "value", "", "quoted", ""} 35 | // 1 4 6 36 | 37 | for _, match := range matches { 38 | // First group, simple key-value detected 39 | if len(match[1]) > 0 && len(match[4]) > 0 { 40 | key, value = match[1], match[4] 41 | } 42 | 43 | // Second group, quoted value detected 44 | if len(match[1]) > 0 && len(match[6]) > 0 { 45 | key, value = match[1], match[6] 46 | value = value[1 : len(value)-1] // remove quotes, first and last character 47 | } 48 | 49 | captures[string(key)] = string(value) 50 | } 51 | 52 | if captures != nil { 53 | // Eliminate key=value from text and trim from the right 54 | e.Message = bytes.TrimRight(se.rxFields.ReplaceAll(e.Message, nil), " \n") 55 | for k, v := range captures { 56 | e.Fields[k] = v 57 | } 58 | } 59 | 60 | return nil 61 | } 62 | -------------------------------------------------------------------------------- /vendor/github.com/comail/colog/std_extractor_test.go: -------------------------------------------------------------------------------- 1 | package colog 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | type extractInOut struct { 8 | in string 9 | outMsg string 10 | outData map[string]interface{} 11 | } 12 | 13 | var extractorTests = []extractInOut{ 14 | { 15 | "some message foo=bar", 16 | "some message", 17 | map[string]interface{}{"foo": "bar"}, 18 | }, 19 | { 20 | "some message foo=42 foo2='other bar'", 21 | "some message", 22 | map[string]interface{}{ 23 | "foo": "42", 24 | "foo2": "other bar", 25 | }, 26 | }, 27 | { 28 | "some foo=42 otherfoo='other bar' mixed text", 29 | "some mixed text", 30 | map[string]interface{}{ 31 | "foo": "42", 32 | "otherfoo": "other bar", 33 | }, 34 | }, 35 | } 36 | 37 | func TestStdExtractor(t *testing.T) { 38 | stde := StdExtractor{} 39 | for _, tt := range extractorTests { 40 | e := &Entry{ 41 | Message: []byte(tt.in), 42 | Fields: make(Fields), 43 | } 44 | stde.Extract(e) 45 | if string(e.Message) != tt.outMsg { 46 | t.Errorf("Extract error:\n %s\n %s", string(e.Message), tt.outMsg) 47 | } 48 | for k, v := range tt.outData { 49 | if e.Fields[k] != v { 50 | t.Errorf("Invalid data value %s\n %s vs %s", k, v, e.Fields[k]) 51 | } 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /vendor/github.com/comail/colog/tty.go: -------------------------------------------------------------------------------- 1 | // +build !windows 2 | 3 | package colog 4 | 5 | import ( 6 | "syscall" 7 | "unsafe" 8 | ) 9 | 10 | // Use variable indirection for test stubbing 11 | var isTerminal = isTerminalFunc 12 | var terminalWidth = terminalWidthFunc 13 | 14 | // isTerminalFunc returns true if the given file descriptor is a terminal. 15 | func isTerminalFunc(fd int) bool { 16 | var termios syscall.Termios 17 | _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0) 18 | return err == 0 19 | } 20 | 21 | // terminalWidthFunc returns the width in characters of the terminal. 22 | func terminalWidthFunc(fd int) (width int) { 23 | var dimensions [4]uint16 24 | 25 | _, _, errno := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(syscall.TIOCGWINSZ), uintptr(unsafe.Pointer(&dimensions)), 0, 0, 0) 26 | if errno != 0 { 27 | return -1 28 | } 29 | 30 | return int(dimensions[1]) 31 | } 32 | -------------------------------------------------------------------------------- /vendor/github.com/comail/colog/tty_bsd.go: -------------------------------------------------------------------------------- 1 | // +build darwin dragonfly freebsd netbsd openbsd 2 | 3 | package colog 4 | 5 | import "syscall" 6 | 7 | const ioctlReadTermios = syscall.TIOCGETA 8 | -------------------------------------------------------------------------------- /vendor/github.com/comail/colog/tty_linux.go: -------------------------------------------------------------------------------- 1 | // +build linux 2 | 3 | package colog 4 | 5 | const ioctlReadTermios = 0x5401 6 | -------------------------------------------------------------------------------- /vendor/github.com/comail/colog/tty_windows.go: -------------------------------------------------------------------------------- 1 | package colog 2 | 3 | import ( 4 | "syscall" 5 | "unsafe" 6 | ) 7 | 8 | // Use variable indirection for test stubbing 9 | var isTerminal = isTerminalFunc 10 | var terminalWidth = terminalWidthFunc 11 | 12 | var kernel32 = syscall.NewLazyDLL("kernel32.dll") 13 | var procInfo = kernel32.NewProc("GetConsoleScreenBufferInfo") 14 | var procMode = kernel32.NewProc("GetConsoleMode") 15 | 16 | // Not applicable in windows 17 | // define constant to avoid compilation error 18 | const ioctlReadTermios = 0x0 19 | 20 | // isTerminalFunc returns true if the given file descriptor is a terminal. 21 | func isTerminalFunc(fd int) bool { 22 | var st uint32 23 | r, _, errno := syscall.Syscall(procMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0) 24 | if errno != 0 { 25 | return false 26 | } 27 | 28 | return r != 0 29 | } 30 | 31 | type short int16 32 | type word uint16 33 | 34 | type coord struct { 35 | x short 36 | y short 37 | } 38 | type rectangle struct { 39 | left short 40 | top short 41 | right short 42 | bottom short 43 | } 44 | 45 | type termInfo struct { 46 | size coord 47 | cursorPosition coord 48 | attributes word 49 | window rectangle 50 | maximumWindowSize coord 51 | } 52 | 53 | // terminalWidthFunc returns the width in characters of the terminal. 54 | func terminalWidthFunc(fd int) (width int) { 55 | var info termInfo 56 | _, _, errno := syscall.Syscall(procInfo.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&info)), 0) 57 | if errno != 0 { 58 | return -1 59 | } 60 | 61 | return int(info.size.x) 62 | } 63 | -------------------------------------------------------------------------------- /vendor/github.com/go-sql-driver/mysql/AUTHORS: -------------------------------------------------------------------------------- 1 | # This is the official list of Go-MySQL-Driver authors for copyright purposes. 2 | 3 | # If you are submitting a patch, please add your name or the name of the 4 | # organization which holds the copyright to this list in alphabetical order. 5 | 6 | # Names should be added to this file as 7 | # Name 8 | # The email address is not required for organizations. 9 | # Please keep the list sorted. 10 | 11 | 12 | # Individual Persons 13 | 14 | Aaron Hopkins 15 | Arne Hormann 16 | Carlos Nieto 17 | Chris Moos 18 | Daniel Nichter 19 | DisposaBoy 20 | Frederick Mayle 21 | Gustavo Kristic 22 | Hanno Braun 23 | Henri Yandell 24 | Hirotaka Yamamoto 25 | INADA Naoki 26 | James Harr 27 | Jian Zhen 28 | Joshua Prunier 29 | Julien Lefevre 30 | Julien Schmidt 31 | Kamil Dziedzic 32 | Kevin Malachowski 33 | Leonardo YongUk Kim 34 | Luca Looz 35 | Lucas Liu 36 | Luke Scott 37 | Michael Woolnough 38 | Nicola Peduzzi 39 | Runrioter Wung 40 | Soroush Pour 41 | Stan Putrya 42 | Stanley Gunawan 43 | Xiaobing Jiang 44 | Xiuming Chen 45 | 46 | # Organizations 47 | 48 | Barracuda Networks, Inc. 49 | Google Inc. 50 | Stripe Inc. 51 | -------------------------------------------------------------------------------- /vendor/github.com/go-sql-driver/mysql/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | ## Reporting Issues 4 | 5 | Before creating a new Issue, please check first if a similar Issue [already exists](https://github.com/go-sql-driver/mysql/issues?state=open) or was [recently closed](https://github.com/go-sql-driver/mysql/issues?direction=desc&page=1&sort=updated&state=closed). 6 | 7 | ## Contributing Code 8 | 9 | By contributing to this project, you share your code under the Mozilla Public License 2, as specified in the LICENSE file. 10 | Don't forget to add yourself to the AUTHORS file. 11 | 12 | ### Code Review 13 | 14 | Everyone is invited to review and comment on pull requests. 15 | If it looks fine to you, comment with "LGTM" (Looks good to me). 16 | 17 | If changes are required, notice the reviewers with "PTAL" (Please take another look) after committing the fixes. 18 | 19 | Before merging the Pull Request, at least one [team member](https://github.com/go-sql-driver?tab=members) must have commented with "LGTM". 20 | 21 | ## Development Ideas 22 | 23 | If you are looking for ideas for code contributions, please check our [Development Ideas](https://github.com/go-sql-driver/mysql/wiki/Development-Ideas) Wiki page. 24 | -------------------------------------------------------------------------------- /vendor/github.com/go-sql-driver/mysql/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Issue description 2 | Tell us what should happen and what happens instead 3 | 4 | ### Example code 5 | ```go 6 | If possible, please enter some example code here to reproduce the issue. 7 | ``` 8 | 9 | ### Error log 10 | ``` 11 | If you have an error log, please paste it here. 12 | ``` 13 | 14 | ### Configuration 15 | *Driver version (or git SHA):* 16 | 17 | *Go version:* run `go version` in your console 18 | 19 | *Server version:* E.g. MySQL 5.6, MariaDB 10.0.20 20 | 21 | *Server OS:* E.g. Debian 8.1 (Jessie), Windows 10 22 | -------------------------------------------------------------------------------- /vendor/github.com/go-sql-driver/mysql/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | Please explain the changes you made here. 3 | 4 | ### Checklist 5 | - [ ] Code compiles correctly 6 | - [ ] Created tests which fail without the change (if possible) 7 | - [ ] All tests passing 8 | - [ ] Extended the README / documentation, if necessary 9 | - [ ] Added myself / the copyright holder to the AUTHORS file 10 | -------------------------------------------------------------------------------- /vendor/github.com/go-sql-driver/mysql/appengine.go: -------------------------------------------------------------------------------- 1 | // Go MySQL Driver - A MySQL-Driver for Go's database/sql package 2 | // 3 | // Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla Public 6 | // License, v. 2.0. If a copy of the MPL was not distributed with this file, 7 | // You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | // +build appengine 10 | 11 | package mysql 12 | 13 | import ( 14 | "appengine/cloudsql" 15 | ) 16 | 17 | func init() { 18 | RegisterDial("cloudsql", cloudsql.Dial) 19 | } 20 | -------------------------------------------------------------------------------- /vendor/github.com/go-sql-driver/mysql/errors_test.go: -------------------------------------------------------------------------------- 1 | // Go MySQL Driver - A MySQL-Driver for Go's database/sql package 2 | // 3 | // Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla Public 6 | // License, v. 2.0. If a copy of the MPL was not distributed with this file, 7 | // You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | package mysql 10 | 11 | import ( 12 | "bytes" 13 | "log" 14 | "testing" 15 | ) 16 | 17 | func TestErrorsSetLogger(t *testing.T) { 18 | previous := errLog 19 | defer func() { 20 | errLog = previous 21 | }() 22 | 23 | // set up logger 24 | const expected = "prefix: test\n" 25 | buffer := bytes.NewBuffer(make([]byte, 0, 64)) 26 | logger := log.New(buffer, "prefix: ", 0) 27 | 28 | // print 29 | SetLogger(logger) 30 | errLog.Print("test") 31 | 32 | // check result 33 | if actual := buffer.String(); actual != expected { 34 | t.Errorf("expected %q, got %q", expected, actual) 35 | } 36 | } 37 | 38 | func TestErrorsStrictIgnoreNotes(t *testing.T) { 39 | runTests(t, dsn+"&sql_notes=false", func(dbt *DBTest) { 40 | dbt.mustExec("DROP TABLE IF EXISTS does_not_exist") 41 | }) 42 | } 43 | -------------------------------------------------------------------------------- /vendor/github.com/go-sql-driver/mysql/result.go: -------------------------------------------------------------------------------- 1 | // Go MySQL Driver - A MySQL-Driver for Go's database/sql package 2 | // 3 | // Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla Public 6 | // License, v. 2.0. If a copy of the MPL was not distributed with this file, 7 | // You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | package mysql 10 | 11 | type mysqlResult struct { 12 | affectedRows int64 13 | insertId int64 14 | } 15 | 16 | func (res *mysqlResult) LastInsertId() (int64, error) { 17 | return res.insertId, nil 18 | } 19 | 20 | func (res *mysqlResult) RowsAffected() (int64, error) { 21 | return res.affectedRows, nil 22 | } 23 | -------------------------------------------------------------------------------- /vendor/github.com/go-sql-driver/mysql/rows.go: -------------------------------------------------------------------------------- 1 | // Go MySQL Driver - A MySQL-Driver for Go's database/sql package 2 | // 3 | // Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla Public 6 | // License, v. 2.0. If a copy of the MPL was not distributed with this file, 7 | // You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | package mysql 10 | 11 | import ( 12 | "database/sql/driver" 13 | "io" 14 | ) 15 | 16 | type mysqlField struct { 17 | tableName string 18 | name string 19 | flags fieldFlag 20 | fieldType byte 21 | decimals byte 22 | } 23 | 24 | type mysqlRows struct { 25 | mc *mysqlConn 26 | columns []mysqlField 27 | } 28 | 29 | type binaryRows struct { 30 | mysqlRows 31 | } 32 | 33 | type textRows struct { 34 | mysqlRows 35 | } 36 | 37 | type emptyRows struct{} 38 | 39 | func (rows *mysqlRows) Columns() []string { 40 | columns := make([]string, len(rows.columns)) 41 | if rows.mc != nil && rows.mc.cfg.ColumnsWithAlias { 42 | for i := range columns { 43 | if tableName := rows.columns[i].tableName; len(tableName) > 0 { 44 | columns[i] = tableName + "." + rows.columns[i].name 45 | } else { 46 | columns[i] = rows.columns[i].name 47 | } 48 | } 49 | } else { 50 | for i := range columns { 51 | columns[i] = rows.columns[i].name 52 | } 53 | } 54 | return columns 55 | } 56 | 57 | func (rows *mysqlRows) Close() error { 58 | mc := rows.mc 59 | if mc == nil { 60 | return nil 61 | } 62 | if mc.netConn == nil { 63 | return ErrInvalidConn 64 | } 65 | 66 | // Remove unread packets from stream 67 | err := mc.readUntilEOF() 68 | if err == nil { 69 | if err = mc.discardResults(); err != nil { 70 | return err 71 | } 72 | } 73 | 74 | rows.mc = nil 75 | return err 76 | } 77 | 78 | func (rows *binaryRows) Next(dest []driver.Value) error { 79 | if mc := rows.mc; mc != nil { 80 | if mc.netConn == nil { 81 | return ErrInvalidConn 82 | } 83 | 84 | // Fetch next row from stream 85 | return rows.readRow(dest) 86 | } 87 | return io.EOF 88 | } 89 | 90 | func (rows *textRows) Next(dest []driver.Value) error { 91 | if mc := rows.mc; mc != nil { 92 | if mc.netConn == nil { 93 | return ErrInvalidConn 94 | } 95 | 96 | // Fetch next row from stream 97 | return rows.readRow(dest) 98 | } 99 | return io.EOF 100 | } 101 | 102 | func (rows emptyRows) Columns() []string { 103 | return nil 104 | } 105 | 106 | func (rows emptyRows) Close() error { 107 | return nil 108 | } 109 | 110 | func (rows emptyRows) Next(dest []driver.Value) error { 111 | return io.EOF 112 | } 113 | -------------------------------------------------------------------------------- /vendor/github.com/go-sql-driver/mysql/transaction.go: -------------------------------------------------------------------------------- 1 | // Go MySQL Driver - A MySQL-Driver for Go's database/sql package 2 | // 3 | // Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla Public 6 | // License, v. 2.0. If a copy of the MPL was not distributed with this file, 7 | // You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | package mysql 10 | 11 | type mysqlTx struct { 12 | mc *mysqlConn 13 | } 14 | 15 | func (tx *mysqlTx) Commit() (err error) { 16 | if tx.mc == nil || tx.mc.netConn == nil { 17 | return ErrInvalidConn 18 | } 19 | err = tx.mc.exec("COMMIT") 20 | tx.mc = nil 21 | return 22 | } 23 | 24 | func (tx *mysqlTx) Rollback() (err error) { 25 | if tx.mc == nil || tx.mc.netConn == nil { 26 | return ErrInvalidConn 27 | } 28 | err = tx.mc.exec("ROLLBACK") 29 | tx.mc = nil 30 | return 31 | } 32 | -------------------------------------------------------------------------------- /vendor/github.com/goji/context/README.md: -------------------------------------------------------------------------------- 1 | Context 2 | ======= 3 | 4 | [![GoDoc](https://godoc.org/github.com/goji/context?status.svg)](https://godoc.org/github.com/goji/context) 5 | 6 | Context provides a canonical way to use `go.net`'s [`context`][context] package 7 | with [Goji][goji]. It provides two-way bindings between `context.Context` 8 | objects and Goji's `web.C`, giving you a convenient way to look up Goji `Env` 9 | variables from the `context.Context` and allowing you to freely convert one 10 | request context to the other. 11 | 12 | [goji]: https://github.com/zenazn/goji 13 | [context]: http://godoc.org/code.google.com/p/go.net/context 14 | -------------------------------------------------------------------------------- /vendor/github.com/goji/context/bridge.go: -------------------------------------------------------------------------------- 1 | package context 2 | 3 | import ( 4 | "github.com/zenazn/goji/web" 5 | "golang.org/x/net/context" 6 | ) 7 | 8 | type private struct{} 9 | 10 | var ckey, contextkey private 11 | 12 | // FromC extracts the bound go.net/context.Context from a Goji context if one 13 | // has been set, or nil if one is not available. 14 | func FromC(c web.C) context.Context { 15 | if c.Env == nil { 16 | return nil 17 | } 18 | v, ok := c.Env[&ckey] 19 | if !ok { 20 | return nil 21 | } 22 | if ctx, ok := v.(context.Context); ok { 23 | return ctx 24 | } 25 | return nil 26 | } 27 | 28 | // ToC extracts the bound Goji context from a go.net/context.Context if one has 29 | // been set, or the empty Goji context if one is not available. 30 | func ToC(ctx context.Context) web.C { 31 | out := ctx.Value(&contextkey) 32 | if out == nil { 33 | return web.C{} 34 | } 35 | if c, ok := out.(*web.C); ok { 36 | return *c 37 | } 38 | return web.C{} 39 | } 40 | 41 | // Set makes a two-way binding between the given Goji request context and the 42 | // given go.net/context.Context. Returns the fresh context.Context that contains 43 | // this binding. Using the ToC and From functions will allow you to convert 44 | // between one and the other. 45 | // 46 | // Note that since context.Context's are immutable, you will have to call this 47 | // function to "re-bind" the request's canonical context.Context if you ever 48 | // decide to change it. 49 | func Set(c *web.C, context context.Context) context.Context { 50 | if c.Env == nil { 51 | c.Env = make(map[interface{}]interface{}) 52 | } 53 | 54 | ctx := ctx{c, context} 55 | c.Env[&ckey] = ctx 56 | return ctx 57 | } 58 | -------------------------------------------------------------------------------- /vendor/github.com/goji/context/context.go: -------------------------------------------------------------------------------- 1 | // Package context provides Goji integration with go.net/context. 2 | package context 3 | 4 | import ( 5 | "github.com/zenazn/goji/web" 6 | "golang.org/x/net/context" 7 | ) 8 | 9 | type ctx struct { 10 | c *web.C 11 | context.Context 12 | } 13 | 14 | func (c ctx) Value(key interface{}) interface{} { 15 | if key == &ckey { 16 | return c.c 17 | } 18 | if c.c.Env != nil { 19 | if v, ok := c.c.Env[key]; ok { 20 | return v 21 | } 22 | } 23 | return c.Context.Value(key) 24 | } 25 | -------------------------------------------------------------------------------- /vendor/github.com/goji/context/middleware.go: -------------------------------------------------------------------------------- 1 | package context 2 | 3 | import ( 4 | "net/http" 5 | 6 | "golang.org/x/net/context" 7 | 8 | "github.com/zenazn/goji/web" 9 | ) 10 | 11 | // Middleware is a Goji middleware that binds a new go.net/context.Context to 12 | // every request. This binding is two-way, and you can use the ToC and FromC 13 | // functions to convert between one and the other. 14 | // 15 | // Note that since context.Context's are immutable, you will have to call Set to 16 | // "re-bind" the request's canonical context.Context if you ever decide to 17 | // change it, otherwise only the original context.Context (as set by this 18 | // middleware) will be bound. 19 | func Middleware(c *web.C, h http.Handler) http.Handler { 20 | fn := func(w http.ResponseWriter, r *http.Request) { 21 | Set(c, context.Background()) 22 | h.ServeHTTP(w, r) 23 | } 24 | return http.HandlerFunc(fn) 25 | } 26 | -------------------------------------------------------------------------------- /vendor/github.com/jmoiron/sqlx/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013, Jason Moiron 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | -------------------------------------------------------------------------------- /vendor/github.com/jmoiron/sqlx/doc.go: -------------------------------------------------------------------------------- 1 | // Package sqlx provides general purpose extensions to database/sql. 2 | // 3 | // It is intended to seamlessly wrap database/sql and provide convenience 4 | // methods which are useful in the development of database driven applications. 5 | // None of the underlying database/sql methods are changed. Instead all extended 6 | // behavior is implemented through new methods defined on wrapper types. 7 | // 8 | // Additions include scanning into structs, named query support, rebinding 9 | // queries for different drivers, convenient shorthands for common error handling 10 | // and more. 11 | // 12 | package sqlx 13 | -------------------------------------------------------------------------------- /vendor/github.com/jmoiron/sqlx/reflectx/README.md: -------------------------------------------------------------------------------- 1 | # reflectx 2 | 3 | The sqlx package has special reflect needs. In particular, it needs to: 4 | 5 | * be able to map a name to a field 6 | * understand embedded structs 7 | * understand mapping names to fields by a particular tag 8 | * user specified name -> field mapping functions 9 | 10 | These behaviors mimic the behaviors by the standard library marshallers and also the 11 | behavior of standard Go accessors. 12 | 13 | The first two are amply taken care of by `Reflect.Value.FieldByName`, and the third is 14 | addressed by `Reflect.Value.FieldByNameFunc`, but these don't quite understand struct 15 | tags in the ways that are vital to most marshalers, and they are slow. 16 | 17 | This reflectx package extends reflect to achieve these goals. 18 | -------------------------------------------------------------------------------- /vendor/github.com/jmoiron/sqlx/types/README.md: -------------------------------------------------------------------------------- 1 | # types 2 | 3 | The types package provides some useful types which implement the `sql.Scanner` 4 | and `driver.Valuer` interfaces, suitable for use as scan and value targets with 5 | database/sql. 6 | -------------------------------------------------------------------------------- /vendor/github.com/jmoiron/sqlx/types/types.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "bytes" 5 | "compress/gzip" 6 | "database/sql/driver" 7 | "encoding/json" 8 | "errors" 9 | 10 | "io/ioutil" 11 | ) 12 | 13 | // GzippedText is a []byte which transparently gzips data being submitted to 14 | // a database and ungzips data being Scanned from a database. 15 | type GzippedText []byte 16 | 17 | // Value implements the driver.Valuer interface, gzipping the raw value of 18 | // this GzippedText. 19 | func (g GzippedText) Value() (driver.Value, error) { 20 | b := make([]byte, 0, len(g)) 21 | buf := bytes.NewBuffer(b) 22 | w := gzip.NewWriter(buf) 23 | w.Write(g) 24 | w.Close() 25 | return buf.Bytes(), nil 26 | 27 | } 28 | 29 | // Scan implements the sql.Scanner interface, ungzipping the value coming off 30 | // the wire and storing the raw result in the GzippedText. 31 | func (g *GzippedText) Scan(src interface{}) error { 32 | var source []byte 33 | switch src.(type) { 34 | case string: 35 | source = []byte(src.(string)) 36 | case []byte: 37 | source = src.([]byte) 38 | default: 39 | return errors.New("Incompatible type for GzippedText") 40 | } 41 | reader, err := gzip.NewReader(bytes.NewReader(source)) 42 | defer reader.Close() 43 | b, err := ioutil.ReadAll(reader) 44 | if err != nil { 45 | return err 46 | } 47 | *g = GzippedText(b) 48 | return nil 49 | } 50 | 51 | // JSONText is a json.RawMessage, which is a []byte underneath. 52 | // Value() validates the json format in the source, and returns an error if 53 | // the json is not valid. Scan does no validation. JSONText additionally 54 | // implements `Unmarshal`, which unmarshals the json within to an interface{} 55 | type JSONText json.RawMessage 56 | 57 | // MarshalJSON returns the *j as the JSON encoding of j. 58 | func (j *JSONText) MarshalJSON() ([]byte, error) { 59 | return *j, nil 60 | } 61 | 62 | // UnmarshalJSON sets *j to a copy of data 63 | func (j *JSONText) UnmarshalJSON(data []byte) error { 64 | if j == nil { 65 | return errors.New("JSONText: UnmarshalJSON on nil pointer") 66 | } 67 | *j = append((*j)[0:0], data...) 68 | return nil 69 | 70 | } 71 | 72 | // Value returns j as a value. This does a validating unmarshal into another 73 | // RawMessage. If j is invalid json, it returns an error. 74 | func (j JSONText) Value() (driver.Value, error) { 75 | var m json.RawMessage 76 | var err = j.Unmarshal(&m) 77 | if err != nil { 78 | return []byte{}, err 79 | } 80 | return []byte(j), nil 81 | } 82 | 83 | // Scan stores the src in *j. No validation is done. 84 | func (j *JSONText) Scan(src interface{}) error { 85 | var source []byte 86 | switch src.(type) { 87 | case string: 88 | source = []byte(src.(string)) 89 | case []byte: 90 | source = src.([]byte) 91 | default: 92 | return errors.New("Incompatible type for JSONText") 93 | } 94 | *j = JSONText(append((*j)[0:0], source...)) 95 | return nil 96 | } 97 | 98 | // Unmarshal unmarshal's the json in j to v, as in json.Unmarshal. 99 | func (j *JSONText) Unmarshal(v interface{}) error { 100 | return json.Unmarshal([]byte(*j), v) 101 | } 102 | 103 | // Pretty printing for JSONText types 104 | func (j JSONText) String() string { 105 | return string(j) 106 | } 107 | -------------------------------------------------------------------------------- /vendor/github.com/jmoiron/sqlx/types/types_test.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import "testing" 4 | 5 | func TestGzipText(t *testing.T) { 6 | g := GzippedText("Hello, world") 7 | v, err := g.Value() 8 | if err != nil { 9 | t.Errorf("Was not expecting an error") 10 | } 11 | err = (&g).Scan(v) 12 | if err != nil { 13 | t.Errorf("Was not expecting an error") 14 | } 15 | if string(g) != "Hello, world" { 16 | t.Errorf("Was expecting the string we sent in (Hello World), got %s", string(g)) 17 | } 18 | } 19 | 20 | func TestJSONText(t *testing.T) { 21 | j := JSONText(`{"foo": 1, "bar": 2}`) 22 | v, err := j.Value() 23 | if err != nil { 24 | t.Errorf("Was not expecting an error") 25 | } 26 | err = (&j).Scan(v) 27 | if err != nil { 28 | t.Errorf("Was not expecting an error") 29 | } 30 | m := map[string]interface{}{} 31 | j.Unmarshal(&m) 32 | 33 | if m["foo"].(float64) != 1 || m["bar"].(float64) != 2 { 34 | t.Errorf("Expected valid json but got some garbage instead? %#v", m) 35 | } 36 | 37 | j = JSONText(`{"foo": 1, invalid, false}`) 38 | v, err = j.Value() 39 | if err == nil { 40 | t.Errorf("Was expecting invalid json to fail!") 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /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.png?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=/var/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=/var/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 (deafbybeheading) 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/certs/README: -------------------------------------------------------------------------------- 1 | This directory contains certificates and private keys for testing some 2 | SSL-related functionality in Travis. Do NOT use these certificates for 3 | anything other than testing. 4 | -------------------------------------------------------------------------------- /vendor/github.com/lib/pq/certs/postgresql.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIICWwIBAAKBgQDjjAaacFRR0TQ0gznNolkPBe2N2A400JL0CU3ujHhVSST4POA0 3 | WAKy55RYwejlu9Gv9lTBQLGQcHkNNVScjxbpwvCS5mRJOMF2+EdmxFtKtqlDzsi+ 4 | bE0rlJc8VbzR0G63U66JXEtrhkC+wa4eZM6crocKaeXIIRK+rh32Rd8WpwIDAQAB 5 | AoGAM5dM6/kp9P700i8qjOgRPym96Zoh5nGfz/rIE5z/r36NBkdvIg8OVZfR96nH 6 | b0b9TOMR5lsPp0sI9yivTWvX6qyvLJRWy2vvx17hXK9NxXUNTAm0PYZUTvCtcPeX 7 | RnJpzQKNZQPkFzF0uXBc4CtPK2Vz0+FGvAelrhYAxnw1dIkCQQD+9qaW5QhXjsjb 8 | Nl85CmXgxPmGROcgLQCO+omfrjf9UXrituU9Dz6auym5lDGEdMFnkzfr+wpasEy9 9 | mf5ZZOhDAkEA5HjXfVGaCtpydOt6hDon/uZsyssCK2lQ7NSuE3vP+sUsYMzIpEoy 10 | t3VWXqKbo+g9KNDTP4WEliqp1aiSIylzzQJANPeqzihQnlgEdD4MdD4rwhFJwVIp 11 | Le8Lcais1KaN7StzOwxB/XhgSibd2TbnPpw+3bSg5n5lvUdo+e62/31OHwJAU1jS 12 | I+F09KikQIr28u3UUWT2IzTT4cpVv1AHAQyV3sG3YsjSGT0IK20eyP9BEBZU2WL0 13 | 7aNjrvR5aHxKc5FXsQJABsFtyGpgI5X4xufkJZVZ+Mklz2n7iXa+XPatMAHFxAtb 14 | EEMt60rngwMjXAzBSC6OYuYogRRAY3UCacNC5VhLYQ== 15 | -----END RSA PRIVATE KEY----- 16 | -------------------------------------------------------------------------------- /vendor/github.com/lib/pq/certs/root.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIEAzCCAuugAwIBAgIJANmheROCdW1NMA0GCSqGSIb3DQEBBQUAMF4xCzAJBgNV 3 | BAYTAlVTMQ8wDQYDVQQIEwZOZXZhZGExEjAQBgNVBAcTCUxhcyBWZWdhczEaMBgG 4 | A1UEChMRZ2l0aHViLmNvbS9saWIvcHExDjAMBgNVBAMTBXBxIENBMB4XDTE0MTAx 5 | MTE1MDQyOVoXDTI0MTAwODE1MDQyOVowXjELMAkGA1UEBhMCVVMxDzANBgNVBAgT 6 | Bk5ldmFkYTESMBAGA1UEBxMJTGFzIFZlZ2FzMRowGAYDVQQKExFnaXRodWIuY29t 7 | L2xpYi9wcTEOMAwGA1UEAxMFcHEgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw 8 | ggEKAoIBAQCV4PxP7ShzWBzUCThcKk3qZtOLtHmszQVtbqhvgTpm1kTRtKBdVMu0 9 | pLAHQ3JgJCnAYgH0iZxVGoMP16T3irdgsdC48+nNTFM2T0cCdkfDURGIhSFN47cb 10 | Pgy306BcDUD2q7ucW33+dlFSRuGVewocoh4BWM/vMtMvvWzdi4Ag/L/jhb+5wZxZ 11 | sWymsadOVSDePEMKOvlCa3EdVwVFV40TVyDb+iWBUivDAYsS2a3KajuJrO6MbZiE 12 | Sp2RCIkZS2zFmzWxVRi9ZhzIZhh7EVF9JAaNC3T52jhGUdlRq3YpBTMnd89iOh74 13 | 6jWXG7wSuPj3haFzyNhmJ0ZUh+2Ynoh1AgMBAAGjgcMwgcAwHQYDVR0OBBYEFFKT 14 | 7R52Cp9lT94ZZsHVIkA1y6ByMIGQBgNVHSMEgYgwgYWAFFKT7R52Cp9lT94ZZsHV 15 | IkA1y6ByoWKkYDBeMQswCQYDVQQGEwJVUzEPMA0GA1UECBMGTmV2YWRhMRIwEAYD 16 | VQQHEwlMYXMgVmVnYXMxGjAYBgNVBAoTEWdpdGh1Yi5jb20vbGliL3BxMQ4wDAYD 17 | VQQDEwVwcSBDQYIJANmheROCdW1NMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEF 18 | BQADggEBAAEhCLWkqJNMI8b4gkbmj5fqQ/4+oO83bZ3w2Oqf6eZ8I8BC4f2NOyE6 19 | tRUlq5+aU7eqC1cOAvGjO+YHN/bF/DFpwLlzvUSXt+JP/pYcUjL7v+pIvwqec9hD 20 | ndvM4iIbkD/H/OYQ3L+N3W+G1x7AcFIX+bGCb3PzYVQAjxreV6//wgKBosMGFbZo 21 | HPxT9RPMun61SViF04H5TNs0derVn1+5eiiYENeAhJzQNyZoOOUuX1X/Inx9bEPh 22 | C5vFBtSMgIytPgieRJVWAiMLYsfpIAStrHztRAbBs2DU01LmMgRvHdxgFEKinC/d 23 | UHZZQDP+6pT+zADrGhQGXe4eThaO6f0= 24 | -----END CERTIFICATE----- 25 | -------------------------------------------------------------------------------- /vendor/github.com/lib/pq/certs/server.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEogIBAAKCAQEA14pMhfsXpTyP4HIRKc4/sB8/fcbuf6f8Ais1RwimPZDfXFYU 3 | lADHbdHS4mGVd7jjpmYx+R8hfWLhJ9qUN2FK6mNToGG4nLul4ue3ptgPBQTHKeLq 4 | SSt/3hUAphhwUMcM3pr5Wpaw4ZQGxm1KITu0D6VtkoY0sk7XDqcZwHcLe4fIkt5C 5 | /4bSt5qk1BUjyq2laSG4zn5my4Vdue2LLQmNlOQEHnLs79B2kBVapPeRS+nOTp1d 6 | mnAXnNjpc4PqPWGZps2skUBaiHflTiqOPRPz+ThvgWuKlcoOB6tv2rSM2f+qeAOq 7 | x8LPb2SS09iD1a/xIxinLnsXC+d98fqoQaMEVwIDAQABAoIBAF3ZoihUhJ82F4+r 8 | Gz4QyDpv4L1reT2sb1aiabhcU8ZK5nbWJG+tRyjSS/i2dNaEcttpdCj9HR/zhgZM 9 | bm0OuAgG58rVwgS80CZUruq++Qs+YVojq8/gWPTiQD4SNhV2Fmx3HkwLgUk3oxuT 10 | SsvdqzGE3okGVrutCIcgy126eA147VPMoej1Bb3fO6npqK0pFPhZfAc0YoqJuM+k 11 | obRm5pAnGUipyLCFXjA9HYPKwYZw2RtfdA3CiImHeanSdqS+ctrC9y8BV40Th7gZ 12 | haXdKUNdjmIxV695QQ1mkGqpKLZFqhzKioGQ2/Ly2d1iaKN9fZltTusu8unepWJ2 13 | tlT9qMECgYEA9uHaF1t2CqE+AJvWTihHhPIIuLxoOQXYea1qvxfcH/UMtaLKzCNm 14 | lQ5pqCGsPvp+10f36yttO1ZehIvlVNXuJsjt0zJmPtIolNuJY76yeussfQ9jHheB 15 | 5uPEzCFlHzxYbBUyqgWaF6W74okRGzEGJXjYSP0yHPPdU4ep2q3bGiUCgYEA34Af 16 | wBSuQSK7uLxArWHvQhyuvi43ZGXls6oRGl+Ysj54s8BP6XGkq9hEJ6G4yxgyV+BR 17 | DUOs5X8/TLT8POuIMYvKTQthQyCk0eLv2FLdESDuuKx0kBVY3s8lK3/z5HhrdOiN 18 | VMNZU+xDKgKc3hN9ypkk8vcZe6EtH7Y14e0rVcsCgYBTgxi8F/M5K0wG9rAqphNz 19 | VFBA9XKn/2M33cKjO5X5tXIEKzpAjaUQvNxexG04rJGljzG8+mar0M6ONahw5yD1 20 | O7i/XWgazgpuOEkkVYiYbd8RutfDgR4vFVMn3hAP3eDnRtBplRWH9Ec3HTiNIys6 21 | F8PKBOQjyRZQQC7jyzW3hQKBgACe5HeuFwXLSOYsb6mLmhR+6+VPT4wR1F95W27N 22 | USk9jyxAnngxfpmTkiziABdgS9N+pfr5cyN4BP77ia/Jn6kzkC5Cl9SN5KdIkA3z 23 | vPVtN/x/ThuQU5zaymmig1ThGLtMYggYOslG4LDfLPxY5YKIhle+Y+259twdr2yf 24 | Mf2dAoGAaGv3tWMgnIdGRk6EQL/yb9PKHo7ShN+tKNlGaK7WwzBdKs+Fe8jkgcr7 25 | pz4Ne887CmxejdISzOCcdT+Zm9Bx6I/uZwWOtDvWpIgIxVX9a9URj/+D1MxTE/y4 26 | d6H+c89yDY62I2+drMpdjCd3EtCaTlxpTbRS+s1eAHMH7aEkcCE= 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /vendor/github.com/lib/pq/hstore/hstore.go: -------------------------------------------------------------------------------- 1 | package hstore 2 | 3 | import ( 4 | "database/sql" 5 | "database/sql/driver" 6 | "strings" 7 | ) 8 | 9 | // A wrapper for transferring Hstore values back and forth easily. 10 | type Hstore struct { 11 | Map map[string]sql.NullString 12 | } 13 | 14 | // escapes and quotes hstore keys/values 15 | // s should be a sql.NullString or string 16 | func hQuote(s interface{}) string { 17 | var str string 18 | switch v := s.(type) { 19 | case sql.NullString: 20 | if !v.Valid { 21 | return "NULL" 22 | } 23 | str = v.String 24 | case string: 25 | str = v 26 | default: 27 | panic("not a string or sql.NullString") 28 | } 29 | 30 | str = strings.Replace(str, "\\", "\\\\", -1) 31 | return `"` + strings.Replace(str, "\"", "\\\"", -1) + `"` 32 | } 33 | 34 | // Scan implements the Scanner interface. 35 | // 36 | // Note h.Map is reallocated before the scan to clear existing values. If the 37 | // hstore column's database value is NULL, then h.Map is set to nil instead. 38 | func (h *Hstore) Scan(value interface{}) error { 39 | if value == nil { 40 | h.Map = nil 41 | return nil 42 | } 43 | h.Map = make(map[string]sql.NullString) 44 | var b byte 45 | pair := [][]byte{{}, {}} 46 | pi := 0 47 | inQuote := false 48 | didQuote := false 49 | sawSlash := false 50 | bindex := 0 51 | for bindex, b = range value.([]byte) { 52 | if sawSlash { 53 | pair[pi] = append(pair[pi], b) 54 | sawSlash = false 55 | continue 56 | } 57 | 58 | switch b { 59 | case '\\': 60 | sawSlash = true 61 | continue 62 | case '"': 63 | inQuote = !inQuote 64 | if !didQuote { 65 | didQuote = true 66 | } 67 | continue 68 | default: 69 | if !inQuote { 70 | switch b { 71 | case ' ', '\t', '\n', '\r': 72 | continue 73 | case '=': 74 | continue 75 | case '>': 76 | pi = 1 77 | didQuote = false 78 | continue 79 | case ',': 80 | s := string(pair[1]) 81 | if !didQuote && len(s) == 4 && strings.ToLower(s) == "null" { 82 | h.Map[string(pair[0])] = sql.NullString{String: "", Valid: false} 83 | } else { 84 | h.Map[string(pair[0])] = sql.NullString{String: string(pair[1]), Valid: true} 85 | } 86 | pair[0] = []byte{} 87 | pair[1] = []byte{} 88 | pi = 0 89 | continue 90 | } 91 | } 92 | } 93 | pair[pi] = append(pair[pi], b) 94 | } 95 | if bindex > 0 { 96 | s := string(pair[1]) 97 | if !didQuote && len(s) == 4 && strings.ToLower(s) == "null" { 98 | h.Map[string(pair[0])] = sql.NullString{String: "", Valid: false} 99 | } else { 100 | h.Map[string(pair[0])] = sql.NullString{String: string(pair[1]), Valid: true} 101 | } 102 | } 103 | return nil 104 | } 105 | 106 | // Value implements the driver Valuer interface. Note if h.Map is nil, the 107 | // database column value will be set to NULL. 108 | func (h Hstore) Value() (driver.Value, error) { 109 | if h.Map == nil { 110 | return nil, nil 111 | } 112 | parts := []string{} 113 | for key, val := range h.Map { 114 | thispart := hQuote(key) + "=>" + hQuote(val) 115 | parts = append(parts, thispart) 116 | } 117 | return []byte(strings.Join(parts, ",")), nil 118 | } 119 | -------------------------------------------------------------------------------- /vendor/github.com/lib/pq/listen_example/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Below you will find a self-contained Go program which uses the LISTEN / NOTIFY 4 | mechanism to avoid polling the database while waiting for more work to arrive. 5 | 6 | // 7 | // You can see the program in action by defining a function similar to 8 | // the following: 9 | // 10 | // CREATE OR REPLACE FUNCTION public.get_work() 11 | // RETURNS bigint 12 | // LANGUAGE sql 13 | // AS $$ 14 | // SELECT CASE WHEN random() >= 0.2 THEN int8 '1' END 15 | // $$ 16 | // ; 17 | 18 | package main 19 | 20 | import ( 21 | "database/sql" 22 | "fmt" 23 | "time" 24 | 25 | "github.com/lib/pq" 26 | ) 27 | 28 | func doWork(db *sql.DB, work int64) { 29 | // work here 30 | } 31 | 32 | func getWork(db *sql.DB) { 33 | for { 34 | // get work from the database here 35 | var work sql.NullInt64 36 | err := db.QueryRow("SELECT get_work()").Scan(&work) 37 | if err != nil { 38 | fmt.Println("call to get_work() failed: ", err) 39 | time.Sleep(10 * time.Second) 40 | continue 41 | } 42 | if !work.Valid { 43 | // no more work to do 44 | fmt.Println("ran out of work") 45 | return 46 | } 47 | 48 | fmt.Println("starting work on ", work.Int64) 49 | go doWork(db, work.Int64) 50 | } 51 | } 52 | 53 | func waitForNotification(l *pq.Listener) { 54 | for { 55 | select { 56 | case <-l.Notify: 57 | fmt.Println("received notification, new work available") 58 | return 59 | case <-time.After(90 * time.Second): 60 | go func() { 61 | l.Ping() 62 | }() 63 | // Check if there's more work available, just in case it takes 64 | // a while for the Listener to notice connection loss and 65 | // reconnect. 66 | fmt.Println("received no work for 90 seconds, checking for new work") 67 | return 68 | } 69 | } 70 | } 71 | 72 | func main() { 73 | var conninfo string = "" 74 | 75 | db, err := sql.Open("postgres", conninfo) 76 | if err != nil { 77 | panic(err) 78 | } 79 | 80 | reportProblem := func(ev pq.ListenerEventType, err error) { 81 | if err != nil { 82 | fmt.Println(err.Error()) 83 | } 84 | } 85 | 86 | listener := pq.NewListener(conninfo, 10 * time.Second, time.Minute, reportProblem) 87 | err = listener.Listen("getwork") 88 | if err != nil { 89 | panic(err) 90 | } 91 | 92 | fmt.Println("entering main loop") 93 | for { 94 | // process all available work before waiting for notifications 95 | getWork(db) 96 | waitForNotification(listener) 97 | } 98 | } 99 | 100 | 101 | */ 102 | package listen_example 103 | -------------------------------------------------------------------------------- /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/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/url_test.go: -------------------------------------------------------------------------------- 1 | package pq 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestSimpleParseURL(t *testing.T) { 8 | expected := "host=hostname.remote" 9 | str, err := ParseURL("postgres://hostname.remote") 10 | if err != nil { 11 | t.Fatal(err) 12 | } 13 | 14 | if str != expected { 15 | t.Fatalf("unexpected result from ParseURL:\n+ %v\n- %v", str, expected) 16 | } 17 | } 18 | 19 | func TestIPv6LoopbackParseURL(t *testing.T) { 20 | expected := "host=::1 port=1234" 21 | str, err := ParseURL("postgres://[::1]:1234") 22 | if err != nil { 23 | t.Fatal(err) 24 | } 25 | 26 | if str != expected { 27 | t.Fatalf("unexpected result from ParseURL:\n+ %v\n- %v", str, expected) 28 | } 29 | } 30 | 31 | func TestFullParseURL(t *testing.T) { 32 | expected := `dbname=database host=hostname.remote password=top\ secret port=1234 user=username` 33 | str, err := ParseURL("postgres://username:top%20secret@hostname.remote:1234/database") 34 | if err != nil { 35 | t.Fatal(err) 36 | } 37 | 38 | if str != expected { 39 | t.Fatalf("unexpected result from ParseURL:\n+ %s\n- %s", str, expected) 40 | } 41 | } 42 | 43 | func TestInvalidProtocolParseURL(t *testing.T) { 44 | _, err := ParseURL("http://hostname.remote") 45 | switch err { 46 | case nil: 47 | t.Fatal("Expected an error from parsing invalid protocol") 48 | default: 49 | msg := "invalid connection protocol: http" 50 | if err.Error() != msg { 51 | t.Fatalf("Unexpected error message:\n+ %s\n- %s", 52 | err.Error(), msg) 53 | } 54 | } 55 | } 56 | 57 | func TestMinimalURL(t *testing.T) { 58 | cs, err := ParseURL("postgres://") 59 | if err != nil { 60 | t.Fatal(err) 61 | } 62 | 63 | if cs != "" { 64 | t.Fatalf("expected blank connection string, got: %q", cs) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /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 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/mattn/go-sqlite3/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Yasuhiro Matsumoto 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 | -------------------------------------------------------------------------------- /vendor/github.com/mattn/go-sqlite3/README.md: -------------------------------------------------------------------------------- 1 | go-sqlite3 2 | ========== 3 | 4 | [![Build Status](https://travis-ci.org/mattn/go-sqlite3.svg?branch=master)](https://travis-ci.org/mattn/go-sqlite3) 5 | [![Coverage Status](https://coveralls.io/repos/mattn/go-sqlite3/badge.svg?branch=master)](https://coveralls.io/r/mattn/go-sqlite3?branch=master) 6 | [![GoDoc](https://godoc.org/github.com/mattn/go-sqlite3?status.svg)](http://godoc.org/github.com/mattn/go-sqlite3) 7 | 8 | Description 9 | ----------- 10 | 11 | sqlite3 driver conforming to the built-in database/sql interface 12 | 13 | Installation 14 | ------------ 15 | 16 | This package can be installed with the go get command: 17 | 18 | go get github.com/mattn/go-sqlite3 19 | 20 | _go-sqlite3_ is *cgo* package. 21 | If you want to build your app using go-sqlite3, you need gcc. 22 | However, if you install _go-sqlite3_ with `go install github.com/mattn/go-sqlite3`, you don't need gcc to build your app anymore. 23 | 24 | Documentation 25 | ------------- 26 | 27 | API documentation can be found here: http://godoc.org/github.com/mattn/go-sqlite3 28 | 29 | Examples can be found under the `./_example` directory 30 | 31 | FAQ 32 | --- 33 | 34 | * Want to build go-sqlite3 with libsqlite3 on my linux. 35 | 36 | Use `go build --tags "libsqlite3 linux"` 37 | 38 | * Want to build go-sqlite3 with icu extension. 39 | 40 | Use `go build --tags "icu"` 41 | 42 | * Can't build go-sqlite3 on windows 64bit. 43 | 44 | > Probably, you are using go 1.0, go1.0 has a problem when it comes to compiling/linking on windows 64bit. 45 | > See: https://github.com/mattn/go-sqlite3/issues/27 46 | 47 | * Getting insert error while query is opened. 48 | 49 | > You can pass some arguments into the connection string, for example, a URI. 50 | > See: https://github.com/mattn/go-sqlite3/issues/39 51 | 52 | * Do you want to cross compile? mingw on Linux or Mac? 53 | 54 | > See: https://github.com/mattn/go-sqlite3/issues/106 55 | > See also: http://www.limitlessfx.com/cross-compile-golang-app-for-windows-from-linux.html 56 | 57 | * Want to get time.Time with current locale 58 | 59 | Use `loc=auto` in SQLite3 filename schema like `file:foo.db?loc=auto`. 60 | 61 | License 62 | ------- 63 | 64 | MIT: http://mattn.mit-license.org/2012 65 | 66 | sqlite3-binding.c, sqlite3-binding.h, sqlite3ext.h 67 | 68 | The -binding suffix was added to avoid build failures under gccgo. 69 | 70 | In this repository, those files are an amalgamation of code that was copied from SQLite3. The license of that code is the same as the license of SQLite3. 71 | 72 | Author 73 | ------ 74 | 75 | Yasuhiro Matsumoto (a.k.a mattn) 76 | -------------------------------------------------------------------------------- /vendor/github.com/mattn/go-sqlite3/_example/custom_func/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "database/sql" 5 | "fmt" 6 | "log" 7 | "math" 8 | "math/rand" 9 | 10 | sqlite "github.com/mattn/go-sqlite3" 11 | ) 12 | 13 | // Computes x^y 14 | func pow(x, y int64) int64 { 15 | return int64(math.Pow(float64(x), float64(y))) 16 | } 17 | 18 | // Computes the bitwise exclusive-or of all its arguments 19 | func xor(xs ...int64) int64 { 20 | var ret int64 21 | for _, x := range xs { 22 | ret ^= x 23 | } 24 | return ret 25 | } 26 | 27 | // Returns a random number. It's actually deterministic here because 28 | // we don't seed the RNG, but it's an example of a non-pure function 29 | // from SQLite's POV. 30 | func getrand() int64 { 31 | return rand.Int63() 32 | } 33 | 34 | // Computes the standard deviation of a GROUPed BY set of values 35 | type stddev struct { 36 | xs []int64 37 | // Running average calculation 38 | sum int64 39 | n int64 40 | } 41 | 42 | func newStddev() *stddev { return &stddev{} } 43 | 44 | func (s *stddev) Step(x int64) { 45 | s.xs = append(s.xs, x) 46 | s.sum += x 47 | s.n++ 48 | } 49 | 50 | func (s *stddev) Done() float64 { 51 | mean := float64(s.sum) / float64(s.n) 52 | var sqDiff []float64 53 | for _, x := range s.xs { 54 | sqDiff = append(sqDiff, math.Pow(float64(x)-mean, 2)) 55 | } 56 | var dev float64 57 | for _, x := range sqDiff { 58 | dev += x 59 | } 60 | dev /= float64(len(sqDiff)) 61 | return math.Sqrt(dev) 62 | } 63 | 64 | func main() { 65 | sql.Register("sqlite3_custom", &sqlite.SQLiteDriver{ 66 | ConnectHook: func(conn *sqlite.SQLiteConn) error { 67 | if err := conn.RegisterFunc("pow", pow, true); err != nil { 68 | return err 69 | } 70 | if err := conn.RegisterFunc("xor", xor, true); err != nil { 71 | return err 72 | } 73 | if err := conn.RegisterFunc("rand", getrand, false); err != nil { 74 | return err 75 | } 76 | if err := conn.RegisterAggregator("stddev", newStddev, true); err != nil { 77 | return err 78 | } 79 | return nil 80 | }, 81 | }) 82 | 83 | db, err := sql.Open("sqlite3_custom", ":memory:") 84 | if err != nil { 85 | log.Fatal("Failed to open database:", err) 86 | } 87 | defer db.Close() 88 | 89 | var i int64 90 | err = db.QueryRow("SELECT pow(2,3)").Scan(&i) 91 | if err != nil { 92 | log.Fatal("POW query error:", err) 93 | } 94 | fmt.Println("pow(2,3) =", i) // 8 95 | 96 | err = db.QueryRow("SELECT xor(1,2,3,4,5,6)").Scan(&i) 97 | if err != nil { 98 | log.Fatal("XOR query error:", err) 99 | } 100 | fmt.Println("xor(1,2,3,4,5) =", i) // 7 101 | 102 | err = db.QueryRow("SELECT rand()").Scan(&i) 103 | if err != nil { 104 | log.Fatal("RAND query error:", err) 105 | } 106 | fmt.Println("rand() =", i) // pseudorandom 107 | 108 | _, err = db.Exec("create table foo (department integer, profits integer)") 109 | if err != nil { 110 | log.Fatal("Failed to create table:", err) 111 | } 112 | _, err = db.Exec("insert into foo values (1, 10), (1, 20), (1, 45), (2, 42), (2, 115)") 113 | if err != nil { 114 | log.Fatal("Failed to insert records:", err) 115 | } 116 | 117 | rows, err := db.Query("select department, stddev(profits) from foo group by department") 118 | if err != nil { 119 | log.Fatal("STDDEV query error:", err) 120 | } 121 | defer rows.Close() 122 | for rows.Next() { 123 | var dept int64 124 | var dev float64 125 | if err := rows.Scan(&dept, &dev); err != nil { 126 | log.Fatal(err) 127 | } 128 | fmt.Printf("dept=%d stddev=%f\n", dept, dev) 129 | } 130 | if err := rows.Err(); err != nil { 131 | log.Fatal(err) 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /vendor/github.com/mattn/go-sqlite3/_example/hook/hook.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "database/sql" 5 | "github.com/mattn/go-sqlite3" 6 | "log" 7 | "os" 8 | ) 9 | 10 | func main() { 11 | sqlite3conn := []*sqlite3.SQLiteConn{} 12 | sql.Register("sqlite3_with_hook_example", 13 | &sqlite3.SQLiteDriver{ 14 | ConnectHook: func(conn *sqlite3.SQLiteConn) error { 15 | sqlite3conn = append(sqlite3conn, conn) 16 | return nil 17 | }, 18 | }) 19 | os.Remove("./foo.db") 20 | os.Remove("./bar.db") 21 | 22 | destDb, err := sql.Open("sqlite3_with_hook_example", "./foo.db") 23 | if err != nil { 24 | log.Fatal(err) 25 | } 26 | defer destDb.Close() 27 | destDb.Ping() 28 | 29 | _, err = destDb.Exec("create table foo(id int, value text)") 30 | if err != nil { 31 | log.Fatal(err) 32 | } 33 | _, err = destDb.Exec("insert into foo values(1, 'foo')") 34 | if err != nil { 35 | log.Fatal(err) 36 | } 37 | _, err = destDb.Exec("insert into foo values(2, 'bar')") 38 | if err != nil { 39 | log.Fatal(err) 40 | } 41 | _, err = destDb.Query("select * from foo") 42 | if err != nil { 43 | log.Fatal(err) 44 | } 45 | srcDb, err := sql.Open("sqlite3_with_hook_example", "./bar.db") 46 | if err != nil { 47 | log.Fatal(err) 48 | } 49 | defer srcDb.Close() 50 | srcDb.Ping() 51 | 52 | bk, err := sqlite3conn[1].Backup("main", sqlite3conn[0], "main") 53 | if err != nil { 54 | log.Fatal(err) 55 | } 56 | 57 | _, err = bk.Step(-1) 58 | if err != nil { 59 | log.Fatal(err) 60 | } 61 | _, err = destDb.Query("select * from foo") 62 | if err != nil { 63 | log.Fatal(err) 64 | } 65 | _, err = destDb.Exec("insert into foo values(3, 'bar')") 66 | if err != nil { 67 | log.Fatal(err) 68 | } 69 | 70 | bk.Finish() 71 | } 72 | -------------------------------------------------------------------------------- /vendor/github.com/mattn/go-sqlite3/_example/mod_regexp/Makefile: -------------------------------------------------------------------------------- 1 | ifeq ($(OS),Windows_NT) 2 | EXE=extension.exe 3 | EXT=sqlite3_mod_regexp.dll 4 | RM=cmd /c del 5 | LDFLAG= 6 | else 7 | EXE=extension 8 | EXT=sqlite3_mod_regexp.so 9 | RM=rm 10 | LDFLAG=-fPIC 11 | endif 12 | 13 | all : $(EXE) $(EXT) 14 | 15 | $(EXE) : extension.go 16 | go build $< 17 | 18 | $(EXT) : sqlite3_mod_regexp.c 19 | gcc $(LDFLAG) -shared -o $@ $< -lsqlite3 -lpcre 20 | 21 | clean : 22 | @-$(RM) $(EXE) $(EXT) 23 | -------------------------------------------------------------------------------- /vendor/github.com/mattn/go-sqlite3/_example/mod_regexp/extension.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "database/sql" 5 | "fmt" 6 | "github.com/mattn/go-sqlite3" 7 | "log" 8 | ) 9 | 10 | func main() { 11 | sql.Register("sqlite3_with_extensions", 12 | &sqlite3.SQLiteDriver{ 13 | Extensions: []string{ 14 | "sqlite3_mod_regexp", 15 | }, 16 | }) 17 | 18 | db, err := sql.Open("sqlite3_with_extensions", ":memory:") 19 | if err != nil { 20 | log.Fatal(err) 21 | } 22 | defer db.Close() 23 | 24 | // Force db to make a new connection in pool 25 | // by putting the original in a transaction 26 | tx, err := db.Begin() 27 | if err != nil { 28 | log.Fatal(err) 29 | } 30 | defer tx.Commit() 31 | 32 | // New connection works (hopefully!) 33 | rows, err := db.Query("select 'hello world' where 'hello world' regexp '^hello.*d$'") 34 | if err != nil { 35 | log.Fatal(err) 36 | } 37 | defer rows.Close() 38 | for rows.Next() { 39 | var helloworld string 40 | rows.Scan(&helloworld) 41 | fmt.Println(helloworld) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /vendor/github.com/mattn/go-sqlite3/_example/mod_regexp/sqlite3_mod_regexp.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | SQLITE_EXTENSION_INIT1 7 | static void regexp_func(sqlite3_context *context, int argc, sqlite3_value **argv) { 8 | if (argc >= 2) { 9 | const char *target = (const char *)sqlite3_value_text(argv[1]); 10 | const char *pattern = (const char *)sqlite3_value_text(argv[0]); 11 | const char* errstr = NULL; 12 | int erroff = 0; 13 | int vec[500]; 14 | int n, rc; 15 | pcre* re = pcre_compile(pattern, 0, &errstr, &erroff, NULL); 16 | rc = pcre_exec(re, NULL, target, strlen(target), 0, 0, vec, 500); 17 | if (rc <= 0) { 18 | sqlite3_result_error(context, errstr, 0); 19 | return; 20 | } 21 | sqlite3_result_int(context, 1); 22 | } 23 | } 24 | 25 | #ifdef _WIN32 26 | __declspec(dllexport) 27 | #endif 28 | int sqlite3_extension_init(sqlite3 *db, char **errmsg, const sqlite3_api_routines *api) { 29 | SQLITE_EXTENSION_INIT2(api); 30 | return sqlite3_create_function(db, "regexp", 2, SQLITE_UTF8, (void*)db, regexp_func, NULL, NULL); 31 | } 32 | -------------------------------------------------------------------------------- /vendor/github.com/mattn/go-sqlite3/_example/mod_vtable/Makefile: -------------------------------------------------------------------------------- 1 | ifeq ($(OS),Windows_NT) 2 | EXE=extension.exe 3 | EXT=sqlite3_mod_vtable.dll 4 | RM=cmd /c del 5 | LIBCURL=-lcurldll 6 | LDFLAG= 7 | else 8 | EXE=extension 9 | EXT=sqlite3_mod_vtable.so 10 | RM=rm 11 | LDFLAG=-fPIC 12 | LIBCURL=-lcurl 13 | endif 14 | 15 | all : $(EXE) $(EXT) 16 | 17 | $(EXE) : extension.go 18 | go build $< 19 | 20 | $(EXT) : sqlite3_mod_vtable.cc 21 | g++ $(LDFLAG) -shared -o $@ $< -lsqlite3 $(LIBCURL) 22 | 23 | clean : 24 | @-$(RM) $(EXE) $(EXT) 25 | -------------------------------------------------------------------------------- /vendor/github.com/mattn/go-sqlite3/_example/mod_vtable/extension.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "database/sql" 5 | "fmt" 6 | "github.com/mattn/go-sqlite3" 7 | "log" 8 | ) 9 | 10 | func main() { 11 | sql.Register("sqlite3_with_extensions", 12 | &sqlite3.SQLiteDriver{ 13 | Extensions: []string{ 14 | "sqlite3_mod_vtable", 15 | }, 16 | }) 17 | 18 | db, err := sql.Open("sqlite3_with_extensions", ":memory:") 19 | if err != nil { 20 | log.Fatal(err) 21 | } 22 | defer db.Close() 23 | 24 | db.Exec("create virtual table repo using github(id, full_name, description, html_url)") 25 | 26 | rows, err := db.Query("select id, full_name, description, html_url from repo") 27 | if err != nil { 28 | log.Fatal(err) 29 | } 30 | defer rows.Close() 31 | for rows.Next() { 32 | var id, full_name, description, html_url string 33 | rows.Scan(&id, &full_name, &description, &html_url) 34 | fmt.Printf("%s: %s\n\t%s\n\t%s\n\n", id, full_name, description, html_url) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /vendor/github.com/mattn/go-sqlite3/_example/simple/simple.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "database/sql" 5 | "fmt" 6 | _ "github.com/mattn/go-sqlite3" 7 | "log" 8 | "os" 9 | ) 10 | 11 | func main() { 12 | os.Remove("./foo.db") 13 | 14 | db, err := sql.Open("sqlite3", "./foo.db") 15 | if err != nil { 16 | log.Fatal(err) 17 | } 18 | defer db.Close() 19 | 20 | sqlStmt := ` 21 | create table foo (id integer not null primary key, name text); 22 | delete from foo; 23 | ` 24 | _, err = db.Exec(sqlStmt) 25 | if err != nil { 26 | log.Printf("%q: %s\n", err, sqlStmt) 27 | return 28 | } 29 | 30 | tx, err := db.Begin() 31 | if err != nil { 32 | log.Fatal(err) 33 | } 34 | stmt, err := tx.Prepare("insert into foo(id, name) values(?, ?)") 35 | if err != nil { 36 | log.Fatal(err) 37 | } 38 | defer stmt.Close() 39 | for i := 0; i < 100; i++ { 40 | _, err = stmt.Exec(i, fmt.Sprintf("こんにちわ世界%03d", i)) 41 | if err != nil { 42 | log.Fatal(err) 43 | } 44 | } 45 | tx.Commit() 46 | 47 | rows, err := db.Query("select id, name from foo") 48 | if err != nil { 49 | log.Fatal(err) 50 | } 51 | defer rows.Close() 52 | for rows.Next() { 53 | var id int 54 | var name string 55 | rows.Scan(&id, &name) 56 | fmt.Println(id, name) 57 | } 58 | 59 | stmt, err = db.Prepare("select name from foo where id = ?") 60 | if err != nil { 61 | log.Fatal(err) 62 | } 63 | defer stmt.Close() 64 | var name string 65 | err = stmt.QueryRow("3").Scan(&name) 66 | if err != nil { 67 | log.Fatal(err) 68 | } 69 | fmt.Println(name) 70 | 71 | _, err = db.Exec("delete from foo") 72 | if err != nil { 73 | log.Fatal(err) 74 | } 75 | 76 | _, err = db.Exec("insert into foo(id, name) values(1, 'foo'), (2, 'bar'), (3, 'baz')") 77 | if err != nil { 78 | log.Fatal(err) 79 | } 80 | 81 | rows, err = db.Query("select id, name from foo") 82 | if err != nil { 83 | log.Fatal(err) 84 | } 85 | defer rows.Close() 86 | for rows.Next() { 87 | var id int 88 | var name string 89 | rows.Scan(&id, &name) 90 | fmt.Println(id, name) 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /vendor/github.com/mattn/go-sqlite3/backup.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Yasuhiro Matsumoto . 2 | // 3 | // Use of this source code is governed by an MIT-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package sqlite3 7 | 8 | /* 9 | #include 10 | #include 11 | */ 12 | import "C" 13 | import ( 14 | "runtime" 15 | "unsafe" 16 | ) 17 | 18 | type SQLiteBackup struct { 19 | b *C.sqlite3_backup 20 | } 21 | 22 | func (c *SQLiteConn) Backup(dest string, conn *SQLiteConn, src string) (*SQLiteBackup, error) { 23 | destptr := C.CString(dest) 24 | defer C.free(unsafe.Pointer(destptr)) 25 | srcptr := C.CString(src) 26 | defer C.free(unsafe.Pointer(srcptr)) 27 | 28 | if b := C.sqlite3_backup_init(c.db, destptr, conn.db, srcptr); b != nil { 29 | bb := &SQLiteBackup{b: b} 30 | runtime.SetFinalizer(bb, (*SQLiteBackup).Finish) 31 | return bb, nil 32 | } 33 | return nil, c.lastError() 34 | } 35 | 36 | // Backs up for one step. Calls the underlying `sqlite3_backup_step` function. 37 | // This function returns a boolean indicating if the backup is done and 38 | // an error signalling any other error. Done is returned if the underlying C 39 | // function returns SQLITE_DONE (Code 101) 40 | func (b *SQLiteBackup) Step(p int) (bool, error) { 41 | ret := C.sqlite3_backup_step(b.b, C.int(p)) 42 | if ret == C.SQLITE_DONE { 43 | return true, nil 44 | } else if ret != 0 && ret != C.SQLITE_LOCKED && ret != C.SQLITE_BUSY { 45 | return false, Error{Code: ErrNo(ret)} 46 | } 47 | return false, nil 48 | } 49 | 50 | func (b *SQLiteBackup) Remaining() int { 51 | return int(C.sqlite3_backup_remaining(b.b)) 52 | } 53 | 54 | func (b *SQLiteBackup) PageCount() int { 55 | return int(C.sqlite3_backup_pagecount(b.b)) 56 | } 57 | 58 | func (b *SQLiteBackup) Finish() error { 59 | return b.Close() 60 | } 61 | 62 | func (b *SQLiteBackup) Close() error { 63 | ret := C.sqlite3_backup_finish(b.b) 64 | if ret != 0 { 65 | return Error{Code: ErrNo(ret)} 66 | } 67 | b.b = nil 68 | runtime.SetFinalizer(b, nil) 69 | return nil 70 | } 71 | -------------------------------------------------------------------------------- /vendor/github.com/mattn/go-sqlite3/callback_test.go: -------------------------------------------------------------------------------- 1 | package sqlite3 2 | 3 | import ( 4 | "errors" 5 | "math" 6 | "reflect" 7 | "testing" 8 | ) 9 | 10 | func TestCallbackArgCast(t *testing.T) { 11 | intConv := callbackSyntheticForTests(reflect.ValueOf(int64(math.MaxInt64)), nil) 12 | floatConv := callbackSyntheticForTests(reflect.ValueOf(float64(math.MaxFloat64)), nil) 13 | errConv := callbackSyntheticForTests(reflect.Value{}, errors.New("test")) 14 | 15 | tests := []struct { 16 | f callbackArgConverter 17 | o reflect.Value 18 | }{ 19 | {intConv, reflect.ValueOf(int8(-1))}, 20 | {intConv, reflect.ValueOf(int16(-1))}, 21 | {intConv, reflect.ValueOf(int32(-1))}, 22 | {intConv, reflect.ValueOf(uint8(math.MaxUint8))}, 23 | {intConv, reflect.ValueOf(uint16(math.MaxUint16))}, 24 | {intConv, reflect.ValueOf(uint32(math.MaxUint32))}, 25 | // Special case, int64->uint64 is only 1<<63 - 1, not 1<<64 - 1 26 | {intConv, reflect.ValueOf(uint64(math.MaxInt64))}, 27 | {floatConv, reflect.ValueOf(float32(math.Inf(1)))}, 28 | } 29 | 30 | for _, test := range tests { 31 | conv := callbackArgCast{test.f, test.o.Type()} 32 | val, err := conv.Run(nil) 33 | if err != nil { 34 | t.Errorf("Couldn't convert to %s: %s", test.o.Type(), err) 35 | } else if !reflect.DeepEqual(val.Interface(), test.o.Interface()) { 36 | t.Errorf("Unexpected result from converting to %s: got %v, want %v", test.o.Type(), val.Interface(), test.o.Interface()) 37 | } 38 | } 39 | 40 | conv := callbackArgCast{errConv, reflect.TypeOf(int8(0))} 41 | _, err := conv.Run(nil) 42 | if err == nil { 43 | t.Errorf("Expected error during callbackArgCast, but got none") 44 | } 45 | } 46 | 47 | func TestCallbackConverters(t *testing.T) { 48 | tests := []struct { 49 | v interface{} 50 | err bool 51 | }{ 52 | // Unfortunately, we can't tell which converter was returned, 53 | // but we can at least check which types can be converted. 54 | {[]byte{0}, false}, 55 | {"text", false}, 56 | {true, false}, 57 | {int8(0), false}, 58 | {int16(0), false}, 59 | {int32(0), false}, 60 | {int64(0), false}, 61 | {uint8(0), false}, 62 | {uint16(0), false}, 63 | {uint32(0), false}, 64 | {uint64(0), false}, 65 | {int(0), false}, 66 | {uint(0), false}, 67 | {float64(0), false}, 68 | {float32(0), false}, 69 | 70 | {func() {}, true}, 71 | {complex64(complex(0, 0)), true}, 72 | {complex128(complex(0, 0)), true}, 73 | {struct{}{}, true}, 74 | {map[string]string{}, true}, 75 | {[]string{}, true}, 76 | {(*int8)(nil), true}, 77 | {make(chan int), true}, 78 | } 79 | 80 | for _, test := range tests { 81 | _, err := callbackArg(reflect.TypeOf(test.v)) 82 | if test.err && err == nil { 83 | t.Errorf("Expected an error when converting %s, got no error", reflect.TypeOf(test.v)) 84 | } else if !test.err && err != nil { 85 | t.Errorf("Expected converter when converting %s, got error: %s", reflect.TypeOf(test.v), err) 86 | } 87 | } 88 | 89 | for _, test := range tests { 90 | _, err := callbackRet(reflect.TypeOf(test.v)) 91 | if test.err && err == nil { 92 | t.Errorf("Expected an error when converting %s, got no error", reflect.TypeOf(test.v)) 93 | } else if !test.err && err != nil { 94 | t.Errorf("Expected converter when converting %s, got error: %s", reflect.TypeOf(test.v), err) 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /vendor/github.com/mattn/go-sqlite3/sqlite3-binding.c: -------------------------------------------------------------------------------- 1 | #ifndef USE_LIBSQLITE3 2 | # include "code/sqlite3-binding.c" 3 | #endif 4 | 5 | -------------------------------------------------------------------------------- /vendor/github.com/mattn/go-sqlite3/sqlite3-binding.h: -------------------------------------------------------------------------------- 1 | #ifndef USE_LIBSQLITE3 2 | #include "code/sqlite3-binding.h" 3 | #else 4 | #include 5 | #endif 6 | -------------------------------------------------------------------------------- /vendor/github.com/mattn/go-sqlite3/sqlite3_fts3_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2015 Yasuhiro Matsumoto . 2 | // 3 | // Use of this source code is governed by an MIT-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package sqlite3 7 | 8 | import ( 9 | "database/sql" 10 | "os" 11 | "testing" 12 | ) 13 | 14 | func TestFTS3(t *testing.T) { 15 | tempFilename := TempFilename(t) 16 | defer os.Remove(tempFilename) 17 | db, err := sql.Open("sqlite3", tempFilename) 18 | if err != nil { 19 | t.Fatal("Failed to open database:", err) 20 | } 21 | defer db.Close() 22 | 23 | _, err = db.Exec("DROP TABLE foo") 24 | _, err = db.Exec("CREATE VIRTUAL TABLE foo USING fts3(id INTEGER PRIMARY KEY, value TEXT)") 25 | if err != nil { 26 | t.Fatal("Failed to create table:", err) 27 | } 28 | 29 | _, err = db.Exec("INSERT INTO foo(id, value) VALUES(?, ?)", 1, `今日の 晩御飯は 天麩羅よ`) 30 | if err != nil { 31 | t.Fatal("Failed to insert value:", err) 32 | } 33 | 34 | _, err = db.Exec("INSERT INTO foo(id, value) VALUES(?, ?)", 2, `今日は いい 天気だ`) 35 | if err != nil { 36 | t.Fatal("Failed to insert value:", err) 37 | } 38 | 39 | rows, err := db.Query("SELECT id, value FROM foo WHERE value MATCH '今日* 天*'") 40 | if err != nil { 41 | t.Fatal("Unable to query foo table:", err) 42 | } 43 | defer rows.Close() 44 | 45 | for rows.Next() { 46 | var id int 47 | var value string 48 | 49 | if err := rows.Scan(&id, &value); err != nil { 50 | t.Error("Unable to scan results:", err) 51 | continue 52 | } 53 | 54 | if id == 1 && value != `今日の 晩御飯は 天麩羅よ` { 55 | t.Error("Value for id 1 should be `今日の 晩御飯は 天麩羅よ`, but:", value) 56 | } else if id == 2 && value != `今日は いい 天気だ` { 57 | t.Error("Value for id 2 should be `今日は いい 天気だ`, but:", value) 58 | } 59 | } 60 | 61 | rows, err = db.Query("SELECT value FROM foo WHERE value MATCH '今日* 天麩羅*'") 62 | if err != nil { 63 | t.Fatal("Unable to query foo table:", err) 64 | } 65 | defer rows.Close() 66 | 67 | var value string 68 | if !rows.Next() { 69 | t.Fatal("Result should be only one") 70 | } 71 | 72 | if err := rows.Scan(&value); err != nil { 73 | t.Fatal("Unable to scan results:", err) 74 | } 75 | 76 | if value != `今日の 晩御飯は 天麩羅よ` { 77 | t.Fatal("Value should be `今日の 晩御飯は 天麩羅よ`, but:", value) 78 | } 79 | 80 | if rows.Next() { 81 | t.Fatal("Result should be only one") 82 | } 83 | } 84 | 85 | func TestFTS4(t *testing.T) { 86 | tempFilename := TempFilename(t) 87 | defer os.Remove(tempFilename) 88 | db, err := sql.Open("sqlite3", tempFilename) 89 | if err != nil { 90 | t.Fatal("Failed to open database:", err) 91 | } 92 | defer db.Close() 93 | 94 | _, err = db.Exec("DROP TABLE foo") 95 | _, err = db.Exec("CREATE VIRTUAL TABLE foo USING fts4(tokenize=unicode61, id INTEGER PRIMARY KEY, value TEXT)") 96 | if err != nil { 97 | t.Fatal("Failed to create table:", err) 98 | } 99 | 100 | _, err = db.Exec("INSERT INTO foo(id, value) VALUES(?, ?)", 1, `février`) 101 | if err != nil { 102 | t.Fatal("Failed to insert value:", err) 103 | } 104 | 105 | rows, err := db.Query("SELECT value FROM foo WHERE value MATCH 'fevrier'") 106 | if err != nil { 107 | t.Fatal("Unable to query foo table:", err) 108 | } 109 | defer rows.Close() 110 | 111 | var value string 112 | if !rows.Next() { 113 | t.Fatal("Result should be only one") 114 | } 115 | 116 | if err := rows.Scan(&value); err != nil { 117 | t.Fatal("Unable to scan results:", err) 118 | } 119 | 120 | if value != `février` { 121 | t.Fatal("Value should be `février`, but:", value) 122 | } 123 | 124 | if rows.Next() { 125 | t.Fatal("Result should be only one") 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /vendor/github.com/mattn/go-sqlite3/sqlite3_icu.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Yasuhiro Matsumoto . 2 | // 3 | // Use of this source code is governed by an MIT-style 4 | // license that can be found in the LICENSE file. 5 | // +build icu 6 | 7 | package sqlite3 8 | 9 | /* 10 | #cgo LDFLAGS: -licuuc -licui18n 11 | #cgo CFLAGS: -DSQLITE_ENABLE_ICU 12 | */ 13 | import "C" 14 | -------------------------------------------------------------------------------- /vendor/github.com/mattn/go-sqlite3/sqlite3_json1.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Yasuhiro Matsumoto . 2 | // 3 | // Use of this source code is governed by an MIT-style 4 | // license that can be found in the LICENSE file. 5 | // +build json1 6 | 7 | package sqlite3 8 | 9 | /* 10 | #cgo CFLAGS: -DSQLITE_ENABLE_JSON1 11 | */ 12 | import "C" 13 | -------------------------------------------------------------------------------- /vendor/github.com/mattn/go-sqlite3/sqlite3_libsqlite3.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Yasuhiro Matsumoto . 2 | // 3 | // Use of this source code is governed by an MIT-style 4 | // license that can be found in the LICENSE file. 5 | // +build libsqlite3 6 | 7 | package sqlite3 8 | 9 | /* 10 | #cgo CFLAGS: -DUSE_LIBSQLITE3 11 | #cgo LDFLAGS: -lsqlite3 12 | */ 13 | import "C" 14 | -------------------------------------------------------------------------------- /vendor/github.com/mattn/go-sqlite3/sqlite3_load_extension.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Yasuhiro Matsumoto . 2 | // 3 | // Use of this source code is governed by an MIT-style 4 | // license that can be found in the LICENSE file. 5 | // +build !sqlite_omit_load_extension 6 | 7 | package sqlite3 8 | 9 | /* 10 | #include 11 | #include 12 | */ 13 | import "C" 14 | import ( 15 | "errors" 16 | "unsafe" 17 | ) 18 | 19 | func (c *SQLiteConn) loadExtensions(extensions []string) error { 20 | rv := C.sqlite3_enable_load_extension(c.db, 1) 21 | if rv != C.SQLITE_OK { 22 | return errors.New(C.GoString(C.sqlite3_errmsg(c.db))) 23 | } 24 | 25 | for _, extension := range extensions { 26 | cext := C.CString(extension) 27 | defer C.free(unsafe.Pointer(cext)) 28 | rv = C.sqlite3_load_extension(c.db, cext, nil, nil) 29 | if rv != C.SQLITE_OK { 30 | return errors.New(C.GoString(C.sqlite3_errmsg(c.db))) 31 | } 32 | } 33 | 34 | rv = C.sqlite3_enable_load_extension(c.db, 0) 35 | if rv != C.SQLITE_OK { 36 | return errors.New(C.GoString(C.sqlite3_errmsg(c.db))) 37 | } 38 | return nil 39 | } 40 | -------------------------------------------------------------------------------- /vendor/github.com/mattn/go-sqlite3/sqlite3_omit_load_extension.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Yasuhiro Matsumoto . 2 | // 3 | // Use of this source code is governed by an MIT-style 4 | // license that can be found in the LICENSE file. 5 | // +build sqlite_omit_load_extension 6 | 7 | package sqlite3 8 | 9 | /* 10 | #cgo CFLAGS: -DSQLITE_OMIT_LOAD_EXTENSION 11 | */ 12 | import "C" 13 | import ( 14 | "errors" 15 | ) 16 | 17 | func (c *SQLiteConn) loadExtensions(extensions []string) error { 18 | return errors.New("Extensions have been disabled for static builds") 19 | } 20 | -------------------------------------------------------------------------------- /vendor/github.com/mattn/go-sqlite3/sqlite3_other.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Yasuhiro Matsumoto . 2 | // 3 | // Use of this source code is governed by an MIT-style 4 | // license that can be found in the LICENSE file. 5 | // +build !windows 6 | 7 | package sqlite3 8 | 9 | /* 10 | #cgo CFLAGS: -I. 11 | #cgo linux LDFLAGS: -ldl 12 | */ 13 | import "C" 14 | -------------------------------------------------------------------------------- /vendor/github.com/mattn/go-sqlite3/sqlite3_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Yasuhiro Matsumoto . 2 | // 3 | // Use of this source code is governed by an MIT-style 4 | // license that can be found in the LICENSE file. 5 | // +build windows 6 | 7 | package sqlite3 8 | 9 | /* 10 | #cgo CFLAGS: -I. -fno-stack-check -fno-stack-protector -mno-stack-arg-probe 11 | #cgo windows,386 CFLAGS: -D_USE_32BIT_TIME_T 12 | #cgo LDFLAGS: -lmingwex -lmingw32 13 | */ 14 | import "C" 15 | -------------------------------------------------------------------------------- /vendor/github.com/oxtoacart/bpool/README.md: -------------------------------------------------------------------------------- 1 | # bpool [![GoDoc](https://godoc.org/github.com/oxtoacart/bpool?status.png)](https://godoc.org/github.com/oxtoacart/bpool) 2 | 3 | Package bpool implements leaky pools of byte arrays and Buffers as bounded channels. 4 | It is based on the leaky buffer example from the Effective Go documentation: http://golang.org/doc/effective_go.html#leaky_buffer 5 | 6 | bpool provides the following pool types: 7 | 8 | * [bpool.BufferPool](https://godoc.org/github.com/oxtoacart/bpool#BufferPool) 9 | which provides a fixed-size pool of 10 | [bytes.Buffers](http://golang.org/pkg/bytes/#Buffer). 11 | * [bpool.BytePool](https://godoc.org/github.com/oxtoacart/bpool#BytePool) which 12 | provides a fixed-size pool of `[]byte` slices with a pre-set width (length). 13 | * [bpool.SizedBufferPool](https://godoc.org/github.com/oxtoacart/bpool#SizedBufferPool), 14 | which is an alternative to `bpool.BufferPool` that pre-sizes the capacity of 15 | buffers issued from the pool and discards buffers that have grown too large 16 | upon return. 17 | 18 | A common use case for this package is to use buffers to execute HTML templates 19 | against (via ExecuteTemplate) or encode JSON into (via json.NewEncoder). This 20 | allows you to catch any rendering or marshalling errors prior to writing to a 21 | `http.ResponseWriter`, which helps to avoid writing incomplete or malformed data 22 | to the response. 23 | 24 | ## Install 25 | 26 | `go get github.com/oxtoacart/bpool` 27 | 28 | ## Documentation 29 | 30 | See [godoc.org](http://godoc.org/github.com/oxtoacart/bpool) or use `godoc github.com/oxtoacart/bpool` 31 | 32 | ## Example 33 | 34 | Here's a quick example for using `bpool.BufferPool`. We create a pool of the 35 | desired size, call the `Get()` method to obtain a buffer for use, and call 36 | `Put(buf)` to return the buffer to the pool. 37 | 38 | ```go 39 | 40 | var bufpool *bpool.BufferPool 41 | 42 | func main() { 43 | 44 | bufpool = bpool.NewBufferPool(48) 45 | 46 | } 47 | 48 | func someFunction() error { 49 | 50 | // Get a buffer from the pool 51 | buf := bufpool.Get() 52 | ... 53 | ... 54 | ... 55 | // Return the buffer to the pool 56 | bufpool.Put(buf) 57 | 58 | return nil 59 | } 60 | ``` 61 | 62 | ## License 63 | 64 | Apache 2.0 Licensed. See the LICENSE file for details. 65 | 66 | -------------------------------------------------------------------------------- /vendor/github.com/oxtoacart/bpool/bpool.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package bpool implements leaky pools of byte arrays and Buffers as bounded 3 | channels. It is based on the leaky buffer example from the Effective Go 4 | documentation: http://golang.org/doc/effective_go.html#leaky_buffer 5 | */ 6 | package bpool 7 | -------------------------------------------------------------------------------- /vendor/github.com/oxtoacart/bpool/bufferpool.go: -------------------------------------------------------------------------------- 1 | package bpool 2 | 3 | import ( 4 | "bytes" 5 | ) 6 | 7 | // BufferPool implements a pool of bytes.Buffers in the form of a bounded 8 | // channel. 9 | type BufferPool struct { 10 | c chan *bytes.Buffer 11 | } 12 | 13 | // NewBufferPool creates a new BufferPool bounded to the given size. 14 | func NewBufferPool(size int) (bp *BufferPool) { 15 | return &BufferPool{ 16 | c: make(chan *bytes.Buffer, size), 17 | } 18 | } 19 | 20 | // Get gets a Buffer from the BufferPool, or creates a new one if none are 21 | // available in the pool. 22 | func (bp *BufferPool) Get() (b *bytes.Buffer) { 23 | select { 24 | case b = <-bp.c: 25 | // reuse existing buffer 26 | default: 27 | // create new buffer 28 | b = bytes.NewBuffer([]byte{}) 29 | } 30 | return 31 | } 32 | 33 | // Put returns the given Buffer to the BufferPool. 34 | func (bp *BufferPool) Put(b *bytes.Buffer) { 35 | b.Reset() 36 | select { 37 | case bp.c <- b: 38 | default: // Discard the buffer if the pool is full. 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /vendor/github.com/oxtoacart/bpool/bufferpool_test.go: -------------------------------------------------------------------------------- 1 | package bpool 2 | 3 | import ( 4 | "bytes" 5 | "testing" 6 | ) 7 | 8 | func TestBufferPool(t *testing.T) { 9 | var size int = 4 10 | 11 | bufPool := NewBufferPool(size) 12 | 13 | // Test Get/Put 14 | b := bufPool.Get() 15 | bufPool.Put(b) 16 | 17 | // Add some additional buffers beyond the pool size. 18 | for i := 0; i < size*2; i++ { 19 | bufPool.Put(bytes.NewBuffer([]byte{})) 20 | } 21 | 22 | // Close the channel so we can iterate over it. 23 | close(bufPool.c) 24 | 25 | // Check the size of the pool. 26 | if len(bufPool.c) != size { 27 | t.Fatalf("bufferpool size invalid: got %v want %v", len(bufPool.c), size) 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /vendor/github.com/oxtoacart/bpool/bytepool.go: -------------------------------------------------------------------------------- 1 | package bpool 2 | 3 | // BytePool implements a leaky pool of []byte in the form of a bounded 4 | // channel. 5 | type BytePool struct { 6 | c chan []byte 7 | w int 8 | } 9 | 10 | // NewBytePool creates a new BytePool bounded to the given maxSize, with new 11 | // byte arrays sized based on width. 12 | func NewBytePool(maxSize int, width int) (bp *BytePool) { 13 | return &BytePool{ 14 | c: make(chan []byte, maxSize), 15 | w: width, 16 | } 17 | } 18 | 19 | // Get gets a []byte from the BytePool, or creates a new one if none are 20 | // available in the pool. 21 | func (bp *BytePool) Get() (b []byte) { 22 | select { 23 | case b = <-bp.c: 24 | // reuse existing buffer 25 | default: 26 | // create new buffer 27 | b = make([]byte, bp.w) 28 | } 29 | return 30 | } 31 | 32 | // Put returns the given Buffer to the BytePool. 33 | func (bp *BytePool) Put(b []byte) { 34 | select { 35 | case bp.c <- b: 36 | // buffer went back into pool 37 | default: 38 | // buffer didn't go back into pool, just discard 39 | } 40 | } 41 | 42 | // Width returns the width of the byte arrays in this pool. 43 | func (bp *BytePool) Width() (n int) { 44 | return bp.w 45 | } 46 | -------------------------------------------------------------------------------- /vendor/github.com/oxtoacart/bpool/bytepool_test.go: -------------------------------------------------------------------------------- 1 | package bpool 2 | 3 | import "testing" 4 | 5 | func TestBytePool(t *testing.T) { 6 | var size int = 4 7 | var width int = 10 8 | 9 | bufPool := NewBytePool(size, width) 10 | 11 | // Check the width 12 | if bufPool.Width() != width { 13 | t.Fatalf("bytepool width invalid: got %v want %v", bufPool.Width(), width) 14 | } 15 | 16 | // Check that retrieved buffer are of the expected width 17 | b := bufPool.Get() 18 | if len(b) != width { 19 | t.Fatalf("bytepool length invalid: got %v want %v", len(b), width) 20 | } 21 | 22 | bufPool.Put(b) 23 | 24 | // Fill the pool beyond the capped pool size. 25 | for i := 0; i < size*2; i++ { 26 | bufPool.Put(make([]byte, bufPool.w)) 27 | } 28 | 29 | // Close the channel so we can iterate over it. 30 | close(bufPool.c) 31 | 32 | // Check the size of the pool. 33 | if len(bufPool.c) != size { 34 | t.Fatalf("bytepool size invalid: got %v want %v", len(bufPool.c), size) 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /vendor/github.com/oxtoacart/bpool/sizedbufferpool.go: -------------------------------------------------------------------------------- 1 | package bpool 2 | 3 | import ( 4 | "bytes" 5 | ) 6 | 7 | // SizedBufferPool implements a pool of bytes.Buffers in the form of a bounded 8 | // channel. Buffers are pre-allocated to the requested size. 9 | type SizedBufferPool struct { 10 | c chan *bytes.Buffer 11 | a int 12 | } 13 | 14 | // SizedBufferPool creates a new BufferPool bounded to the given size. 15 | // size defines the number of buffers to be retained in the pool and alloc sets 16 | // the initial capacity of new buffers to minimize calls to make(). 17 | // 18 | // The value of alloc should seek to provide a buffer that is representative of 19 | // most data written to the the buffer (i.e. 95th percentile) without being 20 | // overly large (which will increase static memory consumption). You may wish to 21 | // track the capacity of your last N buffers (i.e. using an []int) prior to 22 | // returning them to the pool as input into calculating a suitable alloc value. 23 | func NewSizedBufferPool(size int, alloc int) (bp *SizedBufferPool) { 24 | return &SizedBufferPool{ 25 | c: make(chan *bytes.Buffer, size), 26 | a: alloc, 27 | } 28 | } 29 | 30 | // Get gets a Buffer from the SizedBufferPool, or creates a new one if none are 31 | // available in the pool. Buffers have a pre-allocated capacity. 32 | func (bp *SizedBufferPool) Get() (b *bytes.Buffer) { 33 | select { 34 | case b = <-bp.c: 35 | // reuse existing buffer 36 | default: 37 | // create new buffer 38 | b = bytes.NewBuffer(make([]byte, 0, bp.a)) 39 | } 40 | return 41 | } 42 | 43 | // Put returns the given Buffer to the SizedBufferPool. 44 | func (bp *SizedBufferPool) Put(b *bytes.Buffer) { 45 | b.Reset() 46 | 47 | // Release buffers over our maximum capacity and re-create a pre-sized 48 | // buffer to replace it. 49 | // Note that the cap(b.Bytes()) provides the capacity from the read off-set 50 | // only, but as we've called b.Reset() the full capacity of the underlying 51 | // byte slice is returned. 52 | if cap(b.Bytes()) > bp.a { 53 | b = bytes.NewBuffer(make([]byte, 0, bp.a)) 54 | } 55 | 56 | select { 57 | case bp.c <- b: 58 | default: // Discard the buffer if the pool is full. 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /vendor/github.com/oxtoacart/bpool/sizedbufferpool_test.go: -------------------------------------------------------------------------------- 1 | package bpool 2 | 3 | import ( 4 | "bytes" 5 | "testing" 6 | ) 7 | 8 | // TestSizedBufferPool checks that over-sized buffers are released and that new 9 | // buffers are created in their place. 10 | func TestSizedBufferPool(t *testing.T) { 11 | 12 | var size int = 4 13 | var capacity int = 1024 14 | 15 | bufPool := NewSizedBufferPool(size, capacity) 16 | 17 | b := bufPool.Get() 18 | 19 | // Check the cap before we use the buffer. 20 | if cap(b.Bytes()) != capacity { 21 | t.Fatalf("buffer capacity incorrect: got %v want %v", cap(b.Bytes()), 22 | capacity) 23 | } 24 | 25 | // Grow the buffer beyond our capacity and return it to the pool 26 | b.Grow(capacity * 3) 27 | bufPool.Put(b) 28 | 29 | // Add some additional buffers to fill up the pool. 30 | for i := 0; i < size; i++ { 31 | bufPool.Put(bytes.NewBuffer(make([]byte, 0, bufPool.a*2))) 32 | } 33 | 34 | // Check that oversized buffers are being replaced. 35 | if len(bufPool.c) < size { 36 | t.Fatalf("buffer pool too small: got %v want %v", len(bufPool.c), size) 37 | } 38 | 39 | // Close the channel so we can iterate over it. 40 | close(bufPool.c) 41 | 42 | // Check that there are buffers of the correct capacity in the pool. 43 | for buffer := range bufPool.c { 44 | if cap(buffer.Bytes()) != bufPool.a { 45 | t.Fatalf("returned buffers wrong capacity: got %v want %v", 46 | cap(buffer.Bytes()), capacity) 47 | } 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /vendor/github.com/tylerb/graceful/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Tyler Bunnell 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 | -------------------------------------------------------------------------------- /vendor/github.com/tylerb/graceful/tests/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | 7 | "github.com/codegangsta/negroni" 8 | "github.com/tylerb/graceful" 9 | ) 10 | 11 | func main() { 12 | 13 | var wg sync.WaitGroup 14 | 15 | wg.Add(3) 16 | go func() { 17 | n := negroni.New() 18 | fmt.Println("Launching server on :3000") 19 | graceful.Run(":3000", 0, n) 20 | fmt.Println("Terminated server on :3000") 21 | wg.Done() 22 | }() 23 | go func() { 24 | n := negroni.New() 25 | fmt.Println("Launching server on :3001") 26 | graceful.Run(":3001", 0, n) 27 | fmt.Println("Terminated server on :3001") 28 | wg.Done() 29 | }() 30 | go func() { 31 | n := negroni.New() 32 | fmt.Println("Launching server on :3002") 33 | graceful.Run(":3002", 0, n) 34 | fmt.Println("Terminated server on :3002") 35 | wg.Done() 36 | }() 37 | fmt.Println("Press ctrl+c. All servers should terminate.") 38 | wg.Wait() 39 | 40 | } 41 | -------------------------------------------------------------------------------- /vendor/goji.io/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, 2016 Carl Jackson (carl@avtok.com) 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | 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, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /vendor/goji.io/README.md: -------------------------------------------------------------------------------- 1 | Goji 2 | ==== 3 | 4 | [![GoDoc](https://godoc.org/goji.io?status.svg)](https://godoc.org/goji.io) [![Build Status](https://travis-ci.org/goji/goji.svg?branch=master)](https://travis-ci.org/goji/goji) 5 | 6 | Goji is a HTTP request multiplexer, similar to [`net/http.ServeMux`][servemux]. 7 | It compares incoming requests to a list of registered [Patterns][pattern], and 8 | dispatches to the [Handler][handler] that corresponds to the first matching 9 | Pattern. Goji also supports [Middleware][middleware] (composable shared 10 | functionality applied to every request) and uses the de facto standard 11 | [`x/net/context`][context] to store request-scoped values. 12 | 13 | [servemux]: https://golang.org/pkg/net/http/#ServeMux 14 | [pattern]: https://godoc.org/goji.io#Pattern 15 | [handler]: https://godoc.org/goji.io#Handler 16 | [middleware]: https://godoc.org/goji.io#Mux.Use 17 | [context]: https://godoc.org/golang.org/x/net/context 18 | 19 | 20 | Quick Start 21 | ----------- 22 | 23 | ```go 24 | package main 25 | 26 | import ( 27 | "fmt" 28 | "net/http" 29 | 30 | "goji.io" 31 | "goji.io/pat" 32 | "golang.org/x/net/context" 33 | ) 34 | 35 | func hello(ctx context.Context, w http.ResponseWriter, r *http.Request) { 36 | name := pat.Param(ctx, "name") 37 | fmt.Fprintf(w, "Hello, %s!", name) 38 | } 39 | 40 | func main() { 41 | mux := goji.NewMux() 42 | mux.HandleFuncC(pat.Get("/hello/:name"), hello) 43 | 44 | http.ListenAndServe("localhost:8000", mux) 45 | } 46 | ``` 47 | 48 | Please refer to [Goji's GoDoc Documentation][godoc] for a full API reference. 49 | 50 | [godoc]: https://godoc.org/goji.io 51 | 52 | 53 | Stability 54 | --------- 55 | 56 | Goji's API is stable, and guarantees to never break compatibility with existing 57 | code (under similar rules to the Go project's [guidelines][compat]). Goji is 58 | suitable for use in production. 59 | 60 | [compat]: https://golang.org/doc/go1compat 61 | 62 | 63 | Community / Contributing 64 | ------------------------ 65 | 66 | Goji maintains a mailing list, [gojiberries][berries], where you should feel 67 | welcome to ask questions about the project (no matter how simple!), to announce 68 | projects or libraries built on top of Goji, or to talk about Goji more 69 | generally. Goji's author (Carl Jackson) also loves to hear from users directly 70 | at his personal email address, which is available on his GitHub profile page. 71 | 72 | Contributions to Goji are welcome, however please be advised that due to Goji's 73 | stability guarantees interface changes are unlikely to be accepted. 74 | 75 | All interactions in the Goji community will be held to the high standard of the 76 | broader Go community's [Code of Conduct][conduct]. 77 | 78 | [berries]: https://groups.google.com/forum/#!forum/gojiberries 79 | [conduct]: https://golang.org/conduct 80 | -------------------------------------------------------------------------------- /vendor/goji.io/dispatch.go: -------------------------------------------------------------------------------- 1 | package goji 2 | 3 | import ( 4 | "net/http" 5 | 6 | "goji.io/internal" 7 | "golang.org/x/net/context" 8 | ) 9 | 10 | type dispatch struct{} 11 | 12 | func (d dispatch) ServeHTTPC(ctx context.Context, w http.ResponseWriter, r *http.Request) { 13 | h := ctx.Value(internal.Handler) 14 | if h == nil { 15 | http.NotFound(w, r) 16 | } else { 17 | h.(Handler).ServeHTTPC(ctx, w, r) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /vendor/goji.io/dispatch_test.go: -------------------------------------------------------------------------------- 1 | package goji 2 | 3 | import ( 4 | "net/http" 5 | "net/http/httptest" 6 | "testing" 7 | 8 | "goji.io/internal" 9 | "golang.org/x/net/context" 10 | ) 11 | 12 | func TestDispatch(t *testing.T) { 13 | t.Parallel() 14 | 15 | var d dispatch 16 | 17 | w := httptest.NewRecorder() 18 | d.ServeHTTPC(context.Background(), w, nil) 19 | if w.Code != 404 { 20 | t.Errorf("status: expected %d, got %d", 404, w.Code) 21 | } 22 | 23 | w = httptest.NewRecorder() 24 | h := HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) { 25 | w.WriteHeader(123) 26 | }) 27 | ctx := context.WithValue(context.Background(), internal.Handler, h) 28 | d.ServeHTTPC(ctx, w, nil) 29 | if w.Code != 123 { 30 | t.Errorf("status: expected %d, got %d", 123, w.Code) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /vendor/goji.io/goji_test.go: -------------------------------------------------------------------------------- 1 | package goji 2 | 3 | import ( 4 | "net/http" 5 | "net/http/httptest" 6 | "testing" 7 | 8 | "golang.org/x/net/context" 9 | ) 10 | 11 | func TestHandlerFunc(t *testing.T) { 12 | t.Parallel() 13 | 14 | called := false 15 | 16 | rw := httptest.NewRecorder() 17 | req, _ := http.NewRequest("GET", "/", nil) 18 | h := func(ctx context.Context, w http.ResponseWriter, r *http.Request) { 19 | if ctx != context.TODO() { 20 | t.Errorf("ctx: expected %v, got %v", context.TODO(), ctx) 21 | } 22 | if w != rw { 23 | t.Errorf("rw: expected %v, got %v", rw, w) 24 | } 25 | if r != req { 26 | t.Errorf("req: expected %v, got %v", req, r) 27 | } 28 | called = true 29 | } 30 | 31 | HandlerFunc(h).ServeHTTP(rw, req) 32 | if !called { 33 | t.Error("expected handler to be called") 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /vendor/goji.io/handle.go: -------------------------------------------------------------------------------- 1 | package goji 2 | 3 | import ( 4 | "net/http" 5 | 6 | "goji.io/internal" 7 | "golang.org/x/net/context" 8 | ) 9 | 10 | /* 11 | Handle adds a new route to the Mux. Requests that match the given Pattern will 12 | be dispatched to the given http.Handler. If the http.Handler also supports 13 | Handler, that interface will be used instead. 14 | 15 | Routing is performed in the order in which routes are added: the first route 16 | with a matching Pattern will be used. In particular, Goji guarantees that 17 | routing is performed in a manner that is indistinguishable from the following 18 | algorithm: 19 | 20 | // Assume routes is a slice that every call to Handle appends to 21 | for route := range routes { 22 | // For performance, Patterns can opt out of this call to Match. 23 | // See the documentation for Pattern for more. 24 | if ctx2 := route.pattern.Match(ctx, r); ctx2 != nil { 25 | route.handler.ServeHTTPC(ctx2, w, r) 26 | break 27 | } 28 | } 29 | 30 | It is not safe to concurrently register routes from multiple goroutines, or to 31 | register routes concurrently with requests. 32 | */ 33 | func (m *Mux) Handle(p Pattern, h http.Handler) { 34 | gh, ok := h.(Handler) 35 | if !ok { 36 | gh = internal.ContextWrapper{Handler: h} 37 | } 38 | m.router.add(p, gh) 39 | } 40 | 41 | /* 42 | HandleFunc adds a new route to the Mux. It is equivalent to calling Handle on a 43 | handler wrapped with http.HandlerFunc, and is provided only for convenience. 44 | */ 45 | func (m *Mux) HandleFunc(p Pattern, h func(http.ResponseWriter, *http.Request)) { 46 | m.Handle(p, http.HandlerFunc(h)) 47 | } 48 | 49 | /* 50 | HandleC adds a new context-aware route to the Mux. See the documentation for 51 | Handle for more information about the semantics of routing. 52 | 53 | It is not safe to concurrently register routes from multiple goroutines, or to 54 | register routes concurrently with requests. 55 | */ 56 | func (m *Mux) HandleC(p Pattern, h Handler) { 57 | m.router.add(p, h) 58 | } 59 | 60 | /* 61 | HandleFuncC adds a new context-aware route to the Mux. It is equivalent to 62 | calling HandleC on a handler wrapped with HandlerFunc, and is provided for 63 | convenience. 64 | */ 65 | func (m *Mux) HandleFuncC(p Pattern, h func(context.Context, http.ResponseWriter, *http.Request)) { 66 | m.HandleC(p, HandlerFunc(h)) 67 | } 68 | -------------------------------------------------------------------------------- /vendor/goji.io/handle_test.go: -------------------------------------------------------------------------------- 1 | package goji 2 | 3 | import ( 4 | "net/http" 5 | "testing" 6 | 7 | "golang.org/x/net/context" 8 | ) 9 | 10 | func TestHandle(t *testing.T) { 11 | t.Parallel() 12 | 13 | m := NewMux() 14 | called := false 15 | fn := func(w http.ResponseWriter, r *http.Request) { 16 | called = true 17 | } 18 | m.Handle(boolPattern(true), http.HandlerFunc(fn)) 19 | 20 | w, r := wr() 21 | m.ServeHTTPC(context.Background(), w, r) 22 | if !called { 23 | t.Error("expected handler to be called") 24 | } 25 | } 26 | 27 | func TestHandleFunc(t *testing.T) { 28 | t.Parallel() 29 | 30 | m := NewMux() 31 | called := false 32 | fn := func(w http.ResponseWriter, r *http.Request) { 33 | called = true 34 | } 35 | m.HandleFunc(boolPattern(true), fn) 36 | 37 | w, r := wr() 38 | m.ServeHTTPC(context.Background(), w, r) 39 | if !called { 40 | t.Error("expected handler to be called") 41 | } 42 | } 43 | 44 | func TestHandleC(t *testing.T) { 45 | t.Parallel() 46 | 47 | m := NewMux() 48 | called := false 49 | fn := func(ctx context.Context, w http.ResponseWriter, r *http.Request) { 50 | called = true 51 | } 52 | m.HandleC(boolPattern(true), HandlerFunc(fn)) 53 | 54 | w, r := wr() 55 | m.ServeHTTPC(context.Background(), w, r) 56 | if !called { 57 | t.Error("expected handler to be called") 58 | } 59 | } 60 | 61 | func TestHandleFuncC(t *testing.T) { 62 | t.Parallel() 63 | 64 | m := NewMux() 65 | called := false 66 | fn := func(ctx context.Context, w http.ResponseWriter, r *http.Request) { 67 | called = true 68 | } 69 | m.HandleFuncC(boolPattern(true), fn) 70 | 71 | w, r := wr() 72 | m.ServeHTTPC(context.Background(), w, r) 73 | if !called { 74 | t.Error("expected handler to be called") 75 | } 76 | } 77 | 78 | type cHTTP chan string 79 | 80 | func (c cHTTP) ServeHTTP(w http.ResponseWriter, r *http.Request) { 81 | c <- "http" 82 | } 83 | 84 | func (c cHTTP) ServeHTTPC(ctx context.Context, w http.ResponseWriter, r *http.Request) { 85 | c <- "context" 86 | } 87 | 88 | func TestHandleUpgrade(t *testing.T) { 89 | t.Parallel() 90 | 91 | ch := make(cHTTP, 1) 92 | m := NewMux() 93 | m.Handle(boolPattern(true), ch) 94 | w, r := wr() 95 | m.ServeHTTPC(context.Background(), w, r) 96 | if v := <-ch; v != "context" { 97 | t.Errorf("got %v, expected %v", v, "context") 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /vendor/goji.io/internal/context.go: -------------------------------------------------------------------------------- 1 | package internal 2 | 3 | // ContextKey is a type used for Goji's context.Context keys. 4 | type ContextKey int 5 | 6 | var ( 7 | // Path is the context key used to store the path Goji uses for its 8 | // PathPrefix optimization. 9 | Path interface{} = ContextKey(0) 10 | // Pattern is the context key used to store the Pattern that Goji last 11 | // matched. 12 | Pattern interface{} = ContextKey(1) 13 | // Handler is the context key used to store the Handler that Goji last 14 | // mached (and will therefore dispatch to at the end of the middleware 15 | // stack). 16 | Handler interface{} = ContextKey(2) 17 | ) 18 | -------------------------------------------------------------------------------- /vendor/goji.io/internal/http.go: -------------------------------------------------------------------------------- 1 | package internal 2 | 3 | import ( 4 | "net/http" 5 | 6 | "golang.org/x/net/context" 7 | ) 8 | 9 | // ContextWrapper is a standard bridge type from http.Handlers to context-aware 10 | // Handlers. It is included here so that the middleware subpackage can use it to 11 | // unwrap Handlers. 12 | type ContextWrapper struct { 13 | http.Handler 14 | } 15 | 16 | // ServeHTTPC implements goji.Handler. 17 | func (c ContextWrapper) ServeHTTPC(ctx context.Context, w http.ResponseWriter, r *http.Request) { 18 | c.Handler.ServeHTTP(w, r) 19 | } 20 | -------------------------------------------------------------------------------- /vendor/goji.io/internal/http_test.go: -------------------------------------------------------------------------------- 1 | package internal 2 | 3 | import ( 4 | "net/http" 5 | "net/http/httptest" 6 | "testing" 7 | 8 | "golang.org/x/net/context" 9 | ) 10 | 11 | func TestContextWrapper(t *testing.T) { 12 | t.Parallel() 13 | 14 | // This one is kind of silly. 15 | called := false 16 | rw := httptest.NewRecorder() 17 | req, _ := http.NewRequest("GET", "/", nil) 18 | h := func(w http.ResponseWriter, r *http.Request) { 19 | if w != rw { 20 | t.Errorf("rw: expected %v, got %v", rw, w) 21 | } 22 | if r != req { 23 | t.Errorf("req: expected %v, got %v", req, r) 24 | } 25 | called = true 26 | } 27 | cw := ContextWrapper{http.HandlerFunc(h)} 28 | cw.ServeHTTPC(context.Background(), rw, req) 29 | if !called { 30 | t.Error("expected handler to be called") 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /vendor/goji.io/internal/internal.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package internal is a private package that allows Goji to expose a less 3 | confusing interface to its users. This package must not be used outside of Goji; 4 | every piece of its functionality has been exposed by one of Goji's subpackages. 5 | 6 | The problem this package solves is to allow Goji to internally agree on types 7 | and secret values between its packages without introducing import cycles. Goji 8 | needs to agree on these types and values in order to organize its public API 9 | into audience-specific subpackages (for instance, a package for pattern authors, 10 | a package for middleware authors, and a main package for routing users) without 11 | exposing implementation details in any of the packages. 12 | */ 13 | package internal 14 | -------------------------------------------------------------------------------- /vendor/goji.io/middleware/middleware.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package middleware contains utilities for Goji Middleware authors. 3 | 4 | Unless you are writing middleware for your application, you should avoid 5 | importing this package. Instead, use the abstractions provided by your 6 | middleware package. 7 | */ 8 | package middleware 9 | 10 | import ( 11 | "net/http" 12 | 13 | "goji.io" 14 | "goji.io/internal" 15 | "golang.org/x/net/context" 16 | ) 17 | 18 | /* 19 | Pattern returns the most recently matched Pattern, or nil if no pattern was 20 | matched. 21 | */ 22 | func Pattern(ctx context.Context) goji.Pattern { 23 | p := ctx.Value(internal.Pattern) 24 | if p == nil { 25 | return nil 26 | } 27 | return p.(goji.Pattern) 28 | } 29 | 30 | /* 31 | SetPattern returns a new context in which the given Pattern is used as the most 32 | recently matched pattern. 33 | */ 34 | func SetPattern(ctx context.Context, p goji.Pattern) context.Context { 35 | return context.WithValue(ctx, internal.Pattern, p) 36 | } 37 | 38 | /* 39 | Handler returns the handler corresponding to the most recently matched Pattern, 40 | or nil if no pattern was matched. 41 | 42 | Internally, Goji converts net/http.Handlers into goji.Handlers using a wrapper 43 | object. Users who wish to retrieve the original http.Handler they passed to Goji 44 | may call UnwrapHandler. 45 | 46 | The handler returned by this function is the one that will be dispatched to at 47 | the end of the middleware stack. If the returned Handler is nil, http.NotFound 48 | will be used instead. 49 | */ 50 | func Handler(ctx context.Context) goji.Handler { 51 | h := ctx.Value(internal.Handler) 52 | if h == nil { 53 | return nil 54 | } 55 | return h.(goji.Handler) 56 | } 57 | 58 | /* 59 | SetHandler returns a new context in which the given Handler was most recently 60 | matched and which consequently will be dispatched to. 61 | */ 62 | func SetHandler(ctx context.Context, h goji.Handler) context.Context { 63 | return context.WithValue(ctx, internal.Handler, h) 64 | } 65 | 66 | /* 67 | UnwrapHandler extracts the original http.Handler from a Goji-wrapped Handler 68 | object, or returns nil if the given Handler has not been wrapped in this way. 69 | 70 | This function is necessary because Goji uses goji.Handler as its native data 71 | type internally, and uses a wrapper struct to convert all http.Handlers it is 72 | passed into goji.Handlers. 73 | */ 74 | func UnwrapHandler(h goji.Handler) http.Handler { 75 | if cw, ok := h.(internal.ContextWrapper); ok { 76 | return cw.Handler 77 | } 78 | return nil 79 | } 80 | -------------------------------------------------------------------------------- /vendor/goji.io/middleware/middleware_test.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "net/http" 5 | "testing" 6 | 7 | "goji.io" 8 | "goji.io/internal" 9 | "golang.org/x/net/context" 10 | ) 11 | 12 | type testPattern bool 13 | 14 | func (t testPattern) Match(ctx context.Context, _ *http.Request) context.Context { 15 | if t { 16 | return ctx 17 | } 18 | return nil 19 | } 20 | 21 | type testHandler struct{} 22 | 23 | func (t testHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {} 24 | 25 | func (t testHandler) ServeHTTPC(ctx context.Context, w http.ResponseWriter, r *http.Request) {} 26 | 27 | func TestPattern(t *testing.T) { 28 | t.Parallel() 29 | 30 | pat := testPattern(true) 31 | ctx := SetPattern(context.Background(), pat) 32 | if pat2 := Pattern(ctx); pat2 != pat { 33 | t.Errorf("got ctx=%v, expected %v", pat2, pat) 34 | } 35 | 36 | if pat2 := Pattern(context.Background()); pat2 != nil { 37 | t.Errorf("got ctx=%v, expecte nil", pat2) 38 | } 39 | } 40 | 41 | func TestHandler(t *testing.T) { 42 | t.Parallel() 43 | 44 | h := testHandler{} 45 | ctx := SetHandler(context.Background(), h) 46 | if h2 := Handler(ctx); h2 != h { 47 | t.Errorf("got handler=%v, expected %v", h2, h) 48 | } 49 | 50 | if h2 := Handler(context.Background()); h2 != nil { 51 | t.Errorf("got handler=%v, expected nil", h2) 52 | } 53 | } 54 | 55 | func TestUnwrapHandler(t *testing.T) { 56 | t.Parallel() 57 | 58 | h := &testHandler{} 59 | if h2 := UnwrapHandler(internal.ContextWrapper{Handler: h}); h2 != h { 60 | t.Errorf("got handler=%v, expected %v", h2, h) 61 | } 62 | 63 | h3 := goji.HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) {}) 64 | if h2 := UnwrapHandler(h3); h2 != nil { 65 | t.Errorf("got handler=%v, expected nil", h2) 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /vendor/goji.io/middleware_test.go: -------------------------------------------------------------------------------- 1 | package goji 2 | 3 | import ( 4 | "net/http" 5 | "testing" 6 | 7 | "golang.org/x/net/context" 8 | ) 9 | 10 | func expectSequence(t *testing.T, ch chan string, seq ...string) { 11 | for i, str := range seq { 12 | if msg := <-ch; msg != str { 13 | t.Errorf("[%d] expected %s, got %s", i, str, msg) 14 | } 15 | } 16 | } 17 | 18 | func TestMiddlewareNetHTTP(t *testing.T) { 19 | t.Parallel() 20 | 21 | m := NewMux() 22 | ch := make(chan string, 10) 23 | m.Use(func(h http.Handler) http.Handler { 24 | fn := func(w http.ResponseWriter, r *http.Request) { 25 | ch <- "before one" 26 | h.ServeHTTP(w, r) 27 | ch <- "after one" 28 | } 29 | return http.HandlerFunc(fn) 30 | }) 31 | m.Use(func(h http.Handler) http.Handler { 32 | fn := func(w http.ResponseWriter, r *http.Request) { 33 | ch <- "before two" 34 | h.ServeHTTP(w, r) 35 | ch <- "after two" 36 | } 37 | return http.HandlerFunc(fn) 38 | }) 39 | m.Handle(boolPattern(true), http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 40 | ch <- "handler" 41 | })) 42 | 43 | m.ServeHTTP(wr()) 44 | 45 | expectSequence(t, ch, "before one", "before two", "handler", "after two", "after one") 46 | } 47 | 48 | func makeMiddleware(ch chan string, name string) func(Handler) Handler { 49 | return func(h Handler) Handler { 50 | fn := func(ctx context.Context, w http.ResponseWriter, r *http.Request) { 51 | ch <- "before " + name 52 | h.ServeHTTPC(ctx, w, r) 53 | ch <- "after " + name 54 | } 55 | return HandlerFunc(fn) 56 | } 57 | } 58 | 59 | func TestMiddlewareC(t *testing.T) { 60 | t.Parallel() 61 | 62 | m := NewMux() 63 | ch := make(chan string, 10) 64 | m.UseC(makeMiddleware(ch, "one")) 65 | m.UseC(makeMiddleware(ch, "two")) 66 | m.Handle(boolPattern(true), HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) { 67 | ch <- "handler" 68 | })) 69 | 70 | w, r := wr() 71 | m.ServeHTTPC(context.Background(), w, r) 72 | 73 | expectSequence(t, ch, "before one", "before two", "handler", "after two", "after one") 74 | } 75 | 76 | func TestMiddlewareReconfigure(t *testing.T) { 77 | t.Parallel() 78 | 79 | m := NewMux() 80 | ch := make(chan string, 10) 81 | m.UseC(makeMiddleware(ch, "one")) 82 | m.UseC(makeMiddleware(ch, "two")) 83 | m.Handle(boolPattern(true), HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) { 84 | ch <- "handler" 85 | })) 86 | 87 | w, r := wr() 88 | m.ServeHTTPC(context.Background(), w, r) 89 | 90 | expectSequence(t, ch, "before one", "before two", "handler", "after two", "after one") 91 | 92 | m.UseC(makeMiddleware(ch, "three")) 93 | 94 | w, r = wr() 95 | m.ServeHTTPC(context.Background(), w, r) 96 | 97 | expectSequence(t, ch, "before one", "before two", "before three", 98 | "handler", "after three", "after two", "after one") 99 | } 100 | -------------------------------------------------------------------------------- /vendor/goji.io/mux.go: -------------------------------------------------------------------------------- 1 | package goji 2 | 3 | import ( 4 | "net/http" 5 | 6 | "goji.io/internal" 7 | "golang.org/x/net/context" 8 | ) 9 | 10 | /* 11 | Mux is a HTTP multiplexer / router similar to net/http.ServeMux. 12 | 13 | Muxes multiplex traffic between many Handlers by selecting the first applicable 14 | Pattern. They then call a common middleware stack, finally passing control to 15 | the selected Handler. See the documentation on the Handle function for more 16 | information about how routing is performed, the documentation on the Pattern 17 | type for more information about request matching, and the documentation for the 18 | Use method for more about middleware. 19 | 20 | Muxes cannot be configured concurrently from multiple goroutines, nor can they 21 | be configured concurrently with requests. 22 | */ 23 | type Mux struct { 24 | handler Handler 25 | middleware []func(Handler) Handler 26 | router router 27 | root bool 28 | } 29 | 30 | /* 31 | NewMux returns a new Mux with no configured middleware or routes. 32 | */ 33 | func NewMux() *Mux { 34 | m := SubMux() 35 | m.root = true 36 | return m 37 | } 38 | 39 | /* 40 | SubMux returns a new Mux with no configured middleware or routes, and which 41 | inherits routing information from the passed context. This is especially useful 42 | when using one Mux as a Handler registered to another "parent" Mux. 43 | 44 | For example, a common pattern is to organize applications in a way that mirrors 45 | the structure of its URLs: a photo-sharing site might have URLs that start with 46 | "/users/" and URLs that start with "/albums/", and might be organized using 47 | three Muxes: 48 | 49 | root := NewMux() 50 | users := SubMux() 51 | root.HandleC(pat.New("/users/*", users) 52 | albums := SubMux() 53 | root.HandleC(pat.New("/albums/*", albums) 54 | 55 | // e.g., GET /users/carl 56 | users.HandleC(pat.Get("/:name"), renderProfile) 57 | // e.g., POST /albums/ 58 | albums.HandleC(pat.Post("/"), newAlbum) 59 | */ 60 | func SubMux() *Mux { 61 | m := &Mux{} 62 | m.buildChain() 63 | return m 64 | } 65 | 66 | /* 67 | ServeHTTP implements net/http.Handler. It uses context.TODO as the root context 68 | in order to ease the conversion of non-context-aware Handlers to context-aware 69 | ones using static analysis. 70 | 71 | Users who know that their mux sits at the top of the request hierarchy should 72 | consider creating a small helper http.Handler that calls this Mux's ServeHTTPC 73 | function with context.Background. 74 | */ 75 | func (m *Mux) ServeHTTP(w http.ResponseWriter, r *http.Request) { 76 | m.ServeHTTPC(context.TODO(), w, r) 77 | } 78 | 79 | /* 80 | ServeHTTPC implements Handler. 81 | */ 82 | func (m *Mux) ServeHTTPC(ctx context.Context, w http.ResponseWriter, r *http.Request) { 83 | if m.root { 84 | ctx = context.WithValue(ctx, internal.Path, r.URL.EscapedPath()) 85 | } 86 | ctx = m.router.route(ctx, r) 87 | m.handler.ServeHTTPC(ctx, w, r) 88 | } 89 | 90 | var _ http.Handler = &Mux{} 91 | var _ Handler = &Mux{} 92 | -------------------------------------------------------------------------------- /vendor/goji.io/mux_test.go: -------------------------------------------------------------------------------- 1 | package goji 2 | 3 | import ( 4 | "net/http" 5 | "testing" 6 | 7 | "goji.io/internal" 8 | "golang.org/x/net/context" 9 | ) 10 | 11 | func TestMuxExistingPath(t *testing.T) { 12 | m := NewMux() 13 | handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request) { 14 | if path := ctx.Value(internal.Path).(string); path != "/" { 15 | t.Errorf("expected path=/, got %q", path) 16 | } 17 | } 18 | m.HandleFuncC(boolPattern(true), handler) 19 | w, r := wr() 20 | ctx := context.WithValue(context.Background(), internal.Path, "/hello") 21 | m.ServeHTTPC(ctx, w, r) 22 | } 23 | 24 | func TestSubMuxExistingPath(t *testing.T) { 25 | m := SubMux() 26 | handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request) { 27 | if path := ctx.Value(internal.Path).(string); path != "/hello" { 28 | t.Errorf("expected path=/hello, got %q", path) 29 | } 30 | } 31 | m.HandleFuncC(boolPattern(true), handler) 32 | w, r := wr() 33 | ctx := context.WithValue(context.Background(), internal.Path, "/hello") 34 | m.ServeHTTPC(ctx, w, r) 35 | } 36 | -------------------------------------------------------------------------------- /vendor/goji.io/pat/match.go: -------------------------------------------------------------------------------- 1 | package pat 2 | 3 | import ( 4 | "sort" 5 | 6 | "goji.io/internal" 7 | "goji.io/pattern" 8 | "golang.org/x/net/context" 9 | ) 10 | 11 | type match struct { 12 | context.Context 13 | pat *Pattern 14 | matches []string 15 | } 16 | 17 | func (m match) Value(key interface{}) interface{} { 18 | switch key { 19 | case pattern.AllVariables: 20 | var vs map[pattern.Variable]interface{} 21 | if vsi := m.Context.Value(key); vsi == nil { 22 | if len(m.pat.pats) == 0 { 23 | return nil 24 | } 25 | vs = make(map[pattern.Variable]interface{}, len(m.matches)) 26 | } else { 27 | vs = vsi.(map[pattern.Variable]interface{}) 28 | } 29 | 30 | for _, p := range m.pat.pats { 31 | vs[p.name] = m.matches[p.idx] 32 | } 33 | return vs 34 | case internal.Path: 35 | if len(m.matches) == len(m.pat.pats)+1 { 36 | return m.matches[len(m.matches)-1] 37 | } 38 | return "" 39 | } 40 | 41 | if k, ok := key.(pattern.Variable); ok { 42 | i := sort.Search(len(m.pat.pats), func(i int) bool { 43 | return m.pat.pats[i].name >= k 44 | }) 45 | if i < len(m.pat.pats) && m.pat.pats[i].name == k { 46 | return m.matches[m.pat.pats[i].idx] 47 | } 48 | } 49 | 50 | return m.Context.Value(key) 51 | } 52 | -------------------------------------------------------------------------------- /vendor/goji.io/pat/match_test.go: -------------------------------------------------------------------------------- 1 | package pat 2 | 3 | import ( 4 | "net/http" 5 | "reflect" 6 | "testing" 7 | 8 | "goji.io/pattern" 9 | "golang.org/x/net/context" 10 | ) 11 | 12 | func TestExistingContext(t *testing.T) { 13 | t.Parallel() 14 | 15 | pat := New("/hi/:c/:a/:r/:l") 16 | req, err := http.NewRequest("GET", "/hi/foo/bar/baz/quux", nil) 17 | if err != nil { 18 | panic(err) 19 | } 20 | ctx := context.Background() 21 | ctx = pattern.SetPath(ctx, req.URL.EscapedPath()) 22 | ctx = context.WithValue(ctx, pattern.AllVariables, map[pattern.Variable]interface{}{ 23 | "hello": "world", 24 | "c": "nope", 25 | }) 26 | ctx = context.WithValue(ctx, "user", "carl") 27 | 28 | ctx = pat.Match(ctx, req) 29 | if ctx == nil { 30 | t.Fatalf("expected pattern to match") 31 | } 32 | 33 | expected := map[pattern.Variable]interface{}{ 34 | "c": "foo", 35 | "a": "bar", 36 | "r": "baz", 37 | "l": "quux", 38 | } 39 | for k, v := range expected { 40 | if p := Param(ctx, string(k)); p != v { 41 | t.Errorf("expected %s=%q, got %q", k, v, p) 42 | } 43 | } 44 | 45 | expected["hello"] = "world" 46 | all := ctx.Value(pattern.AllVariables).(map[pattern.Variable]interface{}) 47 | if !reflect.DeepEqual(all, expected) { 48 | t.Errorf("expected %v, got %v", expected, all) 49 | } 50 | 51 | if path := pattern.Path(ctx); path != "" { 52 | t.Errorf("expected path=%q, got %q", "", path) 53 | } 54 | 55 | if user := ctx.Value("user"); user != "carl" { 56 | t.Errorf("expected user=%q, got %q", "carl", user) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /vendor/goji.io/pat/methods.go: -------------------------------------------------------------------------------- 1 | package pat 2 | 3 | /* 4 | Delete returns a Pat route that only matches the DELETE HTTP method. 5 | */ 6 | func Delete(pat string) *Pattern { 7 | return newWithMethods(pat, "DELETE") 8 | } 9 | 10 | /* 11 | Get returns a Pat route that only matches the GET and HEAD HTTP method. HEAD 12 | requests are handled transparently by net/http. 13 | */ 14 | func Get(pat string) *Pattern { 15 | return newWithMethods(pat, "GET", "HEAD") 16 | } 17 | 18 | /* 19 | Head returns a Pat route that only matches the HEAD HTTP method. 20 | */ 21 | func Head(pat string) *Pattern { 22 | return newWithMethods(pat, "HEAD") 23 | } 24 | 25 | /* 26 | Options returns a Pat route that only matches the OPTIONS HTTP method. 27 | */ 28 | func Options(pat string) *Pattern { 29 | return newWithMethods(pat, "OPTIONS") 30 | } 31 | 32 | /* 33 | Patch returns a Pat route that only matches the PATCH HTTP method. 34 | */ 35 | func Patch(pat string) *Pattern { 36 | return newWithMethods(pat, "PATCH") 37 | } 38 | 39 | /* 40 | Post returns a Pat route that only matches the POST HTTP method. 41 | */ 42 | func Post(pat string) *Pattern { 43 | return newWithMethods(pat, "POST") 44 | } 45 | 46 | /* 47 | Put returns a Pat route that only matches the PUT HTTP method. 48 | */ 49 | func Put(pat string) *Pattern { 50 | return newWithMethods(pat, "PUT") 51 | } 52 | -------------------------------------------------------------------------------- /vendor/goji.io/pat/methods_test.go: -------------------------------------------------------------------------------- 1 | package pat 2 | 3 | import "testing" 4 | 5 | func TestDelete(t *testing.T) { 6 | t.Parallel() 7 | pat := Delete("/") 8 | if pat.Match(mustReq("GET", "/")) != nil { 9 | t.Errorf("pattern was DELETE, but matched GET") 10 | } 11 | if pat.Match(mustReq("DELETE", "/")) == nil { 12 | t.Errorf("pattern didn't match DELETE") 13 | } 14 | } 15 | 16 | func TestGet(t *testing.T) { 17 | t.Parallel() 18 | pat := Get("/") 19 | if pat.Match(mustReq("POST", "/")) != nil { 20 | t.Errorf("pattern was GET, but matched POST") 21 | } 22 | if pat.Match(mustReq("GET", "/")) == nil { 23 | t.Errorf("pattern didn't match GET") 24 | } 25 | if pat.Match(mustReq("HEAD", "/")) == nil { 26 | t.Errorf("pattern didn't match HEAD") 27 | } 28 | } 29 | 30 | func TestHead(t *testing.T) { 31 | t.Parallel() 32 | pat := Head("/") 33 | if pat.Match(mustReq("GET", "/")) != nil { 34 | t.Errorf("pattern was HEAD, but matched GET") 35 | } 36 | if pat.Match(mustReq("HEAD", "/")) == nil { 37 | t.Errorf("pattern didn't match HEAD") 38 | } 39 | } 40 | 41 | func TestOptions(t *testing.T) { 42 | t.Parallel() 43 | pat := Options("/") 44 | if pat.Match(mustReq("GET", "/")) != nil { 45 | t.Errorf("pattern was OPTIONS, but matched GET") 46 | } 47 | if pat.Match(mustReq("OPTIONS", "/")) == nil { 48 | t.Errorf("pattern didn't match OPTIONS") 49 | } 50 | } 51 | 52 | func TestPatch(t *testing.T) { 53 | t.Parallel() 54 | pat := Patch("/") 55 | if pat.Match(mustReq("GET", "/")) != nil { 56 | t.Errorf("pattern was PATCH, but matched GET") 57 | } 58 | if pat.Match(mustReq("PATCH", "/")) == nil { 59 | t.Errorf("pattern didn't match PATCH") 60 | } 61 | } 62 | 63 | func TestPost(t *testing.T) { 64 | t.Parallel() 65 | pat := Post("/") 66 | if pat.Match(mustReq("GET", "/")) != nil { 67 | t.Errorf("pattern was POST, but matched GET") 68 | } 69 | if pat.Match(mustReq("POST", "/")) == nil { 70 | t.Errorf("pattern didn't match POST") 71 | } 72 | } 73 | 74 | func TestPut(t *testing.T) { 75 | t.Parallel() 76 | pat := Put("/") 77 | if pat.Match(mustReq("GET", "/")) != nil { 78 | t.Errorf("pattern was PUT, but matched GET") 79 | } 80 | if pat.Match(mustReq("PUT", "/")) == nil { 81 | t.Errorf("pattern didn't match PUT") 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /vendor/goji.io/pat/url.go: -------------------------------------------------------------------------------- 1 | package pat 2 | 3 | import "net/url" 4 | 5 | // Stolen (with modifications) from net/url in the Go stdlib 6 | 7 | func ishex(c byte) bool { 8 | switch { 9 | case '0' <= c && c <= '9': 10 | return true 11 | case 'a' <= c && c <= 'f': 12 | return true 13 | case 'A' <= c && c <= 'F': 14 | return true 15 | } 16 | return false 17 | } 18 | 19 | func unhex(c byte) byte { 20 | switch { 21 | case '0' <= c && c <= '9': 22 | return c - '0' 23 | case 'a' <= c && c <= 'f': 24 | return c - 'a' + 10 25 | case 'A' <= c && c <= 'F': 26 | return c - 'A' + 10 27 | } 28 | return 0 29 | } 30 | 31 | func unescape(s string) (string, error) { 32 | // Count %, check that they're well-formed. 33 | n := 0 34 | for i := 0; i < len(s); { 35 | switch s[i] { 36 | case '%': 37 | n++ 38 | if i+2 >= len(s) || !ishex(s[i+1]) || !ishex(s[i+2]) { 39 | s = s[i:] 40 | if len(s) > 3 { 41 | s = s[:3] 42 | } 43 | return "", url.EscapeError(s) 44 | } 45 | i += 3 46 | default: 47 | i++ 48 | } 49 | } 50 | 51 | if n == 0 { 52 | return s, nil 53 | } 54 | 55 | t := make([]byte, len(s)-2*n) 56 | j := 0 57 | for i := 0; i < len(s); { 58 | switch s[i] { 59 | case '%': 60 | t[j] = unhex(s[i+1])<<4 | unhex(s[i+2]) 61 | j++ 62 | i += 3 63 | default: 64 | t[j] = s[i] 65 | j++ 66 | i++ 67 | } 68 | } 69 | return string(t), nil 70 | } 71 | -------------------------------------------------------------------------------- /vendor/goji.io/pat/url_test.go: -------------------------------------------------------------------------------- 1 | package pat 2 | 3 | import ( 4 | "net/url" 5 | "testing" 6 | ) 7 | 8 | var HexTexts = []struct { 9 | input byte 10 | ishex bool 11 | unhex byte 12 | }{ 13 | {'0', true, 0}, 14 | {'4', true, 4}, 15 | {'a', true, 10}, 16 | {'F', true, 15}, 17 | {'h', false, 0}, 18 | {'^', false, 0}, 19 | } 20 | 21 | func TestHex(t *testing.T) { 22 | t.Parallel() 23 | 24 | for _, test := range HexTexts { 25 | if actual := ishex(test.input); actual != test.ishex { 26 | t.Errorf("ishex(%v) == %v, expected %v", test.input, actual, test.ishex) 27 | } 28 | if actual := unhex(test.input); actual != test.unhex { 29 | t.Errorf("unhex(%v) == %v, expected %v", test.input, actual, test.unhex) 30 | } 31 | } 32 | } 33 | 34 | var UnescapeTests = []struct { 35 | input string 36 | err error 37 | output string 38 | }{ 39 | {"hello", nil, "hello"}, 40 | {"file%20one%26two", nil, "file one&two"}, 41 | {"one/two%2fthree", nil, "one/two/three"}, 42 | {"this%20is%0not%valid", url.EscapeError("%0n"), ""}, 43 | } 44 | 45 | func TestUnescape(t *testing.T) { 46 | t.Parallel() 47 | 48 | for _, test := range UnescapeTests { 49 | if actual, err := unescape(test.input); err != test.err { 50 | t.Errorf("unescape(%q) had err %v, expected %q", test.input, err, test.err) 51 | } else if actual != test.output { 52 | t.Errorf("unescape(%q) = %q, expected %q)", test.input, actual, test.output) 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /vendor/goji.io/pattern.go: -------------------------------------------------------------------------------- 1 | package goji 2 | 3 | // httpMethods is an internal interface for the HTTPMethods pattern 4 | // optimization. See the documentation on Pattern for more. 5 | type httpMethods interface { 6 | HTTPMethods() map[string]struct{} 7 | } 8 | 9 | // pathPrefix is an internal interface for the PathPrefix pattern optimization. 10 | // See the documentation on Pattern for more. 11 | type pathPrefix interface { 12 | PathPrefix() string 13 | } 14 | -------------------------------------------------------------------------------- /vendor/goji.io/pattern/pattern.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package pattern contains utilities for Goji Pattern authors. 3 | 4 | Goji users should not import this package. Instead, use the utilities provided 5 | by your Pattern package. If you are looking for an implementation of Pattern, 6 | try Goji's pat subpackage, which contains a simple domain specific language for 7 | specifying routes. 8 | 9 | For Pattern authors, use of this subpackage is entirely optional. Nevertheless, 10 | authors who wish to take advantage of Goji's PathPrefix optimization or who wish 11 | to standardize on a few common interfaces may find this package useful. 12 | */ 13 | package pattern 14 | 15 | import ( 16 | "goji.io/internal" 17 | "golang.org/x/net/context" 18 | ) 19 | 20 | /* 21 | Variable is a standard type for the names of Pattern-bound variables, e.g. 22 | variables extracted from the URL. Pass the name of a variable, cast to this 23 | type, to context.Context.Value to retrieve the value bound to that name. 24 | */ 25 | type Variable string 26 | 27 | type allVariables struct{} 28 | 29 | /* 30 | AllVariables is a standard value which, when passed to context.Context.Value, 31 | returns all variable bindings present in the context, with bindings in newer 32 | contexts overriding values deeper in the stack. The concrete type 33 | 34 | map[Variable]interface{} 35 | 36 | is used for this purpose. If no variables are bound, nil should be returned 37 | instead of an empty map. 38 | */ 39 | var AllVariables = allVariables{} 40 | 41 | /* 42 | Path returns the path that the Goji router uses to perform the PathPrefix 43 | optimization. While this function does not distinguish between the absence of a 44 | path and an empty path, Goji will automatically extract a path from the request 45 | if none is present. 46 | 47 | By convention, paths are stored in their escaped form (i.e., the value returned 48 | by net/url.URL.EscapedPath, and not URL.Path) to ensure that Patterns have as 49 | much discretion as possible (e.g., to behave differently for '/' and '%2f'). 50 | */ 51 | func Path(ctx context.Context) string { 52 | pi := ctx.Value(internal.Path) 53 | if pi == nil { 54 | return "" 55 | } 56 | return pi.(string) 57 | } 58 | 59 | /* 60 | SetPath returns a new context in which the given path is used by the Goji Router 61 | when performing the PathPrefix optimization. See Path for more information about 62 | the intended semantics of this path. 63 | */ 64 | func SetPath(ctx context.Context, path string) context.Context { 65 | return context.WithValue(ctx, internal.Path, path) 66 | } 67 | -------------------------------------------------------------------------------- /vendor/goji.io/pattern/pattern_test.go: -------------------------------------------------------------------------------- 1 | package pattern 2 | 3 | import ( 4 | "net/http" 5 | "testing" 6 | 7 | "golang.org/x/net/context" 8 | ) 9 | 10 | type boolPattern bool 11 | 12 | func (b boolPattern) Match(ctx context.Context, r *http.Request) context.Context { 13 | if b { 14 | return ctx 15 | } 16 | return nil 17 | } 18 | 19 | type prefixPattern string 20 | 21 | func (p prefixPattern) Match(ctx context.Context, r *http.Request) context.Context { 22 | return ctx 23 | } 24 | func (p prefixPattern) PathPrefix() string { 25 | return string(p) 26 | } 27 | 28 | func TestPathRoundTrip(t *testing.T) { 29 | t.Parallel() 30 | 31 | ctx := SetPath(context.Background(), "hi") 32 | if path := Path(ctx); path != "hi" { 33 | t.Errorf("expected hi, got %q", path) 34 | } 35 | 36 | if path := Path(context.Background()); path != "" { 37 | t.Errorf("expected empty path, got %q", path) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /vendor/goji.io/router.go: -------------------------------------------------------------------------------- 1 | package goji 2 | 3 | import ( 4 | "goji.io/internal" 5 | "golang.org/x/net/context" 6 | ) 7 | 8 | type match struct { 9 | context.Context 10 | p Pattern 11 | h Handler 12 | } 13 | 14 | func (m match) Value(key interface{}) interface{} { 15 | switch key { 16 | case internal.Pattern: 17 | return m.p 18 | case internal.Handler: 19 | return m.h 20 | default: 21 | return m.Context.Value(key) 22 | } 23 | } 24 | 25 | var _ context.Context = match{} 26 | -------------------------------------------------------------------------------- /vendor/goji.io/router_simple.go: -------------------------------------------------------------------------------- 1 | // +build goji_router_simple 2 | 3 | package goji 4 | 5 | import ( 6 | "net/http" 7 | 8 | "golang.org/x/net/context" 9 | ) 10 | 11 | /* 12 | This is the simplest correct router implementation for Goji. 13 | */ 14 | 15 | type router []route 16 | 17 | type route struct { 18 | Pattern 19 | Handler 20 | } 21 | 22 | func (rt *router) add(p Pattern, h Handler) { 23 | *rt = append(*rt, route{p, h}) 24 | } 25 | 26 | func (rt *router) route(ctx context.Context, r *http.Request) context.Context { 27 | for _, route := range *rt { 28 | if ctx := route.Match(ctx, r); ctx != nil { 29 | return &match{ctx, route.Pattern, route.Handler} 30 | } 31 | } 32 | return &match{Context: ctx} 33 | } 34 | -------------------------------------------------------------------------------- /vendor/goji.io/util_test.go: -------------------------------------------------------------------------------- 1 | package goji 2 | 3 | import ( 4 | "net/http" 5 | "net/http/httptest" 6 | "strings" 7 | 8 | "goji.io/internal" 9 | "golang.org/x/net/context" 10 | ) 11 | 12 | type boolPattern bool 13 | 14 | func (b boolPattern) Match(ctx context.Context, _ *http.Request) context.Context { 15 | if b { 16 | return ctx 17 | } 18 | return nil 19 | } 20 | 21 | type testPattern struct { 22 | index int 23 | mark *int 24 | methods []string 25 | prefix string 26 | } 27 | 28 | func (t testPattern) Match(ctx context.Context, r *http.Request) context.Context { 29 | if t.index < *t.mark { 30 | return nil 31 | } 32 | path := ctx.Value(internal.Path).(string) 33 | if !strings.HasPrefix(path, t.prefix) { 34 | return nil 35 | } 36 | if t.methods != nil { 37 | if _, ok := t.HTTPMethods()[r.Method]; !ok { 38 | return nil 39 | } 40 | } 41 | return ctx 42 | } 43 | 44 | func (t testPattern) PathPrefix() string { 45 | return t.prefix 46 | } 47 | 48 | func (t testPattern) HTTPMethods() map[string]struct{} { 49 | if t.methods == nil { 50 | return nil 51 | } 52 | m := make(map[string]struct{}) 53 | for _, method := range t.methods { 54 | m[method] = struct{}{} 55 | } 56 | return m 57 | } 58 | 59 | type intHandler int 60 | 61 | func (i intHandler) ServeHTTPC(ctx context.Context, w http.ResponseWriter, r *http.Request) { 62 | } 63 | 64 | func wr() (*httptest.ResponseRecorder, *http.Request) { 65 | w := httptest.NewRecorder() 66 | r, err := http.NewRequest("GET", "/", nil) 67 | if err != nil { 68 | panic(err) 69 | } 70 | return w, r 71 | } 72 | -------------------------------------------------------------------------------- /vendor/golang.org/x/net/context/ctxhttp/cancelreq.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build go1.5 6 | 7 | package ctxhttp 8 | 9 | import "net/http" 10 | 11 | func canceler(client *http.Client, req *http.Request) func() { 12 | // TODO(djd): Respect any existing value of req.Cancel. 13 | ch := make(chan struct{}) 14 | req.Cancel = ch 15 | 16 | return func() { 17 | close(ch) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /vendor/golang.org/x/net/context/ctxhttp/cancelreq_go14.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build !go1.5 6 | 7 | package ctxhttp 8 | 9 | import "net/http" 10 | 11 | type requestCanceler interface { 12 | CancelRequest(*http.Request) 13 | } 14 | 15 | func canceler(client *http.Client, req *http.Request) func() { 16 | rc, ok := client.Transport.(requestCanceler) 17 | if !ok { 18 | return func() {} 19 | } 20 | return func() { 21 | rc.CancelRequest(req) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /vendor/golang.org/x/net/context/withtimeout_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package context_test 6 | 7 | import ( 8 | "fmt" 9 | "time" 10 | 11 | "golang.org/x/net/context" 12 | ) 13 | 14 | func ExampleWithTimeout() { 15 | // Pass a context with a timeout to tell a blocking function that it 16 | // should abandon its work after the timeout elapses. 17 | ctx, _ := context.WithTimeout(context.Background(), 100*time.Millisecond) 18 | select { 19 | case <-time.After(200 * time.Millisecond): 20 | fmt.Println("overslept") 21 | case <-ctx.Done(): 22 | fmt.Println(ctx.Err()) // prints "context deadline exceeded" 23 | } 24 | // Output: 25 | // context deadline exceeded 26 | } 27 | -------------------------------------------------------------------------------- /vendor/golang.org/x/net/netutil/listen.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package netutil provides network utility functions, complementing the more 6 | // common ones in the net package. 7 | package netutil // import "golang.org/x/net/netutil" 8 | 9 | import ( 10 | "net" 11 | "sync" 12 | ) 13 | 14 | // LimitListener returns a Listener that accepts at most n simultaneous 15 | // connections from the provided Listener. 16 | func LimitListener(l net.Listener, n int) net.Listener { 17 | return &limitListener{l, make(chan struct{}, n)} 18 | } 19 | 20 | type limitListener struct { 21 | net.Listener 22 | sem chan struct{} 23 | } 24 | 25 | func (l *limitListener) acquire() { l.sem <- struct{}{} } 26 | func (l *limitListener) release() { <-l.sem } 27 | 28 | func (l *limitListener) Accept() (net.Conn, error) { 29 | l.acquire() 30 | c, err := l.Listener.Accept() 31 | if err != nil { 32 | l.release() 33 | return nil, err 34 | } 35 | return &limitListenerConn{Conn: c, release: l.release}, nil 36 | } 37 | 38 | type limitListenerConn struct { 39 | net.Conn 40 | releaseOnce sync.Once 41 | release func() 42 | } 43 | 44 | func (l *limitListenerConn) Close() error { 45 | err := l.Conn.Close() 46 | l.releaseOnce.Do(l.release) 47 | return err 48 | } 49 | -------------------------------------------------------------------------------- /vendor/golang.org/x/net/netutil/listen_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package netutil 6 | 7 | import ( 8 | "errors" 9 | "fmt" 10 | "io" 11 | "io/ioutil" 12 | "net" 13 | "net/http" 14 | "sync" 15 | "sync/atomic" 16 | "testing" 17 | "time" 18 | 19 | "golang.org/x/net/internal/nettest" 20 | ) 21 | 22 | func TestLimitListener(t *testing.T) { 23 | const max = 5 24 | attempts := (nettest.MaxOpenFiles() - max) / 2 25 | if attempts > 256 { // maximum length of accept queue is 128 by default 26 | attempts = 256 27 | } 28 | 29 | l, err := net.Listen("tcp", "127.0.0.1:0") 30 | if err != nil { 31 | t.Fatal(err) 32 | } 33 | defer l.Close() 34 | l = LimitListener(l, max) 35 | 36 | var open int32 37 | go http.Serve(l, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 38 | if n := atomic.AddInt32(&open, 1); n > max { 39 | t.Errorf("%d open connections, want <= %d", n, max) 40 | } 41 | defer atomic.AddInt32(&open, -1) 42 | time.Sleep(10 * time.Millisecond) 43 | fmt.Fprint(w, "some body") 44 | })) 45 | 46 | var wg sync.WaitGroup 47 | var failed int32 48 | for i := 0; i < attempts; i++ { 49 | wg.Add(1) 50 | go func() { 51 | defer wg.Done() 52 | c := http.Client{Timeout: 3 * time.Second} 53 | r, err := c.Get("http://" + l.Addr().String()) 54 | if err != nil { 55 | t.Log(err) 56 | atomic.AddInt32(&failed, 1) 57 | return 58 | } 59 | defer r.Body.Close() 60 | io.Copy(ioutil.Discard, r.Body) 61 | }() 62 | } 63 | wg.Wait() 64 | 65 | // We expect some Gets to fail as the kernel's accept queue is filled, 66 | // but most should succeed. 67 | if int(failed) >= attempts/2 { 68 | t.Errorf("%d requests failed within %d attempts", failed, attempts) 69 | } 70 | } 71 | 72 | type errorListener struct { 73 | net.Listener 74 | } 75 | 76 | func (errorListener) Accept() (net.Conn, error) { 77 | return nil, errFake 78 | } 79 | 80 | var errFake = errors.New("fake error from errorListener") 81 | 82 | // This used to hang. 83 | func TestLimitListenerError(t *testing.T) { 84 | donec := make(chan bool, 1) 85 | go func() { 86 | const n = 2 87 | ll := LimitListener(errorListener{}, n) 88 | for i := 0; i < n+1; i++ { 89 | _, err := ll.Accept() 90 | if err != errFake { 91 | t.Fatalf("Accept error = %v; want errFake", err) 92 | } 93 | } 94 | donec <- true 95 | }() 96 | select { 97 | case <-donec: 98 | case <-time.After(5 * time.Second): 99 | t.Fatal("timeout. deadlock?") 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /vendor/manifest: -------------------------------------------------------------------------------- 1 | { 2 | "version": 0, 3 | "dependencies": [ 4 | { 5 | "importpath": "github.com/BurntSushi/migration", 6 | "repository": "https://github.com/BurntSushi/migration", 7 | "revision": "c45b897f13350786ccaf2b7403b92b1c7ad85844", 8 | "branch": "master" 9 | }, 10 | { 11 | "importpath": "github.com/codegangsta/negroni", 12 | "repository": "https://github.com/codegangsta/negroni", 13 | "revision": "c7477ad8e330bef55bf1ebe300cf8aa67c492d1b", 14 | "branch": "master" 15 | }, 16 | { 17 | "importpath": "github.com/comail/colog", 18 | "repository": "https://github.com/comail/colog", 19 | "revision": "fa0611f228ad4add3d26aa2fd9583a81a841a186", 20 | "branch": "master" 21 | }, 22 | { 23 | "importpath": "github.com/go-sql-driver/mysql", 24 | "repository": "https://github.com/go-sql-driver/mysql", 25 | "revision": "1fca743146605a172a266e1654e01e5cd5669bee", 26 | "branch": "master" 27 | }, 28 | { 29 | "importpath": "github.com/jmoiron/sqlx", 30 | "repository": "https://github.com/jmoiron/sqlx", 31 | "revision": "398dd5876282499cdfd4cb8ea0f31a672abe9495", 32 | "branch": "master" 33 | }, 34 | { 35 | "importpath": "github.com/lib/pq", 36 | "repository": "https://github.com/lib/pq", 37 | "revision": "e182dc4027e2ded4b19396d638610f2653295f36", 38 | "branch": "master" 39 | }, 40 | { 41 | "importpath": "github.com/mattn/go-sqlite3", 42 | "repository": "https://github.com/mattn/go-sqlite3", 43 | "revision": "45f056ca8f5ef4ee3f68796167a0a0e6a6214813", 44 | "branch": "master" 45 | }, 46 | { 47 | "importpath": "github.com/oxtoacart/bpool", 48 | "repository": "https://github.com/oxtoacart/bpool", 49 | "revision": "4e1c5567d7c2dd59fa4c7c83d34c2f3528b025d6", 50 | "branch": "master" 51 | }, 52 | { 53 | "importpath": "github.com/tylerb/graceful", 54 | "repository": "https://github.com/tylerb/graceful", 55 | "revision": "7116c7a8115899e80197cd9e0b97998c0f97ed8e", 56 | "branch": "master" 57 | }, 58 | { 59 | "importpath": "goji.io", 60 | "repository": "https://github.com/goji/goji", 61 | "revision": "186fdaee47961b336e41716140ce0bd1ecefe98c", 62 | "branch": "master" 63 | }, 64 | { 65 | "importpath": "goji.io/internal", 66 | "repository": "https://github.com/goji/goji", 67 | "revision": "186fdaee47961b336e41716140ce0bd1ecefe98c", 68 | "branch": "master", 69 | "path": "/internal" 70 | }, 71 | { 72 | "importpath": "goji.io/middleware", 73 | "repository": "https://github.com/goji/goji", 74 | "revision": "186fdaee47961b336e41716140ce0bd1ecefe98c", 75 | "branch": "master", 76 | "path": "/middleware" 77 | }, 78 | { 79 | "importpath": "goji.io/pat", 80 | "repository": "https://github.com/goji/goji", 81 | "revision": "186fdaee47961b336e41716140ce0bd1ecefe98c", 82 | "branch": "master", 83 | "path": "/pat" 84 | }, 85 | { 86 | "importpath": "goji.io/pattern", 87 | "repository": "https://github.com/goji/goji", 88 | "revision": "186fdaee47961b336e41716140ce0bd1ecefe98c", 89 | "branch": "master", 90 | "path": "/pattern" 91 | }, 92 | { 93 | "importpath": "golang.org/x/net/context", 94 | "repository": "https://go.googlesource.com/net", 95 | "revision": "d58ca6618b994150e624f6888d871f4709db51a0", 96 | "branch": "master", 97 | "path": "/context" 98 | }, 99 | { 100 | "importpath": "golang.org/x/net/netutil", 101 | "repository": "https://go.googlesource.com/net", 102 | "revision": "d58ca6618b994150e624f6888d871f4709db51a0", 103 | "branch": "master", 104 | "path": "/netutil" 105 | } 106 | ] 107 | } --------------------------------------------------------------------------------