/* * Copyright 2014 Oleg Nenashev * * 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 jenkins.plugins.customtools.util.envvars; import hudson.EnvVars; import hudson.model.Hudson; import hudson.model.Node; import hudson.slaves.EnvironmentVariablesNodeProperty; import hudson.slaves.NodeProperty; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.nio.charset.StandardCharsets; import java.util.Map; import java.util.Properties; import javax.annotation.CheckForNull; import javax.annotation.Nonnull; import jenkins.plugins.customtools.util.JenkinsHelper; /** * Substitutes variables. * @since TODO * @author Oleg Nenashev */ public abstract class VariablesSubstitutionHelper { public static final VariablesSubstitutionHelper PROP_FILE = new PropFileVariablesSubstitutionHelper(); public static final VariablesSubstitutionHelper PATH = new SimpleVariablesSubstitutionHelper(); /** * Escapes variable values for the required format. * @param variableName Name of the variable, which is being substituted * @param rawValue Input value * @return Escaped value */ public String escapeVariableValue(String variableName, String rawValue) { return rawValue; } /** * Resolves tools installation directory using global variables. * @param environment Collection of environment variables * @param inputValue Input path with macro calls * @return Raw string * @since 0.3 */ public String resolveVariable(@CheckForNull String inputValue, @Nonnull EnvVars environment) { if (inputValue == null || !hasMacros(inputValue)) return inputValue; // Substitute parameters String substitutedString = inputValue; for (Map.Entry<String,String> entry : environment.entrySet()) { if (hasMacros(inputValue, entry.getKey())) { final String escapedValue = escapeVariableValue(entry.getKey(), entry.getValue()); substitutedString = substitutedString.replace("${" + entry.getKey() + "}", escapedValue); } } return substitutedString; } public String resolveVariable(@CheckForNull String inputValue, @Nonnull Node node) { if (!hasMacros(inputValue)) return inputValue; // Check node properties String substitutedString = inputValue; for (NodeProperty<?> entry : node.getNodeProperties()) { substitutedString = substituteNodeProperty(substitutedString, entry); } // Substitute global variables for (NodeProperty<?> entry : JenkinsHelper.getInstanceOrDie().getGlobalNodeProperties()) { substitutedString = substituteNodeProperty(substitutedString, entry); } return substitutedString; } /** * Substitutes string according to node property. * @param macroString String to be substituted * @param property Node property * @return Substituted string * @since 0.3 */ private String substituteNodeProperty(@CheckForNull String macroString, @CheckForNull NodeProperty<?> property) { // Get environment variables if (property != null && property instanceof EnvironmentVariablesNodeProperty) { EnvironmentVariablesNodeProperty prop = (EnvironmentVariablesNodeProperty)property; return resolveVariable(macroString, prop.getEnvVars()); } //TODO: add support of other configuration entries or propagate environments return macroString; } public static boolean hasMacros(@CheckForNull String inputString) { return inputString != null ? inputString.contains("${") : false; } public static boolean hasMacros(@CheckForNull String inputString, String macroName) { return inputString != null ? inputString.contains("${"+macroName+"}") : false; } public static class SimpleVariablesSubstitutionHelper extends VariablesSubstitutionHelper { } public static class PropFileVariablesSubstitutionHelper extends VariablesSubstitutionHelper { @Override public String escapeVariableValue(String variableName, String rawValue) { final ByteArrayOutputStream str= new ByteArrayOutputStream(); Properties prop = new Properties(); prop.setProperty("TMP", rawValue); try { prop.store(str,"tmp"); } catch (IOException ex) { // Fallback to the default behavior //TODO: Really??? return super.escapeVariableValue(variableName, rawValue); } try { String res = str.toString("UTF-8") .split("\n")[2].replaceFirst(".*TMP=", "").trim(); return res; } catch (UnsupportedEncodingException ex) { throw new IllegalStateException("UTF-8 encoding is not supported", ex); } } } }