瀏覽代碼

Merge pull request #40 from docker/chore-cleanup

Add comments on exported items, remove example command
Djordje Lukic 5 年之前
父節點
當前提交
f32235b8ba

+ 4 - 10
.github/workflows/ci.yml

@@ -11,23 +11,17 @@ jobs:
     name: Build
     runs-on: ubuntu-latest
     steps:
-      - name: Set up Go 1.13
+      - name: Set up Go 1.14
         uses: actions/setup-go@v1
         with:
-          go-version: 1.13
+          go-version: 1.14
         id: go
 
       - name: Checkout code into the Go module directory
         uses: actions/checkout@v2
 
-      - name: Install Protoc
-        uses: arduino/setup-protoc@master
-
-      - name: Get dependencies
-        run: ./scripts/setup/install-go-gen
-
-      - name: Protos
-        run: make protos
+      - name: Lint
+        run: make lint
 
       - name: Build
         run: make cli

+ 35 - 0
.golangci.yml

@@ -0,0 +1,35 @@
+linters:
+  run:
+    concurrency: 2
+  enable-all: false
+  disable-all: true
+  enable:
+    - deadcode
+    - errcheck
+    - gocyclo
+    - gofmt
+    - goimports
+    - golint
+    - gosimple
+    - govet
+    - ineffassign
+    - interfacer
+    - lll
+    - misspell
+    - nakedret
+    - staticcheck
+    - structcheck
+    - typecheck
+    - unconvert
+    - unparam
+    - unused
+    - varcheck
+linters-settings:
+  gocyclo:
+    min-complexity: 16
+  lll:
+    line-length: 200
+issues:
+  # golangci hides some golint warnings (the warning about exported things
+  # withtout documentation for example), this will make it show them anyway.
+  exclude-use-default: false

+ 14 - 6
Dockerfile

@@ -4,15 +4,20 @@ ARG GO_VERSION=1.14.2
 FROM golang:${GO_VERSION} AS fs
 ARG TARGET_OS=unknown
 ARG TARGET_ARCH=unknown
-ARG PWD=$GOPATH/src/github.com/docker/api
+ARG PWD=/api
+ENV GO111MODULE=on
+
 RUN apt-get update && apt-get install --no-install-recommends -y \
     make \
     git \
     protobuf-compiler \
     libprotobuf-dev
-RUN go get github.com/golang/protobuf/protoc-gen-go && \
+
+RUN go get github.com/golang/protobuf/[email protected] && \
     go get golang.org/x/tools/cmd/goimports && \
-    go get gotest.tools/gotestsum
+    go get gotest.tools/[email protected] && \
+    go get github.com/golangci/golangci-lint/cmd/[email protected]
+
 WORKDIR ${PWD}
 ADD go.* ${PWD}
 RUN go mod download
@@ -32,13 +37,16 @@ RUN --mount=type=cache,target=/root/.cache/go-build \
     make -f builder.Makefile cross
 
 FROM scratch AS protos
-COPY --from=make-protos /go/src/github.com/docker/api .
+COPY --from=make-protos /api .
 
 FROM scratch AS cli
