All Downloads are FREE. Search and download functionalities are using the official Maven repository.

nl.lexemmens.podman.config.image.AbstractImageBuildConfiguration Maven / Gradle / Ivy

package nl.lexemmens.podman.config.image;

import nl.lexemmens.podman.enumeration.ContainerFormat;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static nl.lexemmens.podman.enumeration.ContainerFormat.OCI;

/**
 * Contains the shared configuration used by both single image configurations as well
 * as batch configurations.
 */
public abstract class AbstractImageBuildConfiguration {

    /**
     * This is the regular expression to be used to determine a multistage Containerfile. For now we only support
     * named stages.
     */
    protected static final Pattern MULTISTAGE_CONTAINERFILE_REGEX = Pattern.compile(
            "(FROM\\s[a-zA-Z0-9./:_\\-${}]{0,255}\\s)([ASas]{2}\\s)([a-zA-Z0-9./:_\\-]{1,128})"
    );

    /**
     * The default name of the Containerfile to build.
     */
    protected static final String DEFAULT_CONTAINERFILE = "Containerfile";

    /**
     * Directory containing the Containerfile
     */
    @Parameter
    protected File containerFileDir;

    /**
     * Configures whether caching should be used to build images.
     */
    @Parameter
    protected boolean noCache;

    /**
     * Configures whether from-images should be pulled so that the image will
     * always be build on the latest base.
     */
    @Parameter
    protected Boolean pull;

