
io.fabric8.maven.docker.config.BuildImageConfiguration Maven / Gradle / Ivy
package io.fabric8.maven.docker.config;
import java.io.File;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Nonnull;
import org.apache.maven.plugins.annotations.Parameter;
import io.fabric8.maven.docker.util.DeepCopy;
import io.fabric8.maven.docker.util.EnvUtil;
import io.fabric8.maven.docker.util.Logger;
import io.fabric8.maven.docker.util.MojoParameters;
/**
* @author roland
* @since 02.09.14
*/
public class BuildImageConfiguration implements Serializable {
public static final String DEFAULT_FILTER = "${*}";
public static final String DEFAULT_CLEANUP = "try";
/**
* Directory is used as build context.
* If not specified, dockerfile's parent directory is used as build context.
*/
@Parameter
private String contextDir;
/**
* Directory holding an external Dockerfile which is used to build the
* image. This Dockerfile will be enriched by the addition build configuration
*/
@Parameter
@Deprecated
private String dockerFileDir;
/**
* Path to a dockerfile to use.
* Multiple different Dockerfiles can be specified that way. If set overwrites a possibly givem
* dockerFileDir
*/
@Parameter
private String dockerFile;
/**
* Path to a docker archive to load an image instead of building from scratch.
* Note only either dockerFile/dockerFileDir or
* dockerArchive can be used.
*/
@Parameter
private String dockerArchive;
/**
* Pattern for the image name we expect to find in the dockerArchive.
*
* If set, the archive is scanned prior to sending to Docker and checked to
* ensure a matching name is found linked to one of the images in the archive.
* After loading, the image with the matching name will be tagged with the
* image name configured in this project.
*/
@Parameter
private String loadNamePattern;
/**
* How interpolation of a dockerfile should be performed
*/
@Parameter
private String filter;
/**
* Base Image
*/
@Parameter
private String from;
/**
* Extended version for
*/
@Parameter
private Map fromExt;
@Parameter
private List cacheFrom;
@Parameter
private String registry;
@Parameter
private String maintainer;
@Parameter
private String network;
@Parameter
private List ports;
/**
* Policy for pulling the base images
*/
@Parameter
private String imagePullPolicy;
/**
* SHELL excutable with params
*/
@Parameter
private Arguments shell;
/**
* RUN Commands within Build/Image
*/
@Parameter
private List runCmds;
@Parameter
private String cleanup;
@Deprecated
@Parameter
private Boolean nocache;
@Parameter
private Boolean noCache;
@Parameter
private Boolean squash;
@Parameter
private Boolean optimise;
@Parameter
private List volumes;
@Parameter
private List tags;
@Parameter
private BuildXConfiguration buildx;
@Parameter
private Map env;
@Parameter
private Map labels;
@Parameter
private Map args;
@Parameter
private Arguments entryPoint;
@Parameter
@Deprecated
private String command;
@Parameter
private String workdir;
@Parameter
private Arguments cmd;
@Parameter
private String user;
@Parameter
private HealthCheckConfiguration healthCheck;
@Parameter
private AssemblyConfiguration assembly;
@Parameter
private List assemblies;
@Parameter
private Boolean skip;
@Parameter
private Boolean skipPush;
@Parameter
private ArchiveCompression compression = ArchiveCompression.none;
@Parameter
private Map buildOptions;
/**
* Map specifying the create image options to provide to the docker daemon when pulling or importing an image.
*
* These options map to the ones listed as query parameters in the Docker Remote API and are restricted to
* simple options (e.g.: fromImage, fromSrc, platform).
*
* @see Docker Engine API v1.41
*/
@Parameter
private Map createImageOptions;
// Path to Dockerfile to use, initialized lazily ....
private File dockerFileFile, dockerArchiveFile;
public BuildImageConfiguration() {}
public boolean isDockerFileMode() {
return dockerFileFile != null;
}
public String getLoadNamePattern() {
return loadNamePattern;
}
public File getContextDir() {
if (!isDockerFileMode()) {
return null;
}
if (contextDir != null) {
return new File(contextDir);
}
if (getDockerFile().getParentFile() == null) {
return new File("");
}
return getDockerFile().getParentFile();
}
public String getContextDirRaw() {
return contextDir;
}
public File getDockerFile() {
return dockerFileFile;
}
public File getDockerArchive() {
return dockerArchiveFile;
}
public String getDockerFileRaw() {
return dockerFile;
}
public String getDockerArchiveRaw() {
return dockerArchive;
}
public String getDockerFileDirRaw() {
return dockerFileDir;
}
public String getFilter() {
return filter != null ? filter : DEFAULT_FILTER;
}
public String getFilterRaw() {
return filter;
}
public String getFrom() {
if (from == null && getFromExt() != null) {
return getFromExt().get("name");
}
return from;
}
public Map getFromExt() {
return fromExt;
}
public List getCacheFrom() {
return cacheFrom;
}
public String getNetwork() {
return network;
}
public String getRegistry() {
return registry;
}
public String getMaintainer() {
return maintainer;
}
public String getWorkdir() {
return workdir;
}
/**
* @deprecated Use {@link #getAllAssemblyConfigurations()} instead.
*/
@Deprecated
public AssemblyConfiguration getAssemblyConfiguration() {
return assembly;
}
/**
* Use {@link #getAllAssemblyConfigurations()} unless you specifically want the configuration defined only by assemblies
.
*/
@Nonnull
public List getAssembliesConfiguration() {
final List assemblyConfigurations = new ArrayList<>();
if (assemblies != null) {
for (AssemblyConfiguration config : assemblies) {
if (config != null) {
assemblyConfigurations.add(config);
}
}
}
return assemblyConfigurations;
}
@Nonnull
public List getAllAssemblyConfigurations() {
final List assemblyConfigurations = getAssembliesConfiguration();
if (assembly != null) {
assemblyConfigurations.add(assembly);
}
return assemblyConfigurations;
}
@Nonnull
public List getPorts() {
return EnvUtil.removeEmptyEntries(ports);
}
public String getImagePullPolicy() {
return imagePullPolicy;
}
@Nonnull
public List getVolumes() {
return EnvUtil.removeEmptyEntries(volumes);
}
@Nonnull
public List getTags() {
return EnvUtil.removeEmptyEntries(tags);
}
public Map getEnv() {
return env;
}
public Map getLabels() {
return labels;
}
public Arguments getCmd() {
return cmd;
}
@Deprecated
public String getCommand() {
return command;
}
public String getCleanup() {
return cleanup;
}
public CleanupMode cleanupMode() {
return CleanupMode.parse(cleanup != null ? cleanup : DEFAULT_CLEANUP);
}
public boolean noCache() {
if (noCache != null) {
return noCache;
}
if (nocache != null) {
return nocache;
}
return false;
}
public boolean squash() {
if (squash != null) {
return squash;
}
return false;
}
public boolean optimise() {
return optimise != null ? optimise : false;
}
public boolean skip() {
return skip != null ? skip : false;
}
public boolean skipPush() {
return skipPush != null ? skipPush : false;
}
public Boolean getNoCache() {
return noCache != null ? noCache : nocache;
}
public Boolean getSquash() {
return squash != null ? squash : false;
}
public Boolean getOptimise() {
return optimise;
}
public Boolean getSkip() {
return skip;
}
public Boolean getSkipPush() {
return skipPush;
}
public ArchiveCompression getCompression() {
return compression;
}
public Map getBuildOptions() {
return buildOptions;
}
public Map getCreateImageOptions() {
return createImageOptions;
}
public Arguments getEntryPoint() {
return entryPoint;
}
public Arguments getShell() {
return shell;
}
@Nonnull
public List getRunCmds() {
return EnvUtil.removeEmptyEntries(runCmds);
}
public String getUser() {
return user;
}
public HealthCheckConfiguration getHealthCheck() {
return healthCheck;
}
public Map getArgs() {
return args;
}
public BuildXConfiguration getBuildX() {
return buildx;
}
public boolean isBuildX() {
return buildx!=null && buildx.isBuildX();
}
public File getAbsoluteContextDirPath(MojoParameters mojoParams) {
return EnvUtil.prepareAbsoluteSourceDirPath(mojoParams, getContextDir().getPath());
}
public File getAbsoluteDockerFilePath(MojoParameters mojoParams) {
return EnvUtil.prepareAbsoluteSourceDirPath(mojoParams, getDockerFile().getPath());
}
public File getAbsoluteDockerTarPath(MojoParameters mojoParams) {
return EnvUtil.prepareAbsoluteSourceDirPath(mojoParams, getDockerArchive().getPath());
}
public String getDockerfileName() {
if (isDockerFileMode()) {
return getDockerFile().getName();
} else {
return null;
}
}
public void initTags(ConfigHelper.NameFormatter nameFormatter) {
if (tags != null) {
tags = tags.stream().map(nameFormatter::format).collect(Collectors.toList());
}
}
public static class Builder {
private final BuildImageConfiguration config;
public Builder() {
this(null);
}
public Builder(BuildImageConfiguration that) {
if (that == null) {
this.config = new BuildImageConfiguration();
} else {
this.config = DeepCopy.copy(that);
}
}
public Builder contextDir(String dir) {
config.contextDir = dir;
return this;
}
public Builder dockerFileDir(String dir) {
config.dockerFileDir = dir;
return this;
}
public Builder dockerFile(String file) {
config.dockerFile = file;
return this;
}
public Builder dockerArchive(String archive) {
config.dockerArchive = archive;
return this;
}
public Builder loadNamePattern(String archiveEntryRepoTagPattern) {
config.loadNamePattern = archiveEntryRepoTagPattern;
return this;
}
public Builder filter(String filter) {
config.filter = filter;
return this;
}
public Builder from(String from) {
config.from = from;
return this;
}
public Builder fromExt(Map fromExt) {
config.fromExt = fromExt;
return this;
}
public Builder cacheFrom(String cacheFrom, String ...more) {
if (more == null || more.length == 0) {
return cacheFrom(Collections.singletonList(cacheFrom));
}
List list = new ArrayList<>();
list.add(cacheFrom);
list.addAll(Arrays.asList(more));
return cacheFrom(list);
}
public Builder cacheFrom(Collection cacheFrom) {
config.cacheFrom = cacheFrom != null ? new ArrayList<>(cacheFrom) : null;
return this;
}
public Builder registry(String registry) {
config.registry = registry;
return this;
}
public Builder maintainer(String maintainer) {
config.maintainer = maintainer;
return this;
}
public Builder network(String network) {
config.network = network;
return this;
}
public Builder workdir(String workdir) {
config.workdir = workdir;
return this;
}
public Builder assembly(AssemblyConfiguration assembly) {
config.assembly = assembly;
return this;
}
public Builder assemblies(List assemblies) {
config.assemblies = assemblies;
return this;
}
public Builder ports(List ports) {
config.ports = ports;
return this;
}
public Builder imagePullPolicy(String imagePullPolicy) {
config.imagePullPolicy = imagePullPolicy;
return this;
}
public Builder shell(Arguments shell) {
if(shell != null) {
config.shell = shell;
}
return this;
}
public Builder runCmds(List theCmds) {
if (theCmds == null) {
config.runCmds = new ArrayList<>();
} else {
config.runCmds = theCmds;
}
return this;
}
public Builder volumes(List volumes) {
config.volumes = volumes;
return this;
}
public Builder tags(List tags) {
config.tags = tags;
return this;
}
public Builder buildx(BuildXConfiguration buildx) {
config.buildx = buildx;
return this;
}
public Builder env(Map env) {
config.env = env;
return this;
}
public Builder args(Map args) {
config.args = args;
return this;
}
public Builder labels(Map labels) {
config.labels = labels;
return this;
}
public Builder cmd(Arguments cmd) {
if (cmd != null) {
config.cmd = cmd;
}
return this;
}
public Builder cleanup(String cleanup) {
config.cleanup = cleanup;
return this;
}
public Builder compression(String compression) {
if (compression == null) {
config.compression = ArchiveCompression.none;
} else {
config.compression = ArchiveCompression.valueOf(compression);
}
return this;
}
public Builder noCache(Boolean noCache) {
config.noCache = noCache;
return this;
}
public Builder squash(Boolean squash) {
config.squash = squash;
return this;
}
public Builder optimise(Boolean optimise) {
config.optimise = optimise;
return this;
}
public Builder entryPoint(Arguments entryPoint) {
if (entryPoint != null) {
config.entryPoint = entryPoint;
}
return this;
}
public Builder user(String user) {
config.user = user;
return this;
}
public Builder healthCheck(HealthCheckConfiguration healthCheck) {
config.healthCheck = healthCheck;
return this;
}
public Builder skip(Boolean skip) {
config.skip = skip;
return this;
}
public Builder skipPush(Boolean skipPush) {
config.skipPush = skipPush;
return this;
}
public Builder buildOptions(Map buildOptions) {
config.buildOptions = buildOptions;
return this;
}
public Builder createImageOptions(Map createImageOptions) {
config.createImageOptions = createImageOptions;
return this;
}
public BuildImageConfiguration build() {
return config;
}
}
public String initAndValidate(Logger log) throws IllegalArgumentException {
if (entryPoint != null) {
entryPoint.validate();
}
if (cmd != null) {
cmd.validate();
}
if (healthCheck != null) {
healthCheck.validate();
}
ensureUniqueAssemblyNames(log);
if (command != null) {
log.warn(" in the configuration is deprecated and will be be removed soon");
log.warn("Please use with nested or sections instead.");
log.warn("");
log.warn("More on this is explained in the user manual: ");
log.warn("https://github.com/fabric8io/docker-maven-plugin/blob/master/doc/manual.md#start-up-arguments");
log.warn("");
log.warn("Migration is trivial, see changelog to version 0.12.0 -->");
log.warn("https://github.com/fabric8io/docker-maven-plugin/blob/master/doc/changelog.md");
log.warn("");
log.warn("For now, the command is automatically translated for you to the shell form:");
log.warn(" %s ", command);
}
initDockerFileFile(log);
if (cacheFrom != null && !cacheFrom.isEmpty()) {
// cachefrom query param was introduced in v1.25
return "1.25";
} else if (healthCheck != null) {
// HEALTHCHECK support added later
return "1.24";
} else if (args != null) {
// ARG support came in later
return "1.21";
} else {
return null;
}
}
private void ensureUniqueAssemblyNames(Logger log) {
List assemblyConfigurations = getAllAssemblyConfigurations();
Set assemblyNames = new HashSet<>();
for (AssemblyConfiguration config : assemblyConfigurations) {
String assemblyName = config.getName();
boolean wasElementAbsent = assemblyNames.add(assemblyName);
if (!wasElementAbsent) {
log.error("Multiple assemblies use the name \"%s\". Please assign each assembly a unique name.", assemblyName);
throw new IllegalArgumentException("Assembly names must be unique");
}
}
}
// Initialize the dockerfile location and the build mode
private void initDockerFileFile(Logger log) {
// can't have dockerFile/dockerFileDir and dockerArchive
if ((dockerFile != null || dockerFileDir != null) && dockerArchive != null) {
throw new IllegalArgumentException("Both () and are set. " +
"Only one of them can be specified.");
}
dockerFileFile = findDockerFileFile(log);
if (dockerArchive != null) {
dockerArchiveFile = new File(dockerArchive);
}
}
private File findDockerFileFile(Logger log) {
if(dockerFileDir != null && contextDir != null) {
log.warn("Both contextDir (%s) and deprecated dockerFileDir (%s) are configured. Using contextDir.", contextDir, dockerFileDir);
}
if (dockerFile != null) {
File dFile = new File(dockerFile);
if (dockerFileDir == null && contextDir == null) {
return dFile;
}
if(contextDir != null) {
if (dFile.isAbsolute()) {
return dFile;
}
return new File(contextDir, dockerFile);
}
if (dFile.isAbsolute()) {
throw new IllegalArgumentException(" can not be absolute path if also set.");
}
log.warn("dockerFileDir parameter is deprecated, please migrate to contextDir");
return new File(dockerFileDir, dockerFile);
}
if (contextDir != null) {
return new File(contextDir, "Dockerfile");
}
if (dockerFileDir != null) {
return new File(dockerFileDir, "Dockerfile");
}
// TODO: Remove the following deprecated handling section
if (dockerArchive == null) {
Optional deprecatedDockerFileDir =
getAllAssemblyConfigurations().stream()
.map(AssemblyConfiguration::getDockerFileDir)
.filter(Objects::nonNull)
.findFirst();
if (deprecatedDockerFileDir.isPresent()) {
log.warn(" in the section of a configuration is deprecated");
log.warn("Please use or directly within the configuration instead");
return new File(deprecatedDockerFileDir.get(),"Dockerfile");
}
}
// No dockerfile mode
return null;
}
}