зеркало из https://github.com/docker/compose-cli.git
Коммит
9d341e7539
|
@ -25,9 +25,6 @@ jobs:
|
|||
- name: Validate go-mod is up-to-date and license headers
|
||||
run: make validate
|
||||
|
||||
- name: Validate imports
|
||||
run: make import-restrictions
|
||||
|
||||
- name: Run golangci-lint
|
||||
env:
|
||||
BUILD_TAGS: kube,e2e
|
||||
|
@ -60,7 +57,7 @@ jobs:
|
|||
# Ensure we don't discover cross platform build issues at release time.
|
||||
# Time used to build linux here is gained back in the build for local E2E step
|
||||
- name: Build packages
|
||||
run: make -f builder.Makefile cross cross-compose-plugin
|
||||
run: make -f builder.Makefile cross
|
||||
|
||||
build:
|
||||
name: Build
|
||||
|
@ -99,7 +96,7 @@ jobs:
|
|||
- name: Build for local E2E
|
||||
env:
|
||||
BUILD_TAGS: e2e
|
||||
run: make -f builder.Makefile cli compose-plugin
|
||||
run: make -f builder.Makefile cli
|
||||
|
||||
- name: E2E Test
|
||||
run: make e2e-compose
|
||||
run: make e2e-local
|
||||
|
|
|
@ -1,42 +0,0 @@
|
|||
name: Releaser
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v2*"
|
||||
jobs:
|
||||
upload-release:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Set up Go 1.16
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.16
|
||||
id: go
|
||||
|
||||
- name: Setup docker CLI
|
||||
run: |
|
||||
curl https://download.docker.com/linux/static/stable/x86_64/docker-20.10.3.tgz | tar xz
|
||||
sudo cp ./docker/docker /usr/bin/ && rm -rf docker && docker version
|
||||
|
||||
- name: Checkout code into the Go module directory
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-go-
|
||||
|
||||
- name: Build
|
||||
run: make -f builder.Makefile cross-compose-plugin
|
||||
|
||||
- name: License
|
||||
run: cp packaging/* bin/
|
||||
|
||||
- uses: ncipollo/release-action@v1
|
||||
with:
|
||||
artifacts: "bin/*"
|
||||
prerelease: true
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
20
Dockerfile
20
Dockerfile
|
@ -77,21 +77,6 @@ RUN --mount=target=. \
|
|||
GIT_TAG=${GIT_TAG} \
|
||||
make BINARY=/out/docker -f builder.Makefile cli
|
||||
|
||||
FROM base AS make-compose-plugin
|
||||
ENV CGO_ENABLED=0
|
||||
ARG TARGETOS
|
||||
ARG TARGETARCH
|
||||
ARG BUILD_TAGS
|
||||
ARG GIT_TAG
|
||||
RUN --mount=target=. \
|
||||
--mount=type=cache,target=/go/pkg/mod \
|
||||
--mount=type=cache,target=/root/.cache/go-build \
|
||||
GOOS=${TARGETOS} \
|
||||
GOARCH=${TARGETARCH} \
|
||||
BUILD_TAGS=${BUILD_TAGS} \
|
||||
GIT_TAG=${GIT_TAG} \
|
||||
make COMPOSE_BINARY=/out/docker-compose -f builder.Makefile compose-plugin
|
||||
|
||||
FROM base AS make-cross
|
||||
ARG BUILD_TAGS
|
||||
ARG GIT_TAG
|
||||
|
@ -100,7 +85,7 @@ RUN --mount=target=. \
|
|||
--mount=type=cache,target=/root/.cache/go-build \
|
||||
BUILD_TAGS=${BUILD_TAGS} \
|
||||
GIT_TAG=${GIT_TAG} \
|
||||
make BINARY=/out/docker COMPOSE_BINARY=/out/docker-compose -f builder.Makefile cross
|
||||
make BINARY=/out/docker -f builder.Makefile cross
|
||||
|
||||
FROM scratch AS protos
|
||||
COPY --from=make-protos /compose-cli/cli/server/protos .
|
||||
|
@ -108,9 +93,6 @@ COPY --from=make-protos /compose-cli/cli/server/protos .
|
|||
FROM scratch AS cli
|
||||
COPY --from=make-cli /out/* .
|
||||
|
||||
FROM scratch AS compose-plugin
|
||||
COPY --from=make-compose-plugin /out/* .
|
||||
|
||||
FROM scratch AS cross
|
||||
COPY --from=make-cross /out/* .
|
||||
|
||||
|
|
12
Makefile
12
Makefile
|
@ -31,7 +31,7 @@ else
|
|||
TEST_FLAGS=-run $(E2E_TEST)
|
||||
endif
|
||||
|
||||
all: cli compose-plugin
|
||||
all: cli
|
||||
|
||||
protos: ## Generate go code from .proto files
|
||||
@docker build . --target protos \
|
||||
|
@ -44,16 +44,6 @@ cli: ## Compile the cli
|
|||
--build-arg GIT_TAG=$(GIT_TAG) \
|
||||
--output ./bin
|
||||
|
||||
compose-plugin: ## Compile the compose cli-plugin
|
||||
@docker build . --target compose-plugin \
|
||||
--platform local \
|
||||
--build-arg BUILD_TAGS=e2e,kube \
|
||||
--build-arg GIT_TAG=$(GIT_TAG) \
|
||||
--output ./bin
|
||||
|
||||
e2e-compose: ## Run End to end local tests. Set E2E_TEST=TestName to run a single test
|
||||
gotestsum $(TEST_FLAGS) ./pkg/e2e -- -count=1
|
||||
|
||||
e2e-local: ## Run End to end local tests. Set E2E_TEST=TestName to run a single test
|
||||
gotestsum $(TEST_FLAGS) ./local/e2e/container ./local/e2e/cli-only -- -count=1
|
||||
|
||||
|
|
|
@ -29,6 +29,8 @@ import (
|
|||
"github.com/Azure/go-autorest/autorest/to"
|
||||
tm "github.com/buger/goterm"
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
"github.com/docker/compose/v2/pkg/progress"
|
||||
"github.com/gobwas/ws"
|
||||
"github.com/gobwas/ws/wsutil"
|
||||
"github.com/morikuni/aec"
|
||||
|
@ -39,8 +41,6 @@ import (
|
|||
"github.com/docker/compose-cli/api/client"
|
||||
"github.com/docker/compose-cli/api/containers"
|
||||
"github.com/docker/compose-cli/api/context/store"
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
"github.com/docker/compose-cli/pkg/progress"
|
||||
)
|
||||
|
||||
func createACIContainers(ctx context.Context, aciContext store.AciContext, groupDefinition containerinstance.ContainerGroup) error {
|
||||
|
|
|
@ -21,20 +21,19 @@ import (
|
|||
|
||||
"github.com/Azure/azure-sdk-for-go/services/containerinstance/mgmt/2019-12-01/containerinstance"
|
||||
"github.com/Azure/go-autorest/autorest/to"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/docker/compose-cli/aci/convert"
|
||||
"github.com/docker/compose-cli/aci/login"
|
||||
"github.com/docker/compose-cli/api/backend"
|
||||
"github.com/docker/compose-cli/api/cloud"
|
||||
"github.com/docker/compose-cli/api/containers"
|
||||
apicontext "github.com/docker/compose-cli/api/context"
|
||||
"github.com/docker/compose-cli/api/context/store"
|
||||
"github.com/docker/compose-cli/api/resources"
|
||||
"github.com/docker/compose-cli/api/secrets"
|
||||
"github.com/docker/compose-cli/api/volumes"
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
|
||||
"github.com/docker/compose-cli/api/cloud"
|
||||
apicontext "github.com/docker/compose-cli/api/context"
|
||||
"github.com/docker/compose-cli/api/context/store"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
@ -22,14 +22,14 @@ import (
|
|||
"net/http"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
"github.com/docker/compose/v2/pkg/progress"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/docker/compose-cli/aci/convert"
|
||||
"github.com/docker/compose-cli/aci/login"
|
||||
"github.com/docker/compose-cli/api/context/store"
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
"github.com/docker/compose-cli/pkg/progress"
|
||||
"github.com/docker/compose-cli/utils/formatter"
|
||||
)
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ import (
|
|||
"github.com/Azure/azure-sdk-for-go/services/containerinstance/mgmt/2019-12-01/containerinstance"
|
||||
"github.com/Azure/go-autorest/autorest"
|
||||
"github.com/Azure/go-autorest/autorest/to"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
|
@ -33,7 +34,6 @@ import (
|
|||
"github.com/docker/compose-cli/aci/login"
|
||||
"github.com/docker/compose-cli/api/containers"
|
||||
"github.com/docker/compose-cli/api/context/store"
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
)
|
||||
|
||||
type aciContainerService struct {
|
||||
|
|
|
@ -24,12 +24,12 @@ import (
|
|||
"github.com/AlecAivazis/survey/v2/terminal"
|
||||
"github.com/Azure/azure-sdk-for-go/profiles/preview/preview/subscription/mgmt/subscription"
|
||||
"github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2018-05-01/resources"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
"github.com/docker/compose/v2/pkg/prompt"
|
||||
"github.com/hashicorp/go-uuid"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/docker/compose-cli/api/context/store"
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
"github.com/docker/compose-cli/pkg/prompt"
|
||||
)
|
||||
|
||||
// ContextParams options for creating ACI context
|
||||
|
|
|
@ -28,12 +28,12 @@ import (
|
|||
"github.com/Azure/azure-sdk-for-go/services/containerinstance/mgmt/2019-12-01/containerinstance"
|
||||
"github.com/Azure/go-autorest/autorest/to"
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/docker/compose-cli/aci/login"
|
||||
"github.com/docker/compose-cli/api/containers"
|
||||
"github.com/docker/compose-cli/api/context/store"
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
"github.com/docker/compose-cli/utils/formatter"
|
||||
)
|
||||
|
||||
|
|
|
@ -25,12 +25,12 @@ import (
|
|||
"github.com/Azure/azure-sdk-for-go/services/containerinstance/mgmt/2019-12-01/containerinstance"
|
||||
"github.com/Azure/go-autorest/autorest/to"
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
"gotest.tools/v3/assert"
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
|
||||
"github.com/docker/compose-cli/api/containers"
|
||||
"github.com/docker/compose-cli/api/context/store"
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
@ -22,13 +22,13 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/compose-cli/aci/login"
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/services/containerinstance/mgmt/2019-12-01/containerinstance"
|
||||
"github.com/Azure/go-autorest/autorest/to"
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/docker/compose-cli/aci/login"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
@ -38,6 +38,7 @@ import (
|
|||
"github.com/Azure/azure-sdk-for-go/profiles/2019-03-01/resources/mgmt/resources"
|
||||
"github.com/Azure/azure-storage-file-go/azfile"
|
||||
"github.com/Azure/go-autorest/autorest/to"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
"github.com/docker/docker/pkg/fileutils"
|
||||
"github.com/prometheus/tsdb/fileutil"
|
||||
"gotest.tools/v3/assert"
|
||||
|
@ -51,7 +52,6 @@ import (
|
|||
"github.com/docker/compose-cli/api/containers"
|
||||
"github.com/docker/compose-cli/api/context/store"
|
||||
"github.com/docker/compose-cli/cli/cmd"
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
. "github.com/docker/compose-cli/utils/e2e"
|
||||
)
|
||||
|
||||
|
|
|
@ -30,8 +30,9 @@ import (
|
|||
"github.com/Azure/go-autorest/autorest/date"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
|
||||
"github.com/docker/compose-cli/internal"
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
)
|
||||
|
||||
// UserAgentName is the default user agent used by the cli
|
||||
|
|
|
@ -25,7 +25,7 @@ import (
|
|||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
|
||||
"github.com/Azure/go-autorest/autorest/adal"
|
||||
"github.com/Azure/go-autorest/autorest/azure/auth"
|
||||
|
|
|
@ -22,17 +22,16 @@ import (
|
|||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/services/containerinstance/mgmt/2019-12-01/containerinstance"
|
||||
"github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2019-06-01/storage"
|
||||
"github.com/Azure/go-autorest/autorest/to"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
"github.com/docker/compose/v2/pkg/progress"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/docker/compose-cli/aci/login"
|
||||
"github.com/docker/compose-cli/api/context/store"
|
||||
"github.com/docker/compose-cli/api/volumes"
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
"github.com/docker/compose-cli/pkg/progress"
|
||||
)
|
||||
|
||||
type aciVolumeService struct {
|
||||
|
|
|
@ -20,6 +20,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/docker/compose-cli/api/cloud"
|
||||
|
@ -27,7 +28,6 @@ import (
|
|||
"github.com/docker/compose-cli/api/resources"
|
||||
"github.com/docker/compose-cli/api/secrets"
|
||||
"github.com/docker/compose-cli/api/volumes"
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
@ -19,6 +19,8 @@ package client
|
|||
import (
|
||||
"context"
|
||||
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
|
||||
"github.com/docker/compose-cli/api/backend"
|
||||
"github.com/docker/compose-cli/api/cloud"
|
||||
"github.com/docker/compose-cli/api/containers"
|
||||
|
@ -27,7 +29,6 @@ import (
|
|||
"github.com/docker/compose-cli/api/resources"
|
||||
"github.com/docker/compose-cli/api/secrets"
|
||||
"github.com/docker/compose-cli/api/volumes"
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
)
|
||||
|
||||
// New returns a backend client associated with current context
|
||||
|
|
|
@ -20,7 +20,7 @@ import (
|
|||
"context"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
)
|
||||
|
||||
type composeService struct {
|
||||
|
|
|
@ -19,8 +19,9 @@ package client
|
|||
import (
|
||||
"context"
|
||||
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
|
||||
"github.com/docker/compose-cli/api/containers"
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
)
|
||||
|
||||
type containerService struct {
|
||||
|
|
|
@ -19,8 +19,9 @@ package client
|
|||
import (
|
||||
"context"
|
||||
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
|
||||
"github.com/docker/compose-cli/api/resources"
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
)
|
||||
|
||||
type resourceService struct {
|
||||
|
|
|
@ -19,8 +19,9 @@ package client
|
|||
import (
|
||||
"context"
|
||||
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
|
||||
"github.com/docker/compose-cli/api/secrets"
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
)
|
||||
|
||||
type secretsService struct {
|
||||
|
|
|
@ -19,8 +19,9 @@ package client
|
|||
import (
|
||||
"context"
|
||||
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
|
||||
"github.com/docker/compose-cli/api/volumes"
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
)
|
||||
|
||||
type volumeService struct {
|
||||
|
|
|
@ -19,7 +19,7 @@ package cloud
|
|||
import (
|
||||
"context"
|
||||
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
)
|
||||
|
||||
// Service cloud specific services
|
||||
|
|
|
@ -24,8 +24,7 @@ import (
|
|||
"path/filepath"
|
||||
"reflect"
|
||||
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
"github.com/opencontainers/go-digest"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
|
|
@ -22,7 +22,7 @@ import (
|
|||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
|
||||
"gotest.tools/v3/assert"
|
||||
"gotest.tools/v3/assert/cmp"
|
||||
|
|
|
@ -53,10 +53,6 @@ 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 $(COMPOSE_BINARY_WITH_EXTENSION) ./cmd
|
||||
|
||||
.PHONY: cross
|
||||
cross:
|
||||
GOOS=linux GOARCH=amd64 $(GO_BUILD) $(TAGS) -o $(BINARY)-linux-amd64 ./cli
|
||||
|
@ -68,17 +64,6 @@ cross:
|
|||
GOOS=darwin GOARCH=arm64 $(GO_BUILD) $(TAGS) -o $(BINARY)-darwin-arm64 ./cli
|
||||
GOOS=windows GOARCH=amd64 $(GO_BUILD) $(TAGS) -o $(BINARY)-windows-amd64.exe ./cli
|
||||
|
||||
.PHONY: cross-compose-plugin
|
||||
cross-compose-plugin:
|
||||
GOOS=linux GOARCH=amd64 $(GO_BUILD) $(TAGS) -o $(COMPOSE_BINARY)-linux-amd64 ./cmd
|
||||
GOOS=linux GOARCH=arm64 $(GO_BUILD) $(TAGS) -o $(COMPOSE_BINARY)-linux-arm64 ./cmd
|
||||
GOOS=linux GOARM=6 GOARCH=arm $(GO_BUILD) $(TAGS) -o $(COMPOSE_BINARY)-linux-armv6 ./cmd
|
||||
GOOS=linux GOARM=7 GOARCH=arm $(GO_BUILD) $(TAGS) -o $(COMPOSE_BINARY)-linux-armv7 ./cmd
|
||||
GOOS=linux GOARCH=s390x $(GO_BUILD) $(TAGS) -o $(COMPOSE_BINARY)-linux-s390x ./cmd
|
||||
GOOS=darwin GOARCH=amd64 $(GO_BUILD) $(TAGS) -o $(COMPOSE_BINARY)-darwin-amd64 ./cmd
|
||||
GOOS=darwin GOARCH=arm64 $(GO_BUILD) $(TAGS) -o $(COMPOSE_BINARY)-darwin-arm64 ./cmd
|
||||
GOOS=windows GOARCH=amd64 $(GO_BUILD) $(TAGS) -o $(COMPOSE_BINARY)-windows-amd64.exe ./cmd
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
go test $(TAGS) -cover $(shell go list $(TAGS) ./... | grep -vE 'e2e')
|
||||
|
|
|
@ -19,13 +19,13 @@ package context
|
|||
import (
|
||||
"context"
|
||||
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/docker/compose-cli/aci"
|
||||
"github.com/docker/compose-cli/api/client"
|
||||
"github.com/docker/compose-cli/api/context/store"
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
|
|
@ -23,13 +23,13 @@ import (
|
|||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/docker/compose-cli/api/client"
|
||||
"github.com/docker/compose-cli/api/context/store"
|
||||
"github.com/docker/compose-cli/ecs"
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
package context
|
||||
|
||||
import (
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
|
|
|
@ -23,8 +23,7 @@ import (
|
|||
"sort"
|
||||
"strings"
|
||||
|
||||
formatter2 "github.com/docker/compose-cli/cmd/formatter"
|
||||
|
||||
"github.com/docker/compose/v2/cmd/formatter"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
|
@ -69,7 +68,7 @@ func runList(cmd *cobra.Command, opts lsOpts) error {
|
|||
return err
|
||||
}
|
||||
format := strings.ToLower(strings.ReplaceAll(opts.format, " ", ""))
|
||||
if format != "" && format != formatter2.JSON && format != formatter2.PRETTY && format != formatter2.TemplateLegacyJSON {
|
||||
if format != "" && format != formatter.JSON && format != formatter.PRETTY && format != formatter.TemplateLegacyJSON {
|
||||
mobycli.Exec(cmd.Root())
|
||||
return nil
|
||||
}
|
||||
|
@ -92,15 +91,15 @@ func runList(cmd *cobra.Command, opts lsOpts) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
if opts.json || format == formatter2.JSON {
|
||||
opts.format = formatter2.JSON
|
||||
if opts.json || format == formatter.JSON {
|
||||
opts.format = formatter.JSON
|
||||
}
|
||||
if format == formatter2.TemplateLegacyJSON {
|
||||
opts.format = formatter2.TemplateLegacyJSON
|
||||
if format == formatter.TemplateLegacyJSON {
|
||||
opts.format = formatter.TemplateLegacyJSON
|
||||
}
|
||||
|
||||
view := viewFromContextList(contexts, currentContext)
|
||||
return formatter2.Print(view, opts.format, os.Stdout,
|
||||
return formatter.Print(view, opts.format, os.Stdout,
|
||||
func(w io.Writer) {
|
||||
for _, c := range view {
|
||||
contextName := c.Name
|
||||
|
|
|
@ -20,8 +20,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/docker/compose-cli/cmd/formatter"
|
||||
|
||||
"github.com/docker/compose/v2/cmd/formatter"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
package context
|
||||
|
||||
import (
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
|
|
|
@ -20,10 +20,9 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/docker/compose-cli/cmd/formatter"
|
||||
|
||||
"github.com/Azure/go-autorest/autorest/to"
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/docker/compose/v2/cmd/formatter"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
|
|
|
@ -20,14 +20,14 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/docker/compose-cli/cmd/formatter"
|
||||
|
||||
"github.com/docker/compose/v2/cmd/formatter"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
|
||||
"github.com/docker/compose-cli/api/client"
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
)
|
||||
|
||||
type killOpts struct {
|
||||
|
|
|
@ -23,9 +23,10 @@ import (
|
|||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
|
||||
"github.com/docker/compose-cli/api/client"
|
||||
"github.com/docker/compose-cli/cli/mobycli"
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
)
|
||||
|
||||
// Command returns the login command
|
||||
|
|
|
@ -23,8 +23,9 @@ import (
|
|||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
|
||||
"github.com/docker/compose-cli/api/client"
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
)
|
||||
|
||||
// AzureLogoutCommand returns the azure logout command
|
||||
|
|
|
@ -23,12 +23,12 @@ import (
|
|||
"os"
|
||||
"strings"
|
||||
|
||||
format "github.com/docker/compose/v2/cmd/formatter"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/docker/compose-cli/api/client"
|
||||
"github.com/docker/compose-cli/api/containers"
|
||||
format "github.com/docker/compose-cli/cmd/formatter"
|
||||
"github.com/docker/compose-cli/utils/formatter"
|
||||
)
|
||||
|
||||
|
|
|
@ -20,15 +20,15 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/docker/compose-cli/cmd/formatter"
|
||||
|
||||
"github.com/docker/compose/v2/cmd/formatter"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
|
||||
"github.com/docker/compose-cli/api/client"
|
||||
"github.com/docker/compose-cli/api/containers"
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
)
|
||||
|
||||
type rmOpts struct {
|
||||
|
|
|
@ -26,11 +26,12 @@ import (
|
|||
"github.com/containerd/console"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/docker/compose/v2/pkg/progress"
|
||||
|
||||
"github.com/docker/compose-cli/api/client"
|
||||
"github.com/docker/compose-cli/api/containers"
|
||||
"github.com/docker/compose-cli/api/context/store"
|
||||
"github.com/docker/compose-cli/cli/options/run"
|
||||
"github.com/docker/compose-cli/pkg/progress"
|
||||
)
|
||||
|
||||
// Command runs a container
|
||||
|
|
|
@ -22,8 +22,7 @@ import (
|
|||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"github.com/docker/compose-cli/cmd/formatter"
|
||||
|
||||
"github.com/docker/compose/v2/cmd/formatter"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/docker/compose-cli/api/client"
|
||||
|
|
|
@ -20,14 +20,13 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/docker/compose-cli/cmd/formatter"
|
||||
|
||||
"github.com/docker/compose/v2/cmd/formatter"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/docker/compose-cli/api/client"
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
)
|
||||
|
||||
// StartCommand starts containers
|
||||
|
|
|
@ -20,14 +20,14 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/docker/compose-cli/cmd/formatter"
|
||||
|
||||
"github.com/docker/compose/v2/cmd/formatter"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
|
||||
"github.com/docker/compose-cli/api/client"
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
)
|
||||
|
||||
type stopOpts struct {
|
||||
|
|
|
@ -21,11 +21,9 @@ import (
|
|||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/compose-cli/cmd/formatter"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/docker/cli/cli"
|
||||
"github.com/docker/compose/v2/cmd/formatter"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/docker/compose-cli/cli/mobycli"
|
||||
"github.com/docker/compose-cli/internal"
|
||||
|
|
|
@ -20,13 +20,14 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
|
||||
format "github.com/docker/compose-cli/cmd/formatter"
|
||||
format "github.com/docker/compose/v2/cmd/formatter"
|
||||
|
||||
"github.com/docker/compose/v2/pkg/progress"
|
||||
|
||||
"github.com/docker/compose-cli/aci"
|
||||
"github.com/docker/compose-cli/api/client"
|
||||
"github.com/docker/compose-cli/api/context/store"
|
||||
"github.com/docker/compose-cli/ecs"
|
||||
"github.com/docker/compose-cli/pkg/progress"
|
||||
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/spf13/cobra"
|
||||
|
|
|
@ -21,7 +21,7 @@ import (
|
|||
"io"
|
||||
"os"
|
||||
|
||||
formatter2 "github.com/docker/compose-cli/cmd/formatter"
|
||||
formatter2 "github.com/docker/compose/v2/cmd/formatter"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
|
|
|
@ -30,6 +30,9 @@ import (
|
|||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/docker/cli/cli"
|
||||
compose2 "github.com/docker/compose/v2/cmd/compose"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
"github.com/docker/compose/v2/pkg/compose"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
|
@ -48,10 +51,7 @@ import (
|
|||
"github.com/docker/compose-cli/cli/metrics"
|
||||
"github.com/docker/compose-cli/cli/mobycli"
|
||||
cliopts "github.com/docker/compose-cli/cli/options"
|
||||
compose2 "github.com/docker/compose-cli/cmd/compose"
|
||||
"github.com/docker/compose-cli/local"
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
"github.com/docker/compose-cli/pkg/compose"
|
||||
|
||||
// Backend registrations
|
||||
_ "github.com/docker/compose-cli/aci"
|
||||
|
|
|
@ -21,7 +21,7 @@ import (
|
|||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/compose-cli/pkg/utils"
|
||||
"github.com/docker/compose/v2/pkg/utils"
|
||||
)
|
||||
|
||||
var managementCommands = []string{"ecs", "scan"}
|
||||
|
|
|
@ -20,7 +20,7 @@ import (
|
|||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/compose-cli/pkg/utils"
|
||||
"github.com/docker/compose/v2/pkg/utils"
|
||||
)
|
||||
|
||||
// Track sends the tracking analytics to Docker Desktop
|
||||
|
|
|
@ -25,14 +25,14 @@ import (
|
|||
"path/filepath"
|
||||
"regexp"
|
||||
|
||||
"github.com/docker/compose/v2/pkg/compose"
|
||||
"github.com/docker/compose/v2/pkg/utils"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
apicontext "github.com/docker/compose-cli/api/context"
|
||||
"github.com/docker/compose-cli/api/context/store"
|
||||
"github.com/docker/compose-cli/cli/metrics"
|
||||
"github.com/docker/compose-cli/cli/mobycli/resolvepath"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/docker/compose-cli/pkg/compose"
|
||||
"github.com/docker/compose-cli/pkg/utils"
|
||||
)
|
||||
|
||||
var delegatedContextTypes = []string{store.DefaultContextType}
|
||||
|
|
|
@ -19,11 +19,11 @@ package server
|
|||
import (
|
||||
"context"
|
||||
|
||||
"github.com/docker/compose/v2/pkg/compose"
|
||||
"google.golang.org/grpc"
|
||||
|
||||
"github.com/docker/compose-cli/cli/metrics"
|
||||
"github.com/docker/compose-cli/cli/server/proxy"
|
||||
"github.com/docker/compose-cli/pkg/compose"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
@ -21,8 +21,7 @@ import (
|
|||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/compose-cli/api/resources"
|
||||
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/metadata"
|
||||
|
@ -30,6 +29,7 @@ import (
|
|||
|
||||
"github.com/docker/compose-cli/api/client"
|
||||
"github.com/docker/compose-cli/api/containers"
|
||||
"github.com/docker/compose-cli/api/resources"
|
||||
"github.com/docker/compose-cli/api/secrets"
|
||||
"github.com/docker/compose-cli/api/volumes"
|
||||
"github.com/docker/compose-cli/cli/metrics"
|
||||
|
@ -38,7 +38,6 @@ import (
|
|||
streamsv1 "github.com/docker/compose-cli/cli/server/protos/streams/v1"
|
||||
volumesv1 "github.com/docker/compose-cli/cli/server/protos/volumes/v1"
|
||||
"github.com/docker/compose-cli/cli/server/proxy"
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
)
|
||||
|
||||
func TestAllMethodsHaveCorrespondingCliCommand(t *testing.T) {
|
||||
|
|
|
@ -1,99 +0,0 @@
|
|||
/*
|
||||
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"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
)
|
||||
|
||||
type buildOptions struct {
|
||||
*projectOptions
|
||||
composeOptions
|
||||
quiet bool
|
||||
pull bool
|
||||
progress string
|
||||
args []string
|
||||
noCache bool
|
||||
memory string
|
||||
}
|
||||
|
||||
func buildCommand(p *projectOptions, backend api.Service) *cobra.Command {
|
||||
opts := buildOptions{
|
||||
projectOptions: p,
|
||||
}
|
||||
cmd := &cobra.Command{
|
||||
Use: "build [SERVICE...]",
|
||||
Short: "Build or rebuild services",
|
||||
PreRunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
if opts.memory != "" {
|
||||
fmt.Println("WARNING --memory is ignored as not supported in buildkit.")
|
||||
}
|
||||
if opts.quiet {
|
||||
devnull, err := os.Open(os.DevNull)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
os.Stdout = devnull
|
||||
}
|
||||
return nil
|
||||
}),
|
||||
RunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
return runBuild(ctx, backend, opts, args)
|
||||
}),
|
||||
ValidArgsFunction: serviceCompletion(p),
|
||||
}
|
||||
cmd.Flags().BoolVarP(&opts.quiet, "quiet", "q", false, "Don't print anything to STDOUT")
|
||||
cmd.Flags().BoolVar(&opts.pull, "pull", false, "Always attempt to pull a newer version of the image.")
|
||||
cmd.Flags().StringVar(&opts.progress, "progress", "auto", `Set type of progress output ("auto", "plain", "noTty")`)
|
||||
cmd.Flags().StringArrayVar(&opts.args, "build-arg", []string{}, "Set build-time variables for services.")
|
||||
cmd.Flags().Bool("parallel", true, "Build images in parallel. DEPRECATED")
|
||||
cmd.Flags().MarkHidden("parallel") //nolint:errcheck
|
||||
cmd.Flags().Bool("compress", true, "Compress the build context using gzip. DEPRECATED")
|
||||
cmd.Flags().MarkHidden("compress") //nolint:errcheck
|
||||
cmd.Flags().Bool("force-rm", true, "Always remove intermediate containers. DEPRECATED")
|
||||
cmd.Flags().MarkHidden("force-rm") //nolint:errcheck
|
||||
cmd.Flags().BoolVar(&opts.noCache, "no-cache", false, "Do not use cache when building the image")
|
||||
cmd.Flags().Bool("no-rm", false, "Do not remove intermediate containers after a successful build. DEPRECATED")
|
||||
cmd.Flags().MarkHidden("no-rm") //nolint:errcheck
|
||||
cmd.Flags().StringVarP(&opts.memory, "memory", "m", "", "Set memory limit for the build container. Not supported on buildkit yet.")
|
||||
cmd.Flags().MarkHidden("memory") //nolint:errcheck
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runBuild(ctx context.Context, backend api.Service, opts buildOptions, services []string) error {
|
||||
project, err := opts.toProject(services)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return backend.Build(ctx, project, api.BuildOptions{
|
||||
Pull: opts.pull,
|
||||
Progress: opts.progress,
|
||||
Args: types.NewMappingWithEquals(opts.args),
|
||||
NoCache: opts.noCache,
|
||||
Quiet: opts.quiet,
|
||||
Services: services,
|
||||
})
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
/*
|
||||
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 (
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// validArgsFn defines a completion func to be returned to fetch completion options
|
||||
type validArgsFn func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective)
|
||||
|
||||
func noCompletion() validArgsFn {
|
||||
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
}
|
||||
|
||||
func serviceCompletion(p *projectOptions) validArgsFn {
|
||||
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
project, err := p.toProject(nil)
|
||||
if err != nil {
|
||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
var serviceNames []string
|
||||
for _, s := range project.ServiceNames() {
|
||||
if toComplete == "" || strings.HasPrefix(s, toComplete) {
|
||||
serviceNames = append(serviceNames, s)
|
||||
}
|
||||
}
|
||||
return serviceNames, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
}
|
|
@ -1,289 +0,0 @@
|
|||
/*
|
||||
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"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/docker/compose-cli/cmd/formatter"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/compose-spec/compose-go/cli"
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
dockercli "github.com/docker/cli/cli"
|
||||
"github.com/morikuni/aec"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
"github.com/docker/compose-cli/pkg/compose"
|
||||
)
|
||||
|
||||
// Command defines a compose CLI command as a func with args
|
||||
type Command func(context.Context, []string) error
|
||||
|
||||
// Adapt a Command func to cobra library
|
||||
func Adapt(fn Command) func(cmd *cobra.Command, args []string) error {
|
||||
return func(cmd *cobra.Command, args []string) error {
|
||||
ctx := cmd.Context()
|
||||
contextString := fmt.Sprintf("%s", ctx)
|
||||
if !strings.HasSuffix(contextString, ".WithCancel") { // need to handle cancel
|
||||
cancellableCtx, cancel := context.WithCancel(cmd.Context())
|
||||
ctx = cancellableCtx
|
||||
s := make(chan os.Signal, 1)
|
||||
signal.Notify(s, syscall.SIGTERM, syscall.SIGINT)
|
||||
go func() {
|
||||
<-s
|
||||
cancel()
|
||||
}()
|
||||
}
|
||||
err := fn(ctx, args)
|
||||
var composeErr compose.Error
|
||||
if api.IsErrCanceled(err) || errors.Is(ctx.Err(), context.Canceled) {
|
||||
err = dockercli.StatusError{
|
||||
StatusCode: 130,
|
||||
Status: compose.CanceledStatus,
|
||||
}
|
||||
}
|
||||
if errors.As(err, &composeErr) {
|
||||
err = dockercli.StatusError{
|
||||
StatusCode: composeErr.GetMetricsFailureCategory().ExitCode,
|
||||
Status: err.Error(),
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Warning is a global warning to be displayed to user on command failure
|
||||
var Warning string
|
||||
|
||||
type projectOptions struct {
|
||||
ProjectName string
|
||||
Profiles []string
|
||||
ConfigPaths []string
|
||||
WorkDir string
|
||||
ProjectDir string
|
||||
EnvFile string
|
||||
}
|
||||
|
||||
// ProjectFunc does stuff within a types.Project
|
||||
type ProjectFunc func(ctx context.Context, project *types.Project) error
|
||||
|
||||
// ProjectServicesFunc does stuff within a types.Project and a selection of services
|
||||
type ProjectServicesFunc func(ctx context.Context, project *types.Project, services []string) error
|
||||
|
||||
// WithServices creates a cobra run command from a ProjectFunc based on configured project options and selected services
|
||||
func (o *projectOptions) WithProject(fn ProjectFunc) func(cmd *cobra.Command, args []string) error {
|
||||
return o.WithServices(func(ctx context.Context, project *types.Project, services []string) error {
|
||||
return fn(ctx, project)
|
||||
})
|
||||
}
|
||||
|
||||
// WithServices creates a cobra run command from a ProjectFunc based on configured project options and selected services
|
||||
func (o *projectOptions) WithServices(fn ProjectServicesFunc) func(cmd *cobra.Command, args []string) error {
|
||||
return Adapt(func(ctx context.Context, args []string) error {
|
||||
project, err := o.toProject(args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if o.EnvFile != "" {
|
||||
var services types.Services
|
||||
for _, s := range project.Services {
|
||||
ef := o.EnvFile
|
||||
if ef != "" {
|
||||
if !filepath.IsAbs(ef) {
|
||||
ef = filepath.Join(project.WorkingDir, o.EnvFile)
|
||||
}
|
||||
if s.Labels == nil {
|
||||
s.Labels = make(map[string]string)
|
||||
}
|
||||
s.Labels[api.EnvironmentFileLabel] = ef
|
||||
services = append(services, s)
|
||||
}
|
||||
}
|
||||
project.Services = services
|
||||
}
|
||||
|
||||
return fn(ctx, project, args)
|
||||
})
|
||||
}
|
||||
|
||||
func (o *projectOptions) addProjectFlags(f *pflag.FlagSet) {
|
||||
f.StringArrayVar(&o.Profiles, "profile", []string{}, "Specify a profile to enable")
|
||||
f.StringVarP(&o.ProjectName, "project-name", "p", "", "Project name")
|
||||
f.StringArrayVarP(&o.ConfigPaths, "file", "f", []string{}, "Compose configuration files")
|
||||
f.StringVar(&o.EnvFile, "env-file", "", "Specify an alternate environment file.")
|
||||
f.StringVar(&o.ProjectDir, "project-directory", "", "Specify an alternate working directory\n(default: the path of the Compose file)")
|
||||
f.StringVar(&o.WorkDir, "workdir", "", "DEPRECATED! USE --project-directory INSTEAD.\nSpecify an alternate working directory\n(default: the path of the Compose file)")
|
||||
_ = f.MarkHidden("workdir")
|
||||
}
|
||||
|
||||
func (o *projectOptions) toProjectName() (string, error) {
|
||||
if o.ProjectName != "" {
|
||||
return o.ProjectName, nil
|
||||
}
|
||||
|
||||
project, err := o.toProject(nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return project.Name, nil
|
||||
}
|
||||
|
||||
func (o *projectOptions) toProject(services []string, po ...cli.ProjectOptionsFn) (*types.Project, error) {
|
||||
options, err := o.toProjectOptions(po...)
|
||||
if err != nil {
|
||||
return nil, compose.WrapComposeError(err)
|
||||
}
|
||||
|
||||
project, err := cli.ProjectFromOptions(options)
|
||||
if err != nil {
|
||||
return nil, compose.WrapComposeError(err)
|
||||
}
|
||||
|
||||
if len(services) > 0 {
|
||||
s, err := project.GetServices(services...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
o.Profiles = append(o.Profiles, s.GetProfiles()...)
|
||||
}
|
||||
|
||||
if profiles, ok := options.Environment["COMPOSE_PROFILES"]; ok {
|
||||
o.Profiles = append(o.Profiles, strings.Split(profiles, ",")...)
|
||||
}
|
||||
|
||||
project.ApplyProfiles(o.Profiles)
|
||||
|
||||
project.WithoutUnnecessaryResources()
|
||||
|
||||
err = project.ForServices(services)
|
||||
return project, err
|
||||
}
|
||||
|
||||
func (o *projectOptions) toProjectOptions(po ...cli.ProjectOptionsFn) (*cli.ProjectOptions, error) {
|
||||
return cli.NewProjectOptions(o.ConfigPaths,
|
||||
append(po,
|
||||
cli.WithEnvFile(o.EnvFile),
|
||||
cli.WithDotEnv,
|
||||
cli.WithOsEnv,
|
||||
cli.WithWorkingDirectory(o.ProjectDir),
|
||||
cli.WithConfigFileEnv,
|
||||
cli.WithDefaultConfigPath,
|
||||
cli.WithName(o.ProjectName))...)
|
||||
}
|
||||
|
||||
// RootCommand returns the compose command with its child commands
|
||||
func RootCommand(backend api.Service) *cobra.Command {
|
||||
opts := projectOptions{}
|
||||
var (
|
||||
ansi string
|
||||
noAnsi bool
|
||||
verbose bool
|
||||
)
|
||||
command := &cobra.Command{
|
||||
Short: "Docker Compose",
|
||||
Use: "compose",
|
||||
TraverseChildren: true,
|
||||
// By default (no Run/RunE in parent command) for typos in subcommands, cobra displays the help of parent command but exit(0) !
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if len(args) == 0 {
|
||||
return cmd.Help()
|
||||
}
|
||||
_ = cmd.Help()
|
||||
return dockercli.StatusError{
|
||||
StatusCode: compose.CommandSyntaxFailure.ExitCode,
|
||||
Status: fmt.Sprintf("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"`)
|
||||
}
|
||||
ansi = "never"
|
||||
fmt.Fprint(os.Stderr, aec.Apply("option '--no-ansi' is DEPRECATED ! Please use '--ansi' instead.\n", aec.RedF))
|
||||
}
|
||||
if verbose {
|
||||
logrus.SetLevel(logrus.TraceLevel)
|
||||
}
|
||||
formatter.SetANSIMode(ansi)
|
||||
if opts.WorkDir != "" {
|
||||
if opts.ProjectDir != "" {
|
||||
return errors.New(`cannot specify DEPRECATED "--workdir" and "--project-directory". Please use only "--project-directory" instead`)
|
||||
}
|
||||
opts.ProjectDir = opts.WorkDir
|
||||
fmt.Fprint(os.Stderr, aec.Apply("option '--workdir' is DEPRECATED at root level! Please use '--project-directory' instead.\n", aec.RedF))
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
command.AddCommand(
|
||||
upCommand(&opts, backend),
|
||||
downCommand(&opts, backend),
|
||||
startCommand(&opts, backend),
|
||||
restartCommand(&opts, backend),
|
||||
stopCommand(&opts, backend),
|
||||
psCommand(&opts, backend),
|
||||
listCommand(backend),
|
||||
logsCommand(&opts, backend),
|
||||
convertCommand(&opts, backend),
|
||||
killCommand(&opts, backend),
|
||||
runCommand(&opts, backend),
|
||||
removeCommand(&opts, backend),
|
||||
execCommand(&opts, backend),
|
||||
pauseCommand(&opts, backend),
|
||||
unpauseCommand(&opts, backend),
|
||||
topCommand(&opts, backend),
|
||||
eventsCommand(&opts, backend),
|
||||
portCommand(&opts, backend),
|
||||
imagesCommand(&opts, backend),
|
||||
versionCommand(),
|
||||
buildCommand(&opts, backend),
|
||||
pushCommand(&opts, backend),
|
||||
pullCommand(&opts, backend),
|
||||
createCommand(&opts, backend),
|
||||
copyCommand(&opts, backend),
|
||||
)
|
||||
command.Flags().SetInterspersed(false)
|
||||
opts.addProjectFlags(command.Flags())
|
||||
command.Flags().StringVar(&ansi, "ansi", "auto", `Control when to print ANSI control characters ("never"|"always"|"auto")`)
|
||||
command.Flags().BoolVar(&noAnsi, "no-ansi", false, `Do not print ANSI control characters (DEPRECATED)`)
|
||||
command.Flags().MarkHidden("no-ansi") //nolint:errcheck
|
||||
command.Flags().BoolVar(&verbose, "verbose", false, "Show more output")
|
||||
command.Flags().MarkHidden("verbose") //nolint:errcheck
|
||||
return command
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
/*
|
||||
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 (
|
||||
"testing"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"gotest.tools/v3/assert"
|
||||
)
|
||||
|
||||
func TestFilterServices(t *testing.T) {
|
||||
p := &types.Project{
|
||||
Services: []types.ServiceConfig{
|
||||
{
|
||||
Name: "foo",
|
||||
Links: []string{"bar"},
|
||||
},
|
||||
{
|
||||
Name: "bar",
|
||||
NetworkMode: types.NetworkModeServicePrefix + "zot",
|
||||
},
|
||||
{
|
||||
Name: "zot",
|
||||
},
|
||||
{
|
||||
Name: "qix",
|
||||
},
|
||||
},
|
||||
}
|
||||
err := p.ForServices([]string{"bar"})
|
||||
assert.NilError(t, err)
|
||||
|
||||
assert.Equal(t, len(p.Services), 2)
|
||||
_, err = p.GetService("bar")
|
||||
assert.NilError(t, err)
|
||||
_, err = p.GetService("zot")
|
||||
assert.NilError(t, err)
|
||||
}
|
|
@ -1,214 +0,0 @@
|
|||
/*
|
||||
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 (
|
||||
"bufio"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/cnabio/cnab-to-oci/remotes"
|
||||
"github.com/compose-spec/compose-go/cli"
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/distribution/distribution/v3/reference"
|
||||
cliconfig "github.com/docker/cli/cli/config"
|
||||
"github.com/opencontainers/go-digest"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
"github.com/docker/compose-cli/pkg/compose"
|
||||
)
|
||||
|
||||
type convertOptions struct {
|
||||
*projectOptions
|
||||
Format string
|
||||
Output string
|
||||
quiet bool
|
||||
resolve bool
|
||||
noInterpolate bool
|
||||
services bool
|
||||
volumes bool
|
||||
profiles bool
|
||||
hash string
|
||||
}
|
||||
|
||||
var addFlagsFuncs []func(cmd *cobra.Command, opts *convertOptions)
|
||||
|
||||
func convertCommand(p *projectOptions, backend api.Service) *cobra.Command {
|
||||
opts := convertOptions{
|
||||
projectOptions: p,
|
||||
}
|
||||
cmd := &cobra.Command{
|
||||
Aliases: []string{"config"},
|
||||
Use: "convert SERVICES",
|
||||
Short: "Converts the compose file to platform's canonical format",
|
||||
PreRunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
if opts.quiet {
|
||||
devnull, err := os.Open(os.DevNull)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
os.Stdout = devnull
|
||||
}
|
||||
return nil
|
||||
}),
|
||||
RunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
if opts.services {
|
||||
return runServices(opts)
|
||||
}
|
||||
if opts.volumes {
|
||||
return runVolumes(opts)
|
||||
}
|
||||
if opts.hash != "" {
|
||||
return runHash(opts)
|
||||
}
|
||||
if opts.profiles {
|
||||
return runProfiles(opts, args)
|
||||
}
|
||||
|
||||
return runConvert(ctx, backend, opts, args)
|
||||
}),
|
||||
ValidArgsFunction: serviceCompletion(p),
|
||||
}
|
||||
flags := cmd.Flags()
|
||||
flags.StringVar(&opts.Format, "format", "yaml", "Format the output. Values: [yaml | json]")
|
||||
flags.BoolVar(&opts.resolve, "resolve-image-digests", false, "Pin image tags to digests.")
|
||||
flags.BoolVarP(&opts.quiet, "quiet", "q", false, "Only validate the configuration, don't print anything.")
|
||||
flags.BoolVar(&opts.noInterpolate, "no-interpolate", false, "Don't interpolate environment variables.")
|
||||
|
||||
flags.BoolVar(&opts.services, "services", false, "Print the service names, one per line.")
|
||||
flags.BoolVar(&opts.volumes, "volumes", false, "Print the volume names, one per line.")
|
||||
flags.BoolVar(&opts.profiles, "profiles", false, "Print the profile names, one per line.")
|
||||
flags.StringVar(&opts.hash, "hash", "", "Print the service config hash, one per line.")
|
||||
|
||||
// add flags for hidden backends
|
||||
for _, f := range addFlagsFuncs {
|
||||
f(cmd, &opts)
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runConvert(ctx context.Context, backend api.Service, opts convertOptions, services []string) error {
|
||||
var json []byte
|
||||
project, err := opts.toProject(services, cli.WithInterpolation(!opts.noInterpolate))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if opts.resolve {
|
||||
configFile := cliconfig.LoadDefaultConfigFile(os.Stderr)
|
||||
|
||||
resolver := remotes.CreateResolver(configFile)
|
||||
err = project.ResolveImages(func(named reference.Named) (digest.Digest, error) {
|
||||
_, desc, err := resolver.Resolve(ctx, named.String())
|
||||
return desc.Digest, err
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
json, err = backend.Convert(ctx, project, api.ConvertOptions{
|
||||
Format: opts.Format,
|
||||
Output: opts.Output,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if opts.quiet {
|
||||
return nil
|
||||
}
|
||||
|
||||
var out io.Writer = os.Stdout
|
||||
if opts.Output != "" && len(json) > 0 {
|
||||
file, err := os.Create(opts.Output)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
out = bufio.NewWriter(file)
|
||||
}
|
||||
_, err = fmt.Fprint(out, string(json))
|
||||
return err
|
||||
}
|
||||
|
||||
func runServices(opts convertOptions) error {
|
||||
project, err := opts.toProject(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return project.WithServices(project.ServiceNames(), func(s types.ServiceConfig) error {
|
||||
fmt.Println(s.Name)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func runVolumes(opts convertOptions) error {
|
||||
project, err := opts.toProject(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for n := range project.Volumes {
|
||||
fmt.Println(n)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func runHash(opts convertOptions) error {
|
||||
var services []string
|
||||
if opts.hash != "*" {
|
||||
services = append(services, strings.Split(opts.hash, ",")...)
|
||||
}
|
||||
project, err := opts.toProject(services)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, s := range project.Services {
|
||||
hash, err := compose.ServiceHash(s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("%s %s\n", s.Name, hash)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func runProfiles(opts convertOptions, services []string) error {
|
||||
set := map[string]struct{}{}
|
||||
project, err := opts.toProject(services)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, s := range project.AllServices() {
|
||||
for _, p := range s.Profiles {
|
||||
set[p] = struct{}{}
|
||||
}
|
||||
}
|
||||
profiles := make([]string, 0, len(set))
|
||||
for p := range set {
|
||||
profiles = append(profiles, p)
|
||||
}
|
||||
sort.Strings(profiles)
|
||||
for _, p := range profiles {
|
||||
fmt.Println(p)
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
// +build kube
|
||||
|
||||
/*
|
||||
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 (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func init() {
|
||||
addFlagsFuncs = append(addFlagsFuncs, func(cmd *cobra.Command, opts *convertOptions) {
|
||||
flags := cmd.Flags()
|
||||
flags.StringVar(&opts.Output, "output", "", "Save to directory")
|
||||
})
|
||||
|
||||
}
|
|
@ -1,89 +0,0 @@
|
|||
/*
|
||||
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"
|
||||
"errors"
|
||||
|
||||
"github.com/docker/cli/cli"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
)
|
||||
|
||||
type copyOptions struct {
|
||||
*projectOptions
|
||||
|
||||
source string
|
||||
destination string
|
||||
index int
|
||||
all bool
|
||||
followLink bool
|
||||
copyUIDGID bool
|
||||
}
|
||||
|
||||
func copyCommand(p *projectOptions, backend api.Service) *cobra.Command {
|
||||
opts := copyOptions{
|
||||
projectOptions: p,
|
||||
}
|
||||
copyCmd := &cobra.Command{
|
||||
Use: `cp [OPTIONS] SERVICE:SRC_PATH DEST_PATH|-
|
||||
docker compose cp [OPTIONS] SRC_PATH|- SERVICE:DEST_PATH`,
|
||||
Short: "Copy files/folders between a service container and the local filesystem",
|
||||
Args: cli.ExactArgs(2),
|
||||
PreRunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
if args[0] == "" {
|
||||
return errors.New("source can not be empty")
|
||||
}
|
||||
if args[1] == "" {
|
||||
return errors.New("destination can not be empty")
|
||||
}
|
||||
return nil
|
||||
}),
|
||||
RunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
opts.source = args[0]
|
||||
opts.destination = args[1]
|
||||
return runCopy(ctx, backend, opts)
|
||||
}),
|
||||
ValidArgsFunction: serviceCompletion(p),
|
||||
}
|
||||
|
||||
flags := copyCmd.Flags()
|
||||
flags.IntVar(&opts.index, "index", 1, "Index of the container if there are multiple instances of a service [default: 1].")
|
||||
flags.BoolVar(&opts.all, "all", false, "Copy to all the containers of the service.")
|
||||
flags.BoolVarP(&opts.followLink, "follow-link", "L", false, "Always follow symbol link in SRC_PATH")
|
||||
flags.BoolVarP(&opts.copyUIDGID, "archive", "a", false, "Archive mode (copy all uid/gid information)")
|
||||
|
||||
return copyCmd
|
||||
}
|
||||
|
||||
func runCopy(ctx context.Context, backend api.Service, opts copyOptions) error {
|
||||
projects, err := opts.toProject(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return backend.Copy(ctx, projects, api.CopyOptions{
|
||||
Source: opts.source,
|
||||
Destination: opts.destination,
|
||||
All: opts.all,
|
||||
Index: opts.index,
|
||||
FollowLink: opts.followLink,
|
||||
CopyUIDGID: opts.copyUIDGID,
|
||||
})
|
||||
}
|
|
@ -1,121 +0,0 @@
|
|||
/*
|
||||
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"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
)
|
||||
|
||||
type createOptions struct {
|
||||
Build bool
|
||||
noBuild bool
|
||||
removeOrphans bool
|
||||
forceRecreate bool
|
||||
noRecreate bool
|
||||
recreateDeps bool
|
||||
noInherit bool
|
||||
timeChanged bool
|
||||
timeout int
|
||||
quietPull bool
|
||||
}
|
||||
|
||||
func createCommand(p *projectOptions, backend api.Service) *cobra.Command {
|
||||
opts := createOptions{}
|
||||
cmd := &cobra.Command{
|
||||
Use: "create [SERVICE...]",
|
||||
Short: "Creates containers for a service.",
|
||||
PreRunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
if opts.Build && opts.noBuild {
|
||||
return fmt.Errorf("--build and --no-build are incompatible")
|
||||
}
|
||||
if opts.forceRecreate && opts.noRecreate {
|
||||
return fmt.Errorf("--force-recreate and --no-recreate are incompatible")
|
||||
}
|
||||
return nil
|
||||
}),
|
||||
RunE: p.WithProject(func(ctx context.Context, project *types.Project) error {
|
||||
return backend.Create(ctx, project, api.CreateOptions{
|
||||
RemoveOrphans: opts.removeOrphans,
|
||||
Recreate: opts.recreateStrategy(),
|
||||
RecreateDependencies: opts.dependenciesRecreateStrategy(),
|
||||
Inherit: !opts.noInherit,
|
||||
Timeout: opts.GetTimeout(),
|
||||
QuietPull: false,
|
||||
})
|
||||
}),
|
||||
ValidArgsFunction: serviceCompletion(p),
|
||||
}
|
||||
flags := cmd.Flags()
|
||||
flags.BoolVar(&opts.Build, "build", false, "Build images before starting containers.")
|
||||
flags.BoolVar(&opts.noBuild, "no-build", false, "Don't build an image, even if it's missing.")
|
||||
flags.BoolVar(&opts.forceRecreate, "force-recreate", false, "Recreate containers even if their configuration and image haven't changed.")
|
||||
flags.BoolVar(&opts.noRecreate, "no-recreate", false, "If containers already exist, don't recreate them. Incompatible with --force-recreate.")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (opts createOptions) recreateStrategy() string {
|
||||
if opts.noRecreate {
|
||||
return api.RecreateNever
|
||||
}
|
||||
if opts.forceRecreate {
|
||||
return api.RecreateForce
|
||||
}
|
||||
return api.RecreateDiverged
|
||||
}
|
||||
|
||||
func (opts createOptions) dependenciesRecreateStrategy() string {
|
||||
if opts.noRecreate {
|
||||
return api.RecreateNever
|
||||
}
|
||||
if opts.recreateDeps {
|
||||
return api.RecreateForce
|
||||
}
|
||||
return api.RecreateDiverged
|
||||
}
|
||||
|
||||
func (opts createOptions) GetTimeout() *time.Duration {
|
||||
if opts.timeChanged {
|
||||
t := time.Duration(opts.timeout) * time.Second
|
||||
return &t
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (opts createOptions) Apply(project *types.Project) {
|
||||
if opts.Build {
|
||||
for i, service := range project.Services {
|
||||
if service.Build == nil {
|
||||
continue
|
||||
}
|
||||
service.PullPolicy = types.PullPolicyBuild
|
||||
project.Services[i] = service
|
||||
}
|
||||
}
|
||||
if opts.noBuild {
|
||||
for i, service := range project.Services {
|
||||
service.Build = nil
|
||||
project.Services[i] = service
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,94 +0,0 @@
|
|||
/*
|
||||
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"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
)
|
||||
|
||||
type downOptions struct {
|
||||
*projectOptions
|
||||
removeOrphans bool
|
||||
timeChanged bool
|
||||
timeout int
|
||||
volumes bool
|
||||
images string
|
||||
}
|
||||
|
||||
func downCommand(p *projectOptions, backend api.Service) *cobra.Command {
|
||||
opts := downOptions{
|
||||
projectOptions: p,
|
||||
}
|
||||
downCmd := &cobra.Command{
|
||||
Use: "down",
|
||||
Short: "Stop and remove containers, networks",
|
||||
PreRun: func(cmd *cobra.Command, args []string) {
|
||||
opts.timeChanged = cmd.Flags().Changed("timeout")
|
||||
},
|
||||
PreRunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
if opts.images != "" {
|
||||
if opts.images != "all" && opts.images != "local" {
|
||||
return fmt.Errorf("invalid value for --rmi: %q", opts.images)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}),
|
||||
RunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
return runDown(ctx, backend, opts)
|
||||
}),
|
||||
ValidArgsFunction: noCompletion(),
|
||||
}
|
||||
flags := downCmd.Flags()
|
||||
flags.BoolVar(&opts.removeOrphans, "remove-orphans", false, "Remove containers for services not defined in the Compose file.")
|
||||
flags.IntVarP(&opts.timeout, "timeout", "t", 10, "Specify a shutdown timeout in seconds")
|
||||
flags.BoolVarP(&opts.volumes, "volumes", "v", false, " Remove named volumes declared in the `volumes` section of the Compose file and anonymous volumes attached to containers.")
|
||||
flags.StringVar(&opts.images, "rmi", "", `Remove images used by services. "local" remove only images that don't have a custom tag ("local"|"all")`)
|
||||
return downCmd
|
||||
}
|
||||
|
||||
func runDown(ctx context.Context, backend api.Service, opts downOptions) error {
|
||||
name := opts.ProjectName
|
||||
var project *types.Project
|
||||
if opts.ProjectName == "" {
|
||||
p, err := opts.toProject(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
project = p
|
||||
name = p.Name
|
||||
}
|
||||
|
||||
var timeout *time.Duration
|
||||
if opts.timeChanged {
|
||||
timeoutValue := time.Duration(opts.timeout) * time.Second
|
||||
timeout = &timeoutValue
|
||||
}
|
||||
return backend.Down(ctx, name, api.DownOptions{
|
||||
RemoveOrphans: opts.removeOrphans,
|
||||
Project: project,
|
||||
Timeout: timeout,
|
||||
Images: opts.images,
|
||||
Volumes: opts.volumes,
|
||||
})
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
/*
|
||||
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"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
type eventsOpts struct {
|
||||
*composeOptions
|
||||
json bool
|
||||
}
|
||||
|
||||
func eventsCommand(p *projectOptions, backend api.Service) *cobra.Command {
|
||||
opts := eventsOpts{
|
||||
composeOptions: &composeOptions{
|
||||
projectOptions: p,
|
||||
},
|
||||
}
|
||||
cmd := &cobra.Command{
|
||||
Use: "events [options] [--] [SERVICE...]",
|
||||
Short: "Receive real time events from containers.",
|
||||
RunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
return runEvents(ctx, backend, opts, args)
|
||||
}),
|
||||
ValidArgsFunction: serviceCompletion(p),
|
||||
}
|
||||
|
||||
cmd.Flags().BoolVar(&opts.json, "json", false, "Output events as a stream of json objects")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runEvents(ctx context.Context, backend api.Service, opts eventsOpts, services []string) error {
|
||||
project, err := opts.toProjectName()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return backend.Events(ctx, project, api.EventsOptions{
|
||||
Services: services,
|
||||
Consumer: func(event api.Event) error {
|
||||
if opts.json {
|
||||
marshal, err := json.Marshal(map[string]interface{}{
|
||||
"time": event.Timestamp,
|
||||
"type": "container",
|
||||
"service": event.Service,
|
||||
"id": event.Container,
|
||||
"action": event.Status,
|
||||
"attributes": event.Attributes,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(string(marshal))
|
||||
} else {
|
||||
fmt.Println(event)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
})
|
||||
}
|
|
@ -1,125 +0,0 @@
|
|||
/*
|
||||
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"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/containerd/console"
|
||||
"github.com/docker/cli/cli"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
)
|
||||
|
||||
type execOpts struct {
|
||||
*composeOptions
|
||||
|
||||
service string
|
||||
command []string
|
||||
environment []string
|
||||
workingDir string
|
||||
|
||||
noTty bool
|
||||
user string
|
||||
detach bool
|
||||
index int
|
||||
privileged bool
|
||||
}
|
||||
|
||||
func execCommand(p *projectOptions, backend api.Service) *cobra.Command {
|
||||
opts := execOpts{
|
||||
composeOptions: &composeOptions{
|
||||
projectOptions: p,
|
||||
},
|
||||
}
|
||||
runCmd := &cobra.Command{
|
||||
Use: "exec [options] [-e KEY=VAL...] [--] SERVICE COMMAND [ARGS...]",
|
||||
Short: "Execute a command in a running container.",
|
||||
Args: cobra.MinimumNArgs(2),
|
||||
PreRunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
opts.service = args[0]
|
||||
opts.command = args[1:]
|
||||
return nil
|
||||
}),
|
||||
RunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
return runExec(ctx, backend, opts)
|
||||
}),
|
||||
ValidArgsFunction: serviceCompletion(p),
|
||||
}
|
||||
|
||||
runCmd.Flags().BoolVarP(&opts.detach, "detach", "d", false, "Detached mode: Run command in the background.")
|
||||
runCmd.Flags().StringArrayVarP(&opts.environment, "env", "e", []string{}, "Set environment variables")
|
||||
runCmd.Flags().IntVar(&opts.index, "index", 1, "index of the container if there are multiple instances of a service [default: 1].")
|
||||
runCmd.Flags().BoolVarP(&opts.privileged, "privileged", "", false, "Give extended privileges to the process.")
|
||||
runCmd.Flags().StringVarP(&opts.user, "user", "u", "", "Run the command as this user.")
|
||||
runCmd.Flags().BoolVarP(&opts.noTty, "no-TTY", "T", notAtTTY(), "Disable pseudo-TTY allocation. By default `docker compose exec` allocates a TTY.")
|
||||
runCmd.Flags().StringVarP(&opts.workingDir, "workdir", "w", "", "Path to workdir directory for this command.")
|
||||
|
||||
runCmd.Flags().SetInterspersed(false)
|
||||
return runCmd
|
||||
}
|
||||
|
||||
func runExec(ctx context.Context, backend api.Service, opts execOpts) error {
|
||||
project, err := opts.toProject(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
execOpts := api.RunOptions{
|
||||
Service: opts.service,
|
||||
Command: opts.command,
|
||||
Environment: opts.environment,
|
||||
Tty: !opts.noTty,
|
||||
User: opts.user,
|
||||
Privileged: opts.privileged,
|
||||
Index: opts.index,
|
||||
Detach: opts.detach,
|
||||
WorkingDir: opts.workingDir,
|
||||
|
||||
Stdin: os.Stdin,
|
||||
Stdout: os.Stdout,
|
||||
Stderr: os.Stderr,
|
||||
}
|
||||
|
||||
if execOpts.Tty {
|
||||
con := console.Current()
|
||||
if err := con.SetRaw(); err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if err := con.Reset(); err != nil {
|
||||
fmt.Println("Unable to close the console")
|
||||
}
|
||||
}()
|
||||
|
||||
execOpts.Stdin = con
|
||||
execOpts.Stdout = con
|
||||
execOpts.Stderr = con
|
||||
}
|
||||
exitCode, err := backend.Exec(ctx, project, execOpts)
|
||||
if exitCode != 0 {
|
||||
errMsg := ""
|
||||
if err != nil {
|
||||
errMsg = err.Error()
|
||||
}
|
||||
return cli.StatusError{StatusCode: exitCode, Status: errMsg}
|
||||
}
|
||||
return err
|
||||
}
|
|
@ -1,108 +0,0 @@
|
|||
/*
|
||||
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"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/docker/go-units"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/docker/compose-cli/cmd/formatter"
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
"github.com/docker/compose-cli/pkg/utils"
|
||||
)
|
||||
|
||||
type imageOptions struct {
|
||||
*projectOptions
|
||||
Quiet bool
|
||||
}
|
||||
|
||||
func imagesCommand(p *projectOptions, backend api.Service) *cobra.Command {
|
||||
opts := imageOptions{
|
||||
projectOptions: p,
|
||||
}
|
||||
imgCmd := &cobra.Command{
|
||||
Use: "images [SERVICE...]",
|
||||
Short: "List images used by the created containers",
|
||||
RunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
return runImages(ctx, backend, opts, args)
|
||||
}),
|
||||
ValidArgsFunction: serviceCompletion(p),
|
||||
}
|
||||
imgCmd.Flags().BoolVarP(&opts.Quiet, "quiet", "q", false, "Only display IDs")
|
||||
return imgCmd
|
||||
}
|
||||
|
||||
func runImages(ctx context.Context, backend api.Service, opts imageOptions, services []string) error {
|
||||
projectName, err := opts.toProjectName()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
images, err := backend.Images(ctx, projectName, api.ImagesOptions{
|
||||
Services: services,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if opts.Quiet {
|
||||
ids := []string{}
|
||||
for _, img := range images {
|
||||
id := img.ID
|
||||
if i := strings.IndexRune(img.ID, ':'); i >= 0 {
|
||||
id = id[i+1:]
|
||||
}
|
||||
if !utils.StringContains(ids, id) {
|
||||
ids = append(ids, id)
|
||||
}
|
||||
}
|
||||
for _, img := range ids {
|
||||
fmt.Println(img)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
sort.Slice(images, func(i, j int) bool {
|
||||
return images[i].ContainerName < images[j].ContainerName
|
||||
})
|
||||
|
||||
return formatter.Print(images, formatter.PRETTY, os.Stdout,
|
||||
func(w io.Writer) {
|
||||
for _, img := range images {
|
||||
id := stringid.TruncateID(img.ID)
|
||||
size := units.HumanSizeWithPrecision(float64(img.Size), 3)
|
||||
repo := img.Repository
|
||||
if repo == "" {
|
||||
repo = "<none>"
|
||||
}
|
||||
tag := img.Tag
|
||||
if tag == "" {
|
||||
tag = "<none>"
|
||||
}
|
||||
_, _ = fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\n", img.ContainerName, repo, tag, id, size)
|
||||
}
|
||||
},
|
||||
"Container", "Repository", "Tag", "Image Id", "Size")
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
/*
|
||||
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/spf13/cobra"
|
||||
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
)
|
||||
|
||||
func killCommand(p *projectOptions, backend api.Service) *cobra.Command {
|
||||
var opts api.KillOptions
|
||||
cmd := &cobra.Command{
|
||||
Use: "kill [options] [SERVICE...]",
|
||||
Short: "Force stop service containers.",
|
||||
RunE: p.WithProject(func(ctx context.Context, project *types.Project) error {
|
||||
return backend.Kill(ctx, project, opts)
|
||||
}),
|
||||
ValidArgsFunction: serviceCompletion(p),
|
||||
}
|
||||
|
||||
flags := cmd.Flags()
|
||||
flags.StringVarP(&opts.Signal, "signal", "s", "SIGKILL", "SIGNAL to send to the container.")
|
||||
|
||||
return cmd
|
||||
}
|
|
@ -1,114 +0,0 @@
|
|||
/*
|
||||
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"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/compose-cli/cmd/formatter"
|
||||
|
||||
"github.com/docker/cli/opts"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
)
|
||||
|
||||
type lsOptions struct {
|
||||
Format string
|
||||
Quiet bool
|
||||
All bool
|
||||
Filter opts.FilterOpt
|
||||
}
|
||||
|
||||
func listCommand(backend api.Service) *cobra.Command {
|
||||
opts := lsOptions{Filter: opts.NewFilterOpt()}
|
||||
lsCmd := &cobra.Command{
|
||||
Use: "ls",
|
||||
Short: "List running compose projects",
|
||||
RunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
return runList(ctx, backend, opts)
|
||||
}),
|
||||
ValidArgsFunction: noCompletion(),
|
||||
}
|
||||
lsCmd.Flags().StringVar(&opts.Format, "format", "pretty", "Format the output. Values: [pretty | json].")
|
||||
lsCmd.Flags().BoolVarP(&opts.Quiet, "quiet", "q", false, "Only display IDs.")
|
||||
lsCmd.Flags().Var(&opts.Filter, "filter", "Filter output based on conditions provided.")
|
||||
lsCmd.Flags().BoolVarP(&opts.All, "all", "a", false, "Show all stopped Compose projects")
|
||||
|
||||
return lsCmd
|
||||
}
|
||||
|
||||
var acceptedListFilters = map[string]bool{
|
||||
"name": true,
|
||||
}
|
||||
|
||||
func runList(ctx context.Context, backend api.Service, opts lsOptions) error {
|
||||
filters := opts.Filter.Value()
|
||||
err := filters.Validate(acceptedListFilters)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
stackList, err := backend.List(ctx, api.ListOptions{All: opts.All})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if opts.Quiet {
|
||||
for _, s := range stackList {
|
||||
fmt.Println(s.Name)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if filters.Len() > 0 {
|
||||
var filtered []api.Stack
|
||||
for _, s := range stackList {
|
||||
if filters.Contains("name") && !filters.Match("name", s.Name) {
|
||||
continue
|
||||
}
|
||||
filtered = append(filtered, s)
|
||||
}
|
||||
stackList = filtered
|
||||
}
|
||||
|
||||
view := viewFromStackList(stackList)
|
||||
return formatter.Print(view, opts.Format, os.Stdout, func(w io.Writer) {
|
||||
for _, stack := range view {
|
||||
_, _ = fmt.Fprintf(w, "%s\t%s\n", stack.Name, stack.Status)
|
||||
}
|
||||
}, "NAME", "STATUS")
|
||||
}
|
||||
|
||||
type stackView struct {
|
||||
Name string
|
||||
Status string
|
||||
}
|
||||
|
||||
func viewFromStackList(stackList []api.Stack) []stackView {
|
||||
retList := make([]stackView, len(stackList))
|
||||
for i, s := range stackList {
|
||||
retList[i] = stackView{
|
||||
Name: s.Name,
|
||||
Status: strings.TrimSpace(fmt.Sprintf("%s %s", s.Status, s.Reason)),
|
||||
}
|
||||
}
|
||||
return retList
|
||||
}
|
|
@ -1,79 +0,0 @@
|
|||
/*
|
||||
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"
|
||||
"os"
|
||||
|
||||
"github.com/docker/compose-cli/cmd/formatter"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
)
|
||||
|
||||
type logsOptions struct {
|
||||
*projectOptions
|
||||
composeOptions
|
||||
follow bool
|
||||
tail string
|
||||
since string
|
||||
until string
|
||||
noColor bool
|
||||
noPrefix bool
|
||||
timestamps bool
|
||||
}
|
||||
|
||||
func logsCommand(p *projectOptions, backend api.Service) *cobra.Command {
|
||||
opts := logsOptions{
|
||||
projectOptions: p,
|
||||
}
|
||||
logsCmd := &cobra.Command{
|
||||
Use: "logs [SERVICE...]",
|
||||
Short: "View output from containers",
|
||||
RunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
return runLogs(ctx, backend, opts, args)
|
||||
}),
|
||||
ValidArgsFunction: serviceCompletion(p),
|
||||
}
|
||||
flags := logsCmd.Flags()
|
||||
flags.BoolVarP(&opts.follow, "follow", "f", false, "Follow log output.")
|
||||
flags.StringVar(&opts.since, "since", "", "Show logs since timestamp (e.g. 2013-01-02T13:23:37Z) or relative (e.g. 42m for 42 minutes)")
|
||||
flags.StringVar(&opts.until, "until", "", "Show logs before a timestamp (e.g. 2013-01-02T13:23:37Z) or relative (e.g. 42m for 42 minutes)")
|
||||
flags.BoolVar(&opts.noColor, "no-color", false, "Produce monochrome output.")
|
||||
flags.BoolVar(&opts.noPrefix, "no-log-prefix", false, "Don't print prefix in logs.")
|
||||
flags.BoolVarP(&opts.timestamps, "timestamps", "t", false, "Show timestamps.")
|
||||
flags.StringVar(&opts.tail, "tail", "all", "Number of lines to show from the end of the logs for each container.")
|
||||
return logsCmd
|
||||
}
|
||||
|
||||
func runLogs(ctx context.Context, backend api.Service, opts logsOptions, services []string) error {
|
||||
projectName, err := opts.toProjectName()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
consumer := formatter.NewLogConsumer(ctx, os.Stdout, !opts.noColor, !opts.noPrefix)
|
||||
return backend.Logs(ctx, projectName, consumer, api.LogOptions{
|
||||
Services: services,
|
||||
Follow: opts.follow,
|
||||
Tail: opts.tail,
|
||||
Since: opts.since,
|
||||
Until: opts.until,
|
||||
Timestamps: opts.timestamps,
|
||||
})
|
||||
}
|
|
@ -1,85 +0,0 @@
|
|||
/*
|
||||
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/spf13/cobra"
|
||||
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
)
|
||||
|
||||
type pauseOptions struct {
|
||||
*projectOptions
|
||||
}
|
||||
|
||||
func pauseCommand(p *projectOptions, backend api.Service) *cobra.Command {
|
||||
opts := pauseOptions{
|
||||
projectOptions: p,
|
||||
}
|
||||
cmd := &cobra.Command{
|
||||
Use: "pause [SERVICE...]",
|
||||
Short: "pause services",
|
||||
RunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
return runPause(ctx, backend, opts, args)
|
||||
}),
|
||||
ValidArgsFunction: serviceCompletion(p),
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runPause(ctx context.Context, backend api.Service, opts pauseOptions, services []string) error {
|
||||
project, err := opts.toProjectName()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return backend.Pause(ctx, project, api.PauseOptions{
|
||||
Services: services,
|
||||
})
|
||||
}
|
||||
|
||||
type unpauseOptions struct {
|
||||
*projectOptions
|
||||
}
|
||||
|
||||
func unpauseCommand(p *projectOptions, backend api.Service) *cobra.Command {
|
||||
opts := unpauseOptions{
|
||||
projectOptions: p,
|
||||
}
|
||||
cmd := &cobra.Command{
|
||||
Use: "unpause [SERVICE...]",
|
||||
Short: "unpause services",
|
||||
RunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
return runUnPause(ctx, backend, opts, args)
|
||||
}),
|
||||
ValidArgsFunction: serviceCompletion(p),
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runUnPause(ctx context.Context, backend api.Service, opts unpauseOptions, services []string) error {
|
||||
project, err := opts.toProjectName()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return backend.UnPause(ctx, project, api.PauseOptions{
|
||||
Services: services,
|
||||
})
|
||||
}
|
|
@ -1,77 +0,0 @@
|
|||
/*
|
||||
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"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
)
|
||||
|
||||
type portOptions struct {
|
||||
*projectOptions
|
||||
port int
|
||||
protocol string
|
||||
index int
|
||||
}
|
||||
|
||||
func portCommand(p *projectOptions, backend api.Service) *cobra.Command {
|
||||
opts := portOptions{
|
||||
projectOptions: p,
|
||||
}
|
||||
cmd := &cobra.Command{
|
||||
Use: "port [options] [--] SERVICE PRIVATE_PORT",
|
||||
Short: "Print the public port for a port binding.",
|
||||
Args: cobra.MinimumNArgs(2),
|
||||
PreRunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
port, err := strconv.Atoi(args[1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
opts.port = port
|
||||
return nil
|
||||
}),
|
||||
RunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
return runPort(ctx, backend, opts, args[0])
|
||||
}),
|
||||
ValidArgsFunction: serviceCompletion(p),
|
||||
}
|
||||
cmd.Flags().StringVar(&opts.protocol, "protocol", "tcp", "tcp or udp")
|
||||
cmd.Flags().IntVar(&opts.index, "index", 1, "index of the container if service has multiple replicas")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runPort(ctx context.Context, backend api.Service, opts portOptions, service string) error {
|
||||
projectName, err := opts.toProjectName()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ip, port, err := backend.Port(ctx, projectName, service, opts.port, api.PortOptions{
|
||||
Protocol: opts.protocol,
|
||||
Index: opts.index,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("%s:%d\n", ip, port)
|
||||
return nil
|
||||
}
|
|
@ -1,188 +0,0 @@
|
|||
/*
|
||||
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"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/compose-cli/cmd/formatter"
|
||||
|
||||
formatter2 "github.com/docker/cli/cli/command/formatter"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
"github.com/docker/compose-cli/pkg/utils"
|
||||
)
|
||||
|
||||
type psOptions struct {
|
||||
*projectOptions
|
||||
Format string
|
||||
All bool
|
||||
Quiet bool
|
||||
Services bool
|
||||
Filter string
|
||||
Status string
|
||||
}
|
||||
|
||||
func (p *psOptions) parseFilter() error {
|
||||
if p.Filter == "" {
|
||||
return nil
|
||||
}
|
||||
parts := strings.SplitN(p.Filter, "=", 2)
|
||||
if len(parts) != 2 {
|
||||
return errors.New("arguments to --filter should be in form KEY=VAL")
|
||||
}
|
||||
switch parts[0] {
|
||||
case "status":
|
||||
p.Status = parts[1]
|
||||
case "source":
|
||||
return api.ErrNotImplemented
|
||||
default:
|
||||
return fmt.Errorf("unknow filter %s", parts[0])
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func psCommand(p *projectOptions, backend api.Service) *cobra.Command {
|
||||
opts := psOptions{
|
||||
projectOptions: p,
|
||||
}
|
||||
psCmd := &cobra.Command{
|
||||
Use: "ps [SERVICE...]",
|
||||
Short: "List containers",
|
||||
PreRunE: func(cmd *cobra.Command, args []string) error {
|
||||
return opts.parseFilter()
|
||||
},
|
||||
RunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
return runPs(ctx, backend, args, opts)
|
||||
}),
|
||||
ValidArgsFunction: serviceCompletion(p),
|
||||
}
|
||||
flags := psCmd.Flags()
|
||||
flags.StringVar(&opts.Format, "format", "pretty", "Format the output. Values: [pretty | json]")
|
||||
flags.StringVar(&opts.Filter, "filter", "", "Filter services by a property")
|
||||
flags.StringVar(&opts.Status, "status", "", "Filter services by status")
|
||||
flags.BoolVarP(&opts.Quiet, "quiet", "q", false, "Only display IDs")
|
||||
flags.BoolVar(&opts.Services, "services", false, "Display services")
|
||||
flags.BoolVarP(&opts.All, "all", "a", false, "Show all stopped containers (including those created by the run command)")
|
||||
flags.Lookup("filter").Hidden = true
|
||||
return psCmd
|
||||
}
|
||||
|
||||
func runPs(ctx context.Context, backend api.Service, services []string, opts psOptions) error {
|
||||
projectName, err := opts.toProjectName()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
containers, err := backend.Ps(ctx, projectName, api.PsOptions{
|
||||
All: opts.All,
|
||||
Services: services,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if opts.Services {
|
||||
services := []string{}
|
||||
for _, s := range containers {
|
||||
if !utils.StringContains(services, s.Service) {
|
||||
services = append(services, s.Service)
|
||||
}
|
||||
}
|
||||
fmt.Println(strings.Join(services, "\n"))
|
||||
return nil
|
||||
}
|
||||
|
||||
SERVICES:
|
||||
for _, s := range services {
|
||||
for _, c := range containers {
|
||||
if c.Service == s {
|
||||
continue SERVICES
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("no such service: %s", s)
|
||||
}
|
||||
|
||||
if len(containers) == 0 {
|
||||
return api.ErrNotFound
|
||||
}
|
||||
|
||||
if opts.Status != "" {
|
||||
containers = filterByStatus(containers, opts.Status)
|
||||
}
|
||||
|
||||
sort.Slice(containers, func(i, j int) bool {
|
||||
return containers[i].Name < containers[j].Name
|
||||
})
|
||||
|
||||
if opts.Quiet {
|
||||
for _, c := range containers {
|
||||
fmt.Println(c.ID)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
return formatter.Print(containers, opts.Format, os.Stdout,
|
||||
writter(containers),
|
||||
"NAME", "COMMAND", "SERVICE", "STATUS", "PORTS")
|
||||
}
|
||||
|
||||
func writter(containers []api.ContainerSummary) func(w io.Writer) {
|
||||
return func(w io.Writer) {
|
||||
for _, container := range containers {
|
||||
var ports []string
|
||||
for _, p := range container.Publishers {
|
||||
if p.URL == "" {
|
||||
ports = append(ports, fmt.Sprintf("%d/%s", p.TargetPort, p.Protocol))
|
||||
} else {
|
||||
ports = append(ports, fmt.Sprintf("%s->%d/%s", p.URL, p.TargetPort, p.Protocol))
|
||||
}
|
||||
}
|
||||
status := container.State
|
||||
if status == "running" && container.Health != "" {
|
||||
status = fmt.Sprintf("%s (%s)", container.State, container.Health)
|
||||
} else if status == "exited" || status == "dead" {
|
||||
status = fmt.Sprintf("%s (%d)", container.State, container.ExitCode)
|
||||
}
|
||||
command := formatter2.Ellipsis(container.Command, 20)
|
||||
_, _ = fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\n", container.Name, strconv.Quote(command), container.Service, status, strings.Join(ports, ", "))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func filterByStatus(containers []api.ContainerSummary, status string) []api.ContainerSummary {
|
||||
hasContainerWithState := map[string]struct{}{}
|
||||
for _, c := range containers {
|
||||
if c.State == status {
|
||||
hasContainerWithState[c.Service] = struct{}{}
|
||||
}
|
||||
}
|
||||
var filtered []api.ContainerSummary
|
||||
for _, c := range containers {
|
||||
if _, ok := hasContainerWithState[c.Service]; ok {
|
||||
filtered = append(filtered, c)
|
||||
}
|
||||
}
|
||||
return filtered
|
||||
}
|
|
@ -1,93 +0,0 @@
|
|||
/*
|
||||
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"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/morikuni/aec"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
"github.com/docker/compose-cli/pkg/utils"
|
||||
)
|
||||
|
||||
type pullOptions struct {
|
||||
*projectOptions
|
||||
composeOptions
|
||||
quiet bool
|
||||
parallel bool
|
||||
noParallel bool
|
||||
includeDeps bool
|
||||
ignorePullFailures bool
|
||||
}
|
||||
|
||||
func pullCommand(p *projectOptions, backend api.Service) *cobra.Command {
|
||||
opts := pullOptions{
|
||||
projectOptions: p,
|
||||
}
|
||||
cmd := &cobra.Command{
|
||||
Use: "pull [SERVICE...]",
|
||||
Short: "Pull service images",
|
||||
PreRunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
if opts.noParallel {
|
||||
fmt.Fprint(os.Stderr, aec.Apply("option '--no-parallel' is DEPRECATED and will be ignored.\n", aec.RedF))
|
||||
}
|
||||
return nil
|
||||
}),
|
||||
RunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
return runPull(ctx, backend, opts, args)
|
||||
}),
|
||||
ValidArgsFunction: serviceCompletion(p),
|
||||
}
|
||||
flags := cmd.Flags()
|
||||
flags.BoolVarP(&opts.quiet, "quiet", "q", false, "Pull without printing progress information")
|
||||
cmd.Flags().BoolVar(&opts.includeDeps, "include-deps", false, "Also pull services declared as dependencies")
|
||||
cmd.Flags().BoolVar(&opts.parallel, "parallel", true, "DEPRECATED pull multiple images in parallel.")
|
||||
flags.MarkHidden("parallel") //nolint:errcheck
|
||||
cmd.Flags().BoolVar(&opts.parallel, "no-parallel", true, "DEPRECATED disable parallel pulling.")
|
||||
flags.MarkHidden("no-parallel") //nolint:errcheck
|
||||
cmd.Flags().BoolVar(&opts.ignorePullFailures, "ignore-pull-failures", false, "Pull what it can and ignores images with pull failures")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runPull(ctx context.Context, backend api.Service, opts pullOptions, services []string) error {
|
||||
project, err := opts.toProject(services)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !opts.includeDeps {
|
||||
enabled, err := project.GetServices(services...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, s := range project.Services {
|
||||
if !utils.StringContains(services, s.Name) {
|
||||
project.DisabledServices = append(project.DisabledServices, s)
|
||||
}
|
||||
}
|
||||
project.Services = enabled
|
||||
}
|
||||
|
||||
return backend.Pull(ctx, project, api.PullOptions{
|
||||
Quiet: opts.quiet,
|
||||
IgnoreFailures: opts.ignorePullFailures,
|
||||
})
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
/*
|
||||
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/spf13/cobra"
|
||||
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
)
|
||||
|
||||
type pushOptions struct {
|
||||
*projectOptions
|
||||
composeOptions
|
||||
|
||||
Ignorefailures bool
|
||||
}
|
||||
|
||||
func pushCommand(p *projectOptions, backend api.Service) *cobra.Command {
|
||||
opts := pushOptions{
|
||||
projectOptions: p,
|
||||
}
|
||||
pushCmd := &cobra.Command{
|
||||
Use: "push [SERVICE...]",
|
||||
Short: "Push service images",
|
||||
RunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
return runPush(ctx, backend, opts, args)
|
||||
}),
|
||||
ValidArgsFunction: serviceCompletion(p),
|
||||
}
|
||||
pushCmd.Flags().BoolVar(&opts.Ignorefailures, "ignore-push-failures", false, "Push what it can and ignores images with push failures")
|
||||
|
||||
return pushCmd
|
||||
}
|
||||
|
||||
func runPush(ctx context.Context, backend api.Service, opts pushOptions, services []string) error {
|
||||
project, err := opts.toProject(services)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return backend.Push(ctx, project, api.PushOptions{
|
||||
IgnoreFailures: opts.Ignorefailures,
|
||||
})
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
/*
|
||||
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/docker/compose-cli/pkg/api"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
type removeOptions struct {
|
||||
*projectOptions
|
||||
force bool
|
||||
stop bool
|
||||
volumes bool
|
||||
}
|
||||
|
||||
func removeCommand(p *projectOptions, backend api.Service) *cobra.Command {
|
||||
opts := removeOptions{
|
||||
projectOptions: p,
|
||||
}
|
||||
cmd := &cobra.Command{
|
||||
Use: "rm [SERVICE...]",
|
||||
Short: "Removes stopped service containers",
|
||||
Long: `Removes stopped service containers
|
||||
|
||||
By default, anonymous volumes attached to containers will not be removed. You
|
||||
can override this with -v. To list all volumes, use "docker volume ls".
|
||||
|
||||
Any data which is not in a volume will be lost.`,
|
||||
RunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
return runRemove(ctx, backend, opts, args)
|
||||
}),
|
||||
ValidArgsFunction: serviceCompletion(p),
|
||||
}
|
||||
f := cmd.Flags()
|
||||
f.BoolVarP(&opts.force, "force", "f", false, "Don't ask to confirm removal")
|
||||
f.BoolVarP(&opts.stop, "stop", "s", false, "Stop the containers, if required, before removing")
|
||||
f.BoolVarP(&opts.volumes, "volumes", "v", false, "Remove any anonymous volumes attached to containers")
|
||||
f.BoolP("all", "a", false, "Deprecated - no effect")
|
||||
f.MarkHidden("all") //nolint:errcheck
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runRemove(ctx context.Context, backend api.Service, opts removeOptions, services []string) error {
|
||||
project, err := opts.toProject(services)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if opts.stop {
|
||||
err := backend.Stop(ctx, project, api.StopOptions{
|
||||
Services: services,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return backend.Remove(ctx, project, api.RemoveOptions{
|
||||
Services: services,
|
||||
Force: opts.force,
|
||||
Volumes: opts.volumes,
|
||||
})
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
/*
|
||||
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"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
)
|
||||
|
||||
type restartOptions struct {
|
||||
*projectOptions
|
||||
timeout int
|
||||
}
|
||||
|
||||
func restartCommand(p *projectOptions, backend api.Service) *cobra.Command {
|
||||
opts := restartOptions{
|
||||
projectOptions: p,
|
||||
}
|
||||
restartCmd := &cobra.Command{
|
||||
Use: "restart",
|
||||
Short: "Restart containers",
|
||||
RunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
return runRestart(ctx, backend, opts, args)
|
||||
}),
|
||||
ValidArgsFunction: serviceCompletion(p),
|
||||
}
|
||||
flags := restartCmd.Flags()
|
||||
flags.IntVarP(&opts.timeout, "timeout", "t", 10, "Specify a shutdown timeout in seconds")
|
||||
|
||||
return restartCmd
|
||||
}
|
||||
|
||||
func runRestart(ctx context.Context, backend api.Service, opts restartOptions, services []string) error {
|
||||
project, err := opts.toProject(services)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
timeout := time.Duration(opts.timeout) * time.Second
|
||||
return backend.Restart(ctx, project, api.RestartOptions{
|
||||
Timeout: &timeout,
|
||||
Services: services,
|
||||
})
|
||||
}
|
|
@ -1,232 +0,0 @@
|
|||
/*
|
||||
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"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/compose-spec/compose-go/loader"
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/mattn/go-isatty"
|
||||
"github.com/mattn/go-shellwords"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/docker/cli/cli"
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
"github.com/docker/compose-cli/pkg/progress"
|
||||
)
|
||||
|
||||
type runOptions struct {
|
||||
*composeOptions
|
||||
Service string
|
||||
Command []string
|
||||
environment []string
|
||||
Detach bool
|
||||
Remove bool
|
||||
noTty bool
|
||||
user string
|
||||
workdir string
|
||||
entrypoint string
|
||||
labels []string
|
||||
volumes []string
|
||||
publish []string
|
||||
useAliases bool
|
||||
servicePorts bool
|
||||
name string
|
||||
noDeps bool
|
||||
}
|
||||
|
||||
func (opts runOptions) apply(project *types.Project) error {
|
||||
target, err := project.GetService(opts.Service)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !opts.servicePorts {
|
||||
target.Ports = []types.ServicePortConfig{}
|
||||
}
|
||||
if len(opts.publish) > 0 {
|
||||
target.Ports = []types.ServicePortConfig{}
|
||||
for _, p := range opts.publish {
|
||||
config, err := types.ParsePortConfig(p)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
target.Ports = append(target.Ports, config...)
|
||||
}
|
||||
}
|
||||
if len(opts.volumes) > 0 {
|
||||
for _, v := range opts.volumes {
|
||||
volume, err := loader.ParseVolume(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
target.Volumes = append(target.Volumes, volume)
|
||||
}
|
||||
}
|
||||
|
||||
if opts.noDeps {
|
||||
for _, s := range project.Services {
|
||||
if s.Name != opts.Service {
|
||||
project.DisabledServices = append(project.DisabledServices, s)
|
||||
}
|
||||
}
|
||||
project.Services = types.Services{target}
|
||||
}
|
||||
|
||||
for i, s := range project.Services {
|
||||
if s.Name == opts.Service {
|
||||
project.Services[i] = target
|
||||
break
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func runCommand(p *projectOptions, backend api.Service) *cobra.Command {
|
||||
opts := runOptions{
|
||||
composeOptions: &composeOptions{
|
||||
projectOptions: p,
|
||||
},
|
||||
}
|
||||
cmd := &cobra.Command{
|
||||
Use: "run [options] [-v VOLUME...] [-p PORT...] [-e KEY=VAL...] [-l KEY=VALUE...] SERVICE [COMMAND] [ARGS...]",
|
||||
Short: "Run a one-off command on a service.",
|
||||
Args: cobra.MinimumNArgs(1),
|
||||
PreRunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
opts.Service = args[0]
|
||||
if len(args) > 1 {
|
||||
opts.Command = args[1:]
|
||||
}
|
||||
if len(opts.publish) > 0 && opts.servicePorts {
|
||||
return fmt.Errorf("--service-ports and --publish are incompatible")
|
||||
}
|
||||
return nil
|
||||
}),
|
||||
RunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
project, err := p.toProject([]string{opts.Service})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return runRun(ctx, backend, project, opts)
|
||||
}),
|
||||
ValidArgsFunction: serviceCompletion(p),
|
||||
}
|
||||
flags := cmd.Flags()
|
||||
flags.BoolVarP(&opts.Detach, "detach", "d", false, "Run container in background and print container ID")
|
||||
flags.StringArrayVarP(&opts.environment, "env", "e", []string{}, "Set environment variables")
|
||||
flags.StringArrayVarP(&opts.labels, "labels", "l", []string{}, "Add or override a label")
|
||||
flags.BoolVar(&opts.Remove, "rm", false, "Automatically remove the container when it exits")
|
||||
flags.BoolVarP(&opts.noTty, "no-TTY", "T", notAtTTY(), "Disable pseudo-noTty allocation. By default docker compose run allocates a TTY")
|
||||
flags.StringVar(&opts.name, "name", "", " Assign a name to the container")
|
||||
flags.StringVarP(&opts.user, "user", "u", "", "Run as specified username or uid")
|
||||
flags.StringVarP(&opts.workdir, "workdir", "w", "", "Working directory inside the container")
|
||||
flags.StringVar(&opts.entrypoint, "entrypoint", "", "Override the entrypoint of the image")
|
||||
flags.BoolVar(&opts.noDeps, "no-deps", false, "Don't start linked services.")
|
||||
flags.StringArrayVarP(&opts.volumes, "volumes", "v", []string{}, "Bind mount a volume.")
|
||||
flags.StringArrayVarP(&opts.publish, "publish", "p", []string{}, "Publish a container's port(s) to the host.")
|
||||
flags.BoolVar(&opts.useAliases, "use-aliases", false, "Use the service's network useAliases in the network(s) the container connects to.")
|
||||
flags.BoolVar(&opts.servicePorts, "service-ports", false, "Run command with the service's ports enabled and mapped to the host.")
|
||||
|
||||
flags.SetInterspersed(false)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func notAtTTY() bool {
|
||||
return !isatty.IsTerminal(os.Stdout.Fd())
|
||||
}
|
||||
|
||||
func runRun(ctx context.Context, backend api.Service, project *types.Project, opts runOptions) error {
|
||||
err := opts.apply(project)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = progress.Run(ctx, func(ctx context.Context) error {
|
||||
return startDependencies(ctx, backend, *project, opts.Service)
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var entrypoint []string
|
||||
if opts.entrypoint != "" {
|
||||
entrypoint, err = shellwords.Parse(opts.entrypoint)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
labels := types.Labels{}
|
||||
for _, s := range opts.labels {
|
||||
parts := strings.SplitN(s, "=", 2)
|
||||
if len(parts) != 2 {
|
||||
return fmt.Errorf("label must be set as KEY=VALUE")
|
||||
}
|
||||
labels[parts[0]] = parts[1]
|
||||
}
|
||||
|
||||
// start container and attach to container streams
|
||||
runOpts := api.RunOptions{
|
||||
Name: opts.name,
|
||||
Service: opts.Service,
|
||||
Command: opts.Command,
|
||||
Detach: opts.Detach,
|
||||
AutoRemove: opts.Remove,
|
||||
Stdin: os.Stdin,
|
||||
Stdout: os.Stdout,
|
||||
Stderr: os.Stderr,
|
||||
Tty: !opts.noTty,
|
||||
WorkingDir: opts.workdir,
|
||||
User: opts.user,
|
||||
Environment: opts.environment,
|
||||
Entrypoint: entrypoint,
|
||||
Labels: labels,
|
||||
UseNetworkAliases: opts.useAliases,
|
||||
Index: 0,
|
||||
}
|
||||
exitCode, err := backend.RunOneOffContainer(ctx, project, runOpts)
|
||||
if exitCode != 0 {
|
||||
errMsg := ""
|
||||
if err != nil {
|
||||
errMsg = err.Error()
|
||||
}
|
||||
return cli.StatusError{StatusCode: exitCode, Status: errMsg}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func startDependencies(ctx context.Context, backend api.Service, project types.Project, requestedServiceName string) error {
|
||||
dependencies := types.Services{}
|
||||
var requestedService types.ServiceConfig
|
||||
for _, service := range project.Services {
|
||||
if service.Name != requestedServiceName {
|
||||
dependencies = append(dependencies, service)
|
||||
} else {
|
||||
requestedService = service
|
||||
}
|
||||
}
|
||||
|
||||
project.Services = dependencies
|
||||
project.DisabledServices = append(project.DisabledServices, requestedService)
|
||||
if err := backend.Create(ctx, &project, api.CreateOptions{}); err != nil {
|
||||
return err
|
||||
}
|
||||
return backend.Start(ctx, &project, api.StartOptions{})
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
/*
|
||||
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/docker/compose-cli/pkg/api"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
type startOptions struct {
|
||||
*projectOptions
|
||||
}
|
||||
|
||||
func startCommand(p *projectOptions, backend api.Service) *cobra.Command {
|
||||
opts := startOptions{
|
||||
projectOptions: p,
|
||||
}
|
||||
startCmd := &cobra.Command{
|
||||
Use: "start [SERVICE...]",
|
||||
Short: "Start services",
|
||||
RunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
return runStart(ctx, backend, opts, args)
|
||||
}),
|
||||
ValidArgsFunction: serviceCompletion(p),
|
||||
}
|
||||
return startCmd
|
||||
}
|
||||
|
||||
func runStart(ctx context.Context, backend api.Service, opts startOptions, services []string) error {
|
||||
project, err := opts.toProject(services)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return backend.Start(ctx, project, api.StartOptions{})
|
||||
}
|
|
@ -1,70 +0,0 @@
|
|||
/*
|
||||
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"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
)
|
||||
|
||||
type stopOptions struct {
|
||||
*projectOptions
|
||||
timeChanged bool
|
||||
timeout int
|
||||
}
|
||||
|
||||
func stopCommand(p *projectOptions, backend api.Service) *cobra.Command {
|
||||
opts := stopOptions{
|
||||
projectOptions: p,
|
||||
}
|
||||
cmd := &cobra.Command{
|
||||
Use: "stop [SERVICE...]",
|
||||
Short: "Stop services",
|
||||
PreRun: func(cmd *cobra.Command, args []string) {
|
||||
opts.timeChanged = cmd.Flags().Changed("timeout")
|
||||
},
|
||||
RunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
return runStop(ctx, backend, opts, args)
|
||||
}),
|
||||
ValidArgsFunction: serviceCompletion(p),
|
||||
}
|
||||
flags := cmd.Flags()
|
||||
flags.IntVarP(&opts.timeout, "timeout", "t", 10, "Specify a shutdown timeout in seconds")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runStop(ctx context.Context, backend api.Service, opts stopOptions, services []string) error {
|
||||
project, err := opts.toProject(services)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var timeout *time.Duration
|
||||
if opts.timeChanged {
|
||||
timeoutValue := time.Duration(opts.timeout) * time.Second
|
||||
timeout = &timeoutValue
|
||||
}
|
||||
return backend.Stop(ctx, project, api.StopOptions{
|
||||
Timeout: timeout,
|
||||
Services: services,
|
||||
})
|
||||
}
|
|
@ -1,92 +0,0 @@
|
|||
/*
|
||||
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"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
)
|
||||
|
||||
type topOptions struct {
|
||||
*projectOptions
|
||||
}
|
||||
|
||||
func topCommand(p *projectOptions, backend api.Service) *cobra.Command {
|
||||
opts := topOptions{
|
||||
projectOptions: p,
|
||||
}
|
||||
topCmd := &cobra.Command{
|
||||
Use: "top [SERVICES...]",
|
||||
Short: "Display the running processes",
|
||||
RunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
return runTop(ctx, backend, opts, args)
|
||||
}),
|
||||
ValidArgsFunction: serviceCompletion(p),
|
||||
}
|
||||
return topCmd
|
||||
}
|
||||
|
||||
func runTop(ctx context.Context, backend api.Service, opts topOptions, services []string) error {
|
||||
projectName, err := opts.toProjectName()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
containers, err := backend.Top(ctx, projectName, services)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sort.Slice(containers, func(i, j int) bool {
|
||||
return containers[i].Name < containers[j].Name
|
||||
})
|
||||
|
||||
for _, container := range containers {
|
||||
fmt.Printf("%s\n", container.Name)
|
||||
err := psPrinter(os.Stdout, func(w io.Writer) {
|
||||
for _, proc := range container.Processes {
|
||||
info := []interface{}{}
|
||||
for _, p := range proc {
|
||||
info = append(info, p)
|
||||
}
|
||||
_, _ = fmt.Fprintf(w, strings.Repeat("%s\t", len(info))+"\n", info...)
|
||||
|
||||
}
|
||||
fmt.Fprintln(w)
|
||||
},
|
||||
container.Titles...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func psPrinter(out io.Writer, printer func(writer io.Writer), headers ...string) error {
|
||||
w := tabwriter.NewWriter(out, 5, 1, 3, ' ', 0)
|
||||
_, _ = fmt.Fprintln(w, strings.Join(headers, "\t"))
|
||||
printer(w)
|
||||
return w.Flush()
|
||||
}
|
|
@ -1,209 +0,0 @@
|
|||
/*
|
||||
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"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/compose-cli/cmd/formatter"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
"github.com/docker/compose-cli/pkg/utils"
|
||||
)
|
||||
|
||||
// composeOptions hold options common to `up` and `run` to run compose project
|
||||
type composeOptions struct {
|
||||
*projectOptions
|
||||
}
|
||||
|
||||
type upOptions struct {
|
||||
*composeOptions
|
||||
Detach bool
|
||||
Environment []string
|
||||
noStart bool
|
||||
noDeps bool
|
||||
cascadeStop bool
|
||||
exitCodeFrom string
|
||||
scale []string
|
||||
noColor bool
|
||||
noPrefix bool
|
||||
attachDependencies bool
|
||||
}
|
||||
|
||||
func (opts upOptions) apply(project *types.Project, services []string) error {
|
||||
if opts.noDeps {
|
||||
enabled, err := project.GetServices(services...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, s := range project.Services {
|
||||
if !utils.StringContains(services, s.Name) {
|
||||
project.DisabledServices = append(project.DisabledServices, s)
|
||||
}
|
||||
}
|
||||
project.Services = enabled
|
||||
}
|
||||
|
||||
if opts.exitCodeFrom != "" {
|
||||
_, err := project.GetService(opts.exitCodeFrom)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for _, scale := range opts.scale {
|
||||
split := strings.Split(scale, "=")
|
||||
if len(split) != 2 {
|
||||
return fmt.Errorf("invalid --scale option %q. Should be SERVICE=NUM", scale)
|
||||
}
|
||||
name := split[0]
|
||||
replicas, err := strconv.Atoi(split[1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = setServiceScale(project, name, replicas)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func upCommand(p *projectOptions, backend api.Service) *cobra.Command {
|
||||
up := upOptions{}
|
||||
create := createOptions{}
|
||||
upCmd := &cobra.Command{
|
||||
Use: "up [SERVICE...]",
|
||||
Short: "Create and start containers",
|
||||
PreRun: func(cmd *cobra.Command, args []string) {
|
||||
create.timeChanged = cmd.Flags().Changed("timeout")
|
||||
},
|
||||
PreRunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
if up.exitCodeFrom != "" {
|
||||
up.cascadeStop = true
|
||||
}
|
||||
if create.Build && create.noBuild {
|
||||
return fmt.Errorf("--build and --no-build are incompatible")
|
||||
}
|
||||
if up.Detach && (up.attachDependencies || up.cascadeStop) {
|
||||
return fmt.Errorf("--detach cannot be combined with --abort-on-container-exit or --attach-dependencies")
|
||||
}
|
||||
if create.forceRecreate && create.noRecreate {
|
||||
return fmt.Errorf("--force-recreate and --no-recreate are incompatible")
|
||||
}
|
||||
if create.recreateDeps && create.noRecreate {
|
||||
return fmt.Errorf("--always-recreate-deps and --no-recreate are incompatible")
|
||||
}
|
||||
return nil
|
||||
}),
|
||||
RunE: p.WithServices(func(ctx context.Context, project *types.Project, services []string) error {
|
||||
return runUp(ctx, backend, create, up, project, services)
|
||||
}),
|
||||
ValidArgsFunction: serviceCompletion(p),
|
||||
}
|
||||
flags := upCmd.Flags()
|
||||
flags.StringArrayVarP(&up.Environment, "environment", "e", []string{}, "Environment variables")
|
||||
flags.BoolVarP(&up.Detach, "detach", "d", false, "Detached mode: Run containers in the background")
|
||||
flags.BoolVar(&create.Build, "build", false, "Build images before starting containers.")
|
||||
flags.BoolVar(&create.noBuild, "no-build", false, "Don't build an image, even if it's missing.")
|
||||
flags.BoolVar(&create.removeOrphans, "remove-orphans", false, "Remove containers for services not defined in the Compose file.")
|
||||
flags.StringArrayVar(&up.scale, "scale", []string{}, "Scale SERVICE to NUM instances. Overrides the `scale` setting in the Compose file if present.")
|
||||
flags.BoolVar(&up.noColor, "no-color", false, "Produce monochrome output.")
|
||||
flags.BoolVar(&up.noPrefix, "no-log-prefix", false, "Don't print prefix in logs.")
|
||||
flags.BoolVar(&create.forceRecreate, "force-recreate", false, "Recreate containers even if their configuration and image haven't changed.")
|
||||
flags.BoolVar(&create.noRecreate, "no-recreate", false, "If containers already exist, don't recreate them. Incompatible with --force-recreate.")
|
||||
flags.BoolVar(&up.noStart, "no-start", false, "Don't start the services after creating them.")
|
||||
flags.BoolVar(&up.cascadeStop, "abort-on-container-exit", false, "Stops all containers if any container was stopped. Incompatible with -d")
|
||||
flags.StringVar(&up.exitCodeFrom, "exit-code-from", "", "Return the exit code of the selected service container. Implies --abort-on-container-exit")
|
||||
flags.IntVarP(&create.timeout, "timeout", "t", 10, "Use this timeout in seconds for container shutdown when attached or when containers are already running.")
|
||||
flags.BoolVar(&up.noDeps, "no-deps", false, "Don't start linked services.")
|
||||
flags.BoolVar(&create.recreateDeps, "always-recreate-deps", false, "Recreate dependent containers. Incompatible with --no-recreate.")
|
||||
flags.BoolVarP(&create.noInherit, "renew-anon-volumes", "V", false, "Recreate anonymous volumes instead of retrieving data from the previous containers.")
|
||||
flags.BoolVar(&up.attachDependencies, "attach-dependencies", false, "Attach to dependent containers.")
|
||||
flags.BoolVar(&create.quietPull, "quiet-pull", false, "Pull without printing progress information.")
|
||||
|
||||
return upCmd
|
||||
}
|
||||
|
||||
func runUp(ctx context.Context, backend api.Service, createOptions createOptions, upOptions upOptions, project *types.Project, services []string) error {
|
||||
if len(project.Services) == 0 {
|
||||
return fmt.Errorf("no service selected")
|
||||
}
|
||||
|
||||
createOptions.Apply(project)
|
||||
|
||||
err := upOptions.apply(project, services)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var consumer api.LogConsumer
|
||||
if !upOptions.Detach {
|
||||
consumer = formatter.NewLogConsumer(ctx, os.Stdout, !upOptions.noColor, !upOptions.noPrefix)
|
||||
}
|
||||
|
||||
attachTo := services
|
||||
if upOptions.attachDependencies {
|
||||
attachTo = project.ServiceNames()
|
||||
}
|
||||
|
||||
create := api.CreateOptions{
|
||||
RemoveOrphans: createOptions.removeOrphans,
|
||||
Recreate: createOptions.recreateStrategy(),
|
||||
RecreateDependencies: createOptions.dependenciesRecreateStrategy(),
|
||||
Inherit: !createOptions.noInherit,
|
||||
Timeout: createOptions.GetTimeout(),
|
||||
QuietPull: createOptions.quietPull,
|
||||
}
|
||||
|
||||
if upOptions.noStart {
|
||||
return backend.Create(ctx, project, create)
|
||||
}
|
||||
|
||||
return backend.Up(ctx, project, api.UpOptions{
|
||||
Create: create,
|
||||
Start: api.StartOptions{
|
||||
Attach: consumer,
|
||||
AttachTo: attachTo,
|
||||
ExitCodeFrom: upOptions.exitCodeFrom,
|
||||
CascadeStop: upOptions.cascadeStop,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func setServiceScale(project *types.Project, name string, replicas int) error {
|
||||
for i, s := range project.Services {
|
||||
if s.Name == name {
|
||||
service, err := project.GetService(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
service.Scale = replicas
|
||||
project.Services[i] = service
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("unknown service %q", name)
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
/*
|
||||
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 (
|
||||
"testing"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"gotest.tools/v3/assert"
|
||||
)
|
||||
|
||||
func TestApplyScaleOpt(t *testing.T) {
|
||||
p := types.Project{
|
||||
Services: []types.ServiceConfig{
|
||||
{
|
||||
Name: "foo",
|
||||
},
|
||||
{
|
||||
Name: "bar",
|
||||
},
|
||||
},
|
||||
}
|
||||
opt := upOptions{scale: []string{"foo=2"}}
|
||||
err := opt.apply(&p, nil)
|
||||
assert.NilError(t, err)
|
||||
foo, err := p.GetService("foo")
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, foo.Scale, 2)
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
/*
|
||||
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 (
|
||||
"fmt"
|
||||
|
||||
"github.com/docker/compose-cli/cmd/formatter"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/docker/compose-cli/internal"
|
||||
)
|
||||
|
||||
type versionOptions struct {
|
||||
format string
|
||||
short bool
|
||||
}
|
||||
|
||||
func versionCommand() *cobra.Command {
|
||||
opts := versionOptions{}
|
||||
cmd := &cobra.Command{
|
||||
Use: "version",
|
||||
Short: "Show the Docker Compose version information",
|
||||
Args: cobra.MaximumNArgs(0),
|
||||
Hidden: true,
|
||||
RunE: func(cmd *cobra.Command, _ []string) error {
|
||||
runVersion(opts)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
// define flags for backward compatibility with com.docker.cli
|
||||
flags := cmd.Flags()
|
||||
flags.StringVarP(&opts.format, "format", "f", "", "Format the output. Values: [pretty | json]. (Default: pretty)")
|
||||
flags.BoolVar(&opts.short, "short", false, "Shows only Compose's version number.")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runVersion(opts versionOptions) {
|
||||
if opts.short {
|
||||
fmt.Println(internal.Version)
|
||||
return
|
||||
}
|
||||
if opts.format == formatter.JSON {
|
||||
fmt.Printf(`{"version":%q}\n`, internal.Version)
|
||||
return
|
||||
}
|
||||
fmt.Println("Docker Compose version", internal.Version)
|
||||
}
|
|
@ -1,124 +0,0 @@
|
|||
/*
|
||||
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 formatter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/mattn/go-isatty"
|
||||
)
|
||||
|
||||
var names = []string{
|
||||
"grey",
|
||||
"red",
|
||||
"green",
|
||||
"yellow",
|
||||
"blue",
|
||||
"magenta",
|
||||
"cyan",
|
||||
"white",
|
||||
}
|
||||
|
||||
const (
|
||||
// Never use ANSI codes
|
||||
Never = "never"
|
||||
|
||||
// Always use ANSI codes
|
||||
Always = "always"
|
||||
|
||||
// Auto detect terminal is a tty and can use ANSI codes
|
||||
Auto = "auto"
|
||||
)
|
||||
|
||||
// SetANSIMode configure formatter for colored output on ANSI-compliant console
|
||||
func SetANSIMode(ansi string) {
|
||||
if !useAnsi(ansi) {
|
||||
nextColor = func() colorFunc {
|
||||
return monochrome
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func useAnsi(ansi string) bool {
|
||||
switch ansi {
|
||||
case Always:
|
||||
return true
|
||||
case Auto:
|
||||
return isatty.IsTerminal(os.Stdout.Fd())
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// colorFunc use ANSI codes to render colored text on console
|
||||
type colorFunc func(s string) string
|
||||
|
||||
var monochrome = func(s string) string {
|
||||
return s
|
||||
}
|
||||
|
||||
func ansiColor(code, s string) string {
|
||||
return fmt.Sprintf("%s%s%s", ansi(code), s, ansi("0"))
|
||||
}
|
||||
|
||||
func ansi(code string) string {
|
||||
return fmt.Sprintf("\033[%sm", code)
|
||||
}
|
||||
|
||||
func makeColorFunc(code string) colorFunc {
|
||||
return func(s string) string {
|
||||
return ansiColor(code, s)
|
||||
}
|
||||
}
|
||||
|
||||
var nextColor = rainbowColor
|
||||
|
||||
func rainbowColor() colorFunc {
|
||||
return <-loop
|
||||
}
|
||||
|
||||
var loop = make(chan colorFunc)
|
||||
|
||||
func init() {
|
||||
colors := map[string]colorFunc{}
|
||||
for i, name := range names {
|
||||
colors[name] = makeColorFunc(strconv.Itoa(30 + i))
|
||||
colors["intense_"+name] = makeColorFunc(strconv.Itoa(30+i) + ";1")
|
||||
}
|
||||
|
||||
go func() {
|
||||
i := 0
|
||||
rainbow := []colorFunc{
|
||||
colors["cyan"],
|
||||
colors["yellow"],
|
||||
colors["green"],
|
||||
colors["magenta"],
|
||||
colors["blue"],
|
||||
colors["intense_cyan"],
|
||||
colors["intense_yellow"],
|
||||
colors["intense_green"],
|
||||
colors["intense_magenta"],
|
||||
colors["intense_blue"],
|
||||
}
|
||||
|
||||
for {
|
||||
loop <- rainbow[i]
|
||||
i = (i + 1) % len(rainbow)
|
||||
}
|
||||
}()
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
/*
|
||||
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 formatter
|
||||
|
||||
const (
|
||||
// JSON is the constant for Json formats on list commands
|
||||
JSON = "json"
|
||||
// TemplateLegacyJSON the legacy json formatting value using go template
|
||||
TemplateLegacyJSON = "{{json.}}"
|
||||
// PRETTY is the constant for default formats on list commands
|
||||
PRETTY = "pretty"
|
||||
)
|
|
@ -1,73 +0,0 @@
|
|||
/*
|
||||
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 formatter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Print prints formatted lists in different formats
|
||||
func Print(toJSON interface{}, format string, outWriter io.Writer, writerFn func(w io.Writer), headers ...string) error {
|
||||
switch strings.ToLower(format) {
|
||||
case PRETTY, "":
|
||||
return PrintPrettySection(outWriter, writerFn, headers...)
|
||||
case TemplateLegacyJSON:
|
||||
switch reflect.TypeOf(toJSON).Kind() {
|
||||
case reflect.Slice:
|
||||
s := reflect.ValueOf(toJSON)
|
||||
for i := 0; i < s.Len(); i++ {
|
||||
obj := s.Index(i).Interface()
|
||||
outJSON, err := ToJSON(obj, "", "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, _ = fmt.Fprint(outWriter, outJSON)
|
||||
}
|
||||
default:
|
||||
outJSON, err := ToStandardJSON(toJSON)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, _ = fmt.Fprintln(outWriter, outJSON)
|
||||
}
|
||||
case JSON:
|
||||
switch reflect.TypeOf(toJSON).Kind() {
|
||||
case reflect.Slice:
|
||||
outJSON, err := ToJSON(toJSON, "", "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, _ = fmt.Fprint(outWriter, outJSON)
|
||||
default:
|
||||
outJSON, err := ToStandardJSON(toJSON)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, _ = fmt.Fprintln(outWriter, outJSON)
|
||||
}
|
||||
default:
|
||||
return errors.Wrapf(api.ErrParsingFailed, "format value %q could not be parsed", format)
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
/*
|
||||
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 formatter
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"gotest.tools/assert"
|
||||
)
|
||||
|
||||
type testStruct struct {
|
||||
Name string
|
||||
Status string
|
||||
}
|
||||
|
||||
// Print prints formatted lists in different formats
|
||||
func TestPrint(t *testing.T) {
|
||||
testList := []testStruct{
|
||||
{
|
||||
Name: "myName1",
|
||||
Status: "myStatus1",
|
||||
},
|
||||
{
|
||||
Name: "myName2",
|
||||
Status: "myStatus2",
|
||||
},
|
||||
}
|
||||
|
||||
b := &bytes.Buffer{}
|
||||
assert.NilError(t, Print(testList, PRETTY, b, func(w io.Writer) {
|
||||
for _, t := range testList {
|
||||
_, _ = fmt.Fprintf(w, "%s\t%s\n", t.Name, t.Status)
|
||||
}
|
||||
}, "NAME", "STATUS"))
|
||||
assert.Equal(t, b.String(), "NAME STATUS\nmyName1 myStatus1\nmyName2 myStatus2\n")
|
||||
|
||||
b.Reset()
|
||||
assert.NilError(t, Print(testList, JSON, b, func(w io.Writer) {
|
||||
for _, t := range testList {
|
||||
_, _ = fmt.Fprintf(w, "%s\t%s\n", t.Name, t.Status)
|
||||
}
|
||||
}, "NAME", "STATUS"))
|
||||
assert.Equal(t, b.String(), `[{"Name":"myName1","Status":"myStatus1"},{"Name":"myName2","Status":"myStatus2"}]
|
||||
`)
|
||||
|
||||
b.Reset()
|
||||
assert.NilError(t, Print(testList, TemplateLegacyJSON, b, func(w io.Writer) {
|
||||
for _, t := range testList {
|
||||
_, _ = fmt.Fprintf(w, "%s\t%s\n", t.Name, t.Status)
|
||||
}
|
||||
}, "NAME", "STATUS"))
|
||||
json := b.String()
|
||||
assert.Equal(t, json, `{"Name":"myName1","Status":"myStatus1"}
|
||||
{"Name":"myName2","Status":"myStatus2"}
|
||||
`)
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
/*
|
||||
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 formatter
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
const standardIndentation = " "
|
||||
|
||||
// ToStandardJSON return a string with the JSON representation of the interface{}
|
||||
func ToStandardJSON(i interface{}) (string, error) {
|
||||
return ToJSON(i, "", standardIndentation)
|
||||
}
|
||||
|
||||
// ToJSON return a string with the JSON representation of the interface{}
|
||||
func ToJSON(i interface{}, prefix string, indentation string) (string, error) {
|
||||
buffer := &bytes.Buffer{}
|
||||
encoder := json.NewEncoder(buffer)
|
||||
encoder.SetEscapeHTML(false)
|
||||
encoder.SetIndent(prefix, indentation)
|
||||
err := encoder.Encode(i)
|
||||
return buffer.String(), err
|
||||
}
|
|
@ -1,115 +0,0 @@
|
|||
/*
|
||||
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 formatter
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
)
|
||||
|
||||
// NewLogConsumer creates a new LogConsumer
|
||||
func NewLogConsumer(ctx context.Context, w io.Writer, color bool, prefix bool) api.LogConsumer {
|
||||
return &logConsumer{
|
||||
ctx: ctx,
|
||||
presenters: map[string]*presenter{},
|
||||
width: 0,
|
||||
writer: w,
|
||||
color: color,
|
||||
prefix: prefix,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *logConsumer) Register(name string) {
|
||||
l.register(name)
|
||||
}
|
||||
|
||||
func (l *logConsumer) register(name string) *presenter {
|
||||
cf := monochrome
|
||||
if l.color {
|
||||
cf = nextColor()
|
||||
}
|
||||
p := &presenter{
|
||||
colors: cf,
|
||||
name: name,
|
||||
}
|
||||
l.presenters[name] = p
|
||||
if l.prefix {
|
||||
l.computeWidth()
|
||||
for _, p := range l.presenters {
|
||||
p.setPrefix(l.width)
|
||||
}
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
// Log formats a log message as received from name/container
|
||||
func (l *logConsumer) Log(container, service, message string) {
|
||||
if l.ctx.Err() != nil {
|
||||
return
|
||||
}
|
||||
p, ok := l.presenters[container]
|
||||
if !ok { // should have been registered, but ¯\_(ツ)_/¯
|
||||
p = l.register(container)
|
||||
}
|
||||
for _, line := range strings.Split(message, "\n") {
|
||||
fmt.Fprintf(l.writer, "%s %s\n", p.prefix, line) // nolint:errcheck
|
||||
}
|
||||
}
|
||||
|
||||
func (l *logConsumer) Status(container, msg string) {
|
||||
p, ok := l.presenters[container]
|
||||
if !ok {
|
||||
p = l.register(container)
|
||||
}
|
||||
s := p.colors(fmt.Sprintf("%s %s\n", container, msg))
|
||||
l.writer.Write([]byte(s)) // nolint:errcheck
|
||||
}
|
||||
|
||||
func (l *logConsumer) computeWidth() {
|
||||
width := 0
|
||||
for _, p := range l.presenters {
|
||||
if len(p.name) > width {
|
||||
width = len(p.name)
|
||||
}
|
||||
}
|
||||
l.width = width + 1
|
||||
}
|
||||
|
||||
// LogConsumer consume logs from services and format them
|
||||
type logConsumer struct {
|
||||
ctx context.Context
|
||||
presenters map[string]*presenter
|
||||
width int
|
||||
writer io.Writer
|
||||
color bool
|
||||
prefix bool
|
||||
}
|
||||
|
||||
type presenter struct {
|
||||
colors colorFunc
|
||||
name string
|
||||
prefix string
|
||||
}
|
||||
|
||||
func (p *presenter) setPrefix(width int) {
|
||||
p.prefix = p.colors(fmt.Sprintf("%-"+strconv.Itoa(width)+"s |", p.name))
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
/*
|
||||
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 formatter
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/go-multierror"
|
||||
)
|
||||
|
||||
// SetMultiErrorFormat set cli default format for multi-errors
|
||||
func SetMultiErrorFormat(errs *multierror.Error) {
|
||||
if errs != nil {
|
||||
errs.ErrorFormat = formatErrors
|
||||
}
|
||||
}
|
||||
|
||||
func formatErrors(errs []error) string {
|
||||
messages := make([]string, len(errs))
|
||||
for i, err := range errs {
|
||||
messages[i] = "Error: " + err.Error()
|
||||
}
|
||||
return strings.Join(messages, "\n")
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
/*
|
||||
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 formatter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
)
|
||||
|
||||
// PrintPrettySection prints a tabbed section on the writer parameter
|
||||
func PrintPrettySection(out io.Writer, printer func(writer io.Writer), headers ...string) error {
|
||||
w := tabwriter.NewWriter(out, 20, 1, 3, ' ', 0)
|
||||
_, _ = fmt.Fprintln(w, strings.Join(headers, "\t"))
|
||||
printer(w)
|
||||
return w.Flush()
|
||||
}
|
65
cmd/main.go
65
cmd/main.go
|
@ -1,65 +0,0 @@
|
|||
/*
|
||||
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 (
|
||||
dockercli "github.com/docker/cli/cli"
|
||||
"github.com/docker/cli/cli-plugins/manager"
|
||||
"github.com/docker/cli/cli-plugins/plugin"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
commands "github.com/docker/compose-cli/cmd/compose"
|
||||
"github.com/docker/compose-cli/internal"
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
"github.com/docker/compose-cli/pkg/compose"
|
||||
)
|
||||
|
||||
func init() {
|
||||
commands.Warning = "The new 'docker compose' command is currently experimental. " +
|
||||
"To provide feedback or request new features please open issues at https://github.com/docker/compose-cli"
|
||||
}
|
||||
|
||||
func main() {
|
||||
plugin.Run(func(dockerCli command.Cli) *cobra.Command {
|
||||
lazyInit := api.NewServiceProxy()
|
||||
cmd := commands.RootCommand(lazyInit)
|
||||
originalPreRun := cmd.PersistentPreRunE
|
||||
cmd.PersistentPreRunE = func(cmd *cobra.Command, args []string) error {
|
||||
if err := plugin.PersistentPreRunE(cmd, args); err != nil {
|
||||
return err
|
||||
}
|
||||
lazyInit.WithService(compose.NewComposeService(dockerCli.Client(), dockerCli.ConfigFile()))
|
||||
if originalPreRun != nil {
|
||||
return originalPreRun(cmd, args)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
cmd.SetFlagErrorFunc(func(c *cobra.Command, err error) error {
|
||||
return dockercli.StatusError{
|
||||
StatusCode: compose.CommandSyntaxFailure.ExitCode,
|
||||
Status: err.Error(),
|
||||
}
|
||||
})
|
||||
return cmd
|
||||
},
|
||||
manager.Metadata{
|
||||
SchemaVersion: "0.1.0",
|
||||
Vendor: "Docker Inc.",
|
||||
Version: internal.Version,
|
||||
})
|
||||
}
|
|
@ -27,7 +27,8 @@ import (
|
|||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
|
||||
"github.com/docker/compose-cli/cmd/compose"
|
||||
"github.com/docker/compose/v2/cmd/compose"
|
||||
|
||||
. "github.com/docker/compose-cli/docs/yaml"
|
||||
)
|
||||
|
||||
|
|
|
@ -21,9 +21,9 @@ import (
|
|||
|
||||
"github.com/aws/aws-sdk-go/service/cloudformation"
|
||||
"github.com/aws/aws-sdk-go/service/ecs"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
|
||||
"github.com/docker/compose-cli/api/secrets"
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
@ -30,7 +30,7 @@ import (
|
|||
"github.com/awslabs/goformation/v4/cloudformation/efs"
|
||||
"github.com/awslabs/goformation/v4/cloudformation/elasticloadbalancingv2"
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
|
|
@ -6,12 +6,14 @@ package ecs
|
|||
|
||||
import (
|
||||
context "context"
|
||||
reflect "reflect"
|
||||
|
||||
cloudformation "github.com/aws/aws-sdk-go/service/cloudformation"
|
||||
ecs "github.com/aws/aws-sdk-go/service/ecs"
|
||||
secrets "github.com/docker/compose-cli/api/secrets"
|
||||
compose "github.com/docker/compose-cli/pkg/api"
|
||||
compose "github.com/docker/compose/v2/pkg/api"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
reflect "reflect"
|
||||
|
||||
secrets "github.com/docker/compose-cli/api/secrets"
|
||||
)
|
||||
|
||||
// MockAPI is a mock of API interface
|
||||
|
|
|
@ -21,7 +21,6 @@ import (
|
|||
"fmt"
|
||||
|
||||
"github.com/docker/compose-cli/api/backend"
|
||||
|
||||
"github.com/docker/compose-cli/api/cloud"
|
||||
"github.com/docker/compose-cli/api/containers"
|
||||
apicontext "github.com/docker/compose-cli/api/context"
|
||||
|
@ -29,10 +28,10 @@ import (
|
|||
"github.com/docker/compose-cli/api/resources"
|
||||
"github.com/docker/compose-cli/api/secrets"
|
||||
"github.com/docker/compose-cli/api/volumes"
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
)
|
||||
|
||||
const backendType = store.EcsContextType
|
||||
|
|
|
@ -38,11 +38,12 @@ import (
|
|||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/distribution/distribution/v3/reference"
|
||||
cliconfig "github.com/docker/cli/cli/config"
|
||||
"github.com/docker/compose-cli/api/config"
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
"github.com/opencontainers/go-digest"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml/merge2"
|
||||
|
||||
"github.com/docker/compose-cli/api/config"
|
||||
)
|
||||
|
||||
func (b *ecsAPIService) Kill(ctx context.Context, project *types.Project, options api.KillOptions) error {
|
||||
|
|
|
@ -23,8 +23,6 @@ import (
|
|||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
|
||||
"github.com/aws/aws-sdk-go/service/elbv2"
|
||||
"github.com/awslabs/goformation/v4/cloudformation"
|
||||
"github.com/awslabs/goformation/v4/cloudformation/ec2"
|
||||
|
@ -35,6 +33,7 @@ import (
|
|||
"github.com/awslabs/goformation/v4/cloudformation/logs"
|
||||
"github.com/compose-spec/compose-go/loader"
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
"github.com/golang/mock/gomock"
|
||||
"gotest.tools/v3/assert"
|
||||
"gotest.tools/v3/golden"
|
||||
|
|
|
@ -24,18 +24,18 @@ import (
|
|||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/compose-cli/pkg/prompt"
|
||||
|
||||
"github.com/AlecAivazis/survey/v2/terminal"
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/defaults"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/docker/compose-cli/api/context/store"
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
"github.com/docker/compose/v2/pkg/prompt"
|
||||
"github.com/pkg/errors"
|
||||
"gopkg.in/ini.v1"
|
||||
|
||||
"github.com/docker/compose-cli/api/context/store"
|
||||
)
|
||||
|
||||
func getEnvVars() ContextParams {
|
||||
|
|
|
@ -21,13 +21,13 @@ import (
|
|||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/compose-cli/api/context/store"
|
||||
"github.com/docker/compose-cli/pkg/prompt"
|
||||
|
||||
"github.com/docker/compose/v2/pkg/prompt"
|
||||
"github.com/golang/mock/gomock"
|
||||
"gotest.tools/v3/assert"
|
||||
"gotest.tools/v3/fs"
|
||||
"gotest.tools/v3/golden"
|
||||
|
||||
"github.com/docker/compose-cli/api/context/store"
|
||||
)
|
||||
|
||||
func TestCreateContextDataFromEnv(t *testing.T) {
|
||||
|
|
|
@ -19,10 +19,9 @@ package ecs
|
|||
import (
|
||||
"context"
|
||||
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
"github.com/docker/compose/v2/pkg/progress"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/docker/compose-cli/pkg/api"
|
||||
"github.com/docker/compose-cli/pkg/progress"
|
||||
)
|
||||
|
||||
func (b *ecsAPIService) Down(ctx context.Context, projectName string, options api.DownOptions) error {
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче