Rebooting
This commit is contained in:
parent
41ee2857ee
commit
6030310caa
149 changed files with 1489 additions and 9755 deletions
28
Godeps/Godeps.json
generated
28
Godeps/Godeps.json
generated
|
@ -1,24 +1,20 @@
|
|||
{
|
||||
"ImportPath": "github.com/thermokarst/bactdb",
|
||||
"GoVersion": "go1.4.1",
|
||||
"GoVersion": "go1.4.2",
|
||||
"Deps": [
|
||||
{
|
||||
"ImportPath": "github.com/DavidHuie/gomigrate",
|
||||
"Rev": "7883dd76040debc099811feadd58425b1495103d"
|
||||
"Rev": "cfb6d067cc41d95acfa2e5f496dd236346a8175e"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/codegangsta/cli",
|
||||
"Comment": "1.2.0-62-gbf4a526",
|
||||
"Rev": "bf4a526f48af7badd25d2cb02d587e1b01be3b50"
|
||||
"Comment": "1.2.0-93-g2bcd11f",
|
||||
"Rev": "2bcd11f863d540a1b190dc03b6c4f634c6ae91d4"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/dgrijalva/jwt-go",
|
||||
"Comment": "v2.2.0-11-g7c18dce",
|
||||
"Rev": "7c18dce7b8ff32db34d4b7054d488db656d75cc3"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/google/go-querystring/query",
|
||||
"Rev": "d8840cbb2baa915f4836edda4750050a2c0b7aea"
|
||||
"Comment": "v2.2.0-15-g61124b6",
|
||||
"Rev": "61124b62ad244d655f87d944aefaa2ae5a0d2f16"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gorilla/context",
|
||||
|
@ -26,11 +22,11 @@
|
|||
},
|
||||
{
|
||||
"ImportPath": "github.com/gorilla/mux",
|
||||
"Rev": "e444e69cbd2e2e3e0749a2f3c717cec491552bbf"
|
||||
"Rev": "8a875a034c69b940914d83ea03d3f1299b4d094b"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gorilla/schema",
|
||||
"Rev": "ad8849d14e5cdf1f4423b1f0fc53827ebbdd7477"
|
||||
"Rev": "c8422571edf3131506bab7df27e18980fe2598d5"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/jmoiron/modl",
|
||||
|
@ -43,16 +39,16 @@
|
|||
},
|
||||
{
|
||||
"ImportPath": "github.com/lib/pq",
|
||||
"Comment": "go1.0-cutoff-13-g19eeca3",
|
||||
"Rev": "19eeca3e30d2577b1761db471ec130810e67f532"
|
||||
"Comment": "go1.0-cutoff-29-g30ed220",
|
||||
"Rev": "30ed2200d7ec99cf17272292f1d4b7b0bd7165db"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/crypto/bcrypt",
|
||||
"Rev": "632d287f9f3f54b09809eebbd3cacbcb00b9f2fc"
|
||||
"Rev": "1351f936d976c60a0a48d728281922cf63eafb8d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/crypto/blowfish",
|
||||
"Rev": "632d287f9f3f54b09809eebbd3cacbcb00b9f2fc"
|
||||
"Rev": "1351f936d976c60a0a48d728281922cf63eafb8d"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
2
Godeps/_workspace/src/github.com/DavidHuie/gomigrate/README.md
generated
vendored
2
Godeps/_workspace/src/github.com/DavidHuie/gomigrate/README.md
generated
vendored
|
@ -51,6 +51,8 @@ For a given migration, the `id` and `name` fields must be the same.
|
|||
The id field is an integer that corresponds to the order in which
|
||||
the migration should run relative to the other migrations.
|
||||
|
||||
`id` should not be `0` as that value is used for internal validations.
|
||||
|
||||
### Example
|
||||
|
||||
If I'm trying to add a "users" table to the database, I would create
|
||||
|
|
47
Godeps/_workspace/src/github.com/DavidHuie/gomigrate/gomigrate.go
generated
vendored
47
Godeps/_workspace/src/github.com/DavidHuie/gomigrate/gomigrate.go
generated
vendored
|
@ -3,7 +3,6 @@
|
|||
package gomigrate
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
|
@ -219,37 +218,25 @@ func (m *Migrator) ApplyMigration(migration *Migration, mType migrationType) err
|
|||
return err
|
||||
}
|
||||
|
||||
for n, subMigration := range splitMigrationString(string(sql)) {
|
||||
if allWhitespace.Match([]byte(subMigration)) {
|
||||
continue
|
||||
// Perform the migration.
|
||||
result, err := transaction.Exec(string(sql))
|
||||
if err != nil {
|
||||
log.Printf("Error executing migration: %v", err)
|
||||
if rollbackErr := transaction.Rollback(); rollbackErr != nil {
|
||||
log.Printf("Error rolling back transaction: %v", rollbackErr)
|
||||
return rollbackErr
|
||||
}
|
||||
|
||||
log.Printf("Applying submigration: %v", n+1)
|
||||
|
||||
for _, line := range bytes.Split([]byte(subMigration), []byte("\n")) {
|
||||
log.Printf("MIGRATION: %s", line)
|
||||
}
|
||||
|
||||
// Perform the migration.
|
||||
result, err := transaction.Exec(string(subMigration))
|
||||
if err != nil {
|
||||
log.Printf("Error executing migration: %v", err)
|
||||
if rollbackErr := transaction.Rollback(); rollbackErr != nil {
|
||||
log.Printf("Error rolling back transaction: %v", rollbackErr)
|
||||
return rollbackErr
|
||||
}
|
||||
return err
|
||||
}
|
||||
if rowsAffected, err := result.RowsAffected(); err != nil {
|
||||
log.Printf("Error getting rows affected: %v", err)
|
||||
if rollbackErr := transaction.Rollback(); rollbackErr != nil {
|
||||
log.Printf("Error rolling back transaction: %v", rollbackErr)
|
||||
return rollbackErr
|
||||
}
|
||||
return err
|
||||
} else {
|
||||
log.Printf("Rows affected: %v", rowsAffected)
|
||||
return err
|
||||
}
|
||||
if rowsAffected, err := result.RowsAffected(); err != nil {
|
||||
log.Printf("Error getting rows affected: %v", err)
|
||||
if rollbackErr := transaction.Rollback(); rollbackErr != nil {
|
||||
log.Printf("Error rolling back transaction: %v", rollbackErr)
|
||||
return rollbackErr
|
||||
}
|
||||
return err
|
||||
} else {
|
||||
log.Printf("Rows affected: %v", rowsAffected)
|
||||
}
|
||||
|
||||
// Log the event.
|
||||
|
|
38
Godeps/_workspace/src/github.com/DavidHuie/gomigrate/gomigrate_test.go
generated
vendored
38
Godeps/_workspace/src/github.com/DavidHuie/gomigrate/gomigrate_test.go
generated
vendored
|
@ -16,7 +16,7 @@ var (
|
|||
adapter Migratable
|
||||
)
|
||||
|
||||
func GetMigrator(test string) *Migrator {
|
||||
func GetMigrator(test string) (*Migrator, string) {
|
||||
var suffix string
|
||||
if os.Getenv("DB") == "pg" {
|
||||
suffix = "pg"
|
||||
|
@ -28,12 +28,16 @@ func GetMigrator(test string) *Migrator {
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return m
|
||||
return m, suffix
|
||||
}
|
||||
|
||||
func TestNewMigrator(t *testing.T) {
|
||||
m := GetMigrator("test1")
|
||||
if len(m.migrations) != 1 {
|
||||
m, d := GetMigrator("test1")
|
||||
if d == "pg" && len(m.migrations) != 4 {
|
||||
t.Errorf("Invalid number of migrations detected")
|
||||
}
|
||||
|
||||
if d == "mysql" && len(m.migrations) != 1 {
|
||||
t.Errorf("Invalid number of migrations detected")
|
||||
}
|
||||
|
||||
|
@ -43,10 +47,10 @@ func TestNewMigrator(t *testing.T) {
|
|||
t.Errorf("Invalid migration name detected: %s", migration.Name)
|
||||
}
|
||||
if migration.Id != 1 {
|
||||
t.Errorf("Invalid migration num detected: %s", migration.Id)
|
||||
t.Errorf("Invalid migration num detected: %d", migration.Id)
|
||||
}
|
||||
if migration.Status != Inactive {
|
||||
t.Errorf("Invalid migration num detected: %s", migration.Status)
|
||||
t.Errorf("Invalid migration num detected: %d", migration.Status)
|
||||
}
|
||||
|
||||
cleanup()
|
||||
|
@ -79,7 +83,7 @@ func TestCreatingMigratorWhenTableExists(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestMigrationAndRollback(t *testing.T) {
|
||||
m := GetMigrator("test1")
|
||||
m, d := GetMigrator("test1")
|
||||
|
||||
if err := m.Migrate(); err != nil {
|
||||
t.Error(err)
|
||||
|
@ -110,8 +114,16 @@ func TestMigrationAndRollback(t *testing.T) {
|
|||
t.Error("Invalid status for migration")
|
||||
}
|
||||
|
||||
if err := m.Rollback(); err != nil {
|
||||
t.Error(err)
|
||||
if d == "pg" {
|
||||
if err := m.RollbackN(4); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
if d == "mysql" {
|
||||
if err := m.Rollback(); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that the down migration ran.
|
||||
|
@ -120,8 +132,8 @@ func TestMigrationAndRollback(t *testing.T) {
|
|||
"test",
|
||||
)
|
||||
err := row.Scan(&tableName)
|
||||
if err != sql.ErrNoRows {
|
||||
t.Errorf("Migration table should be deleted")
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
t.Errorf("Migration table should be deleted: %v", err)
|
||||
}
|
||||
|
||||
// Ensure that the migration log is missing.
|
||||
|
@ -129,11 +141,11 @@ func TestMigrationAndRollback(t *testing.T) {
|
|||
adapter.GetMigrationSql(),
|
||||
1,
|
||||
)
|
||||
if err := row.Scan(&status); err != sql.ErrNoRows {
|
||||
if err := row.Scan(&status); err != nil && err != sql.ErrNoRows {
|
||||
t.Error(err)
|
||||
}
|
||||
if m.migrations[1].Status != Inactive {
|
||||
t.Errorf("Invalid status for migration, %v", m.migrations[1].Status)
|
||||
t.Errorf("Invalid status for migration, expected: %d, got: %v", Inactive, m.migrations[1].Status)
|
||||
}
|
||||
|
||||
cleanup()
|
||||
|
|
|
@ -1 +1 @@
|
|||
drop table test;
|
||||
drop table if exists test;
|
||||
|
|
|
@ -1 +1 @@
|
|||
create table test();
|
||||
create table if not exists test();
|
||||
|
|
1
Godeps/_workspace/src/github.com/DavidHuie/gomigrate/test_migrations/test1_pg/2_create_index_function_if_not_exists_down.sql
generated
vendored
Normal file
1
Godeps/_workspace/src/github.com/DavidHuie/gomigrate/test_migrations/test1_pg/2_create_index_function_if_not_exists_down.sql
generated
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
drop function if exists create_index_if_not_exists (t_name text, i_name text, index_sql text);
|
23
Godeps/_workspace/src/github.com/DavidHuie/gomigrate/test_migrations/test1_pg/2_create_index_function_if_not_exists_up.sql
generated
vendored
Normal file
23
Godeps/_workspace/src/github.com/DavidHuie/gomigrate/test_migrations/test1_pg/2_create_index_function_if_not_exists_up.sql
generated
vendored
Normal file
|
@ -0,0 +1,23 @@
|
|||
-- this function allows us to create indexes if they don't exist
|
||||
create or replace function create_index_if_not_exists (t_name text, i_name text, index_sql text) returns void as $$
|
||||
declare
|
||||
full_index_name varchar;
|
||||
schema_name varchar;
|
||||
begin
|
||||
|
||||
full_index_name = t_name || '_' || i_name;
|
||||
schema_name = 'public';
|
||||
|
||||
if not exists (
|
||||
select 1
|
||||
from pg_class c
|
||||
join pg_namespace n on n.oid = c.relnamespace
|
||||
where c.relname = full_index_name
|
||||
and n.nspname = schema_name
|
||||
) then
|
||||
|
||||
execute 'create index ' || full_index_name || ' on ' || schema_name || '.' || t_name || ' ' || index_sql;
|
||||
end if;
|
||||
end
|
||||
$$
|
||||
language plpgsql volatile;
|
1
Godeps/_workspace/src/github.com/DavidHuie/gomigrate/test_migrations/test1_pg/3_multiple_inserts_down.sql
generated
vendored
Normal file
1
Godeps/_workspace/src/github.com/DavidHuie/gomigrate/test_migrations/test1_pg/3_multiple_inserts_down.sql
generated
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
drop table tt;
|
5
Godeps/_workspace/src/github.com/DavidHuie/gomigrate/test_migrations/test1_pg/3_multiple_inserts_up.sql
generated
vendored
Normal file
5
Godeps/_workspace/src/github.com/DavidHuie/gomigrate/test_migrations/test1_pg/3_multiple_inserts_up.sql
generated
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
CREATE TABLE tt (
|
||||
c text NOT NULL
|
||||
);
|
||||
insert into tt values ('a');
|
||||
insert into tt values ('x');
|
1
Godeps/_workspace/src/github.com/DavidHuie/gomigrate/test_migrations/test1_pg/4_dash-test_down.sql
generated
vendored
Normal file
1
Godeps/_workspace/src/github.com/DavidHuie/gomigrate/test_migrations/test1_pg/4_dash-test_down.sql
generated
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
select 1;
|
1
Godeps/_workspace/src/github.com/DavidHuie/gomigrate/test_migrations/test1_pg/4_dash-test_up.sql
generated
vendored
Normal file
1
Godeps/_workspace/src/github.com/DavidHuie/gomigrate/test_migrations/test1_pg/4_dash-test_up.sql
generated
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
select 1;
|
9
Godeps/_workspace/src/github.com/DavidHuie/gomigrate/utils.go
generated
vendored
9
Godeps/_workspace/src/github.com/DavidHuie/gomigrate/utils.go
generated
vendored
|
@ -7,8 +7,8 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
upMigrationFile = regexp.MustCompile(`(\d+)_(\w+)_up\.sql`)
|
||||
downMigrationFile = regexp.MustCompile(`(\d+)_(\w+)_down\.sql`)
|
||||
upMigrationFile = regexp.MustCompile(`(\d+)_([\w-]+)_up\.sql`)
|
||||
downMigrationFile = regexp.MustCompile(`(\d+)_([\w-]+)_down\.sql`)
|
||||
subMigrationSplit = regexp.MustCompile(`;\s*`)
|
||||
allWhitespace = regexp.MustCompile(`^\s*$`)
|
||||
)
|
||||
|
@ -40,11 +40,6 @@ func parseMatches(matches [][][]byte, mType migrationType) (uint64, migrationTyp
|
|||
return parsedNum, mType, string(name), nil
|
||||
}
|
||||
|
||||
// Splits migration sql into different strings separated by a semi-colon.
|
||||
func splitMigrationString(sql string) []string {
|
||||
return subMigrationSplit.Split(sql, -1)
|
||||
}
|
||||
|
||||
// This type is used to sort migration ids.
|
||||
type uint64slice []uint64
|
||||
|
||||
|
|
14
Godeps/_workspace/src/github.com/codegangsta/cli/README.md
generated
vendored
14
Godeps/_workspace/src/github.com/codegangsta/cli/README.md
generated
vendored
|
@ -210,7 +210,7 @@ Subcommands can be defined for a more git-like command line app.
|
|||
app.Commands = []cli.Command{
|
||||
{
|
||||
Name: "add",
|
||||
ShortName: "a",
|
||||
Names: []string{"a"},
|
||||
Usage: "add a task to the list",
|
||||
Action: func(c *cli.Context) {
|
||||
println("added task: ", c.Args().First())
|
||||
|
@ -218,7 +218,7 @@ app.Commands = []cli.Command{
|
|||
},
|
||||
{
|
||||
Name: "complete",
|
||||
ShortName: "c",
|
||||
Names: []string{"c"},
|
||||
Usage: "complete a task on the list",
|
||||
Action: func(c *cli.Context) {
|
||||
println("completed task: ", c.Args().First())
|
||||
|
@ -226,7 +226,7 @@ app.Commands = []cli.Command{
|
|||
},
|
||||
{
|
||||
Name: "template",
|
||||
ShortName: "r",
|
||||
Names: []string{"r"},
|
||||
Usage: "options for task templates",
|
||||
Subcommands: []cli.Command{
|
||||
{
|
||||
|
@ -244,7 +244,7 @@ app.Commands = []cli.Command{
|
|||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
...
|
||||
```
|
||||
|
@ -262,8 +262,8 @@ app := cli.NewApp()
|
|||
app.EnableBashCompletion = true
|
||||
app.Commands = []cli.Command{
|
||||
{
|
||||
Name: "complete",
|
||||
ShortName: "c",
|
||||
Name: "complete",
|
||||
Names: []string{"c"},
|
||||
Usage: "complete a task on the list",
|
||||
Action: func(c *cli.Context) {
|
||||
println("completed task: ", c.Args().First())
|
||||
|
@ -293,6 +293,6 @@ setting the `PROG` variable to the name of your program:
|
|||
## Contribution Guidelines
|
||||
Feel free to put up a pull request to fix a bug or maybe add a feature. I will give it a code review and make sure that it does not break backwards compatibility. If I or any other collaborators agree that it is in line with the vision of the project, we will work with you to get the code into a mergeable state and merge it into the master branch.
|
||||
|
||||
If you are have contributed something significant to the project, I will most likely add you as a collaborator. As a collaborator you are given the ability to merge others pull requests. It is very important that new code does not break existing code, so be careful about what code you do choose to merge. If you have any questions feel free to link @codegangsta to the issue in question and we can review it together.
|
||||
If you have contributed something significant to the project, I will most likely add you as a collaborator. As a collaborator you are given the ability to merge others pull requests. It is very important that new code does not break existing code, so be careful about what code you do choose to merge. If you have any questions feel free to link @codegangsta to the issue in question and we can review it together.
|
||||
|
||||
If you feel like you have contributed to the project but have not yet been added as a collaborator, I probably forgot to add you. Hit @codegangsta up over email and we will get it figured out.
|
||||
|
|
70
Godeps/_workspace/src/github.com/codegangsta/cli/app.go
generated
vendored
70
Godeps/_workspace/src/github.com/codegangsta/cli/app.go
generated
vendored
|
@ -5,6 +5,7 @@ import (
|
|||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
"text/template"
|
||||
"time"
|
||||
|
@ -34,15 +35,20 @@ type App struct {
|
|||
// An action to execute before any subcommands are run, but after the context is ready
|
||||
// If a non-nil error is returned, no subcommands are run
|
||||
Before func(context *Context) error
|
||||
// An action to execute after any subcommands are run, but after the subcommand has finished
|
||||
// It is run even if Action() panics
|
||||
After func(context *Context) error
|
||||
// The action to execute when no subcommands are specified
|
||||
Action func(context *Context)
|
||||
// Execute this function if the proper command cannot be found
|
||||
CommandNotFound func(context *Context, command string)
|
||||
// Compilation date
|
||||
Compiled time.Time
|
||||
// Author
|
||||
// List of all authors who contributed
|
||||
Authors []Author
|
||||
// Name of Author (Note: Use App.Authors, this is deprecated)
|
||||
Author string
|
||||
// Author e-mail
|
||||
// Email of Author (Note: Use App.Authors, this is deprecated)
|
||||
Email string
|
||||
// Writer writer to write output to
|
||||
Writer io.Writer
|
||||
|
@ -67,22 +73,28 @@ func NewApp() *App {
|
|||
BashComplete: DefaultAppComplete,
|
||||
Action: helpCommand.Action,
|
||||
Compiled: compileTime(),
|
||||
Author: "Author",
|
||||
Email: "unknown@email",
|
||||
Writer: os.Stdout,
|
||||
}
|
||||
}
|
||||
|
||||
// Entry point to the cli app. Parses the arguments slice and routes to the proper flag/args combination
|
||||
func (a *App) Run(arguments []string) error {
|
||||
func (a *App) Run(arguments []string) (err error) {
|
||||
if a.Author != "" || a.Email != "" {
|
||||
a.Authors = append(a.Authors, Author{Name: a.Author, Email: a.Email})
|
||||
}
|
||||
|
||||
if HelpPrinter == nil {
|
||||
defer func() {
|
||||
HelpPrinter = nil
|
||||
}()
|
||||
|
||||
HelpPrinter = func(templ string, data interface{}) {
|
||||
funcMap := template.FuncMap{
|
||||
"join": strings.Join,
|
||||
}
|
||||
|
||||
w := tabwriter.NewWriter(a.Writer, 0, 8, 1, '\t', 0)
|
||||
t := template.Must(template.New("help").Parse(templ))
|
||||
t := template.Must(template.New("help").Funcs(funcMap).Parse(templ))
|
||||
err := t.Execute(w, data)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
@ -111,7 +123,7 @@ func (a *App) Run(arguments []string) error {
|
|||
// parse flags
|
||||
set := flagSet(a.Name, a.Flags)
|
||||
set.SetOutput(ioutil.Discard)
|
||||
err := set.Parse(arguments[1:])
|
||||
err = set.Parse(arguments[1:])
|
||||
nerr := normalizeFlags(a.Flags, set)
|
||||
if nerr != nil {
|
||||
fmt.Fprintln(a.Writer, nerr)
|
||||
|
@ -141,6 +153,15 @@ func (a *App) Run(arguments []string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
if a.After != nil {
|
||||
defer func() {
|
||||
// err is always nil here.
|
||||
// There is a check to see if it is non-nil
|
||||
// just few lines before.
|
||||
err = a.After(context)
|
||||
}()
|
||||
}
|
||||
|
||||
if a.Before != nil {
|
||||
err := a.Before(context)
|
||||
if err != nil {
|
||||
|
@ -171,7 +192,7 @@ func (a *App) RunAndExitOnError() {
|
|||
}
|
||||
|
||||
// Invokes the subcommand given the context, parses ctx.Args() to generate command-specific flags
|
||||
func (a *App) RunAsSubcommand(ctx *Context) error {
|
||||
func (a *App) RunAsSubcommand(ctx *Context) (err error) {
|
||||
// append help to commands
|
||||
if len(a.Commands) > 0 {
|
||||
if a.Command(helpCommand.Name) == nil && !a.HideHelp {
|
||||
|
@ -190,7 +211,7 @@ func (a *App) RunAsSubcommand(ctx *Context) error {
|
|||
// parse flags
|
||||
set := flagSet(a.Name, a.Flags)
|
||||
set.SetOutput(ioutil.Discard)
|
||||
err := set.Parse(ctx.Args().Tail())
|
||||
err = set.Parse(ctx.Args().Tail())
|
||||
nerr := normalizeFlags(a.Flags, set)
|
||||
context := NewContext(a, set, ctx.globalSet)
|
||||
|
||||
|
@ -225,6 +246,15 @@ func (a *App) RunAsSubcommand(ctx *Context) error {
|
|||
}
|
||||
}
|
||||
|
||||
if a.After != nil {
|
||||
defer func() {
|
||||
// err is always nil here.
|
||||
// There is a check to see if it is non-nil
|
||||
// just few lines before.
|
||||
err = a.After(context)
|
||||
}()
|
||||
}
|
||||
|
||||
if a.Before != nil {
|
||||
err := a.Before(context)
|
||||
if err != nil {
|
||||
|
@ -242,11 +272,7 @@ func (a *App) RunAsSubcommand(ctx *Context) error {
|
|||
}
|
||||
|
||||
// Run default Action
|
||||
if len(a.Commands) > 0 {
|
||||
a.Action(context)
|
||||
} else {
|
||||
a.Action(ctx)
|
||||
}
|
||||
a.Action(context)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -277,3 +303,19 @@ func (a *App) appendFlag(flag Flag) {
|
|||
a.Flags = append(a.Flags, flag)
|
||||
}
|
||||
}
|
||||
|
||||
// Author represents someone who has contributed to a cli project.
|
||||
type Author struct {
|
||||
Name string // The Authors name
|
||||
Email string // The Authors email
|
||||
}
|
||||
|
||||
// String makes Author comply to the Stringer interface, to allow an easy print in the templating process
|
||||
func (a Author) String() string {
|
||||
e := ""
|
||||
if a.Email != "" {
|
||||
e = "<" + a.Email + "> "
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%v %v", a.Name, e)
|
||||
}
|
||||
|
|
106
Godeps/_workspace/src/github.com/codegangsta/cli/app_test.go
generated
vendored
106
Godeps/_workspace/src/github.com/codegangsta/cli/app_test.go
generated
vendored
|
@ -21,6 +21,9 @@ func ExampleApp() {
|
|||
app.Action = func(c *cli.Context) {
|
||||
fmt.Printf("Hello %v\n", c.String("name"))
|
||||
}
|
||||
app.Author = "Harrison"
|
||||
app.Email = "harrison@lolwut.com"
|
||||
app.Authors = []cli.Author{cli.Author{Name: "Oliver Allen", Email: "oliver@toyshop.com"}}
|
||||
app.Run(os.Args)
|
||||
// Output:
|
||||
// Hello Jeremy
|
||||
|
@ -34,13 +37,13 @@ func ExampleAppSubcommand() {
|
|||
app.Commands = []cli.Command{
|
||||
{
|
||||
Name: "hello",
|
||||
ShortName: "hi",
|
||||
Aliases: []string{"hi"},
|
||||
Usage: "use it to see a description",
|
||||
Description: "This is how we describe hello the function",
|
||||
Subcommands: []cli.Command{
|
||||
{
|
||||
Name: "english",
|
||||
ShortName: "en",
|
||||
Aliases: []string{"en"},
|
||||
Usage: "sends a greeting in english",
|
||||
Description: "greets someone in english",
|
||||
Flags: []cli.Flag{
|
||||
|
@ -75,7 +78,7 @@ func ExampleAppHelp() {
|
|||
app.Commands = []cli.Command{
|
||||
{
|
||||
Name: "describeit",
|
||||
ShortName: "d",
|
||||
Aliases: []string{"d"},
|
||||
Usage: "use it to see a description",
|
||||
Description: "This is how we describe describeit the function",
|
||||
Action: func(c *cli.Context) {
|
||||
|
@ -105,7 +108,7 @@ func ExampleAppBashComplete() {
|
|||
app.Commands = []cli.Command{
|
||||
{
|
||||
Name: "describeit",
|
||||
ShortName: "d",
|
||||
Aliases: []string{"d"},
|
||||
Usage: "use it to see a description",
|
||||
Description: "This is how we describe describeit the function",
|
||||
Action: func(c *cli.Context) {
|
||||
|
@ -159,8 +162,8 @@ var commandAppTests = []struct {
|
|||
|
||||
func TestApp_Command(t *testing.T) {
|
||||
app := cli.NewApp()
|
||||
fooCommand := cli.Command{Name: "foobar", ShortName: "f"}
|
||||
batCommand := cli.Command{Name: "batbaz", ShortName: "b"}
|
||||
fooCommand := cli.Command{Name: "foobar", Aliases: []string{"f"}}
|
||||
batCommand := cli.Command{Name: "batbaz", Aliases: []string{"b"}}
|
||||
app.Commands = []cli.Command{
|
||||
fooCommand,
|
||||
batCommand,
|
||||
|
@ -193,6 +196,32 @@ func TestApp_CommandWithArgBeforeFlags(t *testing.T) {
|
|||
expect(t, firstArg, "my-arg")
|
||||
}
|
||||
|
||||
func TestApp_RunAsSubcommandParseFlags(t *testing.T) {
|
||||
var context *cli.Context
|
||||
|
||||
a := cli.NewApp()
|
||||
a.Commands = []cli.Command{
|
||||
{
|
||||
Name: "foo",
|
||||
Action: func(c *cli.Context) {
|
||||
context = c
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "lang",
|
||||
Value: "english",
|
||||
Usage: "language for the greeting",
|
||||
},
|
||||
},
|
||||
Before: func(_ *cli.Context) error { return nil },
|
||||
},
|
||||
}
|
||||
a.Run([]string{"", "foo", "--lang", "spanish", "abcd"})
|
||||
|
||||
expect(t, context.Args().Get(0), "abcd")
|
||||
expect(t, context.String("lang"), "spanish")
|
||||
}
|
||||
|
||||
func TestApp_CommandWithFlagBeforeTerminator(t *testing.T) {
|
||||
var parsedOption string
|
||||
var args []string
|
||||
|
@ -420,6 +449,71 @@ func TestApp_BeforeFunc(t *testing.T) {
|
|||
|
||||
}
|
||||
|
||||
func TestApp_AfterFunc(t *testing.T) {
|
||||
afterRun, subcommandRun := false, false
|
||||
afterError := fmt.Errorf("fail")
|
||||
var err error
|
||||
|
||||
app := cli.NewApp()
|
||||
|
||||
app.After = func(c *cli.Context) error {
|
||||
afterRun = true
|
||||
s := c.String("opt")
|
||||
if s == "fail" {
|
||||
return afterError
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
app.Commands = []cli.Command{
|
||||
cli.Command{
|
||||
Name: "sub",
|
||||
Action: func(c *cli.Context) {
|
||||
subcommandRun = true
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
app.Flags = []cli.Flag{
|
||||
cli.StringFlag{Name: "opt"},
|
||||
}
|
||||
|
||||
// run with the After() func succeeding
|
||||
err = app.Run([]string{"command", "--opt", "succeed", "sub"})
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Run error: %s", err)
|
||||
}
|
||||
|
||||
if afterRun == false {
|
||||
t.Errorf("After() not executed when expected")
|
||||
}
|
||||
|
||||
if subcommandRun == false {
|
||||
t.Errorf("Subcommand not executed when expected")
|
||||
}
|
||||
|
||||
// reset
|
||||
afterRun, subcommandRun = false, false
|
||||
|
||||
// run with the Before() func failing
|
||||
err = app.Run([]string{"command", "--opt", "fail", "sub"})
|
||||
|
||||
// should be the same error produced by the Before func
|
||||
if err != afterError {
|
||||
t.Errorf("Run error expected, but not received")
|
||||
}
|
||||
|
||||
if afterRun == false {
|
||||
t.Errorf("After() not executed when expected")
|
||||
}
|
||||
|
||||
if subcommandRun == false {
|
||||
t.Errorf("Subcommand not executed when expected")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppNoHelpFlag(t *testing.T) {
|
||||
oldFlag := cli.HelpFlag
|
||||
defer func() {
|
||||
|
|
28
Godeps/_workspace/src/github.com/codegangsta/cli/cli_test.go
generated
vendored
28
Godeps/_workspace/src/github.com/codegangsta/cli/cli_test.go
generated
vendored
|
@ -12,17 +12,17 @@ func Example() {
|
|||
app.Usage = "task list on the command line"
|
||||
app.Commands = []cli.Command{
|
||||
{
|
||||
Name: "add",
|
||||
ShortName: "a",
|
||||
Usage: "add a task to the list",
|
||||
Name: "add",
|
||||
Aliases: []string{"a"},
|
||||
Usage: "add a task to the list",
|
||||
Action: func(c *cli.Context) {
|
||||
println("added task: ", c.Args().First())
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "complete",
|
||||
ShortName: "c",
|
||||
Usage: "complete a task on the list",
|
||||
Name: "complete",
|
||||
Aliases: []string{"c"},
|
||||
Usage: "complete a task on the list",
|
||||
Action: func(c *cli.Context) {
|
||||
println("completed task: ", c.Args().First())
|
||||
},
|
||||
|
@ -38,13 +38,13 @@ func ExampleSubcommand() {
|
|||
app.Commands = []cli.Command{
|
||||
{
|
||||
Name: "hello",
|
||||
ShortName: "hi",
|
||||
Aliases: []string{"hi"},
|
||||
Usage: "use it to see a description",
|
||||
Description: "This is how we describe hello the function",
|
||||
Subcommands: []cli.Command{
|
||||
{
|
||||
Name: "english",
|
||||
ShortName: "en",
|
||||
Aliases: []string{"en"},
|
||||
Usage: "sends a greeting in english",
|
||||
Description: "greets someone in english",
|
||||
Flags: []cli.Flag{
|
||||
|
@ -58,9 +58,9 @@ func ExampleSubcommand() {
|
|||
println("Hello, ", c.String("name"))
|
||||
},
|
||||
}, {
|
||||
Name: "spanish",
|
||||
ShortName: "sp",
|
||||
Usage: "sends a greeting in spanish",
|
||||
Name: "spanish",
|
||||
Aliases: []string{"sp"},
|
||||
Usage: "sends a greeting in spanish",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "surname",
|
||||
|
@ -72,9 +72,9 @@ func ExampleSubcommand() {
|
|||
println("Hola, ", c.String("surname"))
|
||||
},
|
||||
}, {
|
||||
Name: "french",
|
||||
ShortName: "fr",
|
||||
Usage: "sends a greeting in french",
|
||||
Name: "french",
|
||||
Aliases: []string{"fr"},
|
||||
Usage: "sends a greeting in french",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "nickname",
|
||||
|
|
27
Godeps/_workspace/src/github.com/codegangsta/cli/command.go
generated
vendored
27
Godeps/_workspace/src/github.com/codegangsta/cli/command.go
generated
vendored
|
@ -10,8 +10,10 @@ import (
|
|||
type Command struct {
|
||||
// The name of the command
|
||||
Name string
|
||||
// short name of the command. Typically one character
|
||||
// short name of the command. Typically one character (deprecated, use `Aliases`)
|
||||
ShortName string
|
||||
// A list of aliases for the command
|
||||
Aliases []string
|
||||
// A short description of the usage of this command
|
||||
Usage string
|
||||
// A longer explanation of how the command works
|
||||
|
@ -21,6 +23,9 @@ type Command struct {
|
|||
// An action to execute before any sub-subcommands are run, but after the context is ready
|
||||
// If a non-nil error is returned, no sub-subcommands are run
|
||||
Before func(context *Context) error
|
||||
// An action to execute after any subcommands are run, but after the subcommand has finished
|
||||
// It is run even if Action() panics
|
||||
After func(context *Context) error
|
||||
// The function to call when this command is invoked
|
||||
Action func(context *Context)
|
||||
// List of child commands
|
||||
|
@ -36,7 +41,7 @@ type Command struct {
|
|||
// Invokes the command given the context, parses ctx.Args() to generate command-specific flags
|
||||
func (c Command) Run(ctx *Context) error {
|
||||
|
||||
if len(c.Subcommands) > 0 || c.Before != nil {
|
||||
if len(c.Subcommands) > 0 || c.Before != nil || c.After != nil {
|
||||
return c.startApp(ctx)
|
||||
}
|
||||
|
||||
|
@ -114,9 +119,24 @@ func (c Command) Run(ctx *Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (c Command) Names() []string {
|
||||
names := []string{c.Name}
|
||||
|
||||
if c.ShortName != "" {
|
||||
names = append(names, c.ShortName)
|
||||
}
|
||||
|
||||
return append(names, c.Aliases...)
|
||||
}
|
||||
|
||||
// Returns true if Command.Name or Command.ShortName matches given name
|
||||
func (c Command) HasName(name string) bool {
|
||||
return c.Name == name || c.ShortName == name
|
||||
for _, n := range c.Names() {
|
||||
if n == name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (c Command) startApp(ctx *Context) error {
|
||||
|
@ -146,6 +166,7 @@ func (c Command) startApp(ctx *Context) error {
|
|||
|
||||
// set the actions
|
||||
app.Before = c.Before
|
||||
app.After = c.After
|
||||
if c.Action != nil {
|
||||
app.Action = c.Action
|
||||
} else {
|
||||
|
|
4
Godeps/_workspace/src/github.com/codegangsta/cli/command_test.go
generated
vendored
4
Godeps/_workspace/src/github.com/codegangsta/cli/command_test.go
generated
vendored
|
@ -17,7 +17,7 @@ func TestCommandDoNotIgnoreFlags(t *testing.T) {
|
|||
|
||||
command := cli.Command{
|
||||
Name: "test-cmd",
|
||||
ShortName: "tc",
|
||||
Aliases: []string{"tc"},
|
||||
Usage: "this is for testing",
|
||||
Description: "testing",
|
||||
Action: func(_ *cli.Context) {},
|
||||
|
@ -37,7 +37,7 @@ func TestCommandIgnoreFlags(t *testing.T) {
|
|||
|
||||
command := cli.Command{
|
||||
Name: "test-cmd",
|
||||
ShortName: "tc",
|
||||
Aliases: []string{"tc"},
|
||||
Usage: "this is for testing",
|
||||
Description: "testing",
|
||||
Action: func(_ *cli.Context) {},
|
||||
|
|
5
Godeps/_workspace/src/github.com/codegangsta/cli/context.go
generated
vendored
5
Godeps/_workspace/src/github.com/codegangsta/cli/context.go
generated
vendored
|
@ -106,6 +106,11 @@ func (c *Context) GlobalGeneric(name string) interface{} {
|
|||
return lookupGeneric(name, c.globalSet)
|
||||
}
|
||||
|
||||
// Returns the number of flags set
|
||||
func (c *Context) NumFlags() int {
|
||||
return c.flagSet.NFlag()
|
||||
}
|
||||
|
||||
// Determines if the flag was actually set
|
||||
func (c *Context) IsSet(name string) bool {
|
||||
if c.setFlags == nil {
|
||||
|
|
12
Godeps/_workspace/src/github.com/codegangsta/cli/context_test.go
generated
vendored
12
Godeps/_workspace/src/github.com/codegangsta/cli/context_test.go
generated
vendored
|
@ -97,3 +97,15 @@ func TestContext_GlobalIsSet(t *testing.T) {
|
|||
expect(t, c.GlobalIsSet("myflagGlobalUnset"), false)
|
||||
expect(t, c.GlobalIsSet("bogusGlobal"), false)
|
||||
}
|
||||
|
||||
func TestContext_NumFlags(t *testing.T) {
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.Bool("myflag", false, "doc")
|
||||
set.String("otherflag", "hello world", "doc")
|
||||
globalSet := flag.NewFlagSet("test", 0)
|
||||
globalSet.Bool("myflagGlobal", true, "doc")
|
||||
c := cli.NewContext(nil, set, globalSet)
|
||||
set.Parse([]string{"--myflag", "--otherflag=foo"})
|
||||
globalSet.Parse([]string{"--myflagGlobal"})
|
||||
expect(t, c.NumFlags(), 2)
|
||||
}
|
||||
|
|
36
Godeps/_workspace/src/github.com/codegangsta/cli/help.go
generated
vendored
36
Godeps/_workspace/src/github.com/codegangsta/cli/help.go
generated
vendored
|
@ -12,14 +12,13 @@ USAGE:
|
|||
{{.Name}} {{if .Flags}}[global options] {{end}}command{{if .Flags}} [command options]{{end}} [arguments...]
|
||||
|
||||
VERSION:
|
||||
{{.Version}}{{if or .Author .Email}}
|
||||
|
||||
AUTHOR:{{if .Author}}
|
||||
{{.Author}}{{if .Email}} - <{{.Email}}>{{end}}{{else}}
|
||||
{{.Email}}{{end}}{{end}}
|
||||
{{.Version}}
|
||||
|
||||
AUTHOR(S):
|
||||
{{range .Authors}}{{ . }}
|
||||
{{end}}
|
||||
COMMANDS:
|
||||
{{range .Commands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}}
|
||||
{{range .Commands}}{{join .Names ", "}}{{ "\t" }}{{.Usage}}
|
||||
{{end}}{{if .Flags}}
|
||||
GLOBAL OPTIONS:
|
||||
{{range .Flags}}{{.}}
|
||||
|
@ -53,7 +52,7 @@ USAGE:
|
|||
{{.Name}} command{{if .Flags}} [command options]{{end}} [arguments...]
|
||||
|
||||
COMMANDS:
|
||||
{{range .Commands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}}
|
||||
{{range .Commands}}{{join .Names ", "}}{{ "\t" }}{{.Usage}}
|
||||
{{end}}{{if .Flags}}
|
||||
OPTIONS:
|
||||
{{range .Flags}}{{.}}
|
||||
|
@ -61,9 +60,9 @@ OPTIONS:
|
|||
`
|
||||
|
||||
var helpCommand = Command{
|
||||
Name: "help",
|
||||
ShortName: "h",
|
||||
Usage: "Shows a list of commands or help for one command",
|
||||
Name: "help",
|
||||
Aliases: []string{"h"},
|
||||
Usage: "Shows a list of commands or help for one command",
|
||||
Action: func(c *Context) {
|
||||
args := c.Args()
|
||||
if args.Present() {
|
||||
|
@ -75,9 +74,9 @@ var helpCommand = Command{
|
|||
}
|
||||
|
||||
var helpSubcommand = Command{
|
||||
Name: "help",
|
||||
ShortName: "h",
|
||||
Usage: "Shows a list of commands or help for one command",
|
||||
Name: "help",
|
||||
Aliases: []string{"h"},
|
||||
Usage: "Shows a list of commands or help for one command",
|
||||
Action: func(c *Context) {
|
||||
args := c.Args()
|
||||
if args.Present() {
|
||||
|
@ -103,15 +102,20 @@ func ShowAppHelp(c *Context) {
|
|||
// Prints the list of subcommands as the default app completion method
|
||||
func DefaultAppComplete(c *Context) {
|
||||
for _, command := range c.App.Commands {
|
||||
fmt.Fprintln(c.App.Writer, command.Name)
|
||||
if command.ShortName != "" {
|
||||
fmt.Fprintln(c.App.Writer, command.ShortName)
|
||||
for _, name := range command.Names() {
|
||||
fmt.Fprintln(c.App.Writer, name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Prints help for the given command
|
||||
func ShowCommandHelp(c *Context, command string) {
|
||||
// show the subcommand help for a command with subcommands
|
||||
if command == "" {
|
||||
HelpPrinter(SubcommandHelpTemplate, c.App)
|
||||
return
|
||||
}
|
||||
|
||||
for _, c := range c.App.Commands {
|
||||
if c.HasName(command) {
|
||||
HelpPrinter(CommandHelpTemplate, c)
|
||||
|
|
2
Godeps/_workspace/src/github.com/dgrijalva/jwt-go/README.md
generated
vendored
2
Godeps/_workspace/src/github.com/dgrijalva/jwt-go/README.md
generated
vendored
|
@ -34,7 +34,7 @@ Parsing and verifying tokens is pretty straight forward. You pass in the token
|
|||
|
||||
```go
|
||||
// Create the token
|
||||
token := jwt.New(SigningMethodHS256)
|
||||
token := jwt.New(jwt.SigningMethodHS256)
|
||||
// Set some claims
|
||||
token.Claims["foo"] = "bar"
|
||||
token.Claims["exp"] = time.Now().Add(time.Hour * 72).Unix()
|
||||
|
|
2
Godeps/_workspace/src/github.com/dgrijalva/jwt-go/example_test.go
generated
vendored
2
Godeps/_workspace/src/github.com/dgrijalva/jwt-go/example_test.go
generated
vendored
|
@ -18,7 +18,7 @@ func ExampleParse(myToken string, myLookupKey func(interface{}) (interface{}, er
|
|||
}
|
||||
}
|
||||
|
||||
func ExampleNew(mySigningKey string) (string, error) {
|
||||
func ExampleNew(mySigningKey []byte) (string, error) {
|
||||
// Create the token
|
||||
token := jwt.New(jwt.SigningMethodHS256)
|
||||
// Set some claims
|
||||
|
|
2
Godeps/_workspace/src/github.com/dgrijalva/jwt-go/hmac.go
generated
vendored
2
Godeps/_workspace/src/github.com/dgrijalva/jwt-go/hmac.go
generated
vendored
|
@ -66,6 +66,8 @@ func (m *SigningMethodHMAC) Verify(signingString, signature string, key interfac
|
|||
return ErrInvalidKey
|
||||
}
|
||||
|
||||
// Implements the Sign method from SigningMethod for this signing method.
|
||||
// Key must be []byte
|
||||
func (m *SigningMethodHMAC) Sign(signingString string, key interface{}) (string, error) {
|
||||
if keyBytes, ok := key.([]byte); ok {
|
||||
if !m.Hash.Available() {
|
||||
|
|
274
Godeps/_workspace/src/github.com/google/go-querystring/query/encode.go
generated
vendored
274
Godeps/_workspace/src/github.com/google/go-querystring/query/encode.go
generated
vendored
|
@ -1,274 +0,0 @@
|
|||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package query implements encoding of structs into URL query parameters.
|
||||
//
|
||||
// As a simple example:
|
||||
//
|
||||
// type Options struct {
|
||||
// Query string `url:"q"`
|
||||
// ShowAll bool `url:"all"`
|
||||
// Page int `url:"page"`
|
||||
// }
|
||||
//
|
||||
// opt := Options{ "foo", true, 2 }
|
||||
// v, _ := query.Values(opt)
|
||||
// fmt.Print(v.Encode()) // will output: "q=foo&all=true&page=2"
|
||||
//
|
||||
// The exact mapping between Go values and url.Values is described in the
|
||||
// documentation for the Values() function.
|
||||
package query
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var timeType = reflect.TypeOf(time.Time{})
|
||||
|
||||
var encoderType = reflect.TypeOf(new(Encoder)).Elem()
|
||||
|
||||
// Encoder is an interface implemented by any type that wishes to encode
|
||||
// itself into URL values in a non-standard way.
|
||||
type Encoder interface {
|
||||
EncodeValues(key string, v *url.Values) error
|
||||
}
|
||||
|
||||
// Values returns the url.Values encoding of v.
|
||||
//
|
||||
// Values expects to be passed a struct, and traverses it recursively using the
|
||||
// following encoding rules.
|
||||
//
|
||||
// Each exported struct field is encoded as a URL parameter unless
|
||||
//
|
||||
// - the field's tag is "-", or
|
||||
// - the field is empty and its tag specifies the "omitempty" option
|
||||
//
|
||||
// The empty values are false, 0, any nil pointer or interface value, any array
|
||||
// slice, map, or string of length zero, and any time.Time that returns true
|
||||
// for IsZero().
|
||||
//
|
||||
// The URL parameter name defaults to the struct field name but can be
|
||||
// specified in the struct field's tag value. The "url" key in the struct
|
||||
// field's tag value is the key name, followed by an optional comma and
|
||||
// options. For example:
|
||||
//
|
||||
// // Field is ignored by this package.
|
||||
// Field int `url:"-"`
|
||||
//
|
||||
// // Field appears as URL parameter "myName".
|
||||
// Field int `url:"myName"`
|
||||
//
|
||||
// // Field appears as URL parameter "myName" and the field is omitted if
|
||||
// // its value is empty
|
||||
// Field int `url:"myName,omitempty"`
|
||||
//
|
||||
// // Field appears as URL parameter "Field" (the default), but the field
|
||||
// // is skipped if empty. Note the leading comma.
|
||||
// Field int `url:",omitempty"`
|
||||
//
|
||||
// For encoding individual field values, the following type-dependent rules
|
||||
// apply:
|
||||
//
|
||||
// Boolean values default to encoding as the strings "true" or "false".
|
||||
// Including the "int" option signals that the field should be encoded as the
|
||||
// strings "1" or "0".
|
||||
//
|
||||
// time.Time values default to encoding as RFC3339 timestamps. Including the
|
||||
// "unix" option signals that the field should be encoded as a Unix time (see
|
||||
// time.Unix())
|
||||
//
|
||||
// Slice and Array values default to encoding as multiple URL values of the
|
||||
// same name. Including the "comma" option signals that the field should be
|
||||
// encoded as a single comma-delimited value. Including the "space" option
|
||||
// similarly encodes the value as a single space-delimited string.
|
||||
//
|
||||
// Anonymous struct fields are usually encoded as if their inner exported
|
||||
// fields were fields in the outer struct, subject to the standard Go
|
||||
// visibility rules. An anonymous struct field with a name given in its URL
|
||||
// tag is treated as having that name, rather than being anonymous.
|
||||
//
|
||||
// Non-nil pointer values are encoded as the value pointed to.
|
||||
//
|
||||
// All other values are encoded using their default string representation.
|
||||
//
|
||||
// Multiple fields that encode to the same URL parameter name will be included
|
||||
// as multiple URL values of the same name.
|
||||
func Values(v interface{}) (url.Values, error) {
|
||||
val := reflect.ValueOf(v)
|
||||
for val.Kind() == reflect.Ptr {
|
||||
if val.IsNil() {
|
||||
return nil, errors.New("query: Values() expects non-nil value")
|
||||
}
|
||||
val = val.Elem()
|
||||
}
|
||||
|
||||
if val.Kind() != reflect.Struct {
|
||||
return nil, fmt.Errorf("query: Values() expects struct input. Got %v", val.Kind())
|
||||
}
|
||||
|
||||
values := make(url.Values)
|
||||
err := reflectValue(values, val)
|
||||
return values, err
|
||||
}
|
||||
|
||||
// reflectValue populates the values parameter from the struct fields in val.
|
||||
// Embedded structs are followed recursively (using the rules defined in the
|
||||
// Values function documentation) breadth-first.
|
||||
func reflectValue(values url.Values, val reflect.Value) error {
|
||||
var embedded []reflect.Value
|
||||
|
||||
typ := val.Type()
|
||||
for i := 0; i < typ.NumField(); i++ {
|
||||
sf := typ.Field(i)
|
||||
if sf.PkgPath != "" { // unexported
|
||||
continue
|
||||
}
|
||||
|
||||
sv := val.Field(i)
|
||||
tag := sf.Tag.Get("url")
|
||||
if tag == "-" {
|
||||
continue
|
||||
}
|
||||
name, opts := parseTag(tag)
|
||||
if name == "" {
|
||||
if sf.Anonymous && sv.Kind() == reflect.Struct {
|
||||
// save embedded struct for later processing
|
||||
embedded = append(embedded, sv)
|
||||
continue
|
||||
}
|
||||
|
||||
name = sf.Name
|
||||
}
|
||||
|
||||
if opts.Contains("omitempty") && isEmptyValue(sv) {
|
||||
continue
|
||||
}
|
||||
|
||||
if sv.Type().Implements(encoderType) {
|
||||
m := sv.Interface().(Encoder)
|
||||
if err := m.EncodeValues(name, &values); err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if sv.Kind() == reflect.Slice || sv.Kind() == reflect.Array {
|
||||
var del byte
|
||||
if opts.Contains("comma") {
|
||||
del = ','
|
||||
} else if opts.Contains("space") {
|
||||
del = ' '
|
||||
}
|
||||
|
||||
if del != 0 {
|
||||
s := new(bytes.Buffer)
|
||||
first := true
|
||||
for i := 0; i < sv.Len(); i++ {
|
||||
if first {
|
||||
first = false
|
||||
} else {
|
||||
s.WriteByte(del)
|
||||
}
|
||||
s.WriteString(valueString(sv.Index(i), opts))
|
||||
}
|
||||
values.Add(name, s.String())
|
||||
} else {
|
||||
for i := 0; i < sv.Len(); i++ {
|
||||
values.Add(name, valueString(sv.Index(i), opts))
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
values.Add(name, valueString(sv, opts))
|
||||
}
|
||||
|
||||
for _, f := range embedded {
|
||||
if err := reflectValue(values, f); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// valueString returns the string representation of a value.
|
||||
func valueString(v reflect.Value, opts tagOptions) string {
|
||||
for v.Kind() == reflect.Ptr {
|
||||
if v.IsNil() {
|
||||
return ""
|
||||
}
|
||||
v = v.Elem()
|
||||
}
|
||||
|
||||
if v.Kind() == reflect.Bool && opts.Contains("int") {
|
||||
if v.Bool() {
|
||||
return "1"
|
||||
}
|
||||
return "0"
|
||||
}
|
||||
|
||||
if v.Type() == timeType {
|
||||
t := v.Interface().(time.Time)
|
||||
if opts.Contains("unix") {
|
||||
return strconv.FormatInt(t.Unix(), 10)
|
||||
}
|
||||
return t.Format(time.RFC3339)
|
||||
}
|
||||
|
||||
return fmt.Sprint(v.Interface())
|
||||
}
|
||||
|
||||
// isEmptyValue checks if a value should be considered empty for the purposes
|
||||
// of omitting fields with the "omitempty" option.
|
||||
func isEmptyValue(v reflect.Value) bool {
|
||||
switch v.Kind() {
|
||||
case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
|
||||
return v.Len() == 0
|
||||
case reflect.Bool:
|
||||
return !v.Bool()
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return v.Int() == 0
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
return v.Uint() == 0
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return v.Float() == 0
|
||||
case reflect.Interface, reflect.Ptr:
|
||||
return v.IsNil()
|
||||
}
|
||||
|
||||
if v.Type() == timeType {
|
||||
return v.Interface().(time.Time).IsZero()
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// tagOptions is the string following a comma in a struct field's "url" tag, or
|
||||
// the empty string. It does not include the leading comma.
|
||||
type tagOptions []string
|
||||
|
||||
// parseTag splits a struct field's url tag into its name and comma-separated
|
||||
// options.
|
||||
func parseTag(tag string) (string, tagOptions) {
|
||||
s := strings.Split(tag, ",")
|
||||
return s[0], s[1:]
|
||||
}
|
||||
|
||||
// Contains checks whether the tagOptions contains the specified option.
|
||||
func (o tagOptions) Contains(option string) bool {
|
||||
for _, s := range o {
|
||||
if s == option {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
238
Godeps/_workspace/src/github.com/google/go-querystring/query/encode_test.go
generated
vendored
238
Godeps/_workspace/src/github.com/google/go-querystring/query/encode_test.go
generated
vendored
|
@ -1,238 +0,0 @@
|
|||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package query
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestValues_types(t *testing.T) {
|
||||
str := "string"
|
||||
strPtr := &str
|
||||
|
||||
tests := []struct {
|
||||
in interface{}
|
||||
want url.Values
|
||||
}{
|
||||
{
|
||||
// basic primitives
|
||||
struct {
|
||||
A string
|
||||
B int
|
||||
C uint
|
||||
D float32
|
||||
E bool
|
||||
}{},
|
||||
url.Values{
|
||||
"A": {""},
|
||||
"B": {"0"},
|
||||
"C": {"0"},
|
||||
"D": {"0"},
|
||||
"E": {"false"},
|
||||
},
|
||||
},
|
||||
{
|
||||
// pointers
|
||||
struct {
|
||||
A *string
|
||||
B *int
|
||||
C **string
|
||||
}{A: strPtr, C: &strPtr},
|
||||
url.Values{
|
||||
"A": {str},
|
||||
"B": {""},
|
||||
"C": {str},
|
||||
},
|
||||
},
|
||||
{
|
||||
// slices and arrays
|
||||
struct {
|
||||
A []string
|
||||
B []string `url:",comma"`
|
||||
C []string `url:",space"`
|
||||
D [2]string
|
||||
E [2]string `url:",comma"`
|
||||
F [2]string `url:",space"`
|
||||
G []*string `url:",space"`
|
||||
H []bool `url:",int,space"`
|
||||
}{
|
||||
A: []string{"a", "b"},
|
||||
B: []string{"a", "b"},
|
||||
C: []string{"a", "b"},
|
||||
D: [2]string{"a", "b"},
|
||||
E: [2]string{"a", "b"},
|
||||
F: [2]string{"a", "b"},
|
||||
G: []*string{&str, &str},
|
||||
H: []bool{true, false},
|
||||
},
|
||||
url.Values{
|
||||
"A": {"a", "b"},
|
||||
"B": {"a,b"},
|
||||
"C": {"a b"},
|
||||
"D": {"a", "b"},
|
||||
"E": {"a,b"},
|
||||
"F": {"a b"},
|
||||
"G": {"string string"},
|
||||
"H": {"1 0"},
|
||||
},
|
||||
},
|
||||
{
|
||||
// other types
|
||||
struct {
|
||||
A time.Time
|
||||
B time.Time `url:",unix"`
|
||||
C bool `url:",int"`
|
||||
D bool `url:",int"`
|
||||
}{
|
||||
A: time.Date(2000, 1, 1, 12, 34, 56, 0, time.UTC),
|
||||
B: time.Date(2000, 1, 1, 12, 34, 56, 0, time.UTC),
|
||||
C: true,
|
||||
D: false,
|
||||
},
|
||||
url.Values{
|
||||
"A": {"2000-01-01T12:34:56Z"},
|
||||
"B": {"946730096"},
|
||||
"C": {"1"},
|
||||
"D": {"0"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
v, err := Values(tt.in)
|
||||
if err != nil {
|
||||
t.Errorf("%d. Values(%q) returned error: %v", i, tt.in, err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(tt.want, v) {
|
||||
t.Errorf("%d. Values(%q) returned %v, want %v", i, tt.in, v, tt.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValues_omitEmpty(t *testing.T) {
|
||||
str := ""
|
||||
s := struct {
|
||||
a string
|
||||
A string
|
||||
B string `url:",omitempty"`
|
||||
C string `url:"-"`
|
||||
D string `url:"omitempty"` // actually named omitempty, not an option
|
||||
E *string `url:",omitempty"`
|
||||
}{E: &str}
|
||||
|
||||
v, err := Values(s)
|
||||
if err != nil {
|
||||
t.Errorf("Values(%q) returned error: %v", s, err)
|
||||
}
|
||||
|
||||
want := url.Values{
|
||||
"A": {""},
|
||||
"omitempty": {""},
|
||||
"E": {""}, // E is included because the pointer is not empty, even though the string being pointed to is
|
||||
}
|
||||
if !reflect.DeepEqual(want, v) {
|
||||
t.Errorf("Values(%q) returned %v, want %v", s, v, want)
|
||||
}
|
||||
}
|
||||
|
||||
type A struct {
|
||||
B
|
||||
}
|
||||
|
||||
type B struct {
|
||||
C string
|
||||
}
|
||||
|
||||
type D struct {
|
||||
B
|
||||
C string
|
||||
}
|
||||
|
||||
func TestValues_embeddedStructs(t *testing.T) {
|
||||
tests := []struct {
|
||||
in interface{}
|
||||
want url.Values
|
||||
}{
|
||||
{
|
||||
A{B{C: "foo"}},
|
||||
url.Values{"C": {"foo"}},
|
||||
},
|
||||
{
|
||||
D{B: B{C: "bar"}, C: "foo"},
|
||||
url.Values{"C": {"foo", "bar"}},
|
||||
},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
v, err := Values(tt.in)
|
||||
if err != nil {
|
||||
t.Errorf("%d. Values(%q) returned error: %v", i, tt.in, err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(tt.want, v) {
|
||||
t.Errorf("%d. Values(%q) returned %v, want %v", i, tt.in, v, tt.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValues_invalidInput(t *testing.T) {
|
||||
_, err := Values("")
|
||||
if err == nil {
|
||||
t.Errorf("expected Values() to return an error on invalid input")
|
||||
}
|
||||
}
|
||||
|
||||
type EncodedArgs []string
|
||||
|
||||
func (m EncodedArgs) EncodeValues(key string, v *url.Values) error {
|
||||
for i, arg := range m {
|
||||
v.Set(fmt.Sprintf("%s.%d", key, i), arg)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestValues_Marshaler(t *testing.T) {
|
||||
s := struct {
|
||||
Args EncodedArgs `url:"arg"`
|
||||
}{[]string{"a", "b", "c"}}
|
||||
v, err := Values(s)
|
||||
if err != nil {
|
||||
t.Errorf("Values(%q) returned error: %v", s, err)
|
||||
}
|
||||
|
||||
want := url.Values{
|
||||
"arg.0": {"a"},
|
||||
"arg.1": {"b"},
|
||||
"arg.2": {"c"},
|
||||
}
|
||||
if !reflect.DeepEqual(want, v) {
|
||||
t.Errorf("Values(%q) returned %v, want %v", s, v, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTagParsing(t *testing.T) {
|
||||
name, opts := parseTag("field,foobar,foo")
|
||||
if name != "field" {
|
||||
t.Fatalf("name = %q, want field", name)
|
||||
}
|
||||
for _, tt := range []struct {
|
||||
opt string
|
||||
want bool
|
||||
}{
|
||||
{"foobar", true},
|
||||
{"foo", true},
|
||||
{"bar", false},
|
||||
{"field", false},
|
||||
} {
|
||||
if opts.Contains(tt.opt) != tt.want {
|
||||
t.Errorf("Contains(%q) = %v", tt.opt, !tt.want)
|
||||
}
|
||||
}
|
||||
}
|
13
Godeps/_workspace/src/github.com/gorilla/mux/mux.go
generated
vendored
13
Godeps/_workspace/src/github.com/gorilla/mux/mux.go
generated
vendored
|
@ -152,6 +152,13 @@ func (r *Router) getRegexpGroup() *routeRegexpGroup {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (r *Router) buildVars(m map[string]string) map[string]string {
|
||||
if r.parent != nil {
|
||||
m = r.parent.buildVars(m)
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Route factories
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -224,6 +231,12 @@ func (r *Router) Schemes(schemes ...string) *Route {
|
|||
return r.NewRoute().Schemes(schemes...)
|
||||
}
|
||||
|
||||
// BuildVars registers a new route with a custom function for modifying
|
||||
// route variables before building a URL.
|
||||
func (r *Router) BuildVarsFunc(f BuildVarsFunc) *Route {
|
||||
return r.NewRoute().BuildVarsFunc(f)
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Context
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
33
Godeps/_workspace/src/github.com/gorilla/mux/mux_test.go
generated
vendored
33
Godeps/_workspace/src/github.com/gorilla/mux/mux_test.go
generated
vendored
|
@ -593,6 +593,39 @@ func TestMatcherFunc(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestBuildVarsFunc(t *testing.T) {
|
||||
tests := []routeTest{
|
||||
{
|
||||
title: "BuildVarsFunc set on route",
|
||||
route: new(Route).Path(`/111/{v1:\d}{v2:.*}`).BuildVarsFunc(func(vars map[string]string) map[string]string {
|
||||
vars["v1"] = "3"
|
||||
vars["v2"] = "a"
|
||||
return vars
|
||||
}),
|
||||
request: newRequest("GET", "http://localhost/111/2"),
|
||||
path: "/111/3a",
|
||||
shouldMatch: true,
|
||||
},
|
||||
{
|
||||
title: "BuildVarsFunc set on route and parent route",
|
||||
route: new(Route).PathPrefix(`/{v1:\d}`).BuildVarsFunc(func(vars map[string]string) map[string]string {
|
||||
vars["v1"] = "2"
|
||||
return vars
|
||||
}).Subrouter().Path(`/{v2:\w}`).BuildVarsFunc(func(vars map[string]string) map[string]string {
|
||||
vars["v2"] = "b"
|
||||
return vars
|
||||
}),
|
||||
request: newRequest("GET", "http://localhost/1/a"),
|
||||
path: "/2/b",
|
||||
shouldMatch: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
testRoute(t, test)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSubRouter(t *testing.T) {
|
||||
subrouter1 := new(Route).Host("{v1:[a-z]+}.google.com").Subrouter()
|
||||
subrouter2 := new(Route).PathPrefix("/foo/{v1}").Subrouter()
|
||||
|
|
6
Godeps/_workspace/src/github.com/gorilla/mux/regexp.go
generated
vendored
6
Godeps/_workspace/src/github.com/gorilla/mux/regexp.go
generated
vendored
|
@ -150,11 +150,7 @@ func (r *routeRegexp) Match(req *http.Request, match *RouteMatch) bool {
|
|||
}
|
||||
|
||||
// url builds a URL part using the given values.
|
||||
func (r *routeRegexp) url(pairs ...string) (string, error) {
|
||||
values, err := mapFromPairs(pairs...)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
func (r *routeRegexp) url(values map[string]string) (string, error) {
|
||||
urlValues := make([]interface{}, len(r.varsN))
|
||||
for k, v := range r.varsN {
|
||||
value, ok := values[v]
|
||||
|
|
57
Godeps/_workspace/src/github.com/gorilla/mux/route.go
generated
vendored
57
Godeps/_workspace/src/github.com/gorilla/mux/route.go
generated
vendored
|
@ -31,6 +31,8 @@ type Route struct {
|
|||
name string
|
||||
// Error resulted from building a route.
|
||||
err error
|
||||
|
||||
buildVarsFunc BuildVarsFunc
|
||||
}
|
||||
|
||||
// Match matches the route against the request.
|
||||
|
@ -360,6 +362,19 @@ func (r *Route) Schemes(schemes ...string) *Route {
|
|||
return r.addMatcher(schemeMatcher(schemes))
|
||||
}
|
||||
|
||||
// BuildVarsFunc --------------------------------------------------------------
|
||||
|
||||
// BuildVarsFunc is the function signature used by custom build variable
|
||||
// functions (which can modify route variables before a route's URL is built).
|
||||
type BuildVarsFunc func(map[string]string) map[string]string
|
||||
|
||||
// BuildVarsFunc adds a custom function to be used to modify build variables
|
||||
// before a route's URL is built.
|
||||
func (r *Route) BuildVarsFunc(f BuildVarsFunc) *Route {
|
||||
r.buildVarsFunc = f
|
||||
return r
|
||||
}
|
||||
|
||||
// Subrouter ------------------------------------------------------------------
|
||||
|
||||
// Subrouter creates a subrouter for the route.
|
||||
|
@ -422,17 +437,20 @@ func (r *Route) URL(pairs ...string) (*url.URL, error) {
|
|||
if r.regexp == nil {
|
||||
return nil, errors.New("mux: route doesn't have a host or path")
|
||||
}
|
||||
values, err := r.prepareVars(pairs...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var scheme, host, path string
|
||||
var err error
|
||||
if r.regexp.host != nil {
|
||||
// Set a default scheme.
|
||||
scheme = "http"
|
||||
if host, err = r.regexp.host.url(pairs...); err != nil {
|
||||
if host, err = r.regexp.host.url(values); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if r.regexp.path != nil {
|
||||
if path, err = r.regexp.path.url(pairs...); err != nil {
|
||||
if path, err = r.regexp.path.url(values); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
@ -453,7 +471,11 @@ func (r *Route) URLHost(pairs ...string) (*url.URL, error) {
|
|||
if r.regexp == nil || r.regexp.host == nil {
|
||||
return nil, errors.New("mux: route doesn't have a host")
|
||||
}
|
||||
host, err := r.regexp.host.url(pairs...)
|
||||
values, err := r.prepareVars(pairs...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
host, err := r.regexp.host.url(values)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -473,7 +495,11 @@ func (r *Route) URLPath(pairs ...string) (*url.URL, error) {
|
|||
if r.regexp == nil || r.regexp.path == nil {
|
||||
return nil, errors.New("mux: route doesn't have a path")
|
||||
}
|
||||
path, err := r.regexp.path.url(pairs...)
|
||||
values, err := r.prepareVars(pairs...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
path, err := r.regexp.path.url(values)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -482,6 +508,26 @@ func (r *Route) URLPath(pairs ...string) (*url.URL, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
// prepareVars converts the route variable pairs into a map. If the route has a
|
||||
// BuildVarsFunc, it is invoked.
|
||||
func (r *Route) prepareVars(pairs ...string) (map[string]string, error) {
|
||||
m, err := mapFromPairs(pairs...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return r.buildVars(m), nil
|
||||
}
|
||||
|
||||
func (r *Route) buildVars(m map[string]string) map[string]string {
|
||||
if r.parent != nil {
|
||||
m = r.parent.buildVars(m)
|
||||
}
|
||||
if r.buildVarsFunc != nil {
|
||||
m = r.buildVarsFunc(m)
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// parentRoute
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -490,6 +536,7 @@ func (r *Route) URLPath(pairs ...string) (*url.URL, error) {
|
|||
type parentRoute interface {
|
||||
getNamedRoutes() map[string]*Route
|
||||
getRegexpGroup() *routeRegexpGroup
|
||||
buildVars(map[string]string) map[string]string
|
||||
}
|
||||
|
||||
// getNamedRoutes returns the map where named routes are registered.
|
||||
|
|
26
Godeps/_workspace/src/github.com/gorilla/schema/decoder.go
generated
vendored
26
Godeps/_workspace/src/github.com/gorilla/schema/decoder.go
generated
vendored
|
@ -8,6 +8,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// NewDecoder returns a new Decoder.
|
||||
|
@ -156,9 +157,28 @@ func (d *Decoder) decode(v reflect.Value, path string, parts []pathPart,
|
|||
}
|
||||
items = append(items, item)
|
||||
} else {
|
||||
// If a single value is invalid should we give up
|
||||
// or set a zero value?
|
||||
return ConversionError{path, key}
|
||||
if strings.Contains(value, ",") {
|
||||
values := strings.Split(value, ",")
|
||||
for _, value := range values {
|
||||
if value == "" {
|
||||
if d.zeroEmpty {
|
||||
items = append(items, reflect.Zero(elemT))
|
||||
}
|
||||
} else if item := conv(value); item.IsValid() {
|
||||
if isPtrElem {
|
||||
ptr := reflect.New(elemT)
|
||||
ptr.Elem().Set(item)
|
||||
item = ptr
|
||||
}
|
||||
items = append(items, item)
|
||||
} else {
|
||||
return ConversionError{path, key}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
return ConversionError{path, key}
|
||||
}
|
||||
}
|
||||
}
|
||||
value := reflect.Append(reflect.MakeSlice(t, 0, 0), items...)
|
||||
|
|
41
Godeps/_workspace/src/github.com/gorilla/schema/decoder_test.go
generated
vendored
41
Godeps/_workspace/src/github.com/gorilla/schema/decoder_test.go
generated
vendored
|
@ -1036,3 +1036,44 @@ func TestAllNT(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
type S12A struct {
|
||||
ID []int
|
||||
}
|
||||
|
||||
func TestCSVSlice(t *testing.T) {
|
||||
data := map[string][]string{
|
||||
"ID": {"0,1"},
|
||||
}
|
||||
|
||||
s := S12A{}
|
||||
NewDecoder().Decode(&s, data)
|
||||
if len(s.ID) != 2 {
|
||||
t.Errorf("Expected two values in the result list, got %+v", s.ID)
|
||||
}
|
||||
if s.ID[0] != 0 || s.ID[1] != 1 {
|
||||
t.Errorf("Expected []{0, 1} got %+v", s)
|
||||
}
|
||||
}
|
||||
|
||||
type S12B struct {
|
||||
ID []string
|
||||
}
|
||||
|
||||
//Decode should not split on , into a slice for string only
|
||||
func TestCSVStringSlice(t *testing.T) {
|
||||
data := map[string][]string{
|
||||
"ID": {"0,1"},
|
||||
}
|
||||
|
||||
s := S12B{}
|
||||
NewDecoder().Decode(&s, data)
|
||||
if len(s.ID) != 1 {
|
||||
t.Errorf("Expected one value in the result list, got %+v", s.ID)
|
||||
}
|
||||
if s.ID[0] != "0,1" {
|
||||
t.Errorf("Expected []{0, 1} got %+v", s)
|
||||
}
|
||||
}
|
||||
|
|
3
Godeps/_workspace/src/github.com/lib/pq/README.md
generated
vendored
3
Godeps/_workspace/src/github.com/lib/pq/README.md
generated
vendored
|
@ -61,6 +61,8 @@ code still exists in here.
|
|||
* Dan Sosedoff (sosedoff)
|
||||
* Daniel Farina (fdr)
|
||||
* Eric Chlebek (echlebek)
|
||||
* Eric Garrido (minusnine)
|
||||
* Eric Urban (hydrogen18)
|
||||
* Everyone at The Go Team
|
||||
* Evan Shaw (edsrzf)
|
||||
* Ewan Chou (coocood)
|
||||
|
@ -94,5 +96,6 @@ code still exists in here.
|
|||
* Ryan Smith (ryandotsmith)
|
||||
* Samuel Stauffer (samuel)
|
||||
* Timothée Peignier (cyberdelia)
|
||||
* Travis Cline (tmc)
|
||||
* TruongSinh Tran-Nguyen (truongsinh)
|
||||
* notedit (notedit)
|
||||
|
|
3
Godeps/_workspace/src/github.com/lib/pq/bench_test.go
generated
vendored
3
Godeps/_workspace/src/github.com/lib/pq/bench_test.go
generated
vendored
|
@ -7,7 +7,6 @@ import (
|
|||
"bytes"
|
||||
"database/sql"
|
||||
"database/sql/driver"
|
||||
"github.com/lib/pq/oid"
|
||||
"io"
|
||||
"math/rand"
|
||||
"net"
|
||||
|
@ -17,6 +16,8 @@ import (
|
|||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/lib/pq/oid"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
1
Godeps/_workspace/src/github.com/lib/pq/buf.go
generated
vendored
1
Godeps/_workspace/src/github.com/lib/pq/buf.go
generated
vendored
|
@ -3,6 +3,7 @@ package pq
|
|||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
|
||||
"github.com/lib/pq/oid"
|
||||
)
|
||||
|
||||
|
|
17
Godeps/_workspace/src/github.com/lib/pq/conn.go
generated
vendored
17
Godeps/_workspace/src/github.com/lib/pq/conn.go
generated
vendored
|
@ -10,7 +10,6 @@ import (
|
|||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/lib/pq/oid"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
|
@ -22,6 +21,8 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
"unicode"
|
||||
|
||||
"github.com/lib/pq/oid"
|
||||
)
|
||||
|
||||
// Common error types
|
||||
|
@ -212,17 +213,17 @@ func DialOpen(d Dialer, name string) (_ driver.Conn, err error) {
|
|||
cn.buf = bufio.NewReader(cn.c)
|
||||
cn.startup(o)
|
||||
// reset the deadline, in case one was set (see dial)
|
||||
err = cn.c.SetDeadline(time.Time{})
|
||||
if timeout := o.Get("connect_timeout"); timeout != "" && timeout != "0" {
|
||||
err = cn.c.SetDeadline(time.Time{})
|
||||
}
|
||||
return cn, err
|
||||
}
|
||||
|
||||
func dial(d Dialer, o values) (net.Conn, error) {
|
||||
ntw, addr := network(o)
|
||||
|
||||
timeout := o.Get("connect_timeout")
|
||||
|
||||
// Zero or not specified means wait indefinitely.
|
||||
if timeout != "" && timeout != "0" {
|
||||
if timeout := o.Get("connect_timeout"); timeout != "" && timeout != "0" {
|
||||
seconds, err := strconv.ParseInt(timeout, 10, 0)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid value for parameter connect_timeout: %s", err)
|
||||
|
@ -436,6 +437,9 @@ func (cn *conn) Commit() (err error) {
|
|||
|
||||
_, commandTag, err := cn.simpleExec("COMMIT")
|
||||
if err != nil {
|
||||
if cn.isInTransaction() {
|
||||
cn.bad = true
|
||||
}
|
||||
return err
|
||||
}
|
||||
if commandTag != "COMMIT" {
|
||||
|
@ -455,6 +459,9 @@ func (cn *conn) Rollback() (err error) {
|
|||
cn.checkIsInTransaction(true)
|
||||
_, commandTag, err := cn.simpleExec("ROLLBACK")
|
||||
if err != nil {
|
||||
if cn.isInTransaction() {
|
||||
cn.bad = true
|
||||
}
|
||||
return err
|
||||
}
|
||||
if commandTag != "ROLLBACK" {
|
||||
|
|
3
Godeps/_workspace/src/github.com/lib/pq/doc.go
generated
vendored
3
Godeps/_workspace/src/github.com/lib/pq/doc.go
generated
vendored
|
@ -5,8 +5,9 @@ In most cases clients will use the database/sql package instead of
|
|||
using this package directly. For example:
|
||||
|
||||
import (
|
||||
_ "github.com/lib/pq"
|
||||
"database/sql"
|
||||
|
||||
_ "github.com/lib/pq"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
|
118
Godeps/_workspace/src/github.com/lib/pq/encode.go
generated
vendored
118
Godeps/_workspace/src/github.com/lib/pq/encode.go
generated
vendored
|
@ -5,12 +5,13 @@ import (
|
|||
"database/sql/driver"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"github.com/lib/pq/oid"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/lib/pq/oid"
|
||||
)
|
||||
|
||||
func encode(parameterStatus *parameterStatus, x interface{}, pgtypOid oid.Oid) []byte {
|
||||
|
@ -149,12 +150,6 @@ func appendEscapedText(buf []byte, text string) []byte {
|
|||
func mustParse(f string, typ oid.Oid, s []byte) time.Time {
|
||||
str := string(s)
|
||||
|
||||
// Special case until time.Parse bug is fixed:
|
||||
// http://code.google.com/p/go/issues/detail?id=3487
|
||||
if str[len(str)-2] == '.' {
|
||||
str += "0"
|
||||
}
|
||||
|
||||
// check for a 30-minute-offset timezone
|
||||
if (typ == oid.T_timestamptz || typ == oid.T_timetz) &&
|
||||
str[len(str)-3] == ':' {
|
||||
|
@ -212,11 +207,72 @@ func (c *locationCache) getLocation(offset int) *time.Location {
|
|||
return location
|
||||
}
|
||||
|
||||
var infinityTsEnabled = false
|
||||
var infinityTsNegative time.Time
|
||||
var infinityTsPositive time.Time
|
||||
|
||||
const (
|
||||
infinityTsEnabledAlready = "pq: infinity timestamp enabled already"
|
||||
infinityTsNegativeMustBeSmaller = "pq: infinity timestamp: negative value must be smaller (before) than positive"
|
||||
)
|
||||
|
||||
/*
|
||||
* If EnableInfinityTs is not called, "-infinity" and "infinity" will return
|
||||
* []byte("-infinity") and []byte("infinity") respectively, and potentially
|
||||
* cause error "sql: Scan error on column index 0: unsupported driver -> Scan pair: []uint8 -> *time.Time",
|
||||
* when scanning into a time.Time value.
|
||||
*
|
||||
* Once EnableInfinityTs has been called, all connections created using this
|
||||
* driver will decode Postgres' "-infinity" and "infinity" for "timestamp",
|
||||
* "timestamp with time zone" and "date" types to the predefined minimum and
|
||||
* maximum times, respectively. When encoding time.Time values, any time which
|
||||
* equals or preceeds the predefined minimum time will be encoded to
|
||||
* "-infinity". Any values at or past the maximum time will similarly be
|
||||
* encoded to "infinity".
|
||||
*
|
||||
*
|
||||
* If EnableInfinityTs is called with negative >= positive, it will panic.
|
||||
* Calling EnableInfinityTs after a connection has been established results in
|
||||
* undefined behavior. If EnableInfinityTs is called more than once, it will
|
||||
* panic.
|
||||
*/
|
||||
func EnableInfinityTs(negative time.Time, positive time.Time) {
|
||||
if infinityTsEnabled {
|
||||
panic(infinityTsEnabledAlready)
|
||||
}
|
||||
if !negative.Before(positive) {
|
||||
panic(infinityTsNegativeMustBeSmaller)
|
||||
}
|
||||
infinityTsEnabled = true
|
||||
infinityTsNegative = negative
|
||||
infinityTsPositive = positive
|
||||
}
|
||||
|
||||
/*
|
||||
* Testing might want to toggle infinityTsEnabled
|
||||
*/
|
||||
func disableInfinityTs() {
|
||||
infinityTsEnabled = false
|
||||
}
|
||||
|
||||
// This is a time function specific to the Postgres default DateStyle
|
||||
// setting ("ISO, MDY"), the only one we currently support. This
|
||||
// accounts for the discrepancies between the parsing available with
|
||||
// time.Parse and the Postgres date formatting quirks.
|
||||
func parseTs(currentLocation *time.Location, str string) (result time.Time) {
|
||||
func parseTs(currentLocation *time.Location, str string) interface{} {
|
||||
switch str {
|
||||
case "-infinity":
|
||||
if infinityTsEnabled {
|
||||
return infinityTsNegative
|
||||
}
|
||||
return []byte(str)
|
||||
case "infinity":
|
||||
if infinityTsEnabled {
|
||||
return infinityTsPositive
|
||||
}
|
||||
return []byte(str)
|
||||
}
|
||||
|
||||
monSep := strings.IndexRune(str, '-')
|
||||
// this is Gregorian year, not ISO Year
|
||||
// In Gregorian system, the year 1 BC is followed by AD 1
|
||||
|
@ -310,10 +366,18 @@ func parseTs(currentLocation *time.Location, str string) (result time.Time) {
|
|||
return t
|
||||
}
|
||||
|
||||
// formatTs formats t as time.RFC3339Nano and appends time zone seconds if
|
||||
// needed.
|
||||
// formatTs formats t into a format postgres understands.
|
||||
func formatTs(t time.Time) (b []byte) {
|
||||
b = []byte(t.Format(time.RFC3339Nano))
|
||||
if infinityTsEnabled {
|
||||
// t <= -infinity : ! (t > -infinity)
|
||||
if !t.After(infinityTsNegative) {
|
||||
return []byte("-infinity")
|
||||
}
|
||||
// t >= infinity : ! (!t < infinity)
|
||||
if !t.Before(infinityTsPositive) {
|
||||
return []byte("infinity")
|
||||
}
|
||||
}
|
||||
// Need to send dates before 0001 A.D. with " BC" suffix, instead of the
|
||||
// minus sign preferred by Go.
|
||||
// Beware, "0000" in ISO is "1 BC", "-0001" is "2 BC" and so on
|
||||
|
@ -324,25 +388,26 @@ func formatTs(t time.Time) (b []byte) {
|
|||
bc = true
|
||||
}
|
||||
b = []byte(t.Format(time.RFC3339Nano))
|
||||
if bc {
|
||||
b = append(b, " BC"...)
|
||||
}
|
||||
|
||||
_, offset := t.Zone()
|
||||
offset = offset % 60
|
||||
if offset == 0 {
|
||||
return b
|
||||
if offset != 0 {
|
||||
// RFC3339Nano already printed the minus sign
|
||||
if offset < 0 {
|
||||
offset = -offset
|
||||
}
|
||||
|
||||
b = append(b, ':')
|
||||
if offset < 10 {
|
||||
b = append(b, '0')
|
||||
}
|
||||
b = strconv.AppendInt(b, int64(offset), 10)
|
||||
}
|
||||
|
||||
if offset < 0 {
|
||||
offset = -offset
|
||||
if bc {
|
||||
b = append(b, " BC"...)
|
||||
}
|
||||
|
||||
b = append(b, ':')
|
||||
if offset < 10 {
|
||||
b = append(b, '0')
|
||||
}
|
||||
return strconv.AppendInt(b, int64(offset), 10)
|
||||
return b
|
||||
}
|
||||
|
||||
// Parse a bytea value received from the server. Both "hex" and the legacy
|
||||
|
@ -397,7 +462,10 @@ func parseBytea(s []byte) (result []byte) {
|
|||
func encodeBytea(serverVersion int, v []byte) (result []byte) {
|
||||
if serverVersion >= 90000 {
|
||||
// Use the hex format if we know that the server supports it
|
||||
result = []byte(fmt.Sprintf("\\x%x", v))
|
||||
result = make([]byte, 2+hex.EncodedLen(len(v)))
|
||||
result[0] = '\\'
|
||||
result[1] = 'x'
|
||||
hex.Encode(result[2:], v)
|
||||
} else {
|
||||
// .. or resort to "escape"
|
||||
for _, b := range v {
|
||||
|
|
147
Godeps/_workspace/src/github.com/lib/pq/encode_test.go
generated
vendored
147
Godeps/_workspace/src/github.com/lib/pq/encode_test.go
generated
vendored
|
@ -1,12 +1,12 @@
|
|||
package pq
|
||||
|
||||
import (
|
||||
"github.com/lib/pq/oid"
|
||||
|
||||
"bytes"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/lib/pq/oid"
|
||||
)
|
||||
|
||||
func TestScanTimestamp(t *testing.T) {
|
||||
|
@ -78,7 +78,11 @@ func tryParse(str string) (t time.Time, err error) {
|
|||
return
|
||||
}
|
||||
}()
|
||||
t = parseTs(nil, str)
|
||||
i := parseTs(nil, str)
|
||||
t, ok := i.(time.Time)
|
||||
if !ok {
|
||||
err = fmt.Errorf("Not a time.Time type, got %#v", i)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -132,8 +136,18 @@ var formatTimeTests = []struct {
|
|||
{time.Date(2001, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", 0)), "2001-02-03T04:05:06.123456789Z"},
|
||||
{time.Date(2001, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", 2*60*60)), "2001-02-03T04:05:06.123456789+02:00"},
|
||||
{time.Date(2001, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", -6*60*60)), "2001-02-03T04:05:06.123456789-06:00"},
|
||||
{time.Date(1, time.January, 1, 0, 0, 0, 0, time.FixedZone("", 19*60+32)), "0001-01-01T00:00:00+00:19:32"},
|
||||
{time.Date(2001, time.February, 3, 4, 5, 6, 0, time.FixedZone("", -(7*60*60+30*60+9))), "2001-02-03T04:05:06-07:30:09"},
|
||||
|
||||
{time.Date(1, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", 0)), "0001-02-03T04:05:06.123456789Z"},
|
||||
{time.Date(1, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", 2*60*60)), "0001-02-03T04:05:06.123456789+02:00"},
|
||||
{time.Date(1, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", -6*60*60)), "0001-02-03T04:05:06.123456789-06:00"},
|
||||
|
||||
{time.Date(0, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", 0)), "0001-02-03T04:05:06.123456789Z BC"},
|
||||
{time.Date(0, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", 2*60*60)), "0001-02-03T04:05:06.123456789+02:00 BC"},
|
||||
{time.Date(0, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", -6*60*60)), "0001-02-03T04:05:06.123456789-06:00 BC"},
|
||||
|
||||
{time.Date(1, time.February, 3, 4, 5, 6, 0, time.FixedZone("", -(7*60*60+30*60+9))), "0001-02-03T04:05:06-07:30:09"},
|
||||
{time.Date(0, time.February, 3, 4, 5, 6, 0, time.FixedZone("", -(7*60*60+30*60+9))), "0001-02-03T04:05:06-07:30:09 BC"},
|
||||
}
|
||||
|
||||
func TestFormatTs(t *testing.T) {
|
||||
|
@ -249,6 +263,131 @@ func TestTimestampWithOutTimezone(t *testing.T) {
|
|||
test("2013-01-04T20:14:58.80033Z", "2013-01-04 20:14:58.80033")
|
||||
}
|
||||
|
||||
func TestInfinityTimestamp(t *testing.T) {
|
||||
db := openTestConn(t)
|
||||
defer db.Close()
|
||||
var err error
|
||||
var resultT time.Time
|
||||
|
||||
expectedError := fmt.Errorf(`sql: Scan error on column index 0: unsupported driver -> Scan pair: []uint8 -> *time.Time`)
|
||||
type testCases []struct {
|
||||
Query string
|
||||
Param string
|
||||
ExpectedErr error
|
||||
ExpectedVal interface{}
|
||||
}
|
||||
tc := testCases{
|
||||
{"SELECT $1::timestamp", "-infinity", expectedError, "-infinity"},
|
||||
{"SELECT $1::timestamptz", "-infinity", expectedError, "-infinity"},
|
||||
{"SELECT $1::timestamp", "infinity", expectedError, "infinity"},
|
||||
{"SELECT $1::timestamptz", "infinity", expectedError, "infinity"},
|
||||
}
|
||||
// try to assert []byte to time.Time
|
||||
for _, q := range tc {
|
||||
err = db.QueryRow(q.Query, q.Param).Scan(&resultT)
|
||||
if err.Error() != q.ExpectedErr.Error() {
|
||||
t.Errorf("Scanning -/+infinity, expected error, %q, got %q", q.ExpectedErr, err)
|
||||
}
|
||||
}
|
||||
// yield []byte
|
||||
for _, q := range tc {
|
||||
var resultI interface{}
|
||||
err = db.QueryRow(q.Query, q.Param).Scan(&resultI)
|
||||
if err != nil {
|
||||
t.Errorf("Scanning -/+infinity, expected no error, got %q", err)
|
||||
}
|
||||
result, ok := resultI.([]byte)
|
||||
if !ok {
|
||||
t.Errorf("Scanning -/+infinity, expected []byte, got %#v", resultI)
|
||||
}
|
||||
if string(result) != q.ExpectedVal {
|
||||
t.Errorf("Scanning -/+infinity, expected %q, got %q", q.ExpectedVal, result)
|
||||
}
|
||||
}
|
||||
|
||||
y1500 := time.Date(1500, time.January, 1, 0, 0, 0, 0, time.UTC)
|
||||
y2500 := time.Date(2500, time.January, 1, 0, 0, 0, 0, time.UTC)
|
||||
EnableInfinityTs(y1500, y2500)
|
||||
|
||||
err = db.QueryRow("SELECT $1::timestamp", "infinity").Scan(&resultT)
|
||||
if err != nil {
|
||||
t.Errorf("Scanning infinity, expected no error, got %q", err)
|
||||
}
|
||||
if !resultT.Equal(y2500) {
|
||||
t.Errorf("Scanning infinity, expected %q, got %q", y2500, resultT)
|
||||
}
|
||||
|
||||
err = db.QueryRow("SELECT $1::timestamptz", "infinity").Scan(&resultT)
|
||||
if err != nil {
|
||||
t.Errorf("Scanning infinity, expected no error, got %q", err)
|
||||
}
|
||||
if !resultT.Equal(y2500) {
|
||||
t.Errorf("Scanning Infinity, expected time %q, got %q", y2500, resultT.String())
|
||||
}
|
||||
|
||||
err = db.QueryRow("SELECT $1::timestamp", "-infinity").Scan(&resultT)
|
||||
if err != nil {
|
||||
t.Errorf("Scanning -infinity, expected no error, got %q", err)
|
||||
}
|
||||
if !resultT.Equal(y1500) {
|
||||
t.Errorf("Scanning -infinity, expected time %q, got %q", y1500, resultT.String())
|
||||
}
|
||||
|
||||
err = db.QueryRow("SELECT $1::timestamptz", "-infinity").Scan(&resultT)
|
||||
if err != nil {
|
||||
t.Errorf("Scanning -infinity, expected no error, got %q", err)
|
||||
}
|
||||
if !resultT.Equal(y1500) {
|
||||
t.Errorf("Scanning -infinity, expected time %q, got %q", y1500, resultT.String())
|
||||
}
|
||||
|
||||
y_1500 := time.Date(-1500, time.January, 1, 0, 0, 0, 0, time.UTC)
|
||||
y11500 := time.Date(11500, time.January, 1, 0, 0, 0, 0, time.UTC)
|
||||
var s string
|
||||
err = db.QueryRow("SELECT $1::timestamp::text", y_1500).Scan(&s)
|
||||
if err != nil {
|
||||
t.Errorf("Encoding -infinity, expected no error, got %q", err)
|
||||
}
|
||||
if s != "-infinity" {
|
||||
t.Errorf("Encoding -infinity, expected %q, got %q", "-infinity", s)
|
||||
}
|
||||
err = db.QueryRow("SELECT $1::timestamptz::text", y_1500).Scan(&s)
|
||||
if err != nil {
|
||||
t.Errorf("Encoding -infinity, expected no error, got %q", err)
|
||||
}
|
||||
if s != "-infinity" {
|
||||
t.Errorf("Encoding -infinity, expected %q, got %q", "-infinity", s)
|
||||
}
|
||||
|
||||
err = db.QueryRow("SELECT $1::timestamp::text", y11500).Scan(&s)
|
||||
if err != nil {
|
||||
t.Errorf("Encoding infinity, expected no error, got %q", err)
|
||||
}
|
||||
if s != "infinity" {
|
||||
t.Errorf("Encoding infinity, expected %q, got %q", "infinity", s)
|
||||
}
|
||||
err = db.QueryRow("SELECT $1::timestamptz::text", y11500).Scan(&s)
|
||||
if err != nil {
|
||||
t.Errorf("Encoding infinity, expected no error, got %q", err)
|
||||
}
|
||||
if s != "infinity" {
|
||||
t.Errorf("Encoding infinity, expected %q, got %q", "infinity", s)
|
||||
}
|
||||
|
||||
disableInfinityTs()
|
||||
|
||||
var panicErrorString string
|
||||
func() {
|
||||
defer func() {
|
||||
panicErrorString, _ = recover().(string)
|
||||
}()
|
||||
EnableInfinityTs(y2500, y1500)
|
||||
}()
|
||||
if panicErrorString != infinityTsNegativeMustBeSmaller {
|
||||
t.Errorf("Expected error, %q, got %q", infinityTsNegativeMustBeSmaller, panicErrorString)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringWithNul(t *testing.T) {
|
||||
db := openTestConn(t)
|
||||
defer db.Close()
|
||||
|
|
3
Godeps/_workspace/src/github.com/lib/pq/hstore/hstore_test.go
generated
vendored
3
Godeps/_workspace/src/github.com/lib/pq/hstore/hstore_test.go
generated
vendored
|
@ -2,9 +2,10 @@ package hstore
|
|||
|
||||
import (
|
||||
"database/sql"
|
||||
_ "github.com/lib/pq"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
_ "github.com/lib/pq"
|
||||
)
|
||||
|
||||
type Fatalistic interface {
|
||||
|
|
4
Godeps/_workspace/src/github.com/lib/pq/listen_example/doc.go
generated
vendored
4
Godeps/_workspace/src/github.com/lib/pq/listen_example/doc.go
generated
vendored
|
@ -18,11 +18,11 @@ mechanism to avoid polling the database while waiting for more work to arrive.
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/lib/pq"
|
||||
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/lib/pq"
|
||||
)
|
||||
|
||||
func doWork(db *sql.DB, work int64) {
|
||||
|
|
1
Godeps/_workspace/src/github.com/lib/pq/notify_test.go
generated
vendored
1
Godeps/_workspace/src/github.com/lib/pq/notify_test.go
generated
vendored
|
@ -43,6 +43,7 @@ func expectEvent(t *testing.T, eventch <-chan ListenerEventType, et ListenerEven
|
|||
}
|
||||
return nil
|
||||
case <-time.After(1500 * time.Millisecond):
|
||||
panic("expectEvent timeout")
|
||||
return fmt.Errorf("timeout")
|
||||
}
|
||||
}
|
||||
|
|
2
Godeps/_workspace/src/github.com/lib/pq/oid/gen.go
generated
vendored
2
Godeps/_workspace/src/github.com/lib/pq/oid/gen.go
generated
vendored
|
@ -5,12 +5,12 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
||||
"database/sql"
|
||||
_ "github.com/lib/pq"
|
||||
)
|
||||
|
||||
|
|
Reference in a new issue