Skip to content

Commit 8714689

Browse files
Polish "Add option to customize cache volume names when building an image"
See gh-28292
1 parent dc36346 commit 8714689

File tree

27 files changed

+929
-149
lines changed

27 files changed

+929
-149
lines changed

spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/BuildRequest.java

Lines changed: 46 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,9 @@ public class BuildRequest {
7575

7676
private final List<ImageReference> tags;
7777

78-
private final Map<String, String> cacheVolumeNames;
78+
private final Cache buildCache;
79+
80+
private final Cache launchCache;
7981

8082
BuildRequest(ImageReference name, Function<Owner, TarArchive> applicationContent) {
8183
Assert.notNull(name, "Name must not be null");
@@ -94,13 +96,14 @@ public class BuildRequest {
9496
this.bindings = Collections.emptyList();
9597
this.network = null;
9698
this.tags = Collections.emptyList();
97-
this.cacheVolumeNames = Collections.emptyMap();
99+
this.buildCache = null;
100+
this.launchCache = null;
98101
}
99102

100103
BuildRequest(ImageReference name, Function<Owner, TarArchive> applicationContent, ImageReference builder,
101104
ImageReference runImage, Creator creator, Map<String, String> env, boolean cleanCache,
102105
boolean verboseLogging, PullPolicy pullPolicy, boolean publish, List<BuildpackReference> buildpacks,
103-
List<Binding> bindings, String network, List<ImageReference> tags, Map<String, String> cacheVolumeNames) {
106+
List<Binding> bindings, String network, List<ImageReference> tags, Cache buildCache, Cache launchCache) {
104107
this.name = name;
105108
this.applicationContent = applicationContent;
106109
this.builder = builder;
@@ -115,7 +118,8 @@ public class BuildRequest {
115118
this.bindings = bindings;
116119
this.network = network;
117120
this.tags = tags;
118-
this.cacheVolumeNames = cacheVolumeNames;
121+
this.buildCache = buildCache;
122+
this.launchCache = launchCache;
119123
}
120124

121125
/**
@@ -127,7 +131,7 @@ public BuildRequest withBuilder(ImageReference builder) {
127131
Assert.notNull(builder, "Builder must not be null");
128132
return new BuildRequest(this.name, this.applicationContent, builder.inTaggedOrDigestForm(), this.runImage,
129133
this.creator, this.env, this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish,
130-
this.buildpacks, this.bindings, this.network, this.tags, this.cacheVolumeNames);
134+
this.buildpacks, this.bindings, this.network, this.tags, this.buildCache, this.launchCache);
131135
}
132136

133137
/**
@@ -138,7 +142,7 @@ public BuildRequest withBuilder(ImageReference builder) {
138142
public BuildRequest withRunImage(ImageReference runImageName) {
139143
return new BuildRequest(this.name, this.applicationContent, this.builder, runImageName.inTaggedOrDigestForm(),
140144
this.creator, this.env, this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish,
141-
this.buildpacks, this.bindings, this.network, this.tags, this.cacheVolumeNames);
145+
this.buildpacks, this.bindings, this.network, this.tags, this.buildCache, this.launchCache);
142146
}
143147

144148
/**
@@ -150,7 +154,7 @@ public BuildRequest withCreator(Creator creator) {
150154
Assert.notNull(creator, "Creator must not be null");
151155
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, creator, this.env,
152156
this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish, this.buildpacks, this.bindings,
153-
this.network, this.tags, this.cacheVolumeNames);
157+
this.network, this.tags, this.buildCache, this.launchCache);
154158
}
155159

156160
/**
@@ -166,7 +170,7 @@ public BuildRequest withEnv(String name, String value) {
166170
env.put(name, value);
167171
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator,
168172
Collections.unmodifiableMap(env), this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish,
169-
this.buildpacks, this.bindings, this.network, this.tags, this.cacheVolumeNames);
173+
this.buildpacks, this.bindings, this.network, this.tags, this.buildCache, this.launchCache);
170174
}
171175

172176
/**
@@ -180,7 +184,8 @@ public BuildRequest withEnv(Map<String, String> env) {
180184
updatedEnv.putAll(env);
181185
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator,
182186
Collections.unmodifiableMap(updatedEnv), this.cleanCache, this.verboseLogging, this.pullPolicy,
183-
this.publish, this.buildpacks, this.bindings, this.network, this.tags, this.cacheVolumeNames);
187+
this.publish, this.buildpacks, this.bindings, this.network, this.tags, this.buildCache,
188+
this.launchCache);
184189
}
185190

186191
/**
@@ -191,7 +196,7 @@ public BuildRequest withEnv(Map<String, String> env) {
191196
public BuildRequest withCleanCache(boolean cleanCache) {
192197
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, this.env,
193198
cleanCache, this.verboseLogging, this.pullPolicy, this.publish, this.buildpacks, this.bindings,
194-
this.network, this.tags, this.cacheVolumeNames);
199+
this.network, this.tags, this.buildCache, this.launchCache);
195200
}
196201

197202
/**
@@ -202,7 +207,7 @@ public BuildRequest withCleanCache(boolean cleanCache) {
202207
public BuildRequest withVerboseLogging(boolean verboseLogging) {
203208
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, this.env,
204209
this.cleanCache, verboseLogging, this.pullPolicy, this.publish, this.buildpacks, this.bindings,
205-
this.network, this.tags, this.cacheVolumeNames);
210+
this.network, this.tags, this.buildCache, this.launchCache);
206211
}
207212

208213
/**
@@ -213,7 +218,7 @@ public BuildRequest withVerboseLogging(boolean verboseLogging) {
213218
public BuildRequest withPullPolicy(PullPolicy pullPolicy) {
214219
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, this.env,
215220
this.cleanCache, this.verboseLogging, pullPolicy, this.publish, this.buildpacks, this.bindings,
216-
this.network, this.tags, this.cacheVolumeNames);
221+
this.network, this.tags, this.buildCache, this.launchCache);
217222
}
218223

219224
/**
@@ -224,7 +229,7 @@ public BuildRequest withPullPolicy(PullPolicy pullPolicy) {
224229
public BuildRequest withPublish(boolean publish) {
225230
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, this.env,
226231
this.cleanCache, this.verboseLogging, this.pullPolicy, publish, this.buildpacks, this.bindings,
227-
this.network, this.tags, this.cacheVolumeNames);
232+
this.network, this.tags, this.buildCache, this.launchCache);
228233
}
229234

230235
/**
@@ -248,7 +253,7 @@ public BuildRequest withBuildpacks(List<BuildpackReference> buildpacks) {
248253
Assert.notNull(buildpacks, "Buildpacks must not be null");
249254
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, this.env,
250255
this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish, buildpacks, this.bindings,
251-
this.network, this.tags, this.cacheVolumeNames);
256+
this.network, this.tags, this.buildCache, this.launchCache);
252257
}
253258

254259
/**
@@ -272,7 +277,7 @@ public BuildRequest withBindings(List<Binding> bindings) {
272277
Assert.notNull(bindings, "Bindings must not be null");
273278
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, this.env,
274279
this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish, this.buildpacks, bindings,
275-
this.network, this.tags, this.cacheVolumeNames);
280+
this.network, this.tags, this.buildCache, this.launchCache);
276281
}
277282

278283
/**
@@ -284,7 +289,7 @@ public BuildRequest withBindings(List<Binding> bindings) {
284289
public BuildRequest withNetwork(String network) {
285290
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, this.env,
286291
this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish, this.buildpacks, this.bindings,
287-
network, this.tags, this.cacheVolumeNames);
292+
network, this.tags, this.buildCache, this.launchCache);
288293
}
289294

290295
/**
@@ -306,39 +311,31 @@ public BuildRequest withTags(List<ImageReference> tags) {
306311
Assert.notNull(tags, "Tags must not be null");
307312
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, this.env,
308313
this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish, this.buildpacks, this.bindings,
309-
this.network, tags, this.cacheVolumeNames);
314+
this.network, tags, this.buildCache, this.launchCache);
310315
}
311316

312317
/**
313-
* Return a new {@link BuildRequest} with an additional cache volume name.
314-
* @param type the cache volume type
315-
* @param name the cache volume name
318+
* Return a new {@link BuildRequest} with an updated build cache.
319+
* @param buildCache the build cache
316320
* @return an updated build request
317321
*/
318-
public BuildRequest withCacheVolumeName(String type, String name) {
319-
Assert.hasText(type, "Type must not be empty");
320-
Assert.state((type.equals("build") || type.equals("launch")), "Type must be either 'build' or 'launch'");
321-
Assert.hasText(name, "Name must not be empty");
322-
Map<String, String> cacheVolumeNames = new LinkedHashMap<>(this.cacheVolumeNames);
323-
cacheVolumeNames.put(type, name);
322+
public BuildRequest withBuildCache(Cache buildCache) {
323+
Assert.notNull(buildCache, "BuildCache must not be null");
324324
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, this.env,
325325
this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish, this.buildpacks, this.bindings,
326-
this.network, this.tags, Collections.unmodifiableMap(cacheVolumeNames));
326+
this.network, this.tags, buildCache, this.launchCache);
327327
}
328328

329329
/**
330-
* Return a new {@link BuildRequest} with additional cache volume names.
331-
* @param entries the additional cache volume names
330+
* Return a new {@link BuildRequest} with an updated launch cache.
331+
* @param launchCache the cache
332332
* @return an updated build request
333333
*/
334-
public BuildRequest withCacheVolumeNames(Map<String, String> entries) {
335-
Assert.notNull(entries, "Entries must not be null");
336-
Assert.state(!entries.isEmpty(), "Entries must not be empty");
337-
BuildRequest request = null;
338-
for (Map.Entry<String, String> entry : entries.entrySet()) {
339-
request = withCacheVolumeName(entry.getKey(), entry.getValue());
340-
}
341-
return request;
334+
public BuildRequest withLaunchCache(Cache launchCache) {
335+
Assert.notNull(launchCache, "LaunchCache must not be null");
336+
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, this.env,
337+
this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish, this.buildpacks, this.bindings,
338+
this.network, this.tags, this.buildCache, launchCache);
342339
}
343340

344341
/**
@@ -459,11 +456,19 @@ public List<ImageReference> getTags() {
459456
}
460457

461458
/**
462-
* Return the custom cache volume names that should be used by the lifecycle.
463-
* @return the cache volume names
459+
* Return the custom build cache that should be used by the lifecycle.
460+
* @return the build cache
461+
*/
462+
public Cache getBuildCache() {
463+
return this.buildCache;
464+
}
465+
466+
/**
467+
* Return the custom launch cache that should be used by the lifecycle.
468+
* @return the launch cache
464469
*/
465-
public Map<String, String> getCacheVolumeNames() {
466-
return this.cacheVolumeNames;
470+
public Cache getLaunchCache() {
471+
return this.launchCache;
467472
}
468473

469474
/**
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
/*
2+
* Copyright 2012-2021 the original author or 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+
* https://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 org.springframework.boot.buildpack.platform.build;
18+
19+
import java.util.Objects;
20+
21+
import org.springframework.util.Assert;
22+
import org.springframework.util.ObjectUtils;
23+
24+
/**
25+
* Details of a cache for use by the CNB builder.
26+
*
27+
* @author Scott Frederick
28+
* @since 2.6.0
29+
*/
30+
public class Cache {
31+
32+
/**
33+
* The format of the cache.
34+
*/
35+
public enum Format {
36+
37+
/**
38+
* A cache stored as a volume in the Docker daemon.
39+
*/
40+
VOLUME;
41+
42+
}
43+
44+
protected final Format format;
45+
46+
Cache(Format format) {
47+
this.format = format;
48+
}
49+
50+
/**
51+
* Return the details of the cache if it is a volume cache.
52+
* @return the cache, or {@code null} if it is not a volume cache
53+
*/
54+
public Volume getVolume() {
55+
return (this.format.equals(Format.VOLUME)) ? (Volume) this : null;
56+
}
57+
58+
/**
59+
* Create a new {@code Cache} that uses a volume with the provided name.
60+
* @param name the cache volume name
61+
* @return a new cache instance
62+
*/
63+
public static Cache volume(String name) {
64+
Assert.notNull(name, "Name must not be null");
65+
return new Volume(name);
66+
}
67+
68+
@Override
69+
public boolean equals(Object obj) {
70+
if (this == obj) {
71+
return true;
72+
}
73+
if (obj == null || getClass() != obj.getClass()) {
74+
return false;
75+
}
76+
Cache other = (Cache) obj;
77+
return Objects.equals(this.format, other.format);
78+
}
79+
80+
@Override
81+
public int hashCode() {
82+
return ObjectUtils.nullSafeHashCode(this.format);
83+
}
84+
85+
/**
86+
* Details of a cache stored in a Docker volume.
87+
*/
88+
public static class Volume extends Cache {
89+
90+
private final String name;
91+
92+
Volume(String name) {
93+
super(Format.VOLUME);
94+
this.name = name;
95+
}
96+
97+
public String getName() {
98+
return this.name;
99+
}
100+
101+
@Override
102+
public boolean equals(Object obj) {
103+
if (this == obj) {
104+
return true;
105+
}
106+
if (obj == null || getClass() != obj.getClass()) {
107+
return false;
108+
}
109+
if (!super.equals(obj)) {
110+
return false;
111+
}
112+
Volume other = (Volume) obj;
113+
return Objects.equals(this.name, other.name);
114+
}
115+
116+
@Override
117+
public int hashCode() {
118+
int result = super.hashCode();
119+
result = 31 * result + ObjectUtils.nullSafeHashCode(this.name);
120+
return result;
121+
}
122+
123+
}
124+
125+
}

spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Lifecycle.java

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -87,18 +87,36 @@ class Lifecycle implements Closeable {
8787
this.platformVersion = getPlatformVersion(builder.getBuilderMetadata().getLifecycle());
8888
this.layersVolume = createRandomVolumeName("pack-layers-");
8989
this.applicationVolume = createRandomVolumeName("pack-app-");
90-
this.buildCacheVolume = createCacheVolumeName(request, "build");
91-
this.launchCacheVolume = createCacheVolumeName(request, "launch");
90+
this.buildCacheVolume = getBuildCacheVolumeName(request);
91+
this.launchCacheVolume = getLaunchCacheVolumeName(request);
9292
}
9393

9494
protected VolumeName createRandomVolumeName(String prefix) {
9595
return VolumeName.random(prefix);
9696
}
9797

98-
private VolumeName createCacheVolumeName(BuildRequest request, String suffix) {
99-
if (!request.getCacheVolumeNames().isEmpty() && request.getCacheVolumeNames().containsKey(suffix)) {
100-
return VolumeName.of(request.getCacheVolumeNames().get(suffix));
98+
private VolumeName getBuildCacheVolumeName(BuildRequest request) {
99+
if (request.getBuildCache() != null) {
100+
return getVolumeName(request.getBuildCache());
101+
}
102+
return createCacheVolumeName(request, "build");
103+
}
104+
105+
private VolumeName getLaunchCacheVolumeName(BuildRequest request) {
106+
if (request.getLaunchCache() != null) {
107+
return getVolumeName(request.getLaunchCache());
108+
}
109+
return createCacheVolumeName(request, "launch");
110+
}
111+
112+
private VolumeName getVolumeName(Cache cache) {
113+
if (cache.getVolume() != null) {
114+
return VolumeName.of(cache.getVolume().getName());
101115
}
116+
return null;
117+
}
118+
119+
private VolumeName createCacheVolumeName(BuildRequest request, String suffix) {
102120
return VolumeName.basedOn(request.getName(), ImageReference::toLegacyString, "pack-cache-", "." + suffix, 6);
103121
}
104122

0 commit comments

Comments
 (0)