/*******************************************************************************
* Copyright (c) 2012-2017 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.plugin.docker.client;
import java.io.FileWriter;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author andrew00x
*/
public class Dockerfile {
// TODO: docs about template features
final static Pattern TEMPLATE_PATTERN = Pattern.compile("\\$[^\\$^\\$]+\\$");
final static Pattern TEMPLATE_DEFAULT_PATTERN = Pattern.compile("(.*):-(.*)");
// Docker file templates may contains following constructions:
// parameter[= > < >= <= !=]condition?expression1:expression2
// Parameter is replaced with expression1 if value of parameter is matched to condition and replaced with expression2 otherwise
final static Pattern TEMPLATE_CONDITIONAL_PATTERN = Pattern.compile("([^><=!\\s]+)([><=!]+)?(.*)?\\?(.*)?:(.*)?");
private List<String> lines;
private Map<String, Object> parameters;
private List<DockerImage> images;
public List<String> getLines() {
if (lines == null) {
lines = new LinkedList<>();
}
return lines;
}
public List<DockerImage> getImages() {
if (images == null) {
images = new LinkedList<>();
}
return images;
}
public Map<String, Object> getParameters() {
if (parameters == null) {
parameters = new LinkedHashMap<>();
}
return parameters;
}
public void writeDockerfile(java.io.File path) throws IOException {
try (FileWriter output = new FileWriter(path)) {
writeDockerfile(output);
}
}
public void writeDockerfile(Appendable output) throws IOException {
StringBuilder buf = null;
for (String line : getLines()) {
boolean isEmptyOutput = false;
final Matcher matcher = TEMPLATE_PATTERN.matcher(line);
if (matcher.find()) {
int start = 0;
if (buf == null) {
buf = new StringBuilder();
} else {
buf.setLength(0);
}
do {
buf.append(line.substring(start, matcher.start()));
final String template = line.substring(matcher.start(), matcher.end());
final String expression = line.substring(matcher.start() + 1, matcher.end() - 1);
String parameterName;
Matcher subMatcher;
Object value;
// we've a default pattern so extract parameter name
if ((subMatcher = TEMPLATE_DEFAULT_PATTERN.matcher(expression)).matches()) {
parameterName = subMatcher.group(1);
value = getParameters().get(parameterName);
if (value == null) {
value = subMatcher.group(2);
}
} else if ((subMatcher = TEMPLATE_CONDITIONAL_PATTERN.matcher(expression)).matches()) {
parameterName = subMatcher.group(1);
final String operator = subMatcher.group(2);
final String condition = subMatcher.group(3);
final String ifTrue = subMatcher.group(4);
final String ifFalse = subMatcher.group(5);
if (operator == null && condition.isEmpty()) {
// parameter?expression1:expression2
value = getParameters().get(parameterName);
value = (value instanceof Boolean && (Boolean)value)
|| (value instanceof String && Boolean.parseBoolean((String)value))
|| (value instanceof Number && 0 != ((Number)value).intValue())
? ifTrue
: ifFalse;
} else {
value = getParameters().get(parameterName);
if ("=".equals(operator)) {
value = condition.equals(value) ? ifTrue : ifFalse;
} else if ("!=".equals(operator)) {
value = condition.equals(value) ? ifFalse : ifTrue;
} else if (">".equals(operator)) {
value = String.valueOf(value).compareTo(condition) > 0 ? ifTrue : ifFalse;
} else if ("<".equals(operator)) {
value = condition.compareTo(String.valueOf(value)) > 0 ? ifTrue : ifFalse;
} else if (">=".equals(operator)) {
value = condition.compareTo(String.valueOf(value)) <= 0 ? ifTrue : ifFalse;
} else if ("<=".equals(operator)) {
value = condition.compareTo(String.valueOf(value)) >= 0 ? ifTrue : ifFalse;
}
}
if (!isEmptyOutput && (value == null || value.toString().length() == 0)) {
isEmptyOutput = true;
}
} else {
// not a default expression, so expression is the parameter name
parameterName = expression;
value = getParameters().get(parameterName);
}
if (value == null) {
value = template;
}
buf.append(String.valueOf(value));
start = matcher.end();
} while (matcher.find());
final String subLine = line.substring(start);
if (isEmptyOutput && subLine.length() == 0) {
continue;
}
buf.append(subLine);
output.append(buf);
} else {
output.append(line);
}
output.append('\n');
}
}
}