diff --git a/cmd/compose/config.go b/cmd/compose/config.go index f9176ec7b..8631956ce 100644 --- a/cmd/compose/config.go +++ b/cmd/compose/config.go @@ -136,55 +136,19 @@ func configCommand(p *ProjectOptions, dockerCli command.Cli) *cobra.Command { } func runConfig(ctx context.Context, dockerCli command.Cli, opts configOptions, services []string) error { - var content []byte model, err := opts.ToModel(ctx, dockerCli, services) if err != nil { return err } if opts.resolveImageDigests { - // create a pseudo-project so we can rely on WithImagesResolved to resolve images - p := &types.Project{ - Services: types.Services{}, - } - services := model["services"].(map[string]any) - for name, s := range services { - service := s.(map[string]any) - if image, ok := service["image"]; ok { - p.Services[name] = types.ServiceConfig{ - Image: image.(string), - } - } - } - - p, err = p.WithImagesResolved(compose.ImageDigestResolver(ctx, dockerCli.ConfigFile(), dockerCli.Client())) + err = resolveImageDigests(ctx, dockerCli, model) if err != nil { return err } - - for name, s := range services { - service := s.(map[string]any) - config := p.Services[name] - if config.Image != "" { - service["image"] = config.Image - } - services[name] = service - } - model["services"] = services } - switch opts.Format { - case "json": - content, err = json.MarshalIndent(model, "", " ") - case "yaml": - buf := bytes.NewBuffer([]byte{}) - encoder := yaml.NewEncoder(buf) - encoder.SetIndent(2) - err = encoder.Encode(model) - content = buf.Bytes() - default: - return fmt.Errorf("unsupported format %q", opts.Format) - } + content, err := formatModel(model, opts.Format) if err != nil { return err } @@ -204,6 +168,55 @@ func runConfig(ctx context.Context, dockerCli command.Cli, opts configOptions, s return err } +func resolveImageDigests(ctx context.Context, dockerCli command.Cli, model map[string]any) (err error) { + // create a pseudo-project so we can rely on WithImagesResolved to resolve images + p := &types.Project{ + Services: types.Services{}, + } + services := model["services"].(map[string]any) + for name, s := range services { + service := s.(map[string]any) + if image, ok := service["image"]; ok { + p.Services[name] = types.ServiceConfig{ + Image: image.(string), + } + } + } + + p, err = p.WithImagesResolved(compose.ImageDigestResolver(ctx, dockerCli.ConfigFile(), dockerCli.Client())) + if err != nil { + return err + } + + // Collect image resolved with digest and update model accordingly + for name, s := range services { + service := s.(map[string]any) + config := p.Services[name] + if config.Image != "" { + service["image"] = config.Image + } + services[name] = service + } + model["services"] = services + return nil +} + +func formatModel(model map[string]any, format string) (content []byte, err error) { + switch format { + case "json": + content, err = json.MarshalIndent(model, "", " ") + case "yaml": + buf := bytes.NewBuffer([]byte{}) + encoder := yaml.NewEncoder(buf) + encoder.SetIndent(2) + err = encoder.Encode(model) + content = buf.Bytes() + default: + return nil, fmt.Errorf("unsupported format %q", format) + } + return +} + func runServices(ctx context.Context, dockerCli command.Cli, opts configOptions) error { project, err := opts.ToProject(ctx, dockerCli, nil, cli.WithoutEnvironmentResolution) if err != nil {