Support multiple Docker Compose files
Closes gh-41691
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
* Copyright 2012-2024 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.
|
||||
@@ -94,8 +94,10 @@ class DockerCli {
|
||||
case DOCKER_COMPOSE -> {
|
||||
List<String> result = new ArrayList<>(this.dockerCommands.get(type));
|
||||
if (this.composeFile != null) {
|
||||
result.add("--file");
|
||||
result.add(this.composeFile.toString());
|
||||
for (File file : this.composeFile.getFiles()) {
|
||||
result.add("--file");
|
||||
result.add(file.getPath());
|
||||
}
|
||||
}
|
||||
result.add("--ansi");
|
||||
result.add("never");
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
* Copyright 2012-2024 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.
|
||||
@@ -21,7 +21,10 @@ import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -33,6 +36,7 @@ import org.springframework.util.Assert;
|
||||
* @author Phillip Webb
|
||||
* @since 3.1.0
|
||||
* @see #of(File)
|
||||
* @see #of(Collection)
|
||||
* @see #find(File)
|
||||
*/
|
||||
public final class DockerComposeFile {
|
||||
@@ -40,17 +44,31 @@ public final class DockerComposeFile {
|
||||
private static final List<String> SEARCH_ORDER = List.of("compose.yaml", "compose.yml", "docker-compose.yaml",
|
||||
"docker-compose.yml");
|
||||
|
||||
private final File file;
|
||||
private final List<File> files;
|
||||
|
||||
private DockerComposeFile(File file) {
|
||||
private DockerComposeFile(List<File> files) {
|
||||
Assert.state(!files.isEmpty(), "Files must not be empty");
|
||||
this.files = files.stream().map(DockerComposeFile::toCanonicalFile).toList();
|
||||
}
|
||||
|
||||
private static File toCanonicalFile(File file) {
|
||||
try {
|
||||
this.file = file.getCanonicalFile();
|
||||
return file.getCanonicalFile();
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new UncheckedIOException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the source docker compose files.
|
||||
* @return the source docker compose files
|
||||
* @since 3.4.0
|
||||
*/
|
||||
public List<File> getFiles() {
|
||||
return this.files;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
@@ -60,17 +78,20 @@ public final class DockerComposeFile {
|
||||
return false;
|
||||
}
|
||||
DockerComposeFile other = (DockerComposeFile) obj;
|
||||
return this.file.equals(other.file);
|
||||
return this.files.equals(other.files);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.file.hashCode();
|
||||
return this.files.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.file.toString();
|
||||
if (this.files.size() == 1) {
|
||||
return this.files.get(0).getPath();
|
||||
}
|
||||
return this.files.stream().map(File::toString).collect(Collectors.joining(", "));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -111,7 +132,23 @@ public final class DockerComposeFile {
|
||||
Assert.notNull(file, "File must not be null");
|
||||
Assert.isTrue(file.exists(), () -> "Docker Compose file '%s' does not exist".formatted(file));
|
||||
Assert.isTrue(file.isFile(), () -> "Docker compose file '%s' is not a file".formatted(file));
|
||||
return new DockerComposeFile(file);
|
||||
return new DockerComposeFile(Collections.singletonList(file));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link DockerComposeFile} for the given {@link File files}.
|
||||
* @param files the source files
|
||||
* @return the docker compose file
|
||||
* @since 3.4.0
|
||||
*/
|
||||
public static DockerComposeFile of(Collection<? extends File> files) {
|
||||
Assert.notNull(files, "Files must not be null");
|
||||
for (File file : files) {
|
||||
Assert.notNull(file, "File must not be null");
|
||||
Assert.isTrue(file.exists(), () -> "Docker Compose file '%s' does not exist".formatted(file));
|
||||
Assert.isTrue(file.isFile(), () -> "Docker compose file '%s' is not a file".formatted(file));
|
||||
}
|
||||
return new DockerComposeFile(List.copyOf(files));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
* Copyright 2012-2024 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.
|
||||
@@ -31,7 +31,7 @@ public record DockerComposeOrigin(DockerComposeFile composeFile, String serviceN
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Docker compose service '%s' defined in '%s'".formatted(this.serviceName,
|
||||
return "Docker compose service '%s' defined in %s".formatted(this.serviceName,
|
||||
(this.composeFile != null) ? this.composeFile : "default compose file");
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.event.SimpleApplicationEventMulticaster;
|
||||
import org.springframework.core.log.LogMessage;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
* Manages the lifecycle for docker compose services.
|
||||
@@ -110,7 +111,7 @@ class DockerComposeLifecycleManager {
|
||||
Set<String> activeProfiles = this.properties.getProfiles().getActive();
|
||||
DockerCompose dockerCompose = getDockerCompose(composeFile, activeProfiles);
|
||||
if (!dockerCompose.hasDefinedServices()) {
|
||||
logger.warn(LogMessage.format("No services defined in Docker Compose file '%s' with active profiles %s",
|
||||
logger.warn(LogMessage.format("No services defined in Docker Compose file %s with active profiles %s",
|
||||
composeFile, activeProfiles));
|
||||
return;
|
||||
}
|
||||
@@ -145,11 +146,16 @@ class DockerComposeLifecycleManager {
|
||||
}
|
||||
|
||||
protected DockerComposeFile getComposeFile() {
|
||||
DockerComposeFile composeFile = (this.properties.getFile() != null)
|
||||
? DockerComposeFile.of(this.properties.getFile()) : DockerComposeFile.find(this.workingDirectory);
|
||||
DockerComposeFile composeFile = (CollectionUtils.isEmpty(this.properties.getFile()))
|
||||
? DockerComposeFile.find(this.workingDirectory) : DockerComposeFile.of(this.properties.getFile());
|
||||
Assert.state(composeFile != null, () -> "No Docker Compose file found in directory '%s'".formatted(
|
||||
((this.workingDirectory != null) ? this.workingDirectory : new File(".")).toPath().toAbsolutePath()));
|
||||
logger.info(LogMessage.format("Using Docker Compose file '%s'", composeFile));
|
||||
if (composeFile.getFiles().size() == 1) {
|
||||
logger.info(LogMessage.format("Using Docker Compose file %s", composeFile.getFiles().get(0)));
|
||||
}
|
||||
else {
|
||||
logger.info(LogMessage.format("Using Docker Compose files %s", composeFile.toString()));
|
||||
}
|
||||
return composeFile;
|
||||
}
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ public class DockerComposeProperties {
|
||||
/**
|
||||
* Path to a specific docker compose configuration file.
|
||||
*/
|
||||
private File file;
|
||||
private final List<File> file = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Docker compose lifecycle management.
|
||||
@@ -88,14 +88,10 @@ public class DockerComposeProperties {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public File getFile() {
|
||||
public List<File> getFile() {
|
||||
return this.file;
|
||||
}
|
||||
|
||||
public void setFile(File file) {
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
public LifecycleManagement getLifecycleManagement() {
|
||||
return this.lifecycleManagement;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user