Skip to content

Commit 51ebeb5

Browse files
committed
introduce generate command as alpha command
Signed-off-by: Guillaume Lours <[email protected]>
1 parent fafaa9c commit 51ebeb5

File tree

9 files changed

+430
-1
lines changed

9 files changed

+430
-1
lines changed

cmd/compose/alpha.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ func alphaCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service)
3333
cmd.AddCommand(
3434
vizCommand(p, dockerCli, backend),
3535
publishCommand(p, dockerCli, backend),
36+
generateCommand(p, backend),
3637
)
3738
return cmd
3839
}

cmd/compose/generate.go

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/*
2+
Copyright 2023 Docker Compose CLI authors
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package compose
18+
19+
import (
20+
"context"
21+
"fmt"
22+
"os"
23+
24+
"github.com/docker/compose/v2/pkg/api"
25+
"github.com/spf13/cobra"
26+
)
27+
28+
type generateOptions struct {
29+
*ProjectOptions
30+
Format string
31+
}
32+
33+
func generateCommand(p *ProjectOptions, backend api.Service) *cobra.Command {
34+
opts := generateOptions{
35+
ProjectOptions: p,
36+
}
37+
38+
cmd := &cobra.Command{
39+
Use: "generate [OPTIONS] [CONTAINERS...]",
40+
Short: "EXPERIMENTAL - Generate a Compose file from existing containers",
41+
PreRunE: Adapt(func(ctx context.Context, args []string) error {
42+
return nil
43+
}),
44+
RunE: Adapt(func(ctx context.Context, args []string) error {
45+
return runGenerate(ctx, backend, opts, args)
46+
}),
47+
}
48+
49+
cmd.Flags().StringVar(&opts.ProjectName, "name", "", "Project name to set in the Compose file")
50+
cmd.Flags().StringVar(&opts.ProjectDir, "project-dir", "", "Directory to use for the project")
51+
cmd.Flags().StringVar(&opts.Format, "format", "yaml", "Format the output. Values: [yaml | json]")
52+
return cmd
53+
}
54+
55+
func runGenerate(ctx context.Context, backend api.Service, opts generateOptions, containers []string) error {
56+
_, _ = fmt.Fprintln(os.Stderr, "generate command is EXPERIMENTAL")
57+
if len(containers) == 0 {
58+
return fmt.Errorf("at least one container must be specified")
59+
}
60+
project, err := backend.Generate(ctx, api.GenerateOptions{
61+
Containers: containers,
62+
ProjectName: opts.ProjectName,
63+
})
64+
if err != nil {
65+
return err
66+
}
67+
var content []byte
68+
switch opts.Format {
69+
case "json":
70+
content, err = project.MarshalJSON()
71+
case "yaml":
72+
content, err = project.MarshalYAML()
73+
default:
74+
return fmt.Errorf("unsupported format %q", opts.Format)
75+
}
76+
if err != nil {
77+
return err
78+
}
79+
fmt.Println(string(content))
80+
81+
return nil
82+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# docker compose alpha generate
2+
3+
<!---MARKER_GEN_START-->
4+
EXPERIMENTAL - Generate a Compose file from existing containers
5+
6+
### Options
7+
8+
| Name | Type | Default | Description |
9+
|:----------------|:---------|:--------|:------------------------------------------|
10+
| `--dry-run` | `bool` | | Execute command in dry run mode |
11+
| `--format` | `string` | `yaml` | Format the output. Values: [yaml \| json] |
12+
| `--name` | `string` | | Project name to set in the Compose file |
13+
| `--project-dir` | `string` | | Directory to use for the project |
14+
15+
16+
<!---MARKER_GEN_END-->
17+

docs/reference/docker_compose_alpha.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@ long: Experimental commands
44
pname: docker compose
55
plink: docker_compose.yaml
66
cname:
7+
- docker compose alpha generate
78
- docker compose alpha publish
89
- docker compose alpha viz
910
clink:
11+
- docker_compose_alpha_generate.yaml
1012
- docker_compose_alpha_publish.yaml
1113
- docker_compose_alpha_viz.yaml
1214
inherited_options:
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
command: docker compose alpha generate
2+
short: EXPERIMENTAL - Generate a Compose file from existing containers
3+
long: EXPERIMENTAL - Generate a Compose file from existing containers
4+
usage: docker compose alpha generate [OPTIONS] [CONTAINERS...]
5+
pname: docker compose alpha
6+
plink: docker_compose_alpha.yaml
7+
options:
8+
- option: format
9+
value_type: string
10+
default_value: yaml
11+
description: 'Format the output. Values: [yaml | json]'
12+
deprecated: false
13+
hidden: false
14+
experimental: false
15+
experimentalcli: false
16+
kubernetes: false
17+
swarm: false
18+
- option: name
19+
value_type: string
20+
description: Project name to set in the Compose file
21+
deprecated: false
22+
hidden: false
23+
experimental: false
24+
experimentalcli: false
25+
kubernetes: false
26+
swarm: false
27+
- option: project-dir
28+
value_type: string
29+
description: Directory to use for the project
30+
deprecated: false
31+
hidden: false
32+
experimental: false
33+
experimentalcli: false
34+
kubernetes: false
35+
swarm: false
36+
inherited_options:
37+
- option: dry-run
38+
value_type: bool
39+
default_value: "false"
40+
description: Execute command in dry run mode
41+
deprecated: false
42+
hidden: false
43+
experimental: false
44+
experimentalcli: false
45+
kubernetes: false
46+
swarm: false
47+
deprecated: false
48+
hidden: false
49+
experimental: false
50+
experimentalcli: true
51+
kubernetes: false
52+
swarm: false
53+

pkg/api/api.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ type Service interface {
9292
Scale(ctx context.Context, project *types.Project, options ScaleOptions) error
9393
// Export a service container's filesystem as a tar archive
9494
Export(ctx context.Context, projectName string, options ExportOptions) error
95+
// Generate generates a Compose Project from existing containers
96+
Generate(ctx context.Context, options GenerateOptions) (*types.Project, error)
9597
}
9698

9799
type ScaleOptions struct {
@@ -563,6 +565,13 @@ type ExportOptions struct {
563565
Output string
564566
}
565567

568+
type GenerateOptions struct {
569+
// ProjectName to set in the Compose file
570+
ProjectName string
571+
// Containers passed in the command line to be used as reference for service definition
572+
Containers []string
573+
}
574+
566575
const (
567576
// STARTING indicates that stack is being deployed
568577
STARTING string = "Starting"

pkg/compose/compose.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,10 @@ func (s *composeService) projectFromName(containers Containers, projectName stri
176176
}
177177
set := types.Services{}
178178
for _, c := range containers {
179-
serviceLabel := c.Labels[api.ServiceLabel]
179+
serviceLabel, ok := c.Labels[api.ServiceLabel]
180+
if !ok {
181+
serviceLabel = getCanonicalContainerName(c)
182+
}
180183
service, ok := set[serviceLabel]
181184
if !ok {
182185
service = types.ServiceConfig{

0 commit comments

Comments
 (0)