Skip to content

Commit

Permalink
Merge pull request #857 from rsteube/docker-compose_updates-from-2.2.3
Browse files Browse the repository at this point in the history
docker-compose: updates from 2.2.3
  • Loading branch information
rsteube authored Jan 25, 2022
2 parents 77d3323 + 847cc8d commit 149c781
Show file tree
Hide file tree
Showing 32 changed files with 326 additions and 275 deletions.
1 change: 1 addition & 0 deletions completers/docker-compose_completer/cmd/action/path.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
)

func ActionServicePath(service string) carapace.Action {
// TODO container index
return carapace.ActionCallback(func(c carapace.Context) carapace.Action {
path := filepath.Dir(c.CallbackValue)
return carapace.ActionMultiParts("/", func(c carapace.Context) carapace.Action {
Expand Down
105 changes: 37 additions & 68 deletions completers/docker-compose_completer/cmd/action/service.go
Original file line number Diff line number Diff line change
@@ -1,89 +1,58 @@
package action

import (
"errors"
"io/ioutil"
"os"
"path/filepath"
"encoding/json"
"fmt"
"strings"

"github.com/rsteube/carapace"
"github.com/spf13/cobra"
"gopkg.in/yaml.v3"
)

func ActionServices(cmd *cobra.Command) carapace.Action {
return carapace.ActionCallback(func(c carapace.Context) carapace.Action {
if services, _, err := loadFile(cmd); err != nil {
return carapace.ActionMessage(err.Error())
} else {
return carapace.ActionValues(services...)
type config struct {
Services map[string]struct {
Image string
Build struct {
Context string
Dockerfile string
}
})
}
Volumes map[string]struct {
Name string
}
}

func ActionVolumes(cmd *cobra.Command) carapace.Action {
return carapace.ActionCallback(func(c carapace.Context) carapace.Action {
if _, volumes, err := loadFile(cmd); err != nil {
func actionConfig(f func(c config) carapace.Action) carapace.Action {
// TODO support `--files` flag
return carapace.ActionExecCommand("docker-compose", "convert", "--format", "json")(func(output []byte) carapace.Action {
var c config
if err := json.Unmarshal(output, &c); err != nil {
return carapace.ActionMessage(err.Error())
} else {
return carapace.ActionValues(volumes...)
}
return f(c)
})
}

type compose struct {
Version string
Services map[string]interface{}
Volumes map[string]interface{}
}

func fileLocation(cmd *cobra.Command) (string, error) {
if flag := cmd.Root().Flag("file"); flag.Changed {
return flag.Value.String(), nil
} else {
if path, err := os.Getwd(); err == nil {
return traverse(path)
} else {
return "", err
func ActionServices(cmd *cobra.Command) carapace.Action {
return actionConfig(func(c config) carapace.Action {
vals := make([]string, 0)
for name, service := range c.Services {
description := service.Image
if strings.TrimSpace(description) == "" {
description = fmt.Sprintf("%v/%v", service.Build.Context, service.Build.Dockerfile)
}
vals = append(vals, name, description)
}
}
return carapace.ActionValuesDescribed(vals...)
})
}

func traverse(path string) (string, error) {
if _, err := os.Stat(path + "/docker-compose.yml"); err == nil {
return path + "/docker-compose.yml", nil
} else {
if path == "/" {
return "", errors.New("no docker-compose.yml present")
func ActionContainers(cmd *cobra.Command, status string) carapace.Action {
return carapace.ActionExecCommand("docker-compose", "ps", "--status", status)(func(output []byte) carapace.Action {
lines := strings.Split(string(output), "\n")
if lines[0] != "" {
return carapace.ActionValues(lines[:len(lines)-1]...)
}
return traverse(filepath.Dir(path))
}
}

func loadFile(cmd *cobra.Command) ([]string, []string, error) {
file, err := fileLocation(cmd)
if err != nil {
return nil, nil, err
}

yamlFile, err := ioutil.ReadFile(file)
if err != nil {
return nil, nil, err
}

var content compose
if err = yaml.Unmarshal(yamlFile, &content); err != nil {
return nil, nil, err
}
return keys(content.Services), keys(content.Volumes), nil
}

func keys(m map[string]interface{}) []string {
keys := make([]string, len(m))
index := 0
for key := range m {
keys[index] = key
index += 1
}
return keys
return carapace.ActionValues()
})
}
38 changes: 38 additions & 0 deletions completers/docker-compose_completer/cmd/action/user.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package action

import (
"strings"

"github.com/rsteube/carapace"
"github.com/spf13/cobra"
)

func actionContainerExecCommand(cmd *cobra.Command, service string, index string, command string, args ...string) func(f func(output []byte) carapace.Action) carapace.Action {
return func(f func(output []byte) carapace.Action) carapace.Action {
return carapace.ActionExecCommand("docker-compose", append([]string{"exec", "--no-TTY", "--index", index, service, command}, args...)...)(func(output []byte) carapace.Action {
return f(output)
})
}
}

// ActionContainerUsers completes container user names
// root (0)
// daemon (1)
func ActionContainerUsers(cmd *cobra.Command, service string, index string) carapace.Action {
return carapace.ActionCallback(func(c carapace.Context) carapace.Action {
return actionContainerExecCommand(cmd, service, index, "cat", "/etc/passwd")(func(output []byte) carapace.Action {
users := []string{}
for _, entry := range strings.Split(string(output), "\n") {
splitted := strings.Split(entry, ":")
if len(splitted) > 2 {
user := splitted[0]
id := splitted[2]
if len(strings.TrimSpace(user)) > 0 {
users = append(users, user, id)
}
}
}
return carapace.ActionValuesDescribed(users...)
})
})
}
16 changes: 16 additions & 0 deletions completers/docker-compose_completer/cmd/action/volume.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package action

import (
"github.com/rsteube/carapace"
"github.com/spf13/cobra"
)

func ActionVolumes(cmd *cobra.Command) carapace.Action {
return actionConfig(func(c config) carapace.Action {
vals := make([]string, 0)
for name, volume := range c.Volumes {
vals = append(vals, name, volume.Name)
}
return carapace.ActionValuesDescribed(vals...)
})
}
19 changes: 9 additions & 10 deletions completers/docker-compose_completer/cmd/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,20 @@ var buildCmd = &cobra.Command{

func init() {
carapace.Gen(buildCmd).Standalone()

buildCmd.Flags().String("build-arg", "", "Set build-time variables for services.")
buildCmd.Flags().Bool("compress", false, "Compress the build context using gzip.")
buildCmd.Flags().Bool("force-rm", false, "Always remove intermediate containers.")
buildCmd.Flags().StringP("memory", "m", "", "Set memory limit for the build container.")
buildCmd.Flags().Bool("no-cache", false, "Do not use cache when building the image.")
buildCmd.Flags().Bool("no-rm", false, "Do not remove intermediate containers after a successful build.")
buildCmd.Flags().Bool("parallel", false, "Build images in parallel.")
buildCmd.Flags().String("progress", "", "Set type of progress output (auto, plain, tty).")
buildCmd.Flags().StringArray("build-arg", []string{}, "Set build-time variables for services.")
buildCmd.Flags().Bool("compress", true, "Compress the build context using gzip. DEPRECATED")
buildCmd.Flags().Bool("force-rm", true, "Always remove intermediate containers. DEPRECATED")
buildCmd.Flags().StringP("memory", "m", "", "Set memory limit for the build container. Not supported on buildkit yet.")
buildCmd.Flags().Bool("no-cache", false, "Do not use cache when building the image")
buildCmd.Flags().Bool("no-rm", false, "Do not remove intermediate containers after a successful build. DEPRECATED")
buildCmd.Flags().Bool("parallel", true, "Build images in parallel. DEPRECATED")
buildCmd.Flags().String("progress", "auto", "Set type of progress output (auto, tty, plain, quiet)")
buildCmd.Flags().Bool("pull", false, "Always attempt to pull a newer version of the image.")
buildCmd.Flags().BoolP("quiet", "q", false, "Don't print anything to STDOUT")
rootCmd.AddCommand(buildCmd)

carapace.Gen(buildCmd).FlagCompletion(carapace.ActionMap{
"progress": carapace.ActionValues("auto", "plain", "tty"),
"progress": carapace.ActionValues("auto", "tty", "plain", "quiet"),
})

carapace.Gen(buildCmd).PositionalAnyCompletion(
Expand Down
24 changes: 0 additions & 24 deletions completers/docker-compose_completer/cmd/config.go

This file was deleted.

39 changes: 39 additions & 0 deletions completers/docker-compose_completer/cmd/convert.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package cmd

import (
"github.com/rsteube/carapace"
"github.com/rsteube/carapace-bin/completers/docker-compose_completer/cmd/action"
"github.com/spf13/cobra"
)

var convertCmd = &cobra.Command{
Use: "convert",
Short: "Converts the compose file to platform's canonical format",
Run: func(cmd *cobra.Command, args []string) {},
}

func init() {
carapace.Gen(convertCmd).Standalone()
convertCmd.Flags().String("format", "yaml", "Format the output. Values: [yaml | json]")
convertCmd.Flags().String("hash", "", "Print the service config hash, one per line.")
convertCmd.Flags().Bool("images", false, "Print the image names, one per line.")
convertCmd.Flags().Bool("no-interpolate", false, "Don't interpolate environment variables.")
convertCmd.Flags().Bool("no-normalize", false, "Don't normalize compose model.")
convertCmd.Flags().StringP("output", "o", "", "Save to file (default to stdout)")
convertCmd.Flags().Bool("profiles", false, "Print the profile names, one per line.")
convertCmd.Flags().BoolP("quiet", "q", false, "Only validate the configuration, don't print anything.")
convertCmd.Flags().Bool("resolve-image-digests", false, "Pin image tags to digests.")
convertCmd.Flags().Bool("services", false, "Print the service names, one per line.")
convertCmd.Flags().Bool("volumes", false, "Print the volume names, one per line.")
rootCmd.AddCommand(convertCmd)

carapace.Gen(convertCmd).FlagCompletion(carapace.ActionMap{
"format": carapace.ActionValues("yaml", "json"),
"hash": action.ActionServices(convertCmd),
"output": carapace.ActionFiles(),
})

carapace.Gen(convertCmd).PositionalCompletion(
action.ActionServices(convertCmd),
)
}
56 changes: 56 additions & 0 deletions completers/docker-compose_completer/cmd/cp.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package cmd

import (
"github.com/rsteube/carapace"
"github.com/rsteube/carapace-bin/completers/docker-compose_completer/cmd/action"
"github.com/rsteube/carapace-bin/pkg/util"
"github.com/spf13/cobra"
)

var cpCmd = &cobra.Command{
Use: "cp",
Short: "Copy files/folders between a service container and the local filesystem",
Run: func(cmd *cobra.Command, args []string) {},
}

func init() {
carapace.Gen(cpCmd).Standalone()
cpCmd.Flags().Bool("all", false, "Copy to all the containers of the service.")
cpCmd.Flags().BoolP("archive", "a", false, "Archive mode (copy all uid/gid information)")
cpCmd.Flags().BoolP("follow-link", "L", false, "Always follow symbol link in SRC_PATH")
cpCmd.Flags().Int("index", 1, "Index of the container if there are multiple instances of a service [default: 1].")
rootCmd.AddCommand(cpCmd)

carapace.Gen(cpCmd).PositionalCompletion(
carapace.ActionCallback(func(c carapace.Context) carapace.Action {
if util.HasPathPrefix(c.CallbackValue) {
return carapace.ActionFiles()
}
return carapace.ActionMultiParts(":", func(c carapace.Context) carapace.Action {
switch len(c.Parts) {
case 0:
return action.ActionServices(cpCmd).Invoke(c).Suffix(":").ToA()
case 1:
return action.ActionServicePath(c.Parts[0]) // TODO index
default:
return carapace.ActionValues()
}
})
}),
carapace.ActionCallback(func(c carapace.Context) carapace.Action {
if !util.HasPathPrefix(c.Args[0]) {
return carapace.ActionFiles()
}
return carapace.ActionMultiParts(":", func(c carapace.Context) carapace.Action {
switch len(c.Parts) {
case 0:
return action.ActionServices(cpCmd).Invoke(c).Suffix(":").ToA()
case 1:
return action.ActionServicePath(c.Parts[0]) // TODO index
default:
return carapace.ActionValues()
}
})
}),
)
}
9 changes: 4 additions & 5 deletions completers/docker-compose_completer/cmd/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,16 @@ import (

var createCmd = &cobra.Command{
Use: "create",
Short: "Create services",
Short: "Creates containers for a service.",
Run: func(cmd *cobra.Command, args []string) {},
}

func init() {
carapace.Gen(createCmd).Standalone()

createCmd.Flags().Bool("build", false, "Build images before creating containers.")
createCmd.Flags().Bool("force-recreate", false, "Recreate containers even if their configuration and")
createCmd.Flags().Bool("build", false, "Build images before starting containers.")
createCmd.Flags().Bool("force-recreate", false, "Recreate containers even if their configuration and image haven't changed.")
createCmd.Flags().Bool("no-build", false, "Don't build an image, even if it's missing.")
createCmd.Flags().Bool("no-recreate", false, "If containers already exist, don't recreate them.")
createCmd.Flags().Bool("no-recreate", false, "If containers already exist, don't recreate them. Incompatible with --force-recreate.")
rootCmd.AddCommand(createCmd)

carapace.Gen(createCmd).PositionalAnyCompletion(
Expand Down
Loading

0 comments on commit 149c781

Please sign in to comment.