mirror of https://github.com/docker/compose.git
Compose as a cli plugin
Signed-off-by: Guillaume Tardif <guillaume.tardif@gmail.com> Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
This commit is contained in:
parent
85af8cdaaa
commit
1dc97e8c4b
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
Copyright 2020 Docker Compose CLI 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.
|
||||
*/
|
||||
|
||||
package compose
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
)
|
||||
|
||||
// ServiceDelegator implements Service by delegating to another implementation. This allows lazy init
|
||||
type ServiceDelegator struct {
|
||||
Delegate Service
|
||||
}
|
||||
|
||||
//Build implements Service interface
|
||||
func (s *ServiceDelegator) Build(ctx context.Context, project *types.Project, options BuildOptions) error {
|
||||
return s.Delegate.Build(ctx, project, options)
|
||||
}
|
||||
|
||||
//Push implements Service interface
|
||||
func (s *ServiceDelegator) Push(ctx context.Context, project *types.Project, options PushOptions) error {
|
||||
return s.Delegate.Push(ctx, project, options)
|
||||
}
|
||||
|
||||
//Pull implements Service interface
|
||||
func (s *ServiceDelegator) Pull(ctx context.Context, project *types.Project, options PullOptions) error {
|
||||
return s.Delegate.Pull(ctx, project, options)
|
||||
}
|
||||
|
||||
//Create implements Service interface
|
||||
func (s *ServiceDelegator) Create(ctx context.Context, project *types.Project, options CreateOptions) error {
|
||||
return s.Delegate.Create(ctx, project, options)
|
||||
}
|
||||
|
||||
//Start implements Service interface
|
||||
func (s *ServiceDelegator) Start(ctx context.Context, project *types.Project, options StartOptions) error {
|
||||
return s.Delegate.Start(ctx, project, options)
|
||||
}
|
||||
|
||||
//Restart implements Service interface
|
||||
func (s *ServiceDelegator) Restart(ctx context.Context, project *types.Project, options RestartOptions) error {
|
||||
return s.Delegate.Restart(ctx, project, options)
|
||||
}
|
||||
|
||||
//Stop implements Service interface
|
||||
func (s *ServiceDelegator) Stop(ctx context.Context, project *types.Project, options StopOptions) error {
|
||||
return s.Delegate.Stop(ctx, project, options)
|
||||
}
|
||||
|
||||
//Up implements Service interface
|
||||
func (s *ServiceDelegator) Up(ctx context.Context, project *types.Project, options UpOptions) error {
|
||||
return s.Delegate.Up(ctx, project, options)
|
||||
}
|
||||
|
||||
//Down implements Service interface
|
||||
func (s *ServiceDelegator) Down(ctx context.Context, project string, options DownOptions) error {
|
||||
return s.Delegate.Down(ctx, project, options)
|
||||
}
|
||||
|
||||
//Logs implements Service interface
|
||||
func (s *ServiceDelegator) Logs(ctx context.Context, project string, consumer LogConsumer, options LogOptions) error {
|
||||
return s.Delegate.Logs(ctx, project, consumer, options)
|
||||
}
|
||||
|
||||
//Ps implements Service interface
|
||||
func (s *ServiceDelegator) Ps(ctx context.Context, project string, options PsOptions) ([]ContainerSummary, error) {
|
||||
return s.Delegate.Ps(ctx, project, options)
|
||||
}
|
||||
|
||||
//List implements Service interface
|
||||
func (s *ServiceDelegator) List(ctx context.Context, options ListOptions) ([]Stack, error) {
|
||||
return s.Delegate.List(ctx, options)
|
||||
}
|
||||
|
||||
//Convert implements Service interface
|
||||
func (s *ServiceDelegator) Convert(ctx context.Context, project *types.Project, options ConvertOptions) ([]byte, error) {
|
||||
return s.Delegate.Convert(ctx, project, options)
|
||||
}
|
||||
|
||||
//Kill implements Service interface
|
||||
func (s *ServiceDelegator) Kill(ctx context.Context, project *types.Project, options KillOptions) error {
|
||||
return s.Delegate.Kill(ctx, project, options)
|
||||
}
|
||||
|
||||
//RunOneOffContainer implements Service interface
|
||||
func (s *ServiceDelegator) RunOneOffContainer(ctx context.Context, project *types.Project, options RunOptions) (int, error) {
|
||||
return s.Delegate.RunOneOffContainer(ctx, project, options)
|
||||
}
|
||||
|
||||
//Remove implements Service interface
|
||||
func (s *ServiceDelegator) Remove(ctx context.Context, project *types.Project, options RemoveOptions) ([]string, error) {
|
||||
return s.Delegate.Remove(ctx, project, options)
|
||||
}
|
||||
|
||||
//Exec implements Service interface
|
||||
func (s *ServiceDelegator) Exec(ctx context.Context, project *types.Project, options RunOptions) error {
|
||||
return s.Delegate.Exec(ctx, project, options)
|
||||
}
|
||||
|
||||
//Pause implements Service interface
|
||||
func (s *ServiceDelegator) Pause(ctx context.Context, project string, options PauseOptions) error {
|
||||
return s.Delegate.Pause(ctx, project, options)
|
||||
}
|
||||
|
||||
//UnPause implements Service interface
|
||||
func (s *ServiceDelegator) UnPause(ctx context.Context, project string, options PauseOptions) error {
|
||||
return s.Delegate.UnPause(ctx, project, options)
|
||||
}
|
||||
|
||||
//Top implements Service interface
|
||||
func (s *ServiceDelegator) Top(ctx context.Context, project string, services []string) ([]ContainerProcSummary, error) {
|
||||
return s.Delegate.Top(ctx, project, services)
|
||||
}
|
||||
|
||||
//Events implements Service interface
|
||||
func (s *ServiceDelegator) Events(ctx context.Context, project string, options EventsOptions) error {
|
||||
return s.Delegate.Events(ctx, project, options)
|
||||
}
|
||||
|
||||
//Port implements Service interface
|
||||
func (s *ServiceDelegator) Port(ctx context.Context, project string, service string, port int, options PortOptions) (string, int, error) {
|
||||
return s.Delegate.Port(ctx, project, service, port, options)
|
||||
}
|
||||
|
||||
//Images implements Service interface
|
||||
func (s *ServiceDelegator) Images(ctx context.Context, project string, options ImagesOptions) ([]ImageSummary, error) {
|
||||
return s.Delegate.Images(ctx, project, options)
|
||||
}
|
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
Copyright 2020 Docker Compose CLI 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.
|
||||
*/
|
||||
|
||||
package compose
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
|
||||
"github.com/docker/compose-cli/api/errdefs"
|
||||
)
|
||||
|
||||
// NoImpl implements Service to return ErrNotImplemented
|
||||
type NoImpl struct{}
|
||||
|
||||
//Build implements Service interface
|
||||
func (s NoImpl) Build(ctx context.Context, project *types.Project, options BuildOptions) error {
|
||||
return errdefs.ErrNotImplemented
|
||||
}
|
||||
|
||||
//Push implements Service interface
|
||||
func (s NoImpl) Push(ctx context.Context, project *types.Project, options PushOptions) error {
|
||||
return errdefs.ErrNotImplemented
|
||||
}
|
||||
|
||||
//Pull implements Service interface
|
||||
func (s NoImpl) Pull(ctx context.Context, project *types.Project, options PullOptions) error {
|
||||
return errdefs.ErrNotImplemented
|
||||
}
|
||||
|
||||
//Create implements Service interface
|
||||
func (s NoImpl) Create(ctx context.Context, project *types.Project, options CreateOptions) error {
|
||||
return errdefs.ErrNotImplemented
|
||||
}
|
||||
|
||||
//Start implements Service interface
|
||||
func (s NoImpl) Start(ctx context.Context, project *types.Project, options StartOptions) error {
|
||||
return errdefs.ErrNotImplemented
|
||||
}
|
||||
|
||||
//Restart implements Service interface
|
||||
func (s NoImpl) Restart(ctx context.Context, project *types.Project, options RestartOptions) error {
|
||||
return errdefs.ErrNotImplemented
|
||||
}
|
||||
|
||||
//Stop implements Service interface
|
||||
func (s NoImpl) Stop(ctx context.Context, project *types.Project, options StopOptions) error {
|
||||
return errdefs.ErrNotImplemented
|
||||
}
|
||||
|
||||
//Up implements Service interface
|
||||
func (s NoImpl) Up(ctx context.Context, project *types.Project, options UpOptions) error {
|
||||
return errdefs.ErrNotImplemented
|
||||
}
|
||||
|
||||
//Down implements Service interface
|
||||
func (s NoImpl) Down(ctx context.Context, project string, options DownOptions) error {
|
||||
return errdefs.ErrNotImplemented
|
||||
}
|
||||
|
||||
//Logs implements Service interface
|
||||
func (s NoImpl) Logs(ctx context.Context, project string, consumer LogConsumer, options LogOptions) error {
|
||||
return errdefs.ErrNotImplemented
|
||||
}
|
||||
|
||||
//Ps implements Service interface
|
||||
func (s NoImpl) Ps(ctx context.Context, project string, options PsOptions) ([]ContainerSummary, error) {
|
||||
return nil, errdefs.ErrNotImplemented
|
||||
}
|
||||
|
||||
//List implements Service interface
|
||||
func (s NoImpl) List(ctx context.Context, options ListOptions) ([]Stack, error) {
|
||||
return nil, errdefs.ErrNotImplemented
|
||||
}
|
||||
|
||||
//Convert implements Service interface
|
||||
func (s NoImpl) Convert(ctx context.Context, project *types.Project, options ConvertOptions) ([]byte, error) {
|
||||
return nil, errdefs.ErrNotImplemented
|
||||
}
|
||||
|
||||
//Kill implements Service interface
|
||||
func (s NoImpl) Kill(ctx context.Context, project *types.Project, options KillOptions) error {
|
||||
return errdefs.ErrNotImplemented
|
||||
}
|
||||
|
||||
//RunOneOffContainer implements Service interface
|
||||
func (s NoImpl) RunOneOffContainer(ctx context.Context, project *types.Project, options RunOptions) (int, error) {
|
||||
return 0, errdefs.ErrNotImplemented
|
||||
}
|
||||
|
||||
//Remove implements Service interface
|
||||
func (s NoImpl) Remove(ctx context.Context, project *types.Project, options RemoveOptions) ([]string, error) {
|
||||
return nil, errdefs.ErrNotImplemented
|
||||
}
|
||||
|
||||
//Exec implements Service interface
|
||||
func (s NoImpl) Exec(ctx context.Context, project *types.Project, options RunOptions) error {
|
||||
return errdefs.ErrNotImplemented
|
||||
}
|
||||
|
||||
//Pause implements Service interface
|
||||
func (s NoImpl) Pause(ctx context.Context, project string, options PauseOptions) error {
|
||||
return errdefs.ErrNotImplemented
|
||||
}
|
||||
|
||||
//UnPause implements Service interface
|
||||
func (s NoImpl) UnPause(ctx context.Context, project string, options PauseOptions) error {
|
||||
return errdefs.ErrNotImplemented
|
||||
}
|
||||
|
||||
//Top implements Service interface
|
||||
func (s NoImpl) Top(ctx context.Context, project string, services []string) ([]ContainerProcSummary, error) {
|
||||
return nil, errdefs.ErrNotImplemented
|
||||
}
|
||||
|
||||
//Events implements Service interface
|
||||
func (s NoImpl) Events(ctx context.Context, project string, options EventsOptions) error {
|
||||
return errdefs.ErrNotImplemented
|
||||
}
|
||||
|
||||
//Port implements Service interface
|
||||
func (s NoImpl) Port(ctx context.Context, project string, service string, port int, options PortOptions) (string, int, error) {
|
||||
return "", 0, errdefs.ErrNotImplemented
|
||||
}
|
||||
|
||||
//Images implements Service interface
|
||||
func (s NoImpl) Images(ctx context.Context, project string, options ImagesOptions) ([]ImageSummary, error) {
|
||||
return nil, errdefs.ErrNotImplemented
|
||||
}
|
|
@ -57,6 +57,10 @@ protos:
|
|||
cli:
|
||||
GOOS=${GOOS} GOARCH=${GOARCH} $(GO_BUILD) $(TAGS) -o $(BINARY_WITH_EXTENSION) ./cli
|
||||
|
||||
.PHONY: compose-plugin
|
||||
compose-plugin:
|
||||
GOOS=${GOOS} GOARCH=${GOARCH} $(GO_BUILD) $(TAGS) -o ./bin/docker-compose .
|
||||
|
||||
.PHONY: cross
|
||||
cross:
|
||||
GOOS=linux GOARCH=amd64 $(GO_BUILD) $(TAGS) -o $(BINARY)-linux-amd64 ./cli
|
||||
|
|
|
@ -123,6 +123,14 @@ func Command(contextType string, backend compose.Service) *cobra.Command {
|
|||
return fmt.Errorf("unknown docker command: %q", "compose "+args[0])
|
||||
},
|
||||
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
|
||||
parent := cmd.Root()
|
||||
parentPrerun := parent.PersistentPreRunE
|
||||
if parentPrerun != nil {
|
||||
err := parentPrerun(cmd, args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if noAnsi {
|
||||
if ansi != "auto" {
|
||||
return errors.New(`cannot specify DEPRECATED "--no-ansi" and "--ansi". Please use only "--ansi"`)
|
||||
|
|
|
@ -17,9 +17,11 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/pflag"
|
||||
|
||||
"github.com/docker/compose-cli/api/config"
|
||||
|
@ -44,3 +46,36 @@ func confDir() string {
|
|||
home, _ := os.UserHomeDir()
|
||||
return filepath.Join(home, config.ConfigFileDir)
|
||||
}
|
||||
|
||||
// GetCurrentContext get current context based on opts, env vars
|
||||
func GetCurrentContext(contextOpt string, configDir string, hosts []string) string {
|
||||
// host and context flags cannot be both set at the same time -- the local backend enforces this when resolving hostname
|
||||
// -H flag disables context --> set default as current
|
||||
if len(hosts) > 0 {
|
||||
return "default"
|
||||
}
|
||||
// DOCKER_HOST disables context --> set default as current
|
||||
if _, present := os.LookupEnv("DOCKER_HOST"); present {
|
||||
return "default"
|
||||
}
|
||||
res := contextOpt
|
||||
if res == "" {
|
||||
// check if DOCKER_CONTEXT env variable was set
|
||||
if _, present := os.LookupEnv("DOCKER_CONTEXT"); present {
|
||||
res = os.Getenv("DOCKER_CONTEXT")
|
||||
}
|
||||
|
||||
if res == "" {
|
||||
config, err := config.LoadFile(configDir)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, errors.Wrap(err, "WARNING"))
|
||||
return "default"
|
||||
}
|
||||
res = config.CurrentContext
|
||||
}
|
||||
}
|
||||
if res == "" {
|
||||
res = "default"
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
Copyright 2020 Docker Compose CLI 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.
|
||||
*/
|
||||
|
||||
package config
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"gotest.tools/v3/assert"
|
||||
|
||||
"github.com/docker/compose-cli/api/config"
|
||||
)
|
||||
|
||||
var contextSetConfig = []byte(`{
|
||||
"currentContext": "some-context"
|
||||
}`)
|
||||
|
||||
func TestDetermineCurrentContext(t *testing.T) {
|
||||
d, err := ioutil.TempDir("", "")
|
||||
// nolint errcheck
|
||||
defer os.RemoveAll(d)
|
||||
assert.NilError(t, err)
|
||||
err = ioutil.WriteFile(filepath.Join(d, config.ConfigFileName), contextSetConfig, 0644)
|
||||
assert.NilError(t, err)
|
||||
|
||||
// If nothing set, fallback to default
|
||||
c := GetCurrentContext("", "", []string{})
|
||||
assert.Equal(t, c, "default")
|
||||
|
||||
// If context flag set, use that
|
||||
c = GetCurrentContext("other-context", "", []string{})
|
||||
assert.Equal(t, c, "other-context")
|
||||
|
||||
// If no context flag, use config
|
||||
c = GetCurrentContext("", d, []string{})
|
||||
assert.Equal(t, c, "some-context")
|
||||
|
||||
// Ensure context flag overrides config
|
||||
c = GetCurrentContext("other-context", d, []string{})
|
||||
assert.Equal(t, "other-context", c)
|
||||
|
||||
// Ensure host flag overrides context
|
||||
c = GetCurrentContext("other-context", d, []string{"hostname"})
|
||||
assert.Equal(t, "default", c)
|
||||
}
|
62
cli/main.go
62
cli/main.go
|
@ -29,9 +29,6 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/docker/cli/cli"
|
||||
"github.com/docker/cli/cli/command"
|
||||
cliconfig "github.com/docker/cli/cli/config"
|
||||
cliflags "github.com/docker/cli/cli/flags"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
|
@ -48,6 +45,7 @@ import (
|
|||
"github.com/docker/compose-cli/cli/cmd/logout"
|
||||
"github.com/docker/compose-cli/cli/cmd/run"
|
||||
"github.com/docker/compose-cli/cli/cmd/volume"
|
||||
cliconfig "github.com/docker/compose-cli/cli/config"
|
||||
"github.com/docker/compose-cli/cli/metrics"
|
||||
"github.com/docker/compose-cli/cli/mobycli"
|
||||
cliopts "github.com/docker/compose-cli/cli/options"
|
||||
|
@ -62,7 +60,6 @@ import (
|
|||
|
||||
var (
|
||||
contextAgnosticCommands = map[string]struct{}{
|
||||
"compose": {},
|
||||
"context": {},
|
||||
"login": {},
|
||||
"logout": {},
|
||||
|
@ -198,7 +195,7 @@ func main() {
|
|||
configDir := opts.Config
|
||||
config.WithDir(configDir)
|
||||
|
||||
currentContext := determineCurrentContext(opts.Context, configDir, opts.Hosts)
|
||||
currentContext := cliconfig.GetCurrentContext(opts.Context, configDir, opts.Hosts)
|
||||
apicontext.WithCurrentContext(currentContext)
|
||||
|
||||
s, err := store.New(configDir)
|
||||
|
@ -234,27 +231,7 @@ func main() {
|
|||
func getBackend(ctype string, configDir string, opts cliopts.GlobalOpts) (backend.Service, error) {
|
||||
switch ctype {
|
||||
case store.DefaultContextType, store.LocalContextType:
|
||||
configFile, err := cliconfig.Load(configDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
options := cliflags.CommonOptions{
|
||||
Context: opts.Context,
|
||||
Debug: opts.Debug,
|
||||
Hosts: opts.Hosts,
|
||||
LogLevel: opts.LogLevel,
|
||||
}
|
||||
|
||||
if opts.TLSVerify {
|
||||
options.TLS = opts.TLS
|
||||
options.TLSVerify = opts.TLSVerify
|
||||
options.TLSOptions = opts.TLSOptions
|
||||
}
|
||||
apiClient, err := command.NewAPIClientFromFlags(&options, configFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return local.NewService(apiClient), nil
|
||||
return local.GetLocalBackend(configDir, opts)
|
||||
}
|
||||
service, err := backend.Get(ctype)
|
||||
if errdefs.IsNotFoundError(err) {
|
||||
|
@ -311,6 +288,7 @@ func exit(ctx string, err error, ctype string) {
|
|||
}
|
||||
|
||||
if compose.Warning != "" {
|
||||
logrus.Warn(err)
|
||||
fmt.Fprintln(os.Stderr, compose.Warning)
|
||||
}
|
||||
|
||||
|
@ -354,38 +332,6 @@ func newSigContext() (context.Context, func()) {
|
|||
return ctx, cancel
|
||||
}
|
||||
|
||||
func determineCurrentContext(flag string, configDir string, hosts []string) string {
|
||||
// host and context flags cannot be both set at the same time -- the local backend enforces this when resolving hostname
|
||||
// -H flag disables context --> set default as current
|
||||
if len(hosts) > 0 {
|
||||
return "default"
|
||||
}
|
||||
// DOCKER_HOST disables context --> set default as current
|
||||
if _, present := os.LookupEnv("DOCKER_HOST"); present {
|
||||
return "default"
|
||||
}
|
||||
res := flag
|
||||
if res == "" {
|
||||
// check if DOCKER_CONTEXT env variable was set
|
||||
if _, present := os.LookupEnv("DOCKER_CONTEXT"); present {
|
||||
res = os.Getenv("DOCKER_CONTEXT")
|
||||
}
|
||||
|
||||
if res == "" {
|
||||
config, err := config.LoadFile(configDir)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, errors.Wrap(err, "WARNING"))
|
||||
return "default"
|
||||
}
|
||||
res = config.CurrentContext
|
||||
}
|
||||
}
|
||||
if res == "" {
|
||||
res = "default"
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func walk(c *cobra.Command, f func(*cobra.Command)) {
|
||||
f(c)
|
||||
for _, c := range c.Commands() {
|
||||
|
|
|
@ -17,53 +17,17 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"gotest.tools/v3/assert"
|
||||
|
||||
"github.com/docker/compose-cli/api/config"
|
||||
"github.com/docker/compose-cli/cli/cmd"
|
||||
"github.com/docker/compose-cli/cli/cmd/context"
|
||||
"github.com/docker/compose-cli/cli/cmd/login"
|
||||
"github.com/docker/compose-cli/cli/cmd/run"
|
||||
)
|
||||
|
||||
var contextSetConfig = []byte(`{
|
||||
"currentContext": "some-context"
|
||||
}`)
|
||||
|
||||
func TestDetermineCurrentContext(t *testing.T) {
|
||||
d, err := ioutil.TempDir("", "")
|
||||
// nolint errcheck
|
||||
defer os.RemoveAll(d)
|
||||
assert.NilError(t, err)
|
||||
err = ioutil.WriteFile(filepath.Join(d, config.ConfigFileName), contextSetConfig, 0644)
|
||||
assert.NilError(t, err)
|
||||
|
||||
// If nothing set, fallback to default
|
||||
c := determineCurrentContext("", "", []string{})
|
||||
assert.Equal(t, c, "default")
|
||||
|
||||
// If context flag set, use that
|
||||
c = determineCurrentContext("other-context", "", []string{})
|
||||
assert.Equal(t, c, "other-context")
|
||||
|
||||
// If no context flag, use config
|
||||
c = determineCurrentContext("", d, []string{})
|
||||
assert.Equal(t, c, "some-context")
|
||||
|
||||
// Ensure context flag overrides config
|
||||
c = determineCurrentContext("other-context", d, []string{})
|
||||
assert.Equal(t, "other-context", c)
|
||||
|
||||
// Ensure host flag overrides context
|
||||
c = determineCurrentContext("other-context", d, []string{"hostname"})
|
||||
assert.Equal(t, "default", c)
|
||||
}
|
||||
|
||||
func TestCheckOwnCommand(t *testing.T) {
|
||||
assert.Assert(t, isContextAgnosticCommand(login.Command()))
|
||||
assert.Assert(t, isContextAgnosticCommand(context.Command()))
|
||||
|
|
|
@ -19,7 +19,9 @@ package local
|
|||
import (
|
||||
"os"
|
||||
|
||||
"github.com/docker/cli/cli/command"
|
||||
cliconfig "github.com/docker/cli/cli/config"
|
||||
cliflags "github.com/docker/cli/cli/flags"
|
||||
"github.com/docker/docker/client"
|
||||
|
||||
"github.com/docker/compose-cli/api/backend"
|
||||
|
@ -28,6 +30,7 @@ import (
|
|||
"github.com/docker/compose-cli/api/resources"
|
||||
"github.com/docker/compose-cli/api/secrets"
|
||||
"github.com/docker/compose-cli/api/volumes"
|
||||
cliopts "github.com/docker/compose-cli/cli/options"
|
||||
local_compose "github.com/docker/compose-cli/local/compose"
|
||||
)
|
||||
|
||||
|
@ -47,6 +50,31 @@ func NewService(apiClient client.APIClient) backend.Service {
|
|||
}
|
||||
}
|
||||
|
||||
// GetLocalBackend initialize local backend
|
||||
func GetLocalBackend(configDir string, opts cliopts.GlobalOpts) (backend.Service, error) {
|
||||
configFile, err := cliconfig.Load(configDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
options := cliflags.CommonOptions{
|
||||
Context: opts.Context,
|
||||
Debug: opts.Debug,
|
||||
Hosts: opts.Hosts,
|
||||
LogLevel: opts.LogLevel,
|
||||
}
|
||||
|
||||
if opts.TLSVerify {
|
||||
options.TLS = opts.TLS
|
||||
options.TLSVerify = opts.TLSVerify
|
||||
options.TLSOptions = opts.TLSOptions
|
||||
}
|
||||
apiClient, err := command.NewAPIClientFromFlags(&options, configFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewService(apiClient), nil
|
||||
}
|
||||
|
||||
func (s *local) ContainerService() containers.Service {
|
||||
return s.containerService
|
||||
}
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
Copyright 2020 Docker Compose CLI 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.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/docker/cli/cli-plugins/manager"
|
||||
"github.com/docker/cli/cli-plugins/plugin"
|
||||
"github.com/docker/cli/cli/command"
|
||||
api "github.com/docker/compose-cli/api/compose"
|
||||
"github.com/docker/compose-cli/api/context/store"
|
||||
"github.com/docker/compose-cli/cli/cmd/compose"
|
||||
"github.com/docker/compose-cli/internal"
|
||||
impl "github.com/docker/compose-cli/local/compose"
|
||||
)
|
||||
|
||||
func main() {
|
||||
plugin.Run(func(dockerCli command.Cli) *cobra.Command {
|
||||
lazyInit := api.ServiceDelegator{
|
||||
Delegate: api.NoImpl{},
|
||||
}
|
||||
cmd := compose.Command(store.DefaultContextType, &lazyInit)
|
||||
originalPreRun := cmd.PersistentPreRunE
|
||||
cmd.PersistentPreRunE = func(cmd *cobra.Command, args []string) error {
|
||||
if err := plugin.PersistentPreRunE(cmd, args); err != nil {
|
||||
return err
|
||||
}
|
||||
lazyInit.Delegate = impl.NewComposeService(dockerCli.Client(), dockerCli.ConfigFile())
|
||||
if originalPreRun != nil {
|
||||
return originalPreRun(cmd, args)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return cmd
|
||||
},
|
||||
manager.Metadata{
|
||||
SchemaVersion: "0.1.0",
|
||||
Vendor: "Docker Inc.",
|
||||
Version: strings.TrimPrefix(internal.Version, "v"),
|
||||
})
|
||||
}
|
|
@ -85,6 +85,13 @@ func newE2eCLI(t *testing.T, binDir string) *E2eCLI {
|
|||
_ = os.RemoveAll(d)
|
||||
})
|
||||
|
||||
_ = os.MkdirAll(filepath.Join(d, "cli-plugins"), 0755)
|
||||
composePlugin, _ := findExecutable("docker-compose", []string{"../../bin", "../../../bin"})
|
||||
err = CopyFile(composePlugin, filepath.Join(d, "cli-plugins", "docker-compose"))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return &E2eCLI{binDir, d, t}
|
||||
}
|
||||
|
||||
|
@ -117,7 +124,7 @@ func SetupExistingCLI() (string, func(), error) {
|
|||
return "", nil, err
|
||||
}
|
||||
|
||||
bin, err := findExecutable([]string{"../../bin", "../../../bin"})
|
||||
bin, err := findExecutable(DockerExecutableName, []string{"../../bin", "../../../bin"})
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
@ -133,9 +140,9 @@ func SetupExistingCLI() (string, func(), error) {
|
|||
return d, cleanup, nil
|
||||
}
|
||||
|
||||
func findExecutable(paths []string) (string, error) {
|
||||
func findExecutable(executableName string, paths []string) (string, error) {
|
||||
for _, p := range paths {
|
||||
bin, err := filepath.Abs(path.Join(p, DockerExecutableName))
|
||||
bin, err := filepath.Abs(path.Join(p, executableName))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue