diff --git a/cmd/compose/list.go b/cmd/compose/list.go index 6513e2a77..ac05dc1d1 100644 --- a/cmd/compose/list.go +++ b/cmd/compose/list.go @@ -92,22 +92,24 @@ func runList(ctx context.Context, backend api.Service, opts lsOptions) error { 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) + _, _ = fmt.Fprintf(w, "%s\t%s\t%s\n", stack.Name, stack.Status, stack.ConfigFiles) } - }, "NAME", "STATUS") + }, "NAME", "STATUS", "CONFIG FILES") } type stackView struct { - Name string - Status string + Name string + Status string + ConfigFiles 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)), + Name: s.Name, + Status: strings.TrimSpace(fmt.Sprintf("%s %s", s.Status, s.Reason)), + ConfigFiles: s.ConfigFiles, } } return retList diff --git a/pkg/api/api.go b/pkg/api/api.go index 5d963569c..e28cf12a2 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -404,10 +404,11 @@ const ( // Stack holds the name and state of a compose application/stack type Stack struct { - ID string - Name string - Status string - Reason string + ID string + Name string + Status string + ConfigFiles string + Reason string } // LogConsumer is a callback to process log messages from services diff --git a/pkg/compose/ls.go b/pkg/compose/ls.go index aa78da9ea..272edf342 100644 --- a/pkg/compose/ls.go +++ b/pkg/compose/ls.go @@ -20,8 +20,10 @@ import ( "context" "fmt" "sort" + "strings" "github.com/docker/compose/v2/pkg/api" + "github.com/docker/compose/v2/pkg/utils" moby "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/filters" @@ -46,15 +48,40 @@ func containersToStacks(containers []moby.Container) ([]api.Stack, error) { } var projects []api.Stack for _, project := range keys { + configFiles, err := combinedConfigFiles(containersByLabel[project]) + if err != nil { + return nil, err + } + projects = append(projects, api.Stack{ - ID: project, - Name: project, - Status: combinedStatus(containerToState(containersByLabel[project])), + ID: project, + Name: project, + Status: combinedStatus(containerToState(containersByLabel[project])), + ConfigFiles: configFiles, }) } return projects, nil } +func combinedConfigFiles(containers []moby.Container) (string, error) { + configFiles := []string{} + + for _, c := range containers { + files, ok := c.Labels[api.ConfigFilesLabel] + if !ok { + return "", fmt.Errorf("No label %q set on container %q of compose project", api.ConfigFilesLabel, c.ID) + } + + for _, f := range strings.Split(files, ",") { + if !utils.StringContains(configFiles, f) { + configFiles = append(configFiles, f) + } + } + } + + return strings.Join(configFiles, ","), nil +} + func containerToState(containers []moby.Container) []string { statuses := []string{} for _, c := range containers {