Capabilities handling, database.

This commit is contained in:
2019-09-09 21:52:32 +05:00
parent 4e614c094e
commit 28ddc32368
82 changed files with 12467 additions and 20 deletions

11
vendor/github.com/pressly/goose/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,11 @@
.DS_Store
cmd/goose/goose*
*.swp
*.test
# Files output by tests
bin
go.db
sql.db

11
vendor/github.com/pressly/goose/.travis.yml generated vendored Normal file
View File

@@ -0,0 +1,11 @@
sudo: false
language: go
go:
- 1.8
install:
- go get github.com/golang/dep/cmd/dep
- dep ensure
script:
- go test

11
vendor/github.com/pressly/goose/Gopkg.toml generated vendored Normal file
View File

@@ -0,0 +1,11 @@
[[constraint]]
name = "github.com/go-sql-driver/mysql"
version = "^1.3.0"
[[constraint]]
branch = "master"
name = "github.com/lib/pq"
[[constraint]]
name = "github.com/mattn/go-sqlite3"
version = "^1.2.0"

21
vendor/github.com/pressly/goose/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
Original work Copyright (c) 2012 Liam Staskawicz
Modified work Copyright (c) 2016 Vojtech Vitek
MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

9
vendor/github.com/pressly/goose/Makefile generated vendored Normal file
View File

