aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Muré <batolettre@gmail.com>2019-07-09 08:47:46 +0200
committerGitHub <noreply@github.com>2019-07-09 08:47:46 +0200
commita5c42b7c11fc082d47027ba5e0dbdeddcc14e62e (patch)
treea279d04878f3f1b1e28089779d011c0cb4b7545d
parenteef7333243252ae81cd43921beb8e0749a170585 (diff)
parentfb50d470483b91d98e27ca6f9f605f0c51af6a71 (diff)
downloadgit-bug-a5c42b7c11fc082d47027ba5e0dbdeddcc14e62e.tar.gz
Merge pull request #177 from A-Hilaly/git-version
Check git version in repo RmConfigs
-rw-r--r--Gopkg.lock9
-rw-r--r--Gopkg.toml6
-rw-r--r--repository/git.go91
-rw-r--r--repository/git_test.go2
-rw-r--r--vendor/github.com/99designs/gqlgen/api/generate.go2
-rw-r--r--vendor/github.com/99designs/gqlgen/codegen/args.go16
-rw-r--r--vendor/github.com/99designs/gqlgen/codegen/args.gotpl20
-rw-r--r--vendor/github.com/99designs/gqlgen/codegen/config/binder.go24
-rw-r--r--vendor/github.com/99designs/gqlgen/codegen/config/config.go96
-rw-r--r--vendor/github.com/99designs/gqlgen/codegen/data.go7
-rw-r--r--vendor/github.com/99designs/gqlgen/codegen/directive.go63
-rw-r--r--vendor/github.com/99designs/gqlgen/codegen/directives.gotpl137
-rw-r--r--vendor/github.com/99designs/gqlgen/codegen/field.go23
-rw-r--r--vendor/github.com/99designs/gqlgen/codegen/field.gotpl94
-rw-r--r--vendor/github.com/99designs/gqlgen/codegen/generated!.gotpl59
-rw-r--r--vendor/github.com/99designs/gqlgen/codegen/input.gotpl24
-rw-r--r--vendor/github.com/99designs/gqlgen/graphql/version.go2
-rw-r--r--vendor/github.com/99designs/gqlgen/handler/graphql.go93
-rw-r--r--vendor/github.com/99designs/gqlgen/handler/websocket.go10
-rw-r--r--vendor/github.com/99designs/gqlgen/plugin/modelgen/models.go5
-rw-r--r--vendor/github.com/99designs/gqlgen/plugin/resolvergen/resolver.go1
-rw-r--r--vendor/github.com/99designs/gqlgen/plugin/resolvergen/resolver.gotpl6
-rw-r--r--vendor/github.com/99designs/gqlgen/plugin/schemaconfig/schemaconfig.go93
-rw-r--r--vendor/github.com/blang/semver/.travis.yml25
-rw-r--r--vendor/github.com/blang/semver/LICENSE22
-rw-r--r--vendor/github.com/blang/semver/README.md194
-rw-r--r--vendor/github.com/blang/semver/go.mod1
-rw-r--r--vendor/github.com/blang/semver/json.go23
-rw-r--r--vendor/github.com/blang/semver/package.json17
-rw-r--r--vendor/github.com/blang/semver/range.go416
-rw-r--r--vendor/github.com/blang/semver/semver.go455
-rw-r--r--vendor/github.com/blang/semver/sort.go28
-rw-r--r--vendor/github.com/blang/semver/sql.go30
-rw-r--r--vendor/github.com/gorilla/mux/.travis.yml24
-rw-r--r--vendor/github.com/gorilla/mux/ISSUE_TEMPLATE.md11
-rw-r--r--vendor/github.com/gorilla/mux/README.md69
-rw-r--r--vendor/github.com/gorilla/mux/doc.go2
-rw-r--r--vendor/github.com/gorilla/mux/middleware.go61
38 files changed, 2045 insertions, 216 deletions
diff --git a/Gopkg.lock b/Gopkg.lock
index 321ae3c7..b60cb83c 100644
--- a/Gopkg.lock
+++ b/Gopkg.lock
@@ -43,6 +43,14 @@
version = "v1.0.0"
[[projects]]
+ digest = "1:b6d886569181ec96ca83d529f4d6ba0cbf92ace7bb6f633f90c5f34d9bba7aab"
+ name = "github.com/blang/semver"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "ba2c2ddd89069b46a7011d4106f6868f17ee1705"
+ version = "v3.6.1"
+
+[[projects]]
branch = "master"
digest = "1:f438d91be142877c3ad83157992c91de787ddfbddcc2a7da1ef6ef61606cadc4"
name = "github.com/cheekybits/genny"
@@ -442,6 +450,7 @@
"github.com/99designs/gqlgen/graphql/introspection",
"github.com/99designs/gqlgen/handler",
"github.com/MichaelMure/gocui",
+ "github.com/blang/semver",
"github.com/cheekybits/genny/generic",
"github.com/dustin/go-humanize",
"github.com/fatih/color",
diff --git a/Gopkg.toml b/Gopkg.toml
index a406d377..519760c7 100644
--- a/Gopkg.toml
+++ b/Gopkg.toml
@@ -66,4 +66,8 @@
[[override]]
name = "golang.org/x/tools"
- revision = "7e5bf9270d7061560865b8847c378236480f47e3" \ No newline at end of file
+ revision = "7e5bf9270d7061560865b8847c378236480f47e3"
+
+[[constraint]]
+ name = "github.com/blang/semver"
+ version = "3.6.1"
diff --git a/repository/git.go b/repository/git.go
index c8c45d6a..9ec7905a 100644
--- a/repository/git.go
+++ b/repository/git.go
@@ -3,7 +3,6 @@ package repository
import (
"bytes"
- "errors"
"fmt"
"io"
"os/exec"
@@ -11,6 +10,9 @@ import (
"strconv"
"strings"
+ "github.com/blang/semver"
+ "github.com/pkg/errors"
+
"github.com/MichaelMure/git-bug/util/git"
"github.com/MichaelMure/git-bug/util/lamport"
)
@@ -259,16 +261,89 @@ func (repo *GitRepo) ReadConfigString(key string) (string, error) {
return lines[0], nil
}
+func (repo *GitRepo) rmSection(keyPrefix string) error {
+ _, err := repo.runGitCommand("config", "--remove-section", keyPrefix)
+ return err
+}
+
+func (repo *GitRepo) unsetAll(keyPrefix string) error {
+ _, err := repo.runGitCommand("config", "--unset-all", keyPrefix)
+ return err
+}
+
+// return keyPrefix section
+// example: sectionFromKey(a.b.c.d) return a.b.c
+func sectionFromKey(keyPrefix string) string {
+ s := strings.Split(keyPrefix, ".")
+ if len(s) == 1 {
+ return keyPrefix
+ }
+
+ return strings.Join(s[:len(s)-1], ".")
+}
+
+// rmConfigs with git version lesser than 2.18
+func (repo *GitRepo) rmConfigsGitVersionLT218(keyPrefix string) error {
+ // try to remove key/value pair by key
+ err := repo.unsetAll(keyPrefix)
+ if err != nil {
+ return repo.rmSection(keyPrefix)
+ }
+
+ m, err := repo.ReadConfigs(sectionFromKey(keyPrefix))
+ if err != nil {
+ return err
+ }
+
+ // if section doesn't have any left key/value remove the section
+ if len(m) == 0 {
+ return repo.rmSection(sectionFromKey(keyPrefix))
+ }
+
+ return nil
+}
+
// RmConfigs remove all key/value pair matching the key prefix
func (repo *GitRepo) RmConfigs(keyPrefix string) error {
- // try to remove key/value pair by key
- _, err := repo.runGitCommand("config", "--unset-all", keyPrefix)
+ // starting from git 2.18.0 sections are automatically deleted when the last existing
+ // key/value is removed. Before 2.18.0 we should remove the section
+ // see https://github.com/git/git/blob/master/Documentation/RelNotes/2.18.0.txt#L379
+ lt218, err := repo.gitVersionLT218()
if err != nil {
- // try to remove section
- _, err = repo.runGitCommand("config", "--remove-section", keyPrefix)
+ return errors.Wrap(err, "getting git version")
}
- return err
+ if lt218 {
+ return repo.rmConfigsGitVersionLT218(keyPrefix)
+ }
+
+ err = repo.unsetAll(keyPrefix)
+ if err != nil {
+ return repo.rmSection(keyPrefix)
+ }
+
+ return nil
+}
+
+func (repo *GitRepo) gitVersionLT218() (bool, error) {
+ versionOut, err := repo.runGitCommand("version")
+ if err != nil {
+ return false, err
+ }
+
+ versionString := strings.Fields(versionOut)[2]
+ version, err := semver.Make(versionString)
+ if err != nil {
+ return false, err
+ }
+
+ version218string := "2.18.0"
+ gitVersion218, err := semver.Make(version218string)
+ if err != nil {
+ return false, err
+ }
+
+ return version.LT(gitVersion218), nil
}
// FetchRefs fetch git refs from a remote
@@ -428,7 +503,7 @@ func (repo *GitRepo) FindCommonAncestor(hash1 git.Hash, hash2 git.Hash) (git.Has
stdout, err := repo.runGitCommand("merge-base", string(hash1), string(hash2))
if err != nil {
- return "", nil
+ return "", err
}
return git.Hash(stdout), nil
@@ -439,7 +514,7 @@ func (repo *GitRepo) GetTreeHash(commit git.Hash) (git.Hash, error) {
stdout, err := repo.runGitCommand("rev-parse", string(commit)+"^{tree}")
if err != nil {
- return "", nil
+ return "", err
}
return git.Hash(stdout), nil
diff --git a/repository/git_test.go b/repository/git_test.go
index 8bd3aa8e..20bf6ec3 100644
--- a/repository/git_test.go
+++ b/repository/git_test.go
@@ -55,7 +55,7 @@ func TestConfig(t *testing.T) {
assert.Error(t, err)
err = repo.RmConfigs("section")
- assert.NoError(t, err)
+ assert.Error(t, err)
_, err = repo.ReadConfigString("section.key")
assert.Error(t, err)
diff --git a/vendor/github.com/99designs/gqlgen/api/generate.go b/vendor/github.com/99designs/gqlgen/api/generate.go
index 3dd083f5..3256bdc3 100644
--- a/vendor/github.com/99designs/gqlgen/api/generate.go
+++ b/vendor/github.com/99designs/gqlgen/api/generate.go
@@ -8,6 +8,7 @@ import (
"github.com/99designs/gqlgen/plugin"
"github.com/99designs/gqlgen/plugin/modelgen"
"github.com/99designs/gqlgen/plugin/resolvergen"
+ "github.com/99designs/gqlgen/plugin/schemaconfig"
"github.com/pkg/errors"
"golang.org/x/tools/go/packages"
)
@@ -17,6 +18,7 @@ func Generate(cfg *config.Config, option ...Option) error {
_ = syscall.Unlink(cfg.Model.Filename)
plugins := []plugin.Plugin{
+ schemaconfig.New(),
modelgen.New(),
resolvergen.New(),
}
diff --git a/vendor/github.com/99designs/gqlgen/codegen/args.go b/vendor/github.com/99designs/gqlgen/codegen/args.go
index d1498bdd..1d3e51aa 100644
--- a/vendor/github.com/99designs/gqlgen/codegen/args.go
+++ b/vendor/github.com/99designs/gqlgen/codegen/args.go
@@ -26,6 +26,22 @@ type FieldArgument struct {
Value interface{} // value set in Data
}
+//ImplDirectives get not Builtin and location ARGUMENT_DEFINITION directive
+func (f *FieldArgument) ImplDirectives() []*Directive {
+ d := make([]*Directive, 0)
+ for i := range f.Directives {
+ if !f.Directives[i].Builtin && f.Directives[i].IsLocation(ast.LocationArgumentDefinition) {
+ d = append(d, f.Directives[i])
+ }
+ }
+
+ return d
+}
+
+func (f *FieldArgument) DirectiveObjName() string {
+ return "rawArgs"
+}
+
func (f *FieldArgument) Stream() bool {
return f.Object != nil && f.Object.Stream
}
diff --git a/vendor/github.com/99designs/gqlgen/codegen/args.gotpl b/vendor/github.com/99designs/gqlgen/codegen/args.gotpl
index 4c721218..c76bf0f7 100644
--- a/vendor/github.com/99designs/gqlgen/codegen/args.gotpl
+++ b/vendor/github.com/99designs/gqlgen/codegen/args.gotpl
@@ -5,22 +5,10 @@ func (ec *executionContext) {{ $name }}(ctx context.Context, rawArgs map[string]
{{- range $i, $arg := . }}
var arg{{$i}} {{ $arg.TypeReference.GO | ref}}
if tmp, ok := rawArgs[{{$arg.Name|quote}}]; ok {
- {{- if $arg.Directives }}
- getArg0 := func(ctx context.Context) (interface{}, error) { return ec.{{ $arg.TypeReference.UnmarshalFunc }}(ctx, tmp) }
-
- {{- range $i, $directive := $arg.Directives }}
- getArg{{add $i 1}} := func(ctx context.Context) (res interface{}, err error) {
- {{- range $dArg := $directive.Args }}
- {{- if and $dArg.TypeReference.IsPtr ( notNil "Value" $dArg ) }}
- {{ $dArg.VarName }} := {{ $dArg.Value | dump }}
- {{- end }}
- {{- end }}
- n := getArg{{$i}}
- return ec.directives.{{$directive.Name|ucFirst}}({{$directive.ResolveArgs "tmp" "n" }})
- }
- {{- end }}
-
- tmp, err = getArg{{$arg.Directives|len}}(ctx)
+ {{- if $arg.ImplDirectives }}
+ directive0 := func(ctx context.Context) (interface{}, error) { return ec.{{ $arg.TypeReference.UnmarshalFunc }}(ctx, tmp) }
+ {{ template "implDirectives" $arg }}
+ tmp, err = directive{{$arg.ImplDirectives|len}}(ctx)
if err != nil {
return nil, err
}
diff --git a/vendor/github.com/99designs/gqlgen/codegen/config/binder.go b/vendor/github.com/99designs/gqlgen/codegen/config/binder.go
index cea904ad..72956de4 100644
--- a/vendor/github.com/99designs/gqlgen/codegen/config/binder.go
+++ b/vendor/github.com/99designs/gqlgen/codegen/config/binder.go
@@ -14,7 +14,7 @@ import (
// Binder connects graphql types to golang types using static analysis
type Binder struct {
- pkgs []*packages.Package
+ pkgs map[string]*packages.Package
schema *ast.Schema
cfg *Config
References []*TypeReference
@@ -26,7 +26,9 @@ func (c *Config) NewBinder(s *ast.Schema) (*Binder, error) {
return nil, err
}
+ mp := map[string]*packages.Package{}
for _, p := range pkgs {
+ populatePkg(mp, p)
for _, e := range p.Errors {
if e.Kind == packages.ListError {
return nil, p.Errors[0]
@@ -35,12 +37,23 @@ func (c *Config) NewBinder(s *ast.Schema) (*Binder, error) {
}
return &Binder{
- pkgs: pkgs,
+ pkgs: mp,
schema: s,
cfg: c,
}, nil
}
+func populatePkg(mp map[string]*packages.Package, p *packages.Package) {
+ imp := code.NormalizeVendor(p.PkgPath)
+ if _, ok := mp[imp]; ok {
+ return
+ }
+ mp[imp] = p
+ for _, p := range p.Imports {
+ populatePkg(mp, p)
+ }
+}
+
func (b *Binder) TypePosition(typ types.Type) token.Position {
named, isNamed := typ.(*types.Named)
if !isNamed {
@@ -75,10 +88,9 @@ func (b *Binder) FindType(pkgName string, typeName string) (types.Type, error) {
}
func (b *Binder) getPkg(find string) *packages.Package {
- for _, p := range b.pkgs {
- if code.NormalizeVendor(find) == code.NormalizeVendor(p.PkgPath) {
- return p
- }
+ imp := code.NormalizeVendor(find)
+ if p, ok := b.pkgs[imp]; ok {
+ return p
}
return nil
}
diff --git a/vendor/github.com/99designs/gqlgen/codegen/config/config.go b/vendor/github.com/99designs/gqlgen/codegen/config/config.go
index 1725adab..c7a7d4d8 100644
--- a/vendor/github.com/99designs/gqlgen/codegen/config/config.go
+++ b/vendor/github.com/99designs/gqlgen/codegen/config/config.go
@@ -6,9 +6,12 @@ import (
"io/ioutil"
"os"
"path/filepath"
+ "regexp"
"sort"
"strings"
+ "golang.org/x/tools/go/packages"
+
"github.com/99designs/gqlgen/internal/code"
"github.com/pkg/errors"
"github.com/vektah/gqlparser"
@@ -17,12 +20,14 @@ import (
)
type Config struct {
- SchemaFilename StringList `yaml:"schema,omitempty"`
- Exec PackageConfig `yaml:"exec"`
- Model PackageConfig `yaml:"model"`
- Resolver PackageConfig `yaml:"resolver,omitempty"`
- Models TypeMap `yaml:"models,omitempty"`
- StructTag string `yaml:"struct_tag,omitempty"`
+ SchemaFilename StringList `yaml:"schema,omitempty"`
+ Exec PackageConfig `yaml:"exec"`
+ Model PackageConfig `yaml:"model"`
+ Resolver PackageConfig `yaml:"resolver,omitempty"`
+ AutoBind []string `yaml:"autobind"`
+ Models TypeMap `yaml:"models,omitempty"`
+ StructTag string `yaml:"struct_tag,omitempty"`
+ Directives map[string]DirectiveConfig `yaml:"directives,omitempty"`
}
var cfgFilenames = []string{".gqlgen.yml", "gqlgen.yml", "gqlgen.yaml"}
@@ -33,6 +38,17 @@ func DefaultConfig() *Config {
SchemaFilename: StringList{"schema.graphql"},
Model: PackageConfig{Filename: "models_gen.go"},
Exec: PackageConfig{Filename: "generated.go"},
+ Directives: map[string]DirectiveConfig{
+ "skip": {
+ SkipRuntime: true,
+ },
+ "include": {
+ SkipRuntime: true,
+ },
+ "deprecated": {
+ SkipRuntime: true,
+ },
+ },
}
}
@@ -51,6 +67,13 @@ func LoadConfigFromDefaultLocations() (*Config, error) {
return LoadConfig(cfgFile)
}
+var path2regex = strings.NewReplacer(
+ `.`, `\.`,
+ `*`, `.+`,
+ `\`, `[\\/]`,
+ `/`, `[\\/]`,
+)
+
// LoadConfig reads the gqlgen.yml config file
func LoadConfig(filename string) (*Config, error) {
config := DefaultConfig()
@@ -67,9 +90,35 @@ func LoadConfig(filename string) (*Config, error) {
preGlobbing := config.SchemaFilename
config.SchemaFilename = StringList{}
for _, f := range preGlobbing {
- matches, err := filepath.Glob(f)
- if err != nil {
- return nil, errors.Wrapf(err, "failed to glob schema filename %s", f)
+ var matches []string
+
+ // for ** we want to override default globbing patterns and walk all
+ // subdirectories to match schema files.
+ if strings.Contains(f, "**") {
+ pathParts := strings.SplitN(f, "**", 2)
+ rest := strings.TrimPrefix(strings.TrimPrefix(pathParts[1], `\`), `/`)
+ // turn the rest of the glob into a regex, anchored only at the end because ** allows
+ // for any number of dirs in between and walk will let us match against the full path name
+ globRe := regexp.MustCompile(path2regex.Replace(rest) + `$`)
+
+ if err := filepath.Walk(pathParts[0], func(path string, info os.FileInfo, err error) error {
+ if err != nil {
+ return err
+ }
+
+ if globRe.MatchString(strings.TrimPrefix(path, pathParts[0])) {
+ matches = append(matches, path)
+ }
+
+ return nil
+ }); err != nil {
+ return nil, errors.Wrapf(err, "failed to walk schema at root %s", pathParts[0])
+ }
+ } else {
+ matches, err = filepath.Glob(f)
+ if err != nil {
+ return nil, errors.Wrapf(err, "failed to glob schema filename %s", f)
+ }
}
for _, m := range matches {
@@ -265,6 +314,10 @@ func (tm TypeMap) Add(Name string, goType string) {
tm[Name] = modelCfg
}
+type DirectiveConfig struct {
+ SkipRuntime bool `yaml:"skip_runtime"`
+}
+
func inStrSlice(haystack []string, needle string) bool {
for _, v := range haystack {
if needle == v {
@@ -329,6 +382,31 @@ func (c *Config) normalize() error {
return nil
}
+func (c *Config) Autobind(s *ast.Schema) error {
+ if len(c.AutoBind) == 0 {
+ return nil
+ }
+ ps, err := packages.Load(&packages.Config{Mode: packages.LoadTypes}, c.AutoBind...)
+ if err != nil {
+ return err
+ }
+
+ for _, t := range s.Types {
+ if c.Models.UserDefined(t.Name) {
+ continue
+ }
+
+ for _, p := range ps {
+ if t := p.Types.Scope().Lookup(t.Name); t != nil {
+ c.Models.Add(t.Name(), t.Pkg().Path()+"."+t.Name())
+ break
+ }
+ }
+ }
+
+ return nil
+}
+
func (c *Config) InjectBuiltins(s *ast.Schema) {
builtins := TypeMap{
"__Directive": {Model: StringList{"github.com/99designs/gqlgen/graphql/introspection.Directive"}},
diff --git a/vendor/github.com/99designs/gqlgen/codegen/data.go b/vendor/github.com/99designs/gqlgen/codegen/data.go
index f2ea70b4..98d2ec88 100644
--- a/vendor/github.com/99designs/gqlgen/codegen/data.go
+++ b/vendor/github.com/99designs/gqlgen/codegen/data.go
@@ -15,7 +15,7 @@ type Data struct {
Config *config.Config
Schema *ast.Schema
SchemaStr map[string]string
- Directives map[string]*Directive
+ Directives DirectiveList
Objects Objects
Inputs Objects
Interfaces map[string]*Interface
@@ -51,6 +51,11 @@ func BuildData(cfg *config.Config) (*Data, error) {
return nil, err
}
+ err = cfg.Autobind(b.Schema)
+ if err != nil {
+ return nil, err
+ }
+
cfg.InjectBuiltins(b.Schema)
b.Binder, err = b.Config.NewBinder(b.Schema)
diff --git a/vendor/github.com/99designs/gqlgen/codegen/directive.go b/vendor/github.com/99designs/gqlgen/codegen/directive.go
index 5a27e8ac..491f92f4 100644
--- a/vendor/github.com/99designs/gqlgen/codegen/directive.go
+++ b/vendor/github.com/99designs/gqlgen/codegen/directive.go
@@ -10,12 +10,43 @@ import (
"github.com/vektah/gqlparser/ast"
)
+type DirectiveList map[string]*Directive
+
+//LocationDirectives filter directives by location
+func (dl DirectiveList) LocationDirectives(location string) DirectiveList {
+ return locationDirectives(dl, ast.DirectiveLocation(location))
+}
+
type Directive struct {
+ *ast.DirectiveDefinition
Name string
Args []*FieldArgument
Builtin bool
}
+//IsLocation check location directive
+func (d *Directive) IsLocation(location ...ast.DirectiveLocation) bool {
+ for _, l := range d.Locations {
+ for _, a := range location {
+ if l == a {
+ return true
+ }
+ }
+ }
+
+ return false
+}
+
+func locationDirectives(directives DirectiveList, location ...ast.DirectiveLocation) map[string]*Directive {
+ mDirectives := make(map[string]*Directive)
+ for name, d := range directives {
+ if d.IsLocation(location...) {
+ mDirectives[name] = d
+ }
+ }
+ return mDirectives
+}
+
func (b *builder) buildDirectives() (map[string]*Directive, error) {
directives := make(map[string]*Directive, len(b.Schema.Directives))
@@ -24,11 +55,6 @@ func (b *builder) buildDirectives() (map[string]*Directive, error) {
return nil, errors.Errorf("directive with name %s already exists", name)
}
- var builtin bool
- if name == "skip" || name == "include" || name == "deprecated" {
- builtin = true
- }
-
var args []*FieldArgument
for _, arg := range dir.Arguments {
tr, err := b.Binder.TypeReference(arg.Type, nil)
@@ -53,9 +79,10 @@ func (b *builder) buildDirectives() (map[string]*Directive, error) {
}
directives[name] = &Directive{
- Name: name,
- Args: args,
- Builtin: builtin,
+ DirectiveDefinition: dir,
+ Name: name,
+ Args: args,
+ Builtin: b.Config.Directives[name].SkipRuntime,
}
}
@@ -92,8 +119,10 @@ func (b *builder) getDirectives(list ast.DirectiveList) ([]*Directive, error) {
})
}
dirs[i] = &Directive{
- Name: d.Name,
- Args: args,
+ Name: d.Name,
+ Args: args,
+ DirectiveDefinition: list[i].Definition,
+ Builtin: b.Config.Directives[d.Name].SkipRuntime,
}
}
@@ -119,18 +148,12 @@ func (d *Directive) CallArgs() string {
return strings.Join(args, ", ")
}
-func (d *Directive) ResolveArgs(obj string, next string) string {
- args := []string{"ctx", obj, next}
+func (d *Directive) ResolveArgs(obj string, next int) string {
+ args := []string{"ctx", obj, fmt.Sprintf("directive%d", next)}
for _, arg := range d.Args {
- dArg := "&" + arg.VarName
- if !arg.TypeReference.IsPtr() {
- if arg.Value != nil {
- dArg = templates.Dump(arg.Value)
- } else {
- dArg = templates.Dump(arg.Default)
- }
- } else if arg.Value == nil && arg.Default == nil {
+ dArg := arg.VarName
+ if arg.Value == nil && arg.Default == nil {
dArg = "nil"
}
diff --git a/vendor/github.com/99designs/gqlgen/codegen/directives.gotpl b/vendor/github.com/99designs/gqlgen/codegen/directives.gotpl
new file mode 100644
index 00000000..67a0783e
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/codegen/directives.gotpl
@@ -0,0 +1,137 @@
+{{ define "implDirectives" }}{{ $in := .DirectiveObjName }}
+ {{- range $i, $directive := .ImplDirectives -}}
+ directive{{add $i 1}} := func(ctx context.Context) (interface{}, error) {
+ {{- range $arg := $directive.Args }}
+ {{- if notNil "Value" $arg }}
+ {{ $arg.VarName }}, err := ec.{{ $arg.TypeReference.UnmarshalFunc }}(ctx, {{ $arg.Value | dump }})
+ if err != nil{
+ return nil, err
+ }
+ {{- else if notNil "Default" $arg }}
+ {{ $arg.VarName }}, err := ec.{{ $arg.TypeReference.UnmarshalFunc }}(ctx, {{ $arg.Default | dump }})
+ if err != nil{
+ return nil, err
+ }
+ {{- end }}
+ {{- end }}
+ return ec.directives.{{$directive.Name|ucFirst}}({{$directive.ResolveArgs $in $i }})
+ }
+ {{- end -}}
+{{ end }}
+
+{{define "queryDirectives"}}
+ for _, d := range obj.Directives {
+ switch d.Name {
+ {{- range $directive := . }}
+ case "{{$directive.Name}}":
+ {{- if $directive.Args }}
+ rawArgs := d.ArgumentMap(ec.Variables)
+ args, err := ec.{{ $directive.ArgsFunc }}(ctx,rawArgs)
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ {{- end }}
+ n := next
+ next = func(ctx context.Context) (interface{}, error) {
+ return ec.directives.{{$directive.Name|ucFirst}}({{$directive.CallArgs}})
+ }
+ {{- end }}
+ }
+ }
+ tmp, err := next(ctx)
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if data, ok := tmp.(graphql.Marshaler); ok {
+ return data
+ }
+ ec.Errorf(ctx, `unexpected type %T from directive, should be graphql.Marshaler`, tmp)
+ return graphql.Null
+{{end}}
+
+{{ if .Directives.LocationDirectives "QUERY" }}
+func (ec *executionContext) _queryMiddleware(ctx context.Context, obj *ast.OperationDefinition, next func(ctx context.Context) (interface{}, error)) graphql.Marshaler {
+ {{ template "queryDirectives" .Directives.LocationDirectives "QUERY" }}
+}
+{{ end }}
+
+{{ if .Directives.LocationDirectives "MUTATION" }}
+func (ec *executionContext) _mutationMiddleware(ctx context.Context, obj *ast.OperationDefinition, next func(ctx context.Context) (interface{}, error)) graphql.Marshaler {
+ {{ template "queryDirectives" .Directives.LocationDirectives "MUTATION" }}
+}
+{{ end }}
+
+{{ if .Directives.LocationDirectives "SUBSCRIPTION" }}
+func (ec *executionContext) _subscriptionMiddleware(ctx context.Context, obj *ast.OperationDefinition, next func(ctx context.Context) (interface{}, error)) func() graphql.Marshaler {
+ for _, d := range obj.Directives {
+ switch d.Name {
+ {{- range $directive := .Directives.LocationDirectives "SUBSCRIPTION" }}
+ case "{{$directive.Name}}":
+ {{- if $directive.Args }}
+ rawArgs := d.ArgumentMap(ec.Variables)
+ args, err := ec.{{ $directive.ArgsFunc }}(ctx,rawArgs)
+ if err != nil {
+ ec.Error(ctx, err)
+ return func() graphql.Marshaler {
+ return graphql.Null
+ }
+ }
+ {{- end }}
+ n := next
+ next = func(ctx context.Context) (interface{}, error) {
+ return ec.directives.{{$directive.Name|ucFirst}}({{$directive.CallArgs}})
+ }
+ {{- end }}
+ }
+ }
+ tmp, err := next(ctx)
+ if err != nil {
+ ec.Error(ctx, err)
+ return func() graphql.Marshaler {
+ return graphql.Null
+ }
+ }
+ if data, ok := tmp.(func() graphql.Marshaler); ok {
+ return data
+ }
+ ec.Errorf(ctx, `unexpected type %T from directive, should be graphql.Marshaler`, tmp)
+ return func() graphql.Marshaler {
+ return graphql.Null
+ }
+}
+{{ end }}
+
+{{ if .Directives.LocationDirectives "FIELD" }}
+ func (ec *executionContext) _fieldMiddleware(ctx context.Context, obj interface{}, next graphql.Resolver) interface{} {
+ {{- if .Directives.LocationDirectives "FIELD" }}
+ rctx := graphql.GetResolverContext(ctx)
+ for _, d := range rctx.Field.Directives {
+ switch d.Name {
+ {{- range $directive := .Directives.LocationDirectives "FIELD" }}
+ case "{{$directive.Name}}":
+ {{- if $directive.Args }}
+ rawArgs := d.ArgumentMap(ec.Variables)
+ args, err := ec.{{ $directive.ArgsFunc }}(ctx,rawArgs)
+ if err != nil {
+ ec.Error(ctx, err)
+ return nil
+ }
+ {{- end }}
+ n := next
+ next = func(ctx context.Context) (interface{}, error) {
+ return ec.directives.{{$directive.Name|ucFirst}}({{$directive.CallArgs}})
+ }
+ {{- end }}
+ }
+ }
+ {{- end }}
+ res, err := ec.ResolverMiddleware(ctx, next)
+ if err != nil {
+ ec.Error(ctx, err)
+ return nil
+ }
+ return res
+ }
+{{ end }}
diff --git a/vendor/github.com/99designs/gqlgen/codegen/field.go b/vendor/github.com/99designs/gqlgen/codegen/field.go
index f5f7b221..264b59ce 100644
--- a/vendor/github.com/99designs/gqlgen/codegen/field.go
+++ b/vendor/github.com/99designs/gqlgen/codegen/field.go
@@ -284,7 +284,28 @@ func (b *builder) findBindStructTarget(strukt *types.Struct, name string) (types
}
func (f *Field) HasDirectives() bool {
- return len(f.Directives) > 0
+ return len(f.ImplDirectives()) > 0
+}
+
+func (f *Field) DirectiveObjName() string {
+ if f.Object.Root {
+ return "nil"
+ }
+ return f.GoReceiverName
+}
+
+func (f *Field) ImplDirectives() []*Directive {
+ var d []*Directive
+ loc := ast.LocationFieldDefinition
+ if f.Object.IsInputType() {
+ loc = ast.LocationInputFieldDefinition
+ }
+ for i := range f.Directives {
+ if !f.Directives[i].Builtin && f.Directives[i].IsLocation(loc) {
+ d = append(d, f.Directives[i])
+ }
+ }
+ return d
}
func (f *Field) IsReserved() bool {
diff --git a/vendor/github.com/99designs/gqlgen/codegen/field.gotpl b/vendor/github.com/99designs/gqlgen/codegen/field.gotpl
index 9718a08a..c0f6fcae 100644
--- a/vendor/github.com/99designs/gqlgen/codegen/field.gotpl
+++ b/vendor/github.com/99designs/gqlgen/codegen/field.gotpl
@@ -37,9 +37,15 @@
}
}
{{ else }}
- func (ec *executionContext) _{{$object.Name}}_{{$field.Name}}(ctx context.Context, field graphql.CollectedField{{ if not $object.Root }}, obj {{$object.Reference | ref}}{{end}}) graphql.Marshaler {
+ func (ec *executionContext) _{{$object.Name}}_{{$field.Name}}(ctx context.Context, field graphql.CollectedField{{ if not $object.Root }}, obj {{$object.Reference | ref}}{{end}}) (ret graphql.Marshaler) {
ctx = ec.Tracer.StartFieldExecution(ctx, field)
- defer func () { ec.Tracer.EndFieldExecution(ctx) }()
+ defer func () {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ ec.Tracer.EndFieldExecution(ctx)
+ }()
rctx := &graphql.ResolverContext{
Object: {{$object.Name|quote}},
Field: field,
@@ -57,31 +63,19 @@
rctx.Args = args
{{- end }}
ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx)
- resTmp := ec.FieldMiddleware(ctx, {{if $object.Root}}nil{{else}}obj{{end}}, func(rctx context.Context) (interface{}, error) {
- ctx = rctx // use context from middleware stack in children
- {{- if $field.IsResolver }}
- return ec.resolvers.{{ $field.ShortInvocation }}
- {{- else if $field.IsMap }}
- switch v := {{$field.GoReceiverName}}[{{$field.Name|quote}}].(type) {
- case {{$field.TypeReference.GO | ref}}:
- return v, nil
- case {{$field.TypeReference.Elem.GO | ref}}:
- return &v, nil
- case nil:
- return ({{$field.TypeReference.GO | ref}})(nil), nil
- default:
- return nil, fmt.Errorf("unexpected type %T for field %s", v, {{ $field.Name | quote}})
- }
- {{- else if $field.IsMethod }}
- {{- if $field.NoErr }}
- return {{$field.GoReceiverName}}.{{$field.GoFieldName}}({{ $field.CallArgs }}), nil
- {{- else }}
- return {{$field.GoReceiverName}}.{{$field.GoFieldName}}({{ $field.CallArgs }})
- {{- end }}
- {{- else if $field.IsVariable }}
- return {{$field.GoReceiverName}}.{{$field.GoFieldName}}, nil
- {{- end }}
- })
+ {{- if $.Directives.LocationDirectives "FIELD" }}
+ resTmp := ec._fieldMiddleware(ctx, {{if $object.Root}}nil{{else}}obj{{end}}, func(rctx context.Context) (interface{}, error) {
+ {{ template "field" $field }}
+ })
+ {{ else }}
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ {{ template "field" $field }}
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ {{- end }}
if resTmp == nil {
{{- if $field.TypeReference.GQL.NonNull }}
if !ec.HasError(rctx) {
@@ -98,3 +92,49 @@
{{ end }}
{{- end }}{{- end}}
+
+{{ define "field" }}
+ {{- if .HasDirectives -}}
+ directive0 := func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ {{ template "fieldDefinition" . }}
+ }
+ {{ template "implDirectives" . }}
+ tmp, err := directive{{.ImplDirectives|len}}(rctx)
+ if err != nil {
+ return nil, err
+ }
+ if data, ok := tmp.({{ .TypeReference.GO | ref }}) ; ok {
+ return data, nil
+ }
+ return nil, fmt.Errorf(`unexpected type %T from directive, should be {{ .TypeReference.GO }}`, tmp)
+ {{- else -}}
+ ctx = rctx // use context from middleware stack in children
+ {{ template "fieldDefinition" . }}
+ {{- end -}}
+{{ end }}
+
+{{ define "fieldDefinition" }}
+ {{- if .IsResolver -}}
+ return ec.resolvers.{{ .ShortInvocation }}
+ {{- else if .IsMap -}}
+ switch v := {{.GoReceiverName}}[{{.Name|quote}}].(type) {
+ case {{.TypeReference.GO | ref}}:
+ return v, nil
+ case {{.TypeReference.Elem.GO | ref}}:
+ return &v, nil
+ case nil:
+ return ({{.TypeReference.GO | ref}})(nil), nil
+ default:
+ return nil, fmt.Errorf("unexpected type %T for field %s", v, {{ .Name | quote}})
+ }
+ {{- else if .IsMethod -}}
+ {{- if .NoErr -}}
+ return {{.GoReceiverName}}.{{.GoFieldName}}({{ .CallArgs }}), nil
+ {{- else -}}
+ return {{.GoReceiverName}}.{{.GoFieldName}}({{ .CallArgs }})
+ {{- end -}}
+ {{- else if .IsVariable -}}
+ return {{.GoReceiverName}}.{{.GoFieldName}}, nil
+ {{- end }}
+{{- end }}
diff --git a/vendor/github.com/99designs/gqlgen/codegen/generated!.gotpl b/vendor/github.com/99designs/gqlgen/codegen/generated!.gotpl
index 5753f1d1..a95e57b6 100644
--- a/vendor/github.com/99designs/gqlgen/codegen/generated!.gotpl
+++ b/vendor/github.com/99designs/gqlgen/codegen/generated!.gotpl
@@ -117,7 +117,13 @@ func (e *executableSchema) Query(ctx context.Context, op *ast.OperationDefinitio
ec := executionContext{graphql.GetRequestContext(ctx), e}
buf := ec.RequestMiddleware(ctx, func(ctx context.Context) []byte {
+ {{ if .Directives.LocationDirectives "QUERY" -}}
+ data := ec._queryMiddleware(ctx, op, func(ctx context.Context) (interface{}, error){
+ return ec._{{.QueryRoot.Name}}(ctx, op.SelectionSet), nil
+ })
+ {{- else -}}
data := ec._{{.QueryRoot.Name}}(ctx, op.SelectionSet)
+ {{- end }}
var buf bytes.Buffer
data.MarshalGQL(&buf)
return buf.Bytes()
@@ -138,7 +144,13 @@ func (e *executableSchema) Mutation(ctx context.Context, op *ast.OperationDefini
ec := executionContext{graphql.GetRequestContext(ctx), e}
buf := ec.RequestMiddleware(ctx, func(ctx context.Context) []byte {
+ {{ if .Directives.LocationDirectives "MUTATION" -}}
+ data := ec._mutationMiddleware(ctx, op, func(ctx context.Context) (interface{}, error){
+ return ec._{{.MutationRoot.Name}}(ctx, op.SelectionSet), nil
+ })
+ {{- else -}}
data := ec._{{.MutationRoot.Name}}(ctx, op.SelectionSet)
+ {{- end }}
var buf bytes.Buffer
data.MarshalGQL(&buf)
return buf.Bytes()
@@ -158,7 +170,13 @@ func (e *executableSchema) Subscription(ctx context.Context, op *ast.OperationDe
{{- if .SubscriptionRoot }}
ec := executionContext{graphql.GetRequestContext(ctx), e}
- next := ec._{{.SubscriptionRoot.Name}}(ctx, op.SelectionSet)
+ {{ if .Directives.LocationDirectives "SUBSCRIPTION" -}}
+ next := ec._subscriptionMiddleware(ctx, op, func(ctx context.Context) (interface{}, error){
+ return ec._{{.SubscriptionRoot.Name}}(ctx, op.SelectionSet),nil
+ })
+ {{- else -}}
+ next := ec._{{.SubscriptionRoot.Name}}(ctx, op.SelectionSet)
+ {{- end }}
if ec.Errors != nil {
return graphql.OneShot(&graphql.Response{Data: []byte("null"), Errors: ec.Errors})
}
@@ -196,45 +214,6 @@ type executionContext struct {
*executableSchema
}
-func (ec *executionContext) FieldMiddleware(ctx context.Context, obj interface{}, next graphql.Resolver) (ret interface{}) {
- defer func() {
- if r := recover(); r != nil {
- ec.Error(ctx, ec.Recover(ctx, r))
- ret = nil
- }
- }()
- {{- if .Directives }}
- rctx := graphql.GetResolverContext(ctx)
- for _, d := range rctx.Field.Definition.Directives {
- switch d.Name {
- {{- range $directive := .Directives }}
- case "{{$directive.Name}}":
- if ec.directives.{{$directive.Name|ucFirst}} != nil {
- {{- if $directive.Args }}
- rawArgs := d.ArgumentMap(ec.Variables)
- args, err := ec.{{ $directive.ArgsFunc }}(ctx,rawArgs)
- if err != nil {
- ec.Error(ctx, err)
- return nil
- }
- {{- end }}
- n := next
- next = func(ctx context.Context) (interface{}, error) {
- return ec.directives.{{$directive.Name|ucFirst}}({{$directive.CallArgs}})
- }
- }
- {{- end }}
- }
- }
- {{- end }}
- res, err := ec.ResolverMiddleware(ctx, next)
- if err != nil {
- ec.Error(ctx, err)
- return nil
- }
- return res
-}
-
func (ec *executionContext) introspectSchema() (*introspection.Schema, error) {
if ec.DisableIntrospection {
return nil, errors.New("introspection disabled")
diff --git a/vendor/github.com/99designs/gqlgen/codegen/input.gotpl b/vendor/github.com/99designs/gqlgen/codegen/input.gotpl
index c8ac7ad3..b51d53a2 100644
--- a/vendor/github.com/99designs/gqlgen/codegen/input.gotpl
+++ b/vendor/github.com/99designs/gqlgen/codegen/input.gotpl
@@ -1,8 +1,8 @@
{{- range $input := .Inputs }}
{{- if not .HasUnmarshal }}
- func (ec *executionContext) unmarshalInput{{ .Name }}(ctx context.Context, v interface{}) ({{.Type | ref}}, error) {
+ func (ec *executionContext) unmarshalInput{{ .Name }}(ctx context.Context, obj interface{}) ({{.Type | ref}}, error) {
var it {{.Type | ref}}
- var asMap = v.(map[string]interface{})
+ var asMap = obj.(map[string]interface{})
{{ range $field := .Fields}}
{{- if $field.Default}}
if _, present := asMap[{{$field.Name|quote}}] ; !present {
@@ -16,22 +16,10 @@
{{- range $field := .Fields }}
case {{$field.Name|quote}}:
var err error
- {{- if $field.Directives }}
- getField0 := func(ctx context.Context) (interface{}, error) { return ec.{{ $field.TypeReference.UnmarshalFunc }}(ctx, v) }
-
- {{- range $i, $directive := $field.Directives }}
- getField{{add $i 1}} := func(ctx context.Context) (res interface{}, err error) {
- {{- range $dArg := $directive.Args }}
- {{- if and $dArg.TypeReference.IsPtr ( notNil "Value" $dArg ) }}
- {{ $dArg.VarName }} := {{ $dArg.Value | dump }}
- {{- end }}
- {{- end }}
- n := getField{{$i}}
- return ec.directives.{{$directive.Name|ucFirst}}({{$directive.ResolveArgs "it" "n" }})
- }
- {{- end }}
-
- tmp, err := getField{{$field.Directives|len}}(ctx)
+ {{- if $field.ImplDirectives }}
+ directive0 := func(ctx context.Context) (interface{}, error) { return ec.{{ $field.TypeReference.UnmarshalFunc }}(ctx, v) }
+ {{ template "implDirectives" $field }}
+ tmp, err := directive{{$field.ImplDirectives|len}}(ctx)
if err != nil {
return it, err
}
diff --git a/vendor/github.com/99designs/gqlgen/graphql/version.go b/vendor/github.com/99designs/gqlgen/graphql/version.go
index 11dc6b01..3c5e65d6 100644
--- a/vendor/github.com/99designs/gqlgen/graphql/version.go
+++ b/vendor/github.com/99designs/gqlgen/graphql/version.go
@@ -1,3 +1,3 @@
package graphql
-const Version = "v0.9.0"
+const Version = "v0.9.1"
diff --git a/vendor/github.com/99designs/gqlgen/handler/graphql.go b/vendor/github.com/99designs/gqlgen/handler/graphql.go
index a2254222..289901f0 100644
--- a/vendor/github.com/99designs/gqlgen/handler/graphql.go
+++ b/vendor/github.com/99designs/gqlgen/handler/graphql.go
@@ -2,6 +2,8 @@ package handler
import (
"context"
+ "crypto/sha256"
+ "encoding/hex"
"encoding/json"
"errors"
"fmt"
@@ -28,8 +30,30 @@ type params struct {
Query string `json:"query"`
OperationName string `json:"operationName"`
Variables map[string]interface{} `json:"variables"`
+ Extensions *extensions `json:"extensions"`
}
+type extensions struct {
+ PersistedQuery *persistedQuery `json:"persistedQuery"`
+}
+
+type persistedQuery struct {
+ Sha256 string `json:"sha256Hash"`
+ Version int64 `json:"version"`
+}
+
+const (
+ errPersistedQueryNotSupported = "PersistedQueryNotSupported"
+ errPersistedQueryNotFound = "PersistedQueryNotFound"
+)
+
+type PersistedQueryCache interface {
+ Add(ctx context.Context, hash string, query string)
+ Get(ctx context.Context, hash string) (string, bool)
+}
+
+type websocketInitFunc func(ctx context.Context, initPayload InitPayload) error
+
type Config struct {
cacheSize int
upgrader websocket.Upgrader
@@ -40,10 +64,12 @@ type Config struct {
tracer graphql.Tracer
complexityLimit int
complexityLimitFunc graphql.ComplexityLimitFunc
+ websocketInitFunc websocketInitFunc
disableIntrospection bool
connectionKeepAlivePingInterval time.Duration
uploadMaxMemory int64
uploadMaxSize int64
+ apqCache PersistedQueryCache
}
func (c *Config) newRequestContext(es graphql.ExecutableSchema, doc *ast.QueryDocument, op *ast.OperationDefinition, query string, variables map[string]interface{}) *graphql.RequestContext {
@@ -250,6 +276,14 @@ func (tw *tracerWrapper) EndOperationExecution(ctx context.Context) {
tw.tracer1.EndOperationExecution(ctx)
}
+// WebsocketInitFunc is called when the server receives connection init message from the client.
+// This can be used to check initial payload to see whether to accept the websocket connection.
+func WebsocketInitFunc(websocketInitFunc func(ctx context.Context, initPayload InitPayload) error) Option {
+ return func(cfg *Config) {
+ cfg.websocketInitFunc = websocketInitFunc
+ }
+}
+
// CacheSize sets the maximum size of the query cache.
// If size is less than or equal to 0, the cache is disabled.
func CacheSize(size int) Option {
@@ -285,6 +319,13 @@ func WebsocketKeepAliveDuration(duration time.Duration) Option {
}
}
+// Add cache that will hold queries for automatic persisted queries (APQ)
+func EnablePersistedQueryCache(cache PersistedQueryCache) Option {
+ return func(cfg *Config) {
+ cfg.apqCache = cache
+ }
+}
+
const DefaultCacheSize = 1000
const DefaultConnectionKeepAlivePingInterval = 25 * time.Second
@@ -344,6 +385,11 @@ type graphqlHandler struct {
exec graphql.ExecutableSchema
}
+func computeQueryHash(query string) string {
+ b := sha256.Sum256([]byte(query))
+ return hex.EncodeToString(b[:])
+}
+
func (gh *graphqlHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodOptions {
w.Header().Set("Allow", "OPTIONS, GET, POST")
@@ -369,6 +415,13 @@ func (gh *graphqlHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return
}
}
+
+ if extensions := r.URL.Query().Get("extensions"); extensions != "" {
+ if err := jsonDecode(strings.NewReader(extensions), &reqParams.Extensions); err != nil {
+ sendErrorf(w, http.StatusBadRequest, "extensions could not be decoded")
+ return
+ }
+ }
case http.MethodPost:
mediaType, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
if err != nil {
@@ -409,6 +462,41 @@ func (gh *graphqlHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
+ var queryHash string
+ apqRegister := false
+ apq := reqParams.Extensions != nil && reqParams.Extensions.PersistedQuery != nil
+ if apq {
+ // client has enabled apq
+ queryHash = reqParams.Extensions.PersistedQuery.Sha256
+ if gh.cfg.apqCache == nil {
+ // server has disabled apq
+ sendErrorf(w, http.StatusOK, errPersistedQueryNotSupported)
+ return
+ }
+ if reqParams.Extensions.PersistedQuery.Version != 1 {
+ sendErrorf(w, http.StatusOK, "Unsupported persisted query version")
+ return
+ }
+ if reqParams.Query == "" {
+ // client sent optimistic query hash without query string
+ query, ok := gh.cfg.apqCache.Get(ctx, queryHash)
+ if !ok {
+ sendErrorf(w, http.StatusOK, errPersistedQueryNotFound)
+ return
+ }
+ reqParams.Query = query
+ } else {
+ if computeQueryHash(reqParams.Query) != queryHash {
+ sendErrorf(w, http.StatusOK, "provided sha does not match query")
+ return
+ }
+ apqRegister = true
+ }
+ } else if reqParams.Query == "" {
+ sendErrorf(w, http.StatusUnprocessableEntity, "Must provide query string")
+ return
+ }
+
var doc *ast.QueryDocument
var cacheHit bool
if gh.cache != nil {
@@ -463,6 +551,11 @@ func (gh *graphqlHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return
}
+ if apqRegister && gh.cfg.apqCache != nil {
+ // Add to persisted query cache
+ gh.cfg.apqCache.Add(ctx, queryHash, reqParams.Query)
+ }
+
switch op.Operation {
case ast.Query:
b, err := json.Marshal(gh.exec.Query(ctx, op))
diff --git a/vendor/github.com/99designs/gqlgen/handler/websocket.go b/vendor/github.com/99designs/gqlgen/handler/websocket.go
index 58f38e5d..07a1a8c2 100644
--- a/vendor/github.com/99designs/gqlgen/handler/websocket.go
+++ b/vendor/github.com/99designs/gqlgen/handler/websocket.go
@@ -12,7 +12,7 @@ import (
"github.com/99designs/gqlgen/graphql"
"github.com/gorilla/websocket"
- "github.com/hashicorp/golang-lru"
+ lru "github.com/hashicorp/golang-lru"
"github.com/vektah/gqlparser"
"github.com/vektah/gqlparser/ast"
"github.com/vektah/gqlparser/gqlerror"
@@ -94,6 +94,14 @@ func (c *wsConnection) init() bool {
}
}
+ if c.cfg.websocketInitFunc != nil {
+ if err := c.cfg.websocketInitFunc(c.ctx, c.initPayload); err != nil {
+ c.sendConnectionError(err.Error())
+ c.close(websocket.CloseNormalClosure, "terminated")
+ return false
+ }
+ }
+
c.write(&operationMessage{Type: connectionAckMsg})
case connectionTerminateMsg:
c.close(websocket.CloseNormalClosure, "terminated")
diff --git a/vendor/github.com/99designs/gqlgen/plugin/modelgen/models.go b/vendor/github.com/99designs/gqlgen/plugin/modelgen/models.go
index bb400f1b..376499ae 100644
--- a/vendor/github.com/99designs/gqlgen/plugin/modelgen/models.go
+++ b/vendor/github.com/99designs/gqlgen/plugin/modelgen/models.go
@@ -72,6 +72,11 @@ func (m *Plugin) MutateConfig(cfg *config.Config) error {
return err
}
+ err = cfg.Autobind(schema)
+ if err != nil {
+ return err
+ }
+
cfg.InjectBuiltins(schema)
binder, err := cfg.NewBinder(schema)
diff --git a/vendor/github.com/99designs/gqlgen/plugin/resolvergen/resolver.go b/vendor/github.com/99designs/gqlgen/plugin/resolvergen/resolver.go
index 00a6d5c9..6785c77c 100644
--- a/vendor/github.com/99designs/gqlgen/plugin/resolvergen/resolver.go
+++ b/vendor/github.com/99designs/gqlgen/plugin/resolvergen/resolver.go
@@ -19,6 +19,7 @@ type Plugin struct{}
var _ plugin.CodeGenerator = &Plugin{}
func (m *Plugin) Name() string {
+ // TODO: typo, should be resolvergen
return "resovlergen"
}
func (m *Plugin) GenerateCode(data *codegen.Data) error {
diff --git a/vendor/github.com/99designs/gqlgen/plugin/resolvergen/resolver.gotpl b/vendor/github.com/99designs/gqlgen/plugin/resolvergen/resolver.gotpl
index 7d95e690..66d6efac 100644
--- a/vendor/github.com/99designs/gqlgen/plugin/resolvergen/resolver.gotpl
+++ b/vendor/github.com/99designs/gqlgen/plugin/resolvergen/resolver.gotpl
@@ -20,18 +20,18 @@ type {{.ResolverType}} struct {}
{{ range $object := .Objects -}}
{{- if $object.HasResolvers -}}
func (r *{{$.ResolverType}}) {{$object.Name}}() {{ $object.ResolverInterface | ref }} {
- return &{{lcFirst $object.Name}}Resolver{r}
+ return &{{lcFirst $object.Name}}{{ucFirst $.ResolverType}}{r}
}
{{ end -}}
{{ end }}
{{ range $object := .Objects -}}
{{- if $object.HasResolvers -}}
- type {{lcFirst $object.Name}}Resolver struct { *Resolver }
+ type {{lcFirst $object.Name}}{{ucFirst $.ResolverType}} struct { *{{$.ResolverType}} }
{{ range $field := $object.Fields -}}
{{- if $field.IsResolver -}}
- func (r *{{lcFirst $object.Name}}Resolver) {{$field.GoFieldName}}{{ $field.ShortResolverDeclaration }} {
+ func (r *{{lcFirst $object.Name}}{{ucFirst $.ResolverType}}) {{$field.GoFieldName}}{{ $field.ShortResolverDeclaration }} {
panic("not implemented")
}
{{ end -}}
diff --git a/vendor/github.com/99designs/gqlgen/plugin/schemaconfig/schemaconfig.go b/vendor/github.com/99designs/gqlgen/plugin/schemaconfig/schemaconfig.go
new file mode 100644
index 00000000..1fcf4105
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/plugin/schemaconfig/schemaconfig.go
@@ -0,0 +1,93 @@
+package schemaconfig
+
+import (
+ "github.com/99designs/gqlgen/codegen/config"
+ "github.com/99designs/gqlgen/plugin"
+ "github.com/vektah/gqlparser/ast"
+)
+
+func New() plugin.Plugin {
+ return &Plugin{}
+}
+
+type Plugin struct{}
+
+var _ plugin.ConfigMutator = &Plugin{}
+
+func (m *Plugin) Name() string {
+ return "schemaconfig"
+}
+
+func (m *Plugin) MutateConfig(cfg *config.Config) error {
+ if err := cfg.Check(); err != nil {
+ return err
+ }
+
+ schema, _, err := cfg.LoadSchema()
+ if err != nil {
+ return err
+ }
+
+ cfg.Directives["goModel"] = config.DirectiveConfig{
+ SkipRuntime: true,
+ }
+
+ cfg.Directives["goField"] = config.DirectiveConfig{
+ SkipRuntime: true,
+ }
+
+ for _, schemaType := range schema.Types {
+ if schemaType == schema.Query || schemaType == schema.Mutation || schemaType == schema.Subscription {
+ continue
+ }
+
+ if bd := schemaType.Directives.ForName("goModel"); bd != nil {
+ if ma := bd.Arguments.ForName("model"); ma != nil {
+ if mv, err := ma.Value.Value(nil); err == nil {
+ cfg.Models.Add(schemaType.Name, mv.(string))
+ }
+ }
+ if ma := bd.Arguments.ForName("models"); ma != nil {
+ if mvs, err := ma.Value.Value(nil); err == nil {
+ for _, mv := range mvs.([]interface{}) {
+ cfg.Models.Add(schemaType.Name, mv.(string))
+ }
+ }
+ }
+ }
+
+ if schemaType.Kind == ast.Object || schemaType.Kind == ast.InputObject {
+ for _, field := range schemaType.Fields {
+ if fd := field.Directives.ForName("goField"); fd != nil {
+ forceResolver := cfg.Models[schemaType.Name].Fields[field.Name].Resolver
+ fieldName := cfg.Models[schemaType.Name].Fields[field.Name].FieldName
+
+ if ra := fd.Arguments.ForName("forceResolver"); ra != nil {
+ if fr, err := ra.Value.Value(nil); err == nil {
+ forceResolver = fr.(bool)
+ }
+ }
+
+ if na := fd.Arguments.ForName("name"); na != nil {
+ if fr, err := na.Value.Value(nil); err == nil {
+ fieldName = fr.(string)
+ }
+ }
+
+ if cfg.Models[schemaType.Name].Fields == nil {
+ cfg.Models[schemaType.Name] = config.TypeMapEntry{
+ Model: cfg.Models[schemaType.Name].Model,
+ Fields: map[string]config.TypeMapField{},
+ }
+ }
+
+ cfg.Models[schemaType.Name].Fields[field.Name] = config.TypeMapField{
+ FieldName: fieldName,
+ Resolver: forceResolver,
+ }
+ }
+ }
+ }
+ }
+ return nil
+}
diff --git a/vendor/github.com/blang/semver/.travis.yml b/vendor/github.com/blang/semver/.travis.yml
new file mode 100644
index 00000000..7319bdea
--- /dev/null
+++ b/vendor/github.com/blang/semver/.travis.yml
@@ -0,0 +1,25 @@
+language: go
+matrix:
+ include:
+ - go: 1.4.x
+ - go: 1.5.x
+ - go: 1.6.x
+ - go: 1.7.x
+ - go: 1.8.x
+ - go: 1.9.x
+ - go: 1.10.x
+ - go: 1.11.x
+ - go: tip
+ allow_failures:
+ - go: tip
+install:
+- go get golang.org/x/tools/cmd/cover
+- go get github.com/mattn/goveralls
+script:
+- echo "Test and track coverage" ; $HOME/gopath/bin/goveralls -package "." -service=travis-ci
+ -repotoken=$COVERALLS_TOKEN
+- echo "Build examples" ; cd examples && go build
+- echo "Check if gofmt'd" ; diff -u <(echo -n) <(gofmt -d -s .)
+env:
+ global:
+ secure: HroGEAUQpVq9zX1b1VIkraLiywhGbzvNnTZq2TMxgK7JHP8xqNplAeF1izrR2i4QLL9nsY+9WtYss4QuPvEtZcVHUobw6XnL6radF7jS1LgfYZ9Y7oF+zogZ2I5QUMRLGA7rcxQ05s7mKq3XZQfeqaNts4bms/eZRefWuaFZbkw=
diff --git a/vendor/github.com/blang/semver/LICENSE b/vendor/github.com/blang/semver/LICENSE
new file mode 100644
index 00000000..5ba5c86f
--- /dev/null
+++ b/vendor/github.com/blang/semver/LICENSE
@@ -0,0 +1,22 @@
+The MIT License
+
+Copyright (c) 2014 Benedikt Lang <github at benediktlang.de>
+
+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.
+
diff --git a/vendor/github.com/blang/semver/README.md b/vendor/github.com/blang/semver/README.md
new file mode 100644
index 00000000..e05f9865
--- /dev/null
+++ b/vendor/github.com/blang/semver/README.md
@@ -0,0 +1,194 @@
+semver for golang [![Build Status](https://travis-ci.org/blang/semver.svg?branch=master)](https://travis-ci.org/blang/semver) [![GoDoc](https://godoc.org/github.com/blang/semver?status.svg)](https://godoc.org/github.com/blang/semver) [![Coverage Status](https://img.shields.io/coveralls/blang/semver.svg)](https://coveralls.io/r/blang/semver?branch=master) [![Go Report Card](https://goreportcard.com/badge/github.com/blang/semver)](https://goreportcard.com/report/github.com/blang/semver)
+======
+
+semver is a [Semantic Versioning](http://semver.org/) library written in golang. It fully covers spec version `2.0.0`.
+
+Usage
+-----
+```bash
+$ go get github.com/blang/semver
+```
+Note: Always vendor your dependencies or fix on a specific version tag.
+
+```go
+import github.com/blang/semver
+v1, err := semver.Make("1.0.0-beta")
+v2, err := semver.Make("2.0.0-beta")
+v1.Compare(v2)
+```
+
+Also check the [GoDocs](http://godoc.org/github.com/blang/semver).
+
+Why should I use this lib?
+-----
+
+- Fully spec compatible
+- No reflection
+- No regex
+- Fully tested (Coverage >99%)
+- Readable parsing/validation errors
+- Fast (See [Benchmarks](#benchmarks))
+- Only Stdlib
+- Uses values instead of pointers
+- Many features, see below
+
+
+Features
+-----
+
+- Parsing and validation at all levels
+- Comparator-like comparisons
+- Compare Helper Methods
+- InPlace manipulation
+- Ranges `>=1.0.0 <2.0.0 || >=3.0.0 !3.0.1-beta.1`
+- Wildcards `>=1.x`, `<=2.5.x`
+- Sortable (implements sort.Interface)
+- database/sql compatible (sql.Scanner/Valuer)
+- encoding/json compatible (json.Marshaler/Unmarshaler)
+
+Ranges
+------
+
+A `Range` is a set of conditions which specify which versions satisfy the range.
+
+A condition is composed of an operator and a version. The supported operators are:
+
+- `<1.0.0` Less than `1.0.0`
+- `<=1.0.0` Less than or equal to `1.0.0`
+- `>1.0.0` Greater than `1.0.0`
+- `>=1.0.0` Greater than or equal to `1.0.0`
+- `1.0.0`, `=1.0.0`, `==1.0.0` Equal to `1.0.0`
+- `!1.0.0`, `!=1.0.0` Not equal to `1.0.0`. Excludes version `1.0.0`.
+
+Note that spaces between the operator and the version will be gracefully tolerated.
+
+A `Range` can link multiple `Ranges` separated by space:
+
+Ranges can be linked by logical AND:
+
+ - `>1.0.0 <2.0.0` would match between both ranges, so `1.1.1` and `1.8.7` but not `1.0.0` or `2.0.0`
+ - `>1.0.0 <3.0.0 !2.0.3-beta.2` would match every version between `1.0.0` and `3.0.0` except `2.0.3-beta.2`
+
+Ranges can also be linked by logical OR:
+
+ - `<2.0.0 || >=3.0.0` would match `1.x.x` and `3.x.x` but not `2.x.x`
+
+AND has a higher precedence than OR. It's not possible to use brackets.
+
+Ranges can be combined by both AND and OR
+
+ - `>1.0.0 <2.0.0 || >3.0.0 !4.2.1` would match `1.2.3`, `1.9.9`, `3.1.1`, but not `4.2.1`, `2.1.1`
+
+Range usage:
+
+```
+v, err := semver.Parse("1.2.3")
+expectedRange, err := semver.ParseRange(">1.0.0 <2.0.0 || >=3.0.0")
+if expectedRange(v) {
+ //valid
+}
+
+```
+
+Example
+-----
+
+Have a look at full examples in [examples/main.go](examples/main.go)
+
+```go
+import github.com/blang/semver
+
+v, err := semver.Make("0.0.1-alpha.preview+123.github")
+fmt.Printf("Major: %d\n", v.Major)
+fmt.Printf("Minor: %d\n", v.Minor)
+fmt.Printf("Patch: %d\n", v.Patch)
+fmt.Printf("Pre: %s\n", v.Pre)
+fmt.Printf("Build: %s\n", v.Build)
+
+// Prerelease versions array
+if len(v.Pre) > 0 {
+ fmt.Println("Prerelease versions:")
+ for i, pre := range v.Pre {
+ fmt.Printf("%d: %q\n", i, pre)
+ }
+}
+
+// Build meta data array
+if len(v.Build) > 0 {
+ fmt.Println("Build meta data:")
+ for i, build := range v.Build {
+ fmt.Printf("%d: %q\n", i, build)
+ }
+}
+
+v001, err := semver.Make("0.0.1")
+// Compare using helpers: v.GT(v2), v.LT, v.GTE, v.LTE
+v001.GT(v) == true
+v.LT(v001) == true
+v.GTE(v) == true
+v.LTE(v) == true
+
+// Or use v.Compare(v2) for comparisons (-1, 0, 1):
+v001.Compare(v) == 1
+v.Compare(v001) == -1
+v.Compare(v) == 0
+
+// Manipulate Version in place:
+v.Pre[0], err = semver.NewPRVersion("beta")
+if err != nil {
+ fmt.Printf("Error parsing pre release version: %q", err)
+}
+
+fmt.Println("\nValidate versions:")
+v.Build[0] = "?"
+
+err = v.Validate()
+if err != nil {
+ fmt.Printf("Validation failed: %s\n", err)
+}
+```
+
+
+Benchmarks
+-----
+
+ BenchmarkParseSimple-4 5000000 390 ns/op 48 B/op 1 allocs/op
+ BenchmarkParseComplex-4 1000000 1813 ns/op 256 B/op 7 allocs/op
+ BenchmarkParseAverage-4 1000000 1171 ns/op 163 B/op 4 allocs/op
+ BenchmarkStringSimple-4 20000000 119 ns/op 16 B/op 1 allocs/op
+ BenchmarkStringLarger-4 10000000 206 ns/op 32 B/op 2 allocs/op
+ BenchmarkStringComplex-4 5000000 324 ns/op 80 B/op 3 allocs/op
+ BenchmarkStringAverage-4 5000000 273 ns/op 53 B/op 2 allocs/op
+ BenchmarkValidateSimple-4 200000000 9.33 ns/op 0 B/op 0 allocs/op
+ BenchmarkValidateComplex-4 3000000 469 ns/op 0 B/op 0 allocs/op
+ BenchmarkValidateAverage-4 5000000 256 ns/op 0 B/op 0 allocs/op
+ BenchmarkCompareSimple-4 100000000 11.8 ns/op 0 B/op 0 allocs/op
+ BenchmarkCompareComplex-4 50000000 30.8 ns/op 0 B/op 0 allocs/op
+ BenchmarkCompareAverage-4 30000000 41.5 ns/op 0 B/op 0 allocs/op
+ BenchmarkSort-4 3000000 419 ns/op 256 B/op 2 allocs/op
+ BenchmarkRangeParseSimple-4 2000000 850 ns/op 192 B/op 5 allocs/op
+ BenchmarkRangeParseAverage-4 1000000 1677 ns/op 400 B/op 10 allocs/op
+ BenchmarkRangeParseComplex-4 300000 5214 ns/op 1440 B/op 30 allocs/op
+ BenchmarkRangeMatchSimple-4 50000000 25.6 ns/op 0 B/op 0 allocs/op
+ BenchmarkRangeMatchAverage-4 30000000 56.4 ns/op 0 B/op 0 allocs/op
+ BenchmarkRangeMatchComplex-4 10000000 153 ns/op 0 B/op 0 allocs/op
+
+See benchmark cases at [semver_test.go](semver_test.go)
+
+
+Motivation
+-----
+
+I simply couldn't find any lib supporting the full spec. Others were just wrong or used reflection and regex which i don't like.
+
+
+Contribution
+-----
+
+Feel free to make a pull request. For bigger changes create a issue first to discuss about it.
+
+
+License
+-----
+
+See [LICENSE](LICENSE) file.
diff --git a/vendor/github.com/blang/semver/go.mod b/vendor/github.com/blang/semver/go.mod
new file mode 100644
index 00000000..d0083058
--- /dev/null
+++ b/vendor/github.com/blang/semver/go.mod
@@ -0,0 +1 @@
+module github.com/blang/semver
diff --git a/vendor/github.com/blang/semver/json.go b/vendor/github.com/blang/semver/json.go
new file mode 100644
index 00000000..a74bf7c4
--- /dev/null
+++ b/vendor/github.com/blang/semver/json.go
@@ -0,0 +1,23 @@
+package semver
+
+import (
+ "encoding/json"
+)
+
+// MarshalJSON implements the encoding/json.Marshaler interface.
+func (v Version) MarshalJSON() ([]byte, error) {
+ return json.Marshal(v.String())
+}
+
+// UnmarshalJSON implements the encoding/json.Unmarshaler interface.
+func (v *Version) UnmarshalJSON(data []byte) (err error) {
+ var versionString string
+
+ if err = json.Unmarshal(data, &versionString); err != nil {
+ return
+ }
+
+ *v, err = Parse(versionString)
+
+ return
+}
diff --git a/vendor/github.com/blang/semver/package.json b/vendor/github.com/blang/semver/package.json
new file mode 100644
index 00000000..1cf8ebdd
--- /dev/null
+++ b/vendor/github.com/blang/semver/package.json
@@ -0,0 +1,17 @@
+{
+ "author": "blang",
+ "bugs": {
+ "URL": "https://github.com/blang/semver/issues",
+ "url": "https://github.com/blang/semver/issues"
+ },
+ "gx": {
+ "dvcsimport": "github.com/blang/semver"
+ },
+ "gxVersion": "0.10.0",
+ "language": "go",
+ "license": "MIT",
+ "name": "semver",
+ "releaseCmd": "git commit -a -m \"gx publish $VERSION\"",
+ "version": "3.5.1"
+}
+
diff --git a/vendor/github.com/blang/semver/range.go b/vendor/github.com/blang/semver/range.go
new file mode 100644
index 00000000..95f7139b
--- /dev/null
+++ b/vendor/github.com/blang/semver/range.go
@@ -0,0 +1,416 @@
+package semver
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+ "unicode"
+)
+
+type wildcardType int
+
+const (
+ noneWildcard wildcardType = iota
+ majorWildcard wildcardType = 1
+ minorWildcard wildcardType = 2
+ patchWildcard wildcardType = 3
+)
+
+func wildcardTypefromInt(i int) wildcardType {
+ switch i {
+ case 1:
+ return majorWildcard
+ case 2:
+ return minorWildcard
+ case 3:
+ return patchWildcard
+ default:
+ return noneWildcard
+ }
+}
+
+type comparator func(Version, Version) bool
+
+var (
+ compEQ comparator = func(v1 Version, v2 Version) bool {
+ return v1.Compare(v2) == 0
+ }
+ compNE = func(v1 Version, v2 Version) bool {
+ return v1.Compare(v2) != 0
+ }
+ compGT = func(v1 Version, v2 Version) bool {
+ return v1.Compare(v2) == 1
+ }
+ compGE = func(v1 Version, v2 Version) bool {
+ return v1.Compare(v2) >= 0
+ }
+ compLT = func(v1 Version, v2 Version) bool {
+ return v1.Compare(v2) == -1
+ }
+ compLE = func(v1 Version, v2 Version) bool {
+ return v1.Compare(v2) <= 0
+ }
+)
+
+type versionRange struct {
+ v Version
+ c comparator
+}
+
+// rangeFunc creates a Range from the given versionRange.
+func (vr *versionRange) rangeFunc() Range {
+ return Range(func(v Version) bool {
+ return vr.c(v, vr.v)
+ })
+}
+
+// Range represents a range of versions.
+// A Range can be used to check if a Version satisfies it:
+//
+// range, err := semver.ParseRange(">1.0.0 <2.0.0")
+// range(semver.MustParse("1.1.1") // returns true
+type Range func(Version) bool
+
+// OR combines the existing Range with another Range using logical OR.
+func (rf Range) OR(f Range) Range {
+ return Range(func(v Version) bool {
+ return rf(v) || f(v)
+ })
+}
+
+// AND combines the existing Range with another Range using logical AND.
+func (rf Range) AND(f Range) Range {
+ return Range(func(v Version) bool {
+ return rf(v) && f(v)
+ })
+}
+
+// ParseRange parses a range and returns a Range.
+// If the range could not be parsed an error is returned.
+//
+// Valid ranges are:
+// - "<1.0.0"
+// - "<=1.0.0"
+// - ">1.0.0"
+// - ">=1.0.0"
+// - "1.0.0", "=1.0.0", "==1.0.0"
+// - "!1.0.0", "!=1.0.0"
+//
+// A Range can consist of multiple ranges separated by space:
+// Ranges can be linked by logical AND:
+// - ">1.0.0 <2.0.0" would match between both ranges, so "1.1.1" and "1.8.7" but not "1.0.0" or "2.0.0"
+// - ">1.0.0 <3.0.0 !2.0.3-beta.2" would match every version between 1.0.0 and 3.0.0 except 2.0.3-beta.2
+//
+// Ranges can also be linked by logical OR:
+// - "<2.0.0 || >=3.0.0" would match "1.x.x" and "3.x.x" but not "2.x.x"
+//
+// AND has a higher precedence than OR. It's not possible to use brackets.
+//
+// Ranges can be combined by both AND and OR
+//
+// - `>1.0.0 <2.0.0 || >3.0.0 !4.2.1` would match `1.2.3`, `1.9.9`, `3.1.1`, but not `4.2.1`, `2.1.1`
+func ParseRange(s string) (Range, error) {
+ parts := splitAndTrim(s)
+ orParts, err := splitORParts(parts)
+ if err != nil {
+ return nil, err
+ }
+ expandedParts, err := expandWildcardVersion(orParts)
+ if err != nil {
+ return nil, err
+ }
+ var orFn Range
+ for _, p := range expandedParts {
+ var andFn Range
+ for _, ap := range p {
+ opStr, vStr, err := splitComparatorVersion(ap)
+ if err != nil {
+ return nil, err
+ }
+ vr, err := buildVersionRange(opStr, vStr)
+ if err != nil {
+ return nil, fmt.Errorf("Could not parse Range %q: %s", ap, err)
+ }
+ rf := vr.rangeFunc()
+
+ // Set function
+ if andFn == nil {
+ andFn = rf
+ } else { // Combine with existing function
+ andFn = andFn.AND(rf)
+ }
+ }
+ if orFn == nil {
+ orFn = andFn
+ } else {
+ orFn = orFn.OR(andFn)
+ }
+
+ }
+ return orFn, nil
+}
+
+// splitORParts splits the already cleaned parts by '||'.
+// Checks for invalid positions of the operator and returns an
+// error if found.
+func splitORParts(parts []string) ([][]string, error) {
+ var ORparts [][]string
+ last := 0
+ for i, p := range parts {
+ if p == "||" {
+ if i == 0 {
+ return nil, fmt.Errorf("First element in range is '||'")
+ }
+ ORparts = append(ORparts, parts[last:i])
+ last = i + 1
+ }
+ }
+ if last == len(parts) {
+ return nil, fmt.Errorf("Last element in range is '||'")
+ }
+ ORparts = append(ORparts, parts[last:])
+ return ORparts, nil
+}
+
+// buildVersionRange takes a slice of 2: operator and version
+// and builds a versionRange, otherwise an error.
+func buildVersionRange(opStr, vStr string) (*versionRange, error) {
+ c := parseComparator(opStr)
+ if c == nil {
+ return nil, fmt.Errorf("Could not parse comparator %q in %q", opStr, strings.Join([]string{opStr, vStr}, ""))
+ }
+ v, err := Parse(vStr)
+ if err != nil {
+ return nil, fmt.Errorf("Could not parse version %q in %q: %s", vStr, strings.Join([]string{opStr, vStr}, ""), err)
+ }
+
+ return &versionRange{
+ v: v,
+ c: c,
+ }, nil
+
+}
+
+// inArray checks if a byte is contained in an array of bytes
+func inArray(s byte, list []byte) bool {
+ for _, el := range list {
+ if el == s {
+ return true
+ }
+ }
+ return false
+}
+
+// splitAndTrim splits a range string by spaces and cleans whitespaces
+func splitAndTrim(s string) (result []string) {
+ last := 0
+ var lastChar byte
+ excludeFromSplit := []byte{'>', '<', '='}
+ for i := 0; i < len(s); i++ {
+ if s[i] == ' ' && !inArray(lastChar, excludeFromSplit) {
+ if last < i-1 {
+ result = append(result, s[last:i])
+ }
+ last = i + 1
+ } else if s[i] != ' ' {
+ lastChar = s[i]
+ }
+ }
+ if last < len(s)-1 {
+ result = append(result, s[last:])
+ }
+
+ for i, v := range result {
+ result[i] = strings.Replace(v, " ", "", -1)
+ }
+
+ // parts := strings.Split(s, " ")
+ // for _, x := range parts {
+ // if s := strings.TrimSpace(x); len(s) != 0 {
+ // result = append(result, s)
+ // }
+ // }
+ return
+}
+
+// splitComparatorVersion splits the comparator from the version.
+// Input must be free of leading or trailing spaces.
+func splitComparatorVersion(s string) (string, string, error) {
+ i := strings.IndexFunc(s, unicode.IsDigit)
+ if i == -1 {
+ return "", "", fmt.Errorf("Could not get version from string: %q", s)
+ }
+ return strings.TrimSpace(s[0:i]), s[i:], nil
+}
+
+// getWildcardType will return the type of wildcard that the
+// passed version contains
+func getWildcardType(vStr string) wildcardType {
+ parts := strings.Split(vStr, ".")
+ nparts := len(parts)
+ wildcard := parts[nparts-1]
+
+ possibleWildcardType := wildcardTypefromInt(nparts)
+ if wildcard == "x" {
+ return possibleWildcardType
+ }
+
+ return noneWildcard
+}
+
+// createVersionFromWildcard will convert a wildcard version
+// into a regular version, replacing 'x's with '0's, handling
+// special cases like '1.x.x' and '1.x'
+func createVersionFromWildcard(vStr string) string {
+ // handle 1.x.x
+ vStr2 := strings.Replace(vStr, ".x.x", ".x", 1)
+ vStr2 = strings.Replace(vStr2, ".x", ".0", 1)
+ parts := strings.Split(vStr2, ".")
+
+ // handle 1.x
+ if len(parts) == 2 {
+ return vStr2 + ".0"
+ }
+
+ return vStr2
+}
+
+// incrementMajorVersion will increment the major version
+// of the passed version
+func incrementMajorVersion(vStr string) (string, error) {
+ parts := strings.Split(vStr, ".")
+ i, err := strconv.Atoi(parts[0])
+ if err != nil {
+ return "", err
+ }
+ parts[0] = strconv.Itoa(i + 1)
+
+ return strings.Join(parts, "."), nil
+}
+
+// incrementMajorVersion will increment the minor version
+// of the passed version
+func incrementMinorVersion(vStr string) (string, error) {
+ parts := strings.Split(vStr, ".")
+ i, err := strconv.Atoi(parts[1])
+ if err != nil {
+ return "", err
+ }
+ parts[1] = strconv.Itoa(i + 1)
+
+ return strings.Join(parts, "."), nil
+}
+
+// expandWildcardVersion will expand wildcards inside versions
+// following these rules:
+//
+// * when dealing with patch wildcards:
+// >= 1.2.x will become >= 1.2.0
+// <= 1.2.x will become < 1.3.0
+// > 1.2.x will become >= 1.3.0
+// < 1.2.x will become < 1.2.0
+// != 1.2.x will become < 1.2.0 >= 1.3.0
+//
+// * when dealing with minor wildcards:
+// >= 1.x will become >= 1.0.0
+// <= 1.x will become < 2.0.0
+// > 1.x will become >= 2.0.0
+// < 1.0 will become < 1.0.0
+// != 1.x will become < 1.0.0 >= 2.0.0
+//
+// * when dealing with wildcards without
+// version operator:
+// 1.2.x will become >= 1.2.0 < 1.3.0
+// 1.x will become >= 1.0.0 < 2.0.0
+func expandWildcardVersion(parts [][]string) ([][]string, error) {
+ var expandedParts [][]string
+ for _, p := range parts {
+ var newParts []string
+ for _, ap := range p {
+ if strings.Contains(ap, "x") {
+ opStr, vStr, err := splitComparatorVersion(ap)
+ if err != nil {
+ return nil, err
+ }
+
+ versionWildcardType := getWildcardType(vStr)
+ flatVersion := createVersionFromWildcard(vStr)
+
+ var resultOperator string
+ var shouldIncrementVersion bool
+ switch opStr {
+ case ">":
+ resultOperator = ">="
+ shouldIncrementVersion = true
+ case ">=":
+ resultOperator = ">="
+ case "<":
+ resultOperator = "<"
+ case "<=":
+ resultOperator = "<"
+ shouldIncrementVersion = true
+ case "", "=", "==":
+ newParts = append(newParts, ">="+flatVersion)
+ resultOperator = "<"
+ shouldIncrementVersion = true
+ case "!=", "!":
+ newParts = append(newParts, "<"+flatVersion)
+ resultOperator = ">="
+ shouldIncrementVersion = true
+ }
+
+ var resultVersion string
+ if shouldIncrementVersion {
+ switch versionWildcardType {
+ case patchWildcard:
+ resultVersion, _ = incrementMinorVersion(flatVersion)
+ case minorWildcard:
+ resultVersion, _ = incrementMajorVersion(flatVersion)
+ }
+ } else {
+ resultVersion = flatVersion
+ }
+
+ ap = resultOperator + resultVersion
+ }
+ newParts = append(newParts, ap)
+ }
+ expandedParts = append(expandedParts, newParts)
+ }
+
+ return expandedParts, nil
+}
+
+func parseComparator(s string) comparator {
+ switch s {
+ case "==":
+ fallthrough
+ case "":
+ fallthrough
+ case "=":
+ return compEQ
+ case ">":
+ return compGT
+ case ">=":
+ return compGE
+ case "<":
+ return compLT
+ case "<=":
+ return compLE
+ case "!":
+ fallthrough
+ case "!=":
+ return compNE
+ }
+
+ return nil
+}
+
+// MustParseRange is like ParseRange but panics if the range cannot be parsed.
+func MustParseRange(s string) Range {
+ r, err := ParseRange(s)
+ if err != nil {
+ panic(`semver: ParseRange(` + s + `): ` + err.Error())
+ }
+ return r
+}
diff --git a/vendor/github.com/blang/semver/semver.go b/vendor/github.com/blang/semver/semver.go
new file mode 100644
index 00000000..4165bc79
--- /dev/null
+++ b/vendor/github.com/blang/semver/semver.go
@@ -0,0 +1,455 @@
+package semver
+
+import (
+ "errors"
+ "fmt"
+ "strconv"
+ "strings"
+)
+
+const (
+ numbers string = "0123456789"
+ alphas = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-"
+ alphanum = alphas + numbers
+)
+
+// SpecVersion is the latest fully supported spec version of semver
+var SpecVersion = Version{
+ Major: 2,
+ Minor: 0,
+ Patch: 0,
+}
+
+// Version represents a semver compatible version
+type Version struct {
+ Major uint64
+ Minor uint64
+ Patch uint64
+ Pre []PRVersion
+ Build []string //No Precedence
+}
+
+// Version to string
+func (v Version) String() string {
+ b := make([]byte, 0, 5)
+ b = strconv.AppendUint(b, v.Major, 10)
+ b = append(b, '.')
+ b = strconv.AppendUint(b, v.Minor, 10)
+ b = append(b, '.')
+ b = strconv.AppendUint(b, v.Patch, 10)
+
+ if len(v.Pre) > 0 {
+ b = append(b, '-')
+ b = append(b, v.Pre[0].String()...)
+
+ for _, pre := range v.Pre[1:] {
+ b = append(b, '.')
+ b = append(b, pre.String()...)
+ }
+ }
+
+ if len(v.Build) > 0 {
+ b = append(b, '+')
+ b = append(b, v.Build[0]...)
+
+ for _, build := range v.Build[1:] {
+ b = append(b, '.')
+ b = append(b, build...)
+ }
+ }
+
+ return string(b)
+}
+
+// Equals checks if v is equal to o.
+func (v Version) Equals(o Version) bool {
+ return (v.Compare(o) == 0)
+}
+
+// EQ checks if v is equal to o.
+func (v Version) EQ(o Version) bool {
+ return (v.Compare(o) == 0)
+}
+
+// NE checks if v is not equal to o.
+func (v Version) NE(o Version) bool {
+ return (v.Compare(o) != 0)
+}
+
+// GT checks if v is greater than o.
+func (v Version) GT(o Version) bool {
+ return (v.Compare(o) == 1)
+}
+
+// GTE checks if v is greater than or equal to o.
+func (v Version) GTE(o Version) bool {
+ return (v.Compare(o) >= 0)
+}
+
+// GE checks if v is greater than or equal to o.
+func (v Version) GE(o Version) bool {
+ return (v.Compare(o) >= 0)
+}
+
+// LT checks if v is less than o.
+func (v Version) LT(o Version) bool {
+ return (v.Compare(o) == -1)
+}
+
+// LTE checks if v is less than or equal to o.
+func (v Version) LTE(o Version) bool {
+ return (v.Compare(o) <= 0)
+}
+
+// LE checks if v is less than or equal to o.
+func (v Version) LE(o Version) bool {
+ return (v.Compare(o) <= 0)
+}
+
+// Compare compares Versions v to o:
+// -1 == v is less than o
+// 0 == v is equal to o
+// 1 == v is greater than o
+func (v Version) Compare(o Version) int {
+ if v.Major != o.Major {
+ if v.Major > o.Major {
+ return 1
+ }
+ return -1
+ }
+ if v.Minor != o.Minor {
+ if v.Minor > o.Minor {
+ return 1
+ }
+ return -1
+ }
+ if v.Patch != o.Patch {
+ if v.Patch > o.Patch {
+ return 1
+ }
+ return -1
+ }
+
+ // Quick comparison if a version has no prerelease versions
+ if len(v.Pre) == 0 && len(o.Pre) == 0 {
+ return 0
+ } else if len(v.Pre) == 0 && len(o.Pre) > 0 {
+ return 1
+ } else if len(v.Pre) > 0 && len(o.Pre) == 0 {
+ return -1
+ }
+
+ i := 0
+ for ; i < len(v.Pre) && i < len(o.Pre); i++ {
+ if comp := v.Pre[i].Compare(o.Pre[i]); comp == 0 {
+ continue
+ } else if comp == 1 {
+ return 1
+ } else {
+ return -1
+ }
+ }
+
+ // If all pr versions are the equal but one has further prversion, this one greater
+ if i == len(v.Pre) && i == len(o.Pre) {
+ return 0
+ } else if i == len(v.Pre) && i < len(o.Pre) {
+ return -1
+ } else {
+ return 1
+ }
+
+}
+
+// IncrementPatch increments the patch version
+func (v *Version) IncrementPatch() error {
+ if v.Major == 0 {
+ return fmt.Errorf("Patch version can not be incremented for %q", v.String())
+ }
+ v.Patch += 1
+ return nil
+}
+
+// IncrementMinor increments the minor version
+func (v *Version) IncrementMinor() error {
+ if v.Major == 0 {
+ return fmt.Errorf("Minor version can not be incremented for %q", v.String())
+ }
+ v.Minor += 1
+ v.Patch = 0
+ return nil
+}
+
+// IncrementMajor increments the major version
+func (v *Version) IncrementMajor() error {
+ if v.Major == 0 {
+ return fmt.Errorf("Major version can not be incremented for %q", v.String())
+ }
+ v.Major += 1
+ v.Minor = 0
+ v.Patch = 0
+ return nil
+}
+
+// Validate validates v and returns error in case
+func (v Version) Validate() error {
+ // Major, Minor, Patch already validated using uint64
+
+ for _, pre := range v.Pre {
+ if !pre.IsNum { //Numeric prerelease versions already uint64
+ if len(pre.VersionStr) == 0 {
+ return fmt.Errorf("Prerelease can not be empty %q", pre.VersionStr)
+ }
+ if !containsOnly(pre.VersionStr, alphanum) {
+ return fmt.Errorf("Invalid character(s) found in prerelease %q", pre.VersionStr)
+ }
+ }
+ }
+
+ for _, build := range v.Build {
+ if len(build) == 0 {
+ return fmt.Errorf("Build meta data can not be empty %q", build)
+ }
+ if !containsOnly(build, alphanum) {
+ return fmt.Errorf("Invalid character(s) found in build meta data %q", build)
+ }
+ }
+
+ return nil
+}
+
+// New is an alias for Parse and returns a pointer, parses version string and returns a validated Version or error
+func New(s string) (vp *Version, err error) {
+ v, err := Parse(s)
+ vp = &v
+ return
+}
+
+// Make is an alias for Parse, parses version string and returns a validated Version or error
+func Make(s string) (Version, error) {
+ return Parse(s)
+}
+
+// ParseTolerant allows for certain version specifications that do not strictly adhere to semver
+// specs to be parsed by this library. It does so by normalizing versions before passing them to
+// Parse(). It currently trims spaces, removes a "v" prefix, adds a 0 patch number to versions
+// with only major and minor components specified, and removes leading 0s.
+func ParseTolerant(s string) (Version, error) {
+ s = strings.TrimSpace(s)
+ s = strings.TrimPrefix(s, "v")
+
+ // Split into major.minor.(patch+pr+meta)
+ parts := strings.SplitN(s, ".", 3)
+ // Remove leading zeros.
+ for i, p := range parts {
+ if len(p) > 1 {
+ parts[i] = strings.TrimPrefix(p, "0")
+ }
+ }
+ // Fill up shortened versions.
+ if len(parts) < 3 {
+ if strings.ContainsAny(parts[len(parts)-1], "+-") {
+ return Version{}, errors.New("Short version cannot contain PreRelease/Build meta data")
+ }
+ for len(parts) < 3 {
+ parts = append(parts, "0")
+ }
+ }
+ s = strings.Join(parts, ".")
+
+ return Parse(s)
+}
+
+// Parse parses version string and returns a validated Version or error
+func Parse(s string) (Version, error) {
+ if len(s) == 0 {
+ return Version{}, errors.New("Version string empty")
+ }
+
+ // Split into major.minor.(patch+pr+meta)
+ parts := strings.SplitN(s, ".", 3)
+ if len(parts) != 3 {
+ return Version{}, errors.New("No Major.Minor.Patch elements found")
+ }
+
+ // Major
+ if !containsOnly(parts[0], numbers) {
+ return Version{}, fmt.Errorf("Invalid character(s) found in major number %q", parts[0])
+ }
+ if hasLeadingZeroes(parts[0]) {
+ return Version{}, fmt.Errorf("Major number must not contain leading zeroes %q", parts[0])
+ }
+ major, err := strconv.ParseUint(parts[0], 10, 64)
+ if err != nil {
+ return Version{}, err
+ }
+
+ // Minor
+ if !containsOnly(parts[1], numbers) {
+ return Version{}, fmt.Errorf("Invalid character(s) found in minor number %q", parts[1])
+ }
+ if hasLeadingZeroes(parts[1]) {
+ return Version{}, fmt.Errorf("Minor number must not contain leading zeroes %q", parts[1])
+ }
+ minor, err := strconv.ParseUint(parts[1], 10, 64)
+ if err != nil {
+ return Version{}, err
+ }
+
+ v := Version{}
+ v.Major = major
+ v.Minor = minor
+
+ var build, prerelease []string
+ patchStr := parts[2]
+
+ if buildIndex := strings.IndexRune(patchStr, '+'); buildIndex != -1 {
+ build = strings.Split(patchStr[buildIndex+1:], ".")
+ patchStr = patchStr[:buildIndex]
+ }
+
+ if preIndex := strings.IndexRune(patchStr, '-'); preIndex != -1 {
+ prerelease = strings.Split(patchStr[preIndex+1:], ".")
+ patchStr = patchStr[:preIndex]
+ }
+
+ if !containsOnly(patchStr, numbers) {
+ return Version{}, fmt.Errorf("Invalid character(s) found in patch number %q", patchStr)
+ }
+ if hasLeadingZeroes(patchStr) {
+ return Version{}, fmt.Errorf("Patch number must not contain leading zeroes %q", patchStr)
+ }
+ patch, err := strconv.ParseUint(patchStr, 10, 64)
+ if err != nil {
+ return Version{}, err
+ }
+
+ v.Patch = patch
+
+ // Prerelease
+ for _, prstr := range prerelease {
+ parsedPR, err := NewPRVersion(prstr)
+ if err != nil {
+ return Version{}, err
+ }
+ v.Pre = append(v.Pre, parsedPR)
+ }
+
+ // Build meta data
+ for _, str := range build {
+ if len(str) == 0 {
+ return Version{}, errors.New("Build meta data is empty")
+ }
+ if !containsOnly(str, alphanum) {
+ return Version{}, fmt.Errorf("Invalid character(s) found in build meta data %q", str)
+ }
+ v.Build = append(v.Build, str)
+ }
+
+ return v, nil
+}
+
+// MustParse is like Parse but panics if the version cannot be parsed.
+func MustParse(s string) Version {
+ v, err := Parse(s)
+ if err != nil {
+ panic(`semver: Parse(` + s + `): ` + err.Error())
+ }
+ return v
+}
+
+// PRVersion represents a PreRelease Version
+type PRVersion struct {
+ VersionStr string
+ VersionNum uint64
+ IsNum bool
+}
+
+// NewPRVersion creates a new valid prerelease version
+func NewPRVersion(s string) (PRVersion, error) {
+ if len(s) == 0 {
+ return PRVersion{}, errors.New("Prerelease is empty")
+ }
+ v := PRVersion{}
+ if containsOnly(s, numbers) {
+ if hasLeadingZeroes(s) {
+ return PRVersion{}, fmt.Errorf("Numeric PreRelease version must not contain leading zeroes %q", s)
+ }
+ num, err := strconv.ParseUint(s, 10, 64)
+
+ // Might never be hit, but just in case
+ if err != nil {
+ return PRVersion{}, err
+ }
+ v.VersionNum = num
+ v.IsNum = true
+ } else if containsOnly(s, alphanum) {
+ v.VersionStr = s
+ v.IsNum = false
+ } else {
+ return PRVersion{}, fmt.Errorf("Invalid character(s) found in prerelease %q", s)
+ }
+ return v, nil
+}
+
+// IsNumeric checks if prerelease-version is numeric
+func (v PRVersion) IsNumeric() bool {
+ return v.IsNum
+}
+
+// Compare compares two PreRelease Versions v and o:
+// -1 == v is less than o
+// 0 == v is equal to o
+// 1 == v is greater than o
+func (v PRVersion) Compare(o PRVersion) int {
+ if v.IsNum && !o.IsNum {
+ return -1
+ } else if !v.IsNum && o.IsNum {
+ return 1
+ } else if v.IsNum && o.IsNum {
+ if v.VersionNum == o.VersionNum {
+ return 0
+ } else if v.VersionNum > o.VersionNum {
+ return 1
+ } else {
+ return -1
+ }
+ } else { // both are Alphas
+ if v.VersionStr == o.VersionStr {
+ return 0
+ } else if v.VersionStr > o.VersionStr {
+ return 1
+ } else {
+ return -1
+ }
+ }
+}
+
+// PreRelease version to string
+func (v PRVersion) String() string {
+ if v.IsNum {
+ return strconv.FormatUint(v.VersionNum, 10)
+ }
+ return v.VersionStr
+}
+
+func containsOnly(s string, set string) bool {
+ return strings.IndexFunc(s, func(r rune) bool {
+ return !strings.ContainsRune(set, r)
+ }) == -1
+}
+
+func hasLeadingZeroes(s string) bool {
+ return len(s) > 1 && s[0] == '0'
+}
+
+// NewBuildVersion creates a new valid build version
+func NewBuildVersion(s string) (string, error) {
+ if len(s) == 0 {
+ return "", errors.New("Buildversion is empty")
+ }
+ if !containsOnly(s, alphanum) {
+ return "", fmt.Errorf("Invalid character(s) found in build meta data %q", s)
+ }
+ return s, nil
+}
diff --git a/vendor/github.com/blang/semver/sort.go b/vendor/github.com/blang/semver/sort.go
new file mode 100644
index 00000000..e18f8808
--- /dev/null
+++ b/vendor/github.com/blang/semver/sort.go
@@ -0,0 +1,28 @@
+package semver
+
+import (
+ "sort"
+)
+
+// Versions represents multiple versions.
+type Versions []Version
+
+// Len returns length of version collection
+func (s Versions) Len() int {
+ return len(s)
+}
+
+// Swap swaps two versions inside the collection by its indices
+func (s Versions) Swap(i, j int) {
+ s[i], s[j] = s[j], s[i]
+}
+
+// Less checks if version at index i is less than version at index j
+func (s Versions) Less(i, j int) bool {
+ return s[i].LT(s[j])
+}
+
+// Sort sorts a slice of versions
+func Sort(versions []Version) {
+ sort.Sort(Versions(versions))
+}
diff --git a/vendor/github.com/blang/semver/sql.go b/vendor/github.com/blang/semver/sql.go
new file mode 100644
index 00000000..db958134
--- /dev/null
+++ b/vendor/github.com/blang/semver/sql.go
@@ -0,0 +1,30 @@
+package semver
+
+import (
+ "database/sql/driver"
+ "fmt"
+)
+
+// Scan implements the database/sql.Scanner interface.
+func (v *Version) Scan(src interface{}) (err error) {
+ var str string
+ switch src := src.(type) {
+ case string:
+ str = src
+ case []byte:
+ str = string(src)
+ default:
+ return fmt.Errorf("version.Scan: cannot convert %T to string", src)
+ }
+
+ if t, err := Parse(str); err == nil {
+ *v = t
+ }
+
+ return
+}
+
+// Value implements the database/sql/driver.Valuer interface.
+func (v Version) Value() (driver.Value, error) {
+ return v.String(), nil
+}
diff --git a/vendor/github.com/gorilla/mux/.travis.yml b/vendor/github.com/gorilla/mux/.travis.yml
deleted file mode 100644
index d003ad92..00000000
--- a/vendor/github.com/gorilla/mux/.travis.yml
+++ /dev/null
@@ -1,24 +0,0 @@
-language: go
-
-
-matrix:
- include:
- - go: 1.7.x
- - go: 1.8.x
- - go: 1.9.x
- - go: 1.10.x
- - go: 1.11.x
- - go: 1.x
- env: LATEST=true
- - go: tip
- allow_failures:
- - go: tip
-
-install:
- - # Skip
-
-script:
- - go get -t -v ./...
- - diff -u <(echo -n) <(gofmt -d .)
- - if [[ "$LATEST" = true ]]; then go vet .; fi
- - go test -v -race ./...
diff --git a/vendor/github.com/gorilla/mux/ISSUE_TEMPLATE.md b/vendor/github.com/gorilla/mux/ISSUE_TEMPLATE.md
deleted file mode 100644
index 232be82e..00000000
--- a/vendor/github.com/gorilla/mux/ISSUE_TEMPLATE.md
+++ /dev/null
@@ -1,11 +0,0 @@
-**What version of Go are you running?** (Paste the output of `go version`)
-
-
-**What version of gorilla/mux are you at?** (Paste the output of `git rev-parse HEAD` inside `$GOPATH/src/github.com/gorilla/mux`)
-
-
-**Describe your problem** (and what you have tried so far)
-
-
-**Paste a minimal, runnable, reproduction of your issue below** (use backticks to format it)
-
diff --git a/vendor/github.com/gorilla/mux/README.md b/vendor/github.com/gorilla/mux/README.md
index c661599a..92e422ee 100644
--- a/vendor/github.com/gorilla/mux/README.md
+++ b/vendor/github.com/gorilla/mux/README.md
@@ -2,6 +2,7 @@
[![GoDoc](https://godoc.org/github.com/gorilla/mux?status.svg)](https://godoc.org/github.com/gorilla/mux)
[![Build Status](https://travis-ci.org/gorilla/mux.svg?branch=master)](https://travis-ci.org/gorilla/mux)
+[![CircleCI](https://circleci.com/gh/gorilla/mux.svg?style=svg)](https://circleci.com/gh/gorilla/mux)
[![Sourcegraph](https://sourcegraph.com/github.com/gorilla/mux/-/badge.svg)](https://sourcegraph.com/github.com/gorilla/mux?badge)
![Gorilla Logo](http://www.gorillatoolkit.org/static/images/gorilla-icon-64.png)
@@ -29,6 +30,7 @@ The name mux stands for "HTTP request multiplexer". Like the standard `http.Serv
* [Walking Routes](#walking-routes)
* [Graceful Shutdown](#graceful-shutdown)
* [Middleware](#middleware)
+* [Handling CORS Requests](#handling-cors-requests)
* [Testing Handlers](#testing-handlers)
* [Full Example](#full-example)
@@ -491,6 +493,73 @@ r.Use(amw.Middleware)
Note: The handler chain will be stopped if your middleware doesn't call `next.ServeHTTP()` with the corresponding parameters. This can be used to abort a request if the middleware writer wants to. Middlewares _should_ write to `ResponseWriter` if they _are_ going to terminate the request, and they _should not_ write to `ResponseWriter` if they _are not_ going to terminate it.
+### Handling CORS Requests
+
+[CORSMethodMiddleware](https://godoc.org/github.com/gorilla/mux#CORSMethodMiddleware) intends to make it easier to strictly set the `Access-Control-Allow-Methods` response header.
+
+* You will still need to use your own CORS handler to set the other CORS headers such as `Access-Control-Allow-Origin`
+* The middleware will set the `Access-Control-Allow-Methods` header to all the method matchers (e.g. `r.Methods(http.MethodGet, http.MethodPut, http.MethodOptions)` -> `Access-Control-Allow-Methods: GET,PUT,OPTIONS`) on a route
+* If you do not specify any methods, then:
+> _Important_: there must be an `OPTIONS` method matcher for the middleware to set the headers.
+
+Here is an example of using `CORSMethodMiddleware` along with a custom `OPTIONS` handler to set all the required CORS headers:
+
+```go
+package main
+
+import (
+ "net/http"
+ "github.com/gorilla/mux"
+)
+
+func main() {
+ r := mux.NewRouter()
+
+ // IMPORTANT: you must specify an OPTIONS method matcher for the middleware to set CORS headers
+ r.HandleFunc("/foo", fooHandler).Methods(http.MethodGet, http.MethodPut, http.MethodPatch, http.MethodOptions)
+ r.Use(mux.CORSMethodMiddleware(r))
+
+ http.ListenAndServe(":8080", r)
+}
+
+func fooHandler(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("Access-Control-Allow-Origin", "*")
+ if r.Method == http.MethodOptions {
+ return
+ }
+
+ w.Write([]byte("foo"))
+}
+```
+
+And an request to `/foo` using something like:
+
+```bash
+curl localhost:8080/foo -v
+```
+
+Would look like:
+
+```bash
+* Trying ::1...
+* TCP_NODELAY set
+* Connected to localhost (::1) port 8080 (#0)
+> GET /foo HTTP/1.1
+> Host: localhost:8080
+> User-Agent: curl/7.59.0
+> Accept: */*
+>
+< HTTP/1.1 200 OK
+< Access-Control-Allow-Methods: GET,PUT,PATCH,OPTIONS
+< Access-Control-Allow-Origin: *
+< Date: Fri, 28 Jun 2019 20:13:30 GMT
+< Content-Length: 3
+< Content-Type: text/plain; charset=utf-8
+<
+* Connection #0 to host localhost left intact
+foo
+```
+
### Testing Handlers
Testing handlers in a Go web application is straightforward, and _mux_ doesn't complicate this any further. Given two files: `endpoints.go` and `endpoints_test.go`, here's how we'd test an application using _mux_.
diff --git a/vendor/github.com/gorilla/mux/doc.go b/vendor/github.com/gorilla/mux/doc.go
index 38957dee..bd5a38b5 100644
--- a/vendor/github.com/gorilla/mux/doc.go
+++ b/vendor/github.com/gorilla/mux/doc.go
@@ -295,7 +295,7 @@ A more complex authentication middleware, which maps session token to users, cou
r := mux.NewRouter()
r.HandleFunc("/", handler)
- amw := authenticationMiddleware{}
+ amw := authenticationMiddleware{tokenUsers: make(map[string]string)}
amw.Populate()
r.Use(amw.Middleware)
diff --git a/vendor/github.com/gorilla/mux/middleware.go b/vendor/github.com/gorilla/mux/middleware.go
index ceb812ce..cf2b26dc 100644
--- a/vendor/github.com/gorilla/mux/middleware.go
+++ b/vendor/github.com/gorilla/mux/middleware.go
@@ -32,37 +32,19 @@ func (r *Router) useInterface(mw middleware) {
r.middlewares = append(r.middlewares, mw)
}
-// CORSMethodMiddleware sets the Access-Control-Allow-Methods response header
-// on a request, by matching routes based only on paths. It also handles
-// OPTIONS requests, by settings Access-Control-Allow-Methods, and then
-// returning without calling the next http handler.
+// CORSMethodMiddleware automatically sets the Access-Control-Allow-Methods response header
+// on requests for routes that have an OPTIONS method matcher to all the method matchers on
+// the route. Routes that do not explicitly handle OPTIONS requests will not be processed
+// by the middleware. See examples for usage.
func CORSMethodMiddleware(r *Router) MiddlewareFunc {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
- var allMethods []string
-
- err := r.Walk(func(route *Route, _ *Router, _ []*Route) error {
- for _, m := range route.matchers {
- if _, ok := m.(*routeRegexp); ok {
- if m.Match(req, &RouteMatch{}) {
- methods, err := route.GetMethods()
- if err != nil {
- return err
- }
-
- allMethods = append(allMethods, methods...)
- }
- break
- }
- }
- return nil
- })
-
+ allMethods, err := getAllMethodsForRoute(r, req)
if err == nil {
- w.Header().Set("Access-Control-Allow-Methods", strings.Join(append(allMethods, "OPTIONS"), ","))
-
- if req.Method == "OPTIONS" {
- return
+ for _, v := range allMethods {
+ if v == http.MethodOptions {
+ w.Header().Set("Access-Control-Allow-Methods", strings.Join(allMethods, ","))
+ }
}
}
@@ -70,3 +52,28 @@ func CORSMethodMiddleware(r *Router) MiddlewareFunc {
})
}
}
+
+// getAllMethodsForRoute returns all the methods from method matchers matching a given
+// request.
+func getAllMethodsForRoute(r *Router, req *http.Request) ([]string, error) {
+ var allMethods []string
+
+ err := r.Walk(func(route *Route, _ *Router, _ []*Route) error {
+ for _, m := range route.matchers {
+ if _, ok := m.(*routeRegexp); ok {
+ if m.Match(req, &RouteMatch{}) {
+ methods, err := route.GetMethods()
+ if err != nil {
+ return err
+ }
+
+ allMethods = append(allMethods, methods...)
+ }
+ break
+ }
+ }
+ return nil
+ })
+
+ return allMethods, err
+}