(project *types.Project, buildForSinglePlatform bool)
| 38 | ) |
| 39 | |
| 40 | func applyPlatforms(project *types.Project, buildForSinglePlatform bool) error { |
| 41 | defaultPlatform := project.Environment["DOCKER_DEFAULT_PLATFORM"] |
| 42 | for name, service := range project.Services { |
| 43 | if service.Build == nil { |
| 44 | continue |
| 45 | } |
| 46 | |
| 47 | // default platform only applies if the service doesn't specify |
| 48 | if defaultPlatform != "" && service.Platform == "" { |
| 49 | if len(service.Build.Platforms) > 0 && !slices.Contains(service.Build.Platforms, defaultPlatform) { |
| 50 | return fmt.Errorf("service %q build.platforms does not support value set by DOCKER_DEFAULT_PLATFORM: %s", name, defaultPlatform) |
| 51 | } |
| 52 | service.Platform = defaultPlatform |
| 53 | } |
| 54 | |
| 55 | if service.Platform != "" { |
| 56 | if len(service.Build.Platforms) > 0 { |
| 57 | if !slices.Contains(service.Build.Platforms, service.Platform) { |
| 58 | return fmt.Errorf("service %q build configuration does not support platform: %s", name, service.Platform) |
| 59 | } |
| 60 | } |
| 61 | |
| 62 | if buildForSinglePlatform || len(service.Build.Platforms) == 0 { |
| 63 | // if we're building for a single platform, we want to build for the platform we'll use to run the image |
| 64 | // similarly, if no build platforms were explicitly specified, it makes sense to build for the platform |
| 65 | // the image is designed for rather than allowing the builder to infer the platform |
| 66 | service.Build.Platforms = []string{service.Platform} |
| 67 | } |
| 68 | } |
| 69 | |
| 70 | // services can specify that they should be built for multiple platforms, which can be used |
| 71 | // with `docker compose build` to produce a multi-arch image |
| 72 | // other cases, such as `up` and `run`, need a single architecture to actually run |
| 73 | // if there is only a single platform present (which might have been inferred |
| 74 | // from service.Platform above), it will be used, even if it requires emulation. |
| 75 | // if there's more than one platform, then the list is cleared so that the builder |
| 76 | // can decide. |
| 77 | // TODO(milas): there's no validation that the platform the builder will pick is actually one |
| 78 | // of the supported platforms from the build definition |
| 79 | // e.g. `build.platforms: [linux/arm64, linux/amd64]` on a `linux/ppc64` machine would build |
| 80 | // for `linux/ppc64` instead of returning an error that it's not a valid platform for the service. |
| 81 | if buildForSinglePlatform && len(service.Build.Platforms) > 1 { |
| 82 | // empty indicates that the builder gets to decide |
| 83 | service.Build.Platforms = nil |
| 84 | } |
| 85 | project.Services[name] = service |
| 86 | } |
| 87 | return nil |
| 88 | } |
| 89 | |
| 90 | // isRemoteConfig checks if the main compose file is from a remote source (OCI or Git) |
| 91 | func isRemoteConfig(dockerCli command.Cli, options buildOptions) bool { |
no outgoing calls