-COPY --from=make-cli /go/src/github.com/docker/api/bin/* .
+COPY --from=make-cli /api/bin/* .
 
 FROM scratch AS cross
-COPY --from=make-cross /go/src/github.com/docker/api/bin/* .
+COPY --from=make-cross /api/bin/* .
 
 FROM make-protos as test
 RUN make -f builder.Makefile test
+
+FROM fs AS lint
+RUN make -f builder.Makefile lint

+ 7 - 1
Makefile

@@ -53,8 +53,14 @@ test: ## Run unit tests
 cache-clear: # Clear the builder cache
 	@docker builder prune --force --filter type=exec.cachemount --filter=unused-for=24h
 
+lint: ## run linter(s)
+	@docker build . \
+	--target lint
+
 help: ## Show help
 	@echo Please specify a build target. The choices are:
 	@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
 
-.PHONY: all protos cli cross test cache-clear help
+FORCE:
+
+.PHONY: all protos cli cross test cache-clear lint help

+ 11 - 1
README.md

@@ -4,7 +4,17 @@
 
 ## Dev Setup
 
-Make sure you have Docker installed and running.
+The recommended way is to use the main `Makefile` that runs everything inside a container.
+
+If you don't have or want to use Docker for building you need to make sure you have all the needed tools installed locally:
+
+* go 1.14
+* `go get github.com/golang/protobuf/[email protected]`
+* `go get golang.org/x/tools/cmd/goimports`
+* `go get gotest.tools/[email protected]`
+* `go get github.com/golangci/golangci-lint/cmd/[email protected]`
+
+And then you can call the same make targets but you need to pass it the `builder.Makefile` (`make -f builder.Makefile`).
 
 ## Building the project
 

+ 18 - 28
azure/aci.go

@@ -32,7 +32,7 @@ func init() {
 func createACIContainers(ctx context.Context, aciContext store.AciContext, groupDefinition containerinstance.ContainerGroup) (c containerinstance.ContainerGroup, err error) {
 	containerGroupsClient, err := getContainerGroupsClient(aciContext.SubscriptionID)
 	if err != nil {
-		return c, fmt.Errorf("cannot get container group client: %v", err)
+		return c, errors.Wrapf(err, "cannot get container group client")
 	}
 
 	// Check if the container group already exists
@@ -96,30 +96,11 @@ func createACIContainers(ctx context.Context, aciContext store.AciContext, group
 	return containerGroup, err
 }
 
-func listACIContainers(aciContext store.AciContext) (c []containerinstance.ContainerGroup, err error) {
-	ctx := context.TODO()
-	containerGroupsClient, err := getContainerGroupsClient(aciContext.SubscriptionID)
-	if err != nil {
-		return c, fmt.Errorf("cannot get container group client: %v", err)
-	}
-
-	var containers []containerinstance.ContainerGroup
-	result, err := containerGroupsClient.ListByResourceGroup(ctx, aciContext.ResourceGroup)
+func execACIContainer(ctx context.Context, aciContext store.AciContext, command, containerGroup string, containerName string) (c containerinstance.ContainerExecResponse, err error) {
+	containerClient, err := getContainerClient(aciContext.SubscriptionID)
 	if err != nil {
-		return []containerinstance.ContainerGroup{}, err
+		return c, errors.Wrapf(err, "cannot get container client")
 	}
-	for result.NotDone() {
-		containers = append(containers, result.Values()...)
-		if err := result.NextWithContext(ctx); err != nil {
-			return []containerinstance.ContainerGroup{}, err
-		}
-	}
-
-	return containers, err
-}
-
-func execACIContainer(ctx context.Context, aciContext store.AciContext, command, containerGroup string, containerName string) (c containerinstance.ContainerExecResponse, err error) {
-	containerClient := getContainerClient(aciContext.SubscriptionID)
 	rows, cols := getTermSize()
 	containerExecRequest := containerinstance.ContainerExecRequest{
 		Command: to.StringPtr(command),
@@ -224,7 +205,10 @@ func exec(ctx context.Context, address string, password string, reader io.Reader
 }
 
 func getACIContainerLogs(ctx context.Context, aciContext store.AciContext, containerGroupName, containerName string) (string, error) {
-	containerClient := getContainerClient(aciContext.SubscriptionID)
+	containerClient, err := getContainerClient(aciContext.SubscriptionID)
+	if err != nil {
+		return "", errors.Wrapf(err, "cannot get container client")
+	}
 
 	logs, err := containerClient.ListLogs(ctx, aciContext.ResourceGroup, containerGroupName, containerName, nil)
 	if err != nil {
@@ -234,15 +218,21 @@ func getACIContainerLogs(ctx context.Context, aciContext store.AciContext, conta
 }
 
 func getContainerGroupsClient(subscriptionID string) (containerinstance.ContainerGroupsClient, error) {
-	auth, _ := auth.NewAuthorizerFromCLI()
+	auth, err := auth.NewAuthorizerFromCLI()
+	if err != nil {
+		return containerinstance.ContainerGroupsClient{}, err
+	}
 	containerGroupsClient := containerinstance.NewContainerGroupsClient(subscriptionID)
 	containerGroupsClient.Authorizer = auth
 	return containerGroupsClient, nil
 }
 
-func getContainerClient(subscriptionID string) containerinstance.ContainerClient {
-	auth, _ := auth.NewAuthorizerFromCLI()
+func getContainerClient(subscriptionID string) (containerinstance.ContainerClient, error) {
+	auth, err := auth.NewAuthorizerFromCLI()
+	if err != nil {
+		return containerinstance.ContainerClient{}, err
+	}
 	containerClient := containerinstance.NewContainerClient(subscriptionID)
 	containerClient.Authorizer = auth
-	return containerClient
+	return containerClient, nil
 }

+ 1 - 0
azure/backend.go

@@ -36,6 +36,7 @@ func getter() interface{} {
 	return &store.AciContext{}
 }
 
+// New creates a backend that can manage containers on ACI
 func New(ctx context.Context) (containers.ContainerService, error) {
 	currentContext := apicontext.CurrentContext(ctx)
 	contextStore, err := store.New()

+ 4 - 2
azure/convert/convert.go

@@ -21,8 +21,10 @@ const (
 	volumeDriveroptsAccountNameKey = "storage_account_name"
 	volumeDriveroptsAccountKeyKey  = "storage_account_key"
 	singleContainerName            = "single--container--aci"
+	secretInlineMark               = "inline:"
 )
 
+// ToContainerGroup converts a compose project into a ACI container group
 func ToContainerGroup(aciContext store.AciContext, p compose.Project) (containerinstance.ContainerGroup, error) {
 	project := projectAciHelper(p)
 	containerGroupName := strings.ToLower(project.Name)
@@ -98,8 +100,8 @@ func (p projectAciHelper) getAciSecretVolumes() ([]containerinstance.Volume, err
 	var secretVolumes []containerinstance.Volume
 	for secretName, filepathToRead := range p.Secrets {
 		var data []byte
-		if strings.HasPrefix(filepathToRead.File, compose.SecretInlineMark) {
-			data = []byte(filepathToRead.File[len(compose.SecretInlineMark):])
+		if strings.HasPrefix(filepathToRead.File, secretInlineMark) {
+			data = []byte(filepathToRead.File[len(secretInlineMark):])
 		} else {
 			var err error
 			data, err = ioutil.ReadFile(filepathToRead.File)

+ 15 - 12
backend/backend.go

@@ -7,43 +7,46 @@ import (
 )
 
 var (
-	ErrNoType         = errors.New("backend: no type")
-	ErrNoName         = errors.New("backend: no name")
-	ErrTypeRegistered = errors.New("backend: already registered")
+	errNoType         = errors.New("backend: no type")
+	errNoName         = errors.New("backend: no name")
+	errTypeRegistered = errors.New("backend: already registered")
 )
 
-type InitFunc func(context.Context) (interface{}, error)
+type initFunc func(context.Context) (interface{}, error)
 
-type Backend struct {
+type registeredBackend struct {
 	name        string
 	backendType string
-	init        InitFunc
+	init        initFunc
 }
 
 var backends = struct {
-	r []*Backend
+	r []*registeredBackend
 }{}
 
-func Register(name string, backendType string, init InitFunc) {
+// Register adds a typed backend to the registry
+func Register(name string, backendType string, init initFunc) {
 	if name == "" {
-		panic(ErrNoName)
+		panic(errNoName)
 	}
 	if backendType == "" {
-		panic(ErrNoType)
+		panic(errNoType)
 	}
 	for _, b := range backends.r {
 		if b.backendType == backendType {
-			panic(ErrTypeRegistered)
+			panic(errTypeRegistered)
 		}
 	}
 
-	backends.r = append(backends.r, &Backend{
+	backends.r = append(backends.r, &registeredBackend{
 		name,
 		backendType,
 		init,
 	})
 }
 
+// Get returns the backend registered for a particular type, it returns
+// an error if there is no registered backends for the given type.
 func Get(ctx context.Context, backendType string) (interface{}, error) {
 	for _, b := range backends.r {
 		if b.backendType == backendType {

+ 5 - 1
builder.Makefile

@@ -57,6 +57,10 @@ cross:
 test:
 	@gotestsum ./...
 
+lint:
+	golangci-lint run --timeout 10m0s ./...
+
+
 FORCE:
 
-.PHONY: all protos cli cross test
+.PHONY: all protos cli cross test lint

+ 1 - 3
cli/cmd/context.go

@@ -38,9 +38,7 @@ import (
 	"github.com/docker/api/context/store"
 )
 
-type CliContext struct {
-}
-
+// ContextCommand manages contexts
 func ContextCommand() *cobra.Command {
 	cmd := &cobra.Command{
 		Use:   "context",

+ 0 - 71
cli/cmd/example.go

@@ -1,71 +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 cmd
-
-import (
-	"context"
-	"encoding/json"
-	"os"
-
-	"github.com/pkg/errors"
-	"github.com/spf13/cobra"
-
-	v1 "github.com/docker/api/backend/v1"
-	"github.com/docker/api/client"
-)
-
-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()
-
-		c, err := client.New(ctx)
-		if err != nil {
-			return errors.Wrap(err, "cannot connect to backend")
-		}
-
-		info, err := c.BackendInformation(ctx, &v1.BackendInformationRequest{})
-		if err != nil {
-			return errors.Wrap(err, "fetch backend information")
-		}
-		enc := json.NewEncoder(os.Stdout)
-		enc.SetIndent("", " ")
-		return enc.Encode(info)
-	},
-}
-
-type backendAddressKey struct{}
-
-func BackendAddress(ctx context.Context) (string, error) {
-	v, ok := ctx.Value(backendAddressKey{}).(string)
-	if !ok {
-		return "", errors.New("no backend address key")
-	}
-	return v, nil
-}

+ 5 - 1
cli/cmd/exec.go

@@ -2,6 +2,7 @@ package cmd
 
 import (
 	"context"
+	"fmt"
 	"io"
 	"os"
 	"strings"
@@ -17,6 +18,7 @@ type execOpts struct {
 	Tty bool
 }
 
+// ExecCommand runs a command in a running container
 func ExecCommand() *cobra.Command {
 	var opts execOpts
 	cmd := &cobra.Command{
@@ -52,7 +54,9 @@ func runExec(ctx context.Context, opts execOpts, name string, command string) er
 			return err
 		}
 		defer func() {
-			con.Reset()
+			if err := con.Reset(); err != nil {
+				fmt.Println("Unable to close the console")
+			}
 		}()
 
 		stdout = con

+ 1 - 0
cli/cmd/logs.go

@@ -16,6 +16,7 @@ type logsOpts struct {
 	Tail   string
 }
 
+// LogsCommand fetches and shows logs of a container
 func LogsCommand() *cobra.Command {
 	var opts logsOpts
 	cmd := &cobra.Command{

+ 1 - 0
cli/cmd/ps.go

@@ -11,6 +11,7 @@ import (
 	"github.com/docker/api/client"
 )
 
+// PsCommand lists containers
 var PsCommand = cobra.Command{
 	Use:   "ps",
 	Short: "List containers",

+ 1 - 0
cli/cmd/run/run.go

@@ -36,6 +36,7 @@ import (
 	"github.com/docker/api/client"
 )
 
+// Command runs a container
 func Command() *cobra.Command {
 	var opts runOpts
 	cmd := &cobra.Command{

+ 3 - 1
cli/cmd/serve.go

@@ -20,6 +20,7 @@ type serveOpts struct {
 	address string
 }
 
+// ServeCommand returns the command to serve the API
 func ServeCommand() *cobra.Command {
 	var opts serveOpts
 	cmd := &cobra.Command{
@@ -42,9 +43,10 @@ func runServe(ctx context.Context, opts serveOpts) error {
 	if err != nil {
 		return errors.Wrap(err, "listen unix socket")
 	}
+	// nolint errcheck
 	defer listener.Close()
 
-	p := proxy.NewContainerApi()
+	p := proxy.NewContainerAPI()
 
 	containersv1.RegisterContainersServer(s, p)
 	cliv1.RegisterCliServer(s, &cliServer{

+ 1 - 2
cli/main.go

@@ -51,7 +51,7 @@ import (
 )
 
 type mainOpts struct {
-	apicontext.ContextFlags
+	apicontext.Flags
 	debug bool
 }
 
@@ -99,7 +99,6 @@ func main() {
 		cmd.ContextCommand(),
 		&cmd.PsCommand,
 		cmd.ServeCommand(),
-		&cmd.ExampleCommand,
 		run.Command(),
 		cmd.ExecCommand(),
 		cmd.LogsCommand(),

+ 3 - 1
client/client.go

@@ -41,7 +41,7 @@ import (
 	"github.com/docker/api/context/store"
 )
 
-// New returns a GRPC client
+// New returns a backend client
 func New(ctx context.Context) (*Client, error) {
 	currentContext := apicontext.CurrentContext(ctx)
 	s := store.ContextStore(ctx)
@@ -68,6 +68,7 @@ func New(ctx context.Context) (*Client, error) {
 
 }
 
+// Client is a multi-backend client
 type Client struct {
 	backendv1.BackendClient
 	cliv1.CliClient
@@ -78,6 +79,7 @@ type Client struct {
 	cc          containers.ContainerService
 }
 
+// ContainerService returns the backend service for the current context
 func (c *Client) ContainerService() containers.ContainerService {
 	return c.cc
 }

+ 9 - 12
compose/project.go

@@ -14,17 +14,14 @@ import (
 	"github.com/sirupsen/logrus"
 )
 
-const (
-	SecretInlineMark = "inline:"
-)
-
-var SupportedFilenames = []string{
+var supportedFilenames = []string{
 	"compose.yml",
 	"compose.yaml",
 	"docker-compose.yml",
 	"docker-compose.yaml",
 }
 
+// ProjectOptions configures a compose project
 type ProjectOptions struct {
 	Name        string
 	WorkDir     string
@@ -32,6 +29,7 @@ type ProjectOptions struct {
 	Environment []string
 }
 
+// Project represents a compose project with a name
 type Project struct {
 	types.Config
 	projectDir string
@@ -100,7 +98,7 @@ func getConfigPathFromOptions(options *ProjectOptions) ([]string, error) {
 
 	for {
 		var candidates []string
-		for _, n := range SupportedFilenames {
+		for _, n := range supportedFilenames {
 			f := filepath.Join(pwd, n)
 			if _, err := os.Stat(f); err == nil {
 				candidates = append(candidates, f)
@@ -116,7 +114,7 @@ func getConfigPathFromOptions(options *ProjectOptions) ([]string, error) {
 		}
 		parent := filepath.Dir(pwd)
 		if parent == pwd {
-			return nil, fmt.Errorf("Can't find a suitable configuration file in this directory or any parent. Is %q the right directory?", pwd)
+			return nil, fmt.Errorf("can't find a suitable configuration file in this directory or any parent. Is %q the right directory?", pwd)
 		}
 		pwd = parent
 	}
@@ -129,12 +127,11 @@ func parseConfigs(configPaths []string) ([]types.ConfigFile, error) {
 		var err error
 		if f == "-" {
 			return []types.ConfigFile{}, errors.New("reading compose file from stdin is not supported")
-		} else {
-			if _, err := os.Stat(f); err != nil {
-				return nil, err
-			}
-			b, err = ioutil.ReadFile(f)
 		}
+		if _, err := os.Stat(f); err != nil {
+			return nil, err
+		}
+		b, err = ioutil.ReadFile(f)
 		if err != nil {
 			return nil, err
 		}

+ 0 - 30
consts.go

@@ -1,30 +0,0 @@
-/*
-	Copyright (c) 2019 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 api
-
-const DockerContextKey = "DOCKER_CONTEXT_KEY"

+ 2 - 1
containers/api.go

@@ -11,7 +11,7 @@ type Container struct {
 	Status      string
 	Image       string
 	Command     string
-	CpuTime     uint64
+	CPUTime     uint64
 	MemoryUsage uint64
 	MemoryLimit uint64
 	PidsCurrent uint64
@@ -37,6 +37,7 @@ type ContainerConfig struct {
 	Ports []Port
 }
 
+// LogsRequest contains configuration about a log request
 type LogsRequest struct {
 	Follow bool
 	Tail   string

+ 3 - 0
context/config.go

@@ -34,6 +34,7 @@ import (
 	"path/filepath"
 )
 
+// LoadConfigFile loads the docker configuration
 func LoadConfigFile(configDir string, configFileName string) (*ConfigFile, error) {
 	filename := filepath.Join(configDir, configFileName)
 	configFile := &ConfigFile{
@@ -45,6 +46,7 @@ func LoadConfigFile(configDir string, configFileName string) (*ConfigFile, error
 		if err != nil {
 			return nil, fmt.Errorf("can't read %s: %w", filename, err)
 		}
+		// nolint errcheck
 		defer file.Close()
 		err = json.NewDecoder(file).Decode(&configFile)
 		if err != nil {
@@ -59,6 +61,7 @@ func LoadConfigFile(configDir string, configFileName string) (*ConfigFile, error
 	return configFile, nil
 }
 
+// ConfigFile contains the current context from the docker configuration file
 type ConfigFile struct {
 	Filename       string `json:"-"` // Note: for internal use only
 	CurrentContext string `json:"currentContext,omitempty"`

+ 4 - 1
context/context.go

@@ -6,10 +6,13 @@ import (
 	"golang.org/x/net/context"
 )
 
-const KEY = "context_key"
+// Key is the key where the current docker context is stored in the metadata
+// of a gRPC request
+const Key = "context_key"
 
 type currentContextKey struct{}
 
+// WithCurrentContext sets the name of the current docker context
 func WithCurrentContext(ctx gocontext.Context, contextName string) context.Context {
 	return context.WithValue(ctx, currentContextKey{}, contextName)
 }

+ 4 - 2
context/flags.go

@@ -41,12 +41,14 @@ const (
 	configFileDir  = ".docker"
 )
 
-type ContextFlags struct {
+// Flags are the global cli flags
+type Flags struct {
 	Config  string
 	Context string
 }
 
-func (c *ContextFlags) AddFlags(flags *pflag.FlagSet) {
+// AddFlags adds persistent (global) flags
+func (c *Flags) 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")
 }

+ 17 - 10
context/store/store.go

@@ -47,16 +47,18 @@ const (
 
 type contextStoreKey struct{}
 
+// WithContextStore adds the store to the context
 func WithContextStore(ctx context.Context, store Store) context.Context {
 	return context.WithValue(ctx, contextStoreKey{}, store)
 }
 
+// ContextStore returns the store from the context
 func ContextStore(ctx context.Context) Store {
 	s, _ := ctx.Value(contextStoreKey{}).(Store)
 	return s
 }
 
-// Store
+// Store is the context store
 type Store interface {
 	// Get returns the context with name, it returns an error if the  context
 	// doesn't exist
@@ -74,16 +76,18 @@ type store struct {
 	root string
 }
 
-type StoreOpt func(*store)
+// Opt is a functional option for the store
+type Opt func(*store)
 
-func WithRoot(root string) StoreOpt {
+// WithRoot sets a new root to the store
+func WithRoot(root string) Opt {
 	return func(s *store) {
 		s.root = root
 	}
 }
 
-// New returns a configured context store
-func New(opts ...StoreOpt) (Store, error) {
+// New returns a configured context store with $HOME/.docker as root
+func New(opts ...Opt) (Store, error) {
 	home, err := os.UserHomeDir()
 	if err != nil {
 		return nil, err
@@ -182,7 +186,7 @@ func (s *store) Create(name string, data TypedContext) 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)
+		return fmt.Errorf("context %q already exists", name)
 	}
 
 	err := os.Mkdir(metaDir, 0755)
@@ -191,15 +195,15 @@ func (s *store) Create(name string, data TypedContext) error {
 	}
 
 	if data.Data == nil {
-		data.Data = DummyContext{}
+		data.Data = dummyContext{}
 	}
 
 	meta := Metadata{
 		Name:     name,
 		Metadata: data,
 		Endpoints: map[string]interface{}{
-			"docker":    DummyContext{},
-			(data.Type): DummyContext{},
+			"docker":    dummyContext{},
+			(data.Type): dummyContext{},
 		},
 	}
 
@@ -237,8 +241,9 @@ func contextdirOf(name string) string {
 	return digest.FromString(name).Encoded()
 }
 
-type DummyContext struct{}
+type dummyContext struct{}
 
+// Metadata represents the docker context metadata
 type Metadata struct {
 	Name      string                 `json:",omitempty"`
 	Metadata  TypedContext           `json:",omitempty"`
@@ -257,12 +262,14 @@ type untypedContext struct {
 	Type        string          `json:",omitempty"`
 }
 
+// TypedContext is a context with a type (moby, aci, etc...)
 type TypedContext struct {
 	Type        string      `json:",omitempty"`
 	Description string      `json:",omitempty"`
 	Data        interface{} `json:",omitempty"`
 }
 
+// AciContext is the context for ACI
 type AciContext struct {
 	SubscriptionID string `json:",omitempty"`
 	Location       string `json:",omitempty"`

+ 2 - 1
context/store/store_test.go

@@ -55,7 +55,8 @@ func (suite *StoreTestSuite) BeforeTest(suiteName, testName string) {
 }
 
 func (suite *StoreTestSuite) AfterTest(suiteName, testName string) {
-	os.RemoveAll(suite.dir)
+	err := os.RemoveAll(suite.dir)
+	require.Nil(suite.T(), err)
 }
 
 func (suite *StoreTestSuite) TestCreate() {

+ 1 - 5
example/backend.go

@@ -13,14 +13,10 @@ type containerService struct{}
 
 func init() {
 	backend.Register("example", "example", func(ctx context.Context) (interface{}, error) {
-		return New(), nil
+		return &containerService{}, nil
 	})
 }
 
-func New() containers.ContainerService {
-	return &containerService{}
-}
-
 func (cs *containerService) List(ctx context.Context) ([]containers.Container, error) {
 	return []containers.Container{
 		{

+ 1 - 1
go.mod

@@ -1,6 +1,6 @@
 module github.com/docker/api
 
-go 1.13
+go 1.14
 
 require (
 	github.com/Azure/azure-sdk-for-go v42.0.0+incompatible

+ 0 - 7
scripts/setup/install-go-gen

@@ -1,7 +0,0 @@
-#!/usr/bin/env bash
-
-go get -u github.com/gogo/protobuf/proto
-go get -u github.com/gogo/protobuf/jsonpb
-go get -u github.com/golang/protobuf/protoc-gen-go
-go get -u github.com/stevvooe/protobuild
-go get -u gotest.tools/gotestsum

+ 0 - 61
scripts/setup/install-protobuf

@@ -1,61 +0,0 @@
-#!/usr/bin/env bash
-
-#   Copyright The containerd Authors.
-
-#   Licensed under the Apache License, Version 2.0 (the "License");
-#   you may not use this file except in compliance with the License.
-#   You may obtain a copy of the License at
-
-#       http://www.apache.org/licenses/LICENSE-2.0
-
-#   Unless required by applicable law or agreed to in writing, software
-#   distributed under the License is distributed on an "AS IS" BASIS,
-#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-#   See the License for the specific language governing permissions and
-#   limitations under the License.
-
-#
-# Downloads and installs protobuf
-#
-set -eu -o pipefail
-
-PROTOBUF_VERSION=3.11.4
-GOARCH=$(go env GOARCH)
-GOOS=$(go env GOOS)
-PROTOBUF_DIR=$(mktemp -d)
-
-case $GOARCH in
-
-arm64)
-	wget -O $PROTOBUF_DIR/protobuf "https://github.com/google/protobuf/releases/download/v$PROTOBUF_VERSION/protoc-$PROTOBUF_VERSION-linux-aarch64.zip"
-	unzip $PROTOBUF_DIR/protobuf -d /usr/local
-	;;
-
-amd64 | 386)
-	if [ "$GOOS" = windows ]; then
-		wget -O $PROTOBUF_DIR/protobuf "https://github.com/google/protobuf/releases/download/v$PROTOBUF_VERSION/protoc-$PROTOBUF_VERSION-win32.zip"
-	elif [ "$GOOS" = linux ]; then
-		wget -O $PROTOBUF_DIR/protobuf "https://github.com/google/protobuf/releases/download/v$PROTOBUF_VERSION/protoc-$PROTOBUF_VERSION-linux-x86_64.zip"
-	elif [ "$GOOS" = darwin ]; then
-		curl -Lo $PROTOBUF_DIR/protobuf "https://github.com/google/protobuf/releases/download/v$PROTOBUF_VERSION/protoc-$PROTOBUF_VERSION-osx-x86_64.zip"
-	fi
-	unzip $PROTOBUF_DIR/protobuf -x readme.txt -d /usr/local
-	;;
-
-ppc64le)
-	wget -O $PROTOBUF_DIR/protobuf "https://github.com/google/protobuf/releases/download/v$PROTOBUF_VERSION/protoc-$PROTOBUF_VERSION-linux-ppcle_64.zip"
-	unzip $PROTOBUF_DIR/protobuf -d /usr/local
-	;;
-*)
-	wget -O $PROTOBUF_DIR/protobuf "https://github.com/google/protobuf/releases/download/v$PROTOBUF_VERSION/protobuf-cpp-$PROTOBUF_VERSION.zip"
-	unzip $PROTOBUF_DIR/protobuf -d /usr/src/protobuf
-	cd /usr/src/protobuf/protobuf-$PROTOBUF_VERSION
-	./autogen.sh
-	./configure --disable-shared
-	make
-	make check
-	make install
-	ldconfig
-	;;
-esac
-rm -rf $PROTOBUF_DIR

+ 14 - 11
server/proxy/proxy.go

@@ -10,22 +10,25 @@ import (
 
 type clientKey struct{}
 
+// WithClient adds the client to the context
 func WithClient(ctx context.Context, c *client.Client) (context.Context, error) {
 	return context.WithValue(ctx, clientKey{}, c), nil
 }
 
+// Client returns the client from the context
 func Client(ctx context.Context) *client.Client {
 	c, _ := ctx.Value(clientKey{}).(*client.Client)
 	return c
 }
 
-func NewContainerApi() v1.ContainersServer {
-	return &proxyContainerApi{}
+// NewContainerAPI creates a proxy container server
+func NewContainerAPI() v1.ContainersServer {
+	return &proxyContainerAPI{}
 }
 
-type proxyContainerApi struct{}
+type proxyContainerAPI struct{}
 
-func (p *proxyContainerApi) List(ctx context.Context, _ *v1.ListRequest) (*v1.ListResponse, error) {
+func (p *proxyContainerAPI) List(ctx context.Context, _ *v1.ListRequest) (*v1.ListResponse, error) {
 	client := Client(ctx)
 
 	c, err := client.ContainerService().List(ctx)
@@ -46,7 +49,7 @@ func (p *proxyContainerApi) List(ctx context.Context, _ *v1.ListRequest) (*v1.Li
 	return response, nil
 }
 
-func (p *proxyContainerApi) Create(ctx context.Context, request *v1.CreateRequest) (*v1.CreateResponse, error) {
+func (p *proxyContainerAPI) Create(ctx context.Context, request *v1.CreateRequest) (*v1.CreateResponse, error) {
 	client := Client(ctx)
 
 	err := client.ContainerService().Run(ctx, containers.ContainerConfig{
@@ -57,26 +60,26 @@ func (p *proxyContainerApi) Create(ctx context.Context, request *v1.CreateReques
 	return &v1.CreateResponse{}, err
 }
 
-func (p *proxyContainerApi) Start(_ context.Context, _ *v1.StartRequest) (*v1.StartResponse, error) {
+func (p *proxyContainerAPI) Start(_ context.Context, _ *v1.StartRequest) (*v1.StartResponse, error) {
 	panic("not implemented") // TODO: Implement
 }
 
-func (p *proxyContainerApi) Stop(_ context.Context, _ *v1.StopRequest) (*v1.StopResponse, error) {
+func (p *proxyContainerAPI) Stop(_ context.Context, _ *v1.StopRequest) (*v1.StopResponse, error) {
 	panic("not implemented") // TODO: Implement
 }
 
-func (p *proxyContainerApi) Kill(_ context.Context, _ *v1.KillRequest) (*v1.KillResponse, error) {
+func (p *proxyContainerAPI) Kill(_ context.Context, _ *v1.KillRequest) (*v1.KillResponse, error) {
 	panic("not implemented") // TODO: Implement
 }
 
-func (p *proxyContainerApi) Delete(_ context.Context, _ *v1.DeleteRequest) (*v1.DeleteResponse, error) {
+func (p *proxyContainerAPI) Delete(_ context.Context, _ *v1.DeleteRequest) (*v1.DeleteResponse, error) {
 	panic("not implemented") // TODO: Implement
 }
 
-func (p *proxyContainerApi) Update(_ context.Context, _ *v1.UpdateRequest) (*v1.UpdateResponse, error) {
+func (p *proxyContainerAPI) Update(_ context.Context, _ *v1.UpdateRequest) (*v1.UpdateResponse, error) {
 	panic("not implemented") // TODO: Implement
 }
 
-func (p *proxyContainerApi) Exec(_ context.Context, _ *v1.ExecRequest) (*v1.ExecResponse, error) {
+func (p *proxyContainerAPI) Exec(_ context.Context, _ *v1.ExecRequest) (*v1.ExecResponse, error) {
 	panic("not implemented") // TODO: Implement
 }

+ 1 - 1
server/server.go

@@ -71,7 +71,7 @@ func unaryMeta(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo,
 		return nil, errors.New("missing metadata")
 	}
 
-	key := md[apicontext.KEY]
+	key := md[apicontext.Key]
 
 	if len(key) == 1 {
 		s, err := store.New()