Task summary
We already support tool dependencies via dependencies.json files from ide-urls.
This is properly handled here:
|
public ToolInstallation installAsDependency(VersionRange versionRange, ToolInstallRequest parentRequest) { |
|
ToolInstallRequest request = new ToolInstallRequest(parentRequest); |
|
ToolEditionAndVersion requested = new ToolEditionAndVersion(getToolWithConfiguredEdition()); |
|
request.setRequested(requested); |
|
VersionIdentifier configuredVersion = getConfiguredVersion(); |
|
if (versionRange.contains(configuredVersion)) { |
|
// prefer configured version if contained in version range |
|
requested.setVersion(configuredVersion); |
|
// return install(true, configuredVersion, processContext, null); |
|
return install(request); |
|
} else { |
|
if (isIgnoreSoftwareRepo()) { |
|
throw new IllegalStateException( |
|
"Cannot satisfy dependency to " + this.tool + " in version " + versionRange + " for " + parentRequest.getRequested() |
|
+ " since it is conflicting with configured version " |
|
+ configuredVersion |
|
+ " and this tool does not support the software repository."); |
|
} |
|
LOG.info( |
|
"The tool {} requires {} in the version range {}, but your project uses version {}, which does not match." |
|
+ " Therefore, we install a compatible version in that range.", |
|
parentRequest.getRequested().getEdition(), this.tool, versionRange, configuredVersion); |
|
requested.setVersion(versionRange); |
|
return installTool(request); |
|
} |
|
} |
As we can see we are creating a ToolInstallationRequest for the dependent installation as a child that is connected to the parent ToolInstallationRequest.
This way we can properly detect cycles in dependent installations that could lead to infinity loops:
|
public ToolInstallation installTool(ToolInstallRequest request) { |
|
|
|
completeRequest(request); // most likely already done, but if installTool was called directly and not from install |
|
if (request.isInstallLoop()) { |
|
return toolAlreadyInstalled(request); |
|
} |
However, we also have PackageManagerBasedLocalToolCommandlet that implicitly causes a dependency to the package-manager (e.g. npm or pip).
Here we had infinity loop bugs causing stack-overflow errors in tests.
As a hackish quickfix we have this:
|
public ProcessResult runPackageManager(PackageManagerRequest request, boolean skipInstallation) { |
|
|
|
completeRequest(request); |
|
ProcessContext pc = request.getProcessContext(); |
|
ToolCommandlet pm = request.getPackageManager(); |
|
if (!skipInstallation) { // See Node.postInstallOnNewInstallation |
|
ToolInstallRequest installRequest = new ToolInstallRequest(true); |
|
installRequest.setProcessContext(pc.createChild()); |
|
pm.install(installRequest); |
|
} |
|
return pm.runTool(pc, request.getProcessMode(), request.getArgs()); |
|
} |
and:
|
ProcessResult result = npm.runPackageManager(packageManagerRequest, true); |
The idea of this story is to improve this and create a clean solution replacing the hack.
The problem is actually already visible to end-users via our logs:
$ ide install nest
No CVEs found for version 11.15.0 of tool npm.
No CVEs found for version v24.15.0 of tool node.
...
No CVEs found for version 11.0.21 of tool nest.
No CVEs found for version 11.15.0 of tool npm.
No CVEs found for version v24.15.0 of tool node.
...
Successfully installed nest in version 11.0.21 replacing previous version v24.15.0 of nest at D:\projects\test\software\node
So still we see that installation of npm and node was called twice because loop was not detected.
After this issue was fixed we should only see:
$ ide install nest
No CVEs found for version 11.15.0 of tool npm.
No CVEs found for version v24.15.0 of tool node.
...
No CVEs found for version 11.0.21 of tool nest.
...
Successfully installed nest in version v24.15.0 of nest at D:\projects\test\software\node
Additional context
In order to implement a clean fix we would somehow refactor PackageManagerRequest to somehow be compatbile with ToolInstallRequest or to have the ability to contain a ToolInstallRequest as a parent.
Then we could use the same chaining and loop detection fixing this issue.
Task summary
We already support tool dependencies via
dependencies.jsonfiles fromide-urls.This is properly handled here:
IDEasy/cli/src/main/java/com/devonfw/tools/ide/tool/LocalToolCommandlet.java
Lines 276 to 301 in 5cf051a
As we can see we are creating a
ToolInstallationRequestfor the dependent installation as a child that is connected to the parentToolInstallationRequest.This way we can properly detect cycles in dependent installations that could lead to infinity loops:
IDEasy/cli/src/main/java/com/devonfw/tools/ide/tool/LocalToolCommandlet.java
Lines 158 to 163 in 5cf051a
However, we also have
PackageManagerBasedLocalToolCommandletthat implicitly causes a dependency to the package-manager (e.g.npmorpip).Here we had infinity loop bugs causing stack-overflow errors in tests.
As a hackish quickfix we have this:
IDEasy/cli/src/main/java/com/devonfw/tools/ide/tool/PackageManagerBasedLocalToolCommandlet.java
Lines 88 to 99 in 5cf051a
and:
IDEasy/cli/src/main/java/com/devonfw/tools/ide/tool/node/Node.java
Line 47 in 5cf051a
The idea of this story is to improve this and create a clean solution replacing the hack.
The problem is actually already visible to end-users via our logs:
So still we see that installation of
npmandnodewas called twice because loop was not detected.After this issue was fixed we should only see:
Additional context
In order to implement a clean fix we would somehow refactor
PackageManagerRequestto somehow be compatbile withToolInstallRequestor to have the ability to contain aToolInstallRequestas a parent.Then we could use the same chaining and loop detection fixing this issue.