Skip to content

Commit

Permalink
#287: fixed failing tests in FileAccessImplTest (#289)
Browse files Browse the repository at this point in the history
  • Loading branch information
VinceHeu authored Apr 19, 2024
1 parent 3b37c2c commit f49f74a
Showing 1 changed file with 32 additions and 42 deletions.
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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;

Expand Down Expand Up @@ -124,7 +123,9 @@ private final Collection<VariableLine> 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;
Expand All @@ -141,8 +142,7 @@ protected void collectVariables(Set<String> 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}.
*/
Expand All @@ -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() {

Expand All @@ -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++;

Expand All @@ -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
Expand All @@ -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));

}
Expand All @@ -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) {
Expand Down

0 comments on commit f49f74a

Please sign in to comment.