diff --git a/cli/src/main/java/com/devonfw/tools/ide/environment/AbstractEnvironmentVariables.java b/cli/src/main/java/com/devonfw/tools/ide/environment/AbstractEnvironmentVariables.java index d411b2280..cf5e09a68 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/environment/AbstractEnvironmentVariables.java +++ b/cli/src/main/java/com/devonfw/tools/ide/environment/AbstractEnvironmentVariables.java @@ -1,5 +1,9 @@ package com.devonfw.tools.ide.environment; +import com.devonfw.tools.ide.context.IdeContext; +import com.devonfw.tools.ide.variable.IdeVariables; +import com.devonfw.tools.ide.variable.VariableDefinition; + import java.nio.file.Path; import java.util.ArrayList; import java.util.Collection; @@ -9,19 +13,14 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import com.devonfw.tools.ide.context.IdeContext; -import com.devonfw.tools.ide.variable.IdeVariables; -import com.devonfw.tools.ide.variable.VariableDefinition; - /** * Abstract base implementation of {@link EnvironmentVariables}. */ public abstract class AbstractEnvironmentVariables implements EnvironmentVariables { /** - * When we replace variable expressions with their value the resulting {@link String} can change in size (shrink or - * grow). By adding a bit of extra capacity we reduce the chance that the capacity is too small and a new buffer array - * has to be allocated and array-copy has to be performed. + * When we replace variable expressions with their value the resulting {@link String} can change in size (shrink or grow). By adding a bit of extra capacity + * we reduce the chance that the capacity is too small and a new buffer array has to be allocated and array-copy has to be performed. */ private static final int EXTRA_CAPACITY = 8; @@ -124,7 +123,9 @@ private final Collection collectVariables(boolean onlyExported) { boolean export = isExported(name); if (!onlyExported || export) { String value = get(name); - variables.add(VariableLine.of(export, name, value)); + if (value != null) { + variables.add(VariableLine.of(export, name, value)); + } } } return variables; @@ -141,8 +142,7 @@ protected void collectVariables(Set variables) { } /** - * @param propertiesFilePath the {@link #getPropertiesFilePath() propertiesFilePath} of the child - * {@link EnvironmentVariables}. + * @param propertiesFilePath the {@link #getPropertiesFilePath() propertiesFilePath} of the child {@link EnvironmentVariables}. * @param type the {@link #getType() type}. * @return the new {@link EnvironmentVariables}. */ @@ -152,8 +152,7 @@ public AbstractEnvironmentVariables extend(Path propertiesFilePath, EnvironmentV } /** - * @return a new child {@link EnvironmentVariables} that will resolve variables recursively or this instance itself if - * already satisfied. + * @return a new child {@link EnvironmentVariables} that will resolve variables recursively or this instance itself if already satisfied. */ public EnvironmentVariables resolved() { @@ -169,35 +168,30 @@ public String resolve(String string, Object src) { /** * This method is called recursively. This allows you to resolve variables that are defined by other variables. * - * @param value the {@link String} that potentially contains variables in the syntax "${«variable«}". Those will be - * resolved by this method and replaced with their {@link #get(String) value}. - * @param src the source where the {@link String} to resolve originates from. Should have a reasonable - * {@link Object#toString() string representation} that will be used in error or log messages if a variable - * could not be resolved. + * @param value the {@link String} that potentially contains variables in the syntax "${«variable«}". Those will be resolved by this method and replaced with + * their {@link #get(String) value}. + * @param src the source where the {@link String} to resolve originates from. Should have a reasonable {@link Object#toString() string representation} that + * will be used in error or log messages if a variable could not be resolved. * @param recursion the current recursion level. This is used to interrupt endless recursion. * @param rootSrc the root source where the {@link String} to resolve originates from. * @param rootValue the root value to resolve. - * @param resolvedVars this is a reference to an object of {@link EnvironmentVariablesResolved} being the lowest level - * in the {@link EnvironmentVariablesType hierarchy} of variables. In case of a self-referencing variable - * {@code x} the resolving has to continue one level higher in the {@link EnvironmentVariablesType hierarchy} - * to avoid endless recursion. The {@link EnvironmentVariablesResolved} is then used if another variable - * {@code y} must be resolved, since resolving this variable has to again start at the lowest level. For - * example: For levels {@code l1, l2} with {@code l1 < l2} and {@code x=${x} foo} and {@code y=bar} defined at - * level {@code l1} and {@code x=test ${y}} defined at level {@code l2}, {@code x} is first resolved at level - * {@code l1} and then up the {@link EnvironmentVariablesType hierarchy} at {@code l2} to avoid endless - * recursion. However, {@code y} must be resolved starting from the lowest level in the - * {@link EnvironmentVariablesType hierarchy} and therefore {@link EnvironmentVariablesResolved} is used. + * @param resolvedVars this is a reference to an object of {@link EnvironmentVariablesResolved} being the lowest level in the + * {@link EnvironmentVariablesType hierarchy} of variables. In case of a self-referencing variable {@code x} the resolving has to continue one level higher in + * the {@link EnvironmentVariablesType hierarchy} to avoid endless recursion. The {@link EnvironmentVariablesResolved} is then used if another variable + * {@code y} must be resolved, since resolving this variable has to again start at the lowest level. For example: For levels {@code l1, l2} with + * {@code l1 < l2} and {@code x=${x} foo} and {@code y=bar} defined at level {@code l1} and {@code x=test ${y}} defined at level {@code l2}, {@code x} is + * first resolved at level {@code l1} and then up the {@link EnvironmentVariablesType hierarchy} at {@code l2} to avoid endless recursion. However, {@code y} + * must be resolved starting from the lowest level in the {@link EnvironmentVariablesType hierarchy} and therefore {@link EnvironmentVariablesResolved} is + * used. * @return the given {@link String} with the variables resolved. */ - private String resolve(String value, Object src, int recursion, Object rootSrc, String rootValue, - AbstractEnvironmentVariables resolvedVars) { + private String resolve(String value, Object src, int recursion, Object rootSrc, String rootValue, AbstractEnvironmentVariables resolvedVars) { if (value == null) { return null; } if (recursion > MAX_RECURSION) { - throw new IllegalStateException("Reached maximum recursion resolving " + value + " for root variable " + rootSrc - + " with value '" + rootValue + "'."); + throw new IllegalStateException("Reached maximum recursion resolving " + value + " for root variable " + rootSrc + " with value '" + rootValue + "'."); } recursion++; @@ -210,15 +204,13 @@ private String resolve(String value, Object src, int recursion, Object rootSrc, String variableName = matcher.group(2); String variableValue = resolvedVars.getValue(variableName, false); if (variableValue == null) { - this.context.warning("Undefined variable {} in '{}={}' for root '{}={}'", variableName, src, value, rootSrc, - rootValue); + this.context.warning("Undefined variable {} in '{}={}' for root '{}={}'", variableName, src, value, rootSrc, rootValue); continue; } EnvironmentVariables lowestFound = findVariable(variableName); if ((lowestFound == null) || !lowestFound.getFlat(variableName).equals(value)) { // looking for "variableName" starting from resolved upwards the hierarchy - String replacement = resolvedVars.resolve(variableValue, variableName, recursion, rootSrc, rootValue, - resolvedVars); + String replacement = resolvedVars.resolve(variableValue, variableName, recursion, rootSrc, rootValue, resolvedVars); matcher.appendReplacement(sb, Matcher.quoteReplacement(replacement)); } else { // is self referencing // finding next occurrence of "variableName" up the hierarchy of EnvironmentVariablesType @@ -235,8 +227,8 @@ private String resolve(String value, Object src, int recursion, Object rootSrc, } // resolving a self referencing variable one level up the hierarchy of EnvironmentVariablesType, i.e. at "next", // to avoid endless recursion - String replacement = ((AbstractEnvironmentVariables) next).resolve(next.getFlat(variableName), variableName, - recursion, rootSrc, rootValue, resolvedVars); + String replacement = ((AbstractEnvironmentVariables) next).resolve(next.getFlat(variableName), variableName, recursion, rootSrc, rootValue, + resolvedVars); matcher.appendReplacement(sb, Matcher.quoteReplacement(replacement)); } @@ -248,13 +240,11 @@ private String resolve(String value, Object src, int recursion, Object rootSrc, } /** - * Like {@link #get(String)} but with higher-level features including to resolve {@link IdeVariables} with their - * default values. + * Like {@link #get(String)} but with higher-level features including to resolve {@link IdeVariables} with their default values. * * @param name the name of the variable to get. - * @param ignoreDefaultValue - {@code true} if the {@link VariableDefinition#getDefaultValue(IdeContext) default - * value} of a potential {@link VariableDefinition} shall be ignored, {@code false} to return default instead - * of {@code null}. + * @param ignoreDefaultValue - {@code true} if the {@link VariableDefinition#getDefaultValue(IdeContext) default value} of a potential + * {@link VariableDefinition} shall be ignored, {@code false} to return default instead of {@code null}. * @return the value of the variable. */ protected String getValue(String name, boolean ignoreDefaultValue) {