Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.bmuschko.gradle.docker.tasks.image.Dockerfile.groovy Maven / Gradle / Ivy
Go to download
Gradle plugin for managing Docker images and containers.
/*
* Copyright 2014 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
*
* http://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 com.bmuschko.gradle.docker.tasks.image
import groovy.transform.CompileStatic
import groovy.transform.TypeCheckingMode
import org.gradle.api.DefaultTask
import org.gradle.api.Transformer
import org.gradle.api.file.Directory
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.RegularFile
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.ListProperty
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.CacheableTask
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.Nested
import org.gradle.api.tasks.Optional
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.PathSensitive
import org.gradle.api.tasks.PathSensitivity
import org.gradle.api.tasks.TaskAction
import javax.annotation.Nullable
@CacheableTask
@CompileStatic
class Dockerfile extends DefaultTask {
private final ListProperty instructions
@OutputFile
@PathSensitive(PathSensitivity.RELATIVE)
final RegularFileProperty destFile
Dockerfile() {
instructions = project.objects.listProperty(Instruction)
instructions.set([])
destFile = newOutputFile()
destFile.set(project.layout.buildDirectory.file('docker/Dockerfile'))
}
@Nested
ListProperty getInstructions() {
instructions
}
/**
* Returns a provider representing the destination directory containing the Dockerfile.
*
* @return The destination directory containing the Dockerfile
* @since 4.4.0
*/
@Internal
Provider getDestDir() {
destFile.flatMap(new Transformer, RegularFile>() {
@Override
Provider transform(RegularFile f) {
DirectoryProperty destDir = project.objects.directoryProperty()
destDir.set(f.asFile.parentFile)
destDir
}
})
}
@TaskAction
void create() {
verifyValidInstructions()
destFile.get().asFile.withWriter { out ->
instructions.get().forEach() { Instruction instruction ->
String instructionText = instruction.getText()
if (instructionText) {
out.println instructionText
}
}
}
}
@CompileStatic(TypeCheckingMode.SKIP)
private void verifyValidInstructions() {
List allInstructions = instructions.get().collect()
// Comments are not relevant for validating instruction order
allInstructions.removeAll { it.text?.startsWith(CommentInstruction.KEYWORD) }
if (allInstructions.empty) {
throw new IllegalStateException('Please specify instructions for your Dockerfile')
}
def fromPos = allInstructions.findIndexOf { it.keyword == FromInstruction.KEYWORD }
def othersPos = allInstructions.findIndexOf { it.keyword != ArgInstruction.KEYWORD && it.keyword != FromInstruction.KEYWORD }
if (fromPos < 0 || (othersPos >= 0 && fromPos > othersPos)) {
throw new IllegalStateException("The first instruction of a Dockerfile has to be $FromInstruction.KEYWORD (or $ArgInstruction.KEYWORD for Docker later than 17.05)")
}
}
/**
* Adds instructions to the Dockerfile from a template file. The template file can have any name.
*
* @param template The template file
* @see #instructionsFromTemplate(String)
* @see #instructionsFromTemplate(Provider)
*/
void instructionsFromTemplate(java.io.File template) {
if (!template.exists()) {
throw new FileNotFoundException("docker template file not found at location : ${template.getAbsolutePath()}")
}
template.readLines().findAll { it.length() > 0 } each { String instruction ->
instructions.add(new GenericInstruction(instruction))
}
}
/**
* Adds instructions to the Dockerfile from a template file. The path can be relative to the project root directory or absolute.
*
* @param templatePath The path to the template file
* @see #instructionsFromTemplate(java.io.File)
* @see #instructionsFromTemplate(Provider)
*/
void instructionsFromTemplate(String templatePath) {
instructionsFromTemplate(project.file(templatePath))
}
/**
* Adds instructions to the Dockerfile from a template file. Currently, the provider is evaluated as soon as the method is called
* which means that the provider is not evaluated lazily. This behavior might change in the future.
*
* @param provider The provider of the template file
* @see #instructionsFromTemplate(java.io.File)
* @see #instructionsFromTemplate(String)
* @since 4.0.0
*/
void instructionsFromTemplate(Provider provider) {
instructionsFromTemplate(provider.get().asFile)
}
/**
* Adds a full instruction as String.
*
* Example in Groovy DSL:
*
*
* task createDockerfile(type: Dockerfile) {
* instruction('FROM ubuntu:14.04')
* instruction('LABEL [email protected] ')
* }
*
*
* @param instruction Instruction as String
* @see #instruction(Provider)
*/
void instruction(String instruction) {
instructions.add(new GenericInstruction(instruction))
}
/**
* Adds a full instruction as Provider.
*
* Example in Groovy DSL:
*
*
* task createDockerfile(type: Dockerfile) {
* instruction(project.provider(new Callable() {
* @Override
* String call() throws Exception {
* 'FROM ubuntu:14.04'
* }
* }))
* }
*
*
* @param provider Instruction as Provider
* @see #instruction(String)
* @since 4.0.0
*/
void instruction(Provider provider) {
instructions.add(new GenericInstruction(provider))
}
/**
* The FROM instruction sets the Base Image for
* subsequent instructions.
*
* Example in Groovy DSL:
*
*
* task createDockerfile(type: Dockerfile) {
* from('ubuntu:14.04')
* }
*
*
* @param image Base image name
* @param stageName stage name in case of multi-stage builds (default null)
* @see #from(Provider)
*/
void from(String image, String stageName = null) {
instructions.add(new FromInstruction(image, stageName))
}
/**
* A FROM instruction as Provider.
*
* Example in Groovy DSL:
*
*
* task createDockerfile(type: Dockerfile) {
* from(project.provider(new Callable() {
* @Override
* Dockerfile.From call() throws Exception {
* new Dockerfile.From('ubuntu:14.04')
* }
* }))
* }
*
*
* @param provider From information as Provider
* @see #from(String, String)
* @since 4.0.0
*/
void from(Provider provider) {
instructions.add(new FromInstruction(provider))
}
/**
* The ARG instruction defines a variable that
* users can pass at build-time to the builder.
*
* Example in Groovy DSL:
*
*
* task createDockerfile(type: Dockerfile) {
* arg('user1=someuser')
* }
*
*
* @param arg Argument to pass, possibly with default value.
* @see #arg(Provider)
*/
void arg(String arg) {
instructions.add(new ArgInstruction(arg))
}
/**
* A ARG instruction as Provider.
*
* Example in Groovy DSL:
*
*
* task createDockerfile(type: Dockerfile) {
* arg(project.provider(new Callable() {
* @Override
* String call() throws Exception {
* 'user1=someuser'
* }
* }))
* }
*
*
* @param provider Argument to pass as Provider
* @see #arg(String)
* @since 4.0.0
*/
void arg(Provider provider) {
instructions.add(new ArgInstruction(provider))
}
/**
* The RUN instruction will execute any commands in a
* new layer on top of the current image and commit the results.
*
* Example in Groovy DSL:
*
*
* task createDockerfile(type: Dockerfile) {
* runCommand('/bin/bash -c echo hello')
* }
*
*
* @param command Command
* @see #runCommand(Provider)
*/
void runCommand(String command) {
instructions.add(new RunCommandInstruction(command))
}
/**
* A RUN instruction as Provider.
*
* Example in Groovy DSL:
*
*
* task createDockerfile(type: Dockerfile) {
* runCommand(project.provider(new Callable() {
* @Override
* String call() throws Exception {
* '/bin/bash -c echo hello'
* }
* }))
* }
*
*
* @param provider Command as Provider
* @see #runCommand(String)
* @since 4.0.0
*/
void runCommand(Provider provider) {
instructions.add(new RunCommandInstruction(provider))
}
/**
* The main purpose of a CMD instruction is to provide
* defaults for an executing container.
*
* Example in Groovy DSL:
*
*
* task createDockerfile(type: Dockerfile) {
* defaultCommand('/usr/bin/wc', '--help')
* }
*
*
* @param command Command
* @see #defaultCommand(Provider)
*/
void defaultCommand(String... command) {
instructions.add(new DefaultCommandInstruction(command))
}
/**
* A CMD instruction as Provider.
*
* Example in Groovy DSL:
*
*
* task createDockerfile(type: Dockerfile) {
* defaultCommand(project.provider(new Callable>() {
* @Override
* List call() throws Exception {
* ['/usr/bin/wc', '--help']
* }
* }))
* }
*
*
* @param provider Command as Provider
* @see #defaultCommand(String...)
* @since 4.0.0
*/
void defaultCommand(Provider> provider) {
instructions.add(new DefaultCommandInstruction(provider))
}
/**
* The EXPOSE instruction informs Docker that the
* container will listen on the specified network ports at runtime.
*
* Example in Groovy DSL:
*
*
* task createDockerfile(type: Dockerfile) {
* exposePort(8080, 9090)
* }
*
*
* @param ports Ports
* @see #exposePort(Provider)
*/
void exposePort(Integer... ports) {
instructions.add(new ExposePortInstruction(ports))
}
/**
* A EXPOSE instruction as Provider.
*
* Example in Groovy DSL:
*
*
* task createDockerfile(type: Dockerfile) {
* exposePort(project.provider(new Callable>() {
* @Override
* List call() throws Exception {
* [8080, 9090]
* }
* }))
* }
*
*
* @param ports Ports as Provider
* @see #exposePort(Integer...)
* @since 4.0.0
*/
void exposePort(Provider> provider) {
instructions.add(new ExposePortInstruction(provider))
}
/**
* The ENV instruction sets the environment variable
* to the value . This value will be passed to all future RUN instructions.
*
* Example in Groovy DSL:
*
*
* task createDockerfile(type: Dockerfile) {
* environmentVariable('myName', 'John Doe')
* }
*
*
* @param key Key
* @param value Value
* @see #environmentVariable(Map)
* @see #environmentVariable(Provider)
*/
void environmentVariable(String key, String value) {
instructions.add(new EnvironmentVariableInstruction(key, value))
}
/**
* A ENV instruction as Map.
*
* Example in Groovy DSL:
*
*
* task createDockerfile(type: Dockerfile) {
* environmentVariable(['myName': 'John Doe'])
* }
*
*
* @param envVars Environment variables
* @see #environmentVariable(String, String)
* @see #environmentVariable(Provider)
*/
void environmentVariable(Map envVars) {
instructions.add(new EnvironmentVariableInstruction(envVars))
}
/**
* A ENV instruction as Provider.
*
* Example in Groovy DSL:
*
*
* task createDockerfile(type: Dockerfile) {
* environmentVariable(project.provider(new Callable>() {
* @Override
* Map call() throws Exception {
* ['myName': 'John Doe']
* }
* }))
* }
*
*
* @param provider Environment variables as Provider
* @see #environmentVariable(String, String)
* @see #environmentVariable(Map)
* @since 4.0.0
*/
void environmentVariable(Provider> provider) {
instructions.add(new EnvironmentVariableInstruction(provider))
}
/**
* The ADD instruction copies new files, directories
* or remote file URLs from and adds them to the filesystem of the container at the path .
*
* Example in Groovy DSL:
*
*
* task createDockerfile(type: Dockerfile) {
* addFile('test', '/absoluteDir/')
* }
*
*
* @param src Source file
* @param dest Destination path
* @see #addFile(Provider)
*/
void addFile(String src, String dest) {
instructions.add(new AddFileInstruction(src, dest))
}
/**
* A ADD instruction as Provider.
*
* Example in Groovy DSL:
*
*
* task createDockerfile(type: Dockerfile) {
* addFile(project.provider(new Callable() {
* @Override
* Dockerfile.File call() throws Exception {
* new Dockerfile.File('test', '/absoluteDir/')
* }
* }))
* }
*
*
* @param provider Add instruction as Provider
* @see #addFile(String, String)
* @since 4.0.0
*/
void addFile(Provider provider) {
instructions.add(new AddFileInstruction(provider))
}
/**
* The COPY instruction copies new files or directories
* from and adds them to the filesystem of the container at the path .
*
* Example in Groovy DSL:
*
*
* task createDockerfile(type: Dockerfile) {
* copyFile('test', '/absoluteDir/')
* }
*
*
* @param src Source file
* @param dest Destination path
* @param stageName stage name in case of multi stage build
* @see #copyFile(Provider)
*/
void copyFile(String src, String dest, String stageName = null) {
instructions.add(new CopyFileInstruction(src, dest, stageName))
}
/**
* A COPY instruction as Provider.
*
* Example in Groovy DSL:
*
*
* task createDockerfile(type: Dockerfile) {
* copyFile(project.provider(new Callable() {
* @Override
* Dockerfile.File call() throws Exception {
* new Dockerfile.File('test', '/absoluteDir/')
* }
* }))
* }
*
*
* @param provider Copy instruction as Provider
* @see #copyFile(String, String, String)
* @since 4.0.0
*/
void copyFile(Provider provider) {
instructions.add(new CopyFileInstruction(provider))
}
/**
* An ENTRYPOINT allows you to configure a container
* that will run as an executable.
*
* Example in Groovy DSL:
*
*
* task createDockerfile(type: Dockerfile) {
* entryPoint('top', '-b')
* }
*
*
* @param entryPoint Entry point
* @see #entryPoint(Provider)
*/
void entryPoint(String... entryPoint) {
instructions.add(new EntryPointInstruction(entryPoint))
}
/**
* A ENTRYPOINT as Provider.
*
* Example in Groovy DSL:
*
*
* task createDockerfile(type: Dockerfile) {
* entryPoint(project.provider(new Callable>() {
* @Override
* List call() throws Exception {
* ['top', '-b']
* }
* }))
* }
*
*
* @param entryPoint Entry point
* @see #entryPoint(String...)
* @since 4.0.0
*/
void entryPoint(Provider> provider) {
instructions.add(new EntryPointInstruction(provider))
}
/**
* The VOLUME instruction will create a mount point
* with the specified name and mark it as holding externally mounted volumes from native host or other containers.
*
* Example in Groovy DSL:
*
*
* task createDockerfile(type: Dockerfile) {
* volume('/myvol')
* }
*
*
* @param volume Volume
* @see #volume(Provider)
*/
void volume(String... volume) {
instructions.add(new VolumeInstruction(volume))
}
/**
* A VOLUME instruction as Provider.
*
* Example in Groovy DSL:
*
*
* task createDockerfile(type: Dockerfile) {
* volume(project.provider(new Callable>() {
* @Override
* List call() throws Exception {
* ['/myvol']
* }
* }))
* }
*
*
* @param volume Volume
* @see #volume(String...)
* @since 4.0.0
*/
void volume(Provider> provider) {
instructions.add(new VolumeInstruction(provider))
}
/**
* The USER instruction sets the user name or UID to
* use when running the image and for any RUN, CMD and ENTRYPOINT instructions that follow it in the Dockerfile.
*
* Example in Groovy DSL:
*
*
* task createDockerfile(type: Dockerfile) {
* user('patrick')
* }
*
*
* @param user User
* @see #user(Provider)
*/
void user(String user) {
instructions.add(new UserInstruction(user))
}
/**
* A USER instruction as Provider.
*
* Example in Groovy DSL:
*
*
* task createDockerfile(type: Dockerfile) {
* user(project.provider(new Callable() {
* @Override
* String call() throws Exception {
* 'patrick'
* }
* }))
* }
*
*
* @param provider User as Provider
* @see #user(String)
* @since 4.0.0
*/
void user(Provider provider) {
instructions.add(new UserInstruction(provider))
}
/**
* The WORKDIR instruction sets the working directory
* for any RUN, CMD and ENTRYPOINT instructions that follow it in the Dockerfile.
*
* Example in Groovy DSL:
*
*
* task createDockerfile(type: Dockerfile) {
* workingDir('/path/to/workdir')
* }
*
*
* @param dir Directory
* @see #workingDir(Provider)
*/
void workingDir(String dir) {
instructions.add(new WorkDirInstruction(dir))
}
/**
* A WORKDIR instruction as Provider.
*
* Example in Groovy DSL:
*
*
* task createDockerfile(type: Dockerfile) {
* workingDir(project.provider(new Callable() {
* @Override
* String call() throws Exception {
* '/path/to/workdir'
* }
* }))
* }
*
*
* @param dir Directory
* @see #workingDir(String)
* @since 4.0.0
*/
void workingDir(Provider provider) {
instructions.add(new WorkDirInstruction(provider))
}
/**
* The ONBUILD instruction adds to the image a
* trigger instruction to be executed at a later time, when the image is used as the base for another build.
*
* Example in Groovy DSL:
*
*
* task createDockerfile(type: Dockerfile) {
* onBuild('ADD . /app/src')
* }
*
*
* @param instruction Instruction
* @see #onBuild(Provider)
*/
void onBuild(String instruction) {
instructions.add(new OnBuildInstruction(instruction))
}
/**
* A ONBUILD instruction as Provider.
*
* Example in Groovy DSL:
*
*
* task createDockerfile(type: Dockerfile) {
* onBuild(project.provider(new Callable() {
* @Override
* String call() throws Exception {
* 'ADD . /app/src'
* }
* }))
* }
*
*
* @param instruction Instruction
* @see #onBuild(String)
* @since 4.0.0
*/
void onBuild(Provider provider) {
instructions.add(new OnBuildInstruction(provider))
}
/**
* The LABEL instruction adds metadata to an image.
*
* Example in Groovy DSL:
*
*
* task createDockerfile(type: Dockerfile) {
* label(['version': '1.0'])
* }
*
*
* @param labels Labels
* @see #label(Provider)
*/
void label(Map labels) {
instructions.add(new LabelInstruction(labels))
}
/**
* A LABEL instruction as Provider.
*
* Example in Groovy DSL:
*
*
* task createDockerfile(type: Dockerfile) {
* label(project.provider(new Callable>() {
* @Override
* Map call() throws Exception {
* ['version': '1.0']
* }
* }))
* }
*
*
* @param provider Labels as Provider
* @see #label(Map)
* @since 4.0.0
*/
void label(Provider> provider) {
instructions.add(new LabelInstruction(provider))
}
static interface Instruction {
/**
* Gets the keyword of the instruction as used in the Dockerfile.
*
* For example the keyword of the {@link FromInstruction} is {@code FROM}.
*
* @return The instruction keyword
*/
@Internal
@Nullable
String getKeyword()
/**
* Gets the full text of the instruction as used in the Dockerfile.
*
* @return The instruction
* @since 3.6.0
*/
@Input
@Optional
@Nullable
String getText()
}
static class GenericInstruction implements Instruction {
private final String instruction
private final Provider instructionProvider
GenericInstruction(String instruction) {
this.instruction = instruction
}
GenericInstruction(Provider instructionProvider) {
this.instructionProvider = instructionProvider
}
@Override
String getKeyword() {
if (instructionProvider) {
parseKeyword(instructionProvider.getOrNull())
} else {
parseKeyword(instruction)
}
}
private String parseKeyword(String inst) {
inst?.substring(0, inst.indexOf(' '))
}
@Override
String getText() {
if (instructionProvider) {
return instructionProvider.getOrNull()
}
instruction
}
}
static abstract class StringCommandInstruction implements Instruction {
private final String command
private final Provider commandProvider
StringCommandInstruction(String command) {
this.command = command
}
StringCommandInstruction(Provider commandProvider) {
this.commandProvider = commandProvider
}
@Override
String getText() {
if (commandProvider) {
String command = commandProvider.getOrNull()
if (command) {
return buildText(command)
}
} else {
return buildText(command)
}
}
private String buildText(String command) {
"$keyword $command"
}
}
static abstract class StringArrayInstruction implements Instruction {
private final String[] command
private final Provider> commandProvider
StringArrayInstruction(String... command) {
this.command = command
}
StringArrayInstruction(Provider> commandProvider) {
this.commandProvider = commandProvider
}
@Override
String getText() {
if (commandProvider) {
List command = commandProvider.getOrNull()
if (command) {
return buildText(command as String[])
}
} else {
return buildText(command)
}
}
private String buildText(String[] command) {
keyword + ' ["' + command.join('", "') + '"]'
}
}
interface ItemJoiner {
String join(Map map)
}
static class MultiItemJoiner implements ItemJoiner {
@Override
@CompileStatic(TypeCheckingMode.SKIP)
String join(Map map) {
map.inject([]) { result, entry ->
def key = ItemJoinerUtil.isUnquotedStringWithWhitespaces(entry.key) ? ItemJoinerUtil.toQuotedString(entry.key) : entry.key
def value = ItemJoinerUtil.isUnquotedStringWithWhitespaces(entry.value) ? ItemJoinerUtil.toQuotedString(entry.value) : entry.value
value = value.replaceAll("(\r)*\n", "\\\\\n")
result << "$key=$value"
}.join(' ')
}
}
static class SingleItemJoiner implements ItemJoiner {
@Override
@CompileStatic(TypeCheckingMode.SKIP)
String join(Map map) {
map.inject([]) { result, entry ->
def key = ItemJoinerUtil.isUnquotedStringWithWhitespaces(entry.key) ? ItemJoinerUtil.toQuotedString(entry.key) : entry.key
// preserve multiline value in a single item key value instruction but ignore any other whitespaces or quotings
def value = entry.value.replaceAll("(\r)*\n", "\\\\\n")
result << "$key $value"
}.join('')
}
}
private class ItemJoinerUtil {
private static boolean isUnquotedStringWithWhitespaces(String str) {
return !str.matches('["].*["]') &&
str.matches('.*(?: |(?:\r?\n)).*')
}
private static String toQuotedString(final String str) {
'"'.concat(str.replaceAll('"', '\\\\"')).concat('"')
}
}
static abstract class MapInstruction implements Instruction {
private final Map command
private final Provider> commandProvider
private final ItemJoiner joiner
MapInstruction(Map command, ItemJoiner joiner) {
this.command = command
this.joiner = joiner
}
MapInstruction(Map command) {
this(command, new MultiItemJoiner())
}
MapInstruction(Provider> commandProvider) {
this.commandProvider = commandProvider
joiner = new MultiItemJoiner()
}
@Override
String getText() {
Map commandToJoin = command
if (commandProvider) {
def evaluatedCommand = commandProvider.getOrNull()
if (!(evaluatedCommand instanceof Map)) {
throw new IllegalArgumentException("the given evaluated closure is not a valid input for instruction ${keyword} while it doesn't provide a `Map` ([ key: value ]) but a `${evaluatedCommand?.class}` (${evaluatedCommand?.toString()})")
}
commandToJoin = evaluatedCommand as Map
}
if (commandToJoin == null) {
throw new IllegalArgumentException("instruction has to be set for ${keyword}")
}
validateKeysAreNotBlank commandToJoin
"$keyword ${joiner.join(commandToJoin)}"
}
private void validateKeysAreNotBlank(Map command) throws IllegalArgumentException {
command.each { entry ->
if (entry.key.trim().length() == 0) {
throw new IllegalArgumentException("blank keys for a key=value pair are not allowed: please check instruction ${keyword} and given pair `${entry}`")
}
}
}
}
static abstract class FileInstruction implements Instruction {
private final String src
private final String dest
private final String flags
private final Provider provider
FileInstruction(String src, String dest, String flags = null) {
this.src = src
this.dest = dest
this.flags = flags
}
FileInstruction(Provider provider) {
this.provider = provider
}
@Override
String getText() {
String keyword = getKeyword()
File file
if (provider) {
file = provider.getOrNull()
} else {
file = new File(src, dest, flags)
}
if (file) {
if (file.flags) {
keyword += " $file.flags"
}
if (file.src && file.dest) {
"$keyword $file.src $file.dest"
}
}
}
}
static class FromInstruction implements Instruction {
public static final String KEYWORD = 'FROM'
private final String image
private final String stageName
private final Provider provider
FromInstruction(String image, String stageName = null) {
this.image = image
this.stageName = stageName
}
FromInstruction(Provider provider) {
this.provider = provider
}
@Override
String getKeyword() {
KEYWORD
}
@Override
String getText() {
if (provider) {
return buildTextInstruction(provider.getOrNull())
}
buildTextInstruction(new From(image, stageName))
}
private String buildTextInstruction(From from) {
if (from) {
String result = "$keyword $from.image"
if (from.stageName) {
result += " AS $from.stageName"
}
result
}
}
}
static class ArgInstruction extends StringCommandInstruction {
public static final String KEYWORD = 'ARG'
ArgInstruction(String arg) {
super(arg)
}
ArgInstruction(Provider provider) {
super(provider)
}
@Override
String getKeyword() {
KEYWORD
}
}
static class RunCommandInstruction extends StringCommandInstruction {
RunCommandInstruction(String command) {
super(command)
}
RunCommandInstruction(Provider provider) {
super(provider)
}
@Override
String getKeyword() {
"RUN"
}
}
static class DefaultCommandInstruction extends StringArrayInstruction {
DefaultCommandInstruction(String... command) {
super(command)
}
DefaultCommandInstruction(Provider> provider) {
super(provider)
}
@Override
String getKeyword() {
"CMD"
}
}
static class ExposePortInstruction implements Instruction {
private final Integer[] ports
private final Provider> provider
ExposePortInstruction(Integer... ports) {
this.ports = ports
}
ExposePortInstruction(Provider> provider) {
this.provider = provider
}
@Override
String getKeyword() {
"EXPOSE"
}
@Override
String getText() {
if (provider) {
List evaluatedPorts = provider.getOrNull()
if (evaluatedPorts && !evaluatedPorts.isEmpty()) {
return buildText(evaluatedPorts as Integer[])
}
} else {
return buildText(ports)
}
}
private String buildText(Integer[] ports) {
"$keyword ${ports.join(' ')}"
}
}
static class EnvironmentVariableInstruction extends MapInstruction {
EnvironmentVariableInstruction(String key, String value) {
super([(key): value], new SingleItemJoiner())
}
EnvironmentVariableInstruction(Map envVars) {
super(envVars)
}
EnvironmentVariableInstruction(Provider> provider) {
super(provider)
}
@Override
String getKeyword() {
"ENV"
}
}
static class AddFileInstruction extends FileInstruction {
AddFileInstruction(String src, String dest) {
super(src, dest)
}
AddFileInstruction(Provider provider) {
super(provider)
}
@Override
String getKeyword() {
"ADD"
}
}
static class CopyFileInstruction extends FileInstruction {
CopyFileInstruction(String src, String dest, String stageName = null) {
super(src, dest, stageName ? "--from=$stageName" : null)
}
CopyFileInstruction(Provider provider) {
super(provider)
}
@Override
String getKeyword() {
"COPY"
}
}
static class EntryPointInstruction extends StringArrayInstruction {
EntryPointInstruction(String... entryPoint) {
super(entryPoint)
}
EntryPointInstruction(Provider> provider) {
super(provider)
}
@Override
String getKeyword() {
"ENTRYPOINT"
}
}
static class VolumeInstruction extends StringArrayInstruction {
VolumeInstruction(String... volume) {
super(volume)
}
VolumeInstruction(Provider> provider) {
super(provider)
}
@Override
String getKeyword() {
"VOLUME"
}
}
static class UserInstruction extends StringCommandInstruction {
UserInstruction(String user) {
super(user)
}
UserInstruction(Provider provider) {
super(provider)
}
@Override
String getKeyword() {
"USER"
}
}
static class WorkDirInstruction extends StringCommandInstruction {
WorkDirInstruction(String dir) {
super(dir)
}
WorkDirInstruction(Provider provider) {
super(provider)
}
@Override
String getKeyword() {
"WORKDIR"
}
}
static class OnBuildInstruction extends StringCommandInstruction {
OnBuildInstruction(String instruction) {
super(instruction)
}
OnBuildInstruction(Provider provider) {
super(provider)
}
@Override
String getKeyword() {
"ONBUILD"
}
}
static class LabelInstruction extends MapInstruction {
LabelInstruction(Map labels) {
super(labels)
}
LabelInstruction(Provider> provider) {
super(provider)
}
@Override
String getKeyword() {
"LABEL"
}
}
/**
* @since 4.0.1
*/
static class CommentInstruction extends StringCommandInstruction {
public static final String KEYWORD = '#'
CommentInstruction(String command) {
super(command)
}
CommentInstruction(Provider commandProvider) {
super(commandProvider)
}
@Override
String getKeyword() {
KEYWORD
}
}
/**
* Input data for a copy or add instruction.
*
* @since 4.0.0
*/
static class File {
final String src
final String dest
final @Nullable String flags
File(String src, String dest) {
this.src = src
this.dest = dest
}
File(String src, String dest, @Nullable String flags) {
this.src = src
this.dest = dest
this.flags = flags
}
}
/**
* Input data for a from instruction.
*
* @since 4.0.0
*/
static class From {
final String image
final @Nullable String stageName
From(String image) {
this.image = image
}
From(String image, @Nullable String stageName) {
this.image = image
this.stageName = stageName
}
}
}