
com.github.dockerjava.core.dockerfile.Dockerfile Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of docker-java Show documentation
Show all versions of docker-java Show documentation
Java API Client for Docker
package com.github.dockerjava.core.dockerfile;
import com.github.dockerjava.api.DockerClientException;
import com.github.dockerjava.core.CompressArchiveUtil;
import com.github.dockerjava.core.FilePathUtil;
import com.github.dockerjava.core.GoLangFileMatch;
import com.github.dockerjava.core.GoLangFileMatchException;
import com.github.dockerjava.core.GoLangMatchFileFilter;
import com.google.common.base.Function;
import com.google.common.base.Objects;
import com.google.common.base.Optional;
import com.google.common.collect.Collections2;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.filefilter.TrueFileFilter;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
/**
* Parse a Dockerfile.
*/
public class Dockerfile {
public final File dockerFile;
public Dockerfile(File dockerFile) {
if (!dockerFile.exists()) {
throw new IllegalStateException(String.format("Dockerfile %s does not exist", dockerFile.getAbsolutePath()));
}
if (!dockerFile.isFile()) {
throw new IllegalStateException(String.format("Dockerfile %s is not a file", dockerFile.getAbsolutePath()));
}
this.dockerFile = dockerFile;
}
private static class LineTransformer implements Function> {
private int line = 0;
@Override
public Optional extends DockerfileStatement> apply(String input) {
try {
line++;
return DockerfileStatement.createFromLine(input);
} catch (Exception ex) {
throw new DockerClientException("Error on dockerfile line " + line);
}
}
}
public Iterable getStatements() throws IOException {
Collection dockerFileContent = FileUtils.readLines(dockerFile);
if (dockerFileContent.size() <= 0) {
throw new DockerClientException(String.format("Dockerfile %s is empty", dockerFile));
}
Collection> optionals = Collections2.transform(dockerFileContent,
new LineTransformer());
return Optional.presentInstances(optionals);
}
public List getIgnores() throws IOException {
List ignores = new ArrayList();
File dockerIgnoreFile = new File(getDockerFolder(), ".dockerignore");
if (dockerIgnoreFile.exists()) {
int lineNumber = 0;
List dockerIgnoreFileContent = FileUtils.readLines(dockerIgnoreFile);
for (String pattern : dockerIgnoreFileContent) {
lineNumber++;
pattern = pattern.trim();
if (pattern.isEmpty()) {
continue; // skip empty lines
}
pattern = FilenameUtils.normalize(pattern);
try {
ignores.add(pattern);
} catch (GoLangFileMatchException e) {
throw new DockerClientException(String.format(
"Invalid pattern '%s' on line %s in .dockerignore file", pattern, lineNumber));
}
}
}
return ignores;
}
public ScannedResult parse() throws IOException {
return new ScannedResult();
}
public File getDockerFolder() {
return dockerFile.getParentFile();
}
/**
* Result of scanning / parsing a docker file.
*/
public class ScannedResult {
final List ignores;
final Map environmentMap = new HashMap();
final List filesToAdd = new ArrayList();
public InputStream buildDockerFolderTar() {
return buildDockerFolderTar(getDockerFolder());
}
public InputStream buildDockerFolderTar(File directory) {
File dockerFolderTar = null;
try {
final String archiveNameWithOutExtension = UUID.randomUUID().toString();
dockerFolderTar = CompressArchiveUtil.archiveTARFiles(directory, filesToAdd,
archiveNameWithOutExtension);
final InputStream tarInputStream = FileUtils.openInputStream(dockerFolderTar);
final File tarFile = dockerFolderTar;
return new InputStream() {
@Override
public int read() throws IOException {
return tarInputStream.read();
}
@Override
public void close() throws IOException {
IOUtils.closeQuietly(tarInputStream);
FileUtils.deleteQuietly(tarFile);
}
};
} catch (IOException ex) {
FileUtils.deleteQuietly(dockerFolderTar);
throw new DockerClientException("Error occurred while preparing Docker context folder.", ex);
}
}
@Override
public String toString() {
return Objects.toStringHelper(this).add("ignores", ignores).add("environmentMap", environmentMap)
.add("filesToAdd", filesToAdd).toString();
}
public ScannedResult() throws IOException {
ignores = getIgnores();
String matchingIgnorePattern = effectiveMatchingIgnorePattern(dockerFile);
if (matchingIgnorePattern == null) {
filesToAdd.add(dockerFile);
} else {
throw new DockerClientException(String.format(
"Dockerfile is excluded by pattern '%s' in .dockerignore file", matchingIgnorePattern));
}
for (DockerfileStatement statement : getStatements()) {
if (statement instanceof DockerfileStatement.Env) {
processEnvStatement((DockerfileStatement.Env) statement);
} else if (statement instanceof DockerfileStatement.Add) {
processAddStatement((DockerfileStatement.Add) statement);
}
}
}
/**
* Returns all matching ignore patterns for the given file name.
*/
private List matchingIgnorePatterns(String fileName) {
List matches = new ArrayList();
int lineNumber = 0;
for (String pattern : ignores) {
lineNumber++;
try {
if (GoLangFileMatch.match(pattern, fileName)) {
matches.add(pattern);
}
} catch (GoLangFileMatchException e) {
throw new DockerClientException(String.format(
"Invalid pattern '%s' on line %s in .dockerignore file", pattern, lineNumber));
}
}
return matches;
}
/**
* Returns the matching ignore pattern for the given file or null if it should NOT be ignored. Exception rules
* like "!Dockerfile" will be respected.
*/
private String effectiveMatchingIgnorePattern(File file) {
String relativeFilename = FilePathUtil.relativize(getDockerFolder(), file);
List matchingPattern = matchingIgnorePatterns(relativeFilename);
if (matchingPattern.isEmpty())
return null;
String lastMatchingPattern = matchingPattern.get(matchingPattern.size() - 1);
int lastMatchingPatternIndex = ignores.lastIndexOf(lastMatchingPattern);
if (lastMatchingPatternIndex == ignores.size() - 1)
return lastMatchingPattern;
List remainingIgnorePattern = ignores.subList(lastMatchingPatternIndex + 1, ignores.size());
for (String ignorePattern : remainingIgnorePattern) {
if (ignorePattern.equals("!" + relativeFilename))
return null;
}
return lastMatchingPattern;
}
private void processAddStatement(DockerfileStatement.Add add) throws IOException {
add = add.transform(environmentMap);
for (String resource : add.getFileResources()) {
File dockerFolder = getDockerFolder();
File src = new File(resource);
if (!src.isAbsolute()) {
src = new File(dockerFolder, resource);
} else {
throw new DockerClientException(String.format("Source file %s must be relative to %s", src,
dockerFolder));
}
if (src.exists()) {
src = src.getCanonicalFile();
if (src.isDirectory()) {
Collection files = FileUtils.listFiles(src, new GoLangMatchFileFilter(src, ignores),
TrueFileFilter.INSTANCE);
filesToAdd.addAll(files);
} else if (effectiveMatchingIgnorePattern(src) == null) {
filesToAdd.add(src);
} else {
throw new DockerClientException(String.format(
"Source file %s is excluded by .dockerignore file", src));
}
} else {
filesToAdd.addAll(resolveWildcards(src, ignores));
}
}
}
private Collection resolveWildcards(File file, List ignores) {
List filesToAdd = new ArrayList();
File parent = file.getParentFile();
if (parent != null) {
if (parent.isDirectory()) {
Collection files = FileUtils.listFiles(parent, new GoLangMatchFileFilter(parent, ignores),
TrueFileFilter.INSTANCE);
filesToAdd.addAll(files);
} else {
filesToAdd.addAll(resolveWildcards(parent, ignores));
}
} else {
throw new DockerClientException(String.format("Source file %s doesn't exist", file));
}
return filesToAdd;
}
private void processEnvStatement(DockerfileStatement.Env env) {
environmentMap.put(env.variable, env.value);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy