Skip to content

Commit

Permalink
#593: #651: #564: #439: fixed bugs, refactored tool dependencies (#652)
Browse files Browse the repository at this point in the history
  • Loading branch information
hohwille authored Sep 26, 2024
1 parent ad80f56 commit bacd9ea
Show file tree
Hide file tree
Showing 70 changed files with 1,116 additions and 1,097 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ Release with new features and bugfixes:
* https://github.com/devonfw/IDEasy/issues/52[#52]: Adjusting Intellij settings in ide-settings
* https://github.com/devonfw/IDEasy/issues/588[#588]: ide create installs wrong Java version
* https://github.com/devonfw/IDEasy/issues/650[#650]: Improve default success message of step
* https://github.com/devonfw/IDEasy/issues/593[#593]: Tool error reporting still buggy
* https://github.com/devonfw/IDEasy/issues/651[#651]: IDE not started in background anymore
* https://github.com/devonfw/IDEasy/issues/439[#439]: Refactor and improve tool-dependencies and tomcat
* https://github.com/devonfw/IDEasy/issues/356[#356]: Eclipse plugin installation opens an Eclipse window for each plugin installed
* https://github.com/devonfw/IDEasy/issues/655[#655]: CVE-2024-26308 and library updates

The full list of changes for this release can be found in https://github.com/devonfw/IDEasy/milestone/13?closed=1[milestone 2024.09.002].
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.devonfw.tools.ide.cli;

import com.devonfw.tools.ide.process.ProcessResult;

