mirror of
https://github.com/spring-projects/spring-boot.git
synced 2026-09-17 12:09:16 +00:00
Polish "Add support for image-based build caches"
See gh-50899
This commit is contained in:
+14
-13
@@ -47,6 +47,7 @@ import org.springframework.boot.buildpack.platform.build.Builder;
|
||||
import org.springframework.boot.buildpack.platform.build.BuildpackReference;
|
||||
import org.springframework.boot.buildpack.platform.build.Cache;
|
||||
import org.springframework.boot.buildpack.platform.build.Creator;
|
||||
import org.springframework.boot.buildpack.platform.build.LocalCache;
|
||||
import org.springframework.boot.buildpack.platform.build.PullPolicy;
|
||||
import org.springframework.boot.buildpack.platform.docker.transport.DockerEngineException;
|
||||
import org.springframework.boot.buildpack.platform.docker.type.Binding;
|
||||
@@ -75,11 +76,11 @@ public abstract class BootBuildImage extends DefaultTask {
|
||||
|
||||
private final String projectName;
|
||||
|
||||
private final CacheSpec buildWorkspace;
|
||||
private final LocalCacheSpec buildWorkspace;
|
||||
|
||||
private final CacheSpec buildCache;
|
||||
|
||||
private final CacheSpec launchCache;
|
||||
private final LocalCacheSpec launchCache;
|
||||
|
||||
private final DockerSpec docker;
|
||||
|
||||
@@ -100,9 +101,9 @@ public abstract class BootBuildImage extends DefaultTask {
|
||||
getCleanCache().convention(false);
|
||||
getVerboseLogging().convention(false);
|
||||
getPublish().convention(false);
|
||||
this.buildWorkspace = getProject().getObjects().newInstance(CacheSpec.class);
|
||||
this.buildWorkspace = getProject().getObjects().newInstance(LocalCacheSpec.class);
|
||||
this.buildCache = getProject().getObjects().newInstance(CacheSpec.class);
|
||||
this.launchCache = getProject().getObjects().newInstance(CacheSpec.class);
|
||||
this.launchCache = getProject().getObjects().newInstance(LocalCacheSpec.class);
|
||||
this.docker = getProject().getObjects().newInstance(DockerSpec.class);
|
||||
this.pullPolicy = getProject().getObjects().property(PullPolicy.class);
|
||||
getSecurityOptions().convention((Iterable<? extends String>) null);
|
||||
@@ -280,17 +281,17 @@ public abstract class BootBuildImage extends DefaultTask {
|
||||
*/
|
||||
@Nested
|
||||
@Optional
|
||||
public CacheSpec getBuildWorkspace() {
|
||||
public LocalCacheSpec getBuildWorkspace() {
|
||||
return this.buildWorkspace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Customizes the {@link CacheSpec} for the build temporary workspace using the given
|
||||
* {@code action}.
|
||||
* Customizes the {@link LocalCacheSpec} for the build temporary workspace using the
|
||||
* given {@code action}.
|
||||
* @param action the action
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public void buildWorkspace(Action<CacheSpec> action) {
|
||||
public void buildWorkspace(Action<LocalCacheSpec> action) {
|
||||
action.execute(this.buildWorkspace);
|
||||
}
|
||||
|
||||
@@ -319,16 +320,16 @@ public abstract class BootBuildImage extends DefaultTask {
|
||||
*/
|
||||
@Nested
|
||||
@Optional
|
||||
public CacheSpec getLaunchCache() {
|
||||
public LocalCacheSpec getLaunchCache() {
|
||||
return this.launchCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Customizes the {@link CacheSpec} for the launch cache using the given
|
||||
* Customizes the {@link LocalCacheSpec} for the launch cache using the given
|
||||
* {@code action}.
|
||||
* @param action the action
|
||||
*/
|
||||
public void launchCache(Action<CacheSpec> action) {
|
||||
public void launchCache(Action<LocalCacheSpec> action) {
|
||||
action.execute(this.launchCache);
|
||||
}
|
||||
|
||||
@@ -495,7 +496,7 @@ public abstract class BootBuildImage extends DefaultTask {
|
||||
}
|
||||
|
||||
private BuildRequest customizeCaches(BuildRequest request) {
|
||||
Cache buildWorkspaceCache = this.buildWorkspace.asCache();
|
||||
LocalCache buildWorkspaceCache = this.buildWorkspace.asCache();
|
||||
if (buildWorkspaceCache != null) {
|
||||
request = request.withBuildWorkspace(buildWorkspaceCache);
|
||||
}
|
||||
@@ -503,7 +504,7 @@ public abstract class BootBuildImage extends DefaultTask {
|
||||
if (buildCache != null) {
|
||||
request = request.withBuildCache(buildCache);
|
||||
}
|
||||
Cache launchCache = this.launchCache.asCache();
|
||||
LocalCache launchCache = this.launchCache.asCache();
|
||||
if (launchCache != null) {
|
||||
request = request.withLaunchCache(launchCache);
|
||||
}
|
||||
|
||||
+3
-28
@@ -26,6 +26,8 @@ import org.gradle.api.tasks.Input;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.buildpack.platform.build.Cache;
|
||||
import org.springframework.boot.gradle.tasks.bundling.LocalCacheSpec.BindCacheSpec;
|
||||
import org.springframework.boot.gradle.tasks.bundling.LocalCacheSpec.VolumeCacheSpec;
|
||||
|
||||
/**
|
||||
* Configuration for an image building cache.
|
||||
@@ -77,6 +79,7 @@ public class CacheSpec {
|
||||
/**
|
||||
* Configures an image cache using the given {@code action}.
|
||||
* @param action the action
|
||||
* @since 4.2.0
|
||||
*/
|
||||
public void image(Action<ImageCacheSpec> action) {
|
||||
if (this.cache != null) {
|
||||
@@ -87,34 +90,6 @@ public class CacheSpec {
|
||||
this.cache = Cache.image(spec.getName().get());
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration for an image building cache stored in a Docker volume.
|
||||
*/
|
||||
public abstract static class VolumeCacheSpec {
|
||||
|
||||
/**
|
||||
* Returns the name of the cache.
|
||||
* @return the cache name
|
||||
*/
|
||||
@Input
|
||||
public abstract Property<String> getName();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration for an image building cache stored in a bind mount.
|
||||
*/
|
||||
public abstract static class BindCacheSpec {
|
||||
|
||||
/**
|
||||
* Returns the source of the cache.
|
||||
* @return the cache source
|
||||
*/
|
||||
@Input
|
||||
public abstract Property<String> getSource();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration for an image building cache stored in an image.
|
||||
*/
|
||||
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright 2012-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.gradle.tasks.bundling;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.gradle.api.Action;
|
||||
import org.gradle.api.GradleException;
|
||||
import org.gradle.api.model.ObjectFactory;
|
||||
import org.gradle.api.provider.Property;
|
||||
import org.gradle.api.tasks.Input;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.buildpack.platform.build.Cache;
|
||||
import org.springframework.boot.buildpack.platform.build.LocalCache;
|
||||
|
||||
/**
|
||||
* Configuration for a local image building cache stored in a volume or bind mount.
|
||||
*
|
||||
* @author Scott Frederick
|
||||
* @author Stephane Nicoll
|
||||
* @since 4.2.0
|
||||
*/
|
||||
public class LocalCacheSpec {
|
||||
|
||||
private final ObjectFactory objectFactory;
|
||||
|
||||
private @Nullable LocalCache cache;
|
||||
|
||||
@Inject
|
||||
public LocalCacheSpec(ObjectFactory objectFactory) {
|
||||
this.objectFactory = objectFactory;
|
||||
}
|
||||
|
||||
public @Nullable LocalCache asCache() {
|
||||
return this.cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures a volume cache using the given {@code action}.
|
||||
* @param action the action
|
||||
*/
|
||||
public void volume(Action<VolumeCacheSpec> action) {
|
||||
if (this.cache != null) {
|
||||
throw new GradleException("Each image building cache can be configured only once");
|
||||
}
|
||||
VolumeCacheSpec spec = this.objectFactory.newInstance(VolumeCacheSpec.class);
|
||||
action.execute(spec);
|
||||
this.cache = Cache.volume(spec.getName().get());
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures a bind cache using the given {@code action}.
|
||||
* @param action the action
|
||||
*/
|
||||
public void bind(Action<BindCacheSpec> action) {
|
||||
if (this.cache != null) {
|
||||
throw new GradleException("Each image building cache can be configured only once");
|
||||
}
|
||||
BindCacheSpec spec = this.objectFactory.newInstance(BindCacheSpec.class);
|
||||
action.execute(spec);
|
||||
this.cache = Cache.bind(spec.getSource().get());
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration for an image building cache stored in a Docker volume.
|
||||
*/
|
||||
public abstract static class VolumeCacheSpec {
|
||||
|
||||
/**
|
||||
* Returns the name of the cache.
|
||||
* @return the cache name
|
||||
*/
|
||||
@Input
|
||||
public abstract Property<String> getName();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration for an image building cache stored in a bind mount.
|
||||
*/
|
||||
public abstract static class BindCacheSpec {
|
||||
|
||||
/**
|
||||
* Returns the source of the cache.
|
||||
* @return the cache source
|
||||
*/
|
||||
@Input
|
||||
public abstract Property<String> getSource();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+25
@@ -29,6 +29,7 @@ import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
import org.springframework.boot.buildpack.platform.build.BuildRequest;
|
||||
import org.springframework.boot.buildpack.platform.build.BuildpackReference;
|
||||
import org.springframework.boot.buildpack.platform.build.Cache;
|
||||
import org.springframework.boot.buildpack.platform.build.PullPolicy;
|
||||
import org.springframework.boot.buildpack.platform.docker.ImagePlatform;
|
||||
import org.springframework.boot.buildpack.platform.docker.type.Binding;
|
||||
@@ -357,4 +358,28 @@ class BootBuildImageTests {
|
||||
assertThat(this.buildImage.createRequest().getImagePlatform()).isEqualTo(ImagePlatform.of("linux/arm64/v1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenBuildWorkspaceIsConfiguredThenRequestHasBuildWorkspace() {
|
||||
this.buildImage.buildWorkspace((cache) -> cache.volume((volume) -> volume.getName().set("workspace-vol")));
|
||||
assertThat(this.buildImage.createRequest().getBuildWorkspace()).isEqualTo(Cache.volume("workspace-vol"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenBuildCacheIsConfiguredWithVolumeThenRequestHasBuildCache() {
|
||||
this.buildImage.buildCache((cache) -> cache.volume((volume) -> volume.getName().set("build-vol")));
|
||||
assertThat(this.buildImage.createRequest().getBuildCache()).isEqualTo(Cache.volume("build-vol"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenBuildCacheIsConfiguredWithImageThenRequestHasBuildCache() {
|
||||
this.buildImage.buildCache((cache) -> cache.image((image) -> image.getName().set("build-cache-image")));
|
||||
assertThat(this.buildImage.createRequest().getBuildCache()).isEqualTo(Cache.image("build-cache-image"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenLaunchCacheIsConfiguredThenRequestHasLaunchCache() {
|
||||
this.buildImage.launchCache((cache) -> cache.bind((bind) -> bind.getSource().set("/tmp/launch")));
|
||||
assertThat(this.buildImage.createRequest().getLaunchCache()).isEqualTo(Cache.bind("/tmp/launch"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -19,4 +19,4 @@
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
<!-- end::caches[] -->
|
||||
<!-- end::caches[] -->
|
||||
|
||||
+2
-48
@@ -19,6 +19,8 @@ package org.springframework.boot.maven;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.buildpack.platform.build.Cache;
|
||||
import org.springframework.boot.maven.LocalCacheInfo.BindCacheInfo;
|
||||
import org.springframework.boot.maven.LocalCacheInfo.VolumeCacheInfo;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -81,54 +83,6 @@ public class CacheInfo {
|
||||
return new CacheInfo(Cache.image(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Encapsulates configuration of an image building cache stored in a volume.
|
||||
*/
|
||||
public static class VolumeCacheInfo {
|
||||
|
||||
private @Nullable String name;
|
||||
|
||||
public VolumeCacheInfo() {
|
||||
}
|
||||
|
||||
VolumeCacheInfo(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public @Nullable String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
void setName(@Nullable String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Encapsulates configuration of an image building cache stored in a bind mount.
|
||||
*/
|
||||
public static class BindCacheInfo {
|
||||
|
||||
private @Nullable String source;
|
||||
|
||||
public BindCacheInfo() {
|
||||
}
|
||||
|
||||
BindCacheInfo(String name) {
|
||||
this.source = name;
|
||||
}
|
||||
|
||||
public @Nullable String getSource() {
|
||||
return this.source;
|
||||
}
|
||||
|
||||
void setSource(@Nullable String source) {
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Encapsulates configuration of an image building cache stored in an image.
|
||||
*/
|
||||
|
||||
+5
-4
@@ -26,6 +26,7 @@ import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.boot.buildpack.platform.build.BuildRequest;
|
||||
import org.springframework.boot.buildpack.platform.build.BuildpackReference;
|
||||
import org.springframework.boot.buildpack.platform.build.Cache;
|
||||
import org.springframework.boot.buildpack.platform.build.LocalCache;
|
||||
import org.springframework.boot.buildpack.platform.build.PullPolicy;
|
||||
import org.springframework.boot.buildpack.platform.docker.type.Binding;
|
||||
import org.springframework.boot.buildpack.platform.docker.type.ImageName;
|
||||
@@ -74,11 +75,11 @@ public class Image {
|
||||
|
||||
@Nullable List<String> tags;
|
||||
|
||||
@Nullable CacheInfo buildWorkspace;
|
||||
@Nullable LocalCacheInfo buildWorkspace;
|
||||
|
||||
@Nullable CacheInfo buildCache;
|
||||
|
||||
@Nullable CacheInfo launchCache;
|
||||
@Nullable LocalCacheInfo launchCache;
|
||||
|
||||
@Nullable String createdDate;
|
||||
|
||||
@@ -284,7 +285,7 @@ public class Image {
|
||||
request = request.withTags(this.tags.stream().map(ImageReference::of).toList());
|
||||
}
|
||||
if (this.buildWorkspace != null) {
|
||||
Cache cache = this.buildWorkspace.asCache();
|
||||
LocalCache cache = this.buildWorkspace.asCache();
|
||||
Assert.state(cache != null, "'cache' must not be null");
|
||||
request = request.withBuildWorkspace(cache);
|
||||
}
|
||||
@@ -294,7 +295,7 @@ public class Image {
|
||||
request = request.withBuildCache(cache);
|
||||
}
|
||||
if (this.launchCache != null) {
|
||||
Cache cache = this.launchCache.asCache();
|
||||
LocalCache cache = this.launchCache.asCache();
|
||||
Assert.state(cache != null, "'cache' must not be null");
|
||||
request = request.withLaunchCache(cache);
|
||||
}
|
||||
|
||||
+121
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright 2012-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.maven;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.buildpack.platform.build.Cache;
|
||||
import org.springframework.boot.buildpack.platform.build.LocalCache;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Encapsulates configuration of a local image building cache.
|
||||
*
|
||||
* @author Scott Frederick
|
||||
* @author Stephane Nicoll
|
||||
* @since 4.2.0
|
||||
*/
|
||||
public class LocalCacheInfo {
|
||||
|
||||
private @Nullable LocalCache cache;
|
||||
|
||||
public LocalCacheInfo() {
|
||||
}
|
||||
|
||||
LocalCacheInfo(LocalCache cache) {
|
||||
this.cache = cache;
|
||||
}
|
||||
|
||||
public void setVolume(VolumeCacheInfo info) {
|
||||
Assert.state(this.cache == null, "Each image building cache can be configured only once");
|
||||
String name = info.getName();
|
||||
Assert.state(name != null, "'name' must not be null");
|
||||
this.cache = Cache.volume(name);
|
||||
}
|
||||
|
||||
public void setBind(BindCacheInfo info) {
|
||||
Assert.state(this.cache == null, "Each image building cache can be configured only once");
|
||||
String source = info.getSource();
|
||||
Assert.state(source != null, "'source' must not be null");
|
||||
this.cache = Cache.bind(source);
|
||||
}
|
||||
|
||||
@Nullable LocalCache asCache() {
|
||||
return this.cache;
|
||||
}
|
||||
|
||||
static LocalCacheInfo fromVolume(VolumeCacheInfo cacheInfo) {
|
||||
String name = cacheInfo.getName();
|
||||
Assert.state(name != null, "'name' must not be null");
|
||||
return new LocalCacheInfo(Cache.volume(name));
|
||||
}
|
||||
|
||||
static LocalCacheInfo fromBind(BindCacheInfo cacheInfo) {
|
||||
String source = cacheInfo.getSource();
|
||||
Assert.state(source != null, "'source' must not be null");
|
||||
return new LocalCacheInfo(Cache.bind(source));
|
||||
}
|
||||
|
||||
/**
|
||||
* Encapsulates configuration of an image building cache stored in a volume.
|
||||
*/
|
||||
public static class VolumeCacheInfo {
|
||||
|
||||
private @Nullable String name;
|
||||
|
||||
public VolumeCacheInfo() {
|
||||
}
|
||||
|
||||
VolumeCacheInfo(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public @Nullable String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
void setName(@Nullable String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Encapsulates configuration of an image building cache stored in a bind mount.
|
||||
*/
|
||||
public static class BindCacheInfo {
|
||||
|
||||
private @Nullable String source;
|
||||
|
||||
public BindCacheInfo() {
|
||||
}
|
||||
|
||||
BindCacheInfo(String name) {
|
||||
this.source = name;
|
||||
}
|
||||
|
||||
public @Nullable String getSource() {
|
||||
return this.source;
|
||||
}
|
||||
|
||||
void setSource(@Nullable String source) {
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+6
-16
@@ -36,12 +36,11 @@ import org.springframework.boot.buildpack.platform.docker.type.Binding;
|
||||
import org.springframework.boot.buildpack.platform.docker.type.ImageReference;
|
||||
import org.springframework.boot.buildpack.platform.io.Owner;
|
||||
import org.springframework.boot.buildpack.platform.io.TarArchive;
|
||||
import org.springframework.boot.maven.CacheInfo.BindCacheInfo;
|
||||
import org.springframework.boot.maven.CacheInfo.ImageCacheInfo;
|
||||
import org.springframework.boot.maven.CacheInfo.VolumeCacheInfo;
|
||||
import org.springframework.boot.maven.LocalCacheInfo.BindCacheInfo;
|
||||
import org.springframework.boot.maven.LocalCacheInfo.VolumeCacheInfo;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
import static org.assertj.core.api.Assertions.entry;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
@@ -202,7 +201,7 @@ class ImageTests {
|
||||
@Test
|
||||
void getBuildRequestWhenHasBuildWorkspaceVolumeUsesWorkspace() {
|
||||
Image image = new Image();
|
||||
image.buildWorkspace = CacheInfo.fromVolume(new VolumeCacheInfo("build-work-vol"));
|
||||
image.buildWorkspace = LocalCacheInfo.fromVolume(new VolumeCacheInfo("build-work-vol"));
|
||||
BuildRequest request = image.getBuildRequest(createArtifact(), mockApplicationContent());
|
||||
assertThat(request.getBuildWorkspace()).isEqualTo(Cache.volume("build-work-vol"));
|
||||
}
|
||||
@@ -218,7 +217,7 @@ class ImageTests {
|
||||
@Test
|
||||
void getBuildRequestWhenHasLaunchCacheVolumeUsesCache() {
|
||||
Image image = new Image();
|
||||
image.launchCache = CacheInfo.fromVolume(new VolumeCacheInfo("launch-cache-vol"));
|
||||
image.launchCache = LocalCacheInfo.fromVolume(new VolumeCacheInfo("launch-cache-vol"));
|
||||
BuildRequest request = image.getBuildRequest(createArtifact(), mockApplicationContent());
|
||||
assertThat(request.getLaunchCache()).isEqualTo(Cache.volume("launch-cache-vol"));
|
||||
}
|
||||
@@ -226,7 +225,7 @@ class ImageTests {
|
||||
@Test
|
||||
void getBuildRequestWhenHasBuildWorkspaceBindUsesWorkspace() {
|
||||
Image image = new Image();
|
||||
image.buildWorkspace = CacheInfo.fromBind(new BindCacheInfo("build-work-dir"));
|
||||
image.buildWorkspace = LocalCacheInfo.fromBind(new BindCacheInfo("build-work-dir"));
|
||||
BuildRequest request = image.getBuildRequest(createArtifact(), mockApplicationContent());
|
||||
assertThat(request.getBuildWorkspace()).isEqualTo(Cache.bind("build-work-dir"));
|
||||
}
|
||||
@@ -242,7 +241,7 @@ class ImageTests {
|
||||
@Test
|
||||
void getBuildRequestWhenHasLaunchCacheBindUsesCache() {
|
||||
Image image = new Image();
|
||||
image.launchCache = CacheInfo.fromBind(new BindCacheInfo("launch-cache-dir"));
|
||||
image.launchCache = LocalCacheInfo.fromBind(new BindCacheInfo("launch-cache-dir"));
|
||||
BuildRequest request = image.getBuildRequest(createArtifact(), mockApplicationContent());
|
||||
assertThat(request.getLaunchCache()).isEqualTo(Cache.bind("launch-cache-dir"));
|
||||
}
|
||||
@@ -255,15 +254,6 @@ class ImageTests {
|
||||
assertThat(request.getBuildCache()).isEqualTo(Cache.image("build-cache-image"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getBuildRequestWhenHasLaunchCacheImageThrowsException() {
|
||||
Image image = new Image();
|
||||
image.launchCache = CacheInfo.fromImage(new ImageCacheInfo("launch-cache-image"));
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> image.getBuildRequest(createArtifact(), mockApplicationContent()))
|
||||
.withMessage("Launch cache must not be an image cache");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getBuildRequestWhenHasCreatedDateUsesCreatedDate() {
|
||||
Image image = new Image();
|
||||
|
||||
+8
-9
@@ -95,11 +95,11 @@ public class BuildRequest {
|
||||
|
||||
private final List<ImageReference> tags;
|
||||
|
||||
private final @Nullable Cache buildWorkspace;
|
||||
private final @Nullable LocalCache buildWorkspace;
|
||||
|
||||
private final @Nullable Cache buildCache;
|
||||
|
||||
private final @Nullable Cache launchCache;
|
||||
private final @Nullable LocalCache launchCache;
|
||||
|
||||
private final @Nullable Instant createdDate;
|
||||
|
||||
@@ -140,8 +140,8 @@ public class BuildRequest {
|
||||
@Nullable Boolean trustBuilder, @Nullable ImageReference runImage, Creator creator, Map<String, String> env,
|
||||
boolean cleanCache, boolean verboseLogging, PullPolicy pullPolicy, boolean publish,
|
||||
List<BuildpackReference> buildpacks, List<Binding> bindings, @Nullable String network,
|
||||
List<ImageReference> tags, @Nullable Cache buildWorkspace, @Nullable Cache buildCache,
|
||||
@Nullable Cache launchCache, @Nullable Instant createdDate, @Nullable String applicationDirectory,
|
||||
List<ImageReference> tags, @Nullable LocalCache buildWorkspace, @Nullable Cache buildCache,
|
||||
@Nullable LocalCache launchCache, @Nullable Instant createdDate, @Nullable String applicationDirectory,
|
||||
@Nullable List<String> securityOptions, @Nullable ImagePlatform platform) {
|
||||
this.name = name;
|
||||
this.applicationContent = applicationContent;
|
||||
@@ -395,7 +395,7 @@ public class BuildRequest {
|
||||
* @return an updated build request
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public BuildRequest withBuildWorkspace(Cache buildWorkspace) {
|
||||
public BuildRequest withBuildWorkspace(LocalCache buildWorkspace) {
|
||||
Assert.notNull(buildWorkspace, "'buildWorkspace' must not be null");
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder, this.trustBuilder, this.runImage,
|
||||
this.creator, this.env, this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish,
|
||||
@@ -421,9 +421,8 @@ public class BuildRequest {
|
||||
* @param launchCache the cache
|
||||
* @return an updated build request
|
||||
*/
|
||||
public BuildRequest withLaunchCache(Cache launchCache) {
|
||||
public BuildRequest withLaunchCache(LocalCache launchCache) {
|
||||
Assert.notNull(launchCache, "'launchCache' must not be null");
|
||||
Assert.isNull(launchCache.getImage(), "Launch cache must not be an image cache");
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder, this.trustBuilder, this.runImage,
|
||||
this.creator, this.env, this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish,
|
||||
this.buildpacks, this.bindings, this.network, this.tags, this.buildWorkspace, this.buildCache,
|
||||
@@ -633,7 +632,7 @@ public class BuildRequest {
|
||||
* @return the build workspace or {@code null}
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public @Nullable Cache getBuildWorkspace() {
|
||||
public @Nullable LocalCache getBuildWorkspace() {
|
||||
return this.buildWorkspace;
|
||||
}
|
||||
|
||||
@@ -649,7 +648,7 @@ public class BuildRequest {
|
||||
* Return the custom launch cache that should be used by the lifecycle.
|
||||
* @return the launch cache
|
||||
*/
|
||||
public @Nullable Cache getLaunchCache() {
|
||||
public @Nullable LocalCache getLaunchCache() {
|
||||
return this.launchCache;
|
||||
}
|
||||
|
||||
|
||||
+18
-209
@@ -16,82 +16,46 @@
|
||||
|
||||
package org.springframework.boot.buildpack.platform.build;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.buildpack.platform.build.LocalCache.Bind;
|
||||
import org.springframework.boot.buildpack.platform.build.LocalCache.Volume;
|
||||
import org.springframework.boot.buildpack.platform.docker.type.VolumeName;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Details of a cache for use by the CNB builder.
|
||||
*
|
||||
* @author Scott Frederick
|
||||
* @author Tim Ysewyn
|
||||
* @author Stephane Nicoll
|
||||
* @since 2.6.0
|
||||
*/
|
||||
public class Cache {
|
||||
|
||||
/**
|
||||
* The format of the cache.
|
||||
*/
|
||||
public enum Format {
|
||||
|
||||
/**
|
||||
* A cache stored as a volume in the Docker daemon.
|
||||
*/
|
||||
VOLUME("volume"),
|
||||
|
||||
/**
|
||||
* A cache stored as a bind mount.
|
||||
*/
|
||||
BIND("bind mount"),
|
||||
|
||||
/**
|
||||
* A cache stored as an image.
|
||||
*/
|
||||
IMAGE("image");
|
||||
|
||||
private final String description;
|
||||
|
||||
Format(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return this.description;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected final Format format;
|
||||
|
||||
Cache(Format format) {
|
||||
this.format = format;
|
||||
}
|
||||
public sealed interface Cache permits LocalCache, ImageCache {
|
||||
|
||||
/**
|
||||
* Return the details of the cache if it is a volume cache.
|
||||
* @return the cache, or {@code null} if it is not a volume cache
|
||||
*/
|
||||
public @Nullable Volume getVolume() {
|
||||
return (this.format.equals(Format.VOLUME)) ? (Volume) this : null;
|
||||
default LocalCache.@Nullable Volume getVolume() {
|
||||
return (this instanceof LocalCache.Volume volume) ? volume : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the details of the cache if it is a bind cache.
|
||||
* @return the cache, or {@code null} if it is not a bind cache
|
||||
*/
|
||||
public @Nullable Bind getBind() {
|
||||
return (this.format.equals(Format.BIND)) ? (Bind) this : null;
|
||||
default LocalCache.@Nullable Bind getBind() {
|
||||
return (this instanceof LocalCache.Bind bind) ? bind : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the details of the cache if it is an image cache.
|
||||
* @return the cache, or {@code null} if it is not an image cache
|
||||
* @since 4.2.0
|
||||
*/
|
||||
public @Nullable Image getImage() {
|
||||
return (this.format.equals(Format.IMAGE)) ? (Image) this : null;
|
||||
default @Nullable ImageCache getImage() {
|
||||
return (this instanceof ImageCache image) ? image : null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -99,7 +63,7 @@ public class Cache {
|
||||
* @param name the cache volume name
|
||||
* @return a new cache instance
|
||||
*/
|
||||
public static Cache volume(String name) {
|
||||
static LocalCache volume(String name) {
|
||||
Assert.notNull(name, "'name' must not be null");
|
||||
return new Volume(VolumeName.of(name));
|
||||
}
|
||||
@@ -109,7 +73,7 @@ public class Cache {
|
||||
* @param name the cache volume name
|
||||
* @return a new cache instance
|
||||
*/
|
||||
public static Cache volume(VolumeName name) {
|
||||
static LocalCache volume(VolumeName name) {
|
||||
Assert.notNull(name, "'name' must not be null");
|
||||
return new Volume(name);
|
||||
}
|
||||
@@ -119,7 +83,7 @@ public class Cache {
|
||||
* @param source the cache bind mount source
|
||||
* @return a new cache instance
|
||||
*/
|
||||
public static Cache bind(String source) {
|
||||
static LocalCache bind(String source) {
|
||||
Assert.notNull(source, "'source' must not be null");
|
||||
return new Bind(source);
|
||||
}
|
||||
@@ -128,166 +92,11 @@ public class Cache {
|
||||
* Create a new {@code Cache} that uses an image with the provided name.
|
||||
* @param name the cache image name
|
||||
* @return a new cache instance
|
||||
* @since 4.2.0
|
||||
*/
|
||||
public static Cache image(String name) {
|
||||
static ImageCache image(String name) {
|
||||
Assert.notNull(name, "'name' must not be null");
|
||||
return new Image(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null || getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
Cache other = (Cache) obj;
|
||||
return Objects.equals(this.format, other.format);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return ObjectUtils.nullSafeHashCode(this.format);
|
||||
}
|
||||
|
||||
/**
|
||||
* Details of a cache stored in a Docker volume.
|
||||
*/
|
||||
public static class Volume extends Cache {
|
||||
|
||||
private final VolumeName name;
|
||||
|
||||
Volume(VolumeName name) {
|
||||
super(Format.VOLUME);
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name.toString();
|
||||
}
|
||||
|
||||
public VolumeName getVolumeName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null || getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
if (!super.equals(obj)) {
|
||||
return false;
|
||||
}
|
||||
Volume other = (Volume) obj;
|
||||
return Objects.equals(this.name, other.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = super.hashCode();
|
||||
result = 31 * result + ObjectUtils.nullSafeHashCode(this.name);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.format.getDescription() + " '" + this.name + "'";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Details of a cache stored in a bind mount.
|
||||
*/
|
||||
public static class Bind extends Cache {
|
||||
|
||||
private final String source;
|
||||
|
||||
Bind(String source) {
|
||||
super(Format.BIND);
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
public String getSource() {
|
||||
return this.source;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null || getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
if (!super.equals(obj)) {
|
||||
return false;
|
||||
}
|
||||
Bind other = (Bind) obj;
|
||||
return Objects.equals(this.source, other.source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = super.hashCode();
|
||||
result = 31 * result + ObjectUtils.nullSafeHashCode(this.source);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.format.getDescription() + " '" + this.source + "'";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Details of a cache stored in an image.
|
||||
*/
|
||||
public static class Image extends Cache {
|
||||
|
||||
private final String name;
|
||||
|
||||
Image(String name) {
|
||||
super(Format.IMAGE);
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null || getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
if (!super.equals(obj)) {
|
||||
return false;
|
||||
}
|
||||
Image other = (Image) obj;
|
||||
return Objects.equals(this.name, other.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = super.hashCode();
|
||||
result = 31 * result + ObjectUtils.nullSafeHashCode(this.name);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.format.getDescription() + " '" + this.name + "'";
|
||||
}
|
||||
|
||||
return new ImageCache(name);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2012-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.buildpack.platform.build;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Details of a cache stored in an image.
|
||||
*
|
||||
* @author Tim Ysewyn
|
||||
* @author Stephane Nicoll
|
||||
* @since 4.2.0
|
||||
*/
|
||||
public final class ImageCache implements Cache {
|
||||
|
||||
private final String name;
|
||||
|
||||
ImageCache(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null || getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
ImageCache other = (ImageCache) obj;
|
||||
return Objects.equals(this.name, other.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return ObjectUtils.nullSafeHashCode(this.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "image '" + this.name + "'";
|
||||
}
|
||||
|
||||
}
|
||||
+18
-23
@@ -27,7 +27,6 @@ import java.util.function.Consumer;
|
||||
import com.sun.jna.Platform;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.buildpack.platform.build.Cache.Bind;
|
||||
import org.springframework.boot.buildpack.platform.docker.ApiVersion;
|
||||
import org.springframework.boot.buildpack.platform.docker.DockerApi;
|
||||
import org.springframework.boot.buildpack.platform.docker.LogUpdateEvent;
|
||||
@@ -78,13 +77,13 @@ class Lifecycle implements Closeable {
|
||||
|
||||
private final ApiVersion platformVersion;
|
||||
|
||||
private final Cache layers;
|
||||
private final LocalCache layers;
|
||||
|
||||
private final Cache application;
|
||||
private final LocalCache application;
|
||||
|
||||
private final Cache buildCache;
|
||||
|
||||
private final Cache launchCache;
|
||||
private final LocalCache launchCache;
|
||||
|
||||
private final String applicationDirectory;
|
||||
|
||||
@@ -130,7 +129,7 @@ class Lifecycle implements Closeable {
|
||||
return createVolumeCache(request, "build");
|
||||
}
|
||||
|
||||
private Cache getLaunchCache(BuildRequest request) {
|
||||
private LocalCache getLaunchCache(BuildRequest request) {
|
||||
if (request.getLaunchCache() != null) {
|
||||
return request.getLaunchCache();
|
||||
}
|
||||
@@ -215,9 +214,8 @@ class Lifecycle implements Closeable {
|
||||
private Phase analyzePhase() {
|
||||
Phase phase = new Phase("analyzer", isVerboseLogging());
|
||||
configureDaemonAccess(phase);
|
||||
Cache.Image buildCacheImage = this.buildCache.getImage();
|
||||
if (buildCacheImage != null) {
|
||||
phase.withBuildCache(buildCacheImage.getName());
|
||||
if (this.buildCache instanceof ImageCache imageBuildCache) {
|
||||
phase.withBuildCache(imageBuildCache.getName());
|
||||
}
|
||||
phase.withLaunchCache(Directory.LAUNCH_CACHE,
|
||||
Binding.from(getCacheBindingSource(this.launchCache), Directory.LAUNCH_CACHE));
|
||||
@@ -277,44 +275,43 @@ class Lifecycle implements Closeable {
|
||||
return phase;
|
||||
}
|
||||
|
||||
private Cache getLayersBindingSource(BuildRequest request) {
|
||||
private LocalCache getLayersBindingSource(BuildRequest request) {
|
||||
if (request.getBuildWorkspace() != null) {
|
||||
return getBuildWorkspaceBindingSource(request.getBuildWorkspace(), "layers");
|
||||
}
|
||||
return createVolumeCache("pack-layers-");
|
||||
}
|
||||
|
||||
private Cache getApplicationBindingSource(BuildRequest request) {
|
||||
private LocalCache getApplicationBindingSource(BuildRequest request) {
|
||||
if (request.getBuildWorkspace() != null) {
|
||||
return getBuildWorkspaceBindingSource(request.getBuildWorkspace(), "app");
|
||||
}
|
||||
return createVolumeCache("pack-app-");
|
||||
}
|
||||
|
||||
private Cache getBuildWorkspaceBindingSource(Cache buildWorkspace, String suffix) {
|
||||
private LocalCache getBuildWorkspaceBindingSource(LocalCache buildWorkspace, String suffix) {
|
||||
if (buildWorkspace.getVolume() != null) {
|
||||
return Cache.volume(buildWorkspace.getVolume().getName() + "-" + suffix);
|
||||
}
|
||||
|
||||
Bind bind = buildWorkspace.getBind();
|
||||
LocalCache.Bind bind = buildWorkspace.getBind();
|
||||
Assert.state(bind != null, "'bind' must not be null");
|
||||
return Cache.bind(bind.getSource() + "-" + suffix);
|
||||
}
|
||||
|
||||
private String getCacheBindingSource(Cache cache) {
|
||||
private String getCacheBindingSource(LocalCache cache) {
|
||||
if (cache.getVolume() != null) {
|
||||
return cache.getVolume().getName();
|
||||
}
|
||||
Bind bind = cache.getBind();
|
||||
LocalCache.Bind bind = cache.getBind();
|
||||
Assert.state(bind != null, "'bind' must not be null");
|
||||
return bind.getSource();
|
||||
}
|
||||
|
||||
private Cache createVolumeCache(String prefix) {
|
||||
private LocalCache createVolumeCache(String prefix) {
|
||||
return Cache.volume(createRandomVolumeName(prefix));
|
||||
}
|
||||
|
||||
private Cache createVolumeCache(BuildRequest request, String suffix) {
|
||||
private LocalCache createVolumeCache(BuildRequest request, String suffix) {
|
||||
return Cache.volume(
|
||||
VolumeName.basedOn(request.getName(), ImageReference::toLegacyString, "pack-cache-", "." + suffix, 6));
|
||||
}
|
||||
@@ -348,13 +345,11 @@ class Lifecycle implements Closeable {
|
||||
}
|
||||
|
||||
private void configureBuildCache(Phase phase) {
|
||||
Cache.Image image = this.buildCache.getImage();
|
||||
if (image != null) {
|
||||
if (this.buildCache instanceof ImageCache image) {
|
||||
phase.withBuildCache(image.getName());
|
||||
}
|
||||
else {
|
||||
phase.withBuildCache(Directory.CACHE,
|
||||
Binding.from(getCacheBindingSource(this.buildCache), Directory.CACHE));
|
||||
else if (this.buildCache instanceof LocalCache localCache) {
|
||||
phase.withBuildCache(Directory.CACHE, Binding.from(getCacheBindingSource(localCache), Directory.CACHE));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -436,7 +431,7 @@ class Lifecycle implements Closeable {
|
||||
this.docker.volume().delete(name, true);
|
||||
}
|
||||
|
||||
private void deleteBind(Cache.Bind bind) {
|
||||
private void deleteBind(LocalCache.Bind bind) {
|
||||
try {
|
||||
FileSystemUtils.deleteRecursively(Path.of(bind.getSource()));
|
||||
}
|
||||
|
||||
+117
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright 2012-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.buildpack.platform.build;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.buildpack.platform.docker.type.VolumeName;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Details of a local cache stored as a volume or bind mount.
|
||||
*
|
||||
* @author Scott Frederick
|
||||
* @author Stephane Nicoll
|
||||
* @since 4.2.0
|
||||
*/
|
||||
public sealed interface LocalCache extends Cache permits LocalCache.Volume, LocalCache.Bind {
|
||||
|
||||
/**
|
||||
* Details of a cache stored in a Docker volume.
|
||||
*/
|
||||
final class Volume implements LocalCache {
|
||||
|
||||
private final VolumeName name;
|
||||
|
||||
Volume(VolumeName name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name.toString();
|
||||
}
|
||||
|
||||
public VolumeName getVolumeName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null || getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
Volume other = (Volume) obj;
|
||||
return Objects.equals(this.name, other.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return ObjectUtils.nullSafeHashCode(this.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "volume '" + this.name + "'";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Details of a cache stored in a bind mount.
|
||||
*/
|
||||
final class Bind implements LocalCache {
|
||||
|
||||
private final String source;
|
||||
|
||||
Bind(String source) {
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
public String getSource() {
|
||||
return this.source;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null || getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
Bind other = (Bind) obj;
|
||||
return Objects.equals(this.source, other.source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return ObjectUtils.nullSafeHashCode(this.source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "bind mount '" + this.source + "'";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+8
-8
@@ -325,6 +325,14 @@ class BuildRequestTests {
|
||||
assertThat(withCache.getBuildCache()).isEqualTo(Cache.bind("/tmp/build-cache"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void withBuildImageCacheAddsCache() throws IOException {
|
||||
BuildRequest request = BuildRequest.forJarFile(writeTestJarFile("my-app-0.0.1.jar"));
|
||||
BuildRequest withCache = request.withBuildCache(Cache.image("build-cache-image"));
|
||||
assertThat(request.getBuildCache()).isNull();
|
||||
assertThat(withCache.getBuildCache()).isEqualTo(Cache.image("build-cache-image"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("NullAway") // Test null check
|
||||
void withBuildVolumeCacheWhenCacheIsNullThrowsException() throws IOException {
|
||||
@@ -349,14 +357,6 @@ class BuildRequestTests {
|
||||
assertThat(withCache.getLaunchCache()).isEqualTo(Cache.bind("/tmp/launch-cache"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void withLaunchImageCacheThrowsException() throws IOException {
|
||||
BuildRequest request = BuildRequest.forJarFile(writeTestJarFile("my-app-0.0.1.jar"));
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> request.withLaunchCache(Cache.image("launch-cache-image")))
|
||||
.withMessage("Launch cache must not be an image cache");
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("NullAway") // Test null check
|
||||
void withLaunchVolumeCacheWhenCacheIsNullThrowsException() throws IOException {
|
||||
|
||||
Reference in New Issue
Block a user