├── .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 |
7 | {{ range .People }}
8 | -
9 | {{.Name}}
10 |
11 | {{ end }}
12 |
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 | [](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 | [](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 | [](https://travis-ci.org/mattn/go-sqlite3)
5 | [](https://coveralls.io/r/mattn/go-sqlite3?branch=master)
6 | [](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 [](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 | [](https://godoc.org/goji.io) [](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 | }
--------------------------------------------------------------------------------