From 3bb4fe163c154e6349ed3a438eb137b0b9ace8f3 Mon Sep 17 00:00:00 2001 From: Djordje Lukic <djordje.lukic@docker.com> Date: Fri, 24 Apr 2020 18:04:32 +0200 Subject: [PATCH 1/8] Add `docker context create` command This creates a context with a name and a type --- Makefile | 5 +- cli/cmd/context.go | 83 ++++++++++++++++++ {cmd => cli/cmd}/example.go | 18 ++-- cli/main.go | 165 ++++++++++++++++++++++++++++++++++++ cmd/main.go | 131 ---------------------------- context/config.go | 31 ++++++- {cmd => context}/context.go | 16 +--- context/flags.go | 56 +++++++----- context/store.go | 65 -------------- context/store/store.go | 157 ++++++++++++++++++++++++++++++++++ context/store/store_test.go | 73 ++++++++++++++++ go.mod | 8 +- go.sum | 93 +++++++++++++++++++- util/util.go | 2 +- 14 files changed, 657 insertions(+), 246 deletions(-) create mode 100644 cli/cmd/context.go rename {cmd => cli/cmd}/example.go (89%) create mode 100644 cli/main.go delete mode 100644 cmd/main.go rename {cmd => context}/context.go (78%) delete mode 100644 context/store.go create mode 100644 context/store/store.go create mode 100644 context/store/store_test.go diff --git a/Makefile b/Makefile index d6451f291..4a693bc7a 100644 --- a/Makefile +++ b/Makefile @@ -40,7 +40,7 @@ protos: @protoc -I. --go_out=plugins=grpc,paths=source_relative:. ${PROTOS} cli: protos - cd cmd && GOOS=${GOOS} GOARCH=${GOARCH} go build -v -o ../bin/docker + cd cli && GOOS=${GOOS} GOARCH=${GOARCH} go build -v -o ../bin/docker example: protos cd example/backend && go build -v -o ../../bin/backend-example @@ -72,6 +72,9 @@ dxbins: dbins --output type=local,dest=./bin \ --target xbins +test: + gotestsum ./... + FORCE: .PHONY: all xall protos example xexample xcli cli bins dbins dxbins dprotos diff --git a/cli/cmd/context.go b/cli/cmd/context.go new file mode 100644 index 000000000..1d8547109 --- /dev/null +++ b/cli/cmd/context.go @@ -0,0 +1,83 @@ +/* + Copyright (c) 2020 Docker Inc. + + 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. +*/ + +package cmd + +import ( + "context" + + "github.com/docker/api/context/store" + "github.com/spf13/cobra" +) + +type CliContext struct { +} + +func ContextCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "context", + Short: "Manage contexts", + } + + cmd.AddCommand( + createCommand(), + ) + + return cmd +} + +type createOpts struct { + description string +} + +func createCommand() *cobra.Command { + var opts createOpts + cmd := &cobra.Command{ + Use: "create", + Short: "Create a context", + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + return runCreate(cmd.Context(), opts, args[0], args[1]) + }, + } + + cmd.Flags().StringVar(&opts.description, "description", "", "Description of the context") + + return cmd +} + +func runCreate(ctx context.Context, opts createOpts, name string, contextType string) error { + s := store.ContextStore(ctx) + return s.Create(name, store.TypeContext{ + Type: contextType, + Description: opts.description, + }, map[string]interface{}{ + // If we don't set anything here the main docker cli + // doesn't know how to read the context any more + "docker": CliContext{}, + }) +} diff --git a/cmd/example.go b/cli/cmd/example.go similarity index 89% rename from cmd/example.go rename to cli/cmd/example.go index b73344a31..bc3077325 100644 --- a/cmd/example.go +++ b/cli/cmd/example.go @@ -25,7 +25,7 @@ THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package main +package cmd import ( "context" @@ -35,20 +35,16 @@ import ( "time" "github.com/docker/api/client" - "github.com/docker/api/util" - "github.com/golang/protobuf/ptypes/empty" "github.com/pkg/errors" - "github.com/urfave/cli/v2" + "github.com/spf13/cobra" ) -var exampleCommand = cli.Command{ - Name: "example", - Usage: "sample command using backend, to be removed later", - Action: func(clix *cli.Context) error { - // return information for the current context - ctx, cancel := util.NewSigContext() - defer cancel() +var ExampleCommand = cobra.Command{ + Use: "example", + Short: "sample command using backend, to be removed later", + RunE: func(cmd *cobra.Command, args []string) error { + ctx := cmd.Context() // get our current context ctx = current(ctx) diff --git a/cli/main.go b/cli/main.go new file mode 100644 index 000000000..16d019f3d --- /dev/null +++ b/cli/main.go @@ -0,0 +1,165 @@ +/* + Copyright (c) 2020 Docker Inc. + + 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. +*/ + +package main + +import ( + "context" + "fmt" + "log" + "os" + "os/exec" + "path/filepath" + + "github.com/docker/api/cli/cmd" + apicontext "github.com/docker/api/context" + "github.com/docker/api/context/store" + "github.com/docker/api/util" + "github.com/sirupsen/logrus" + "github.com/spf13/cobra" +) + +type mainOpts struct { + apicontext.ContextFlags + debug bool +} + +func init() { + // initial hack to get the path of the project's bin dir + // into the env of this cli for development + path, err := filepath.Abs(filepath.Dir(os.Args[0])) + if err != nil { + log.Fatal(err) + } + if err := os.Setenv("PATH", fmt.Sprintf("%s:%s", os.Getenv("PATH"), path)); err != nil { + panic(err) + } +} + +func main() { + var opts mainOpts + root := &cobra.Command{ + Use: "docker", + Long: "docker for the 2020s", + PersistentPreRunE: func(cmd *cobra.Command, args []string) error { + execMoby(cmd.Context()) + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + return cmd.Help() + }, + } + + helpFunc := root.HelpFunc() + root.SetHelpFunc(func(cmd *cobra.Command, args []string) { + execMoby(cmd.Context()) + helpFunc(cmd, args) + }) + + root.PersistentFlags().BoolVarP(&opts.debug, "debug", "d", false, "enable debug output in the logs") + opts.AddFlags(root.PersistentFlags()) + + // populate the opts with the global flags + _ = root.PersistentFlags().Parse(os.Args[1:]) + if opts.debug { + logrus.SetLevel(logrus.DebugLevel) + } + + root.AddCommand( + cmd.ContextCommand(), + &cmd.ExampleCommand, + ) + + ctx, cancel := util.NewSigContext() + defer cancel() + + ctx, err := withCurrentContext(ctx, opts) + if err != nil { + logrus.Fatal(err) + } + + s, err := store.New(opts.Config) + if err != nil { + logrus.Fatal(err) + } + ctx = store.WithContextStore(ctx, s) + + if err = root.ExecuteContext(ctx); err != nil { + os.Exit(1) + } +} + +type currentContextKey struct{} + +func withCurrentContext(ctx context.Context, opts mainOpts) (context.Context, error) { + config, err := apicontext.LoadConfigFile(opts.Config, "config.json") + if err != nil { + return ctx, err + } + + currentContext := opts.Context + if currentContext == "" { + currentContext = config.CurrentContext + } + if currentContext == "" { + currentContext = "default" + } + logrus.Debugf("Current context %q", currentContext) + return context.WithValue(ctx, currentContextKey{}, currentContext), nil +} + +// CurrentContext returns the current context name +func CurrentContext(ctx context.Context) string { + cc, _ := ctx.Value(currentContextKey{}).(string) + return cc +} + +func execMoby(ctx context.Context) { + currentContext := CurrentContext(ctx) + s := store.ContextStore(ctx) + + cc, err := s.Get(currentContext) + if err != nil { + logrus.Fatal(err) + } + _, ok := cc.Metadata.(store.TypeContext) + if !ok { + cmd := exec.Command("docker", os.Args[1:]...) + cmd.Stdin = os.Stdin + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + if err != nil { + if exiterr, ok := err.(*exec.ExitError); ok { + os.Exit(exiterr.ExitCode()) + } + os.Exit(1) + } + } + os.Exit(0) + } +} diff --git a/cmd/main.go b/cmd/main.go deleted file mode 100644 index 5bcc5c9c5..000000000 --- a/cmd/main.go +++ /dev/null @@ -1,131 +0,0 @@ -/* - Copyright (c) 2020 Docker Inc. - - 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. -*/ - -package main - -import ( - "fmt" - "io" - "log" - "os" - "os/exec" - "path/filepath" - "sort" - - "github.com/docker/api/context" - "github.com/sirupsen/logrus" - "github.com/urfave/cli/v2" -) - -func init() { - // initial hack to get the path of the project's bin dir - // into the env of this cli for development - - path, err := filepath.Abs(filepath.Dir(os.Args[0])) - if err != nil { - log.Fatal(err) - } - if err := os.Setenv("PATH", fmt.Sprintf("%s:%s", os.Getenv("PATH"), path)); err != nil { - panic(err) - } -} - -func main() { - app := cli.NewApp() - app.Name = "docker" - app.Usage = "Docker for the 2020s" - app.UseShortOptionHandling = true - app.EnableBashCompletion = true - app.Flags = []cli.Flag{ - &cli.BoolFlag{ - Name: "debug", - Usage: "enable debug output in the logs", - }, - &context.ConfigFlag, - &context.ContextFlag, - } - - // Make a copy of the default HelpPrinter function - originalHelpPrinter := cli.HelpPrinter - // Change the HelpPrinter function to shell out to the Moby CLI help - // when the current context is pointing to Docker engine - // else we use the copy of the original HelpPrinter - cli.HelpPrinter = func(w io.Writer, templ string, data interface{}) { - ctx, err := context.GetContext() - if err != nil { - logrus.Fatal(err) - } - if ctx.Metadata.Type == "Moby" { - shellOutToDefaultEngine() - } else { - originalHelpPrinter(w, templ, data) - } - } - - app.Before = func(clix *cli.Context) error { - if clix.Bool("debug") { - logrus.SetLevel(logrus.DebugLevel) - } - ctx, err := context.GetContext() - if err != nil { - logrus.Fatal(err) - } - if ctx.Metadata.Type == "Moby" { - shellOutToDefaultEngine() - } - // TODO select backend based on context.Metadata.Type - return nil - } - app.Commands = []*cli.Command{ - &contextCommand, - &exampleCommand, - } - - sort.Sort(cli.FlagsByName(app.Flags)) - sort.Sort(cli.CommandsByName(app.Commands)) - - if err := app.Run(os.Args); err != nil { - fmt.Fprintln(os.Stderr, err) - os.Exit(1) - } -} - -func shellOutToDefaultEngine() { - cmd := exec.Command("docker", os.Args[1:]...) - cmd.Stdin = os.Stdin - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - if err := cmd.Run(); err != nil { - if err != nil { - if exiterr, ok := err.(*exec.ExitError); ok { - os.Exit(exiterr.ExitCode()) - } - os.Exit(1) - } - } - os.Exit(0) -} diff --git a/context/config.go b/context/config.go index 0a858e24c..30227dfa1 100644 --- a/context/config.go +++ b/context/config.go @@ -1,3 +1,30 @@ +/* + Copyright (c) 2020 Docker Inc. + + 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. +*/ + package context import ( @@ -7,8 +34,8 @@ import ( "path/filepath" ) -func LoadConfigFile() (*ConfigFile, error) { - filename := filepath.Join(ConfigDir, ConfigFileName) +func LoadConfigFile(configDir string, configFileName string) (*ConfigFile, error) { + filename := filepath.Join(configDir, configFileName) configFile := &ConfigFile{ Filename: filename, } diff --git a/cmd/context.go b/context/context.go similarity index 78% rename from cmd/context.go rename to context/context.go index ccdd61f03..100ad3111 100644 --- a/cmd/context.go +++ b/context/context.go @@ -25,18 +25,8 @@ THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package main +package context -import ( - "github.com/pkg/errors" - "github.com/urfave/cli/v2" -) - -var contextCommand = cli.Command{ - Name: "context", - Usage: "manage contexts", - Action: func(clix *cli.Context) error { - // return information for the current context - return errors.New("Error : To be implemented") - }, +type TypeContext struct { + Type string } diff --git a/context/flags.go b/context/flags.go index f875a9fc9..3c671cdea 100644 --- a/context/flags.go +++ b/context/flags.go @@ -1,10 +1,38 @@ +/* + Copyright (c) 2020 Docker Inc. + + 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. +*/ + package context import ( + "os" "path/filepath" "github.com/mitchellh/go-homedir" - "github.com/urfave/cli/v2" + "github.com/spf13/pflag" ) const ( @@ -13,25 +41,15 @@ const ( configFileDir = ".docker" ) -var ( - ConfigDir string - ContextName string - ConfigFlag = cli.StringFlag{ - Name: "config", - Usage: "Location of client config files `DIRECTORY`", - EnvVars: []string{"DOCKER_CONFIG"}, - Value: filepath.Join(home(), configFileDir), - Destination: &ConfigDir, - } +type ContextFlags struct { + Config string + Context string +} - ContextFlag = cli.StringFlag{ - Name: "context", - Aliases: []string{"c"}, - Usage: "Name of the context `CONTEXT` to use to connect to the daemon (overrides DOCKER_HOST env var and default context set with \"docker context use\")", - EnvVars: []string{"DOCKER_CONTEXT"}, - Destination: &ContextName, - } -) +func (c *ContextFlags) AddFlags(flags *pflag.FlagSet) { + flags.StringVar(&c.Config, "config", filepath.Join(home(), configFileDir), "Location of the client config files `DIRECTORY`") + flags.StringVarP(&c.Context, "context", "c", os.Getenv("DOCKER_CONTEXT"), "context") +} func home() string { home, _ := homedir.Dir() diff --git a/context/store.go b/context/store.go deleted file mode 100644 index 8c298fd28..000000000 --- a/context/store.go +++ /dev/null @@ -1,65 +0,0 @@ -package context - -import ( - "encoding/json" - "io/ioutil" - "path/filepath" - - "github.com/opencontainers/go-digest" -) - -const ( - contextsDir = "contexts" - metadataDir = "meta" - metaFile = "meta.json" -) - -// ContextStoreDir returns the directory the docker contexts are stored in -func ContextStoreDir() string { - return filepath.Join(ConfigDir, contextsDir) -} - -type Metadata struct { - Name string `json:",omitempty"` - Metadata TypeContext `json:",omitempty"` - Endpoints map[string]interface{} `json:",omitempty"` -} - -type TypeContext struct { - Type string -} - -func GetContext() (*Metadata, error) { - config, err := LoadConfigFile() - if err != nil { - return nil, err - } - r := &Metadata{ - Endpoints: make(map[string]interface{}), - } - - if ContextName == "" { - ContextName = config.CurrentContext - } - if ContextName == "" || ContextName == "default" { - r.Metadata.Type = "Moby" - return r, nil - } - - meta := filepath.Join(ConfigDir, contextsDir, metadataDir, contextdirOf(ContextName), metaFile) - bytes, err := ioutil.ReadFile(meta) - if err != nil { - return nil, err - } - - if err := json.Unmarshal(bytes, r); err != nil { - return r, err - } - - r.Name = ContextName - return r, nil -} - -func contextdirOf(name string) string { - return digest.FromString(name).Encoded() -} diff --git a/context/store/store.go b/context/store/store.go new file mode 100644 index 000000000..8750f386f --- /dev/null +++ b/context/store/store.go @@ -0,0 +1,157 @@ +/* + Copyright (c) 2020 Docker Inc. + + 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. +*/ + +package store + +import ( + "context" + "encoding/json" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "reflect" + + "github.com/opencontainers/go-digest" +) + +const ( + contextsDir = "contexts" + metadataDir = "meta" + metaFile = "meta.json" +) + +type contextStoreKey struct{} + +func WithContextStore(ctx context.Context, store Store) context.Context { + return context.WithValue(ctx, contextStoreKey{}, store) +} + +func ContextStore(ctx context.Context) Store { + s, _ := ctx.Value(contextStoreKey{}).(Store) + return s +} + +type Store interface { + Get(name string) (*Metadata, error) + Create(name string, data interface{}, endpoints map[string]interface{}) error +} + +type store struct { + root string +} + +// New returns a configured context store +func New(root string) (Store, error) { + cd := filepath.Join(root, contextsDir) + if _, err := os.Stat(cd); os.IsNotExist(err) { + if err = os.Mkdir(cd, 0755); err != nil { + return nil, err + } + } + m := filepath.Join(cd, metadataDir) + if _, err := os.Stat(m); os.IsNotExist(err) { + if err = os.Mkdir(m, 0755); err != nil { + return nil, err + } + } + + return &store{ + root: root, + }, nil +} + +// Get returns the context with the given name +func (s *store) Get(name string) (*Metadata, error) { + if name == "default" { + return &Metadata{}, nil + } + + meta := filepath.Join(s.root, contextsDir, metadataDir, contextdirOf(name), metaFile) + bytes, err := ioutil.ReadFile(meta) + if err != nil { + return nil, err + } + + r := &Metadata{ + Endpoints: make(map[string]interface{}), + } + + typed := getter() + if err := json.Unmarshal(bytes, typed); err != nil { + return r, err + } + + r.Metadata = reflect.ValueOf(typed).Elem().Interface() + + return r, nil +} + +func (s *store) Create(name string, data interface{}, endpoints map[string]interface{}) error { + dir := contextdirOf(name) + metaDir := filepath.Join(s.root, contextsDir, metadataDir, dir) + if _, err := os.Stat(metaDir); !os.IsNotExist(err) { + return fmt.Errorf("Context %q already exists", name) + } + + err := os.Mkdir(metaDir, 0755) + if err != nil { + return err + } + + meta := Metadata{ + Name: name, + Metadata: data, + Endpoints: endpoints, + } + + bytes, err := json.Marshal(&meta) + if err != nil { + return err + } + + return ioutil.WriteFile(filepath.Join(metaDir, metaFile), bytes, 0644) +} + +func contextdirOf(name string) string { + return digest.FromString(name).Encoded() +} + +type Metadata struct { + Name string `json:",omitempty"` + Metadata interface{} `json:",omitempty"` + Endpoints map[string]interface{} `json:",omitempty"` +} + +type TypeContext struct { + Type string + Description string +} + +func getter() interface{} { + return &TypeContext{} +} diff --git a/context/store/store_test.go b/context/store/store_test.go new file mode 100644 index 000000000..a5db64d9c --- /dev/null +++ b/context/store/store_test.go @@ -0,0 +1,73 @@ +/* + Copyright (c) 2020 Docker Inc. + + 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. +*/ + +package store + +import ( + _ "crypto/sha256" + "io/ioutil" + "os" + "testing" + + "github.com/stretchr/testify/assert" +) + +func setup(t *testing.T, cb func(*testing.T, Store)) { + dir, err := ioutil.TempDir("", "store") + assert.Nil(t, err) + defer os.RemoveAll(dir) + + store, err := New(dir) + assert.Nil(t, err) + + cb(t, store) +} + +func TestGetUnknown(t *testing.T) { + setup(t, func(t *testing.T, store Store) { + meta, err := store.Get("unknown") + assert.Nil(t, meta) + assert.Error(t, err) + }) +} + +func TestCreate(t *testing.T) { + setup(t, func(t *testing.T, store Store) { + err := store.Create("test", nil, nil) + assert.Nil(t, err) + }) +} + +func TestGet(t *testing.T) { + setup(t, func(t *testing.T, store Store) { + err := store.Create("test", nil, nil) + assert.Nil(t, err) + meta, err := store.Get("test") + assert.Nil(t, err) + assert.NotNil(t, meta) + }) +} diff --git a/go.mod b/go.mod index cf47268c5..226add973 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,13 @@ require ( github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.5.1 // indirect github.com/sirupsen/logrus v1.5.0 + github.com/spf13/cobra v1.0.0 + github.com/spf13/pflag v1.0.5 + github.com/stretchr/testify v1.5.1 github.com/urfave/cli/v2 v2.2.0 - google.golang.org/grpc v1.28.1 + golang.org/x/net v0.0.0-20191004110552-13f9640d40b9 // indirect + golang.org/x/text v0.3.2 // indirect + google.golang.org/grpc v1.29.1 google.golang.org/protobuf v1.21.0 + gopkg.in/yaml.v2 v2.2.8 // indirect ) diff --git a/go.sum b/go.sum index f2dee35bb..d82778e6a 100644 --- a/go.sum +++ b/go.sum @@ -1,33 +1,51 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -39,17 +57,29 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0 h1:oOuy+ugB+P/kBdUnG5QaMXSIyJ1q38wWSojYCb3z5VQ= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= @@ -58,17 +88,26 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -76,6 +115,7 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.5.1 h1:bdHYieyGlH+6OLEk2YQha8THib30KP0/yD0YH9m6xcA= github.com/prometheus/client_golang v1.5.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= @@ -84,13 +124,18 @@ github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1: github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.9.1 h1:KOMtN28tlbam3/7ZKEYKHhKoJZYYj3gMH4uc62x7X7U= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLkt8= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= @@ -99,15 +144,42 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.5.0 h1:1N5EYkVAPEywqZRJd7cwnRtCb6xJx7NH3T3WUTF980Q= github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8= +github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.4.0 h1:yXHLWeravcrgGyFSyCgdYpXQ9dR9c/WED3pg1RhxqEU= +github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/urfave/cli/v2 v2.2.0 h1:JTTnM6wKzdA0Jqodd966MVj4vWbbquZykeX1sKbe2C4= github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -116,19 +188,25 @@ golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980 h1:dfGZHvZk057jK2MCeWus/TowKpJ8y4AmooUzdBSR9GU= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191004110552-13f9640d40b9 h1:rjwSpXsdiK0dV8/Naq3kAw9ymfAeJIyd0upUIElB+lI= +golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc= @@ -137,6 +215,11 @@ golang.org/x/sys v0.0.0-20200122134326-e047566fdf82 h1:ywK/j/KkyTHcdyYSZNXGjMwgm golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= @@ -149,10 +232,11 @@ google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoA google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.28.1 h1:C1QC6KzgSiLyBabDi87BbjaGreoRgGUF5nOyvfrAZ1k= -google.golang.org/grpc v1.28.1/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1 h1:EC2SB8S04d2r73uptxphDSUG+kTKVgjRPF+N3xpxRB4= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -161,12 +245,17 @@ google.golang.org/protobuf v1.21.0 h1:qdOKuR/EIArgaWNjetjgTzgVTAZ+S/WXVrq9HW9zim google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5 h1:ymVxjfMaHvXD8RqPRmzHHsB3VvucivSkIAvJFDI5O3c= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/util/util.go b/util/util.go index 9ad70d3d6..92d337583 100644 --- a/util/util.go +++ b/util/util.go @@ -1,5 +1,5 @@ /* - Copyright (c) 2019 Docker Inc. + Copyright (c) 2020 Docker Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation From e2c7370a82fc2895504a7291c3cddaabfa4bc677 Mon Sep 17 00:00:00 2001 From: Djordje Lukic <djordje.lukic@docker.com> Date: Sun, 26 Apr 2020 22:07:50 +0200 Subject: [PATCH 2/8] Implement context list --- cli/cmd/context.go | 37 ++++++++++++++++++++++ context/context.go | 32 ------------------- context/store/store.go | 61 ++++++++++++++++++++++++++++++++----- context/store/store_test.go | 31 ++++++++++++++++++- go.mod | 2 +- go.sum | 4 +++ 6 files changed, 125 insertions(+), 42 deletions(-) delete mode 100644 context/context.go diff --git a/cli/cmd/context.go b/cli/cmd/context.go index 1d8547109..8e8041fe3 100644 --- a/cli/cmd/context.go +++ b/cli/cmd/context.go @@ -29,6 +29,9 @@ package cmd import ( "context" + "fmt" + "os" + "text/tabwriter" "github.com/docker/api/context/store" "github.com/spf13/cobra" @@ -45,6 +48,7 @@ func ContextCommand() *cobra.Command { cmd.AddCommand( createCommand(), + listCommand(), ) return cmd @@ -70,6 +74,17 @@ func createCommand() *cobra.Command { return cmd } +func listCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "list", + Aliases: []string{"ls"}, + RunE: func(cmd *cobra.Command, args []string) error { + return runList(cmd.Context()) + }, + } + return cmd +} + func runCreate(ctx context.Context, opts createOpts, name string, contextType string) error { s := store.ContextStore(ctx) return s.Create(name, store.TypeContext{ @@ -81,3 +96,25 @@ func runCreate(ctx context.Context, opts createOpts, name string, contextType st "docker": CliContext{}, }) } + +func runList(ctx context.Context) error { + s := store.ContextStore(ctx) + contexts, err := s.List() + if err != nil { + return err + } + + w := tabwriter.NewWriter(os.Stdout, 0, 0, 1, ' ', 0) + fmt.Fprintln(w, "NAME\tDESCRIPTION\tTYPE") + format := "%s\t%s\t%s\n" + + for _, c := range contexts { + meta, ok := c.Metadata.(store.TypeContext) + if !ok { + return fmt.Errorf("Unable to list contexts, context %q is not valid", c.Name) + } + fmt.Fprintf(w, format, c.Name, meta.Description, meta.Type) + } + + return w.Flush() +} diff --git a/context/context.go b/context/context.go deleted file mode 100644 index 100ad3111..000000000 --- a/context/context.go +++ /dev/null @@ -1,32 +0,0 @@ -/* - Copyright (c) 2020 Docker Inc. - - 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. -*/ - -package context - -type TypeContext struct { - Type string -} diff --git a/context/store/store.go b/context/store/store.go index 8750f386f..d693b90a1 100644 --- a/context/store/store.go +++ b/context/store/store.go @@ -56,9 +56,16 @@ func ContextStore(ctx context.Context) Store { return s } +// Store type Store interface { + // Get returns the context with with name, it returns an error if the + // context doesn't exist Get(name string) (*Metadata, error) + // Create creates a new context, it returns an error if a context with the + // same name exists already. Create(name string, data interface{}, endpoints map[string]interface{}) error + // List returns the list of created contexts + List() ([]*Metadata, error) } type store struct { @@ -92,23 +99,33 @@ func (s *store) Get(name string) (*Metadata, error) { } meta := filepath.Join(s.root, contextsDir, metadataDir, contextdirOf(name), metaFile) + return read(meta) +} + +func read(meta string) (*Metadata, error) { bytes, err := ioutil.ReadFile(meta) if err != nil { return nil, err } - r := &Metadata{ - Endpoints: make(map[string]interface{}), + var r untypedContextMetadata + if err := json.Unmarshal(bytes, &r); err != nil { + return nil, err + } + + result := &Metadata{ + Name: r.Name, + Endpoints: r.Endpoints, } typed := getter() - if err := json.Unmarshal(bytes, typed); err != nil { - return r, err + if err := json.Unmarshal(r.Metadata, typed); err != nil { + return nil, err } - r.Metadata = reflect.ValueOf(typed).Elem().Interface() + result.Metadata = reflect.ValueOf(typed).Elem().Interface() - return r, nil + return result, nil } func (s *store) Create(name string, data interface{}, endpoints map[string]interface{}) error { @@ -137,6 +154,28 @@ func (s *store) Create(name string, data interface{}, endpoints map[string]inter return ioutil.WriteFile(filepath.Join(metaDir, metaFile), bytes, 0644) } +func (s *store) List() ([]*Metadata, error) { + root := filepath.Join(s.root, contextsDir, metadataDir) + c, err := ioutil.ReadDir(root) + if err != nil { + return nil, err + } + + var result []*Metadata + for _, fi := range c { + if fi.IsDir() { + meta := filepath.Join(root, fi.Name(), metaFile) + r, err := read(meta) + if err != nil { + return nil, err + } + result = append(result, r) + } + } + + return result, nil +} + func contextdirOf(name string) string { return digest.FromString(name).Encoded() } @@ -147,9 +186,15 @@ type Metadata struct { Endpoints map[string]interface{} `json:",omitempty"` } +type untypedContextMetadata struct { + Metadata json.RawMessage `json:"metadata,omitempty"` + Endpoints map[string]interface{} `json:"endpoints,omitempty"` + Name string `json:"name,omitempty"` +} + type TypeContext struct { - Type string - Description string + Type string `json:",omitempty"` + Description string `json:",omitempty"` } func getter() interface{} { diff --git a/context/store/store_test.go b/context/store/store_test.go index a5db64d9c..43c96b47c 100644 --- a/context/store/store_test.go +++ b/context/store/store_test.go @@ -29,6 +29,7 @@ package store import ( _ "crypto/sha256" + "fmt" "io/ioutil" "os" "testing" @@ -64,10 +65,38 @@ func TestCreate(t *testing.T) { func TestGet(t *testing.T) { setup(t, func(t *testing.T, store Store) { - err := store.Create("test", nil, nil) + err := store.Create("test", TypeContext{ + Type: "type", + Description: "description", + }, nil) assert.Nil(t, err) + meta, err := store.Get("test") assert.Nil(t, err) assert.NotNil(t, meta) + assert.Equal(t, "test", meta.Name) + + m, ok := meta.Metadata.(TypeContext) + assert.Equal(t, ok, true) + fmt.Printf("%#v\n", meta) + assert.Equal(t, "description", m.Description) + assert.Equal(t, "type", m.Type) + }) +} + +func TestList(t *testing.T) { + setup(t, func(t *testing.T, store Store) { + err := store.Create("test1", TypeContext{}, nil) + assert.Nil(t, err) + + err = store.Create("test2", TypeContext{}, nil) + assert.Nil(t, err) + + contexts, err := store.List() + assert.Nil(t, err) + + assert.Equal(t, len(contexts), 2) + assert.Equal(t, contexts[0].Name, "test1") + assert.Equal(t, contexts[1].Name, "test2") }) } diff --git a/go.mod b/go.mod index 226add973..47237d188 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.5.1 github.com/urfave/cli/v2 v2.2.0 - golang.org/x/net v0.0.0-20191004110552-13f9640d40b9 // indirect + golang.org/x/net v0.0.0-20200425230154-ff2c4b7c35a0 // indirect golang.org/x/text v0.3.2 // indirect google.golang.org/grpc v1.29.1 google.golang.org/protobuf v1.21.0 diff --git a/go.sum b/go.sum index d82778e6a..8568eec5a 100644 --- a/go.sum +++ b/go.sum @@ -197,6 +197,8 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980 h1:dfGZHvZk057jK2MCeWus/TowK golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191004110552-13f9640d40b9 h1:rjwSpXsdiK0dV8/Naq3kAw9ymfAeJIyd0upUIElB+lI= golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200425230154-ff2c4b7c35a0 h1:Jcxah/M+oLZ/R4/z5RzfPzGbPXnVDPkEDtf2JnuxN+U= +golang.org/x/net v0.0.0-20200425230154-ff2c4b7c35a0/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -213,6 +215,8 @@ golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/p golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82 h1:ywK/j/KkyTHcdyYSZNXGjMwgmDSfjglYZ3vStQ/gSCU= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= From 32da9e65e8a588d60cf8a8007a42fc403696f6f1 Mon Sep 17 00:00:00 2001 From: Djordje Lukic <djordje.lukic@docker.com> Date: Sun, 26 Apr 2020 22:13:35 +0200 Subject: [PATCH 3/8] Only execute moby if the command is not a context command --- cli/main.go | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/cli/main.go b/cli/main.go index 16d019f3d..c7f6bcaf4 100644 --- a/cli/main.go +++ b/cli/main.go @@ -60,13 +60,25 @@ func init() { } } +func isContextCommand(cmd *cobra.Command) bool { + if cmd == nil { + return false + } + if cmd.Name() == "context" { + return true + } + return isContextCommand(cmd.Parent()) +} + func main() { var opts mainOpts root := &cobra.Command{ Use: "docker", Long: "docker for the 2020s", PersistentPreRunE: func(cmd *cobra.Command, args []string) error { - execMoby(cmd.Context()) + if !isContextCommand(cmd) { + execMoby(cmd.Context()) + } return nil }, RunE: func(cmd *cobra.Command, args []string) error { @@ -76,7 +88,9 @@ func main() { helpFunc := root.HelpFunc() root.SetHelpFunc(func(cmd *cobra.Command, args []string) { - execMoby(cmd.Context()) + if !isContextCommand(cmd) { + execMoby(cmd.Context()) + } helpFunc(cmd, args) }) @@ -128,7 +142,9 @@ func withCurrentContext(ctx context.Context, opts mainOpts) (context.Context, er if currentContext == "" { currentContext = "default" } + logrus.Debugf("Current context %q", currentContext) + return context.WithValue(ctx, currentContextKey{}, currentContext), nil } @@ -146,6 +162,8 @@ func execMoby(ctx context.Context) { if err != nil { logrus.Fatal(err) } + // Only run original docker command if the current context is not + // ours. _, ok := cc.Metadata.(store.TypeContext) if !ok { cmd := exec.Command("docker", os.Args[1:]...) From cdff00d571e5fcf3eceed71cc4395e046d994373 Mon Sep 17 00:00:00 2001 From: Djordje Lukic <djordje.lukic@docker.com> Date: Mon, 27 Apr 2020 10:17:10 +0200 Subject: [PATCH 4/8] Run tests inside a container --- Dockerfile | 6 +++++- Makefile | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index a30b3538a..bea06624c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,7 +10,8 @@ RUN apt-get update && apt-get install --no-install-recommends -y \ git \ protobuf-compiler \ libprotobuf-dev -RUN go get github.com/golang/protobuf/protoc-gen-go +RUN go get github.com/golang/protobuf/protoc-gen-go && \ + go get gotest.tools/gotestsum WORKDIR ${PWD} ADD go.* ${PWD} RUN go mod download @@ -25,6 +26,9 @@ RUN --mount=type=cache,target=/root/.cache/go-build \ GOARCH=${TARGET_ARCH} \ make bins +FROM make-protos as make-test +RUN make test + FROM make-protos AS make-xbins RUN --mount=type=cache,target=/root/.cache/go-build \ make xbins diff --git a/Makefile b/Makefile index 4a693bc7a..7286a142b 100644 --- a/Makefile +++ b/Makefile @@ -72,6 +72,10 @@ dxbins: dbins --output type=local,dest=./bin \ --target xbins +dtest: + docker build . \ + --target make-test + test: gotestsum ./... From 10bc4b93f62f460f88f6673f15c96aef2c9a7a30 Mon Sep 17 00:00:00 2001 From: Djordje Lukic <djordje.lukic@docker.com> Date: Mon, 27 Apr 2020 11:32:16 +0200 Subject: [PATCH 5/8] Call moby if the command is unknown Will also check if the context is an original docker context --- cli/main.go | 10 ++++++++-- context/store/store.go | 4 ++-- context/store/store_test.go | 2 -- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/cli/main.go b/cli/main.go index c7f6bcaf4..418765501 100644 --- a/cli/main.go +++ b/cli/main.go @@ -34,6 +34,7 @@ import ( "os" "os/exec" "path/filepath" + "strings" "github.com/docker/api/cli/cmd" apicontext "github.com/docker/api/context" @@ -73,8 +74,9 @@ func isContextCommand(cmd *cobra.Command) bool { func main() { var opts mainOpts root := &cobra.Command{ - Use: "docker", - Long: "docker for the 2020s", + Use: "docker", + Long: "docker for the 2020s", + SilenceErrors: true, PersistentPreRunE: func(cmd *cobra.Command, args []string) error { if !isContextCommand(cmd) { execMoby(cmd.Context()) @@ -123,6 +125,10 @@ func main() { ctx = store.WithContextStore(ctx, s) if err = root.ExecuteContext(ctx); err != nil { + if strings.Contains(err.Error(), "unknown command") { + execMoby(ctx) + } + fmt.Println(err) os.Exit(1) } } diff --git a/context/store/store.go b/context/store/store.go index d693b90a1..6f864d978 100644 --- a/context/store/store.go +++ b/context/store/store.go @@ -58,8 +58,8 @@ func ContextStore(ctx context.Context) Store { // Store type Store interface { - // Get returns the context with with name, it returns an error if the - // context doesn't exist + // Get returns the context with name, it returns an error if the context + // doesn't exist Get(name string) (*Metadata, error) // Create creates a new context, it returns an error if a context with the // same name exists already. diff --git a/context/store/store_test.go b/context/store/store_test.go index 43c96b47c..fd331695c 100644 --- a/context/store/store_test.go +++ b/context/store/store_test.go @@ -29,7 +29,6 @@ package store import ( _ "crypto/sha256" - "fmt" "io/ioutil" "os" "testing" @@ -78,7 +77,6 @@ func TestGet(t *testing.T) { m, ok := meta.Metadata.(TypeContext) assert.Equal(t, ok, true) - fmt.Printf("%#v\n", meta) assert.Equal(t, "description", m.Description) assert.Equal(t, "type", m.Type) }) From 756836ffabd5c64b67372847a684d62f57808ba4 Mon Sep 17 00:00:00 2001 From: Djordje Lukic <djordje.lukic@docker.com> Date: Mon, 27 Apr 2020 11:45:23 +0200 Subject: [PATCH 6/8] Use testify/suite and testify/require --- context/store/store_test.go | 101 +++++++++++++++++++----------------- go.mod | 1 + go.sum | 2 + 3 files changed, 57 insertions(+), 47 deletions(-) diff --git a/context/store/store_test.go b/context/store/store_test.go index fd331695c..b853de4fc 100644 --- a/context/store/store_test.go +++ b/context/store/store_test.go @@ -34,67 +34,74 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" ) -func setup(t *testing.T, cb func(*testing.T, Store)) { +type StoreTestSuite struct { + suite.Suite + store Store + dir string +} + +func (suite *StoreTestSuite) BeforeTest(suiteName, testName string) { dir, err := ioutil.TempDir("", "store") - assert.Nil(t, err) - defer os.RemoveAll(dir) + require.Nil(suite.T(), err) store, err := New(dir) - assert.Nil(t, err) + require.Nil(suite.T(), err) - cb(t, store) + suite.dir = dir + suite.store = store } -func TestGetUnknown(t *testing.T) { - setup(t, func(t *testing.T, store Store) { - meta, err := store.Get("unknown") - assert.Nil(t, meta) - assert.Error(t, err) - }) +func (suite *StoreTestSuite) AfterTest(suiteName, testName string) { + os.RemoveAll(suite.dir) } -func TestCreate(t *testing.T) { - setup(t, func(t *testing.T, store Store) { - err := store.Create("test", nil, nil) - assert.Nil(t, err) - }) +func (suite *StoreTestSuite) TestCreate() { + err := suite.store.Create("test", nil, nil) + assert.Nil(suite.T(), err) } -func TestGet(t *testing.T) { - setup(t, func(t *testing.T, store Store) { - err := store.Create("test", TypeContext{ - Type: "type", - Description: "description", - }, nil) - assert.Nil(t, err) - - meta, err := store.Get("test") - assert.Nil(t, err) - assert.NotNil(t, meta) - assert.Equal(t, "test", meta.Name) - - m, ok := meta.Metadata.(TypeContext) - assert.Equal(t, ok, true) - assert.Equal(t, "description", m.Description) - assert.Equal(t, "type", m.Type) - }) +func (suite *StoreTestSuite) TestGetUnknown() { + meta, err := suite.store.Get("unknown") + assert.Nil(suite.T(), meta) + assert.Error(suite.T(), err) } -func TestList(t *testing.T) { - setup(t, func(t *testing.T, store Store) { - err := store.Create("test1", TypeContext{}, nil) - assert.Nil(t, err) +func (suite *StoreTestSuite) TestGet() { + err := suite.store.Create("test", TypeContext{ + Type: "type", + Description: "description", + }, nil) + assert.Nil(suite.T(), err) - err = store.Create("test2", TypeContext{}, nil) - assert.Nil(t, err) + meta, err := suite.store.Get("test") + assert.Nil(suite.T(), err) + assert.NotNil(suite.T(), meta) + assert.Equal(suite.T(), "test", meta.Name) - contexts, err := store.List() - assert.Nil(t, err) - - assert.Equal(t, len(contexts), 2) - assert.Equal(t, contexts[0].Name, "test1") - assert.Equal(t, contexts[1].Name, "test2") - }) + m, ok := meta.Metadata.(TypeContext) + assert.Equal(suite.T(), ok, true) + assert.Equal(suite.T(), "description", m.Description) + assert.Equal(suite.T(), "type", m.Type) +} +func (suite *StoreTestSuite) TestList() { + err := suite.store.Create("test1", TypeContext{}, nil) + assert.Nil(suite.T(), err) + + err = suite.store.Create("test2", TypeContext{}, nil) + assert.Nil(suite.T(), err) + + contexts, err := suite.store.List() + assert.Nil(suite.T(), err) + + require.Equal(suite.T(), len(contexts), 2) + assert.Equal(suite.T(), contexts[0].Name, "test1") + assert.Equal(suite.T(), contexts[1].Name, "test2") +} + +func TestExampleTestSuite(t *testing.T) { + suite.Run(t, new(StoreTestSuite)) } diff --git a/go.mod b/go.mod index 47237d188..dc204573c 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/docker/api go 1.13 require ( + github.com/coreos/etcd v3.3.10+incompatible github.com/golang/protobuf v1.4.0 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 github.com/mitchellh/go-homedir v1.1.0 diff --git a/go.sum b/go.sum index 8568eec5a..c9c3e8ee3 100644 --- a/go.sum +++ b/go.sum @@ -18,6 +18,7 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.10+incompatible h1:jFneRYjIvLMLhDLCzuTuU4rSJUjRplcJQ7pD7MnhC04= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= @@ -73,6 +74,7 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= From e6597d61394bd4dca86e00452dd46b7c371d0a94 Mon Sep 17 00:00:00 2001 From: Djordje Lukic <djordje.lukic@docker.com> Date: Mon, 27 Apr 2020 14:04:53 +0200 Subject: [PATCH 7/8] Don't cd into a directory before building We pass the directory to build to the `go build` command --- Makefile | 14 +++++++------- cli/cmd/context.go | 3 ++- context/store/store_test.go | 1 + 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index 7286a142b..87186234e 100644 --- a/Makefile +++ b/Makefile @@ -40,20 +40,20 @@ protos: @protoc -I. --go_out=plugins=grpc,paths=source_relative:. ${PROTOS} cli: protos - cd cli && GOOS=${GOOS} GOARCH=${GOARCH} go build -v -o ../bin/docker + GOOS=${GOOS} GOARCH=${GOARCH} go build -v -o bin/docker ./cli example: protos cd example/backend && go build -v -o ../../bin/backend-example xcli: cli - cd cmd && GOOS=linux GOARCH=amd64 go build -v -o ../bin/docker-linux-amd64 - cd cmd && GOOS=darwin GOARCH=amd64 go build -v -o ../bin/docker-darwin-amd64 - cd cmd && GOOS=windows GOARCH=amd64 go build -v -o ../bin/docker-windows-amd64.exe + GOOS=linux GOARCH=amd64 go build -v -o bin/docker-linux-amd64 ./cli + GOOS=darwin GOARCH=amd64 go build -v -o bin/docker-darwin-amd64 ./cli + GOOS=windows GOARCH=amd64 go build -v -o bin/docker-windows-amd64.exe ./cli xexample: example - cd example/backend && GOOS=linux GOARCH=amd64 go build -v -o ../../bin/backend-example-linux-amd64 - cd example/backend && GOOS=darwin GOARCH=amd64 go build -v -o ../../bin/backend-example-darwin-amd64 - cd example/backend && GOOS=windows GOARCH=amd64 go build -v -o ../../bin/backend-example-windows-amd64.exe + GOOS=linux GOARCH=amd64 go build -v -o bin/backend-example-linux-amd64 ./example/backend + GOOS=darwin GOARCH=amd64 go build -v -o bin/backend-example-darwin-amd64 ./example/backend + GOOS=windows GOARCH=amd64 go build -v -o bin/backend-example-windows-amd64.exe ./example/backend dprotos: docker build . \ diff --git a/cli/cmd/context.go b/cli/cmd/context.go index 8e8041fe3..eff416e1a 100644 --- a/cli/cmd/context.go +++ b/cli/cmd/context.go @@ -61,7 +61,7 @@ type createOpts struct { func createCommand() *cobra.Command { var opts createOpts cmd := &cobra.Command{ - Use: "create", + Use: "create CONTEXT BACKEND [OPTIONS]", Short: "Create a context", Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { @@ -78,6 +78,7 @@ func listCommand() *cobra.Command { cmd := &cobra.Command{ Use: "list", Aliases: []string{"ls"}, + Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { return runList(cmd.Context()) }, diff --git a/context/store/store_test.go b/context/store/store_test.go index b853de4fc..d424e078b 100644 --- a/context/store/store_test.go +++ b/context/store/store_test.go @@ -87,6 +87,7 @@ func (suite *StoreTestSuite) TestGet() { assert.Equal(suite.T(), "description", m.Description) assert.Equal(suite.T(), "type", m.Type) } + func (suite *StoreTestSuite) TestList() { err := suite.store.Create("test1", TypeContext{}, nil) assert.Nil(suite.T(), err) From 474cdbae11d6a225077dd701e43541ee946d8e4b Mon Sep 17 00:00:00 2001 From: Djordje Lukic <djordje.lukic@docker.com> Date: Mon, 27 Apr 2020 15:56:23 +0200 Subject: [PATCH 8/8] Remove unnecessary if --- cli/main.go | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/cli/main.go b/cli/main.go index 418765501..0bd929cbc 100644 --- a/cli/main.go +++ b/cli/main.go @@ -177,12 +177,10 @@ func execMoby(ctx context.Context) { cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr if err := cmd.Run(); err != nil { - if err != nil { - if exiterr, ok := err.(*exec.ExitError); ok { - os.Exit(exiterr.ExitCode()) - } - os.Exit(1) + if exiterr, ok := err.(*exec.ExitError); ok { + os.Exit(exiterr.ExitCode()) } + os.Exit(1) } os.Exit(0) }