    /**
     * Configures whether from-images should always be pulled from the first registry it is found in.
     * 

* From Podman docs: * Pull the image from the first registry it is found in as listed in registries.conf. * Raise an error if not found in the registries, even if the image is present locally. * * @see --pull-always on docs.podman.io */ @Parameter protected Boolean pullAlways; /** * Array consisting of one or more tags to attach to a container image. * Tags will be appended at the end of the image name */ @Parameter protected String[] tags; /** * Name of the Containerfile to use. Defaults to Containerfile */ @Parameter protected String containerFile; /** * Collection of build arguments to use during Podman build */ @Parameter private Map args; /** * Specify any labels to be applied to the image */ @Parameter protected Map labels; /** * Specifies whether a version of the container image should be based on the version of this Maven project. Defaults to true. * When set to false, 'podman.image.tag.version' must be specified. */ @Parameter protected boolean tagWithMavenProjectVersion; /** * The Maven project version to use (only when useMavenProjectVersion is set to true) */ protected String mavenProjectVersion; /** * Specified whether a container image should *ALSO* be tagged 'latest'. This defaults to false. */ @Parameter protected boolean createLatestTag; /** * Specifies the format of the Container image to use */ @Parameter protected ContainerFormat format; /** * Squash all of the image’s new layers into a single new layer; any preexisting layers are not squashed. *

* * @see "http://docs.podman.io/en/latest/markdown/podman-build.1.html" */ @Parameter protected Boolean squash; /** * Squash all of the new image’s layers (including those inherited from a base image) into a single new layer. *

* * @see "http://docs.podman.io/en/latest/markdown/podman-build.1.html" */ @Parameter protected Boolean squashAll; /** * Cache intermediate images during the build process (Default is true). *

* Note: You can also override the default value of layers by setting the BUILDAH_LAYERS environment variable. * export BUILDAH_LAYERS=true * * @see "http://docs.podman.io/en/latest/markdown/podman-build.1.html" */ @Parameter protected Boolean layers; /** * Specify the resulting image platform by being passed to the "--platform" option of podman. *

* * @see "https://docs.podman.io/en/latest/markdown/podman-build.1.html" */ @Parameter protected String platform; /** * Specify the final target stage to build. It is passed to the "--target" option of podman. *

* * @see "https://docs.podman.io/en/latest/markdown/podman-build.1.html" */ @Parameter protected String targetStage; /** * Will be set when this class is validated using the #initAndValidate() method */ protected File outputDirectory; /** * Will be set to true when the Containerfile is a multistage Containerfile. */ private boolean isMultistageContainerFile; /** * Represents the validity of this configuration */ protected boolean valid; /** * Returns which value should be used for the --no-cache property * * @return When set to true, podman will run with --no-cache=true */ public boolean isNoCache() { return noCache; } /** * Returns if the --pull property should be used * * @return When set to true, podman will build with --pull */ public Optional getPull() { return Optional.ofNullable(pull); } /** * Returns if the --pull-always property should be used * * @return When set to true, podman will build with --pull-always */ public Optional getPullAlways() { return Optional.ofNullable(pullAlways); } public void validate(MavenProject project) { if (containerFile == null) { containerFile = DEFAULT_CONTAINERFILE; } if (labels == null) { labels = new HashMap<>(); } if (format == null) { format = OCI; } this.mavenProjectVersion = project.getVersion(); this.outputDirectory = new File(project.getBuild().getDirectory()); if (containerFileDir == null) { containerFileDir = project.getBasedir(); } if(args == null) { args = new HashMap<>(); } } /** * Returns the tags to be applied for this image * * @return The tags to be applied */ public List getAllTags() { List allTags = new ArrayList<>(); if (tags != null) { allTags.addAll(Arrays.asList(tags)); } if (createLatestTag) { allTags.add("latest"); } if (tagWithMavenProjectVersion) { allTags.add(mavenProjectVersion); } return allTags; } /** * Returns the path to the target Containerfile * * @return Returns a path to the target Containerfile */ public Path getTargetContainerFile() { return Paths.get(outputDirectory.toURI()).resolve(containerFile); } /** *

* Returns the labels to be applied to the container image *

*

* All specified labels will be added to the Containerfile after filtering. *

* * @return All labels to be added to the Containerfile */ public Map getLabels() { return labels; } /** * Returns the project's output directory * * @return The configured output directory */ public File getOutputDirectory() { return outputDirectory; } /** * Returns the format for the built image's manifest and configuration data. * * @return The format for the built image's manifest and configuration data */ public ContainerFormat getFormat() { return format; } /** * Returns true when the Containerfile is a multistage Containerfile * * @return true when a multistage Containerfile is used */ public boolean isMultistageContainerFile() { return isMultistageContainerFile; } /** * Returns the Pattern that is used to determine if a line matches a multi-stage Containerfile * * @return The pattern to determine if a line matches the expected pattern for a multi-stage Containerfile. */ public Pattern getMultistageContainerfilePattern() { return MULTISTAGE_CONTAINERFILE_REGEX; } /** * Returns true when all of the image’s new layers should be squashed into a single new layer; any * preexisting layers are not squashed. * * @return true when all of the images's new layers should be squashed into a new layer. False otherwise. */ public Boolean getSquash() { return squash; } /** * Returns true when all of the image’s new layers, including those inherited from a base image, into a single new layer. * * @return true when all of the images's new layers should be squashed into a new layer. False otherwise. */ public Boolean getSquashAll() { return squashAll; } /** * Returns true if intermediate layers should be cached during a Podman build. * * @return true, when intermediate layers should be cached. False otherwise. */ public Boolean getLayers() { return layers; } /** * Returns the platform that Podman should be told to build for. * * @return When set, a string in the format of GO OS/GO ARCH (because GO is the language of Podman) for example: linux/arm64 */ public Optional getPlatform(){ return Optional.ofNullable(platform); } /** * Returns the final target stage to build. * * @return if set, the final target stage to build defined in Containerfile. */ public Optional getTargetStage(){ return Optional.ofNullable(targetStage); } /** * Returns a boolean indicating whether this configuration is valid * * @return true if this configuration is valid. False otherwise. */ public boolean isValid() { return valid; } /** * Returns true when a latest tag should be created * * @return true if an image should be tagged 'latest' */ public boolean isCreateLatestTag() { return createLatestTag; } protected boolean isContainerFileEmpty(Log log, Path fullContainerFilePath) throws MojoExecutionException { try { return 0 == Files.size(fullContainerFilePath); } catch (IOException e) { String msg = "Unable to determine if Containerfile is empty."; log.error(msg, e); throw new MojoExecutionException(msg, e); } } protected void determineBuildStages(Log log, Path fullContainerFilePath) throws MojoExecutionException { boolean foundTargetStage = false; try (Stream containerFileStream = Files.lines(fullContainerFilePath)) { List content = containerFileStream.filter(c -> !c.matches("^\\s*#.*")) .collect(Collectors.toList()); for (String line : content) { Matcher matcher = MULTISTAGE_CONTAINERFILE_REGEX.matcher(line); if (matcher.find()) { isMultistageContainerFile = true; String stage = matcher.group(3); if (Objects.equals(stage, targetStage)) { foundTargetStage = true; } log.debug("Found a stage named: " + stage); } } } catch (IOException e) { String msg = "Unable to determine if Containerfile is a multistage Containerfile."; log.error(msg, e); throw new MojoExecutionException(msg, e); } if (targetStage != null && isMultistageContainerFile && !foundTargetStage) { String msg = String.format("Target stage '%s' was not found in the given Containerfile.", targetStage); log.error(msg); throw new MojoExecutionException(msg); } } /** * Configures whether to cache intermediate images during the build process. * * @param layers The value to set */ public void setLayers(Boolean layers) { this.layers = layers; } /** * Used to set the platform to be passed to Podman when building the image. * * @param platform String in the format of GO OS/GO ARCH (because GO is the language of Podman) for example: linux/arm64 */ public void setPlatform(String platform){ this.platform = platform; } /** * Sets the noCache option. Allows configuring whether caching should be used * to cache images * * @param noCache Sets the noCache option on and off. */ public void setNoCache(boolean noCache) { this.noCache = noCache; } /** * Configures whether from-images should be pulled so that the image will * always be build on the latest base. * * @param pull The value to set */ public void setPull(Boolean pull) { this.pull = pull; } /** * Configures whether from-images should always be pulled from the first registry it is found in. * * @param pullAlways The value to set */ public void setPullAlways(Boolean pullAlways) { this.pullAlways = pullAlways; } /** * Configures whether to squash all newly created layers into one layer. * * @param squash The value to set */ public void setSquash(Boolean squash) { this.squash = squash; } /** * Configures whether to squash all layers into one layer, this includes the base layer(s). * * @param squashAll The value to set */ public void setSquashAll(Boolean squashAll) { this.squashAll = squashAll; } /** * Sets the tags that should be used for this image * * @param tags The tags this image should receive */ public void setTags(String[] tags) { this.tags = tags; } /** * Sets the name of the Containerfile (defaults to Containerfile) * * @param containerFile The name of the Containerfile to set */ public void setContainerFile(String containerFile) { this.containerFile = containerFile; } /** * Sets the labels to add to the container image. * * @param labels The labels to set. */ public void setLabels(Map labels) { this.labels = labels; } /** * Specifies whether the image should be tagged with the Maven Project version * * @param tagWithMavenProjectVersion whether the image should be tagged with the Maven project version */ public void setTagWithMavenProjectVersion(boolean tagWithMavenProjectVersion) { this.tagWithMavenProjectVersion = tagWithMavenProjectVersion; } /** * Specifies whether a latest tag should be created * * @param createLatestTag If true, the image will receive the tag 'latest' */ public void setCreateLatestTag(boolean createLatestTag) { this.createLatestTag = createLatestTag; } /** * The format of the container image to use. * * @param format The format to use */ public void setFormat(ContainerFormat format) { this.format = format; } /** * Sets the directory where the Containerfile is located (copied from BatchImageBuildCOnfiguration). * * @param containerFileDir The directory to set */ public void setContainerFileDir(File containerFileDir) { this.containerFileDir = containerFileDir; } /** * Sets the final target stage to build. * * @param targetStage The final target stage to build. */ public void setTargetStage(String targetStage) { this.targetStage = targetStage; } /** * Retrieves a collection of build arguments to provide to podman build using --build-arg * * @return A collection of build arguments to provide to podman build */ public Map getArgs() { return args; } /** * The build arguments to set for use during Podman build * * @param args The arguments to set */ public void setArgs(Map args) { this.args = args; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy