Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#1130: improve using variable FAIL_ON_AMBIGOUS_MERGE incl. documentat… #1158

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

import com.devonfw.tools.ide.context.IdeContext;
import com.devonfw.tools.ide.environment.EnvironmentVariables;
import com.devonfw.tools.ide.merge.xmlmerger.XmlMerger;
import com.devonfw.tools.ide.merge.xml.XmlMerger;
import com.devonfw.tools.ide.util.FilenameUtil;

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.devonfw.tools.ide.merge.xmlmerger;
package com.devonfw.tools.ide.merge.xml;

import java.nio.file.Path;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.devonfw.tools.ide.merge.xmlmerger;
package com.devonfw.tools.ide.merge.xml;

/**
* {@link RuntimeException} for errors related to {@link XmlMerger}.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.devonfw.tools.ide.merge.xmlmerger;
package com.devonfw.tools.ide.merge.xml;

import java.util.Locale;
import java.util.function.BiFunction;
Expand All @@ -9,7 +9,7 @@
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.devonfw.tools.ide.merge.xmlmerger.matcher.ElementMatcher;
import com.devonfw.tools.ide.merge.xml.matcher.ElementMatcher;

/**
* Enum of merge strategies for XML elements.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.devonfw.tools.ide.merge.xmlmerger;
package com.devonfw.tools.ide.merge.xml;

import java.io.StringWriter;
import java.util.Objects;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.devonfw.tools.ide.merge.xmlmerger;
package com.devonfw.tools.ide.merge.xml;

import java.io.BufferedWriter;
import java.io.InputStream;
Expand All @@ -24,7 +24,7 @@
import com.devonfw.tools.ide.context.IdeContext;
import com.devonfw.tools.ide.environment.EnvironmentVariables;
import com.devonfw.tools.ide.merge.FileMerger;
import com.devonfw.tools.ide.merge.xmlmerger.matcher.ElementMatcher;
import com.devonfw.tools.ide.merge.xml.matcher.ElementMatcher;

/**
* {@link FileMerger} for XML files.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.devonfw.tools.ide.merge.xmlmerger.matcher;
package com.devonfw.tools.ide.merge.xml.matcher;

import java.util.HashMap;
import java.util.Map;
Expand All @@ -7,7 +7,7 @@
import org.w3c.dom.Element;

import com.devonfw.tools.ide.context.IdeContext;
import com.devonfw.tools.ide.merge.xmlmerger.XmlMergeSupport;
import com.devonfw.tools.ide.merge.xml.XmlMergeSupport;

/**
* The ElementMatcher class is responsible for matching XML elements in a target document based on the provided update elements.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.devonfw.tools.ide.merge.xmlmerger.matcher;
package com.devonfw.tools.ide.merge.xml.matcher;

import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
Expand All @@ -10,23 +10,23 @@
import org.w3c.dom.NodeList;

import com.devonfw.tools.ide.context.IdeContext;
import com.devonfw.tools.ide.merge.xmlmerger.XmlMergeSupport;
import com.devonfw.tools.ide.merge.xml.XmlMergeSupport;

/**
* The IdComputer class is responsible for building XPath expressions and evaluating those expressions to match elements in a target document.
*/
public class IdComputer {

/** Name of the {@link com.devonfw.tools.ide.environment.EnvironmentVariables variable} to fail on ambiguous merge. */
public static final String FAIL_ON_AMBIGOUS_MERGE = "FAIL_ON_AMBIGOUS_MERGE";

/** The value of merge:id that is used to evaluate the xpath expression. */
private final String id;

private final IdeContext context;

private static final XPathFactory xPathFactory = XPathFactory.newInstance();

private final boolean throwExceptionOnMultipleMatches = Boolean.parseBoolean(System.getProperty("throwExceptionOnMultipleMatches", "false"));


/**
* The constructor.
*
Expand Down Expand Up @@ -68,12 +68,11 @@ public Element evaluateExpression(Element templateElement, Element workspaceElem
} else if (length == 0) {
return null;
} else {
if (throwExceptionOnMultipleMatches) {
throw new IllegalStateException(
length + " matches found for XPath " + xpathExpr + " in workspace XML at " + XmlMergeSupport.getXPath(workspaceElement, true));
String message = length + " matches found for XPath " + xpathExpr + " in workspace XML at " + XmlMergeSupport.getXPath(workspaceElement, true);
if ("true".equals(this.context.getVariables().get(FAIL_ON_AMBIGOUS_MERGE))) {
throw new IllegalStateException(message);
} else {
this.context.warning("Matches found: {} matches for XPath {} in workspace XML at {}",
length, xpathExpr, XmlMergeSupport.getXPath(workspaceElement, true));
this.context.warning(message);
}
return (Element) nodeList.item(0);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.devonfw.tools.ide.merge.xmlmerger.matcher;
package com.devonfw.tools.ide.merge.xml.matcher;

import java.util.Collections;
import java.util.Iterator;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.devonfw.tools.ide.merge;
package com.devonfw.tools.ide.merge.xml;

import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;

Expand All @@ -7,6 +7,7 @@
import java.nio.file.Path;
import java.util.stream.Stream;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
Expand All @@ -15,11 +16,11 @@
import org.xmlunit.assertj3.XmlAssert;

import com.devonfw.tools.ide.context.AbstractIdeContextTest;
import com.devonfw.tools.ide.context.IdeTestContext;
import com.devonfw.tools.ide.context.IdeTestContextMock;
import com.devonfw.tools.ide.environment.EnvironmentVariables;
import com.devonfw.tools.ide.environment.EnvironmentVariablesPropertiesMock;
import com.devonfw.tools.ide.environment.EnvironmentVariablesType;
import com.devonfw.tools.ide.merge.xmlmerger.XmlMerger;

/**
* Test of {@link XmlMerger}.
Expand Down Expand Up @@ -67,4 +68,27 @@ private static Stream<Path> xmlMergerTestCases() throws IOException {

return Files.list(XML_TEST_RESOURCES).filter(Files::isDirectory);
}

@Test
void testFailOnAmbiguousMerge(@TempDir Path tempDir) throws Exception {

// arrange
IdeTestContext context = new IdeTestContext();
EnvironmentVariables variables = context.getVariables();
variables.getByType(EnvironmentVariablesType.CONF).set("FAIL_ON_AMBIGOUS_MERGE", "true");
XmlMerger merger = new XmlMerger(context);
Path folder = XML_TEST_RESOURCES.resolve("ambiguous-id");
Path sourcePath = folder.resolve(SOURCE_XML);
Path targetPath = tempDir.resolve(TARGET_XML);
Files.copy(folder.resolve(TARGET_XML), targetPath, REPLACE_EXISTING);
// act
assertThatThrownBy(() -> {
merger.doMerge(null, sourcePath, variables, targetPath);
})
// assert
.hasRootCauseInstanceOf(IllegalStateException.class).hasRootCauseMessage(
"2 matches found for XPath configuration[@default='true' and @type='JUnit'] in workspace XML at /project[@version='4']/component[@name='RunManager' @selected='Application.IDEasy']");
;

}
}
21 changes: 21 additions & 0 deletions cli/src/test/resources/xmlmerger/ambiguous-id/result.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RunManager" selected="Application.IDEasy">
<configuration default="true" type="JUnit" factoryName="JUnit">
<shortenClasspath name="ARGS_FILE"/>
<option name="METHOD_NAME" value=""/>
<option name="TEST_OBJECT" value="class"/>
<method v="2">
<option name="Make" enabled="true"/>
</method>
</configuration>
<!-- For our test we have this block duplicated -->
<configuration default="true" type="JUnit" factoryName="JUnit">
<shortenClasspath name="ARGS_FILE"/>
<option name="METHOD_NAME" value=""/>
<option name="TEST_OBJECT" value="class"/>
</configuration>
</component>
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level"
UseSingleDictionary="true" transferred="true"/>
</project>
16 changes: 16 additions & 0 deletions cli/src/test/resources/xmlmerger/ambiguous-id/target.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RunManager" selected="Application.IDEasy">
<configuration default="true" type="JUnit" factoryName="JUnit">
<shortenClasspath name="broken"/>
<option name="METHOD_NAME" value=""/>
<option name="TEST_OBJECT" value="class"/>
</configuration>
<!-- For our test we have this block duplicated -->
<configuration default="true" type="JUnit" factoryName="JUnit">
<shortenClasspath name="ARGS_FILE"/>
<option name="METHOD_NAME" value=""/>
<option name="TEST_OBJECT" value="class"/>
</configuration>
</component>
</project>
15 changes: 15 additions & 0 deletions cli/src/test/resources/xmlmerger/ambiguous-id/template.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project xmlns:merge="https://github.com/devonfw/IDEasy/merge" version="4">
<component name="RunManager">
<configuration default="true" type="JUnit" factoryName="JUnit" merge:id="configuration[@default='true' and @type='JUnit']">
<shortenClasspath name="ARGS_FILE" merge:id="name()"/>
<option name="METHOD_NAME" value=""/>
<option name="TEST_OBJECT" value="class"/>
<method v="2" merge:id="@v">
<option name="Make" enabled="true"/>
</method>
</configuration>
</component>
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level"
UseSingleDictionary="true" transferred="true"/>
</project>
1 change: 1 addition & 0 deletions documentation/variables.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ Please note that we are trying to minimize any potential side-effect from `IDEas
|*`IDE_VARIABLE_SYNTAX_LEGACY_SUPPORT_ENABLED`*|`true`|Enable/disable legacy support for devonfw-ide link:configurator.adoc[configuration templates] in IDE workspace folders.
|`ECLIPSE_VMARGS`|`-Xms128M -Xmx768M -XX:MaxPermSize=256M`|JVM options for Eclipse
|`PREFERRED_GIT_PROTOCOL`| |Allows to enforce a specific protocol for git. Options are `ssh` (for SSH) and `https`. If set any git URL will automatically be converted to the preferred protocol before IDEasy clones it. This option should only be set for individual users in `$IDE_HOME/conf/ide.properties` or `~/.ide/ide.properties` (and not in shared `settings`).
|`FAIL_ON_AMBIGOUS_MERGE`| |If set to `true` the link:configurator.adoc#element-identification[merge:id] is ambiguous and the resulting XPath expression matches multiple elements. Typically the link:usage.adoc#admin[IDE admin] did something wrong in the workspace template configuration. However, we decided to log a warning if that happens and use the first match by default to prevent our users from being blocked or annoyed in case of such configuration error. With this property you can enforce that this is handled as error aborting the merge. If that happens the user sees the stacktrace of the error and gets asked if he want to continue in order to launch his IDE (IntelliJ, Eclipse, VSCode, etc.).
|`«TOOL»_EDITION`|`«tool»`|The edition of the tool `«TOOL»` to install and use (e.g. `ECLIPSE_EDITION`, `INTELLIJ_EDITION` or `DOCKER_EDITION`). Default of `DOCKER_EDITION` is `rancher`.
|`«TOOL»_VERSION`|`*`|The version of the tool `«TOOL»` to install and use (e.g. `ECLIPSE_VERSION` or `MVN_VERSION`).
|`«TOOL»_BUILD_OPTS`| |The arguments provided to the build-tool `«TOOL»` in order to run a build. E.g.`clean install`
Expand Down