@@ -0,0 +1,9 @@
.PHONY: dist
dist:
@mkdir -p ./bin
@rm -f ./bin/*
GOOS=darwin GOARCH=amd64 go build -o ./bin/goose-darwin64 ./cmd/goose
GOOS=linux GOARCH=amd64 go build -o ./bin/goose-linux64 ./cmd/goose
GOOS=linux GOARCH=386 go build -o ./bin/goose-linux386 ./cmd/goose
GOOS=windows GOARCH=amd64 go build -o ./bin/goose-windows64.exe ./cmd/goose
GOOS=windows GOARCH=386 go build -o ./bin/goose-windows386.exe ./cmd/goose

256
vendor/github.com/pressly/goose/README.md generated vendored Normal file
View File

@@ -0,0 +1,256 @@
# goose
Goose is a database migration tool. Manage your database schema by creating incremental SQL changes or Go functions.
[![GoDoc Widget]][GoDoc] [![Travis Widget]][Travis]
### Goals of this fork
`github.com/pressly/goose` is a fork of `bitbucket.org/liamstask/goose` with the following changes:
- No config files
- [Default goose binary](./cmd/goose/main.go) can migrate SQL files only
- Go migrations:
- We don't `go build` Go migrations functions on-the-fly
from within the goose binary
- Instead, we let you
[create your own custom goose binary](examples/go-migrations),
register your Go migration functions explicitly and run complex
migrations with your own `*sql.DB` connection
- Go migration functions let you run your code within
an SQL transaction, if you use the `*sql.Tx` argument
- The goose pkg is decoupled from the binary:
- goose pkg doesn't register any SQL drivers anymore,
thus no driver `panic()` conflict within your codebase!
- goose pkg doesn't have any vendor dependencies anymore
- We use timestamped migrations by default but recommend a hybrid approach of using timestamps in the development process and sequential versions in production.
# Install
$ go get -u github.com/pressly/goose/cmd/goose
This will install the `goose` binary to your `$GOPATH/bin` directory.
For a lite version of the binary without DB connection dependent commands, use the exclusive build tags:
$ go build -tags='no_mysql no_sqlite no_psql' -i -o goose ./cmd/goose
# Usage
```
Usage: goose [OPTIONS] DRIVER DBSTRING COMMAND
Drivers:
postgres
mysql
sqlite3
redshift
Commands:
up Migrate the DB to the most recent version available
up-to VERSION Migrate the DB to a specific VERSION
down Roll back the version by 1
down-to VERSION Roll back to a specific VERSION
redo Re-run the latest migration
status Dump the migration status for the current DB
version Print the current version of the database
create NAME [sql|go] Creates new migration file with the current timestamp
Options:
-dir string
directory with migration files (default ".")
Examples:
goose sqlite3 ./foo.db status
goose sqlite3 ./foo.db create init sql
goose sqlite3 ./foo.db create add_some_column sql
goose sqlite3 ./foo.db create fetch_user_data go
goose sqlite3 ./foo.db up
goose postgres "user=postgres dbname=postgres sslmode=disable" status
goose mysql "user:password@/dbname?parseTime=true" status
goose redshift "postgres://user:password@qwerty.us-east-1.redshift.amazonaws.com:5439/db" status
goose tidb "user:password@/dbname?parseTime=true" status
```
## create
Create a new SQL migration.
$ goose create add_some_column sql
$ Created new file: 20170506082420_add_some_column.sql
Edit the newly created file to define the behavior of your migration.
You can also create a Go migration, if you then invoke it with [your own goose binary](#go-migrations):
$ goose create fetch_user_data go
$ Created new file: 20170506082421_fetch_user_data.go
## up
Apply all available migrations.
$ goose up
$ OK 001_basics.sql
$ OK 002_next.sql
$ OK 003_and_again.go
## up-to
Migrate up to a specific version.
$ goose up-to 20170506082420
$ OK 20170506082420_create_table.sql
## down
Roll back a single migration from the current version.
$ goose down
$ OK 003_and_again.go
## down-to
Roll back migrations to a specific version.
$ goose down-to 20170506082527
$ OK 20170506082527_alter_column.sql
## redo
Roll back the most recently applied migration, then run it again.
$ goose redo
$ OK 003_and_again.go
$ OK 003_and_again.go
## status
Print the status of all migrations:
$ goose status
$ Applied At Migration
$ =======================================
$ Sun Jan 6 11:25:03 2013 -- 001_basics.sql
$ Sun Jan 6 11:25:03 2013 -- 002_next.sql
$ Pending -- 003_and_again.go
Note: for MySQL [parseTime flag](https://github.com/go-sql-driver/mysql#parsetime) must be enabled.
## version
Print the current version of the database:
$ goose version
$ goose: version 002
# Migrations
goose supports migrations written in SQL or in Go.
## SQL Migrations
A sample SQL migration looks like:
```sql
-- +goose Up
CREATE TABLE post (
id int NOT NULL,
title text,
body text,
PRIMARY KEY(id)
);
-- +goose Down
DROP TABLE post;
```
Notice the annotations in the comments. Any statements following `-- +goose Up` will be executed as part of a forward migration, and any statements following `-- +goose Down` will be executed as part of a rollback.
By default, all migrations are run within a transaction. Some statements like `CREATE DATABASE`, however, cannot be run within a transaction. You may optionally add `-- +goose NO TRANSACTION` to the top of your migration
file in order to skip transactions within that specific migration file. Both Up and Down migrations within this file will be run without transactions.
By default, SQL statements are delimited by semicolons - in fact, query statements must end with a semicolon to be properly recognized by goose.
More complex statements (PL/pgSQL) that have semicolons within them must be annotated with `-- +goose StatementBegin` and `-- +goose StatementEnd` to be properly recognized. For example:
```sql
-- +goose Up
-- +goose StatementBegin
CREATE OR REPLACE FUNCTION histories_partition_creation( DATE, DATE )
returns void AS $$
DECLARE
create_query text;
BEGIN
FOR create_query IN SELECT
'CREATE TABLE IF NOT EXISTS histories_'
|| TO_CHAR( d, 'YYYY_MM' )
|| ' ( CHECK( created_at >= timestamp '''
|| TO_CHAR( d, 'YYYY-MM-DD 00:00:00' )
|| ''' AND created_at < timestamp '''
|| TO_CHAR( d + INTERVAL '1 month', 'YYYY-MM-DD 00:00:00' )
|| ''' ) ) inherits ( histories );'
FROM generate_series( $1, $2, '1 month' ) AS d
LOOP
EXECUTE create_query;
END LOOP; -- LOOP END
END; -- FUNCTION END
$$
language plpgsql;
-- +goose StatementEnd
```
## Go Migrations
1. Create your own goose binary, see [example](./examples/go-migrations)
2. Import `github.com/pressly/goose`
3. Register your migration functions
4. Run goose command, ie. `goose.Up(db *sql.DB, dir string)`
A [sample Go migration 00002_users_add_email.go file](./example/migrations-go/00002_rename_root.go) looks like:
```go
package migrations
import (
"database/sql"
"github.com/pressly/goose"
)
func init() {
goose.AddMigration(Up, Down)
}
func Up(tx *sql.Tx) error {
_, err := tx.Exec("UPDATE users SET username='admin' WHERE username='root';")
if err != nil {
return err
}
return nil
}
func Down(tx *sql.Tx) error {
_, err := tx.Exec("UPDATE users SET username='root' WHERE username='admin';")
if err != nil {
return err
}
return nil
}
```
# Hybrid Versioning
Please, read the [versioning problem](https://github.com/pressly/goose/issues/63#issuecomment-428681694) first.
We strongly recommend adopting a hybrid versioning approach, using both timestamps and sequential numbers. Migrations created during the development process are timestamped and sequential versions are ran on production. We believe this method will prevent the problem of conflicting versions when writing software in a team environment.
To help you adopt this approach, `create` will use the current timestamp as the migration version. When you're ready to deploy your migrations in a production environment, we also provide a helpful `fix` command to convert your migrations into sequential order, while preserving the timestamp ordering. We recommend running `fix` in the CI pipeline, and only when the migrations are ready for production.
## License
Licensed under [MIT License](./LICENSE)
[GoDoc]: https://godoc.org/github.com/pressly/goose
[GoDoc Widget]: https://godoc.org/github.com/pressly/goose?status.svg
[Travis]: https://travis-ci.org/pressly/goose
[Travis Widget]: https://travis-ci.org/pressly/goose.svg?branch=master

88
vendor/github.com/pressly/goose/create.go generated vendored Normal file
View File

@@ -0,0 +1,88 @@
package goose
import (
"database/sql"
"fmt"
"os"
"path/filepath"
"text/template"
"time"
)
// Create writes a new blank migration file.
func CreateWithTemplate(db *sql.DB, dir string, migrationTemplate *template.Template, name, migrationType string) error {
version := time.Now().Format(timestampFormat)
filename := fmt.Sprintf("%v_%v.%v", version, name, migrationType)
fpath := filepath.Join(dir, filename)
tmpl := sqlMigrationTemplate
if migrationType == "go" {
tmpl = goSQLMigrationTemplate
}
if migrationTemplate != nil {
tmpl = migrationTemplate
}
path, err := writeTemplateToFile(fpath, tmpl, version)
if err != nil {
return err
}
log.Printf("Created new file: %s\n", path)
return nil
}
// Create writes a new blank migration file.
func Create(db *sql.DB, dir, name, migrationType string) error {
return CreateWithTemplate(db, dir, nil, name, migrationType)
}
func writeTemplateToFile(path string, t *template.Template, version string) (string, error) {
if _, err := os.Stat(path); !os.IsNotExist(err) {
return "", fmt.Errorf("failed to create file: %v already exists", path)
}
f, err := os.Create(path)
if err != nil {
return "", err
}
defer f.Close()
err = t.Execute(f, version)
if err != nil {
return "", err
}
return f.Name(), nil
}
var sqlMigrationTemplate = template.Must(template.New("goose.sql-migration").Parse(`-- +goose Up
-- SQL in this section is executed when the migration is applied.
-- +goose Down
-- SQL in this section is executed when the migration is rolled back.
`))
var goSQLMigrationTemplate = template.Must(template.New("goose.go-migration").Parse(`package migration
import (
"database/sql"
"github.com/pressly/goose"
)
func init() {
goose.AddMigration(Up{{.}}, Down{{.}})
}
func Up{{.}}(tx *sql.Tx) error {
// This code is executed when the migration is applied.
return nil
}
func Down{{.}}(tx *sql.Tx) error {
// This code is executed when the migration is rolled back.
return nil
}
`))

211
vendor/github.com/pressly/goose/dialect.go generated vendored Normal file
View File

@@ -0,0 +1,211 @@
package goose
import (
"database/sql"
"fmt"
)
// SQLDialect abstracts the details of specific SQL dialects
// for goose's few SQL specific statements
type SQLDialect interface {
createVersionTableSQL() string // sql string to create the db version table
insertVersionSQL() string // sql string to insert the initial version table row
deleteVersionSQL() string // sql string to delete version
dbVersionQuery(db *sql.DB) (*sql.Rows, error)
}
var dialect SQLDialect = &PostgresDialect{}
// GetDialect gets the SQLDialect
func GetDialect() SQLDialect {
return dialect
}
// SetDialect sets the SQLDialect
func SetDialect(d string) error {
switch d {
case "postgres":
dialect = &PostgresDialect{}
case "mysql":
dialect = &MySQLDialect{}
case "sqlite3":
dialect = &Sqlite3Dialect{}
case "redshift":
dialect = &RedshiftDialect{}
case "tidb":
dialect = &TiDBDialect{}
default:
return fmt.Errorf("%q: unknown dialect", d)
}
return nil
}
////////////////////////////
// Postgres
////////////////////////////
// PostgresDialect struct.
type PostgresDialect struct{}
func (pg PostgresDialect) createVersionTableSQL() string {
return fmt.Sprintf(`CREATE TABLE %s (
id serial NOT NULL,
version_id bigint NOT NULL,
is_applied boolean NOT NULL,
tstamp timestamp NULL default now(),
PRIMARY KEY(id)
);`, TableName())
}
func (pg PostgresDialect) insertVersionSQL() string {
return fmt.Sprintf("INSERT INTO %s (version_id, is_applied) VALUES ($1, $2);", TableName())
}
func (pg PostgresDialect) dbVersionQuery(db *sql.DB) (*sql.Rows, error) {
rows, err := db.Query(fmt.Sprintf("SELECT version_id, is_applied from %s ORDER BY id DESC", TableName()))
if err != nil {
return nil, err
}
return rows, err
}
func (pg PostgresDialect) deleteVersionSQL() string {
return fmt.Sprintf("DELETE FROM %s WHERE version_id=$1;", TableName())
}
////////////////////////////
// MySQL
////////////////////////////
// MySQLDialect struct.
type MySQLDialect struct{}
func (m MySQLDialect) createVersionTableSQL() string {
return fmt.Sprintf(`CREATE TABLE %s (
id serial NOT NULL,
version_id bigint NOT NULL,
is_applied boolean NOT NULL,
tstamp timestamp NULL default now(),
PRIMARY KEY(id)
);`, TableName())
}
func (m MySQLDialect) insertVersionSQL() string {
return fmt.Sprintf("INSERT INTO %s (version_id, is_applied) VALUES (?, ?);", TableName())
}
func (m MySQLDialect) dbVersionQuery(db *sql.DB) (*sql.Rows, error) {
rows, err := db.Query(fmt.Sprintf("SELECT version_id, is_applied from %s ORDER BY id DESC", TableName()))
if err != nil {
return nil, err
}
return rows, err
}
func (m MySQLDialect) deleteVersionSQL() string {
return fmt.Sprintf("DELETE FROM %s WHERE version_id=?;", TableName())
}
////////////////////////////
// sqlite3
////////////////////////////
// Sqlite3Dialect struct.
type Sqlite3Dialect struct{}
func (m Sqlite3Dialect) createVersionTableSQL() string {
return fmt.Sprintf(`CREATE TABLE %s (
id INTEGER PRIMARY KEY AUTOINCREMENT,
version_id INTEGER NOT NULL,
is_applied INTEGER NOT NULL,
tstamp TIMESTAMP DEFAULT (datetime('now'))
);`, TableName())
}
func (m Sqlite3Dialect) insertVersionSQL() string {
return fmt.Sprintf("INSERT INTO %s (version_id, is_applied) VALUES (?, ?);", TableName())
}
func (m Sqlite3Dialect) dbVersionQuery(db *sql.DB) (*sql.Rows, error) {
rows, err := db.Query(fmt.Sprintf("SELECT version_id, is_applied from %s ORDER BY id DESC", TableName()))
if err != nil {
return nil, err
}
return rows, err
}
func (m Sqlite3Dialect) deleteVersionSQL() string {
return fmt.Sprintf("DELETE FROM %s WHERE version_id=?;", TableName())
}
////////////////////////////
// Redshift
////////////////////////////
// RedshiftDialect struct.
type RedshiftDialect struct{}
func (rs RedshiftDialect) createVersionTableSQL() string {
return fmt.Sprintf(`CREATE TABLE %s (
id integer NOT NULL identity(1, 1),
version_id bigint NOT NULL,
is_applied boolean NOT NULL,
tstamp timestamp NULL default sysdate,
PRIMARY KEY(id)
);`, TableName())
}
func (rs RedshiftDialect) insertVersionSQL() string {
return fmt.Sprintf("INSERT INTO %s (version_id, is_applied) VALUES ($1, $2);", TableName())
}
func (rs RedshiftDialect) dbVersionQuery(db *sql.DB) (*sql.Rows, error) {
rows, err := db.Query(fmt.Sprintf("SELECT version_id, is_applied from %s ORDER BY id DESC", TableName()))
if err != nil {
return nil, err
}
return rows, err
}
func (rs RedshiftDialect) deleteVersionSQL() string {
return fmt.Sprintf("DELETE FROM %s WHERE version_id=?;", TableName())
}
////////////////////////////
// TiDB
////////////////////////////
// TiDBDialect struct.
type TiDBDialect struct{}
func (m TiDBDialect) createVersionTableSQL() string {
return fmt.Sprintf(`CREATE TABLE %s (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE,
version_id bigint NOT NULL,
is_applied boolean NOT NULL,
tstamp timestamp NULL default now(),
PRIMARY KEY(id)
);`, TableName())
}
func (m TiDBDialect) insertVersionSQL() string {
return fmt.Sprintf("INSERT INTO %s (version_id, is_applied) VALUES (?, ?);", TableName())
}
func (m TiDBDialect) dbVersionQuery(db *sql.DB) (*sql.Rows, error) {
rows, err := db.Query(fmt.Sprintf("SELECT version_id, is_applied from %s ORDER BY id DESC", TableName()))
if err != nil {
return nil, err
}
return rows, err
}
func (m TiDBDialect) deleteVersionSQL() string {
return fmt.Sprintf("DELETE FROM %s WHERE version_id=?;", TableName())
}

56
vendor/github.com/pressly/goose/down.go generated vendored Normal file
View File

@@ -0,0 +1,56 @@
package goose
import (
"database/sql"
"fmt"
)
// Down rolls back a single migration from the current version.
func Down(db *sql.DB, dir string) error {
currentVersion, err := GetDBVersion(db)
if err != nil {
return err
}
migrations, err := CollectMigrations(dir, minVersion, maxVersion)
if err != nil {
return err
}
current, err := migrations.Current(currentVersion)
if err != nil {
return fmt.Errorf("no migration %v", currentVersion)
}
return current.Down(db)
}
// DownTo rolls back migrations to a specific version.
func DownTo(db *sql.DB, dir string, version int64) error {
migrations, err := CollectMigrations(dir, minVersion, maxVersion)
if err != nil {
return err
}
for {
currentVersion, err := GetDBVersion(db)
if err != nil {
return err
}
current, err := migrations.Current(currentVersion)
if err != nil {
log.Printf("goose: no migrations to run. current version: %d\n", currentVersion)
return nil
}
if current.Version <= version {
log.Printf("goose: no migrations to run. current version: %d\n", currentVersion)
return nil
}
if err = current.Down(db); err != nil {
return err
}
}
}

46
vendor/github.com/pressly/goose/fix.go generated vendored Normal file
View File

@@ -0,0 +1,46 @@
package goose
import (
"fmt"
"os"
"path/filepath"
"strings"
)
func Fix(dir string) error {
migrations, err := CollectMigrations(dir, minVersion, maxVersion)
if err != nil {
return err
}
// split into timestamped and versioned migrations
tsMigrations, err := migrations.timestamped()
if err != nil {
return err
}
vMigrations, err := migrations.versioned()
if err != nil {
return err
}
// Initial version.
version := int64(1)
if last, err := vMigrations.Last(); err == nil {
version = last.Version + 1
}
// fix filenames by replacing timestamps with sequential versions
for _, tsm := range tsMigrations {
oldPath := tsm.Source
newPath := strings.Replace(oldPath, fmt.Sprintf("%d", tsm.Version), fmt.Sprintf("%05v", version), 1)
if err := os.Rename(oldPath, newPath); err != nil {
return err
}
log.Printf("RENAMED %s => %s", filepath.Base(oldPath), filepath.Base(newPath))
version++
}
return nil
}

100
vendor/github.com/pressly/goose/goose.go generated vendored Normal file
View File

@@ -0,0 +1,100 @@
package goose
import (
"database/sql"
"fmt"
"strconv"
"sync"
)
const VERSION = "v2.6.0"
var (
duplicateCheckOnce sync.Once
minVersion = int64(0)
maxVersion = int64((1 << 63) - 1)
timestampFormat = "20060102150405"
verbose = false
)
// SetVerbose set the goose verbosity mode
func SetVerbose(v bool) {
verbose = v
}
// Run runs a goose command.
func Run(command string, db *sql.DB, dir string, args ...string) error {
switch command {
case "up":
if err := Up(db, dir); err != nil {
return err
}
case "up-by-one":
if err := UpByOne(db, dir); err != nil {
return err
}
case "up-to":
if len(args) == 0 {
return fmt.Errorf("up-to must be of form: goose [OPTIONS] DRIVER DBSTRING up-to VERSION")
}
version, err := strconv.ParseInt(args[0], 10, 64)
if err != nil {
return fmt.Errorf("version must be a number (got '%s')", args[0])
}
if err := UpTo(db, dir, version); err != nil {
return err
}
case "create":
if len(args) == 0 {
return fmt.Errorf("create must be of form: goose [OPTIONS] DRIVER DBSTRING create NAME [go|sql]")
}
migrationType := "go"
if len(args) == 2 {
migrationType = args[1]
}
if err := Create(db, dir, args[0], migrationType); err != nil {
return err
}
case "down":
if err := Down(db, dir); err != nil {
return err
}
case "down-to":
if len(args) == 0 {
return fmt.Errorf("down-to must be of form: goose [OPTIONS] DRIVER DBSTRING down-to VERSION")
}
version, err := strconv.ParseInt(args[0], 10, 64)
if err != nil {
return fmt.Errorf("version must be a number (got '%s')", args[0])
}
if err := DownTo(db, dir, version); err != nil {
return err
}
case "fix":
if err := Fix(dir); err != nil {
return err
}
case "redo":
if err := Redo(db, dir); err != nil {
return err
}
case "reset":
if err := Reset(db, dir); err != nil {
return err
}
case "status":
if err := Status(db, dir); err != nil {
return err
}
case "version":
if err := Version(db, dir); err != nil {
return err
}
default:
return fmt.Errorf("%q: no such command", command)
}
return nil
}

30
vendor/github.com/pressly/goose/log.go generated vendored Normal file
View File

@@ -0,0 +1,30 @@
package goose
import (
std "log"
)
var log Logger = &stdLogger{}
// Logger is standart logger interface
type Logger interface {
Fatal(v ...interface{})
Fatalf(format string, v ...interface{})
Print(v ...interface{})
Println(v ...interface{})
Printf(format string, v ...interface{})
}
// SetLogger sets the logger for package output
func SetLogger(l Logger) {
log = l
}
// stdLogger is a default logger that outputs to a stdlib's log.std logger.
type stdLogger struct{}
func (*stdLogger) Fatal(v ...interface{}) { std.Fatal(v...) }
func (*stdLogger) Fatalf(format string, v ...interface{}) { std.Fatalf(format, v...) }
func (*stdLogger) Print(v ...interface{}) { std.Print(v...) }
func (*stdLogger) Println(v ...interface{}) { std.Println(v...) }
func (*stdLogger) Printf(format string, v ...interface{}) { std.Printf(format, v...) }

319
vendor/github.com/pressly/goose/migrate.go generated vendored Normal file
View File

@@ -0,0 +1,319 @@
package goose
import (
"database/sql"
"fmt"
"os"
"path/filepath"
"runtime"
"sort"
"time"
"github.com/pkg/errors"
)
var (
// ErrNoCurrentVersion when a current migration version is not found.
ErrNoCurrentVersion = errors.New("no current version found")
// ErrNoNextVersion when the next migration version is not found.
ErrNoNextVersion = errors.New("no next version found")
// MaxVersion is the maximum allowed version.
MaxVersion int64 = 9223372036854775807 // max(int64)
registeredGoMigrations = map[int64]*Migration{}
)
// Migrations slice.
type Migrations []*Migration
// helpers so we can use pkg sort
func (ms Migrations) Len() int { return len(ms) }
func (ms Migrations) Swap(i, j int) { ms[i], ms[j] = ms[j], ms[i] }
func (ms Migrations) Less(i, j int) bool {
if ms[i].Version == ms[j].Version {
panic(fmt.Sprintf("goose: duplicate version %v detected:\n%v\n%v", ms[i].Version, ms[i].Source, ms[j].Source))
}
return ms[i].Version < ms[j].Version
}
// Current gets the current migration.
func (ms Migrations) Current(current int64) (*Migration, error) {
for i, migration := range ms {
if migration.Version == current {
return ms[i], nil
}
}
return nil, ErrNoCurrentVersion
}
// Next gets the next migration.
func (ms Migrations) Next(current int64) (*Migration, error) {
for i, migration := range ms {
if migration.Version > current {
return ms[i], nil
}
}
return nil, ErrNoNextVersion
}
// Previous : Get the previous migration.
func (ms Migrations) Previous(current int64) (*Migration, error) {
for i := len(ms) - 1; i >= 0; i-- {
if ms[i].Version < current {
return ms[i], nil
}
}
return nil, ErrNoNextVersion
}
// Last gets the last migration.
func (ms Migrations) Last() (*Migration, error) {
if len(ms) == 0 {
return nil, ErrNoNextVersion
}
return ms[len(ms)-1], nil
}
// Versioned gets versioned migrations.
func (ms Migrations) versioned() (Migrations, error) {
var migrations Migrations
// assume that the user will never have more than 19700101000000 migrations
for _, m := range ms {
// parse version as timestmap
versionTime, err := time.Parse(timestampFormat, fmt.Sprintf("%d", m.Version))
if versionTime.Before(time.Unix(0, 0)) || err != nil {
migrations = append(migrations, m)
}
}
return migrations, nil
}
// Timestamped gets the timestamped migrations.
func (ms Migrations) timestamped() (Migrations, error) {
var migrations Migrations
// assume that the user will never have more than 19700101000000 migrations
for _, m := range ms {
// parse version as timestmap
versionTime, err := time.Parse(timestampFormat, fmt.Sprintf("%d", m.Version))
if err != nil {
// probably not a timestamp
continue
}
if versionTime.After(time.Unix(0, 0)) {
migrations = append(migrations, m)
}
}
return migrations, nil
}
func (ms Migrations) String() string {
str := ""
for _, m := range ms {
str += fmt.Sprintln(m)
}
return str
}
// AddMigration adds a migration.
func AddMigration(up func(*sql.Tx) error, down func(*sql.Tx) error) {
_, filename, _, _ := runtime.Caller(1)
AddNamedMigration(filename, up, down)
}
// AddNamedMigration : Add a named migration.
func AddNamedMigration(filename string, up func(*sql.Tx) error, down func(*sql.Tx) error) {
v, _ := NumericComponent(filename)
migration := &Migration{Version: v, Next: -1, Previous: -1, Registered: true, UpFn: up, DownFn: down, Source: filename}
if existing, ok := registeredGoMigrations[v]; ok {
panic(fmt.Sprintf("failed to add migration %q: version conflicts with %q", filename, existing.Source))
}
registeredGoMigrations[v] = migration
}
// CollectMigrations returns all the valid looking migration scripts in the
// migrations folder and go func registry, and key them by version.
func CollectMigrations(dirpath string, current, target int64) (Migrations, error) {
if _, err := os.Stat(dirpath); os.IsNotExist(err) {
return nil, fmt.Errorf("%s directory does not exists", dirpath)
}
var migrations Migrations
// SQL migration files.
sqlMigrationFiles, err := filepath.Glob(dirpath + "/**.sql")
if err != nil {
return nil, err
}
for _, file := range sqlMigrationFiles {
v, err := NumericComponent(file)
if err != nil {
return nil, err
}
if versionFilter(v, current, target) {
migration := &Migration{Version: v, Next: -1, Previous: -1, Source: file}
migrations = append(migrations, migration)
}
}
// Go migrations registered via goose.AddMigration().
for _, migration := range registeredGoMigrations {
v, err := NumericComponent(migration.Source)
if err != nil {
return nil, err
}
if versionFilter(v, current, target) {
migrations = append(migrations, migration)
}
}
// Go migration files
goMigrationFiles, err := filepath.Glob(dirpath + "/**.go")
if err != nil {
return nil, err
}
for _, file := range goMigrationFiles {
v, err := NumericComponent(file)
if err != nil {
continue // Skip any files that don't have version prefix.
}
// Skip migrations already existing migrations registered via goose.AddMigration().
if _, ok := registeredGoMigrations[v]; ok {
continue
}
if versionFilter(v, current, target) {
migration := &Migration{Version: v, Next: -1, Previous: -1, Source: file, Registered: false}
migrations = append(migrations, migration)
}
}
migrations = sortAndConnectMigrations(migrations)
return migrations, nil
}
func sortAndConnectMigrations(migrations Migrations) Migrations {
sort.Sort(migrations)
// now that we're sorted in the appropriate direction,
// populate next and previous for each migration
for i, m := range migrations {
prev := int64(-1)
if i > 0 {
prev = migrations[i-1].Version
migrations[i-1].Next = m.Version
}
migrations[i].Previous = prev
}
return migrations
}
func versionFilter(v, current, target int64) bool {
if target > current {
return v > current && v <= target
}
if target < current {
return v <= current && v > target
}
return false
}
// EnsureDBVersion retrieves the current version for this DB.
// Create and initialize the DB version table if it doesn't exist.
func EnsureDBVersion(db *sql.DB) (int64, error) {
rows, err := GetDialect().dbVersionQuery(db)
if err != nil {
return 0, createVersionTable(db)
}
defer rows.Close()
// The most recent record for each migration specifies
// whether it has been applied or rolled back.
// The first version we find that has been applied is the current version.
toSkip := make([]int64, 0)
for rows.Next() {
var row MigrationRecord
if err = rows.Scan(&row.VersionID, &row.IsApplied); err != nil {
return 0, errors.Wrap(err, "failed to scan row")
}
// have we already marked this version to be skipped?
skip := false
for _, v := range toSkip {
if v == row.VersionID {
skip = true
break
}
}
if skip {
continue
}
// if version has been applied we're done
if row.IsApplied {
return row.VersionID, nil
}
// latest version of migration has not been applied.
toSkip = append(toSkip, row.VersionID)
}
if err := rows.Err(); err != nil {
return 0, errors.Wrap(err, "failed to get next row")
}
return 0, ErrNoNextVersion
}
// Create the db version table
// and insert the initial 0 value into it
func createVersionTable(db *sql.DB) error {
txn, err := db.Begin()
if err != nil {
return err
}
d := GetDialect()
if _, err := txn.Exec(d.createVersionTableSQL()); err != nil {
txn.Rollback()
return err
}
version := 0
applied := true
if _, err := txn.Exec(d.insertVersionSQL(), version, applied); err != nil {
txn.Rollback()
return err
}
return txn.Commit()
}
// GetDBVersion is an alias for EnsureDBVersion, but returns -1 in error.
func GetDBVersion(db *sql.DB) (int64, error) {
version, err := EnsureDBVersion(db)
if err != nil {
return -1, err
}
return version, nil
}

124
vendor/github.com/pressly/goose/migration.go generated vendored Normal file
View File

@@ -0,0 +1,124 @@
package goose
import (
"database/sql"
"fmt"
"path/filepath"
"strconv"
"strings"
"time"
"github.com/pkg/errors"
)
// MigrationRecord struct.
type MigrationRecord struct {
VersionID int64
TStamp time.Time
IsApplied bool // was this a result of up() or down()
}
// Migration struct.
type Migration struct {
Version int64
Next int64 // next version, or -1 if none
Previous int64 // previous version, -1 if none
Source string // path to .sql script
Registered bool
UpFn func(*sql.Tx) error // Up go migration function
DownFn func(*sql.Tx) error // Down go migration function
}
func (m *Migration) String() string {
return fmt.Sprintf(m.Source)
}
// Up runs an up migration.
func (m *Migration) Up(db *sql.DB) error {
if err := m.run(db, true); err != nil {
return err
}
log.Println("OK ", filepath.Base(m.Source))
return nil
}
// Down runs a down migration.
func (m *Migration) Down(db *sql.DB) error {
if err := m.run(db, false); err != nil {
return err
}
log.Println("OK ", filepath.Base(m.Source))
return nil
}
func (m *Migration) run(db *sql.DB, direction bool) error {
switch filepath.Ext(m.Source) {
case ".sql":
if err := runSQLMigration(db, m.Source, m.Version, direction); err != nil {
return errors.Wrapf(err, "failed to run SQL migration %q", filepath.Base(m.Source))
}
case ".go":
if !m.Registered {
return errors.Errorf("failed to run Go migration %q: Go functions must be registered and built into a custom binary (see https://github.com/pressly/goose/tree/master/examples/go-migrations)", m.Source)
}
tx, err := db.Begin()
if err != nil {
return errors.Wrap(err, "failed to begin transaction")
}
fn := m.UpFn
if !direction {
fn = m.DownFn
}
if fn != nil {
if err := fn(tx); err != nil {
tx.Rollback()
return errors.Wrapf(err, "failed to run Go migration %q", filepath.Base(m.Source))
}
}
if direction {
if _, err := tx.Exec(GetDialect().insertVersionSQL(), m.Version, direction); err != nil {
tx.Rollback()
return errors.Wrap(err, "failed to execute transaction")
}
} else {
if _, err := tx.Exec(GetDialect().deleteVersionSQL(), m.Version); err != nil {
tx.Rollback()
return errors.Wrap(err, "failed to execute transaction")
}
}
if err := tx.Commit(); err != nil {
return errors.Wrap(err, "failed to commit transaction")
}
return nil
}
return nil
}
// NumericComponent looks for migration scripts with names in the form:
// XXX_descriptivename.ext where XXX specifies the version number
// and ext specifies the type of migration
func NumericComponent(name string) (int64, error) {
base := filepath.Base(name)
if ext := filepath.Ext(base); ext != ".go" && ext != ".sql" {
return 0, errors.New("not a recognized migration file type")
}
idx := strings.Index(base, "_")
if idx < 0 {
return 0, errors.New("no separator found")
}
n, e := strconv.ParseInt(base[:idx], 10, 64)
if e == nil && n <= 0 {
return 0, errors.New("migration IDs must be greater than zero")
}
return n, e
}

240
vendor/github.com/pressly/goose/migration_sql.go generated vendored Normal file
View File

@@ -0,0 +1,240 @@
package goose
import (
"bufio"
"bytes"
"database/sql"
"fmt"
"io"
"os"
"regexp"
"strings"
"sync"
"github.com/pkg/errors"
)
const sqlCmdPrefix = "-- +goose "
const scanBufSize = 4 * 1024 * 1024
var bufferPool = sync.Pool{
New: func() interface{} {
return make([]byte, scanBufSize)
},
}
// Checks the line to see if the line has a statement-ending semicolon
// or if the line contains a double-dash comment.
func endsWithSemicolon(line string) bool {
scanBuf := bufferPool.Get().([]byte)
defer bufferPool.Put(scanBuf)
prev := ""
scanner := bufio.NewScanner(strings.NewReader(line))
scanner.Buffer(scanBuf, scanBufSize)
scanner.Split(bufio.ScanWords)
for scanner.Scan() {
word := scanner.Text()
if strings.HasPrefix(word, "--") {
break
}
prev = word
}
return strings.HasSuffix(prev, ";")
}
// Split the given sql script into individual statements.
//
// The base case is to simply split on semicolons, as these
// naturally terminate a statement.
//
// However, more complex cases like pl/pgsql can have semicolons
// within a statement. For these cases, we provide the explicit annotations
// 'StatementBegin' and 'StatementEnd' to allow the script to
// tell us to ignore semicolons.
func getSQLStatements(r io.Reader, direction bool) ([]string, bool, error) {
var buf bytes.Buffer
scanBuf := bufferPool.Get().([]byte)
defer bufferPool.Put(scanBuf)
scanner := bufio.NewScanner(r)
scanner.Buffer(scanBuf, scanBufSize)
// track the count of each section
// so we can diagnose scripts with no annotations
upSections := 0
downSections := 0
statementEnded := false
ignoreSemicolons := false
directionIsActive := false
tx := true
stmts := []string{}
for scanner.Scan() {
line := scanner.Text()
// handle any goose-specific commands
if strings.HasPrefix(line, sqlCmdPrefix) {
cmd := strings.TrimSpace(line[len(sqlCmdPrefix):])
switch cmd {
case "Up":
directionIsActive = (direction == true)
upSections++
break
case "Down":
directionIsActive = (direction == false)
downSections++
break
case "StatementBegin":
if directionIsActive {
ignoreSemicolons = true
}
break
case "StatementEnd":
if directionIsActive {
statementEnded = (ignoreSemicolons == true)
ignoreSemicolons = false
}
break
case "NO TRANSACTION":
tx = false
break
}
}
if !directionIsActive {
continue
}
if _, err := buf.WriteString(line + "\n"); err != nil {
return nil, false, fmt.Errorf("io err: %v", err)
}
// Wrap up the two supported cases: 1) basic with semicolon; 2) psql statement
// Lines that end with semicolon that are in a statement block
// do not conclude statement.
if (!ignoreSemicolons && endsWithSemicolon(line)) || statementEnded {
statementEnded = false
stmts = append(stmts, buf.String())
buf.Reset()
}
}
if err := scanner.Err(); err != nil {
return nil, false, fmt.Errorf("scanning migration: %v", err)
}
// diagnose likely migration script errors
if ignoreSemicolons {
return nil, false, fmt.Errorf("parsing migration: saw '-- +goose StatementBegin' with no matching '-- +goose StatementEnd'")
}
if bufferRemaining := strings.TrimSpace(buf.String()); len(bufferRemaining) > 0 {
return nil, false, fmt.Errorf("parsing migration: unexpected unfinished SQL query: %s. potential missing semicolon", bufferRemaining)
}
if upSections == 0 && downSections == 0 {
return nil, false, fmt.Errorf("parsing migration: no Up/Down annotations found, so no statements were executed. See https://bitbucket.org/liamstask/goose/overview for details")
}
return stmts, tx, nil
}
// Run a migration specified in raw SQL.
//
// Sections of the script can be annotated with a special comment,
// starting with "-- +goose" to specify whether the section should
// be applied during an Up or Down migration
//
// All statements following an Up or Down directive are grouped together
// until another direction directive is found.
func runSQLMigration(db *sql.DB, sqlFile string, v int64, direction bool) error {
f, err := os.Open(sqlFile)
if err != nil {
return errors.Wrap(err, "failed to open SQL migration file")
}
defer f.Close()
statements, useTx, err := getSQLStatements(f, direction)
if err != nil {
return err
}
if useTx {
// TRANSACTION.
printInfo("Begin transaction\n")
tx, err := db.Begin()
if err != nil {
errors.Wrap(err, "failed to begin transaction")
}
for _, query := range statements {
printInfo("Executing statement: %s\n", clearStatement(query))
if _, err = tx.Exec(query); err != nil {
printInfo("Rollback transaction\n")
tx.Rollback()
return errors.Wrapf(err, "failed to execute SQL query %q", clearStatement(query))
}
}
if direction {
if _, err := tx.Exec(GetDialect().insertVersionSQL(), v, direction); err != nil {
printInfo("Rollback transaction\n")
tx.Rollback()
return errors.Wrap(err, "failed to insert new goose version")
}
} else {
if _, err := tx.Exec(GetDialect().deleteVersionSQL(), v); err != nil {
printInfo("Rollback transaction\n")
tx.Rollback()
return errors.Wrap(err, "failed to delete goose version")
}
}
printInfo("Commit transaction\n")
if err := tx.Commit(); err != nil {
return errors.Wrap(err, "failed to commit transaction")
}
return nil
}
// NO TRANSACTION.
for _, query := range statements {
printInfo("Executing statement: %s\n", clearStatement(query))
if _, err := db.Exec(query); err != nil {
return errors.Wrapf(err, "failed to execute SQL query %q", clearStatement(query))
}
}
if _, err := db.Exec(GetDialect().insertVersionSQL(), v, direction); err != nil {
return errors.Wrap(err, "failed to insert new goose version")
}
return nil
}
func printInfo(s string, args ...interface{}) {
if verbose {
log.Printf(s, args...)
}
}
var (
matchSQLComments = regexp.MustCompile(`(?m)^--.*$[\r\n]*`)
matchEmptyLines = regexp.MustCompile(`(?m)^$[\r\n]*`)
)
func clearStatement(s string) string {
s = matchSQLComments.ReplaceAllString(s, ``)
return matchEmptyLines.ReplaceAllString(s, ``)
}

33
vendor/github.com/pressly/goose/redo.go generated vendored Normal file
View File

@@ -0,0 +1,33 @@
package goose
import (
"database/sql"
)
// Redo rolls back the most recently applied migration, then runs it again.
func Redo(db *sql.DB, dir string) error {
currentVersion, err := GetDBVersion(db)
if err != nil {
return err
}
migrations, err := CollectMigrations(dir, minVersion, maxVersion)
if err != nil {
return err
}
current, err := migrations.Current(currentVersion)
if err != nil {
return err
}
if err := current.Down(db); err != nil {
return err
}
if err := current.Up(db); err != nil {
return err
}
return nil
}

60
vendor/github.com/pressly/goose/reset.go generated vendored Normal file
View File

@@ -0,0 +1,60 @@
package goose
import (
"database/sql"
"sort"
"github.com/pkg/errors"
)
// Reset rolls back all migrations
func Reset(db *sql.DB, dir string) error {
migrations, err := CollectMigrations(dir, minVersion, maxVersion)
if err != nil {
return errors.Wrap(err, "failed to collect migrations")
}
statuses, err := dbMigrationsStatus(db)
if err != nil {
return errors.Wrap(err, "failed to get status of migrations")
}
sort.Sort(sort.Reverse(migrations))
for _, migration := range migrations {
if !statuses[migration.Version] {
continue
}
if err = migration.Down(db); err != nil {
return errors.Wrap(err, "failed to db-down")
}
}
return nil
}
func dbMigrationsStatus(db *sql.DB) (map[int64]bool, error) {
rows, err := GetDialect().dbVersionQuery(db)
if err != nil {
return map[int64]bool{}, nil
}
defer rows.Close()
// The most recent record for each migration specifies
// whether it has been applied or rolled back.
result := make(map[int64]bool)
for rows.Next() {
var row MigrationRecord
if err = rows.Scan(&row.VersionID, &row.IsApplied); err != nil {
return nil, errors.Wrap(err, "failed to scan row")
}
if _, ok := result[row.VersionID]; ok {
continue
}
result[row.VersionID] = row.IsApplied
}
return result, nil
}

54
vendor/github.com/pressly/goose/status.go generated vendored Normal file
View File

@@ -0,0 +1,54 @@
package goose
import (
"database/sql"
"fmt"
"path/filepath"
"time"
"github.com/pkg/errors"
)
// Status prints the status of all migrations.
func Status(db *sql.DB, dir string) error {
// collect all migrations
migrations, err := CollectMigrations(dir, minVersion, maxVersion)
if err != nil {
return errors.Wrap(err, "failed to collect migrations")
}
// must ensure that the version table exists if we're running on a pristine DB
if _, err := EnsureDBVersion(db); err != nil {
return errors.Wrap(err, "failed to ensure DB version")
}
log.Println(" Applied At Migration")
log.Println(" =======================================")
for _, migration := range migrations {
if err := printMigrationStatus(db, migration.Version, filepath.Base(migration.Source)); err != nil {
return errors.Wrap(err, "failed to print status")
}
}
return nil
}
func printMigrationStatus(db *sql.DB, version int64, script string) error {
q := fmt.Sprintf("SELECT tstamp, is_applied FROM %s WHERE version_id=%d ORDER BY tstamp DESC LIMIT 1", TableName(), version)
var row MigrationRecord
err := db.QueryRow(q).Scan(&row.TStamp, &row.IsApplied)
if err != nil && err != sql.ErrNoRows {
return errors.Wrap(err, "failed to query the latest migration")
}
var appliedAt string
if row.IsApplied {
appliedAt = row.TStamp.Format(time.ANSIC)
} else {
appliedAt = "Pending"
}
log.Printf(" %-24s -- %v\n", appliedAt, script)
return nil
}

65
vendor/github.com/pressly/goose/up.go generated vendored Normal file
View File

@@ -0,0 +1,65 @@
package goose
import (
"database/sql"
)
// UpTo migrates up to a specific version.
func UpTo(db *sql.DB, dir string, version int64) error {
migrations, err := CollectMigrations(dir, minVersion, version)
if err != nil {
return err
}
for {
current, err := GetDBVersion(db)
if err != nil {
return err
}
next, err := migrations.Next(current)
if err != nil {
if err == ErrNoNextVersion {
log.Printf("goose: no migrations to run. current version: %d\n", current)
return nil
}
return err
}
if err = next.Up(db); err != nil {
return err
}
}
}
// Up applies all available migrations.
func Up(db *sql.DB, dir string) error {
return UpTo(db, dir, maxVersion)
}
// UpByOne migrates up by a single version.
func UpByOne(db *sql.DB, dir string) error {
migrations, err := CollectMigrations(dir, minVersion, maxVersion)
if err != nil {
return err
}
currentVersion, err := GetDBVersion(db)
if err != nil {
return err
}
next, err := migrations.Next(currentVersion)
if err != nil {
if err == ErrNoNextVersion {
log.Printf("goose: no migrations to run. current version: %d\n", currentVersion)
}
return err
}
if err = next.Up(db); err != nil {
return err
}
return nil
}

28
vendor/github.com/pressly/goose/version.go generated vendored Normal file
View File

@@ -0,0 +1,28 @@
package goose
import (
"database/sql"
)
// Version prints the current version of the database.
func Version(db *sql.DB, dir string) error {
current, err := GetDBVersion(db)
if err != nil {
return err
}
log.Printf("goose: version %v\n", current)
return nil
}
var tableName = "goose_db_version"
// TableName returns goose db version table name
func TableName() string {
return tableName
}
// SetTableName set goose db version table name
func SetTableName(n string) {
tableName = n
}