/**
* {@link CliException} that is thrown if a process failed (external tool executed) but we assume this is an error of the end-user.
*
* @see com.devonfw.tools.ide.process.ProcessErrorHandling#THROW_CLI
*/
public final class CliProcessException extends CliException {

private final ProcessResult processResult;

/**
* The constructor.
*/
public CliProcessException(String message, ProcessResult processResult) {

super(message, processResult.getExitCode());
this.processResult = processResult;
}

/**
* @return the {@link ProcessResult}.
*/
public ProcessResult getProcessResult() {

return this.processResult;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ private void updateSoftware() {
List<Path> softwarePaths = this.context.getFileAccess().listChildren(this.context.getSoftwarePath(), Files::isDirectory);
for (Path softwarePath : softwarePaths) {
String toolName = softwarePath.getFileName().toString();
ToolCommandlet toolCommandlet = this.context.getCommandletManager().getToolCommandletOrNull(toolName);
ToolCommandlet toolCommandlet = this.context.getCommandletManager().getToolCommandlet(toolName);
if (toolCommandlet != null) {
toolCommandlets.add(toolCommandlet);
}
Expand All @@ -158,7 +158,7 @@ private void updateSoftware() {
List<String> regularTools = IdeVariables.IDE_TOOLS.get(this.context);
if (regularTools != null) {
for (String regularTool : regularTools) {
toolCommandlets.add(this.context.getCommandletManager().getToolCommandlet(regularTool));
toolCommandlets.add(this.context.getCommandletManager().getRequiredToolCommandlet(regularTool));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ public void run() {
}

if (commandlet != null) {
commandlet.runTool(null, defaultToolOptions);
commandlet.runTool(defaultToolOptions);
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
import com.devonfw.tools.ide.property.KeywordProperty;
import com.devonfw.tools.ide.property.Property;
import com.devonfw.tools.ide.tool.ToolCommandlet;
import com.devonfw.tools.ide.tool.plugin.PluginDescriptor;
import com.devonfw.tools.ide.validation.ValidationResult;
import com.devonfw.tools.ide.validation.ValidationState;
import com.devonfw.tools.ide.version.VersionIdentifier;
Expand Down Expand Up @@ -245,7 +244,7 @@ public String toString() {

/**
* @return the {@link ToolCommandlet} set in a {@link Property} of this commandlet used for auto-completion of a {@link VersionIdentifier} or
* {@link PluginDescriptor}, otherwise {@code null} if not exists or not configured.
* {@link com.devonfw.tools.ide.tool.plugin.ToolPluginDescriptor}, otherwise {@code null} if not exists or not configured.
*/
public ToolCommandlet getToolForCompletion() {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import com.devonfw.tools.ide.property.KeywordProperty;
import com.devonfw.tools.ide.property.Property;
import com.devonfw.tools.ide.tool.LocalToolCommandlet;
import com.devonfw.tools.ide.tool.ToolCommandlet;

/**
Expand Down Expand Up @@ -37,29 +38,58 @@ public interface CommandletManager {
Collection<Commandlet> getCommandlets();

/**
* @param name the {@link Commandlet#getName() name} of the requested {@link ToolCommandlet}.
* @return the requested {@link ToolCommandlet} if found.
* @throws IllegalArgumentException if the commandlet with the given name is not a {@link ToolCommandlet}
* @param name the {@link Commandlet#getName() name} of the requested {@link Commandlet}.
* @return the requested {@link Commandlet}.
* @throws IllegalArgumentException if not found.
*/
default ToolCommandlet getToolCommandlet(String name) {
default Commandlet getRequiredCommandlet(String name) {

Commandlet commandlet = getCommandlet(name);
if (commandlet instanceof ToolCommandlet) {
return (ToolCommandlet) commandlet;
if (commandlet == null) {
throw new IllegalArgumentException("The commandlet " + name + " could not be found!");
}
throw new IllegalArgumentException("The commandlet " + name + " is not a ToolCommandlet!");
return commandlet;
}

/**
* @param name the {@link Commandlet#getName() name} of the requested {@link ToolCommandlet}.
* @return the requested {@link ToolCommandlet} or {@code null} if not found.
*/
default ToolCommandlet getToolCommandletOrNull(String name) {
default ToolCommandlet getToolCommandlet(String name) {

Commandlet commandlet = getCommandlet(name);
if (commandlet instanceof ToolCommandlet) {
return (ToolCommandlet) commandlet;
if (commandlet instanceof ToolCommandlet tc) {
return tc;
}
return null;
}

/**
* @param name the {@link Commandlet#getName() name} of the requested {@link ToolCommandlet}.
* @return the requested {@link ToolCommandlet}.
* @throws IllegalArgumentException if no {@link ToolCommandlet} exists with the given {@code name}.
*/
default ToolCommandlet getRequiredToolCommandlet(String name) {

Commandlet commandlet = getRequiredCommandlet(name);
if (commandlet instanceof ToolCommandlet tc) {
return tc;
}
throw new IllegalArgumentException("The commandlet " + name + " is not a ToolCommandlet!");
}

/**
* @param name the {@link Commandlet#getName() name} of the requested {@link LocalToolCommandlet}.
* @return the requested {@link LocalToolCommandlet}.
* @throws IllegalArgumentException if no {@link LocalToolCommandlet} exists with the given {@code name}.
*/
default LocalToolCommandlet getRequiredLocalToolCommandlet(String name) {

Commandlet commandlet = getRequiredCommandlet(name);
if (commandlet instanceof LocalToolCommandlet ltc) {
return ltc;
}
throw new IllegalArgumentException("The commandlet " + name + " is not a LocalToolCommandlet!");
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public void run() {
String plugin = this.plugin.getValue();

if (commandlet instanceof PluginBasedCommandlet cmd) {
cmd.installPlugin(cmd.getPlugin(plugin));
cmd.installPlugin(cmd.getPlugin(plugin), this.context.getCurrentStep());
} else {
context.warning("Tool {} does not support installation of plugins.", commandlet.getName());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ private void doImportRepository(Path repositoryFile, boolean forceMode) {
this.context.debug("Building repository with ide command: {}", buildCmd);
if (buildCmd != null && !buildCmd.isEmpty()) {
String[] command = buildCmd.split("\\s+");
ToolCommandlet commandlet = this.context.getCommandletManager().getToolCommandlet(command[0]);
ToolCommandlet commandlet = this.context.getCommandletManager().getRequiredToolCommandlet(command[0]);

for (int i = 1; i < command.length; i++) {
commandlet.arguments.addValue(command[i]);
Expand Down
3 changes: 3 additions & 0 deletions cli/src/main/java/com/devonfw/tools/ide/common/Tag.java
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,9 @@ public final class Tag {
/** {@link Tag} for everything related to databases. */
public static final Tag DB = create("database", ROOT);

/** {@link Tag} for administration tools. */
public static final Tag ADMIN = create("admin", ROOT);

/** {@link #Tag} for network. */
public static final Tag NETWORK = create("network", ROOT, false, "remote");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public class GitContextImpl implements GitContext {
public GitContextImpl(IdeContext context) {

this.context = context;
this.processContext = this.context.newProcess().executable("git").withEnvVar("GIT_TERMINAL_PROMPT", "0").errorHandling(ProcessErrorHandling.WARNING);
this.processContext = this.context.newProcess().executable("git").withEnvVar("GIT_TERMINAL_PROMPT", "0").errorHandling(ProcessErrorHandling.LOG_WARNING);
}

@Override
Expand Down
4 changes: 2 additions & 2 deletions cli/src/main/java/com/devonfw/tools/ide/json/JsonMapping.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.devonfw.tools.ide.json;

import com.devonfw.tools.ide.url.model.file.json.DependencyInfo;
import com.devonfw.tools.ide.url.model.file.json.ToolDependency;
import com.devonfw.tools.ide.version.VersionIdentifier;
import com.devonfw.tools.ide.version.VersionRange;
import com.fasterxml.jackson.annotation.JsonInclude;
Expand Down Expand Up @@ -29,7 +29,7 @@ public static ObjectMapper create() {
SimpleModule customModule = new SimpleModule();
customModule.addDeserializer(VersionIdentifier.class, new VersionIdentifierDeserializer());
customModule.addDeserializer(VersionRange.class, new VersionRangeDeserializer());
customModule.addDeserializer(DependencyInfo.class, new DependencyInfoDeserializer());
customModule.addDeserializer(ToolDependency.class, new ToolDependencyDeserializer());
customModule.addKeyDeserializer(VersionRange.class, new VersionRangeKeyDeserializer());
mapper = mapper.registerModule(customModule);
return mapper;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,20 @@

import java.io.IOException;

import com.devonfw.tools.ide.url.model.file.json.DependencyInfo;
import com.devonfw.tools.ide.url.model.file.json.ToolDependency;
import com.devonfw.tools.ide.version.VersionRange;
import com.fasterxml.jackson.core.JacksonException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;

/**
* {@link JsonDeserializer} for {@link DependencyInfo}.
* {@link JsonDeserializer} for {@link ToolDependency}.
*/
public class DependencyInfoDeserializer extends JsonDeserializer<DependencyInfo> {
public class ToolDependencyDeserializer extends JsonDeserializer<ToolDependency> {

@Override
public DependencyInfo deserialize(JsonParser p, DeserializationContext context) throws IOException, JacksonException {
public ToolDependency deserialize(JsonParser p, DeserializationContext context) throws IOException {

JsonToken token = p.getCurrentToken();
if (token == JsonToken.START_OBJECT) {
Expand All @@ -40,7 +39,7 @@ public DependencyInfo deserialize(JsonParser p, DeserializationContext context)
token = p.nextToken();
}
if ((tool != null) && (versionRange != null)) {
return new DependencyInfo(tool, versionRange);
return new ToolDependency(tool, versionRange);
}
}
throw new IllegalArgumentException("Invalid JSON for DependencyInfo!");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,12 @@ public interface EnvironmentContext {
*/
EnvironmentContext withPathEntry(Path path);

/**
* @return an empty instance of {@link EnvironmentContext} to prevent {@link NullPointerException}s.
*/
static EnvironmentContext getEmpty() {

return EnvironmentContextEmpty.INSTANCE;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.devonfw.tools.ide.process;

import java.nio.file.Path;

/**
* Empty implementation of {@link EnvironmentContext} used to prevent {@link NullPointerException}s.
*/
class EnvironmentContextEmpty implements EnvironmentContext {

static final EnvironmentContextEmpty INSTANCE = new EnvironmentContextEmpty();

private EnvironmentContextEmpty() {
super();
}

@Override
public EnvironmentContext withEnvVar(String key, String value) {

return this;
}

@Override
public EnvironmentContext withPathEntry(Path path) {

return this;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

import com.devonfw.tools.ide.cli.CliException;
import com.devonfw.tools.ide.cli.CliProcessException;
import com.devonfw.tools.ide.common.SystemPath;
import com.devonfw.tools.ide.context.IdeContext;
import com.devonfw.tools.ide.environment.VariableLine;
Expand Down Expand Up @@ -57,7 +57,7 @@ public ProcessContextImpl(IdeContext context) {
super();
this.context = context;
this.processBuilder = new ProcessBuilder();
this.errorHandling = ProcessErrorHandling.THROW;
this.errorHandling = ProcessErrorHandling.THROW_ERR;
Map<String, String> environment = this.processBuilder.environment();
for (VariableLine var : this.context.getVariables().collectExportedVariables()) {
if (var.isExport()) {
Expand Down Expand Up @@ -191,6 +191,9 @@ public ProcessResult run(ProcessMode processMode) {

return result;

} catch (CliProcessException | IllegalStateException e) {
// these exceptions are thrown from performLogOnError and we do not want to wrap them (see #593)
throw e;
} catch (Exception e) {
String msg = e.getMessage();
if ((msg == null) || msg.isEmpty()) {
Expand Down Expand Up @@ -311,13 +314,15 @@ private void performLogOnError(ProcessResult result, int exitCode, String interp

if (!result.isSuccessful() && (this.errorHandling != ProcessErrorHandling.NONE)) {
String message = createCommandMessage(interpreter, " failed with exit code " + exitCode + "!");
if (this.errorHandling == ProcessErrorHandling.THROW) {
throw new CliException(message, exitCode);
if (this.errorHandling == ProcessErrorHandling.THROW_CLI) {
throw new CliProcessException(message, result);
} else if (this.errorHandling == ProcessErrorHandling.THROW_ERR) {
throw new IllegalStateException(message);
}
IdeSubLogger level;
if (this.errorHandling == ProcessErrorHandling.ERROR) {
if (this.errorHandling == ProcessErrorHandling.LOG_ERROR) {
level = this.context.error();
} else if (this.errorHandling == ProcessErrorHandling.WARNING) {
} else if (this.errorHandling == ProcessErrorHandling.LOG_WARNING) {
level = this.context.warning();
} else {
level = this.context.error();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,21 @@ public enum ProcessErrorHandling {
NONE,

/** Log a warning if the status code was not successful. */
WARNING,
LOG_WARNING,

/** Log an error if the status code was not successful. */
ERROR,
LOG_ERROR,

/**
* Throw a {@link com.devonfw.tools.ide.cli.CliException} if the status code was not successful. In this case the {@link ProcessContext#run() run} method will
* never return an exit code other than {@link ProcessResult#SUCCESS} as otherwise an exception is thrown preventing the method to return.
*/
THROW_CLI,

/**
* Throw an exception if the status code was not successful. In this case the {@link ProcessContext#run() run} method will never return an exit code other
* than {@link ProcessResult#SUCCESS} as otherwise an exception is thrown preventing the method to return.
*/
THROW
THROW_ERR

}
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
import com.devonfw.tools.ide.context.IdeContext;
import com.devonfw.tools.ide.tool.ToolCommandlet;
import com.devonfw.tools.ide.tool.plugin.PluginBasedCommandlet;
import com.devonfw.tools.ide.tool.plugin.PluginDescriptor;
import com.devonfw.tools.ide.tool.plugin.PluginMaps;
import com.devonfw.tools.ide.tool.plugin.ToolPluginDescriptor;
import com.devonfw.tools.ide.tool.plugin.ToolPlugins;
import com.devonfw.tools.ide.validation.PropertyValidator;

/**
Expand Down Expand Up @@ -56,11 +56,11 @@ public String parse(String valueAsString, IdeContext context) {
protected void completeValue(String arg, IdeContext context, Commandlet commandlet, CompletionCandidateCollector collector) {

ToolCommandlet cmd = commandlet.getToolForCompletion();
if (cmd instanceof PluginBasedCommandlet) {
PluginMaps pluginMap = ((PluginBasedCommandlet) cmd).getPluginsMap();
for (PluginDescriptor pluginDescriptor : pluginMap.getPlugins()) {
if (pluginDescriptor.getName().toLowerCase().startsWith(arg.toLowerCase())) {
collector.add(pluginDescriptor.getName(), null, null, commandlet);
if (cmd instanceof PluginBasedCommandlet pbc) {
ToolPlugins plugins = pbc.getPlugins();
for (ToolPluginDescriptor pluginDescriptor : plugins.getPlugins()) {
if (pluginDescriptor.name().toLowerCase().startsWith(arg.toLowerCase())) {
collector.add(pluginDescriptor.name(), null, null, commandlet);
}
}
}
Expand Down
Loading

0 comments on commit bacd9ea

Please sign in to comment.