Skip to content

Commit a92069c

Browse files
feat(compose): auto-extract used images from Docker Compose file if not specified
Signed-off-by: Aleksei Igrychev <aleksei.igrychev@palark.com>
1 parent 45aa6a3 commit a92069c

File tree

1 file changed

+97
-2
lines changed

1 file changed

+97
-2
lines changed

cmd/werf/compose/main.go

Lines changed: 97 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
package compose
22

33
import (
4+
"bufio"
45
"context"
56
"fmt"
67
"os"
78
"os/exec"
9+
"regexp"
810
"strings"
911
"syscall"
1012

@@ -13,6 +15,7 @@ import (
1315
"github.com/werf/logboek"
1416
"github.com/werf/werf/v2/cmd/werf/common"
1517
"github.com/werf/werf/v2/pkg/build"
18+
"github.com/werf/werf/v2/pkg/config"
1619
"github.com/werf/werf/v2/pkg/container_backend"
1720
"github.com/werf/werf/v2/pkg/git_repo"
1821
"github.com/werf/werf/v2/pkg/git_repo/gitdata"
@@ -47,6 +50,95 @@ type composeCmdData struct {
4750
imagesToProcess build.ImagesToProcess
4851
}
4952

53+
func (d *composeCmdData) GetOrExtractImagesToProcess(werfConfig *config.WerfConfig) (build.ImagesToProcess, error) {
54+
if len(d.imagesToProcess.ImageNameList) != 0 {
55+
return d.imagesToProcess, nil
56+
}
57+
58+
// Replace all special characters in image name with empty string to find the same image name in werf config.
59+
replaceAllFunc := func(s string) string {
60+
for _, l := range []string{"_", "-", "/"} {
61+
s = strings.ReplaceAll(s, l, "")
62+
}
63+
return s
64+
}
65+
66+
extractedImageNameList, err := extractImageNamesFromDockerComposeFile(d.getComposeFilePath())
67+
if err != nil {
68+
return build.ImagesToProcess{}, fmt.Errorf("unable to extract image names from docker-compose file: %w", err)
69+
}
70+
71+
configImageNameList := werfConfig.GetImageNameList(false)
72+
73+
var imageNameList []string
74+
for _, configImageName := range configImageNameList {
75+
for _, imageName := range extractedImageNameList {
76+
if configImageName == imageName {
77+
imageNameList = append(imageNameList, imageName)
78+
continue
79+
}
80+
81+
if replaceAllFunc(configImageName) == replaceAllFunc(imageName) {
82+
imageNameList = append(imageNameList, configImageName)
83+
continue
84+
}
85+
}
86+
}
87+
88+
return build.NewImagesToProcess(imageNameList, len(imageNameList) == 0), nil
89+
}
90+
91+
func (d *composeCmdData) getComposeFilePath() string {
92+
for ind, value := range d.ComposeOptions {
93+
if strings.HasPrefix(value, "-f") || strings.HasPrefix(value, "--file") {
94+
parts := strings.Split(value, "=")
95+
if len(parts) == 2 {
96+
return parts[1]
97+
} else if len(d.ComposeOptions) > ind+1 {
98+
return d.ComposeOptions[ind+1]
99+
}
100+
}
101+
}
102+
103+
return "docker-compose.yml"
104+
}
105+
106+
func extractImageNamesFromDockerComposeFile(filename string) ([]string, error) {
107+
file, err := os.Open(filename)
108+
if err != nil {
109+
return nil, fmt.Errorf("error opening file: %v", err)
110+
}
111+
defer file.Close()
112+
113+
// Matches $WERF_<IMAGE_NAME>_DOCKER_IMAGE_NAME and ${WERF_<IMAGE_NAME>_DOCKER_IMAGE_NAME}.
114+
re := regexp.MustCompile(`\${?WERF_(.*)_DOCKER_IMAGE_NAME}?`)
115+
116+
var imageNames []string
117+
scanner := bufio.NewScanner(file)
118+
for scanner.Scan() {
119+
line := strings.TrimSpace(scanner.Text())
120+
121+
// Ignore commented lines.
122+
if strings.HasPrefix(line, "#") {
123+
continue
124+
}
125+
126+
matches := re.FindAllStringSubmatch(line, -1)
127+
for _, match := range matches {
128+
if len(match) > 1 {
129+
imageName := strings.ToLower(match[1])
130+
imageNames = append(imageNames, imageName)
131+
}
132+
}
133+
}
134+
135+
if err := scanner.Err(); err != nil {
136+
return nil, fmt.Errorf("error reading file: %v", err)
137+
}
138+
139+
return imageNames, nil
140+
}
141+
50142
func NewConfigCmd(ctx context.Context) *cobra.Command {
51143
return newCmd(ctx, "config", &newCmdOptions{
52144
Use: "config [IMAGE_NAME...] [options] [--docker-compose-options=\"OPTIONS\"] [--docker-compose-command-options=\"OPTIONS\"]",
@@ -342,13 +434,16 @@ func runMain(ctx context.Context, dockerComposeCmdName string, cmdData composeCm
342434
}
343435

344436
func run(ctx context.Context, containerBackend container_backend.ContainerBackend, giterminismManager giterminism_manager.Interface, commonCmdData common.CmdData, cmdData composeCmdData, dockerComposeCmdName string) error {
345-
imagesToProcess := cmdData.imagesToProcess
346-
347437
_, werfConfig, err := common.GetRequiredWerfConfig(ctx, &commonCmdData, giterminismManager, common.GetWerfConfigOptions(&commonCmdData, true))
348438
if err != nil {
349439
return fmt.Errorf("unable to load werf config: %w", err)
350440
}
351441

442+
imagesToProcess, err := cmdData.GetOrExtractImagesToProcess(werfConfig)
443+
if err != nil {
444+
return err
445+
}
446+
352447
if err := imagesToProcess.CheckImagesExistence(werfConfig); err != nil {
353448
return err
354449
}

0 commit comments

Comments
 (0)