diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index eac1f6acbc..68dbedcf99 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -6,6 +6,7 @@ This file documents all notable changes to https://github.com/devonfw/IDEasy[IDE Release with new features and bugfixes: +* https://github.com/devonfw/IDEasy/issues/1713[#1713]: Advanced logging and writing logfiles The full list of changes for this release can be found in https://github.com/devonfw/IDEasy/milestone/41?closed=1[milestone 2026.03.001]. diff --git a/cli/pom.xml b/cli/pom.xml index 894134a1c2..1609facee8 100644 --- a/cli/pom.xml +++ b/cli/pom.xml @@ -49,11 +49,6 @@ slf4j-api - - ch.qos.logback - logback-classic - - org.graalvm.sdk nativeimage diff --git a/cli/src/main/java/com/devonfw/tools/ide/cli/Ideasy.java b/cli/src/main/java/com/devonfw/tools/ide/cli/Ideasy.java index eabbde615c..6f508ee919 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/cli/Ideasy.java +++ b/cli/src/main/java/com/devonfw/tools/ide/cli/Ideasy.java @@ -3,12 +3,15 @@ import java.net.URLEncoder; import java.nio.charset.StandardCharsets; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.commandlet.ContextCommandlet; import com.devonfw.tools.ide.context.AbstractIdeContext; import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.context.IdeContextConsole; import com.devonfw.tools.ide.context.IdeStartContextImpl; -import com.devonfw.tools.ide.log.IdeLogLevel; +import com.devonfw.tools.ide.log.JulLogLevel; import com.devonfw.tools.ide.property.FlagProperty; import com.devonfw.tools.ide.property.Property; @@ -17,6 +20,8 @@ */ public final class Ideasy { + private static final Logger LOG = LoggerFactory.getLogger(Ideasy.class); + private AbstractIdeContext context; /** @@ -37,15 +42,6 @@ public Ideasy() { this.context = context; } - private IdeContext context() { - - if (this.context == null) { - // fallback in case of exception before initialization - return new IdeContextConsole(IdeLogLevel.INFO, null, false); - } - return this.context; - } - /** * Non-static variant of {@link #main(String...) main method} without invoking {@link System#exit(int)} so it can be tested. * @@ -61,7 +57,7 @@ public int run(String... args) { exitStatus = error.getExitCode(); String errorMessage = error.getMessage(); if ((errorMessage != null) && !errorMessage.isBlank()) { - context().error(errorMessage); + LOG.error(errorMessage); } } catch (Throwable error) { exitStatus = 255; @@ -77,7 +73,7 @@ public int run(String... args) { + "If the error is not on your end (network connectivity, lack of permissions, etc.) please file a bug:\n" // + "https://github.com/devonfw/IDEasy/issues/new?template=bug_report.yml&title=" + URLEncoder.encode(title, StandardCharsets.UTF_8); - context().error(error, message); + LOG.error(message, error); } return exitStatus; } @@ -97,7 +93,11 @@ public int runOrThrow(String... args) { private void initContext(CliArguments arguments) { - ContextCommandlet contextCommandlet = new ContextCommandlet(); + IdeStartContextImpl startContext = null; + if (this.context != null) { + startContext = this.context.getStartContext(); + } + ContextCommandlet contextCommandlet = new ContextCommandlet(startContext); while (arguments.hasNext()) { CliArgument current = arguments.next(); String key = current.getKey(); @@ -118,7 +118,7 @@ private void initContext(CliArguments arguments) { } contextCommandlet.run(); if (this.context == null) { - IdeStartContextImpl startContext = contextCommandlet.getStartContext(); + startContext = contextCommandlet.getStartContext(); this.context = new IdeContextConsole(startContext); } } @@ -130,6 +130,7 @@ private void initContext(CliArguments arguments) { */ public static void main(String... args) { + JulLogLevel.init(); int exitStatus = new Ideasy().run(args); System.exit(exitStatus); } diff --git a/cli/src/main/java/com/devonfw/tools/ide/commandlet/AbstractUpdateCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/commandlet/AbstractUpdateCommandlet.java index aa1bb59204..68096a6bf9 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/commandlet/AbstractUpdateCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/commandlet/AbstractUpdateCommandlet.java @@ -9,6 +9,9 @@ import java.util.Set; import java.util.stream.Stream; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.cli.CliException; import com.devonfw.tools.ide.context.AbstractIdeContext; import com.devonfw.tools.ide.context.IdeContext; @@ -38,6 +41,8 @@ */ public abstract class AbstractUpdateCommandlet extends Commandlet { + private static final Logger LOG = LoggerFactory.getLogger(AbstractUpdateCommandlet.class); + private static final String MESSAGE_CODE_REPO_URL = """ No code repository was given after '--code'. Further details can be found here: https://github.com/devonfw/IDEasy/blob/main/documentation/settings.adoc @@ -85,7 +90,7 @@ public AbstractUpdateCommandlet(IdeContext context) { } @Override - public void run() { + protected void doRun() { IdeStartContextImpl startContext = ((AbstractIdeContext) this.context).getStartContext(); startContext.setForcePull(forcePull.isTrue()); @@ -116,7 +121,7 @@ private void updateConf() { if (Files.exists(legacyTemplatesFolder)) { templatesFolder = legacyTemplatesFolder; } else { - this.context.warning("Templates folder is missing in settings repository."); + LOG.warn("Templates folder is missing in settings repository."); return; } } @@ -141,10 +146,10 @@ private void setupConf(Path template, Path conf) { setupConf(child, confPath); } else if (Files.isRegularFile(child)) { if (Files.isRegularFile(confPath)) { - this.context.debug("Configuration {} already exists - skipping to copy from {}", confPath, child); + LOG.debug("Configuration {} already exists - skipping to copy from {}", confPath, child); } else { if (!basename.equals("settings.xml")) { - this.context.info("Copying template {} to {}.", child, conf); + LOG.info("Copying template {} to {}.", child, conf); this.context.getFileAccess().copy(child, conf); } } @@ -175,7 +180,7 @@ private void updateSettingsInStep() { gitContext.pull(settingsPath); this.context.getGitContext().saveCurrentCommitId(settingsPath, this.context.getSettingsCommitIdPath()); } else { - this.context.info("Skipping git pull in settings due to code repository. Use --force-pull to enforce pulling."); + LOG.info("Skipping git pull in settings due to code repository. Use --force-pull to enforce pulling."); } } else { GitUrl gitUrl = getOrAskSettingsUrl(); @@ -193,11 +198,11 @@ private GitUrl getOrAskSettingsUrl() { if (isCodeRepository()) { userPromt = "Code repository URL:"; defaultUrl = null; - this.context.info(MESSAGE_CODE_REPO_URL); + LOG.info(MESSAGE_CODE_REPO_URL); } else { userPromt = "Settings URL [" + IdeContext.DEFAULT_SETTINGS_REPO_URL + "]:"; defaultUrl = IdeContext.DEFAULT_SETTINGS_REPO_URL; - this.context.info(MESSAGE_SETTINGS_REPO_URL, this.context.getSettingsPath()); + LOG.info(MESSAGE_SETTINGS_REPO_URL, this.context.getSettingsPath()); } GitUrl gitUrl = null; if (repository != null) { @@ -208,7 +213,7 @@ private GitUrl getOrAskSettingsUrl() { repository = handleDefaultRepository(repository); gitUrl = GitUrl.of(repository); if (!gitUrl.isValid()) { - this.context.warning("The input URL is not valid, please try again."); + LOG.warn("The input URL is not valid, please try again."); } } return gitUrl; @@ -217,10 +222,10 @@ private GitUrl getOrAskSettingsUrl() { private String handleDefaultRepository(String repository) { if ("-".equals(repository)) { if (isCodeRepository()) { - this.context.warning("'-' is found after '--code'. This is invalid."); + LOG.warn("'-' is found after '--code'. This is invalid."); repository = null; } else { - this.context.info("'-' was found for settings repository, the default settings repository '{}' will be used.", IdeContext.DEFAULT_SETTINGS_REPO_URL); + LOG.info("'-' was found for settings repository, the default settings repository '{}' will be used.", IdeContext.DEFAULT_SETTINGS_REPO_URL); repository = IdeContext.DEFAULT_SETTINGS_REPO_URL; } } @@ -275,7 +280,7 @@ private void initializeRepository(GitUrl gitUrl) { private void updateSoftware() { if (this.skipTools.isTrue()) { - this.context.info("Skipping installation/update of tools as specified by the user."); + LOG.info("Skipping installation/update of tools as specified by the user."); return; } Step step = this.context.newStep("Install or update software"); @@ -303,7 +308,7 @@ private void doUpdateSoftwareStep(Step step) { ToolCommandlet toolCommandlet = commandletManager.getToolCommandlet(regularTool); if (toolCommandlet == null) { String displayName = (regularTool == null || regularTool.isBlank()) ? "" : "'" + regularTool + "'"; - this.context.error("Cannot install or update tool '{}''. No matching commandlet found. Please check your IDE_TOOLS configuration.", displayName); + LOG.error("Cannot install or update tool '{}''. No matching commandlet found. Please check your IDE_TOOLS configuration.", displayName); } else { toolCommandlets.add(toolCommandlet); } @@ -324,7 +329,7 @@ private void doUpdateSoftwareStep(Step step) { ExtraTools extraTools = ExtraToolsMapper.get().loadJsonFromFolder(this.context.getSettingsPath()); if (extraTools != null) { List toolNames = extraTools.getSortedToolNames(); - this.context.info("Found extra installation of the following tools: {}", toolNames); + LOG.info("Found extra installation of the following tools: {}", toolNames); for (String tool : toolNames) { List installations = extraTools.getExtraInstallations(tool); this.context.newStep("Install extra version(s) of " + tool).run(() -> installExtraToolInstallations(tool, installations)); @@ -358,9 +363,9 @@ private void updateRepositories() { if (this.skipRepositories.isTrue()) { if (this.forceRepositories.isTrue()) { - this.context.warning("Options to skip and force repositories are incompatible and should not be combined. Ignoring --force-repositories to proceed."); + LOG.warn("Options to skip and force repositories are incompatible and should not be combined. Ignoring --force-repositories to proceed."); } - this.context.info("Skipping setup of repositories as specified by the user."); + LOG.info("Skipping setup of repositories as specified by the user."); return; } RepositoryCommandlet repositoryCommandlet = this.context.getCommandletManager().getCommandlet(RepositoryCommandlet.class); @@ -372,13 +377,13 @@ private void createStartScripts() { List ides = IdeVariables.CREATE_START_SCRIPTS.get(this.context); if (ides == null) { - this.context.info("Variable CREATE_START_SCRIPTS is undefined - skipping start script creation."); + LOG.info("Variable CREATE_START_SCRIPTS is undefined - skipping start script creation."); return; } for (String ide : ides) { ToolCommandlet tool = this.context.getCommandletManager().getToolCommandlet(ide); if (tool == null) { - this.context.error("Undefined IDE '{}' configured in variable CREATE_START_SCRIPTS."); + LOG.error("Undefined IDE '{}' configured in variable CREATE_START_SCRIPTS.", ide); } else { createStartScript(ide); } @@ -387,7 +392,7 @@ private void createStartScripts() { private void createStartScript(String ide) { - this.context.info("Creating start scripts for {}", ide); + LOG.info("Creating start scripts for {}", ide); Path workspaces = this.context.getIdeHome().resolve(IdeContext.FOLDER_WORKSPACES); try (Stream childStream = Files.list(workspaces)) { Iterator iterator = childStream.iterator(); diff --git a/cli/src/main/java/com/devonfw/tools/ide/commandlet/AbstractVersionOrEditionGetCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/commandlet/AbstractVersionOrEditionGetCommandlet.java index 5fa05edbca..b387e884a7 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/commandlet/AbstractVersionOrEditionGetCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/commandlet/AbstractVersionOrEditionGetCommandlet.java @@ -2,10 +2,12 @@ import java.util.Objects; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.cli.CliException; import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.log.IdeLogLevel; -import com.devonfw.tools.ide.log.IdeSubLogger; import com.devonfw.tools.ide.property.FlagProperty; import com.devonfw.tools.ide.property.ToolProperty; import com.devonfw.tools.ide.tool.ToolCommandlet; @@ -17,6 +19,8 @@ */ public abstract class AbstractVersionOrEditionGetCommandlet extends Commandlet { + private static final Logger LOG = LoggerFactory.getLogger(AbstractVersionOrEditionGetCommandlet.class); + /** The tool to get the version of. */ public final ToolProperty tool; @@ -68,10 +72,10 @@ public boolean isProcessableOutput() { protected abstract Object getInstalledValue(ToolCommandlet commandlet); @Override - public void run() { + protected void doRun() { ToolCommandlet commandlet = this.tool.getValue(); - IdeSubLogger logger = this.context.level(IdeLogLevel.PROCESSABLE); + IdeLogLevel level = IdeLogLevel.PROCESSABLE; Object configuredValue = getConfiguredValue(commandlet); Object installedValue = getInstalledValue(commandlet); boolean getInstalledValue = this.installed.isTrue(); @@ -81,42 +85,43 @@ public void run() { } if (getInstalledValue == getConfiguredValue) { if (getInstalledValue) { // both --configured and --installed - logToolInfo(logger, commandlet, configuredValue, installedValue); - } else if (this.context.debug().isEnabled()) { - logToolInfo(logger, commandlet, configuredValue, installedValue); + logToolInfo(commandlet, configuredValue, installedValue); + } else if (LOG.isDebugEnabled()) { + logToolInfo(commandlet, configuredValue, installedValue); } else { if (installedValue == null) { - logger.log(configuredValue.toString()); + level.log(LOG, configuredValue.toString()); } else { - logger.log(installedValue.toString()); + level.log(LOG, installedValue.toString()); } } } else { if (getInstalledValue) { if (installedValue == null) { - logToolInfo(logger, commandlet, configuredValue, null); + logToolInfo(commandlet, configuredValue, null); } else { - logger.log(installedValue.toString()); + level.log(LOG, installedValue.toString()); } } else { - logger.log(configuredValue.toString()); + level.log(LOG, configuredValue.toString()); } } } - private void logToolInfo(IdeSubLogger logger, ToolCommandlet commandlet, Object configuredValue, Object installedValue) { + private void logToolInfo(ToolCommandlet commandlet, Object configuredValue, Object installedValue) { String property = getPropertyToGet(); String toolName = commandlet.getName(); + IdeLogLevel level = IdeLogLevel.PROCESSABLE; if (installedValue == null) { - logger.log("No installation of tool {} was found.", toolName); + level.log(LOG, "No installation of tool {} was found.", toolName); } else { - logger.log("The installed {} for tool {} is {}", property, toolName, installedValue); + level.log(LOG, "The installed {} for tool {} is {}", property, toolName, installedValue); } - logger.log("The configured {} for tool {} is {}", property, toolName, configuredValue); + level.log(LOG, "The configured {} for tool {} is {}", property, toolName, configuredValue); if (!Objects.equals(configuredValue, installedValue)) { - logger.log("To install the configured {} call the following command:", property); - logger.log("ide install {}", toolName); + level.log(LOG, "To install the configured {} call the following command:", property); + level.log(LOG, "ide install {}", toolName); } } diff --git a/cli/src/main/java/com/devonfw/tools/ide/commandlet/BuildCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/commandlet/BuildCommandlet.java index 968b259c2a..99c7c131de 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/commandlet/BuildCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/commandlet/BuildCommandlet.java @@ -42,7 +42,7 @@ public String getName() { } @Override - public void run() { + protected void doRun() { Path buildPath = this.context.getCwd(); diff --git a/cli/src/main/java/com/devonfw/tools/ide/commandlet/Commandlet.java b/cli/src/main/java/com/devonfw/tools/ide/commandlet/Commandlet.java index 8ad3176347..76dd91ebe8 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/commandlet/Commandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/commandlet/Commandlet.java @@ -7,6 +7,7 @@ import java.util.Map; import java.util.Objects; +import com.devonfw.tools.ide.context.AbstractIdeContext; import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.nls.NlsBundle; import com.devonfw.tools.ide.property.KeywordProperty; @@ -212,10 +213,26 @@ public boolean isProcessableOutput() { return false; } + /** + * @return {@code true} to write a logfile (unless disabled via {@link com.devonfw.tools.ide.variable.IdeVariables#IDE_WRITE_LOGFILE}), {@code false} + * otherwise. + */ + public boolean isWriteLogFile() { + return !isProcessableOutput(); + } + /** * Runs this {@link Commandlet}. */ - public abstract void run(); + public final void run() { + + if (this.context != null) { // for ContextCommandlet we do not have a context yet + ((AbstractIdeContext) this.context).configureJavaUtilLogging(this); + } + doRun(); + } + + protected abstract void doRun(); /** * @return {@code true} if this {@link Commandlet} is the valid candidate to be {@link #run()}, {@code false} otherwise. diff --git a/cli/src/main/java/com/devonfw/tools/ide/commandlet/CommandletManagerImpl.java b/cli/src/main/java/com/devonfw/tools/ide/commandlet/CommandletManagerImpl.java index 87be7ca2f8..ed9083e5af 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/commandlet/CommandletManagerImpl.java +++ b/cli/src/main/java/com/devonfw/tools/ide/commandlet/CommandletManagerImpl.java @@ -8,6 +8,9 @@ import java.util.Map; import java.util.NoSuchElementException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.cli.CliArgument; import com.devonfw.tools.ide.cli.CliArguments; import com.devonfw.tools.ide.completion.CompletionCandidateCollector; @@ -58,6 +61,8 @@ */ public class CommandletManagerImpl implements CommandletManager { + private static final Logger LOG = LoggerFactory.getLogger(CommandletManagerImpl.class); + private final IdeContext context; private final Map, Commandlet> commandletTypeMap; @@ -184,7 +189,7 @@ private void registerKeyword(String keyword, Commandlet commandlet) { Commandlet duplicate = this.firstKeywordMap.putIfAbsent(keyword, commandlet); if (duplicate != null) { - this.context.debug("Duplicate keyword {} already used by {} so it cannot be associated also with {}", keyword, duplicate, commandlet); + LOG.debug("Duplicate keyword {} already used by {} so it cannot be associated also with {}", keyword, duplicate, commandlet); } } @@ -288,7 +293,7 @@ private Commandlet findNext() { if (properties.isEmpty()) { assert false : cmd.getClass().getSimpleName() + " has no properties!"; } else { - Property property = properties.get(0); + Property property = properties.getFirst(); if (property instanceof KeywordProperty) { boolean matches = property.apply(arguments.copy(), context, cmd, this.collector); if (matches) { diff --git a/cli/src/main/java/com/devonfw/tools/ide/commandlet/CompleteCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/commandlet/CompleteCommandlet.java index c588464e19..ec16ac4fa1 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/commandlet/CompleteCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/commandlet/CompleteCommandlet.java @@ -47,7 +47,7 @@ public boolean isProcessableOutput() { } @Override - public void run() { + protected void doRun() { CliArguments arguments = CliArguments.ofCompletion(this.args.asArray()); List candidates = ((AbstractIdeContext) this.context).complete(arguments, true); diff --git a/cli/src/main/java/com/devonfw/tools/ide/commandlet/ContextCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/commandlet/ContextCommandlet.java index 1858430624..da9903c314 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/commandlet/ContextCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/commandlet/ContextCommandlet.java @@ -5,7 +5,6 @@ import com.devonfw.tools.ide.context.IdeStartContextImpl; import com.devonfw.tools.ide.log.IdeLogLevel; import com.devonfw.tools.ide.log.IdeLogListenerBuffer; -import com.devonfw.tools.ide.log.IdeSubLoggerOut; import com.devonfw.tools.ide.property.FlagProperty; import com.devonfw.tools.ide.property.LocaleProperty; @@ -40,8 +39,16 @@ public class ContextCommandlet extends Commandlet { * The constructor. */ public ContextCommandlet() { + this(null); + } + + /** + * The constructor. + */ + public ContextCommandlet(IdeStartContextImpl startContext) { super(null); + this.startContext = startContext; this.batch = add(new FlagProperty("--batch", false, "-b")); this.force = add(new FlagProperty("--force", false, "-f")); this.trace = add(new FlagProperty("--trace", false, "-t")); @@ -67,12 +74,18 @@ public boolean isIdeHomeRequired() { } @Override - public void run() { + public boolean isWriteLogFile() { + + return false; + } + + @Override + protected void doRun() { IdeLogLevel logLevel = determineLogLevel(); if (this.startContext == null) { IdeLogListenerBuffer listener = new IdeLogListenerBuffer(); - this.startContext = new IdeStartContextImpl(logLevel, level -> new IdeSubLoggerOut(level, null, true, logLevel, listener)); + this.startContext = new IdeStartContextImpl(logLevel, listener); } else if (this.context != null) { IdeStartContextImpl newStartContext = ((AbstractIdeContext) this.context).getStartContext(); assert (this.startContext == newStartContext); // fast fail during development via assert diff --git a/cli/src/main/java/com/devonfw/tools/ide/commandlet/CreateCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/commandlet/CreateCommandlet.java index 446f25fa21..deb031459d 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/commandlet/CreateCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/commandlet/CreateCommandlet.java @@ -4,8 +4,12 @@ import java.nio.file.Path; import java.util.function.Predicate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.io.FileAccess; +import com.devonfw.tools.ide.log.IdeLogLevel; import com.devonfw.tools.ide.property.FlagProperty; import com.devonfw.tools.ide.property.StringProperty; import com.devonfw.tools.ide.version.IdeVersion; @@ -15,6 +19,8 @@ */ public class CreateCommandlet extends AbstractUpdateCommandlet { + private static final Logger LOG = LoggerFactory.getLogger(CreateCommandlet.class); + /** {@link StringProperty} for the name of the new project */ public final StringProperty newProject; @@ -47,14 +53,14 @@ public boolean isIdeHomeRequired() { } @Override - public void run() { + protected void doRun() { String newProjectName = this.newProject.getValue(); Path newProjectPath = this.context.getIdeRoot().resolve(newProjectName); - this.context.info("Creating new IDEasy project in {}", newProjectPath); + LOG.info("Creating new IDEasy project in {}", newProjectPath); if (!this.context.getFileAccess().isEmptyDir(newProjectPath)) { - this.context.askToContinue("Directory " + newProjectPath + " already exists. Do you want to continue?"); + this.context.askToContinue("Directory {} already exists. Do you want to continue?", newProjectPath); } else { this.context.getFileAccess().mkdirs(newProjectPath); } @@ -62,10 +68,10 @@ public void run() { initializeProject(newProjectPath); this.context.setIdeHome(newProjectPath); this.context.verifyIdeMinVersion(true); - super.run(); + super.doRun(); this.context.verifyIdeMinVersion(true); this.context.getFileAccess().writeFileContent(IdeVersion.getVersionString(), newProjectPath.resolve(IdeContext.FILE_SOFTWARE_VERSION)); - this.context.success("Successfully created new project '{}'.", newProjectName); + IdeLogLevel.SUCCESS.log(LOG, "Successfully created new project '{}'.", newProjectName); logWelcomeMessage(); } @@ -95,7 +101,7 @@ private void logWelcomeMessage() { Predicate welcomePredicate = path -> String.valueOf(path.getFileName()).startsWith("welcome."); Path welcomeFilePath = this.context.getFileAccess().findFirst(settingsFolder, welcomePredicate, false); if (welcomeFilePath != null) { - this.context.info(this.context.getFileAccess().readFileContent(welcomeFilePath)); + LOG.info(this.context.getFileAccess().readFileContent(welcomeFilePath)); } } } diff --git a/cli/src/main/java/com/devonfw/tools/ide/commandlet/EditionListCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/commandlet/EditionListCommandlet.java index eea3a261b5..4385317186 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/commandlet/EditionListCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/commandlet/EditionListCommandlet.java @@ -33,7 +33,13 @@ public String getName() { } @Override - public void run() { + public boolean isWriteLogFile() { + + return false; + } + + @Override + protected void doRun() { ToolCommandlet commandlet = this.tool.getValue(); commandlet.listEditions(); diff --git a/cli/src/main/java/com/devonfw/tools/ide/commandlet/EditionSetCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/commandlet/EditionSetCommandlet.java index 4ca8d81e36..08cbfdea7c 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/commandlet/EditionSetCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/commandlet/EditionSetCommandlet.java @@ -41,7 +41,7 @@ public String getName() { } @Override - public void run() { + protected void doRun() { ToolCommandlet commandlet = this.tool.getValue(); String edition = this.edition.getValue(); diff --git a/cli/src/main/java/com/devonfw/tools/ide/commandlet/EnvironmentCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/commandlet/EnvironmentCommandlet.java index 86b640374f..7a1df72bee 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/commandlet/EnvironmentCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/commandlet/EnvironmentCommandlet.java @@ -5,6 +5,9 @@ import java.util.Map; import java.util.stream.Collectors; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.cli.CliExitException; import com.devonfw.tools.ide.context.AbstractIdeContext; import com.devonfw.tools.ide.context.IdeContext; @@ -12,7 +15,6 @@ import com.devonfw.tools.ide.environment.VariableLine; import com.devonfw.tools.ide.environment.VariableSource; import com.devonfw.tools.ide.log.IdeLogLevel; -import com.devonfw.tools.ide.log.IdeSubLogger; import com.devonfw.tools.ide.os.WindowsPathSyntax; import com.devonfw.tools.ide.process.EnvironmentContext; import com.devonfw.tools.ide.process.EnvironmentVariableCollectorContext; @@ -26,6 +28,8 @@ */ public final class EnvironmentCommandlet extends Commandlet { + private static final Logger LOG = LoggerFactory.getLogger(EnvironmentCommandlet.class); + /** {@link FlagProperty} to enable Bash (MSys) path conversion on Windows. */ public final FlagProperty bash; @@ -60,14 +64,13 @@ public boolean isProcessableOutput() { } @Override - public void run() { + protected void doRun() { if (this.context.getIdeHome() == null) { throw new CliExitException(); } boolean winCmd = false; WindowsPathSyntax pathSyntax = null; - IdeSubLogger logger = this.context.level(IdeLogLevel.PROCESSABLE); if (this.context.getSystemInfo().isWindows()) { if (this.bash.isTrue()) { pathSyntax = WindowsPathSyntax.MSYS; @@ -85,11 +88,11 @@ public void run() { new VariableSource(EnvironmentVariablesType.TOOL, this.context.getSoftwarePath()), pathSyntax); setEnvironmentVariablesInLocalTools(environmentVariableCollectorContext); - printLines(variableMap, logger, winCmd); + printLines(variableMap, winCmd); } - private void printLines(Map variableMap, IdeSubLogger logger, boolean winCmd) { - if (this.context.debug().isEnabled()) { + private void printLines(Map variableMap, boolean winCmd) { + if (LOG.isDebugEnabled()) { Map> type2lines = variableMap.values().stream().collect(Collectors.groupingBy(l -> l.getSource().type())); for (EnvironmentVariablesType type : EnvironmentVariablesType.values()) { List lines = type2lines.get(type); @@ -98,10 +101,10 @@ private void printLines(Map variableMap, IdeSubLogger logg sortVariables(lines); for (VariableLine line : lines) { if (!sourcePrinted) { - this.context.debug("from {}:", line.getSource()); + LOG.debug("from {}:", line.getSource()); sourcePrinted = true; } - logger.log(format(line, winCmd)); + IdeLogLevel.PROCESSABLE.log(LOG, format(line, winCmd)); } } } @@ -109,7 +112,7 @@ private void printLines(Map variableMap, IdeSubLogger logg List variables = new ArrayList<>(variableMap.values()); sortVariables(variables); for (VariableLine line : variables) { - logger.log(format(line, winCmd)); + IdeLogLevel.PROCESSABLE.log(LOG, format(line, winCmd)); } } } @@ -144,7 +147,7 @@ private void setEnvironmentVariablesInLocalTools(EnvironmentContext environmentC tool.setEnvironment(environmentContext, toolInstallation, false); } } catch (Exception e) { - this.context.warning("An error occurred while setting the environment variables in local tools:", e); + LOG.warn("An error occurred while setting the environment variables in local tools:", e); } } } diff --git a/cli/src/main/java/com/devonfw/tools/ide/commandlet/HelpCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/commandlet/HelpCommandlet.java index 0cadd0c722..1a655f7444 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/commandlet/HelpCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/commandlet/HelpCommandlet.java @@ -4,9 +4,12 @@ import java.util.Collections; import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.devonfw.tools.ide.context.AbstractIdeContext; import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.log.IdeLogLevel; -import com.devonfw.tools.ide.log.IdeSubLogger; import com.devonfw.tools.ide.nls.NlsBundle; import com.devonfw.tools.ide.property.CommandletProperty; import com.devonfw.tools.ide.property.KeywordProperty; @@ -19,6 +22,8 @@ */ public final class HelpCommandlet extends Commandlet { + private static final Logger LOG = LoggerFactory.getLogger(HelpCommandlet.class); + /** The optional commandlet to get help about. */ public final CommandletProperty commandlet; @@ -46,37 +51,43 @@ public boolean isIdeRootRequired() { return false; } + @Override + public boolean isWriteLogFile() { + + return false; + } @Override - public void run() { + protected void doRun() { this.context.printLogo(); NlsBundle bundle = NlsBundle.of(this.context); - this.context.success(bundle.get("version-banner"), IdeVersion.getVersionString()); + IdeLogLevel.SUCCESS.log(LOG, bundle.get("version-banner"), IdeVersion.getVersionString()); Commandlet cmd = this.commandlet.getValue(); if (cmd == null) { - this.context.info(bundle.get("usage") + " ide [option]* [[commandlet] [arg]*]"); - this.context.info(""); + String usage = bundle.get("usage") + " ide [option]* [[commandlet] [arg]*]"; + LOG.info(usage); + LOG.info(""); printCommandlets(bundle); } else { printCommandletHelp(bundle, cmd); } - this.context.info(""); - this.context.info(bundle.get("options")); + LOG.info(""); + LOG.info(bundle.get("options")); Args options = new Args(); - ContextCommandlet cxtCmd = new ContextCommandlet(); + ContextCommandlet cxtCmd = new ContextCommandlet(((AbstractIdeContext) this.context).getStartContext()); collectOptions(options, cxtCmd, bundle); if (cmd != null) { collectOptions(options, cmd, bundle); } options.print(); if (cmd == null) { - this.context.info(""); - this.context.info(bundle.getDetail(this.context.getCommandletManager().getCommandlet(HelpCommandlet.class))); + LOG.info(""); + LOG.info(bundle.getDetail(this.context.getCommandletManager().getCommandlet(HelpCommandlet.class))); } - this.context.info(""); - this.context.info(bundle.get("icd-hint")); + LOG.info(""); + LOG.info(bundle.get("icd-hint")); } private void printCommandletHelp(NlsBundle bundle, Commandlet cmd) { @@ -108,11 +119,11 @@ private void printCommandletHelp(NlsBundle bundle, Commandlet cmd) { } } } - this.context.info(usage.toString()); - this.context.info(bundle.get(cmd)); - this.context.info(bundle.getDetail(cmd)); - this.context.info(""); - this.context.info(bundle.get("values")); + LOG.info(usage.toString()); + LOG.info(bundle.get(cmd)); + LOG.info(bundle.getDetail(cmd)); + LOG.info(""); + LOG.info(bundle.get("values")); values.print(); cmd.printHelp(bundle); } @@ -137,10 +148,10 @@ private void printCommandlets(NlsBundle bundle) { } } - this.context.info(bundle.get("commandlets")); + LOG.info(bundle.get("commandlets")); commandlets.print(IdeLogLevel.INTERACTION); - this.context.info(""); - this.context.info(bundle.get("toolcommandlets")); + LOG.info(""); + LOG.info(bundle.get("toolcommandlets")); toolcommandlets.print(IdeLogLevel.INTERACTION); } @@ -231,9 +242,9 @@ void print() { void print(IdeLogLevel level) { - IdeSubLogger logger = HelpCommandlet.this.context.level(level); for (Arg arg : get()) { - logger.log(format(arg)); + String message = format(arg); + level.log(LOG, message); } } diff --git a/cli/src/main/java/com/devonfw/tools/ide/commandlet/InstallCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/commandlet/InstallCommandlet.java index 8459a5d772..57ba14ba02 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/commandlet/InstallCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/commandlet/InstallCommandlet.java @@ -2,6 +2,9 @@ import java.nio.file.Path; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.cli.GraalVmHelper; import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.property.ToolProperty; @@ -20,6 +23,8 @@ */ public class InstallCommandlet extends Commandlet { + private static final Logger LOG = LoggerFactory.getLogger(InstallCommandlet.class); + /** The tool to install. */ public final ToolProperty tool; @@ -52,18 +57,18 @@ public boolean isIdeRootRequired() { } @Override - public void run() { + protected void doRun() { if (this.tool.getValueCount() == 0) { IdeasyCommandlet ideasy = new IdeasyCommandlet(this.context); GraalVmHelper graalVmHelper = GraalVmHelper.get(); if (graalVmHelper.isNativeImage()) { - this.context.debug("Detected that IDEasy is running as graalvm native image..."); + LOG.debug("Detected that IDEasy is running as graalvm native image..."); } else { - this.context.debug("Detected that IDEasy is running in JVM..."); + LOG.debug("Detected that IDEasy is running in JVM..."); } Path cwd = graalVmHelper.getCwd(); - this.context.info("Installing IDEasy from {}", cwd); + LOG.info("Installing IDEasy from {}", cwd); if (!this.context.isForceMode()) { this.context.askToContinue("Sub-command install without any further arguments will perform the initial installation of IDEasy.\n" + "Since this is typically not to be called manually, you may have forgotten to specify the tool to install as extra argument.\n" diff --git a/cli/src/main/java/com/devonfw/tools/ide/commandlet/InstallPluginCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/commandlet/InstallPluginCommandlet.java index 9471d7b4cc..ac4b466256 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/commandlet/InstallPluginCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/commandlet/InstallPluginCommandlet.java @@ -1,5 +1,8 @@ package com.devonfw.tools.ide.commandlet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.property.PluginProperty; import com.devonfw.tools.ide.property.ToolProperty; @@ -14,6 +17,8 @@ */ public class InstallPluginCommandlet extends Commandlet { + private static final Logger LOG = LoggerFactory.getLogger(InstallPluginCommandlet.class); + /** The tool to install. */ public final ToolProperty tool; @@ -40,7 +45,7 @@ public String getName() { } @Override - public void run() { + protected void doRun() { ToolCommandlet commandlet = this.tool.getValue(); String plugin = this.plugin.getValue(); @@ -48,7 +53,7 @@ public void run() { Step step = context.newStep("Install plugin: " + plugin); step.run(() -> cmd.installPlugin(cmd.getPlugin(plugin), step)); } else { - context.warning("Tool {} does not support installation of plugins.", commandlet.getName()); + LOG.warn("Tool {} does not support installation of plugins.", commandlet.getName()); } } diff --git a/cli/src/main/java/com/devonfw/tools/ide/commandlet/ShellCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/commandlet/ShellCommandlet.java index c88fbc5c67..9667c9e269 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/commandlet/ShellCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/commandlet/ShellCommandlet.java @@ -19,6 +19,8 @@ import org.jline.terminal.Terminal; import org.jline.terminal.TerminalBuilder; import org.jline.widget.AutosuggestionWidgets; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.devonfw.tools.ide.cli.CliArgument; import com.devonfw.tools.ide.cli.CliArguments; @@ -35,6 +37,8 @@ */ public final class ShellCommandlet extends Commandlet { + private static final Logger LOG = LoggerFactory.getLogger(ShellCommandlet.class); + private static final int AUTOCOMPLETER_MAX_RESULTS = 50; private static final int RC_EXIT = 987654321; @@ -63,7 +67,7 @@ public boolean isIdeHomeRequired() { } @Override - public void run() { + protected void doRun() { try { Parser parser = new DefaultParser(); @@ -173,7 +177,7 @@ private int changeDirectory(CliArguments cliArgs) { */ private boolean apply(CliArgument argument, Commandlet commandlet) { - this.context.trace("Trying to match arguments to commandlet {}", commandlet.getName()); + LOG.trace("Trying to match arguments to commandlet {}", commandlet.getName()); CliArgument currentArgument = argument; Iterator> valueIterator = commandlet.getValues().iterator(); Property currentProperty = null; @@ -183,7 +187,7 @@ private boolean apply(CliArgument argument, Commandlet commandlet) { endOpts = true; } else { String arg = currentArgument.get(); - this.context.trace("Trying to match argument '{}'", currentArgument); + LOG.trace("Trying to match argument '{}'", currentArgument); if ((currentProperty != null) && (currentProperty.isExpectValue())) { currentProperty.setValueAsString(arg, this.context); if (!currentProperty.isMultiValued()) { @@ -196,17 +200,17 @@ private boolean apply(CliArgument argument, Commandlet commandlet) { } if (property == null) { if (!valueIterator.hasNext()) { - this.context.trace("No option or next value found"); + LOG.trace("No option or next value found"); return false; } currentProperty = valueIterator.next(); - this.context.trace("Next value candidate is {}", currentProperty); + LOG.trace("Next value candidate is {}", currentProperty); if (currentProperty instanceof KeywordProperty keyword) { if (keyword.matches(arg)) { keyword.setValue(Boolean.TRUE); - this.context.trace("Keyword matched"); + LOG.trace("Keyword matched"); } else { - this.context.trace("Missing keyword"); + LOG.trace("Missing keyword"); return false; } } else { @@ -219,7 +223,7 @@ private boolean apply(CliArgument argument, Commandlet commandlet) { currentProperty = null; } } else { - this.context.trace("Found option by name"); + LOG.trace("Found option by name"); String value = currentArgument.getValue(); if (value != null) { property.setValueAsString(value, this.context); diff --git a/cli/src/main/java/com/devonfw/tools/ide/commandlet/StatusCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/commandlet/StatusCommandlet.java index 65a12482fc..9d050b3410 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/commandlet/StatusCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/commandlet/StatusCommandlet.java @@ -3,9 +3,13 @@ import java.nio.file.Files; import java.nio.file.Path; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.environment.EnvironmentVariables; import com.devonfw.tools.ide.git.GitContext; +import com.devonfw.tools.ide.log.IdeLogLevel; import com.devonfw.tools.ide.migration.IdeMigrator; import com.devonfw.tools.ide.os.SystemInfo; import com.devonfw.tools.ide.step.Step; @@ -17,6 +21,8 @@ */ public class StatusCommandlet extends Commandlet { + private static final Logger LOG = LoggerFactory.getLogger(StatusCommandlet.class); + /** * The constructor. * @@ -35,7 +41,13 @@ public String getName() { } @Override - public void run() { + public boolean isWriteLogFile() { + + return false; + } + + @Override + protected void doRun() { Step step = this.context.newStep(true, "Show IDE_ROOT and IDE_HOME"); step.run(this.context::logIdeHomeAndRootStatus); step = this.context.newStep(true, "Check for updates of IDEasy"); @@ -62,7 +74,7 @@ private void checkForUpdate() { private void logSystemInfo() { SystemInfo systemInfo = this.context.getSystemInfo(); - this.context.info("Your operating system is {}({})@{} [{}@{}]", systemInfo.getOs(), systemInfo.getOsVersion(), systemInfo.getArchitecture(), + LOG.info("Your operating system is {}({})@{} [{}@{}]", systemInfo.getOs(), systemInfo.getOsVersion(), systemInfo.getArchitecture(), systemInfo.getOsName(), systemInfo.getArchitectureName()); } @@ -73,12 +85,12 @@ private void logSettingsLegacyStatus() { Path legacyProperties = variables.getLegacyPropertiesFilePath(); if (legacyProperties != null && Files.exists(legacyProperties)) { hasLegacyProperties = true; - this.context.warning("Found legacy properties {}", legacyProperties); + LOG.warn("Found legacy properties {}", legacyProperties); } variables = variables.getParent(); } if (hasLegacyProperties) { - this.context.warning( + LOG.warn( "Your settings are outdated and contain legacy configurations. Please consider upgrading your settings:\nhttps://github.com/devonfw/IDEasy/blob/main/documentation/settings.adoc#upgrade"); } } @@ -87,21 +99,21 @@ private void logSettingsGitStatus() { Path settingsPath = this.context.getSettingsGitRepository(); if (settingsPath == null) { if (this.context.getIdeHome() != null) { - this.context.error("No settings repository was found."); + LOG.error("No settings repository was found."); } } else { GitContext gitContext = this.context.getGitContext(); if (gitContext.isRepositoryUpdateAvailable(settingsPath, this.context.getSettingsCommitIdPath())) { if (!this.context.isSettingsRepositorySymlinkOrJunction()) { - this.context.warning("Your settings are not up-to-date, please run 'ide update'."); + LOG.warn("Your settings are not up-to-date, please run 'ide update'."); } } else { - this.context.success("Your settings are up-to-date."); + IdeLogLevel.SUCCESS.log(LOG, "Your settings are up-to-date."); } String branch = gitContext.determineCurrentBranch(settingsPath); - this.context.debug("Your settings branch is {}", branch); + LOG.debug("Your settings branch is {}", branch); if (!"master".equals(branch) && !"main".equals(branch)) { - this.context.warning("Your settings are on a custom branch: {}", branch); + LOG.warn("Your settings are on a custom branch: {}", branch); } } } @@ -116,7 +128,8 @@ private void logMigrationStatus() { VersionIdentifier projectVersion = this.context.getProjectVersion(); VersionIdentifier targetVersion = migrator.getTargetVersion(); if (projectVersion.isLess(targetVersion)) { - this.context.interaction("Your project is on IDEasy version {} and needs an update to version {}!\nPlease run 'ide update' to migrate your project", + IdeLogLevel.INTERACTION.log(LOG, + "Your project is on IDEasy version {} and needs an update to version {}!\nPlease run 'ide update' to migrate your project", projectVersion, targetVersion); } } @@ -124,16 +137,16 @@ private void logMigrationStatus() { private void logGitBashLocationStatus() { Path bashPath = this.context.findBash(); if (bashPath != null) { - this.context.success("Found bash executable at: {}", bashPath); + IdeLogLevel.SUCCESS.log(LOG, "Found bash executable at: {}", bashPath); } else { - this.context.error("No bash executable was found on your system!"); + LOG.error("No bash executable was found on your system!"); } GitContext gitContext = this.context.getGitContext(); Path gitPath = gitContext.findGit(); if (gitPath != null) { - this.context.success("Found git executable at: {}", gitPath); + IdeLogLevel.SUCCESS.log(LOG, "Found git executable at: {}", gitPath); } else { - this.context.error("No git executable was found on your system!"); + LOG.error("No git executable was found on your system!"); } } diff --git a/cli/src/main/java/com/devonfw/tools/ide/commandlet/UninstallCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/commandlet/UninstallCommandlet.java index afe2562e86..3871d7da60 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/commandlet/UninstallCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/commandlet/UninstallCommandlet.java @@ -1,5 +1,8 @@ package com.devonfw.tools.ide.commandlet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.property.ToolProperty; import com.devonfw.tools.ide.tool.IdeasyCommandlet; @@ -10,6 +13,8 @@ */ public class UninstallCommandlet extends Commandlet { + private static final Logger LOG = LoggerFactory.getLogger(UninstallCommandlet.class); + /** The tool to uninstall. */ public final ToolProperty tools; @@ -38,7 +43,7 @@ public boolean isIdeRootRequired() { } @Override - public void run() { + protected void doRun() { int valueCount = this.tools.getValueCount(); if (valueCount == 0) { @@ -56,9 +61,8 @@ public void run() { if (toolCommandlet.isInstalled()) { toolCommandlet.uninstall(); } else { - this.context.warning("Couldn't uninstall " + toolCommandlet.getName() + " because we could not find an installation"); + LOG.warn("Couldn't uninstall " + toolCommandlet.getName() + " because we could not find an installation"); } - } } } diff --git a/cli/src/main/java/com/devonfw/tools/ide/commandlet/UninstallPluginCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/commandlet/UninstallPluginCommandlet.java index ba5b73eca3..fc9bf3b4c6 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/commandlet/UninstallPluginCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/commandlet/UninstallPluginCommandlet.java @@ -1,5 +1,8 @@ package com.devonfw.tools.ide.commandlet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.property.PluginProperty; import com.devonfw.tools.ide.property.ToolProperty; @@ -13,6 +16,8 @@ */ public class UninstallPluginCommandlet extends Commandlet { + private static final Logger LOG = LoggerFactory.getLogger(UninstallPluginCommandlet.class); + /** The tool to install. */ public final ToolProperty tool; @@ -39,14 +44,14 @@ public String getName() { } @Override - public void run() { + protected void doRun() { ToolCommandlet commandlet = this.tool.getValue(); String plugin = this.plugin.getValue(); if (commandlet instanceof PluginBasedCommandlet cmd) { cmd.uninstallPlugin(cmd.getPlugin(plugin)); } else { - context.warning("Tool {} does not support plugins.", tool.getName()); + LOG.warn("Tool {} does not support plugins.", tool.getName()); } } diff --git a/cli/src/main/java/com/devonfw/tools/ide/commandlet/UpdateCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/commandlet/UpdateCommandlet.java index 91f2086bbc..944a4c0eeb 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/commandlet/UpdateCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/commandlet/UpdateCommandlet.java @@ -25,8 +25,8 @@ public String getName() { } @Override - public void run() { + protected void doRun() { new IdeMigrator().run(this.context); - super.run(); + super.doRun(); } } diff --git a/cli/src/main/java/com/devonfw/tools/ide/commandlet/UpgradeCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/commandlet/UpgradeCommandlet.java index 3f60579c33..d33d44afbf 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/commandlet/UpgradeCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/commandlet/UpgradeCommandlet.java @@ -1,6 +1,10 @@ package com.devonfw.tools.ide.commandlet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.context.IdeContext; +import com.devonfw.tools.ide.log.IdeLogLevel; import com.devonfw.tools.ide.property.EnumProperty; import com.devonfw.tools.ide.tool.IdeasyCommandlet; import com.devonfw.tools.ide.tool.ToolInstallation; @@ -10,6 +14,8 @@ */ public class UpgradeCommandlet extends Commandlet { + private static final Logger LOG = LoggerFactory.getLogger(UpgradeCommandlet.class); + /** Optional {@link UpgradeMode}. */ public final EnumProperty mode; @@ -38,12 +44,12 @@ public boolean isIdeHomeRequired() { } @Override - public void run() { + protected void doRun() { IdeasyCommandlet ideasy = new IdeasyCommandlet(this.context, this.mode.getValue()); ToolInstallation installation = ideasy.install(false); if (installation.newInstallation()) { - this.context.interaction("It is recommended to run 'ide update' on your IDEasy projects now."); + IdeLogLevel.INTERACTION.log(LOG, "It is recommended to run 'ide update' on your IDEasy projects now."); } } diff --git a/cli/src/main/java/com/devonfw/tools/ide/commandlet/UpgradeSettingsCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/commandlet/UpgradeSettingsCommandlet.java index 0468c07c53..46914bb2ae 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/commandlet/UpgradeSettingsCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/commandlet/UpgradeSettingsCommandlet.java @@ -8,11 +8,15 @@ import java.util.List; import java.util.function.Function; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.environment.EnvironmentVariables; import com.devonfw.tools.ide.environment.EnvironmentVariablesPropertiesFile; import com.devonfw.tools.ide.environment.EnvironmentVariablesType; import com.devonfw.tools.ide.io.FileAccess; +import com.devonfw.tools.ide.log.IdeLogLevel; import com.devonfw.tools.ide.merge.DirectoryMerger; import com.devonfw.tools.ide.tool.custom.CustomTools; import com.devonfw.tools.ide.tool.custom.CustomToolsMapper; @@ -25,6 +29,8 @@ */ public class UpgradeSettingsCommandlet extends Commandlet { + private static final Logger LOG = LoggerFactory.getLogger(UpgradeSettingsCommandlet.class); + /** * The constructor. * @@ -43,14 +49,14 @@ public String getName() { } @Override - public void run() { + protected void doRun() { updateLegacyFolders(); updateProperties(); updateWorkspaceTemplates(); } private void updateLegacyFolders() { - this.context.info("Updating legacy folders if present..."); + LOG.info("Updating legacy folders if present..."); Path settingsPath = context.getSettingsPath(); updateLegacyFolder(settingsPath, IdeContext.FOLDER_LEGACY_REPOSITORIES, IdeContext.FOLDER_REPOSITORIES); updateLegacyFolder(settingsPath, IdeContext.FOLDER_LEGACY_TEMPLATES, IdeContext.FOLDER_TEMPLATES); @@ -65,16 +71,16 @@ private void updateLegacyFolder(Path folder, String legacyName, String newName) try { if (!Files.exists(newFolder)) { fileAccess.move(legacyFolder, newFolder, StandardCopyOption.REPLACE_EXISTING); - this.context.success("Successfully renamed folder '{}' to '{}' in {}.", legacyName, newName, folder); + IdeLogLevel.SUCCESS.log(LOG, "Successfully renamed folder '{}' to '{}' in {}.", legacyName, newName, folder); } } catch (IllegalStateException e) { - this.context.error(e, "Error renaming folder {} to {} in {}", legacyName, newName, folder); + LOG.error("Error renaming folder {} to {} in {}", legacyName, newName, folder, e); } } } private void updateWorkspaceTemplates() { - this.context.info("Updating workspace templates (replace legacy variables and change variable syntax)..."); + LOG.info("Updating workspace templates (replace legacy variables and change variable syntax)..."); FileAccess fileAccess = this.context.getFileAccess(); DirectoryMerger merger = this.context.getWorkspaceMerger(); @@ -96,7 +102,7 @@ private void updateProperties() { // updates DEVON_IDE_CUSTOM_TOOLS to new ide-custom-tools.json String devonCustomTools = IdeVariables.DEVON_IDE_CUSTOM_TOOLS.get(this.context); if (devonCustomTools != null) { - CustomTools customTools = CustomToolsMapper.parseCustomToolsFromLegacyConfig(devonCustomTools, context); + CustomTools customTools = CustomToolsMapper.parseCustomToolsFromLegacyConfig(devonCustomTools); if (customTools != null) { CustomToolsMapper.get().saveJsonToFolder(customTools, this.context.getSettingsPath()); } @@ -154,7 +160,7 @@ private String mapLegacyIntellijEdition(String legacyEdition) { case "U" -> "ultimate"; case "C" -> "intellij"; default -> { - this.context.warning("Undefined legacy edition {}", legacyEdition); + LOG.warn("Undefined legacy edition {}", legacyEdition); yield "intellij"; } }; @@ -167,7 +173,7 @@ private String mapLegacyEclipseEdition(String legacyEdition) { case "jee" -> "jee"; case "cpp" -> "cpp"; default -> { - this.context.warning("Undefined legacy edition {}", legacyEdition); + LOG.warn("Undefined legacy edition {}", legacyEdition); yield "eclipse"; } }; @@ -187,7 +193,7 @@ private static void updatePropertiesLegacyEdition(EnvironmentVariablesProperties } private void cleanupLegacyProperties() { - this.context.info("Cleaning up legacy properties..."); + LOG.info("Cleaning up legacy properties..."); Path settingsPath = context.getSettingsPath(); Path repositoriesPath = settingsPath.resolve(IdeContext.FOLDER_REPOSITORIES); @@ -227,9 +233,9 @@ private void updateRepositoryPropertiesFile(Path filePath) throws IOException { if (updated) { try { Files.write(filePath, lines, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING); - this.context.success("Successfully updated repository configuration file {}", filePath); + IdeLogLevel.SUCCESS.log(LOG, "Successfully updated repository configuration file {}", filePath); } catch (IOException e) { - this.context.error("Failed to write updated repository configuration file {}", filePath); + LOG.error("Failed to write updated repository configuration file {}", filePath); throw e; } } diff --git a/cli/src/main/java/com/devonfw/tools/ide/commandlet/VersionCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/commandlet/VersionCommandlet.java index 6c334f540f..da3ecb2ac7 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/commandlet/VersionCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/commandlet/VersionCommandlet.java @@ -1,5 +1,8 @@ package com.devonfw.tools.ide.commandlet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.log.IdeLogLevel; import com.devonfw.tools.ide.version.IdeVersion; @@ -9,6 +12,8 @@ */ public class VersionCommandlet extends Commandlet { + private static final Logger LOG = LoggerFactory.getLogger(VersionCommandlet.class); + /** * The constructor. * @@ -39,8 +44,8 @@ public boolean isProcessableOutput() { } @Override - public void run() { + protected void doRun() { - this.context.level(IdeLogLevel.PROCESSABLE).log(IdeVersion.getVersionString()); + IdeLogLevel.PROCESSABLE.log(LOG, IdeVersion.getVersionString()); } } diff --git a/cli/src/main/java/com/devonfw/tools/ide/commandlet/VersionListCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/commandlet/VersionListCommandlet.java index 1b4ab40ec3..abbb6fc7ec 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/commandlet/VersionListCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/commandlet/VersionListCommandlet.java @@ -33,7 +33,13 @@ public String getName() { } @Override - public void run() { + public boolean isWriteLogFile() { + + return false; + } + + @Override + protected void doRun() { ToolCommandlet commandlet = this.tool.getValue(); commandlet.listVersions(); diff --git a/cli/src/main/java/com/devonfw/tools/ide/commandlet/VersionSetCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/commandlet/VersionSetCommandlet.java index 4f45efa1db..1c12d1f44c 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/commandlet/VersionSetCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/commandlet/VersionSetCommandlet.java @@ -44,7 +44,7 @@ public String getName() { } @Override - public void run() { + protected void doRun() { ToolCommandlet commandlet = this.tool.getValue(); VersionIdentifier versionIdentifier = this.version.getValue(); diff --git a/cli/src/main/java/com/devonfw/tools/ide/completion/CompletionCandidateCollectorDefault.java b/cli/src/main/java/com/devonfw/tools/ide/completion/CompletionCandidateCollectorDefault.java index e5163dc6e4..33f6fc25fb 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/completion/CompletionCandidateCollectorDefault.java +++ b/cli/src/main/java/com/devonfw/tools/ide/completion/CompletionCandidateCollectorDefault.java @@ -4,6 +4,9 @@ import java.util.Collections; import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.commandlet.Commandlet; import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.property.Property; @@ -13,6 +16,8 @@ */ public class CompletionCandidateCollectorDefault implements CompletionCandidateCollector { + private static final Logger LOG = LoggerFactory.getLogger(CompletionCandidateCollectorDefault.class); + private final List candidates; private final IdeContext context; @@ -45,7 +50,7 @@ public void add(String text, String description, Property property, Commandle CompletionCandidate candidate = createCandidate(text, description, property, commandlet); this.candidates.add(candidate); - this.context.trace("Added {} for auto-completion of property {}.{}", candidate, commandlet, property); + LOG.trace("Added {} for auto-completion of property {}.{}", candidate, commandlet, property); } @Override diff --git a/cli/src/main/java/com/devonfw/tools/ide/context/AbstractIdeContext.java b/cli/src/main/java/com/devonfw/tools/ide/context/AbstractIdeContext.java index 3ac95006fc..171c8b288b 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/context/AbstractIdeContext.java +++ b/cli/src/main/java/com/devonfw/tools/ide/context/AbstractIdeContext.java @@ -2,6 +2,9 @@ import static com.devonfw.tools.ide.variable.IdeVariables.IDE_MIN_VERSION; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.time.LocalDateTime; @@ -13,7 +16,12 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Objects; +import java.util.Properties; import java.util.function.Predicate; +import java.util.logging.LogManager; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.devonfw.tools.ide.cli.CliAbortException; import com.devonfw.tools.ide.cli.CliArgument; @@ -41,8 +49,7 @@ import com.devonfw.tools.ide.io.FileAccessImpl; import com.devonfw.tools.ide.log.IdeLogArgFormatter; import com.devonfw.tools.ide.log.IdeLogLevel; -import com.devonfw.tools.ide.log.IdeLogger; -import com.devonfw.tools.ide.log.IdeSubLogger; +import com.devonfw.tools.ide.log.IdeLogListener; import com.devonfw.tools.ide.merge.DirectoryMerger; import com.devonfw.tools.ide.migration.IdeMigrator; import com.devonfw.tools.ide.network.NetworkStatus; @@ -80,10 +87,15 @@ */ public abstract class AbstractIdeContext implements IdeContext, IdeLogArgFormatter { + static final Logger LOG = LoggerFactory.getLogger(AbstractIdeContext.class); + + /** The default shell bash (Bourne Again SHell). */ + public static final String BASH = "bash"; + private static final GitUrl IDE_URLS_GIT = new GitUrl("https://github.com/devonfw/ide-urls.git", null); private static final String LICENSE_URL = "https://github.com/devonfw/IDEasy/blob/main/documentation/LICENSE.adoc"; - public static final String BASH = "bash"; + private static final String DEFAULT_WINDOWS_GIT_PATH = "C:\\Program Files\\Git\\bin\\bash.exe"; private static final String OPTION_DETAILS_START = "(["; @@ -154,10 +166,14 @@ public abstract class AbstractIdeContext implements IdeContext, IdeLogArgFormatt private Path bash; + private boolean julConfigured; + + private Path logfile; + /** * The constructor. * - * @param startContext the {@link IdeLogger}. + * @param startContext the {@link IdeStartContextImpl}. * @param workingDirectory the optional {@link Path} to current working directory. */ public AbstractIdeContext(IdeStartContextImpl startContext, Path workingDirectory) { @@ -167,6 +183,9 @@ public AbstractIdeContext(IdeStartContextImpl startContext, Path workingDirector this.startContext.setArgFormatter(this); this.privacyMap = new HashMap<>(); this.systemInfo = SystemInfoImpl.INSTANCE; + if (isTest()) { + configureJavaUtilLogging(null); + } this.commandletManager = new CommandletManagerImpl(this); this.fileAccess = new FileAccessImpl(this); String userHomeProperty = getSystem().getProperty("user.home"); @@ -180,7 +199,7 @@ public AbstractIdeContext(IdeStartContextImpl startContext, Path workingDirector if (Files.isDirectory(workingDirectory)) { workingDirectory = this.fileAccess.toCanonicalPath(workingDirectory); } else { - warning("Current working directory does not exist: {}", workingDirectory); + LOG.warn("Current working directory does not exist: {}", workingDirectory); } this.cwd = workingDirectory; // detect IDE_HOME and WORKSPACE @@ -205,7 +224,6 @@ public AbstractIdeContext(IdeStartContextImpl startContext, Path workingDirector this.fileAccess.mkdirs(tempDownloadPath); } } - this.defaultToolRepository = new DefaultToolRepository(this); } @@ -225,7 +243,7 @@ protected IdeHomeAndWorkspace findIdeHome(Path workingDirectory) { Path ideRootPath = getIdeRootPathFromEnv(false); while (currentDir != null) { - trace("Looking for IDE_HOME in {}", currentDir); + LOG.trace("Looking for IDE_HOME in {}", currentDir); if (isIdeHome(currentDir)) { if (FOLDER_WORKSPACES.equals(name1) && !name2.isEmpty()) { workspace = name2; @@ -275,7 +293,7 @@ private Path findIdeRoot(Path ideHomePath) { Path ideRootPathFromEnv = getIdeRootPathFromEnv(true); ideRootPath = ideHomePath.getParent(); if ((ideRootPathFromEnv != null) && !ideRootPath.toString().equals(ideRootPathFromEnv.toString())) { - warning( + LOG.warn( "Variable IDE_ROOT is set to '{}' but for your project '{}' the path '{}' would have been expected.\n" + "Please check your 'user.dir' or working directory setting and make sure that it matches your IDE_ROOT variable.", ideRootPathFromEnv, @@ -306,19 +324,19 @@ protected Path getIdeRootPathFromEnv(boolean withSanityCheck) { String rootName = rootPath.getName(nameIndex).toString(); String absoluteRootName = absoluteRootPath.getName(nameIndex + delta).toString(); if (!rootName.equals(absoluteRootName)) { - warning("IDE_ROOT is set to {} but was expanded to absolute path {} and does not match for segment {} and {} - fix your IDEasy installation!", + LOG.warn("IDE_ROOT is set to {} but was expanded to absolute path {} and does not match for segment {} and {} - fix your IDEasy installation!", rootPath, absoluteRootPath, rootName, absoluteRootName); break; } } } else { - warning("IDE_ROOT is set to {} but was expanded to a shorter absolute path {}", rootPath, + LOG.warn("IDE_ROOT is set to {} but was expanded to a shorter absolute path {}", rootPath, absoluteRootPath); } } return absoluteRootPath; } else if (withSanityCheck) { - warning("IDE_ROOT is set to {} that is not an existing directory - fix your IDEasy installation!", rootPath); + LOG.warn("IDE_ROOT is set to {} that is not an existing directory - fix your IDEasy installation!", rootPath); } } return null; @@ -598,7 +616,7 @@ public Path getSettingsGitRepository() { Path settingsPath = getSettingsPath(); // check whether the settings path has a .git folder only if its not a symbolic link or junction if ((settingsPath != null) && !Files.exists(settingsPath.resolve(".git")) && !isSettingsRepositorySymlinkOrJunction()) { - error("Settings repository exists but is not a git repository."); + LOG.error("Settings repository exists but is not a git repository."); return null; } return settingsPath; @@ -814,7 +832,7 @@ public DirectoryMerger getWorkspaceMerger() { } /** - * @return the {@link #getDefaultExecutionDirectory() default execution directory} in which a command process is executed. + * @return the default execution directory in which a command process is executed. */ @Override public Path getDefaultExecutionDirectory() { @@ -852,7 +870,7 @@ public ProcessContext newProcess() { public IdeSystem getSystem() { if (this.system == null) { - this.system = new IdeSystemImpl(this); + this.system = new IdeSystemImpl(); } return this.system; } @@ -867,20 +885,32 @@ protected ProcessContext createProcessContext() { } @Override - public IdeSubLogger level(IdeLogLevel level) { + public IdeLogLevel getLogLevelConsole() { + + return this.startContext.getLogLevelConsole(); + } + + @Override + public IdeLogLevel getLogLevelLogger() { - return this.startContext.level(level); + return this.startContext.getLogLevelLogger(); + } + + @Override + public IdeLogListener getLogListener() { + + return this.startContext.getLogListener(); } @Override public void logIdeHomeAndRootStatus() { if (this.ideRoot != null) { - success("IDE_ROOT is set to {}", this.ideRoot); + IdeLogLevel.SUCCESS.log(LOG, "IDE_ROOT is set to {}", this.ideRoot); } if (this.ideHome == null) { - warning(getMessageNotInsideIdeProject()); + LOG.warn(getMessageNotInsideIdeProject()); } else { - success("IDE_HOME is set to {}", this.ideHome); + IdeLogLevel.SUCCESS.log(LOG, "IDE_HOME is set to {}", this.ideHome); } } @@ -938,7 +968,7 @@ public String askForInput(String message, String defaultValue) { while (true) { if (!message.isBlank()) { - interaction(message); + IdeLogLevel.INTERACTION.log(LOG, message); } if (isBatchMode()) { if (isForceMode()) { @@ -958,12 +988,11 @@ public String askForInput(String message, String defaultValue) { } } - @SuppressWarnings("unchecked") @Override public O question(O[] options, String question, Object... args) { assert (options.length > 0); - interaction(question, args); + IdeLogLevel.INTERACTION.log(LOG, question, args); return displayOptionsAndGetAnswer(options); } @@ -977,24 +1006,24 @@ private O displayOptionsAndGetAnswer(O[] options) { addMapping(mapping, key, option); String numericKey = Integer.toString(i); if (numericKey.equals(key)) { - trace("Options should not be numeric: " + key); + LOG.trace("Options should not be numeric: {}", key); } else { addMapping(mapping, numericKey, option); } - interaction("Option " + numericKey + ": " + title); + IdeLogLevel.INTERACTION.log(LOG, "Option {}: {}", numericKey, title); } O option = null; if (isBatchMode()) { if (isForceMode()) { option = options[0]; - interaction("" + option); + IdeLogLevel.INTERACTION.log(LOG, "" + option); } } else { while (option == null) { String answer = readLine(); option = mapping.get(answer); if (option == null) { - warning("Invalid answer: '" + answer + "' - please try again."); + LOG.warn("Invalid answer: '{}' - please try again.", answer); } } } @@ -1058,7 +1087,7 @@ public void endStep(StepImpl step) { if (this.currentStep != null) { currentStepName = this.currentStep.getName(); } - warning("endStep called with wrong step '{}' but expected '{}'", step.getName(), currentStepName); + LOG.warn("endStep called with wrong step '{}' but expected '{}'", step.getName(), currentStepName); } } @@ -1087,10 +1116,10 @@ public int run(CliArguments arguments) { return ProcessResult.SUCCESS; } } - this.startContext.activateLogging(); + activateLogging(cmd); verifyIdeMinVersion(false); if (result != null) { - error(result.getErrorMessage()); + LOG.error(result.getErrorMessage()); } step.error("Invalid arguments: {}", current.getArgs()); HelpCommandlet help = this.commandletManager.getCommandlet(HelpCommandlet.class); @@ -1100,8 +1129,11 @@ public int run(CliArguments arguments) { help.run(); return 1; } catch (Throwable t) { - this.startContext.activateLogging(); + activateLogging(cmd); step.error(t, true); + if (this.logfile != null) { + System.err.println("Logfile can be found at " + this.logfile); // do not use logger + } throw t; } finally { step.close(); @@ -1110,6 +1142,95 @@ public int run(CliArguments arguments) { } } + /** + * Ensure the logging system is initialized. + */ + private void activateLogging(Commandlet cmd) { + + configureJavaUtilLogging(cmd); + this.startContext.activateLogging(); + } + + /** + * Configures the logging system (JUL). + * + * @param cmd the {@link Commandlet} to be called. May be {@code null}. + */ + public void configureJavaUtilLogging(Commandlet cmd) { + + if (this.julConfigured) { + return; + } + boolean writeLogfile = isWriteLogfile(cmd); + this.startContext.setWriteLogfile(writeLogfile); + Properties properties = createJavaUtilLoggingProperties(writeLogfile, cmd); + try { + ByteArrayOutputStream out = new ByteArrayOutputStream(512); + properties.store(out, null); + out.flush(); + ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()); + LogManager.getLogManager().readConfiguration(in); + this.julConfigured = true; + this.startContext.activateLogging(); + } catch (IOException e) { + LOG.error("Failed to configure logging: {}", e.toString(), e); + } + } + + protected boolean isWriteLogfile(Commandlet cmd) { + if (!cmd.isWriteLogFile()) { + return false; + } + Boolean writeLogfile = IdeVariables.IDE_WRITE_LOGFILE.get(this); + return Boolean.TRUE.equals(writeLogfile); + } + + private Properties createJavaUtilLoggingProperties(boolean writeLogfile, Commandlet cmd) { + + Path idePath = getIdePath(); + if (writeLogfile && (idePath == null)) { + writeLogfile = false; + LOG.error("Cannot enable log-file since IDE_ROOT is undefined."); + } + Properties properties = new Properties(); + // prevent 3rd party (e.g. java.lang.ProcessBuilder) logging into our console via JUL + // see JulLogLevel for the trick we did to workaround JUL flaws + properties.setProperty(".level", "SEVERE"); + if (writeLogfile) { + this.startContext.setLogLevelLogger(IdeLogLevel.TRACE); + properties.setProperty("handlers", "com.devonfw.tools.ide.log.JulConsoleHandler,java.util.logging.FileHandler"); + properties.setProperty("java.util.logging.FileHandler.formatter", "java.util.logging.SimpleFormatter"); + properties.setProperty("java.util.logging.FileHandler.encoding", "UTF-8"); + this.logfile = createLogfilePath(idePath, cmd); + getFileAccess().mkdirs(this.logfile.getParent()); + properties.setProperty("java.util.logging.FileHandler.pattern", this.logfile.toString()); + } else { + properties.setProperty("handlers", "com.devonfw.tools.ide.log.JulConsoleHandler"); + } + properties.setProperty("java.util.logging.SimpleFormatter.format", "%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%1$tL [%4$s] [%3$s] %5$s%6$s%n"); + return properties; + } + + private Path createLogfilePath(Path idePath, Commandlet cmd) { + LocalDateTime now = LocalDateTime.now(); + Path logsPath = idePath.resolve(FOLDER_LOGS).resolve(DateTimeUtil.formatDate(now, true)); + StringBuilder sb = new StringBuilder(32); + if (this.ideHome == null || ((cmd != null) && !cmd.isIdeHomeRequired())) { + sb.append("_ide-"); + } else { + sb.append(this.ideHome.getFileName().toString()); + sb.append('-'); + } + sb.append("ide-"); + if (cmd != null) { + sb.append(cmd.getName()); + sb.append('-'); + } + sb.append(DateTimeUtil.formatTime(now)); + sb.append(".log"); + return logsPath.resolve(sb.toString()); + } + @Override public void runWithoutLogging(Runnable lambda, IdeLogLevel threshold) { @@ -1132,7 +1253,7 @@ private ValidationResult applyAndRun(CliArguments arguments, Commandlet cmd) { result = cmd.validate(); } if (result.isValid()) { - debug("Running commandlet {}", cmd); + LOG.debug("Running commandlet {}", cmd); if (cmd.isIdeHomeRequired() && (this.ideHome == null)) { throw new CliException(getMessageNotInsideIdeProject(), ProcessResult.NO_IDE_HOME); } else if (cmd.isIdeRootRequired() && (this.ideRoot == null)) { @@ -1140,29 +1261,26 @@ private ValidationResult applyAndRun(CliArguments arguments, Commandlet cmd) { } try { if (cmd.isProcessableOutput()) { - if (!debug().isEnabled()) { + if (!LOG.isDebugEnabled()) { // unless --debug or --trace was supplied, processable output commandlets will disable all log-levels except INFO to prevent other logs interfere - previousLogLevel = this.startContext.setLogLevel(IdeLogLevel.PROCESSABLE); + previousLogLevel = this.startContext.setLogLevelConsole(IdeLogLevel.PROCESSABLE); } - this.startContext.activateLogging(); } else { - this.startContext.activateLogging(); if (cmd.isIdeHomeRequired()) { - debug(getMessageIdeHomeFound()); + LOG.debug(getMessageIdeHomeFound()); } Path settingsRepository = getSettingsGitRepository(); if (settingsRepository != null) { if (getGitContext().isRepositoryUpdateAvailable(settingsRepository, getSettingsCommitIdPath()) || ( getGitContext().fetchIfNeeded(settingsRepository) && getGitContext().isRepositoryUpdateAvailable( settingsRepository, getSettingsCommitIdPath()))) { + String msg; if (isSettingsRepositorySymlinkOrJunction()) { - interaction( - "Updates are available for the settings repository. Please pull the latest changes by yourself or by calling \"ide -f update\" to apply them."); - + msg = "Updates are available for the settings repository. Please pull the latest changes by yourself or by calling \"ide -f update\" to apply them."; } else { - interaction( - "Updates are available for the settings repository. If you want to apply the latest changes, call \"ide update\""); + msg = "Updates are available for the settings repository. If you want to apply the latest changes, call \"ide update\""; } + IdeLogLevel.INTERACTION.log(LOG, msg); } } } @@ -1173,11 +1291,11 @@ settingsRepository, getSettingsCommitIdPath()))) { cmd.run(); } finally { if (previousLogLevel != null) { - this.startContext.setLogLevel(previousLogLevel); + this.startContext.setLogLevelConsole(previousLogLevel); } } } else { - trace("Commandlet did not match"); + LOG.trace("Commandlet did not match"); } return result; } @@ -1198,13 +1316,11 @@ private boolean ensureLicenseAgreement(Commandlet cmd) { // printing anything anymore in such case. return false; } - boolean logLevelInfoDisabled = !this.startContext.info().isEnabled(); - if (logLevelInfoDisabled) { - this.startContext.setLogLevel(IdeLogLevel.INFO, true); - } - boolean logLevelInteractionDisabled = !this.startContext.interaction().isEnabled(); - if (logLevelInteractionDisabled) { - this.startContext.setLogLevel(IdeLogLevel.INTERACTION, true); + IdeLogLevel oldLogLevel = this.startContext.getLogLevelConsole(); + IdeLogLevel newLogLevel = oldLogLevel; + if (oldLogLevel.ordinal() > IdeLogLevel.INFO.ordinal()) { + newLogLevel = IdeLogLevel.INFO; + this.startContext.setLogLevelConsole(newLogLevel); } StringBuilder sb = new StringBuilder(1180); sb.append(LOGO).append(""" @@ -1222,7 +1338,7 @@ This product (with its included 3rd party components) is open-source software an sb.append("\n\nAlso it is included in the documentation that you can find here:\n"). append(getIdePath().resolve("IDEasy.pdf").toString()).append("\n"); } - info(sb.toString()); + LOG.info(sb.toString()); askToContinue("Do you accept these terms of use and all license agreements?"); sb.setLength(0); @@ -1234,11 +1350,8 @@ This product (with its included 3rd party components) is open-source software an } catch (Exception e) { throw new RuntimeException("Failed to save license agreement!", e); } - if (logLevelInfoDisabled) { - this.startContext.setLogLevel(IdeLogLevel.INFO, false); - } - if (logLevelInteractionDisabled) { - this.startContext.setLogLevel(IdeLogLevel.INTERACTION, false); + if (oldLogLevel != newLogLevel) { + this.startContext.setLogLevelConsole(oldLogLevel); } return true; } @@ -1257,7 +1370,7 @@ public void verifyIdeMinVersion(boolean throwException) { if (throwException) { throw new CliException(message); } else { - warning(message); + LOG.warn(message); } } } @@ -1297,7 +1410,7 @@ public List complete(CliArguments arguments, boolean includ private void completeCommandlet(CliArguments arguments, Commandlet cmd, CompletionCandidateCollector collector) { - trace("Trying to match arguments for auto-completion for commandlet {}", cmd.getName()); + LOG.trace("Trying to match arguments for auto-completion for commandlet {}", cmd.getName()); Iterator> valueIterator = cmd.getValues().iterator(); valueIterator.next(); // skip first property since this is the keyword property that already matched to find the commandlet List> properties = cmd.getProperties(); @@ -1310,7 +1423,7 @@ private void completeCommandlet(CliArguments arguments, Commandlet cmd, Completi } CliArgument currentArgument = arguments.current(); while (!currentArgument.isEnd()) { - trace("Trying to match argument '{}'", currentArgument); + LOG.trace("Trying to match argument '{}'", currentArgument); if (currentArgument.isOption() && !arguments.isEndOptions()) { if (currentArgument.isCompletion()) { Iterator> optionIterator = optionProperties.iterator(); @@ -1332,7 +1445,7 @@ private void completeCommandlet(CliArguments arguments, Commandlet cmd, Completi } } if (option == null) { - trace("No such option was found."); + LOG.trace("No such option was found."); return; } } @@ -1341,11 +1454,11 @@ private void completeCommandlet(CliArguments arguments, Commandlet cmd, Completi Property valueProperty = valueIterator.next(); boolean success = valueProperty.apply(arguments, this, cmd, collector); if (!success) { - trace("Completion cannot match any further."); + LOG.trace("Completion cannot match any further."); return; } } else { - trace("No value left for completion."); + LOG.trace("No value left for completion."); return; } } @@ -1361,7 +1474,7 @@ private void completeCommandlet(CliArguments arguments, Commandlet cmd, Completi */ public ValidationResult apply(CliArguments arguments, Commandlet cmd) { - trace("Trying to match arguments to commandlet {}", cmd.getName()); + LOG.trace("Trying to match arguments to commandlet {}", cmd.getName()); CliArgument currentArgument = arguments.current(); Iterator> propertyIterator = cmd.getValues().iterator(); Property property = null; @@ -1369,7 +1482,7 @@ public ValidationResult apply(CliArguments arguments, Commandlet cmd) { property = propertyIterator.next(); } while (!currentArgument.isEnd()) { - trace("Trying to match argument '{}'", currentArgument); + LOG.trace("Trying to match argument '{}'", currentArgument); Property currentProperty = property; if (!arguments.isEndOptions()) { Property option = cmd.getOption(currentArgument.getKey()); @@ -1378,12 +1491,12 @@ public ValidationResult apply(CliArguments arguments, Commandlet cmd) { } } if (currentProperty == null) { - trace("No option or next value found"); + LOG.trace("No option or next value found"); ValidationState state = new ValidationState(null); state.addErrorMessage("No matching property found"); return state; } - trace("Next property candidate to match argument is {}", currentProperty); + LOG.trace("Next property candidate to match argument is {}", currentProperty); if (currentProperty == property) { if (!property.isMultiValued()) { if (propertyIterator.hasNext()) { @@ -1423,7 +1536,7 @@ public Path findBash() { } } if (bashPath == null) { - error("No bash executable could be found on your system."); + LOG.error("No bash executable could be found on your system."); } else { this.bash = bashPath; } @@ -1431,21 +1544,21 @@ public Path findBash() { } private Path findBashOnBashPath() { - trace("Trying to find BASH_PATH environment variable."); + LOG.trace("Trying to find BASH_PATH environment variable."); Path bash; String bashPathVariableName = IdeVariables.BASH_PATH.getName(); String bashVariable = getVariables().get(bashPathVariableName); if (bashVariable != null) { bash = Path.of(bashVariable); if (Files.exists(bash)) { - debug("{} environment variable was found and points to: {}", bashPathVariableName, bash); + LOG.debug("{} environment variable was found and points to: {}", bashPathVariableName, bash); return bash; } else { - error("The environment variable {} points to a non existing file: {}", bashPathVariableName, bash); + LOG.error("The environment variable {} points to a non existing file: {}", bashPathVariableName, bash); return null; } } else { - debug("{} environment variable was not found", bashPathVariableName); + LOG.debug("{} environment variable was not found", bashPathVariableName); return null; } } @@ -1466,7 +1579,7 @@ private boolean checkPathToIgnoreLowercase(Path path, String toIgnore) { * @return Path to bash.exe if found in PATH environment variable, {@code null} if bash.exe was not found. */ private Path findBashInPath() { - trace("Trying to find bash in PATH environment variable."); + LOG.trace("Trying to find bash in PATH environment variable."); Path bash; String pathVariableName = IdeVariables.PATH.getName(); if (pathVariableName != null) { @@ -1476,20 +1589,20 @@ private Path findBashInPath() { Path bashPath = getPath().findBinary(plainBash, pathsToIgnore); bash = bashPath.toAbsolutePath(); if (bashPath.equals(plainBash)) { - warning("No usable bash executable was found in your PATH environment variable!"); + LOG.warn("No usable bash executable was found in your PATH environment variable!"); bash = null; } else { if (Files.exists(bashPath)) { - debug("A proper bash executable was found in your PATH environment variable at: {}", bash); + LOG.debug("A proper bash executable was found in your PATH environment variable at: {}", bash); } else { bash = null; - error("A path to a bash executable was found in your PATH environment variable at: {} but the file is not existing.", bash); + LOG.error("A path to a bash executable was found in your PATH environment variable at: {} but the file is not existing.", bash); } } } else { bash = null; // this should never happen... - error("PATH environment variable was not found"); + LOG.error("PATH environment variable was not found"); } return bash; } @@ -1500,14 +1613,14 @@ private Path findBashInPath() { * @return Path to bash.exe if found in registry, {@code null} if bash.exe was found. */ protected Path findBashInWindowsRegistry() { - trace("Trying to find bash in Windows registry"); + LOG.trace("Trying to find bash in Windows registry"); // If not found in the default location, try the registry query String[] bashVariants = { "GitForWindows", "Cygwin\\setup" }; String[] registryKeys = { "HKEY_LOCAL_MACHINE", "HKEY_CURRENT_USER" }; for (String bashVariant : bashVariants) { - trace("Trying to find bash variant: {}", bashVariant); + LOG.trace("Trying to find bash variant: {}", bashVariant); for (String registryKey : registryKeys) { - trace("Trying to find bash from registry key: {}", registryKey); + LOG.trace("Trying to find bash from registry key: {}", registryKey); String toolValueName = ("GitForWindows".equals(bashVariant)) ? "InstallPath" : "rootdir"; String registryPath = registryKey + "\\Software\\" + bashVariant; @@ -1515,14 +1628,14 @@ protected Path findBashInWindowsRegistry() { if (path != null) { Path bashPath = Path.of(path + "\\bin\\bash.exe"); if (Files.exists(bashPath)) { - debug("Found bash at: {}", bashPath); + LOG.debug("Found bash at: {}", bashPath); return bashPath; } else { - error("Found bash at: {} but it is not pointing to an existing file", bashPath); + LOG.error("Found bash at: {} but it is not pointing to an existing file", bashPath); return null; } } else { - info("No bash executable could be found in the Windows registry."); + LOG.info("No bash executable could be found in the Windows registry."); } } } @@ -1532,13 +1645,13 @@ protected Path findBashInWindowsRegistry() { private Path findBashOnWindowsDefaultGitPath() { // Check if Git Bash exists in the default location - trace("Trying to find bash on the Windows default git path."); + LOG.trace("Trying to find bash on the Windows default git path."); Path defaultPath = Path.of(getDefaultWindowsGitPath()); if (!defaultPath.toString().isEmpty() && Files.exists(defaultPath)) { - trace("Found default path to git bash on Windows at: {}", getDefaultWindowsGitPath()); + LOG.trace("Found default path to git bash on Windows at: {}", getDefaultWindowsGitPath()); return defaultPath; } - debug("No bash was found on the Windows default git path."); + LOG.debug("No bash was found on the Windows default git path."); return null; } @@ -1600,7 +1713,7 @@ public void writeVersionFile(VersionIdentifier version, Path installationPath) { getFileAccess().writeFileContent(version.toString(), versionFile); } - /** + /* * @param home the IDE_HOME directory. * @param workspace the name of the active workspace folder. */ diff --git a/cli/src/main/java/com/devonfw/tools/ide/context/IdeContext.java b/cli/src/main/java/com/devonfw/tools/ide/context/IdeContext.java index 63da19862c..58f317bd3e 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/context/IdeContext.java +++ b/cli/src/main/java/com/devonfw/tools/ide/context/IdeContext.java @@ -94,6 +94,9 @@ public interface IdeContext extends IdeStartContext { /** The name of the backups folder for backup. */ String FOLDER_BACKUPS = "backups"; + /** The name of the logs folder for log-files (in {@link #FOLDER_UNDERSCORE_IDE}). */ + String FOLDER_LOGS = "logs"; + /** The name of the downloads folder. */ String FOLDER_DOWNLOADS = "Downloads"; @@ -227,7 +230,7 @@ default boolean isOnline() { */ default void printLogo() { - info(LOGO); + AbstractIdeContext.LOG.info(LOGO); } /** @@ -535,7 +538,8 @@ default Path getSettingsTemplatePath() { if (Files.isDirectory(templatesFolderLegacy)) { templatesFolder = templatesFolderLegacy; } else { - warning("No templates found in settings git repo neither in {} nor in {} - configuration broken", templatesFolder, templatesFolderLegacy); + AbstractIdeContext.LOG.warn("No templates found in settings git repo neither in {} nor in {} - configuration broken", templatesFolder, + templatesFolderLegacy); return null; } } @@ -828,4 +832,5 @@ default Path getNpmConfigUserConfig() { Npm npm = getCommandletManager().getCommandlet(Npm.class); return npm.getOrCreateNpmConfigUserConfig(); } + } diff --git a/cli/src/main/java/com/devonfw/tools/ide/context/IdeContextConsole.java b/cli/src/main/java/com/devonfw/tools/ide/context/IdeContextConsole.java index a04ea542f1..81e949ea8f 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/context/IdeContextConsole.java +++ b/cli/src/main/java/com/devonfw/tools/ide/context/IdeContextConsole.java @@ -2,34 +2,28 @@ import java.util.Scanner; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.io.IdeProgressBar; import com.devonfw.tools.ide.io.IdeProgressBarConsole; import com.devonfw.tools.ide.log.IdeLogLevel; -import com.devonfw.tools.ide.log.IdeSubLoggerOut; +import com.devonfw.tools.ide.log.IdeLogListenerNone; /** * Default implementation of {@link IdeContext} using the console. */ public class IdeContextConsole extends AbstractIdeContext { + private static final Logger LOG = LoggerFactory.getLogger(IdeContextConsole.class); + private final Scanner scanner; /** * The constructor. - * - * @param minLogLevel the minimum {@link IdeLogLevel} to enable. Should be {@link IdeLogLevel#INFO} by default. - * @param out the {@link Appendable} to {@link Appendable#append(CharSequence) write} log messages to. - * @param colored - {@code true} for colored output according to {@link IdeLogLevel}, {@code false} otherwise. */ - public IdeContextConsole(IdeLogLevel minLogLevel, Appendable out, boolean colored) { - - super(new IdeStartContextImpl(minLogLevel, level -> new IdeSubLoggerOut(level, out, colored, minLogLevel, null)), null); - if (System.console() == null) { - debug("System console not available - using System.in as fallback"); - this.scanner = new Scanner(System.in); - } else { - this.scanner = null; - } + public IdeContextConsole() { + this(new IdeStartContextImpl(IdeLogLevel.INFO, IdeLogListenerNone.INSTANCE)); } /** @@ -41,7 +35,7 @@ public IdeContextConsole(IdeStartContextImpl startContext) { super(startContext, null); if (System.console() == null) { - debug("System console not available - using System.in as fallback"); + LOG.debug("System console not available - using System.in as fallback"); this.scanner = new Scanner(System.in); } else { this.scanner = null; diff --git a/cli/src/main/java/com/devonfw/tools/ide/context/IdeStartContext.java b/cli/src/main/java/com/devonfw/tools/ide/context/IdeStartContext.java index 97e61f6677..b290133b1f 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/context/IdeStartContext.java +++ b/cli/src/main/java/com/devonfw/tools/ide/context/IdeStartContext.java @@ -2,15 +2,33 @@ import java.util.Locale; -import com.devonfw.tools.ide.log.IdeLogger; +import com.devonfw.tools.ide.log.IdeLogLevel; +import com.devonfw.tools.ide.log.IdeLogListener; import com.devonfw.tools.ide.network.ReadOfflineMode; /** - * Extends {@link IdeLogger} with the options configurable via {@link com.devonfw.tools.ide.cli.Ideasy} CLI (see - * {@link com.devonfw.tools.ide.commandlet.ContextCommandlet}). The {@link IdeStartContext} is therefore the object configured at bootstrapping and then used to - * create the actual {@link IdeContext} from it. + * Contains the options configurable via {@link com.devonfw.tools.ide.cli.Ideasy} CLI. The {@link IdeStartContext} is therefore the object configured at + * bootstrapping and then used to create the actual {@link IdeContext} from it. + * + * @see com.devonfw.tools.ide.commandlet.ContextCommandlet */ -public interface IdeStartContext extends IdeLogger, ReadOfflineMode { +public interface IdeStartContext extends ReadOfflineMode { + + /** + * @return the {@link IdeLogListener}. + */ + IdeLogListener getLogListener(); + + /** + * @return the minimum allowed {@link IdeLogLevel} (threshold) for console output (see --debug and --trace options). + */ + IdeLogLevel getLogLevelConsole(); + + /** + * @return the minimum allowed {@link IdeLogLevel} (threshold) for SLF4J and JUL logger (can be lower than {@link #getLogLevelConsole()} for finer details in + * logfile). + */ + IdeLogLevel getLogLevelLogger(); /** * @return {@code true} in case of quiet mode (reduced output), {@code false} otherwise. diff --git a/cli/src/main/java/com/devonfw/tools/ide/context/IdeStartContextImpl.java b/cli/src/main/java/com/devonfw/tools/ide/context/IdeStartContextImpl.java index 8afde36c76..18d7d996de 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/context/IdeStartContextImpl.java +++ b/cli/src/main/java/com/devonfw/tools/ide/context/IdeStartContextImpl.java @@ -1,17 +1,28 @@ package com.devonfw.tools.ide.context; import java.util.Locale; -import java.util.function.Function; -import com.devonfw.tools.ide.log.AbstractIdeSubLogger; +import com.devonfw.tools.ide.log.IdeLogArgFormatter; import com.devonfw.tools.ide.log.IdeLogLevel; -import com.devonfw.tools.ide.log.IdeLoggerImpl; -import com.devonfw.tools.ide.log.IdeSubLogger; +import com.devonfw.tools.ide.log.IdeLogListener; +import com.devonfw.tools.ide.log.IdeLogListenerBuffer; /** * Implementation of {@link IdeStartContext}. */ -public class IdeStartContextImpl extends IdeLoggerImpl implements IdeStartContext { +public class IdeStartContextImpl implements IdeStartContext { + + private static IdeStartContextImpl instance; + + protected final IdeLogListener logListener; + + protected final IdeLogListenerBuffer logListenerBuffer; + + private IdeLogLevel logLevelConsole; + + private IdeLogLevel logLevelLogger; + + private IdeLogArgFormatter argFormatter; private boolean skipUpdatesMode; @@ -33,15 +44,116 @@ public class IdeStartContextImpl extends IdeLoggerImpl implements IdeStartContex private boolean noColorsMode; + private boolean writeLogfile; + private Locale locale; /** - * @param minLogLevel the minimum enabled {@link IdeLogLevel}. - * @param factory the factory to create active {@link IdeSubLogger} instances. + * @param logLevelConsole the minimum enabled {@link #getLogLevelConsole() log level}. + * @param logListener the {@link #getLogListener() logListener}. */ - public IdeStartContextImpl(IdeLogLevel minLogLevel, Function factory) { + public IdeStartContextImpl(IdeLogLevel logLevelConsole, IdeLogListener logListener) { + + super(); + this.logLevelConsole = logLevelConsole; + this.logListener = logListener; + this.argFormatter = IdeLogArgFormatter.DEFAULT; + IdeStartContextImpl.instance = this; + if (logListener instanceof IdeLogListenerBuffer buffer) { + this.logListenerBuffer = buffer; + } else { + this.logListenerBuffer = null; + } + } + + @Override + public IdeLogListener getLogListener() { + + return this.logListener; + } + + @Override + public IdeLogLevel getLogLevelConsole() { - super(minLogLevel, factory); + return this.logLevelConsole; + } + + /** + * @param logLevelConsole the new {@link IdeLogLevel} for the console. + * @return the previous set logLevel {@link IdeLogLevel} + */ + public IdeLogLevel setLogLevelConsole(IdeLogLevel logLevelConsole) { + + IdeLogLevel previousLogLevel = this.logLevelConsole; + if ((previousLogLevel == null) || (previousLogLevel.ordinal() > IdeLogLevel.INFO.ordinal())) { + previousLogLevel = IdeLogLevel.INFO; + } + this.logLevelConsole = logLevelConsole; + return previousLogLevel; + } + + @Override + public IdeLogLevel getLogLevelLogger() { + + if (this.logLevelLogger == null) { + if ((this.logListenerBuffer != null) && (this.logListenerBuffer.isBuffering())) { + return IdeLogLevel.TRACE; + } + return this.logLevelConsole; + } + return this.logLevelLogger; + } + + /** + * @param logLevelLogger the new {@link #getLogLevelLogger() loglevel for the logger}. + */ + public void setLogLevelLogger(IdeLogLevel logLevelLogger) { + + this.logLevelLogger = logLevelLogger; + } + + /** + * @return the {@link IdeLogArgFormatter}. + */ + public IdeLogArgFormatter getArgFormatter() { + + return this.argFormatter; + } + + /** + * Internal method to set the {@link IdeLogArgFormatter}. + * + * @param argFormatter the new {@link IdeLogArgFormatter}. + */ + public void setArgFormatter(IdeLogArgFormatter argFormatter) { + + this.argFormatter = argFormatter; + } + + /** + * Ensure the logging system is initialized. + */ + public void activateLogging() { + + if (this.logListener instanceof IdeLogListenerBuffer buffer) { + // https://github.com/devonfw/IDEasy/issues/754 + buffer.flushAndEndBuffering(); + } + } + + /** + * Disables the logging system (temporary). + * + * @param threshold the {@link IdeLogLevel} acting as threshold. + * @see com.devonfw.tools.ide.context.IdeContext#runWithoutLogging(Runnable, IdeLogLevel) + */ + public void deactivateLogging(IdeLogLevel threshold) { + + if (this.logListener instanceof IdeLogListenerBuffer buffer) { + buffer.startBuffering(threshold); + } else { + throw new IllegalStateException(); + } } @Override @@ -104,18 +216,6 @@ public boolean isForcePull() { return this.forcePull; } - @Override - public boolean isForcePlugins() { - - return this.forcePlugins; - } - - @Override - public boolean isForceRepositories() { - - return this.forceRepositories; - } - /** * @param forcePull new value of {@link #isForcePull()}. */ @@ -124,6 +224,12 @@ public void setForcePull(boolean forcePull) { this.forcePull = forcePull; } + @Override + public boolean isForcePlugins() { + + return this.forcePlugins; + } + /** * @param forcePlugins new value of {@link #isForcePlugins()}. */ @@ -132,6 +238,12 @@ public void setForcePlugins(boolean forcePlugins) { this.forcePlugins = forcePlugins; } + @Override + public boolean isForceRepositories() { + + return this.forceRepositories; + } + /** * @param forceRepositories new value of {@link #isForceRepositories()}. */ @@ -194,6 +306,29 @@ public boolean isNoColorsMode() { public void setNoColorsMode(boolean noColoursMode) { this.noColorsMode = noColoursMode; - setLogColors(!noColoursMode); } + + /** + * @return {@code true} to write a logfile to disc, {@code false} otherwise. + */ + public boolean isWriteLogfile() { + + return this.writeLogfile; + } + + /** + * @param writeLogfile new value of {@link #isWriteLogfile()}. + */ + public void setWriteLogfile(boolean writeLogfile) { + this.writeLogfile = writeLogfile; + } + + /** + * @return the current {@link IdeStartContextImpl} instance. + */ + public static IdeStartContextImpl get() { + + return instance; + } + } 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 bce471f30d..6b12926a1f 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 @@ -7,8 +7,11 @@ import java.util.Map; import java.util.regex.Matcher; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.event.Level; + import com.devonfw.tools.ide.context.IdeContext; -import com.devonfw.tools.ide.log.IdeLogLevel; import com.devonfw.tools.ide.variable.IdeVariables; import com.devonfw.tools.ide.variable.VariableDefinition; import com.devonfw.tools.ide.variable.VariableSyntax; @@ -19,6 +22,8 @@ */ public abstract class AbstractEnvironmentVariables implements EnvironmentVariables { + private static final Logger LOG = LoggerFactory.getLogger(AbstractEnvironmentVariables.class); + /** * 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. @@ -225,15 +230,15 @@ private String resolveWithSyntax(final String value, final Object src, final int String variableName = syntax.getVariable(matcher); String variableValue = resolvedVars.getValue(variableName, false); if (variableValue == null) { - IdeLogLevel logLevel = IdeLogLevel.WARNING; + Level logLevel = Level.WARN; if (context.legacySupport && (syntax == VariableSyntax.CURLY)) { - logLevel = IdeLogLevel.INFO; + logLevel = Level.INFO; } String var = matcher.group(); if (recursion > 1) { - this.context.level(logLevel).log("Undefined variable {} in '{}' at '{}={}'", var, context.rootSrc, src, value); + LOG.atLevel(logLevel).log("Undefined variable {} in '{}' at '{}={}'", var, context.rootSrc, src, value); } else { - this.context.level(logLevel).log("Undefined variable {} in '{}'", var, src); + LOG.atLevel(logLevel).log("Undefined variable {} in '{}'", var, src); } continue; } @@ -265,8 +270,7 @@ private String resolveWithSyntax(final String value, final Object src, final int } while (matcher.find()); matcher.appendTail(sb); - String resolved = sb.toString(); - return resolved; + return sb.toString(); } /** @@ -307,7 +311,6 @@ protected String getValue(String name, boolean ignoreDefaultValue) { public String inverseResolve(String string, Object src, VariableSyntax syntax) { String result = string; - // TODO add more variables to IdeVariables like JAVA_HOME for (VariableDefinition variable : IdeVariables.VARIABLES) { if (variable != IdeVariables.PATH) { String name = variable.getName(); @@ -321,7 +324,7 @@ public String inverseResolve(String string, Object src, VariableSyntax syntax) { } } if (!result.equals(string)) { - this.context.trace("Inverse resolved '{}' to '{}' from {}.", string, result, src); + LOG.trace("Inverse resolved '{}' to '{}' from {}.", string, result, src); } return result; } @@ -334,7 +337,7 @@ public VersionIdentifier getToolVersion(String tool) { if (value == null) { return VersionIdentifier.LATEST; } else if (value.isEmpty()) { - this.context.warning("Variable {} is configured with empty value, please fix your configuration.", variable); + LOG.warn("Variable {} is configured with empty value, please fix your configuration.", variable); return VersionIdentifier.LATEST; } VersionIdentifier version = VersionIdentifier.of(value); diff --git a/cli/src/main/java/com/devonfw/tools/ide/environment/EnvironmentVariablesMap.java b/cli/src/main/java/com/devonfw/tools/ide/environment/EnvironmentVariablesMap.java index 71ad26a6fb..a823229bb1 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/environment/EnvironmentVariablesMap.java +++ b/cli/src/main/java/com/devonfw/tools/ide/environment/EnvironmentVariablesMap.java @@ -2,6 +2,9 @@ import java.util.Map; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.os.WindowsPathSyntax; @@ -10,6 +13,8 @@ */ abstract class EnvironmentVariablesMap extends AbstractEnvironmentVariables { + private static final Logger LOG = LoggerFactory.getLogger(EnvironmentVariablesMap.class); + /** * The constructor. * @@ -31,14 +36,14 @@ public String getFlat(String name) { String value = getVariables().get(name); if (value == null) { - this.context.trace("{}: Variable {} is undefined.", getSource(), name); + LOG.trace("{}: Variable {} is undefined.", getSource(), name); } else { - this.context.trace("{}: Variable {}={}", getSource(), name, value); + LOG.trace("{}: Variable {}={}", getSource(), name, value); WindowsPathSyntax pathSyntax = this.context.getPathSyntax(); if (pathSyntax != null) { String normalized = pathSyntax.normalize(value); if (!value.equals(normalized)) { - this.context.trace("Normalized {} using {} to {}", value, pathSyntax, normalized); + LOG.trace("Normalized {} using {} to {}", value, pathSyntax, normalized); value = normalized; } } diff --git a/cli/src/main/java/com/devonfw/tools/ide/environment/EnvironmentVariablesPropertiesFile.java b/cli/src/main/java/com/devonfw/tools/ide/environment/EnvironmentVariablesPropertiesFile.java index cc78465e2b..092b0423d7 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/environment/EnvironmentVariablesPropertiesFile.java +++ b/cli/src/main/java/com/devonfw/tools/ide/environment/EnvironmentVariablesPropertiesFile.java @@ -13,6 +13,9 @@ import java.util.Objects; import java.util.Set; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.variable.IdeVariables; import com.devonfw.tools.ide.variable.VariableDefinition; @@ -22,6 +25,8 @@ */ public final class EnvironmentVariablesPropertiesFile extends EnvironmentVariablesMap { + private static final Logger LOG = LoggerFactory.getLogger(EnvironmentVariablesPropertiesFile.class); + private static final String NEWLINE = "\n"; private final EnvironmentVariablesType type; @@ -117,29 +122,29 @@ private boolean load(Path file) { return false; } if (!Files.exists(file)) { - this.context.trace("Properties not found at {}", file); + LOG.trace("Properties not found at {}", file); return false; } - this.context.trace("Loading properties from {}", file); + LOG.trace("Loading properties from {}", file); boolean legacyProperties = file.getFileName().toString().equals(LEGACY_PROPERTIES); try (BufferedReader reader = Files.newBufferedReader(file)) { String line; do { line = reader.readLine(); if (line != null) { - VariableLine variableLine = VariableLine.of(line, this.context, getSource()); + VariableLine variableLine = VariableLine.of(line, getSource()); String name = variableLine.getName(); if (name != null) { VariableLine migratedVariableLine = migrateLine(variableLine, false); if (migratedVariableLine == null) { - this.context.warning("Illegal variable definition: {}", variableLine); + LOG.warn("Illegal variable definition: {}", variableLine); continue; } String migratedName = migratedVariableLine.getName(); String migratedValue = migratedVariableLine.getValue(); boolean legacyVariable = IdeVariables.isLegacyVariable(name); if (legacyVariable && !legacyProperties) { - this.context.warning("Legacy variable name is used to define variable {} in {} - please cleanup your configuration.", variableLine, + LOG.warn("Legacy variable name is used to define variable {} in {} - please cleanup your configuration.", variableLine, file); } String oldValue = this.variables.get(migratedName); @@ -147,10 +152,10 @@ private boolean load(Path file) { VariableDefinition variableDefinition = IdeVariables.get(name); if (legacyVariable) { // if the legacy name was configured we do not want to override the official variable! - this.context.warning("Both legacy variable {} and official variable {} are configured in {} - ignoring legacy variable declaration!", + LOG.warn("Both legacy variable {} and official variable {} are configured in {} - ignoring legacy variable declaration!", variableDefinition.getLegacyName(), variableDefinition.getName(), file); } else { - this.context.warning("Duplicate variable definition {} with old value '{}' and new value '{}' in {}", name, oldValue, migratedValue, + LOG.warn("Duplicate variable definition {} with old value '{}' and new value '{}' in {}", name, oldValue, migratedValue, file); this.variables.put(migratedName, migratedValue); } @@ -174,13 +179,13 @@ public void save() { boolean isLegacy = Boolean.TRUE.equals(this.legacyConfiguration); if (this.modifiedVariables.isEmpty() && !isLegacy) { - this.context.trace("No changes to save in properties file {}", this.propertiesFilePath); + LOG.trace("No changes to save in properties file {}", this.propertiesFilePath); return; } Path file = this.propertiesFilePath; if (isLegacy) { - this.context.info("Converting legacy properties to {}", this.propertiesFilePath); + LOG.info("Converting legacy properties to {}", this.propertiesFilePath); file = this.legacyPropertiesFilePath; } @@ -192,10 +197,10 @@ public void save() { for (VariableLine line : lines) { VariableLine newLine = migrateLine(line, true); if (newLine == null) { - this.context.debug("Removed variable line '{}' from {}", line, this.propertiesFilePath); + LOG.debug("Removed variable line '{}' from {}", line, this.propertiesFilePath); } else { if (newLine != line) { - this.context.debug("Changed variable line from '{}' to '{}' in {}", line, newLine, this.propertiesFilePath); + LOG.debug("Changed variable line from '{}' to '{}' in {}", line, newLine, this.propertiesFilePath); } writer.append(newLine.toString()); writer.append(NEWLINE); @@ -209,7 +214,7 @@ public void save() { for (String name : this.modifiedVariables) { String value = this.variables.get(name); if (value == null) { - this.context.trace("Internal error: removed variable {} was not found in {}", name, this.propertiesFilePath); + LOG.trace("Internal error: removed variable {} was not found in {}", name, this.propertiesFilePath); } else { boolean export = this.exportedVariables.contains(name); VariableLine line = VariableLine.of(export, name, value); @@ -228,7 +233,7 @@ private List loadVariableLines(Path file) { List lines = new ArrayList<>(); if (!Files.exists(file)) { // Skip reading if the file does not exist - this.context.debug("Properties file {} does not exist, skipping read.", file); + LOG.debug("Properties file {} does not exist, skipping read.", file); return lines; } try (BufferedReader reader = Files.newBufferedReader(file)) { @@ -236,7 +241,7 @@ private List loadVariableLines(Path file) { do { line = reader.readLine(); if (line != null) { - VariableLine variableLine = VariableLine.of(line, this.context, getSource()); + VariableLine variableLine = VariableLine.of(line, getSource()); lines.add(variableLine); } } while (line != null); @@ -336,9 +341,9 @@ public String set(String name, String value, boolean export) { String oldValue = this.variables.put(name, value); boolean flagChanged = export != this.exportedVariables.contains(name); if (Objects.equals(value, oldValue) && !flagChanged) { - this.context.trace("Set variable '{}={}' caused no change in {}", name, value, this.propertiesFilePath); + LOG.trace("Set variable '{}={}' caused no change in {}", name, value, this.propertiesFilePath); } else { - this.context.debug("Set variable '{}={}' in {}", name, value, this.propertiesFilePath); + LOG.debug("Set variable '{}={}' in {}", name, value, this.propertiesFilePath); this.modifiedVariables.add(name); if (export && (value != null)) { this.exportedVariables.add(name); @@ -359,7 +364,7 @@ public void remove(String name) { if (oldValue != null) { this.modifiedVariables.add(name); this.exportedVariables.remove(name); - this.context.debug("Removed variable name of '{}' in {}", name, this.propertiesFilePath); + LOG.debug("Removed variable name of '{}' in {}", name, this.propertiesFilePath); } } diff --git a/cli/src/main/java/com/devonfw/tools/ide/environment/IdeSystemImpl.java b/cli/src/main/java/com/devonfw/tools/ide/environment/IdeSystemImpl.java index 880e112229..10d4c04920 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/environment/IdeSystemImpl.java +++ b/cli/src/main/java/com/devonfw/tools/ide/environment/IdeSystemImpl.java @@ -4,36 +4,37 @@ import java.util.Objects; import java.util.Properties; -import com.devonfw.tools.ide.log.IdeLogger; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Implementation of {@link IdeSystem}. */ public class IdeSystemImpl implements IdeSystem { - private final IdeLogger logger; + private static final Logger LOG = LoggerFactory.getLogger(IdeSystemImpl.class); final Properties systemProperties; final Map environmentVariables; /** - * @param logger the {@link IdeLogger}. + * The constructor. */ - public IdeSystemImpl(IdeLogger logger) { + public IdeSystemImpl() { - this(logger, System.getProperties(), System.getenv()); + this(System.getProperties(), System.getenv()); } /** - * @param logger the {@link IdeLogger}. + * The constructor. + * * @param systemProperties the {@link System#getProperties() system properties}. * @param environmentVariables the {@link System#getenv() environment variables}. */ - protected IdeSystemImpl(IdeLogger logger, Properties systemProperties, Map environmentVariables) { + protected IdeSystemImpl(Properties systemProperties, Map environmentVariables) { super(); - this.logger = logger; this.systemProperties = systemProperties; this.environmentVariables = environmentVariables; } @@ -55,13 +56,13 @@ public void setProperty(String key, String value) { String old = getProperty(key); if (Objects.equals(old, value)) { - this.logger.trace("System property was already set to {}={}", key, value); + LOG.trace("System property was already set to {}={}", key, value); } else { this.systemProperties.put(key, value); if (old == null) { - this.logger.trace("System property was set to {}={}", key, value); + LOG.trace("System property was set to {}={}", key, value); } else { - this.logger.trace("System property was changed to {}={} from {}", key, value, old); + LOG.trace("System property was changed to {}={} from {}", key, value, old); } } } diff --git a/cli/src/main/java/com/devonfw/tools/ide/environment/VariableLine.java b/cli/src/main/java/com/devonfw/tools/ide/environment/VariableLine.java index c26539a996..4f807f1b4a 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/environment/VariableLine.java +++ b/cli/src/main/java/com/devonfw/tools/ide/environment/VariableLine.java @@ -3,8 +3,8 @@ import java.util.Arrays; import java.util.List; -import com.devonfw.tools.ide.context.IdeContext; -import com.devonfw.tools.ide.log.IdeLogger; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Container that represents a line from a properties (ide.properties) file. We do not use {@link java.util.Properties} as we need support for exported @@ -12,6 +12,8 @@ */ public abstract class VariableLine { + private static final Logger LOG = LoggerFactory.getLogger(VariableLine.class); + /** * @return {@code true} if the variable is exported (e.g. "export MAVEN_OPTS=-Xmx20248m"), {@code false} otherwise. */ @@ -81,7 +83,7 @@ public VariableLine withExport(boolean newExport) { static final class Variable extends VariableLine { - private boolean export; + private final boolean export; private final String name; @@ -239,11 +241,10 @@ public String toString() { * Parses a {@link VariableLine} from {@link String}. * * @param line the {@link VariableLine} as {@link String} to parse. - * @param logger the {@link IdeLogger}. * @param source the source where the given {@link String} to parse is from (e.g. the file path). * @return the parsed {@link VariableLine}. */ - public static VariableLine of(String line, IdeLogger logger, VariableSource source) { + public static VariableLine of(String line, VariableSource source) { int len = line.length(); int start = 0; @@ -291,7 +292,7 @@ public static VariableLine of(String line, IdeLogger logger, VariableSource sour } end++; } - logger.warning("Ignoring corrupted line '{}' in {}", line, source); + LOG.warn("Ignoring corrupted line '{}' in {}", line, source); return new Garbage(line); } @@ -331,7 +332,6 @@ public static boolean isBashArray(String value) { * Returns a list of String Variables. * * @param value String to parse - * @param context the {@link IdeContext} for logging warnings (may be {@code null}). * @return List of variables. */ public static List parseArray(String value) { @@ -346,9 +346,9 @@ public static List parseArray(String value) { } } return Arrays.stream(csv.split(separator)) - .map(String::trim) - .filter(s -> !s.isEmpty()) - .toList(); + .map(String::trim) + .filter(s -> !s.isEmpty()) + .toList(); } } diff --git a/cli/src/main/java/com/devonfw/tools/ide/git/GitContextImpl.java b/cli/src/main/java/com/devonfw/tools/ide/git/GitContextImpl.java index dd11f0bbb3..5b15438e6e 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/git/GitContextImpl.java +++ b/cli/src/main/java/com/devonfw/tools/ide/git/GitContextImpl.java @@ -7,8 +7,12 @@ import java.util.List; import java.util.Objects; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.cli.CliException; import com.devonfw.tools.ide.context.IdeContext; +import com.devonfw.tools.ide.log.IdeLogLevel; import com.devonfw.tools.ide.os.SystemInfoImpl; import com.devonfw.tools.ide.process.ProcessContext; import com.devonfw.tools.ide.process.ProcessErrorHandling; @@ -21,6 +25,8 @@ */ public class GitContextImpl implements GitContext { + private static final Logger LOG = LoggerFactory.getLogger(GitContextImpl.class); + /** @see #getContext() */ protected final IdeContext context; private Path git; @@ -118,14 +124,14 @@ private void handleErrors(Path targetRepository, ProcessResult result) { if (!result.isSuccessful()) { String message = "Failed to update git repository at " + targetRepository; if (this.context.isOfflineMode()) { - this.context.warning(message); - this.context.interaction("Continuing as we are in offline mode - results may be outdated!"); + LOG.warn(message); + IdeLogLevel.INTERACTION.log(LOG, "Continuing as we are in offline mode - results may be outdated!"); } else { - this.context.error(message); + LOG.error(message); if (this.context.isOnline()) { - this.context.error("See above error for details. If you have local changes, please stash or revert and retry."); + LOG.error("See above error for details. If you have local changes, please stash or revert and retry."); } else { - this.context.error("It seems you are offline - please ensure Internet connectivity and retry or activate offline mode (-o or --offline)."); + LOG.error("It seems you are offline - please ensure Internet connectivity and retry or activate offline mode (-o or --offline)."); } this.context.askToContinue("Typically you should abort and fix the problem. Do you want to continue anyways?"); } @@ -162,13 +168,13 @@ public void clone(GitUrl gitUrl, Path repository) { public void pull(Path repository) { if (this.context.isOffline()) { - this.context.info("Skipping git pull on {} because offline", repository); + LOG.info("Skipping git pull on {} because offline", repository); return; } ProcessResult result = runGitCommand(repository, ProcessMode.DEFAULT, "--no-pager", "pull", "--quiet"); if (!result.isSuccessful()) { String branchName = determineCurrentBranch(repository); - this.context.warning("Git pull on branch {} failed for repository {}.", branchName, repository); + LOG.warn("Git pull on branch {} failed for repository {}.", branchName, repository); handleErrors(repository, result); } } @@ -186,7 +192,7 @@ public void fetch(Path repository, String remote, String branch) { ProcessResult result = runGitCommand(repository, ProcessMode.DEFAULT_CAPTURE, "fetch", Objects.requireNonNullElse(remote, "origin"), branch); if (!result.isSuccessful()) { - this.context.warning("Git fetch for '{}/{} failed.'.", remote, branch); + LOG.warn("Git fetch for '{}/{} failed.'.", remote, branch); } } @@ -214,10 +220,10 @@ public void reset(Path repository, String branchName, String remoteName) { ProcessResult result = runGitCommand(repository, ProcessMode.DEFAULT, "diff-index", "--quiet", "HEAD"); if (!result.isSuccessful()) { // reset to origin/master - this.context.warning("Git has detected modified files -- attempting to reset {} to '{}/{}'.", repository, remoteName, branchName); + LOG.warn("Git has detected modified files -- attempting to reset {} to '{}/{}'.", repository, remoteName, branchName); result = runGitCommand(repository, ProcessMode.DEFAULT, "reset", "--hard", remoteName + "/" + branchName); if (!result.isSuccessful()) { - this.context.warning("Git failed to reset {} to '{}/{}'.", remoteName, branchName, repository); + LOG.warn("Git failed to reset {} to '{}/{}'.", remoteName, branchName, repository); handleErrors(repository, result); } } @@ -230,7 +236,7 @@ public void cleanup(Path repository) { ProcessResult result = runGitCommand(repository, ProcessMode.DEFAULT_CAPTURE, "ls-files", "--other", "--directory", "--exclude-standard"); if (!result.getOut().isEmpty()) { // delete untracked files - this.context.warning("Git detected untracked files in {} and is attempting a cleanup.", repository); + LOG.warn("Git detected untracked files in {} and is attempting a cleanup.", repository); runGitCommand(repository, "clean", "-df"); } } @@ -277,7 +283,7 @@ public Path findGit() { if (gitPath != null) { this.git = gitPath; - this.context.trace("Found git at: {}", gitPath); + LOG.trace("Found git at: {}", gitPath); } return gitPath; @@ -286,27 +292,27 @@ public Path findGit() { private Path findGitOnWindowsViaBash() { Path gitPath; Path bashBinary = this.context.findBashRequired(); - this.context.trace("Trying to find git path on Windows"); + LOG.trace("Trying to find git path on Windows"); if (Files.exists(bashBinary)) { gitPath = bashBinary.getParent().resolve("git.exe"); if (Files.exists(gitPath)) { - this.context.trace("Git path was extracted from bash path at: {}", gitPath); + LOG.trace("Git path was extracted from bash path at: {}", gitPath); } else { - this.context.error("Git path: {} was extracted from bash path at: {} but it does not exist", gitPath, bashBinary); + LOG.error("Git path: {} was extracted from bash path at: {} but it does not exist", gitPath, bashBinary); return null; } } else { - this.context.error("Bash path was checked at: {} but it does not exist", bashBinary); + LOG.error("Bash path was checked at: {} but it does not exist", bashBinary); return null; } return gitPath; } private Path findGitInPath(Path gitPath) { - this.context.trace("Trying to find git executable within the PATH environment variable"); + LOG.trace("Trying to find git executable within the PATH environment variable"); Path binaryGitPath = this.context.getPath().findBinary(gitPath); if (gitPath == binaryGitPath) { - this.context.debug("No git executable could be found within the PATH environment variable"); + LOG.debug("No git executable could be found within the PATH environment variable"); return null; } return binaryGitPath; @@ -334,7 +340,7 @@ private String runGitCommandAndGetSingleOutput(String warningOnError, Path direc private String runGitCommandAndGetSingleOutput(String warningOnError, Path directory, ProcessMode mode, String... args) { ProcessErrorHandling errorHandling = ProcessErrorHandling.NONE; - if (this.context.debug().isEnabled()) { + if (LOG.isDebugEnabled()) { errorHandling = ProcessErrorHandling.LOG_WARNING; } ProcessResult result = runGitCommand(directory, mode, errorHandling, args); @@ -342,14 +348,14 @@ private String runGitCommandAndGetSingleOutput(String warningOnError, Path direc List out = result.getOut(); int size = out.size(); if (size == 1) { - return out.get(0); + return out.getFirst(); } else if (size == 0) { warningOnError += " - No output received from " + result.getCommand(); } else { warningOnError += " - Expected single line of output but received " + size + " lines from " + result.getCommand(); } } - this.context.warning(warningOnError); + LOG.warn(warningOnError); return null; } @@ -378,10 +384,10 @@ private ProcessResult runGitCommand(Path directory, ProcessMode mode, ProcessErr public void saveCurrentCommitId(Path repository, Path trackedCommitIdPath) { if ((repository == null) || (trackedCommitIdPath == null)) { - this.context.warning("Invalid usage of saveCurrentCommitId with null value"); + LOG.warn("Invalid usage of saveCurrentCommitId with null value"); return; } - this.context.trace("Saving commit Id of {} into {}", repository, trackedCommitIdPath); + LOG.trace("Saving commit Id of {} into {}", repository, trackedCommitIdPath); String currentCommitId = determineCurrentCommitId(repository); if (currentCommitId != null) { try { diff --git a/cli/src/main/java/com/devonfw/tools/ide/git/GitOperation.java b/cli/src/main/java/com/devonfw/tools/ide/git/GitOperation.java index a682ae4c45..6eed32cbda 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/git/GitOperation.java +++ b/cli/src/main/java/com/devonfw/tools/ide/git/GitOperation.java @@ -4,6 +4,9 @@ import java.nio.file.Path; import java.time.Duration; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.context.IdeContext; /** @@ -35,6 +38,8 @@ protected boolean execute(IdeContext context, GitUrl gitUrl, Path targetReposito } }; + private static final Logger LOG = LoggerFactory.getLogger(GitOperation.class); + private final String name; private final String timestampFilename; @@ -127,12 +132,12 @@ boolean executeIfNeeded(IdeContext context, GitUrl gitUrl, Path targetRepository try { context.getFileAccess().touch(timestampPath); } catch (IllegalStateException e) { - context.warning(e.getMessage()); + LOG.warn(e.getMessage()); } } return result; } else { - context.trace("Skipped git {}.", this.name); + LOG.trace("Skipped git {}.", this.name); return false; } } @@ -146,16 +151,16 @@ private boolean isNeeded(Path targetRepository, IdeContext context) { return true; } if (context.isOffline()) { - context.info("Skipping git {} on {} because we are offline.", this.name, targetRepository); + LOG.info("Skipping git {} on {} because we are offline.", this.name, targetRepository); return false; } else if (context.isForceMode() || context.isForcePull()) { - context.debug("Enforcing git {} on {} because force mode is active.", this.name, targetRepository); + LOG.debug("Enforcing git {} on {} because force mode is active.", this.name, targetRepository); return true; } if (!hasGitDirectory) { if (isRequireGitFolder()) { if (context.getSettingsGitRepository() == null) { - context.warning("Missing .git folder in {}.", targetRepository); + LOG.warn("Missing .git folder in {}.", targetRepository); } } else { logEnforceGitOperationBecauseGitFolderNotPresent(targetRepository, context); @@ -164,17 +169,17 @@ private boolean isNeeded(Path targetRepository, IdeContext context) { } Path timestampFilePath = gitDirectory.resolve(this.timestampFilename); if (context.getFileAccess().isFileAgeRecent(timestampFilePath, this.cacheDuration)) { - context.debug("Skipping git {} on {} because last fetch was just recently to avoid overhead.", this.name, + LOG.debug("Skipping git {} on {} because last fetch was just recently to avoid overhead.", this.name, targetRepository); return false; } else { - context.debug("Will need to do git {} on {} because last fetch was some time ago.", this.name, targetRepository); + LOG.debug("Will need to do git {} on {} because last fetch was some time ago.", this.name, targetRepository); return true; } } private void logEnforceGitOperationBecauseGitFolderNotPresent(Path targetRepository, IdeContext context) { - context.debug("Enforcing git {} on {} because .git folder is not present.", this.name, targetRepository); + LOG.debug("Enforcing git {} on {} because .git folder is not present.", this.name, targetRepository); } } diff --git a/cli/src/main/java/com/devonfw/tools/ide/git/repository/RepositoryCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/git/repository/RepositoryCommandlet.java index 93b7872348..54c5e72dbf 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/git/repository/RepositoryCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/git/repository/RepositoryCommandlet.java @@ -5,6 +5,9 @@ import java.util.List; import java.util.Set; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.commandlet.Commandlet; import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.git.GitContext; @@ -20,6 +23,8 @@ */ public class RepositoryCommandlet extends Commandlet { + private static final Logger LOG = LoggerFactory.getLogger(RepositoryCommandlet.class); + /** the repository to setup. */ public final RepositoryProperty repository; @@ -43,7 +48,7 @@ public String getName() { } @Override - public void run() { + protected void doRun() { Path repositoryFile = this.repository.getValue(); @@ -54,7 +59,7 @@ public void run() { // If no specific repository is provided, check for repositories folder Path repositoriesPath = this.context.getRepositoriesPath(); if (repositoriesPath == null) { - this.context.warning("Cannot find folder 'repositories' nor 'projects' in your settings."); + LOG.warn("Cannot find folder 'repositories' nor 'projects' in your settings."); return; } List propertiesFiles = this.context.getFileAccess() @@ -84,9 +89,9 @@ private void doImportRepository(Path repositoryFile, boolean forceMode, String r RepositoryConfig repositoryConfig = RepositoryConfig.loadProperties(repositoryFile, this.context); if (!repositoryConfig.active()) { if (forceMode) { - this.context.info("Setup of repository {} is forced, hence proceeding ...", repositoryId); + LOG.info("Setup of repository {} is forced, hence proceeding ...", repositoryId); } else { - this.context.info("Skipping repository {} because it is not active - use --force to setup all repositories ...", repositoryId); + LOG.info("Skipping repository {} because it is not active - use --force to setup all repositories ...", repositoryId); return; } } @@ -95,7 +100,7 @@ private void doImportRepository(Path repositoryFile, boolean forceMode, String r // error was already logged. return; } - this.context.debug("Repository configuration: {}", repositoryConfig); + LOG.debug("Repository configuration: {}", repositoryConfig); List workspaces = repositoryConfig.workspaces(); String repositoryRelativePath = repositoryConfig.path(); if (repositoryRelativePath == null) { @@ -113,16 +118,16 @@ private void doImportRepository(Path repositoryFile, boolean forceMode, String r if (firstRepository == null) { firstRepository = repositoryPath; } - this.context.info("Repository {} already exists in workspace {} at {}", repositoryId, workspaceName, repositoryPath); + LOG.info("Repository {} already exists in workspace {} at {}", repositoryId, workspaceName, repositoryPath); if (!(this.context.isForceMode() || this.context.isForceRepositories())) { - this.context.info("Ignoring repository {} in workspace {} - use --force or --force-repositories to rerun setup.", repositoryId, workspaceName); + LOG.info("Ignoring repository {} in workspace {} - use --force or --force-repositories to rerun setup.", repositoryId, workspaceName); continue; } } Path repositoryCreatedStatusFile = ideStatusDir.resolve("repository." + repositoryId + "." + workspaceName); if (Files.exists(repositoryCreatedStatusFile)) { if (!(this.context.isForceMode() || this.context.isForceRepositories())) { - this.context.info("Ignoring repository {} in workspace {} because it was already setup before - use --force or --force-repositories for recreation.", + LOG.info("Ignoring repository {} in workspace {} because it was already setup before - use --force or --force-repositories for recreation.", repositoryId, workspaceName); continue; } @@ -159,7 +164,8 @@ private boolean buildRepository(RepositoryConfig repositoryConfig, Path reposito ToolCommandlet commandlet = this.context.getCommandletManager().getToolCommandlet(command[0]); if (commandlet == null) { String displayName = (command[0] == null || command[0].isBlank()) ? "" : "'" + command[0] + "'"; - this.context.error("Cannot build repository. Required tool '{}' not found. Please check your repository's build_cmd configuration value.", displayName); + LOG.error("Cannot build repository. Required tool '{}' not found. Please check your repository's build_cmd configuration value.", + displayName); return; } commandlet.reset(); @@ -175,7 +181,7 @@ private boolean buildRepository(RepositoryConfig repositoryConfig, Path reposito commandlet.run(); }); } else { - this.context.debug("Build command not set. Skipping build for repository."); + LOG.debug("Build command not set. Skipping build for repository."); return true; } } @@ -184,7 +190,7 @@ private void importRepository(RepositoryConfig repositoryConfig, Path repository Set imports = repositoryConfig.imports(); if ((imports == null) || imports.isEmpty()) { - this.context.debug("Repository {} has no IDE configured for import.", repositoryId); + LOG.debug("Repository {} has no IDE configured for import.", repositoryId); return; } for (String ide : imports) { @@ -193,7 +199,8 @@ private void importRepository(RepositoryConfig repositoryConfig, Path repository ToolCommandlet commandlet = this.context.getCommandletManager().getToolCommandlet(ide); if (commandlet == null) { String displayName = (ide == null || ide.isBlank()) ? "" : "'" + ide + "'"; - step.error("Cannot import repository '{}'. Required IDE '{}' not found. Please check your repository's imports configuration.", repositoryId, displayName); + step.error("Cannot import repository '{}'. Required IDE '{}' not found. Please check your repository's imports configuration.", repositoryId, + displayName); } else if (commandlet instanceof IdeToolCommandlet ideCommandlet) { ideCommandlet.importRepository(repositoryPath); } else { diff --git a/cli/src/main/java/com/devonfw/tools/ide/git/repository/RepositoryProperties.java b/cli/src/main/java/com/devonfw/tools/ide/git/repository/RepositoryProperties.java index f9e07cc526..e6db096b76 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/git/repository/RepositoryProperties.java +++ b/cli/src/main/java/com/devonfw/tools/ide/git/repository/RepositoryProperties.java @@ -10,6 +10,9 @@ import java.util.Set; import java.util.stream.Collectors; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.cli.CliException; import com.devonfw.tools.ide.context.IdeContext; @@ -18,12 +21,12 @@ */ final class RepositoryProperties { + private static final Logger LOG = LoggerFactory.getLogger(RepositoryProperties.class); + private final Path file; private final Properties properties; - private final IdeContext context; - /** * The constructor. * @@ -31,19 +34,17 @@ final class RepositoryProperties { * @param context the {@link IdeContext}. */ public RepositoryProperties(Path file, IdeContext context) { - this(file, context, context.getFileAccess().readProperties(file)); + this(file, context.getFileAccess().readProperties(file)); } /** * @param file the {@link Path} to the properties file. - * @param context the {@link IdeContext}. * @param properties the actual {@link Properties} loaded from the file. */ - RepositoryProperties(Path file, IdeContext context, Properties properties) { + RepositoryProperties(Path file, Properties properties) { super(); this.file = file; this.properties = properties; - this.context = context; } /** @@ -90,7 +91,7 @@ private String getLegacyProperty(String legacyName, String name) { String value = this.properties.getProperty(legacyName); if (value != null) { - this.context.warning("The properties file {} uses the legacy property {} instead of {}", this.file, legacyName, name); + LOG.warn("The properties file {} uses the legacy property {} instead of {}", this.file, legacyName, name); } return value; } @@ -110,7 +111,7 @@ public Set getImports() { String legacyImportProperty = getLegacyProperty(RepositoryConfig.PROPERTY_ECLIPSE, RepositoryConfig.PROPERTY_IMPORT); if ("import".equals(legacyImportProperty)) { - this.context.warning("Property {} is deprecated and should be replaced with {} (invert key and value).", RepositoryConfig.PROPERTY_ECLIPSE, + LOG.warn("Property {} is deprecated and should be replaced with {} (invert key and value).", RepositoryConfig.PROPERTY_ECLIPSE, RepositoryConfig.PROPERTY_IMPORT); return Set.of("eclipse"); } else { @@ -127,7 +128,7 @@ public List getWorkspaces() { if (workspaceProperty == null) { workspaceProperty = this.properties.getProperty("workspace"); if (workspaceProperty != null) { - this.context.debug("Property workspace is legacy, please change property name to workspaces in {}", this.file); + LOG.debug("Property workspace is legacy, please change property name to workspaces in {}", this.file); } } if ((workspaceProperty != null) && !workspaceProperty.isEmpty()) { @@ -139,7 +140,7 @@ public List getWorkspaces() { if (added) { list.add(workspace); } else { - this.context.warning("Ignoring duplicate workspace {} from {}", workspace, workspaceProperty); + LOG.warn("Ignoring duplicate workspace {} from {}", workspace, workspaceProperty); } } return Collections.unmodifiableList(list); diff --git a/cli/src/main/java/com/devonfw/tools/ide/io/FileAccessImpl.java b/cli/src/main/java/com/devonfw/tools/ide/io/FileAccessImpl.java index 0f664365ef..ca756df280 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/io/FileAccessImpl.java +++ b/cli/src/main/java/com/devonfw/tools/ide/io/FileAccessImpl.java @@ -50,6 +50,8 @@ import org.apache.commons.compress.compressors.bzip2.BZip2CompressorOutputStream; import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream; import org.apache.commons.io.IOUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.devonfw.tools.ide.cli.CliException; import com.devonfw.tools.ide.context.IdeContext; @@ -70,6 +72,8 @@ */ public class FileAccessImpl extends HttpDownloader implements FileAccess { + private static final Logger LOG = LoggerFactory.getLogger(FileAccessImpl.class); + private static final String WINDOWS_FILE_LOCK_DOCUMENTATION_PAGE = "https://github.com/devonfw/IDEasy/blob/main/documentation/windows-file-lock.adoc"; private static final String WINDOWS_FILE_LOCK_WARNING = @@ -136,9 +140,9 @@ private void downloadViaHttp(String url, Path target) { private void downloadWithHttpVersion(String url, Path target, Version httpVersion) throws Exception { if (httpVersion == null) { - this.context.info("Trying to download {} from {}", target.getFileName(), url); + LOG.info("Trying to download {} from {}", target.getFileName(), url); } else { - this.context.info("Trying to download {} from {} with HTTP protocol version {}", target.getFileName(), url, httpVersion); + LOG.info("Trying to download {} from {} with HTTP protocol version {}", target.getFileName(), url, httpVersion); } mkdirs(target.getParent()); this.context.getNetworkStatus().invokeNetworkTask(() -> @@ -159,7 +163,7 @@ private void downloadFileWithProgressBar(String url, Path target, HttpResponse postExtractHook, boolean extract) { if (Files.isDirectory(archiveFile)) { - this.context.warning("Found directory for download at {} hence copying without extraction!", archiveFile); + LOG.warn("Found directory for download at {} hence copying without extraction!", archiveFile); copy(archiveFile, targetDir, FileCopyMode.COPY_TREE_CONTENT); postExtractHook(postExtractHook, targetDir); return; @@ -595,7 +599,7 @@ public void extract(Path archiveFile, Path targetDir, Consumer postExtract return; } Path tmpDir = createTempDir("extract-" + archiveFile.getFileName()); - this.context.trace("Trying to extract the file {} to {} and move it to {}.", archiveFile, tmpDir, targetDir); + LOG.trace("Trying to extract the file {} to {} and move it to {}.", archiveFile, tmpDir, targetDir); String filename = archiveFile.getFileName().toString(); TarCompression tarCompression = TarCompression.of(filename); if (tarCompression != null) { @@ -605,7 +609,7 @@ public void extract(Path archiveFile, Path targetDir, Consumer postExtract if (extension == null) { throw new IllegalStateException("Unknown archive format without extension - can not extract " + archiveFile); } else { - this.context.trace("Determined file extension {}", extension); + LOG.trace("Determined file extension {}", extension); } switch (extension) { case "zip" -> extractZip(archiveFile, tmpDir); @@ -656,7 +660,7 @@ private Path getProperInstallationSubDirOf(Path path, Path archiveFile) { @Override public void extractZip(Path file, Path targetDir) { - this.context.info("Extracting ZIP file {} to {}", file, targetDir); + LOG.info("Extracting ZIP file {} to {}", file, targetDir); URI uri = URI.create("jar:" + file.toUri()); try (FileSystem fs = FileSystems.newFileSystem(uri, FS_ENV)) { long size = 0; @@ -686,7 +690,7 @@ private void onFileCopiedFromZip(Path source, Path target, boolean directory, Id Files.setPosixFilePermissions(target, (Set) permissionSet); } } catch (Exception e) { - this.context.error(e, "Failed to transfer zip permissions for {}", target); + LOG.error("Failed to transfer zip permissions for {}", target, e); } } progressBar.stepBy(getFileSize(target)); @@ -725,7 +729,7 @@ public static String generatePermissionString(int permissions) { private void extractArchive(Path file, Path targetDir, Function> unpacker) { - this.context.info("Extracting TAR file {} to {}", file, targetDir); + LOG.info("Extracting TAR file {} to {}", file, targetDir); final List links = new ArrayList<>(); try (InputStream is = Files.newInputStream(file); @@ -796,7 +800,7 @@ private Path resolveRelativePathSecure(Path entryPath, Path root, String entryNa @Override public void extractDmg(Path file, Path targetDir) { - this.context.info("Extracting DMG file {} to {}", file, targetDir); + LOG.info("Extracting DMG file {} to {}", file, targetDir); assert this.context.getSystemInfo().isMac(); Path mountPath = this.context.getIdeHome().resolve(IdeContext.FOLDER_UPDATES).resolve(IdeContext.FOLDER_VOLUME); @@ -818,7 +822,7 @@ public void extractDmg(Path file, Path targetDir) { @Override public void extractMsi(Path file, Path targetDir) { - this.context.info("Extracting MSI file {} to {}", file, targetDir); + LOG.info("Extracting MSI file {} to {}", file, targetDir); this.context.newProcess().executable("msiexec").addArgs("/a", file, "/qn", "TARGETDIR=" + targetDir).run(); // msiexec also creates a copy of the MSI Path msiCopy = targetDir.resolve(file.getFileName()); @@ -828,7 +832,7 @@ public void extractMsi(Path file, Path targetDir) { @Override public void extractPkg(Path file, Path targetDir) { - this.context.info("Extracting PKG file {} to {}", file, targetDir); + LOG.info("Extracting PKG file {} to {}", file, targetDir); Path tmpDirPkg = createTempDir("ide-pkg-"); ProcessContext pc = this.context.newProcess(); // we might also be able to use cpio from commons-compression instead of external xar... @@ -955,10 +959,10 @@ private void compressRecursive(Path path, ArchiveOutput public void delete(Path path) { if (!Files.exists(path, LinkOption.NOFOLLOW_LINKS)) { - this.context.trace("Deleting {} skipped as the path does not exist.", path); + LOG.trace("Deleting {} skipped as the path does not exist.", path); return; } - this.context.debug("Deleting {} ...", path); + LOG.debug("Deleting {} ...", path); try { if (Files.isSymbolicLink(path) || isJunction(path)) { Files.delete(path); @@ -981,10 +985,10 @@ private void deleteRecursive(Path path) throws IOException { } } } - this.context.trace("Deleting {} ...", path); + LOG.trace("Deleting {} ...", path); boolean isSetWritable = setWritable(path, true); if (!isSetWritable) { - this.context.debug("Couldn't give write access to file: " + path); + LOG.debug("Couldn't give write access to file: {}", path); } Files.delete(path); } @@ -1034,7 +1038,7 @@ private Path findFirstRecursive(Path dir, Predicate filter, boolean recurs public Path findAncestor(Path path, Path baseDir, int subfolderCount) { if ((path == null) || (baseDir == null)) { - this.context.debug("Path should not be null for findAncestor."); + LOG.debug("Path should not be null for findAncestor."); return null; } if (subfolderCount <= 0) { @@ -1080,13 +1084,13 @@ public List listChildrenMapped(Path dir, Function filter) { Path filteredChild = filter.apply(child); if (filteredChild != null) { if (filteredChild == child) { - this.context.trace("Accepted file {}", child); + LOG.trace("Accepted file {}", child); } else { - this.context.trace("Accepted file {} and mapped to {}", child, filteredChild); + LOG.trace("Accepted file {} and mapped to {}", child, filteredChild); } children.add(filteredChild); } else { - this.context.trace("Ignoring file {} according to filter", child); + LOG.trace("Ignoring file {} according to filter", child); } } } catch (IOException e) { @@ -1115,7 +1119,7 @@ private long getFileSize(Path file) { try { return Files.size(file); } catch (IOException e) { - this.context.warning(e.getMessage(), e); + LOG.warn("Failed to determine size of file {}: {}", file, e.toString(), e); return 0; } } @@ -1182,11 +1186,11 @@ public boolean setWritable(Path file, boolean writable) { return true; } - this.context.debug("Failed to set writing permission for file {}", file); + LOG.debug("Failed to set writing permission for file {}", file); return false; } catch (IOException e) { - this.context.debug("Error occurred when trying to set writing permission for file " + file + ": " + e); + LOG.debug("Error occurred when trying to set writing permission for file {}: {}", file, e.toString(), e); return false; } } @@ -1217,10 +1221,10 @@ public void makeExecutable(Path path, boolean confirm) { } setFilePermissions(path, executablePermissions, false); } else { - this.context.trace("Executable flags already present so no need to set them for file {}", path); + LOG.trace("Executable flags already present so no need to set them for file {}", path); } } else { - this.context.warning("Cannot set executable flag on file that does not exist: {}", path); + LOG.warn("Cannot set executable flag on file that does not exist: {}", path); } } @@ -1251,7 +1255,7 @@ public PathPermissions getFilePermissions(Path path) { } pathPermissions = PathPermissions.of(permissions); } - this.context.trace("Read {}permissions of {} as {}.", info, path, pathPermissions); + LOG.trace("Read {}permissions of {} as {}.", info, path, pathPermissions); return pathPermissions; } @@ -1262,14 +1266,15 @@ public void setFilePermissions(Path path, PathPermissions permissions, boolean l return; } try { - this.context.debug("Setting permissions for {} to {}", path, permissions); + LOG.debug("Setting permissions for {} to {}", path, permissions); // Set the new permissions Files.setPosixFilePermissions(path, permissions.toPosix()); } catch (IOException e) { + String message = "Failed to set permissions to " + permissions + " for path " + path; if (logErrorAndContinue) { - this.context.warning().log(e, "Failed to set permissions to {} for path {}", permissions, path); + LOG.warn(message, e); } else { - throw new RuntimeException("Failed to set permissions to " + permissions + " for path " + path, e); + throw new RuntimeException(message, e); } } } @@ -1277,7 +1282,7 @@ public void setFilePermissions(Path path, PathPermissions permissions, boolean l private boolean skipPermissionsIfWindows(Path path) { if (SystemInfoImpl.INSTANCE.isWindows()) { - this.context.trace("Windows does not have file permissions hence omitting for {}", path); + LOG.trace("Windows does not have file permissions hence omitting for {}", path); return true; } return false; @@ -1304,14 +1309,14 @@ public void touch(Path file) { @Override public String readFileContent(Path file) { - this.context.trace("Reading content of file from {}", file); + LOG.trace("Reading content of file from {}", file); if (!Files.exists((file))) { - this.context.debug("File {} does not exist", file); + LOG.debug("File {} does not exist", file); return null; } try { String content = Files.readString(file); - this.context.trace("Completed reading {} character(s) from file {}", content.length(), file); + LOG.trace("Completed reading {} character(s) from file {}", content.length(), file); return content; } catch (IOException e) { throw new IllegalStateException("Failed to read file " + file, e); @@ -1327,13 +1332,13 @@ public void writeFileContent(String content, Path file, boolean createParentDir) if (content == null) { content = ""; } - this.context.trace("Writing content with {} character(s) to file {}", content.length(), file); + LOG.trace("Writing content with {} character(s) to file {}", content.length(), file); if (Files.exists(file)) { - this.context.info("Overriding content of file {}", file); + LOG.info("Overriding content of file {}", file); } try { Files.writeString(file, content); - this.context.trace("Wrote content to file {}", file); + LOG.trace("Wrote content to file {}", file); } catch (IOException e) { throw new RuntimeException("Failed to write file " + file, e); } @@ -1342,14 +1347,14 @@ public void writeFileContent(String content, Path file, boolean createParentDir) @Override public List readFileLines(Path file) { - this.context.trace("Reading content of file from {}", file); + LOG.trace("Reading lines of file from {}", file); if (!Files.exists(file)) { - this.context.warning("File {} does not exist", file); + LOG.warn("File {} does not exist", file); return null; } try { List content = Files.readAllLines(file); - this.context.trace("Completed reading {} lines from file {}", content.size(), file); + LOG.trace("Completed reading {} lines from file {}", content.size(), file); return content; } catch (IOException e) { throw new IllegalStateException("Failed to read file " + file, e); @@ -1365,13 +1370,13 @@ public void writeFileLines(List content, Path file, boolean createParent if (content == null) { content = List.of(); } - this.context.trace("Writing content with {} lines to file {}", content.size(), file); + LOG.trace("Writing content with {} lines to file {}", content.size(), file); if (Files.exists(file)) { - this.context.debug("Overriding content of file {}", file); + LOG.debug("Overriding content of file {}", file); } try { Files.write(file, content); - this.context.trace("Wrote content to file {}", file); + LOG.trace("Wrote lines to file {}", file); } catch (IOException e) { throw new RuntimeException("Failed to write file " + file, e); } @@ -1382,7 +1387,7 @@ public void readProperties(Path file, Properties properties) { try (Reader reader = Files.newBufferedReader(file)) { properties.load(reader); - this.context.debug("Successfully loaded {} properties from {}", properties.size(), file); + LOG.debug("Successfully loaded {} properties from {}", properties.size(), file); } catch (IOException e) { throw new IllegalStateException("Failed to read properties file: " + file, e); } @@ -1396,7 +1401,7 @@ public void writeProperties(Properties properties, Path file, boolean createPare } try (Writer writer = Files.newBufferedWriter(file)) { properties.store(writer, null); // do not get confused - Java still writes a date/time header that cannot be omitted - this.context.debug("Successfully saved {} properties to {}", properties.size(), file); + LOG.debug("Successfully saved {} properties to {}", properties.size(), file); } catch (IOException e) { throw new IllegalStateException("Failed to save properties file during tests.", e); } @@ -1406,7 +1411,7 @@ public void writeProperties(Properties properties, Path file, boolean createPare public void readIniFile(Path file, IniFile iniFile) { if (!Files.exists(file)) { - this.context.debug("INI file {} does not exist.", iniFile); + LOG.debug("INI file {} does not exist.", iniFile); return; } List iniLines = readFileLines(file); @@ -1441,10 +1446,10 @@ public Duration getFileAge(Path path) { long fileModifiedTime = Files.getLastModifiedTime(path).toMillis(); return Duration.ofMillis(currentTime - fileModifiedTime); } catch (IOException e) { - this.context.warning().log(e, "Could not get modification-time of {}.", path); + LOG.warn("Could not get modification-time of {}.", path, e); } } else { - this.context.debug("Path {} is missing - skipping modification-time and file age check.", path); + LOG.debug("Path {} is missing - skipping modification-time and file age check.", path); } return null; } @@ -1456,7 +1461,7 @@ public boolean isFileAgeRecent(Path path, Duration cacheDuration) { if (age == null) { return false; } - this.context.debug("The path {} was last updated {} ago and caching duration is {}.", path, age, cacheDuration); + LOG.debug("The path {} was last updated {} ago and caching duration is {}.", path, age, cacheDuration); return (age.toMillis() <= cacheDuration.toMillis()); } } diff --git a/cli/src/main/java/com/devonfw/tools/ide/log/AbstractIdeSubLogger.java b/cli/src/main/java/com/devonfw/tools/ide/log/AbstractIdeSubLogger.java deleted file mode 100644 index 5081fc5f7d..0000000000 --- a/cli/src/main/java/com/devonfw/tools/ide/log/AbstractIdeSubLogger.java +++ /dev/null @@ -1,192 +0,0 @@ -package com.devonfw.tools.ide.log; - -import com.devonfw.tools.ide.cli.CliException; - -/** - * Abstract base implementation of {@link IdeSubLogger}. - */ -public abstract class AbstractIdeSubLogger implements IdeSubLogger { - - /** @see #getLevel() */ - protected final IdeLogLevel level; - - protected final IdeLogExceptionDetails exceptionDetails; - - final IdeLogListener listener; - - protected boolean colored; - - private boolean enabled; - - private IdeLogArgFormatter argFormatter; - - /** - * The constructor. - * - * @param level the {@link #getLevel() log-level}. - * @param colored - see {@link #isColored()}. - * @param exceptionDetails the {@link IdeLogExceptionDetails} configuring how to handle exceptions. - * @param listener the {@link IdeLogListener} to send log-events to. - */ - public AbstractIdeSubLogger(IdeLogLevel level, boolean colored, IdeLogExceptionDetails exceptionDetails, IdeLogListener listener) { - - super(); - this.level = level; - this.exceptionDetails = exceptionDetails; - this.argFormatter = IdeLogArgFormatter.DEFAULT; - if (listener == null) { - this.listener = IdeLogListenerNone.INSTANCE; - } else { - this.listener = listener; - } - this.colored = colored; - this.enabled = true; - } - - @Override - public IdeLogLevel getLevel() { - - return this.level; - } - - @Override - public boolean isEnabled() { - - return this.enabled; - } - - void setEnabled(boolean enabled) { - - this.enabled = enabled; - } - - void setColored(boolean colored) { - - this.colored = colored; - } - - /** - * Should only be used internally by logger implementation. - * - * @param message the message template. - * @param args the dynamic arguments to fill in. - * @return the resolved message with the parameters filled in. - */ - protected String compose(String message, Object... args) { - - int pos = message.indexOf("{}"); - if (pos < 0) { - if (args.length > 0) { - invalidMessage(message, false, args); - } - return message; - } - int argIndex = 0; - int start = 0; - int length = message.length(); - StringBuilder sb = new StringBuilder(length + 48); - while (pos >= 0) { - sb.append(message, start, pos); - sb.append(this.argFormatter.formatArgument(args[argIndex++])); - start = pos + 2; - pos = message.indexOf("{}", start); - if ((argIndex >= args.length) && (pos > 0)) { - invalidMessage(message, true, args); - pos = -1; - } - } - if (start < length) { - String rest = message.substring(start); - sb.append(rest); - } - if (argIndex < args.length) { - invalidMessage(message, false, args); - } - return sb.toString(); - } - - private void invalidMessage(String message, boolean more, Object[] args) { - - warning("Invalid log message with " + args.length + " argument(s) but " + (more ? "more" : "less") - + " placeholders: " + message); - } - - private void warning(String message) { - - boolean colored = isColored(); - if (colored) { - System.err.print(IdeLogLevel.ERROR.getEndColor()); - System.err.print(IdeLogLevel.ERROR.getStartColor()); - } - System.err.println(message); - if (colored) { - System.err.print(IdeLogLevel.ERROR.getEndColor()); - } - } - - /** - * @return {@code true} if colored logging is used, {@code false} otherwise. - */ - public boolean isColored() { - - return this.colored; - } - - @Override - public String log(Throwable error, String message, Object... args) { - - if (!this.enabled) { - // performance optimization: do not fill in arguments if disabled - return message; - } - String actualMessage = message; - if (error != null) { - if (isOmitStacktrace(error)) { - if (message == null) { - actualMessage = error.getMessage(); - } - error = null; - } else if (message == null) { - actualMessage = error.toString(); - } - } - if (actualMessage == null) { - actualMessage = "Internal error: Both message and error is null - nothing to log!"; - // fail fast if assertions are enabled, so developers of IDEasy will find the bug immediately but in productive use better log the error and continue - assert false : actualMessage; - } else if ((args != null) && (args.length > 0)) { - actualMessage = compose(actualMessage, args); - } - boolean accept = this.listener.onLog(this.level, actualMessage, message, args, error); - if (accept) { - doLog(actualMessage, error); - } - return actualMessage; - } - - private boolean isOmitStacktrace(Throwable error) { - - return (error instanceof CliException); - } - - /** - * @param message the formatted message to log. - * @param error the optional {@link Throwable} to log or {@code null} for no error. - */ - protected abstract void doLog(String message, Throwable error); - - /** - * @param argFormatter the new {@link IdeLogArgFormatter} to use. - */ - void setArgFormatter(IdeLogArgFormatter argFormatter) { - - this.argFormatter = argFormatter; - } - - @Override - public String toString() { - - return getClass().getSimpleName() + "@" + this.level; - } - -} diff --git a/cli/src/main/java/com/devonfw/tools/ide/log/IdeLogLevel.java b/cli/src/main/java/com/devonfw/tools/ide/log/IdeLogLevel.java index a6edec6b99..84a873eb9a 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/log/IdeLogLevel.java +++ b/cli/src/main/java/com/devonfw/tools/ide/log/IdeLogLevel.java @@ -1,53 +1,68 @@ package com.devonfw.tools.ide.log; -import com.devonfw.tools.ide.context.IdeContext; +import org.slf4j.Logger; +import org.slf4j.Marker; +import org.slf4j.MarkerFactory; +import org.slf4j.event.Level; +import org.slf4j.spi.LoggingEventBuilder; + +import com.devonfw.tools.ide.context.IdeStartContextImpl; /** - * {@link Enum} with the available log-levels. + * {@link Enum} with the available log-levels for IDEasy. * - * @see IdeContext#level(IdeLogLevel) + * @see Slf4jLoggerAdapter */ public enum IdeLogLevel { /** {@link IdeLogLevel} for tracing (very detailed and verbose logging). */ - TRACE("\033[38;5;240m"), + TRACE("\033[38;5;240m", Level.TRACE, null, JulLogLevel.TRACE), /** {@link IdeLogLevel} for debugging (more detailed logging). */ - DEBUG("\033[90m"), + DEBUG("\033[90m", Level.DEBUG, null, JulLogLevel.DEBUG), /** {@link IdeLogLevel} for general information (regular logging). */ - INFO(null), + INFO(null, Level.INFO, null, JulLogLevel.INFO), /** * {@link IdeLogLevel} for a step (logs the step name and groups the following log statements until the next step). */ - STEP("\033[35m"), + STEP("\033[35m", Level.INFO, MarkerFactory.getMarker("STEP"), JulLogLevel.STEP), /** {@link IdeLogLevel} for user interaction (e.g. questions or options). */ - INTERACTION("\033[96m"), + INTERACTION("\033[96m", Level.INFO, MarkerFactory.getMarker("INTERACTION"), JulLogLevel.INTERACTION), /** {@link IdeLogLevel} for success (an important aspect has been completed successfully). */ - SUCCESS("\033[92m"), + SUCCESS("\033[92m", Level.INFO, MarkerFactory.getMarker("SUCCESS"), JulLogLevel.SUCCESS), /** {@link IdeLogLevel} for a warning (something unexpected or abnormal happened but can be compensated). */ - WARNING("\033[93m"), + WARNING("\033[93m", Level.WARN, null, JulLogLevel.WARNING), /** * {@link IdeLogLevel} for an error (something failed and we cannot proceed or the user has to continue with extreme care). */ - ERROR("\033[91m"), + ERROR("\033[91m", Level.ERROR, null, JulLogLevel.ERROR), /** {@link IdeLogLevel} for {@link com.devonfw.tools.ide.commandlet.Commandlet#isProcessableOutput() processable output} */ - PROCESSABLE(null); + PROCESSABLE(null, Level.INFO, MarkerFactory.getMarker("PROCESSABLE"), JulLogLevel.PROCESSABLE); private final String color; + private final Level slf4jLevel; + + private final Marker slf4jMarker; + + private final java.util.logging.Level julLevel; + /** * The constructor. */ - private IdeLogLevel(String color) { + private IdeLogLevel(String color, Level slf4jLevel, Marker slf4jMarker, java.util.logging.Level julLevel) { this.color = color; + this.slf4jLevel = slf4jLevel; + this.slf4jMarker = slf4jMarker; + this.julLevel = julLevel; } /** @@ -66,12 +81,167 @@ public String getEndColor() { return "\033[0m"; // reset color } + /** + * @return the Slf4J {@link Level}. + */ + public Level getSlf4jLevel() { + + return this.slf4jLevel; + } + + /** + * @return the SLF4J {@link Marker}. Will be {@code null} for standard log-levels. + */ + public Marker getSlf4jMarker() { + + return this.slf4jMarker; + } + + /** + * @return the JUL {@link java.util.logging.Level}. + */ + public java.util.logging.Level getJulLevel() { + + return this.julLevel; + } + /** * @return {@code true} in case of a custom log-level, {@code false} otherwise (standard log-level supported by SLF4J and all reasonable loggers). */ public boolean isCustom() { - return (this == STEP) || (this == INTERACTION) || (this == SUCCESS) || (this == PROCESSABLE); + return (this.slf4jMarker != null); + } + + /** + * @param logger the SLF4J {@link Logger}. + * @param error the {@link Throwable} with the error to log. Must not be {@code null}. + */ + public void log(Logger logger, Throwable error) { + + log(logger, error, null, (Object[]) null); + } + + /** + * @param logger the SLF4J {@link Logger}. + * @param error the optional {@link Throwable} with the error to log or {@code null} for no error. + * @param message the message (template) to log. + */ + public void log(Logger logger, Throwable error, String message) { + + log(logger, error, message, (Object[]) null); + } + + /** + * @param logger the SLF4J {@link Logger}. + * @param message the message (template) to log. + */ + public void log(Logger logger, String message) { + + log(logger, null, message, (Object[]) null); + } + + /** + * @param logger the SLF4J {@link Logger}. + * @param message the message (template) to log. + * @param args the optional arguments to fill into the {@code message}. May be {@code null} or empty for no parameters. + */ + public void log(Logger logger, String message, Object... args) { + + log(logger, null, message, args); + } + + /** + * @param logger the SLF4J {@link Logger}. + * @param error the optional {@link Throwable} with the error to log or {@code null} for no error. + * @param message the message (template) to log. + * @param args the optional arguments to fill into the {@code message}. May be {@code null} or empty for no parameters. + */ + public void log(Logger logger, Throwable error, String message, Object... args) { + + LoggingEventBuilder builder = logger.atLevel(this.slf4jLevel).setCause(error); + if (this.slf4jMarker != null) { + builder = builder.addMarker(this.slf4jMarker); + } + if (!Slf4jLoggerAdapter.isEmpty(args)) { + builder.log(message, args); + } else if (message == null) { + String msg = error.getMessage(); + if (msg == null) { + msg = error.toString(); + } + builder.log(msg); + } else { + builder.log(message); + } + } + + /** + * @return {@code true} if this {@link IdeLogLevel} is enabled (globally), {@code false} otherwise. + */ + public boolean isEnabled() { + + IdeLogLevel threshold = getLogLevel(); + return ordinal() >= threshold.ordinal(); + } + + static IdeLogLevel getLogLevel() { + IdeLogLevel threshold = IdeLogLevel.TRACE; + IdeStartContextImpl startContext = IdeStartContextImpl.get(); + if (startContext != null) { + threshold = startContext.getLogLevelLogger(); + } + return threshold; + } + + /** + * @param marker the {@link Marker}. + * @return the corresponding {@link IdeLogLevel}. + */ + public static IdeLogLevel getLevel(Marker marker) { + + if (marker == INTERACTION.slf4jMarker) { + return IdeLogLevel.INTERACTION; + } else if (marker == STEP.slf4jMarker) { + return IdeLogLevel.STEP; + } else if (marker == SUCCESS.slf4jMarker) { + return IdeLogLevel.SUCCESS; + } else if (marker == PROCESSABLE.slf4jMarker) { + return IdeLogLevel.PROCESSABLE; + } else { + return IdeLogLevel.INFO; // unknown marker + } + } + + /** + * @param level the SLF4J log {@link Level}. + * @param marker the SLF4J {@link Marker}. + * @return the {@link IdeLogLevel}. + */ + public static IdeLogLevel of(Level level, Marker marker) { + + return switch (level) { + case ERROR -> IdeLogLevel.ERROR; + case WARN -> IdeLogLevel.WARNING; + case INFO -> getLevel(marker); + case DEBUG -> IdeLogLevel.DEBUG; + case TRACE -> IdeLogLevel.TRACE; + default -> throw new IllegalStateException("" + level); + }; + } + + /** + * @param level the JUL {@link Level}. + * @return the {@link IdeLogLevel}. + */ + public static IdeLogLevel of(java.util.logging.Level level) { + + for (IdeLogLevel ideLevel : values()) { + if (ideLevel.julLevel == level) { + return ideLevel; + } + } + throw new IllegalStateException("" + level); } } diff --git a/cli/src/main/java/com/devonfw/tools/ide/log/IdeLogListenerBuffer.java b/cli/src/main/java/com/devonfw/tools/ide/log/IdeLogListenerBuffer.java index b7dc7a1f35..99ed845343 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/log/IdeLogListenerBuffer.java +++ b/cli/src/main/java/com/devonfw/tools/ide/log/IdeLogListenerBuffer.java @@ -3,6 +3,9 @@ import java.util.ArrayList; import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * Implements {@link IdeLogListener} to buffer log events during bootstrapping and then flush them once the logger is properly configured. * @@ -10,6 +13,8 @@ */ public class IdeLogListenerBuffer implements IdeLogListener { + private static final Logger LOG = LoggerFactory.getLogger(IdeLogListenerBuffer.class); + protected final List buffer; protected IdeLogLevel threshold; @@ -44,31 +49,31 @@ public boolean onLog(IdeLogLevel level, String message, String rawMessage, Objec /** * @return {@code true} if this collector is currently buffering all logs, {@code false} otherwise (regular logging). */ - protected boolean isBuffering() { + public boolean isBuffering() { return this.buffering; } /** - * This method is supposed to be called once after the {@link IdeLogger} has been properly initialized or after invocation of - * {@link #startBuffering(IdeLogLevel)}. - * - * @param logger the initialized {@link IdeLogger}. + * This method is supposed to be called once after invocation of {@link #startBuffering(IdeLogLevel)}. */ - public void flushAndEndBuffering(IdeLogger logger) { + public void flushAndEndBuffering() { + if (!this.buffering) { + return; // buffering already ended + } // disable buffering further log events this.buffering = false; // write all cached log events to the logger again for processing for (IdeLogEntry entry : this.buffer) { - logger.level(entry.level()).log(entry.error(), entry.message()); + IdeLogLevel level = entry.level(); + level.log(LOG, entry.error(), entry.rawMessage(), entry.args()); } this.buffer.clear(); this.threshold = IdeLogLevel.TRACE; } /** - * Re-enables the buffering of the logger so nothing gets logged and log messages are only collected until {@link #flushAndEndBuffering(IdeLogger)} is - * called. + * Re-enables the buffering of the logger so nothing gets logged and log messages are only collected until {@link #flushAndEndBuffering()} is called. * * @param threshold the {@link IdeLogLevel} acting as threshold. * @see com.devonfw.tools.ide.context.IdeContext#runWithoutLogging(Runnable, IdeLogLevel) diff --git a/cli/src/main/java/com/devonfw/tools/ide/log/IdeLogger.java b/cli/src/main/java/com/devonfw/tools/ide/log/IdeLogger.java deleted file mode 100644 index 927ade5004..0000000000 --- a/cli/src/main/java/com/devonfw/tools/ide/log/IdeLogger.java +++ /dev/null @@ -1,242 +0,0 @@ -package com.devonfw.tools.ide.log; - -/** - * Interface for interaction with the user allowing to input and output information. - */ -public interface IdeLogger { - - /** - * @param level the {@link IdeLogLevel}. - * @return the requested {@link IdeLogLevel} for the given {@link IdeLogLevel}. - * @see IdeSubLogger#getLevel() - */ - IdeSubLogger level(IdeLogLevel level); - - /** - * @return the {@link #level(IdeLogLevel) logger} for {@link IdeLogLevel#TRACE}. - */ - default IdeSubLogger trace() { - - return level(IdeLogLevel.TRACE); - } - - /** - * @param message the {@link IdeSubLogger#log(String) message to log} with {@link IdeLogLevel#TRACE}. - */ - default void trace(String message) { - - trace().log(message); - } - - /** - * @param message the {@link IdeSubLogger#log(String, Object...) message to log} with {@link IdeLogLevel#TRACE}. - * @param args the dynamic arguments to fill in. - */ - default void trace(String message, Object... args) { - - trace().log(message, args); - } - - /** - * @return the {@link #level(IdeLogLevel) logger} for {@link IdeLogLevel#DEBUG}. - */ - default IdeSubLogger debug() { - - return level(IdeLogLevel.DEBUG); - } - - /** - * @param message the {@link IdeSubLogger#log(String) message to log} with {@link IdeLogLevel#DEBUG}. - */ - default void debug(String message) { - - debug().log(message); - } - - /** - * @param message the {@link IdeSubLogger#log(String, Object...) message to log} with {@link IdeLogLevel#DEBUG}. - * @param args the dynamic arguments to fill in. - */ - default void debug(String message, Object... args) { - - debug().log(message, args); - } - - /** - * @return the {@link #level(IdeLogLevel) logger} for {@link IdeLogLevel#INFO}. - */ - default IdeSubLogger info() { - - return level(IdeLogLevel.INFO); - } - - /** - * @param message the {@link IdeSubLogger#log(String) message to log} with {@link IdeLogLevel#INFO}. - */ - default void info(String message) { - - info().log(message); - } - - /** - * @param message the {@link IdeSubLogger#log(String, Object...) message to log} with {@link IdeLogLevel#INFO}. - * @param args the dynamic arguments to fill in. - */ - default void info(String message, Object... args) { - - info().log(message, args); - } - - /** - * @return the {@link #level(IdeLogLevel) logger} for {@link IdeLogLevel#STEP}. - */ - default IdeSubLogger step() { - - return level(IdeLogLevel.STEP); - } - - /** - * @param message the {@link IdeSubLogger#log(String) message to log} with {@link IdeLogLevel#STEP}. - */ - default void step(String message) { - - step().log(message); - } - - /** - * @param message the {@link IdeSubLogger#log(String, Object...) message to log} with {@link IdeLogLevel#STEP}. - * @param args the dynamic arguments to fill in. - */ - default void step(String message, Object... args) { - - step().log(message, args); - } - - /** - * @return the {@link #level(IdeLogLevel) logger} for {@link IdeLogLevel#INTERACTION}. - */ - default IdeSubLogger interaction() { - - return level(IdeLogLevel.INTERACTION); - } - - /** - * @param message the {@link IdeSubLogger#log(String) message to log} with {@link IdeLogLevel#INTERACTION}. - */ - default void interaction(String message) { - - interaction().log(message); - } - - /** - * @param message the {@link IdeSubLogger#log(String, Object...) message to log} with {@link IdeLogLevel#INTERACTION}. - * @param args the dynamic arguments to fill in. - */ - default void interaction(String message, Object... args) { - - interaction().log(message, args); - } - - /** - * @return the {@link #level(IdeLogLevel) logger} for {@link IdeLogLevel#SUCCESS}. - */ - default IdeSubLogger success() { - - return level(IdeLogLevel.SUCCESS); - } - - /** - * @param message the {@link IdeSubLogger#log(String) message to log} with {@link IdeLogLevel#SUCCESS}. - */ - default void success(String message) { - - success().log(message); - } - - /** - * @param message the {@link IdeSubLogger#log(String, Object...) message to log} with {@link IdeLogLevel#SUCCESS}. - * @param args the dynamic arguments to fill in. - */ - default void success(String message, Object... args) { - - success().log(message, args); - } - - /** - * @return the {@link #level(IdeLogLevel) logger} for {@link IdeLogLevel#WARNING}. - */ - default IdeSubLogger warning() { - - return level(IdeLogLevel.WARNING); - } - - /** - * @param message the {@link IdeSubLogger#log(String) message to log} with {@link IdeLogLevel#WARNING}. - */ - default void warning(String message) { - - warning().log(message); - } - - /** - * @param message the {@link IdeSubLogger#log(String, Object...) message to log} with {@link IdeLogLevel#WARNING}. - * @param args the dynamic arguments to fill in. - */ - default void warning(String message, Object... args) { - - warning().log(message, args); - } - - /** - * @return the {@link #level(IdeLogLevel) logger} for {@link IdeLogLevel#ERROR}. - */ - default IdeSubLogger error() { - - return level(IdeLogLevel.ERROR); - } - - /** - * @param message the {@link IdeSubLogger#log(String) message to log} with {@link IdeLogLevel#ERROR}. - */ - default void error(String message) { - - error().log(message); - } - - /** - * @param message the {@link IdeSubLogger#log(String, Object...) message to log} with {@link IdeLogLevel#ERROR}. - * @param args the dynamic arguments to fill in. - */ - default void error(String message, Object... args) { - - error().log(message, args); - } - - /** - * @param error the {@link Throwable} that caused the error. - */ - default void error(Throwable error) { - - error(error, null); - } - - /** - * @param error the {@link Throwable} that caused the error. - * @param message the {@link IdeSubLogger#log(String, Object...) message to log} with {@link IdeLogLevel#ERROR}. - */ - default void error(Throwable error, String message) { - - error().log(error, message); - } - - /** - * @param error the {@link Throwable} that caused the error. - * @param message the {@link IdeSubLogger#log(String, Object...) message to log} with {@link IdeLogLevel#ERROR}. - * @param args the dynamic arguments to fill in. - */ - default void error(Throwable error, String message, Object... args) { - - error().log(error, message, args); - } - -} diff --git a/cli/src/main/java/com/devonfw/tools/ide/log/IdeLoggerImpl.java b/cli/src/main/java/com/devonfw/tools/ide/log/IdeLoggerImpl.java deleted file mode 100644 index 6a0a0e3d8d..0000000000 --- a/cli/src/main/java/com/devonfw/tools/ide/log/IdeLoggerImpl.java +++ /dev/null @@ -1,122 +0,0 @@ -package com.devonfw.tools.ide.log; - -import java.util.Objects; -import java.util.function.Function; - -/** - * Implementation of {@link IdeLogger}. - */ -public class IdeLoggerImpl implements IdeLogger { - - private final AbstractIdeSubLogger[] loggers; - - protected final IdeLogListener listener; - - /** - * @param minLogLevel the minimum enabled {@link IdeLogLevel}. - * @param factory the factory to create active {@link IdeSubLogger} instances. - */ - public IdeLoggerImpl(IdeLogLevel minLogLevel, Function factory) { - - super(); - IdeLogLevel[] levels = IdeLogLevel.values(); - this.loggers = new AbstractIdeSubLogger[levels.length]; - IdeLogListener listener = null; - for (IdeLogLevel level : levels) { - this.loggers[level.ordinal()] = factory.apply(level); - if (listener == null) { - listener = this.loggers[level.ordinal()].listener; - } - } - this.listener = listener; - setLogLevel(minLogLevel); - } - - @Override - public IdeSubLogger level(IdeLogLevel level) { - - IdeSubLogger logger = this.loggers[level.ordinal()]; - Objects.requireNonNull(logger); - return logger; - } - - /** - * Sets the log level. - * - * @param logLevel {@link IdeLogLevel} - * @return the previous set logLevel {@link IdeLogLevel} - */ - public IdeLogLevel setLogLevel(IdeLogLevel logLevel) { - - IdeLogLevel previousLogLevel = null; - for (IdeLogLevel level : IdeLogLevel.values()) { - boolean enabled = level.ordinal() >= logLevel.ordinal(); - if ((previousLogLevel == null) && this.loggers[level.ordinal()].isEnabled()) { - previousLogLevel = level; - } - setLogLevel(level, enabled); - } - if ((previousLogLevel == null) || (previousLogLevel.ordinal() > IdeLogLevel.INFO.ordinal())) { - previousLogLevel = IdeLogLevel.INFO; - } - return previousLogLevel; - } - - /** - * @param colored the new {@link AbstractIdeSubLogger#isColored() colored flag}. - */ - protected void setLogColors(boolean colored) { - - for (IdeLogLevel level : IdeLogLevel.values()) { - this.loggers[level.ordinal()].setColored(colored); - } - } - - /** - * @param logLevel the {@link IdeLogLevel} to modify. - * @param enabled - {@code true} to enable, {@code false} to disable. - */ - public void setLogLevel(IdeLogLevel logLevel, boolean enabled) { - - this.loggers[logLevel.ordinal()].setEnabled(enabled); - } - - /** - * Ensure the logging system is initialized. - */ - public void activateLogging() { - - if (this.listener instanceof IdeLogListenerBuffer buffer) { - // https://github.com/devonfw/IDEasy/issues/754 - buffer.flushAndEndBuffering(this); - } - } - - /** - * Disables the logging system (temporary). - * - * @param threshold the {@link IdeLogLevel} acting as threshold. - * @see com.devonfw.tools.ide.context.IdeContext#runWithoutLogging(Runnable, IdeLogLevel) - */ - public void deactivateLogging(IdeLogLevel threshold) { - - if (this.listener instanceof IdeLogListenerBuffer buffer) { - buffer.startBuffering(threshold); - } else { - throw new IllegalStateException(); - } - } - - /** - * Internal method to set the {@link IdeLogArgFormatter}. - * - * @param argFormatter the {@link IdeLogArgFormatter}. - */ - public void setArgFormatter(IdeLogArgFormatter argFormatter) { - - for (AbstractIdeSubLogger logger : this.loggers) { - logger.setArgFormatter(argFormatter); - } - } - -} diff --git a/cli/src/main/java/com/devonfw/tools/ide/log/IdeSubLogger.java b/cli/src/main/java/com/devonfw/tools/ide/log/IdeSubLogger.java deleted file mode 100644 index a3caf808cb..0000000000 --- a/cli/src/main/java/com/devonfw/tools/ide/log/IdeSubLogger.java +++ /dev/null @@ -1,55 +0,0 @@ -package com.devonfw.tools.ide.log; - -/** - * Interface for a logger to {@link #log(String) log a message} on a specific {@link #getLevel() log-level}. - */ -public interface IdeSubLogger { - - /** - * @param message the message to log. - */ - default void log(String message) { - - log(null, message); - } - - /** - * @param message the message to log. - * @param args the dynamic arguments to fill in. - * @return the message headline that was logged. - */ - default String log(String message, Object... args) { - - return log(null, message, args); - } - - /** - * @param error the {@link Throwable} that was catched and should be logged or {@code null} for no error. - * @param message the message to log. - * @return the message headline that was logged. - */ - default String log(Throwable error, String message) { - - return log(error, message, (Object[]) null); - } - - /** - * @param error the {@link Throwable} that was catched and should be logged or {@code null} for no error. - * @param message the message to log. - * @param args the dynamic arguments to fill in. - * @return the message headline that was logged. - */ - String log(Throwable error, String message, Object... args); - - /** - * @return {@code true} if this logger is enabled, {@code false} otherwise (this logger does nothing and all {@link #log(String) logged messages} with be - * ignored). - */ - boolean isEnabled(); - - /** - * @return the {@link IdeLogLevel} of this logger. - */ - IdeLogLevel getLevel(); - -} diff --git a/cli/src/main/java/com/devonfw/tools/ide/log/IdeSubLoggerOut.java b/cli/src/main/java/com/devonfw/tools/ide/log/IdeSubLoggerOut.java deleted file mode 100644 index acd79c75ea..0000000000 --- a/cli/src/main/java/com/devonfw/tools/ide/log/IdeSubLoggerOut.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.devonfw.tools.ide.log; - -import java.io.IOException; - -/** - * Default implementation of {@link IdeSubLogger} that can write to an {@link Appendable} such as {@link System#out} or in case of testing a - * {@link java.io.StringWriter}. - */ -public class IdeSubLoggerOut extends AbstractIdeSubLogger { - - private final Appendable out; - - /** - * The constructor. - * - * @param level the {@link #getLevel() log-level}. - * @param out the {@link Appendable} to {@link Appendable#append(CharSequence) write} log messages to. - * @param colored - {@code true} for colored output according to {@link IdeLogLevel}, {@code false} otherwise. - * @param minLogLevel the minimum log level (threshold). - */ - public IdeSubLoggerOut(IdeLogLevel level, Appendable out, boolean colored, IdeLogLevel minLogLevel, IdeLogListener listener) { - - super(level, colored, IdeLogExceptionDetails.of(level, minLogLevel), listener); - if (out == null) { - // this is on of the very rare excuses where System.out or System.err is allowed to be used! - if (level == IdeLogLevel.ERROR) { - this.out = System.err; - } else { - this.out = System.out; - } - } else { - this.out = out; - } - } - - @Override - public void doLog(String message, Throwable error) { - - try { - String startColor = null; - if (this.colored) { - startColor = this.level.getStartColor(); - if (startColor != null) { - this.out.append(startColor); - } - } - if (error != null) { - message = this.exceptionDetails.format(message, error); - } - this.out.append(message); - if (startColor != null) { - this.out.append(this.level.getEndColor()); - } - this.out.append("\n"); - } catch (IOException e) { - throw new IllegalStateException("Failed to log message: " + message, e); - } - } -} diff --git a/cli/src/main/java/com/devonfw/tools/ide/log/InvalidLogMessageHandler.java b/cli/src/main/java/com/devonfw/tools/ide/log/InvalidLogMessageHandler.java new file mode 100644 index 0000000000..2df898aace --- /dev/null +++ b/cli/src/main/java/com/devonfw/tools/ide/log/InvalidLogMessageHandler.java @@ -0,0 +1,19 @@ +package com.devonfw.tools.ide.log; + +/** + * Handler for {@link #invalidMessage(String, boolean, Object[]) invalid log messages}. + */ +@FunctionalInterface +public interface InvalidLogMessageHandler { + + /** An instance doing nothing. */ + InvalidLogMessageHandler NONE = (message, more, args) -> { + }; + + /** + * @param message the message template. + * @param more - {@code true} if more placeholders were present than {@code args} given, {@code false} otherwise (fewer placeholders present). + * @param args the dynamic arguments to fill into the message template. + */ + void invalidMessage(String message, boolean more, Object[] args); +} diff --git a/cli/src/main/java/com/devonfw/tools/ide/log/JulConsoleHandler.java b/cli/src/main/java/com/devonfw/tools/ide/log/JulConsoleHandler.java new file mode 100644 index 0000000000..ff5817e5d5 --- /dev/null +++ b/cli/src/main/java/com/devonfw/tools/ide/log/JulConsoleHandler.java @@ -0,0 +1,59 @@ +package com.devonfw.tools.ide.log; + +import java.io.PrintStream; +import java.util.logging.Handler; +import java.util.logging.Level; +import java.util.logging.LogRecord; + +import com.devonfw.tools.ide.context.IdeStartContextImpl; + +/** + * Custom {@link Handler} for java.util.logging to log to console. + */ +public class JulConsoleHandler extends Handler { + + @Override + public void publish(LogRecord record) { + Level julLevel = record.getLevel(); + IdeLogLevel ideLevel = IdeLogLevel.of(julLevel); + IdeStartContextImpl startContext = IdeStartContextImpl.get(); + boolean colored = false; + if (startContext != null) { + colored = !startContext.isNoColorsMode(); + if (ideLevel.ordinal() < startContext.getLogLevelConsole().ordinal()) { + return; // console logging disabled for ideLevel + } + } + PrintStream out = System.out; + if (ideLevel == IdeLogLevel.ERROR) { + out = System.err; + } + String message = record.getMessage(); + Throwable error = record.getThrown(); + String startColor = null; + if (colored) { + startColor = ideLevel.getStartColor(); + if (startColor != null) { + out.append(startColor); + } + } + if (error != null) { + message = IdeLogExceptionDetails.of(ideLevel, IdeLogLevel.getLogLevel()).format(message, error); + } + out.append(message); + if (startColor != null) { + out.append(ideLevel.getEndColor()); + } + out.append("\n"); + } + + @Override + public void flush() { + + } + + @Override + public void close() { + + } +} diff --git a/cli/src/main/java/com/devonfw/tools/ide/log/JulLogLevel.java b/cli/src/main/java/com/devonfw/tools/ide/log/JulLogLevel.java new file mode 100644 index 0000000000..31e02bc4f6 --- /dev/null +++ b/cli/src/main/java/com/devonfw/tools/ide/log/JulLogLevel.java @@ -0,0 +1,48 @@ +package com.devonfw.tools.ide.log; + +import java.util.logging.Level; + +/** + * {@link Level} from java.util.logging corresponding to {@link IdeLogLevel}. + */ +public class JulLogLevel extends Level { + + /** @see IdeLogLevel#TRACE */ + public static final Level TRACE = new JulLogLevel("TRACE", 1010); + + /** @see IdeLogLevel#DEBUG */ + public static final Level DEBUG = new JulLogLevel("DEBUG", 1020); + + /** @see IdeLogLevel#INFO */ + public static final Level INFO = new JulLogLevel("INFO", 1030); + + /** @see IdeLogLevel#STEP */ + public static final Level STEP = new JulLogLevel("STEP", 1040); + + /** @see IdeLogLevel#INTERACTION */ + public static final Level INTERACTION = new JulLogLevel("INTERACTION", 1050); + + /** @see IdeLogLevel#SUCCESS */ + public static final Level SUCCESS = new JulLogLevel("SUCCESS", 1060); + + /** @see IdeLogLevel#WARNING */ + public static final Level WARNING = new JulLogLevel("WARNING", 1070); + + /** @see IdeLogLevel#WARNING */ + public static final Level ERROR = new JulLogLevel("ERROR", 1080); + + /** @see IdeLogLevel#PROCESSABLE */ + public static final Level PROCESSABLE = new JulLogLevel("PROCESSABLE", 2000); + + private JulLogLevel(String name, int value) { + + super(name, value); + } + + /** + * Ensures that all custom log-levels are initialized. + */ + public static void init() { + + } +} diff --git a/cli/src/main/java/com/devonfw/tools/ide/log/Slf4jLoggerAdapter.java b/cli/src/main/java/com/devonfw/tools/ide/log/Slf4jLoggerAdapter.java new file mode 100644 index 0000000000..47713db162 --- /dev/null +++ b/cli/src/main/java/com/devonfw/tools/ide/log/Slf4jLoggerAdapter.java @@ -0,0 +1,220 @@ +package com.devonfw.tools.ide.log; + +import java.util.List; +import java.util.logging.Logger; + +import org.slf4j.Marker; +import org.slf4j.event.Level; +import org.slf4j.event.LoggingEvent; +import org.slf4j.helpers.AbstractLogger; +import org.slf4j.spi.LoggingEventAware; + +import com.devonfw.tools.ide.context.IdeStartContextImpl; + +/** + * Implementation of SLF4J {@link AbstractLogger} for IDEasy. + */ +public class Slf4jLoggerAdapter extends AbstractLogger implements LoggingEventAware { + + /** Package prefix of IDEasy: {@value} */ + public static final String IDEASY_PACKAGE_PREFIX = "com.devonfw.tools.ide."; + private final String name; + + private final boolean internal; + + private Logger julLogger; + + /** + * The constructor. + * + * @param name of the logger. + */ + public Slf4jLoggerAdapter(String name) { + + this.name = name; + this.internal = name.startsWith(IDEASY_PACKAGE_PREFIX); + this.julLogger = Logger.getLogger(name); + } + + @Override + public String getName() { + + return this.name; + } + + static boolean isEmpty(Object[] args) { + return (args == null) || (args.length == 0); + } + + /** + * Should only be used internally by logger implementation. + * + * @param message the message template. + * @param args the dynamic arguments to fill in. + * @return the resolved message with the parameters filled in. + */ + private String compose(IdeLogArgFormatter formatter, String message, Object... args) { + + if (isEmpty(args)) { + return message; + } + int pos = message.indexOf("{}"); + if (pos < 0) { + if (args.length > 0) { + invalidMessage(message, false, args); + } + return message; + } + int argIndex = 0; + int start = 0; + int length = message.length(); + StringBuilder sb = new StringBuilder(length + 48); + while (pos >= 0) { + sb.append(message, start, pos); + sb.append(formatter.formatArgument(args[argIndex++])); + start = pos + 2; + pos = message.indexOf("{}", start); + if ((argIndex >= args.length) && (pos > 0)) { + invalidMessage(message, true, args); + pos = -1; + } + } + if (start < length) { + String rest = message.substring(start); + sb.append(rest); + } + if (argIndex < args.length) { + invalidMessage(message, false, args); + } + return sb.toString(); + } + + private void invalidMessage(String message, boolean more, Object[] args) { + + warning("Invalid log message with " + args.length + " argument(s) but " + (more ? "more" : "less") + + " placeholders: " + message); + } + + private void warning(String message) { + + boolean colored = isColored(); + if (colored) { + System.err.print(IdeLogLevel.ERROR.getEndColor()); + System.err.print(IdeLogLevel.ERROR.getStartColor()); + } + System.err.println(message); + if (colored) { + System.err.print(IdeLogLevel.ERROR.getEndColor()); + } + } + + static boolean isColored() { + IdeStartContextImpl startContext = IdeStartContextImpl.get(); + if (startContext != null) { + return !startContext.isNoColorsMode(); + } + return false; + } + + @Override + protected String getFullyQualifiedCallerName() { + + return null; + } + + @Override + protected void handleNormalizedLoggingCall(Level level, Marker marker, String message, Object[] args, Throwable error) { + IdeLogLevel ideLevel = IdeLogLevel.of(level, marker); + IdeLogListener listener = IdeLogListenerNone.INSTANCE; + IdeStartContextImpl startContext = IdeStartContextImpl.get(); + IdeLogArgFormatter argFormatter = IdeLogArgFormatter.DEFAULT; + if (startContext != null) { + listener = startContext.getLogListener(); + argFormatter = startContext.getArgFormatter(); + } + String composedMessage = compose(argFormatter, message, args); + boolean accept = listener.onLog(ideLevel, composedMessage, message, args, error); + if (accept) { + java.util.logging.Level julLevel = ideLevel.getJulLevel(); + this.julLogger.log(julLevel, composedMessage, error); + } + } + + @Override + public void log(LoggingEvent event) { + + List markers = event.getMarkers(); + Marker marker = null; + if ((markers != null) && !markers.isEmpty()) { + assert markers.size() == 1; + marker = markers.getFirst(); + } + Level level = event.getLevel(); + IdeLogLevel ideLogLevel = IdeLogLevel.of(level, marker); + if (ideLogLevel.isEnabled()) { + handleNormalizedLoggingCall(level, marker, event.getMessage(), event.getArgumentArray(), event.getThrowable()); + } + } + + private boolean isLevelEnabled(Level level, Marker marker) { + IdeLogLevel ideLevel = IdeLogLevel.of(level, marker); + if (!ideLevel.isEnabled()) { + return false; + } + if (!this.internal) { + return level.toInt() >= Level.WARN.toInt(); // 3rd party is limited to INFO logging to avoid potential log spam + } + return true; + } + + @Override + public boolean isTraceEnabled() { + return isLevelEnabled(Level.TRACE, null); + } + + @Override + public boolean isTraceEnabled(Marker marker) { + return isLevelEnabled(Level.TRACE, marker); + } + + @Override + public boolean isDebugEnabled() { + return isLevelEnabled(Level.DEBUG, null); + } + + @Override + public boolean isDebugEnabled(Marker marker) { + return isLevelEnabled(Level.DEBUG, marker); + } + + @Override + public boolean isInfoEnabled() { + return isLevelEnabled(Level.INFO, null); + } + + @Override + public boolean isInfoEnabled(Marker marker) { + return isLevelEnabled(Level.INFO, marker); + } + + @Override + public boolean isWarnEnabled() { + return isLevelEnabled(Level.WARN, null); + } + + @Override + public boolean isWarnEnabled(Marker marker) { + return isLevelEnabled(Level.WARN, marker); + } + + @Override + public boolean isErrorEnabled() { + return isLevelEnabled(Level.ERROR, null); + } + + @Override + public boolean isErrorEnabled(Marker marker) { + return isLevelEnabled(Level.ERROR, marker); + } + +} diff --git a/cli/src/main/java/com/devonfw/tools/ide/log/Slf4jLoggerFactoryIdeasy.java b/cli/src/main/java/com/devonfw/tools/ide/log/Slf4jLoggerFactoryIdeasy.java new file mode 100644 index 0000000000..4a33ac436b --- /dev/null +++ b/cli/src/main/java/com/devonfw/tools/ide/log/Slf4jLoggerFactoryIdeasy.java @@ -0,0 +1,16 @@ +package com.devonfw.tools.ide.log; + +import org.slf4j.ILoggerFactory; +import org.slf4j.Logger; + +/** + * Implementation of SLF4J {@link ILoggerFactory} for IDEasy. + */ +public class Slf4jLoggerFactoryIdeasy implements ILoggerFactory { + + @Override + public Logger getLogger(String name) { + + return new Slf4jLoggerAdapter(name); + } +} diff --git a/cli/src/main/java/com/devonfw/tools/ide/log/Slf4jProviderIdeasy.java b/cli/src/main/java/com/devonfw/tools/ide/log/Slf4jProviderIdeasy.java new file mode 100644 index 0000000000..a42f21835e --- /dev/null +++ b/cli/src/main/java/com/devonfw/tools/ide/log/Slf4jProviderIdeasy.java @@ -0,0 +1,53 @@ +package com.devonfw.tools.ide.log; + +import org.slf4j.ILoggerFactory; +import org.slf4j.IMarkerFactory; +import org.slf4j.helpers.BasicMarkerFactory; +import org.slf4j.helpers.NOPMDCAdapter; +import org.slf4j.spi.MDCAdapter; +import org.slf4j.spi.SLF4JServiceProvider; + +/** + * Implementation of {@link SLF4JServiceProvider}. + */ +public class Slf4jProviderIdeasy implements SLF4JServiceProvider { + + private final Slf4jLoggerFactoryIdeasy loggerFactory; + + /** + * The constructor. + */ + public Slf4jProviderIdeasy() { + super(); + this.loggerFactory = new Slf4jLoggerFactoryIdeasy(); + } + + @Override + public ILoggerFactory getLoggerFactory() { + + return this.loggerFactory; + } + + @Override + public IMarkerFactory getMarkerFactory() { + + return new BasicMarkerFactory(); + } + + @Override + public MDCAdapter getMDCAdapter() { + + return new NOPMDCAdapter(); + } + + @Override + public String getRequestedApiVersion() { + + return "2.0.12"; + } + + @Override + public void initialize() { + // nothing to do... + } +} diff --git a/cli/src/main/java/com/devonfw/tools/ide/merge/DirectoryMerger.java b/cli/src/main/java/com/devonfw/tools/ide/merge/DirectoryMerger.java index 426f271fa2..5108a85c0d 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/merge/DirectoryMerger.java +++ b/cli/src/main/java/com/devonfw/tools/ide/merge/DirectoryMerger.java @@ -11,6 +11,8 @@ import java.util.stream.Stream; import org.jline.utils.Log; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.environment.EnvironmentVariables; @@ -27,6 +29,8 @@ */ public class DirectoryMerger extends AbstractWorkspaceMerger { + private static final Logger LOG = LoggerFactory.getLogger(DirectoryMerger.class); + private final Map extension2mergerMap; private final FallbackMerger fallbackMerger; @@ -81,9 +85,9 @@ private FileMerger getMerger(Path file) { String filename = file.getFileName().toString(); String extension = FilenameUtil.getExtension(filename); if (extension == null) { - this.context.debug("No extension for {}", file); + LOG.debug("No extension for {}", file); } else { - this.context.trace("Extension is {}", extension); + LOG.trace("Extension is {}", extension); FileMerger merger = this.extension2mergerMap.get(extension); if (merger != null) { return merger; diff --git a/cli/src/main/java/com/devonfw/tools/ide/merge/FileMerger.java b/cli/src/main/java/com/devonfw/tools/ide/merge/FileMerger.java index 0eba942bb6..63767d319d 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/merge/FileMerger.java +++ b/cli/src/main/java/com/devonfw/tools/ide/merge/FileMerger.java @@ -6,6 +6,9 @@ import java.nio.file.StandardCopyOption; import java.util.regex.Matcher; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.environment.EnvironmentVariables; import com.devonfw.tools.ide.variable.IdeVariables; @@ -17,6 +20,8 @@ */ public abstract class FileMerger extends AbstractWorkspaceMerger { + private static final Logger LOG = LoggerFactory.getLogger(FileMerger.class); + protected final boolean legacySupport; /** @@ -49,7 +54,7 @@ public final int merge(Path setup, Path update, EnvironmentVariables variables, try { doMerge(setup, update, variables, workspace); } catch (Exception e) { - this.context.error(e, "Failed to merge workspace file {} with update template {} and setup file {}!", workspace, update, setup); + LOG.error("Failed to merge workspace file {} with update template {} and setup file {}!", workspace, update, setup, e); return 1; } return 0; @@ -71,9 +76,9 @@ public void upgrade(Path workspaceFile) { try { boolean modified = doUpgrade(workspaceFile); if (modified) { - this.context.debug("Successfully migrated file {}", workspaceFile); + LOG.debug("Successfully migrated file {}", workspaceFile); } else { - this.context.trace("Nothing to migrate in file {}", workspaceFile); + LOG.trace("Nothing to migrate in file {}", workspaceFile); } } catch (Exception e) { throw new IllegalStateException("Failed to update file " + workspaceFile, e); diff --git a/cli/src/main/java/com/devonfw/tools/ide/merge/JsonMerger.java b/cli/src/main/java/com/devonfw/tools/ide/merge/JsonMerger.java index 9b9e883929..ae30bd0d69 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/merge/JsonMerger.java +++ b/cli/src/main/java/com/devonfw/tools/ide/merge/JsonMerger.java @@ -24,6 +24,9 @@ import jakarta.json.JsonWriterFactory; import jakarta.json.stream.JsonGenerator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.environment.EnvironmentVariables; import com.fasterxml.jackson.core.util.DefaultIndenter; @@ -39,6 +42,8 @@ */ public class JsonMerger extends FileMerger { + private static final Logger LOG = LoggerFactory.getLogger(JsonMerger.class); + /** * The constructor. * @@ -76,9 +81,9 @@ protected void doMerge(Path setup, Path update, EnvironmentVariables variables, JsonStructure result = (JsonStructure) mergeAndResolve(json, mergeJson, variables, status, template.toString()); if (status.updated) { save(result, workspace); - this.context.debug("Saved created/updated file {}", workspace); + LOG.debug("Saved created/updated file {}", workspace); } else { - this.context.trace("No changes for file {}", workspace); + LOG.trace("No changes for file {}", workspace); } } @@ -125,9 +130,9 @@ public void inverseMerge(Path workspace, EnvironmentVariables variables, boolean workspace.getFileName()); if (status.updated) { save(result, updateFile); - this.context.debug("Saved changes from {} to {}", workspace.getFileName(), updateFile); + LOG.debug("Saved changes from {} to {}", workspace.getFileName(), updateFile); } else { - this.context.trace("No changes for {}", updateFile); + LOG.trace("No changes for {}", updateFile); } } @@ -150,7 +155,7 @@ private JsonValue mergeAndResolve(JsonValue json, JsonValue mergeJson, Environme case STRING -> mergeAndResolveString((JsonString) json, (JsonString) mergeJson, variables, status, src); case NUMBER, FALSE, TRUE, NULL -> mergeAndResolveNativeType(json, mergeJson, variables, status); default -> { - this.context.error("Undefined JSON type {}", json.getClass()); + LOG.error("Undefined JSON type {}", json.getClass()); yield null; } }; @@ -286,7 +291,7 @@ private ObjectNode upgradeJsonObject(ObjectNode jsonObject) { if (migratedChild != child) { result = null; if (migratedChild != null) { - jsonObject.put(fieldName, migratedChild); + jsonObject.set(fieldName, migratedChild); } } } diff --git a/cli/src/main/java/com/devonfw/tools/ide/merge/PropertiesMerger.java b/cli/src/main/java/com/devonfw/tools/ide/merge/PropertiesMerger.java index 378fb95008..1ed2d25686 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/merge/PropertiesMerger.java +++ b/cli/src/main/java/com/devonfw/tools/ide/merge/PropertiesMerger.java @@ -5,6 +5,9 @@ import java.util.Properties; import java.util.Set; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.environment.EnvironmentVariables; import com.devonfw.tools.ide.environment.SortedProperties; @@ -15,6 +18,8 @@ */ public class PropertiesMerger extends FileMerger { + private static final Logger LOG = LoggerFactory.getLogger(PropertiesMerger.class); + /** * The constructor. * @@ -34,7 +39,7 @@ protected void doMerge(Path setup, Path update, EnvironmentVariables resolver, P Path template = setup; if (Files.exists(workspace)) { if (!updateFileExists) { - this.context.trace("Nothing to do as update file does not exist: {}", update); + LOG.trace("Nothing to do as update file does not exist: {}", update); return; // nothing to do ... } fileAccess.readProperties(workspace, properties); @@ -47,7 +52,7 @@ protected void doMerge(Path setup, Path update, EnvironmentVariables resolver, P } resolve(properties, resolver, template.toString()); fileAccess.writeProperties(properties, workspace, true); - this.context.trace("Saved merged properties to: {}", workspace); + LOG.trace("Saved merged properties to: {}", workspace); } private void resolve(Properties properties, EnvironmentVariables variables, Object src) { @@ -63,11 +68,11 @@ private void resolve(Properties properties, EnvironmentVariables variables, Obje public void inverseMerge(Path workspace, EnvironmentVariables variables, boolean addNewProperties, Path update) { if (!Files.exists(workspace)) { - this.context.trace("Workspace file does not exist: {}", workspace); + LOG.trace("Workspace file does not exist: {}", workspace); return; } if (!Files.exists(update)) { - this.context.trace("Update file does not exist: {}", update); + LOG.trace("Update file does not exist: {}", update); return; } Object src = workspace.getFileName(); @@ -94,9 +99,9 @@ public void inverseMerge(Path workspace, EnvironmentVariables variables, boolean } if (updated) { fileAccess.writeProperties(mergedProperties, update); - this.context.debug("Saved changes from: {} to: {}", workspace.getFileName(), update); + LOG.debug("Saved changes from: {} to: {}", workspace.getFileName(), update); } else { - this.context.trace("No changes for: {}", update); + LOG.trace("No changes for: {}", update); } } diff --git a/cli/src/main/java/com/devonfw/tools/ide/merge/xml/XmlMerger.java b/cli/src/main/java/com/devonfw/tools/ide/merge/xml/XmlMerger.java index 2ccc3b57f0..971943395f 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/merge/xml/XmlMerger.java +++ b/cli/src/main/java/com/devonfw/tools/ide/merge/xml/XmlMerger.java @@ -13,6 +13,8 @@ import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.w3c.dom.Attr; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -32,6 +34,8 @@ */ public class XmlMerger extends FileMerger implements XmlMergeSupport { + private static final Logger LOG = LoggerFactory.getLogger(XmlMerger.class); + private static final DocumentBuilder DOCUMENT_BUILDER; private static final TransformerFactory TRANSFORMER_FACTORY; @@ -114,7 +118,7 @@ public Document merge(XmlMergeDocument templateDocument, XmlMergeDocument worksp Document resultDocument; Path template = templateDocument.getPath(); Path source = workspaceDocument.getPath(); - this.context.debug("Merging {} into {} ...", template, source); + LOG.debug("Merging {} into {} ...", template, source); Element templateRoot = templateDocument.getRoot(); QName templateQName = XmlMergeSupport.getQualifiedName(templateRoot); Document document = workspaceDocument.getDocument(); @@ -146,7 +150,7 @@ public Document merge(XmlMergeDocument templateDocument, XmlMergeDocument worksp strategy = XmlMergeStrategy.KEEP; } } else { - this.context.warning( + LOG.warn( "XML merge namespace not found in file {}. If you are working in a legacy devonfw-ide project, please set IDE_XML_MERGE_LEGACY_SUPPORT_ENABLED=true to " + "proceed correctly.", source); } @@ -155,7 +159,7 @@ public Document merge(XmlMergeDocument templateDocument, XmlMergeDocument worksp strategy.merge(templateRoot, workspaceRoot, elementMatcher); resultDocument = document; } else { - this.context.error("Cannot merge XML template {} with root {} into XML file {} with root {} as roots do not match.", templateDocument.getPath(), + LOG.error("Cannot merge XML template {} with root {} into XML file {} with root {} as roots do not match.", templateDocument.getPath(), templateQName, workspaceDocument.getPath(), workspaceQName); return null; } @@ -369,7 +373,7 @@ private void checkForXmlNamespace(Document document, Path workspaceFile) { } } } - this.context.warning( + LOG.warn( "The XML file {} does not contain the XML merge namespace and seems outdated. For details see:\n" + "https://github.com/devonfw/IDEasy/blob/main/documentation/configurator.adoc#xml-merger", workspaceFile); } diff --git a/cli/src/main/java/com/devonfw/tools/ide/merge/xml/matcher/IdComputer.java b/cli/src/main/java/com/devonfw/tools/ide/merge/xml/matcher/IdComputer.java index e021f708e4..fea8c45abc 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/merge/xml/matcher/IdComputer.java +++ b/cli/src/main/java/com/devonfw/tools/ide/merge/xml/matcher/IdComputer.java @@ -7,6 +7,8 @@ import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.w3c.dom.Element; import org.w3c.dom.NodeList; @@ -18,6 +20,8 @@ */ public class IdComputer { + private static final Logger LOG = LoggerFactory.getLogger(IdComputer.class); + /** 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"; @@ -71,11 +75,13 @@ public Element evaluateExpression(Element templateElement, Element workspaceElem } else if (length == 0) { return null; } else { - String message = length + " matches found for XPath " + xpathExpr + " in workspace XML file '" + workspacePath + "' at " + XmlMergeSupport.getXPath(workspaceElement, true) + " for template file '" + templatePath + "'"; + String message = + length + " matches found for XPath " + xpathExpr + " in workspace XML file '" + workspacePath + "' at " + XmlMergeSupport.getXPath(workspaceElement, + true) + " for template file '" + templatePath + "'"; if ("true".equals(this.context.getVariables().get(FAIL_ON_AMBIGOUS_MERGE))) { throw new IllegalStateException(message); } else { - this.context.warning(message); + LOG.warn(message); } return (Element) nodeList.item(0); } diff --git a/cli/src/main/java/com/devonfw/tools/ide/migration/IdeMigrator.java b/cli/src/main/java/com/devonfw/tools/ide/migration/IdeMigrator.java index c371fa9bd2..a79d56afb4 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/migration/IdeMigrator.java +++ b/cli/src/main/java/com/devonfw/tools/ide/migration/IdeMigrator.java @@ -2,7 +2,11 @@ import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.context.IdeContext; +import com.devonfw.tools.ide.log.IdeLogLevel; import com.devonfw.tools.ide.migration.v2025.Mig202502001; import com.devonfw.tools.ide.migration.v2025.Mig202510001; import com.devonfw.tools.ide.step.Step; @@ -14,6 +18,8 @@ */ public class IdeMigrator implements IdeMigration { + private static final Logger LOG = LoggerFactory.getLogger(IdeMigrator.class); + /** {@link VersionIdentifier} to use as fallback if {@link IdeContext#FILE_SOFTWARE_VERSION} does not exist. */ public static final VersionIdentifier START_VERSION = VersionIdentifier.of("2025.01.001-beta"); @@ -53,7 +59,7 @@ public VersionIdentifier getTargetVersion() { public void run(IdeContext context) { if (context.getIdeHome() == null) { - context.debug("Skipping migration since IDE_HOME is undefined."); + LOG.debug("Skipping migration since IDE_HOME is undefined."); return; } VersionIdentifier currentVersion = context.getProjectVersion(); @@ -80,13 +86,13 @@ public void run(IdeContext context) { throw new IllegalStateException("Failed: " + step.getName()); } } else { - context.debug("Skipping migration {} since we are already at version {}", targetVersion, currentVersion); + LOG.debug("Skipping migration {} since we are already at version {}", targetVersion, currentVersion); } } if (migrationCount > 0) { - context.success("Successfully applied {} migration(s) to project {}", migrationCount, context.getProjectName()); + IdeLogLevel.SUCCESS.log(LOG, "Successfully applied {} migration(s) to project {}", migrationCount, context.getProjectName()); } else { - context.debug("No migration to apply to project {}", context.getProjectName()); + LOG.debug("No migration to apply to project {}", context.getProjectName()); } } } diff --git a/cli/src/main/java/com/devonfw/tools/ide/network/NetworkProxy.java b/cli/src/main/java/com/devonfw/tools/ide/network/NetworkProxy.java index 80d78ada47..4efcd33683 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/network/NetworkProxy.java +++ b/cli/src/main/java/com/devonfw/tools/ide/network/NetworkProxy.java @@ -4,15 +4,19 @@ import java.net.URL; import java.util.Locale; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.environment.IdeSystem; -import com.devonfw.tools.ide.log.IdeLogLevel; /** * Simple class to {@link #configure()} network proxy. */ public class NetworkProxy { + private static final Logger LOG = LoggerFactory.getLogger(NetworkProxy.class); + private static final String PROXY_DOCUMENTATION_PAGE = "https://github.com/devonfw/IDEasy/blob/main/documentation/proxy-support.adoc"; private final IdeContext context; @@ -44,12 +48,12 @@ private void setupNetworkProxy(String protocol) { String systemPropertyProxyHost = protocol + ".proxyHost"; String configuredValue = System.getProperty(systemPropertyProxyHost); if (configuredValue != null) { - this.context.trace("Proxy already configured via system property {}={}", systemPropertyProxyHost, configuredValue); + LOG.trace("Proxy already configured via system property {}={}", systemPropertyProxyHost, configuredValue); return; } String proxyUrlString = getProxyUrlFromEnvironmentVariable(protocol); if (proxyUrlString == null) { - this.context.trace("No {} proxy configured.", protocol); + LOG.trace("No {} proxy configured.", protocol); return; } try { @@ -75,9 +79,8 @@ private void setupNetworkProxy(String protocol) { system.setProperty(protocol + ".nonProxyHosts", this.nonProxyHosts); } } catch (MalformedURLException e) { - context.level(IdeLogLevel.WARNING) - .log(e, "Invalid {} proxy configuration detected with URL {}. Proxy configuration will be skipped.\n" - + "For further details, see " + PROXY_DOCUMENTATION_PAGE, protocol, proxyUrlString); + LOG.warn("Invalid {} proxy configuration detected with URL {}. Proxy configuration will be skipped.\n" + + "For further details, see " + PROXY_DOCUMENTATION_PAGE, protocol, proxyUrlString, e); } } @@ -118,7 +121,7 @@ private String getEnvironmentVariable(String name) { String value = this.context.getSystem().getEnv(name); if (value != null) { - this.context.trace("Found environment variable {}={}", name, value); + LOG.trace("Found environment variable {}={}", name, value); } return value; } diff --git a/cli/src/main/java/com/devonfw/tools/ide/network/NetworkStatusImpl.java b/cli/src/main/java/com/devonfw/tools/ide/network/NetworkStatusImpl.java index 24c72c21bd..4b7489def6 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/network/NetworkStatusImpl.java +++ b/cli/src/main/java/com/devonfw/tools/ide/network/NetworkStatusImpl.java @@ -6,15 +6,21 @@ import java.util.concurrent.Callable; import javax.net.ssl.SSLException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.cache.CachedValue; import com.devonfw.tools.ide.cli.CliOfflineException; import com.devonfw.tools.ide.context.AbstractIdeContext; +import com.devonfw.tools.ide.log.IdeLogLevel; /** * Implementation of {@link NetworkStatus}. */ public class NetworkStatusImpl implements NetworkStatus { + private static final Logger LOG = LoggerFactory.getLogger(NetworkStatusImpl.class); + private final AbstractIdeContext context; private NetworkProxy networkProxy; @@ -73,8 +79,8 @@ private Throwable doOnlineCheck() { connection.getContent(); return null; } catch (Exception e) { - if (this.context.debug().isEnabled()) { - this.context.debug().log(e, "Error when trying to connect to {}", this.onlineCheckUrl); + if (LOG.isDebugEnabled()) { + LOG.debug("Error when trying to connect to {}", this.onlineCheckUrl, e); } return e; } @@ -92,27 +98,27 @@ private void configureNetworkProxy() { public void logStatusMessage() { if (isOfflineMode()) { - this.context.warning("You are offline because you have enabled offline mode via CLI option."); + LOG.warn("You are offline because you have enabled offline mode via CLI option."); return; } Throwable error = getError(); if (error == null) { - this.context.success("You are online."); + IdeLogLevel.INTERACTION.log(LOG, "You are online."); return; } String message = "You are offline because of the following error:"; - if (this.context.debug().isEnabled()) { - this.context.error(error, message); + if (LOG.isDebugEnabled()) { + LOG.error(message, error); } else { - this.context.error(message); - this.context.error(error.toString()); + LOG.error(message); + LOG.error(error.toString()); } if (error instanceof SSLException) { - this.context.warning( + LOG.warn( "You are having TLS issues. We guess you are forced to use a VPN tool breaking end-to-end encryption causing this effect. As a workaround you can create and configure a truststore as described here:"); - this.context.interaction("https://github.com/devonfw/IDEasy/blob/main/documentation/proxy-support.adoc#tls-certificate-issues"); + IdeLogLevel.INTERACTION.log(LOG, "https://github.com/devonfw/IDEasy/blob/main/documentation/proxy-support.adoc#tls-certificate-issues"); } else { - this.context.interaction("Please check potential proxy settings, ensure you are properly connected to the internet and retry this operation."); + IdeLogLevel.INTERACTION.log(LOG, "Please check potential proxy settings, ensure you are properly connected to the internet and retry this operation."); } } diff --git a/cli/src/main/java/com/devonfw/tools/ide/nls/NlsBundle.java b/cli/src/main/java/com/devonfw/tools/ide/nls/NlsBundle.java index 545b853430..006ff936df 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/nls/NlsBundle.java +++ b/cli/src/main/java/com/devonfw/tools/ide/nls/NlsBundle.java @@ -3,6 +3,9 @@ import java.util.Locale; import java.util.ResourceBundle; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.commandlet.Commandlet; import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.property.Property; @@ -12,6 +15,8 @@ */ public class NlsBundle { + private static final Logger LOG = LoggerFactory.getLogger(NlsBundle.class); + private final IdeContext context; private final String fqn; @@ -62,7 +67,7 @@ public NlsBundle(IdeContext context, String name, Locale locale) { public String get(String key) { if (!this.bundle.containsKey(key)) { - this.context.warning("Cound not find key '{}' in ResourceBundle {}.properties", key, this.fqn); + LOG.warn("Cound not find key '{}' in ResourceBundle {}.properties", key, this.fqn); return "?" + key; } return this.bundle.getString(key); diff --git a/cli/src/main/java/com/devonfw/tools/ide/os/MacOsHelper.java b/cli/src/main/java/com/devonfw/tools/ide/os/MacOsHelper.java index 08b7a8380b..1d631427d5 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/os/MacOsHelper.java +++ b/cli/src/main/java/com/devonfw/tools/ide/os/MacOsHelper.java @@ -7,9 +7,11 @@ import java.util.Set; import java.util.stream.Stream; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.io.FileAccess; -import com.devonfw.tools.ide.log.IdeLogger; import com.devonfw.tools.ide.tool.ToolCommandlet; import com.devonfw.tools.ide.tool.repository.ToolRepository; @@ -18,6 +20,8 @@ */ public final class MacOsHelper { + private static final Logger LOG = LoggerFactory.getLogger(MacOsHelper.class); + private static final Set INVALID_LINK_FOLDERS = Set.of(IdeContext.FOLDER_CONTENTS, IdeContext.FOLDER_RESOURCES, IdeContext.FOLDER_BIN); @@ -25,8 +29,6 @@ public final class MacOsHelper { private final SystemInfo systemInfo; - private final IdeLogger logger; - /** * The constructor. * @@ -34,7 +36,7 @@ public final class MacOsHelper { */ public MacOsHelper(IdeContext context) { - this(context.getFileAccess(), context.getSystemInfo(), context); + this(context.getFileAccess(), context.getSystemInfo()); } /** @@ -42,14 +44,12 @@ public MacOsHelper(IdeContext context) { * * @param fileAccess the {@link FileAccess} instance. * @param systemInfo the {@link SystemInfo} instance. - * @param logger the {@link IdeLogger} instance. */ - public MacOsHelper(FileAccess fileAccess, SystemInfo systemInfo, IdeLogger logger) { + public MacOsHelper(FileAccess fileAccess, SystemInfo systemInfo) { super(); this.fileAccess = fileAccess; this.systemInfo = systemInfo; - this.logger = logger; } /** @@ -100,7 +100,7 @@ public Path findRootToolPath(ToolCommandlet commandlet, IdeContext context) { private Path findLinkDir(Path contentsDir, Path rootDir, String tool) { - this.logger.debug("Found MacOS app in {}", contentsDir); + LOG.debug("Found MacOS app in {}", contentsDir); Path resourcesAppBin = contentsDir.resolve(IdeContext.FOLDER_RESOURCES).resolve(IdeContext.FOLDER_APP) .resolve(IdeContext.FOLDER_BIN); if (Files.isDirectory(resourcesAppBin)) { diff --git a/cli/src/main/java/com/devonfw/tools/ide/os/WindowsHelperImpl.java b/cli/src/main/java/com/devonfw/tools/ide/os/WindowsHelperImpl.java index fc7ef12850..ee6d55eb2f 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/os/WindowsHelperImpl.java +++ b/cli/src/main/java/com/devonfw/tools/ide/os/WindowsHelperImpl.java @@ -2,6 +2,9 @@ import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.log.IdeLogLevel; import com.devonfw.tools.ide.process.ProcessErrorHandling; @@ -13,6 +16,8 @@ */ public class WindowsHelperImpl implements WindowsHelper { + private static final Logger LOG = LoggerFactory.getLogger(WindowsHelperImpl.class); + /** Registry key for the users environment variables. */ public static final String HKCU_ENVIRONMENT = "HKCU\\Environment"; @@ -40,9 +45,9 @@ public void removeUserEnvironmentValue(String key) { ProcessResult result = this.context.newProcess().executable("reg").addArgs("delete", HKCU_ENVIRONMENT, "/v", key, "/f") .errorHandling(ProcessErrorHandling.LOG_WARNING).run(ProcessMode.DEFAULT_CAPTURE); if (result.isSuccessful()) { - this.context.debug("Removed environment variable {}", key); + LOG.debug("Removed environment variable {}", key); } else { - result.log(IdeLogLevel.WARNING, this.context); + result.log(IdeLogLevel.WARNING); } } diff --git a/cli/src/main/java/com/devonfw/tools/ide/process/ProcessContext.java b/cli/src/main/java/com/devonfw/tools/ide/process/ProcessContext.java index 75e45189be..914dd518af 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/process/ProcessContext.java +++ b/cli/src/main/java/com/devonfw/tools/ide/process/ProcessContext.java @@ -5,7 +5,7 @@ import java.util.Objects; import java.util.function.Predicate; -import com.devonfw.tools.ide.log.IdeSubLogger; +import com.devonfw.tools.ide.log.IdeLogLevel; /** * Wrapper for {@link ProcessBuilder} to simplify its usage and avoid common mistakes and pitfalls. @@ -185,40 +185,40 @@ default List runAndGetOutput(String executable, String... arguments) { /** * Runs the given {@code executable} with the given {@code arguments} and returns the output from its {@link ProcessResult#getOut() standard output}. * - * @param logger the {@link IdeSubLogger} used to log errors instead of throwing an exception. + * @param logLevel the {@link IdeLogLevel} used to log errors instead of throwing an exception. * @param executable the executable program. * @param arguments the program arguments. * @return the output printed from the command. * @throws IllegalStateException if the command failed. */ - default List runAndGetOutput(IdeSubLogger logger, String executable, String... arguments) { + default List runAndGetOutput(IdeLogLevel logLevel, String executable, String... arguments) { executable(executable).addArgs(arguments); - if (logger == null) { + if (logLevel == null) { errorHandling(ProcessErrorHandling.THROW_ERR); } ProcessResult result = run(ProcessMode.DEFAULT_CAPTURE); - return result.getOutput(logger); + return result.getOutput(logLevel); } /** * Runs the given {@code executable} with the given {@code arguments} and returns the expected single line from its * {@link ProcessResult#getOut() standard output}. * - * @param logger the {@link IdeSubLogger} used to log errors instead of throwing an exception. + * @param logLevel the {@link IdeLogLevel} used to log errors instead of throwing an exception. * @param executable the executable program. * @param arguments the program arguments. * @return the single line printed from the command. * @throws IllegalStateException if the command did not print a single line as expected. */ - default String runAndGetSingleOutput(IdeSubLogger logger, String executable, String... arguments) { + default String runAndGetSingleOutput(IdeLogLevel logLevel, String executable, String... arguments) { executable(executable).addArgs(arguments); - if (logger == null) { + if (logLevel == null) { errorHandling(ProcessErrorHandling.THROW_ERR); } ProcessResult result = run(ProcessMode.DEFAULT_CAPTURE); - return result.getSingleOutput(logger); + return result.getSingleOutput(logLevel); } /** diff --git a/cli/src/main/java/com/devonfw/tools/ide/process/ProcessContextImpl.java b/cli/src/main/java/com/devonfw/tools/ide/process/ProcessContextImpl.java index 6c67a4e71f..d61cd85fc7 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/process/ProcessContextImpl.java +++ b/cli/src/main/java/com/devonfw/tools/ide/process/ProcessContextImpl.java @@ -17,6 +17,9 @@ import java.util.function.Predicate; import java.util.stream.Collectors; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.cli.CliProcessException; import com.devonfw.tools.ide.common.SystemPath; import com.devonfw.tools.ide.context.IdeContext; @@ -32,6 +35,8 @@ */ public class ProcessContextImpl implements ProcessContext { + private static final Logger LOG = LoggerFactory.getLogger(ProcessContextImpl.class); + private static final String PREFIX_USR_BIN_ENV = "/usr/bin/env "; private static final Predicate EXIT_CODE_ACCEPTOR = rc -> rc == ProcessResult.SUCCESS; @@ -101,7 +106,7 @@ public ProcessContext directory(Path directory) { if (directory != null) { this.processBuilder.directory(directory.toFile()); } else { - this.context.debug( + LOG.debug( "Could not set the process builder's working directory! Directory of the current java process is used."); } @@ -132,7 +137,7 @@ public ProcessContext withEnvVar(String key, String value) { if (IdeVariables.PATH.getName().equals(key)) { this.overriddenPath = value; } else { - this.context.trace("Setting process environment variable {}={}", key, value); + LOG.trace("Setting process environment variable {}={}", key, value); this.processBuilder.environment().put(key, value); } return this; @@ -175,16 +180,16 @@ public ProcessResult run(ProcessMode processMode) { systemPath = systemPath.withPath(this.overriddenPath, this.extraPathEntries); } String path = systemPath.toString(); - this.context.trace("Setting PATH for process execution of {} to {}", this.executable.getFileName(), path); + LOG.trace("Setting PATH for process execution of {} to {}", this.executable.getFileName(), path); this.executable = systemPath.findBinary(this.executable); this.processBuilder.environment().put(IdeVariables.PATH.getName(), path); List args = new ArrayList<>(this.arguments.size() + 4); String interpreter = addExecutable(args); args.addAll(this.arguments); String command = createCommand(); - if (this.context.debug().isEnabled()) { + if (LOG.isDebugEnabled()) { String message = createCommandMessage(interpreter, " ..."); - this.context.debug(message); + LOG.debug(message); } try { @@ -374,8 +379,8 @@ private String addExecutable(List args) { args.add(this.context.findBashRequired().toString()); } if ("msi".equalsIgnoreCase(fileExtension)) { - args.add(0, "/i"); - args.add(0, "msiexec"); + args.addFirst("/i"); + args.addFirst("msiexec"); } args.add(this.executable.toString()); return interpreter; @@ -387,8 +392,8 @@ private void performLogging(ProcessResult result, int exitCode, String interpret IdeLogLevel ideLogLevel = this.errorHandling.getLogLevel(); String message = createCommandMessage(interpreter, "\nfailed with exit code " + exitCode + "!"); - context.level(ideLogLevel).log(message); - result.log(ideLogLevel, context); + LOG.atLevel(ideLogLevel.getSlf4jLevel()).log(message); + result.log(ideLogLevel); if (this.errorHandling == ProcessErrorHandling.THROW_CLI) { throw new CliProcessException(message, result); @@ -404,8 +409,7 @@ private void modifyArgumentsOnBackgroundProcess(ProcessMode processMode) { Path bash = this.context.findBash(); if (bash == null) { - this.context.warning( - "Cannot start background process via bash because no bash installation was found. Hence, output will be discarded."); + LOG.warn("Cannot start background process via bash because no bash installation was found. Hence, output will be discarded."); this.processBuilder.redirectOutput(Redirect.DISCARD).redirectError(Redirect.DISCARD); return; } diff --git a/cli/src/main/java/com/devonfw/tools/ide/process/ProcessResult.java b/cli/src/main/java/com/devonfw/tools/ide/process/ProcessResult.java index 8b9fe1650b..0c52cbb0b2 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/process/ProcessResult.java +++ b/cli/src/main/java/com/devonfw/tools/ide/process/ProcessResult.java @@ -4,9 +4,7 @@ import java.util.function.Predicate; import com.devonfw.tools.ide.cli.CliProcessException; -import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.log.IdeLogLevel; -import com.devonfw.tools.ide.log.IdeSubLogger; /** * Result of a {@link Process} execution. @@ -79,16 +77,16 @@ default String getSingleOutput() { } /** - * @param logger the {@link IdeSubLogger logger} to use. + * @param logLevel the {@link IdeLogLevel} to use. * @return the first captured standard out. Will be {@code null} if not captured but redirected. */ - String getSingleOutput(IdeSubLogger logger); + String getSingleOutput(IdeLogLevel logLevel); /** - * @param logger the {@link IdeSubLogger logger} to use. + * @param logLevel the {@link IdeLogLevel} to use. * @return the first captured standard out. Will be {@code null} if not captured but redirected. */ - List getOutput(IdeSubLogger logger); + List getOutput(IdeLogLevel logLevel); /** * @return the {@link List} with the lines captured on standard out. Will be {@code null} if not captured but redirected. @@ -110,18 +108,16 @@ default String getSingleOutput() { * Logs output and error messages on the provided log level. * * @param level the {@link IdeLogLevel} to use e.g. IdeLogLevel.ERROR. - * @param context the {@link IdeContext} to use. */ - void log(IdeLogLevel level, IdeContext context); + void log(IdeLogLevel level); /** * Logs output and error messages on the provided log level. * * @param outLevel the {@link IdeLogLevel} to use for {@link #getOut()}. - * @param context the {@link IdeContext} to use. * @param errorLevel the {@link IdeLogLevel} to use for {@link #getErr()}. */ - void log(IdeLogLevel outLevel, IdeContext context, IdeLogLevel errorLevel); + void log(IdeLogLevel outLevel, IdeLogLevel errorLevel); /** * Throws a {@link CliProcessException} if not {@link #isSuccessful() successful} and otherwise does nothing. diff --git a/cli/src/main/java/com/devonfw/tools/ide/process/ProcessResultImpl.java b/cli/src/main/java/com/devonfw/tools/ide/process/ProcessResultImpl.java index 9c4538905c..ece2516626 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/process/ProcessResultImpl.java +++ b/cli/src/main/java/com/devonfw/tools/ide/process/ProcessResultImpl.java @@ -4,16 +4,19 @@ import java.util.List; import java.util.Objects; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.cli.CliProcessException; -import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.log.IdeLogLevel; -import com.devonfw.tools.ide.log.IdeSubLogger; /** * Implementation of {@link ProcessResult}. */ public class ProcessResultImpl implements ProcessResult { + private static final Logger LOG = LoggerFactory.getLogger(ProcessResultImpl.class); + private final String executable; private final String command; @@ -74,7 +77,7 @@ public int getExitCode() { } @Override - public String getSingleOutput(IdeSubLogger logger) throws IllegalStateException { + public String getSingleOutput(IdeLogLevel logLevel) throws IllegalStateException { String errorMessage; if (this.isSuccessful()) { List out = this.getOut(); @@ -99,16 +102,16 @@ public String getSingleOutput(IdeSubLogger logger) throws IllegalStateException } else { errorMessage = "Command " + this.getCommand() + " failed with exit code " + this.getExitCode(); } - if (logger == null) { + if (logLevel == null) { throw new IllegalStateException(errorMessage); } else { - logger.log(errorMessage); + doLog(logLevel, errorMessage); return null; } } @Override - public List getOutput(IdeSubLogger logger) throws IllegalStateException { + public List getOutput(IdeLogLevel logLevel) throws IllegalStateException { String errorMessage; if (this.isSuccessful()) { List out = this.getOut(); @@ -116,10 +119,10 @@ public List getOutput(IdeSubLogger logger) throws IllegalStateException } else { errorMessage = "Command " + this.getCommand() + " failed with exit code " + this.getExitCode(); } - if (logger == null) { + if (logLevel == null) { throw new IllegalStateException(errorMessage); } else { - logger.log(errorMessage); + doLog(logLevel, errorMessage); return null; } } @@ -149,30 +152,30 @@ public boolean isSuccessful() { } @Override - public void log(IdeLogLevel level, IdeContext context) { - log(level, context, level); + public void log(IdeLogLevel level) { + log(level, level); } @Override - public void log(IdeLogLevel outLevel, IdeContext context, IdeLogLevel errorLevel) { + public void log(IdeLogLevel outLevel, IdeLogLevel errorLevel) { if (!this.outputMessages.isEmpty()) { for (OutputMessage outputMessage : this.outputMessages) { if (outputMessage.error()) { - doLog(errorLevel, outputMessage.message(), context); + doLog(errorLevel, outputMessage.message()); } else { - doLog(outLevel, outputMessage.message(), context); + doLog(outLevel, outputMessage.message()); } } } } - private void doLog(IdeLogLevel level, String message, IdeContext context) { + private void doLog(IdeLogLevel level, String message) { // remove !MESSAGE from log message if (message.startsWith("!MESSAGE ")) { message = message.substring(9); } - context.level(level).log(message); + LOG.atLevel(level.getSlf4jLevel()).log(message); } @Override diff --git a/cli/src/main/java/com/devonfw/tools/ide/property/Property.java b/cli/src/main/java/com/devonfw/tools/ide/property/Property.java index aa1edd7d52..dbda7b1271 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/property/Property.java +++ b/cli/src/main/java/com/devonfw/tools/ide/property/Property.java @@ -5,6 +5,9 @@ import java.util.Objects; import java.util.function.Consumer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.cli.CliArgument; import com.devonfw.tools.ide.cli.CliArguments; import com.devonfw.tools.ide.commandlet.Commandlet; @@ -27,6 +30,8 @@ */ public abstract class Property { + private static final Logger LOG = LoggerFactory.getLogger(Property.class); + private static final String INVALID_ARGUMENT = "Invalid CLI argument '{}' for property '{}' of commandlet '{}'"; private static final String INVALID_ARGUMENT_WITH_EXCEPTION_MESSAGE = INVALID_ARGUMENT + ": {}"; @@ -186,7 +191,7 @@ public V getValue() { if (this.value.isEmpty()) { return null; } else { - return this.value.get(0); + return this.value.getFirst(); } } @@ -306,9 +311,9 @@ public final boolean assignValueAsString(String valueAsString, IdeContext contex return true; } catch (Exception e) { if (e instanceof IllegalArgumentException) { - context.warning(INVALID_ARGUMENT, valueAsString, getNameOrAlias(), commandlet.getName()); + LOG.warn(INVALID_ARGUMENT, valueAsString, getNameOrAlias(), commandlet.getName()); } else { - context.warning(INVALID_ARGUMENT_WITH_EXCEPTION_MESSAGE, valueAsString, getNameOrAlias(), commandlet.getName(), e.getMessage()); + LOG.warn(INVALID_ARGUMENT_WITH_EXCEPTION_MESSAGE, valueAsString, getNameOrAlias(), commandlet.getName(), e.getMessage()); } return false; } diff --git a/cli/src/main/java/com/devonfw/tools/ide/security/ToolVersionChoice.java b/cli/src/main/java/com/devonfw/tools/ide/security/ToolVersionChoice.java index 6ee2959a07..262b17777b 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/security/ToolVersionChoice.java +++ b/cli/src/main/java/com/devonfw/tools/ide/security/ToolVersionChoice.java @@ -1,6 +1,9 @@ package com.devonfw.tools.ide.security; -import com.devonfw.tools.ide.log.IdeLogger; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.devonfw.tools.ide.log.IdeLogLevel; import com.devonfw.tools.ide.tool.ToolEditionAndVersion; import com.devonfw.tools.ide.url.model.file.json.Cve; import com.devonfw.tools.ide.version.VersionIdentifier; @@ -15,6 +18,8 @@ */ public record ToolVersionChoice(ToolEditionAndVersion toolEditionAndVersion, String option, ToolVulnerabilities vulnerabilities) { + private static final Logger LOG = LoggerFactory.getLogger(ToolVersionChoice.class); + /** @see #ofCurrent(ToolEditionAndVersion, ToolVulnerabilities) */ public static final String CVE_OPTION_CURRENT = "current"; @@ -52,17 +57,16 @@ public static ToolVersionChoice ofNearest(ToolEditionAndVersion toolEditionAndVe } /** - * @param logger the {@link IdeLogger}. * @return {@code true} if {@link ToolVulnerabilities#EMPTY empty} (no vulnerabilities), {@code false} otherwise. */ - public boolean logAndCheckIfEmpty(IdeLogger logger) { + public boolean logAndCheckIfEmpty() { String message = this.vulnerabilities.toString(this.toolEditionAndVersion); if (this.vulnerabilities.getIssues().isEmpty()) { - logger.success(message); + IdeLogLevel.SUCCESS.log(LOG, message); return true; } else { - logger.warning(message); + LOG.warn(message); return false; } } diff --git a/cli/src/main/java/com/devonfw/tools/ide/step/Step.java b/cli/src/main/java/com/devonfw/tools/ide/step/Step.java index b95bc25da9..19760d9723 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/step/Step.java +++ b/cli/src/main/java/com/devonfw/tools/ide/step/Step.java @@ -3,8 +3,6 @@ import java.util.concurrent.Callable; import java.util.function.Supplier; -import com.devonfw.tools.ide.log.IdeSubLogger; - /** * Interface for a {@link Step} of the process. Allows to split larger processes into smaller steps that are traced and measured. Also prevents that if one step * fails, the overall process can still continue so a sub-step (e.g. "plugin installation" or "git update") does not automatically block the entire process. At @@ -70,6 +68,15 @@ default boolean isFailure() { */ boolean isSilent(); + /** + * Should be called to end this {@link Step} {@link #getSuccess() successfully}. May be called only once. + * + * @param silent to suppress the success message from being logged. + */ + default void success(boolean silent) { + success(); + } + /** * Should be called to end this {@link Step} {@link #getSuccess() successfully}. May be called only once. */ @@ -96,11 +103,6 @@ default void success(String message) { */ void success(String message, Object... args); - /** - * @return the {@link IdeSubLogger} for success messages allowing generic code sharing logger fallback. - */ - IdeSubLogger asSuccess(); - /** * Ensures this {@link Step} is properly ended. Has to be called from a finally block. Do not call manually but always use {@link #run(Runnable)} or * {@link #call(Callable)}. @@ -133,7 +135,7 @@ default void error(String message, Object... args) { * Should be called to end this {@link Step} as {@link #isFailure() failure} with an explicit error message and/or {@link Throwable exception}. May be called * only once. * - * @param error the catched {@link Throwable}. + * @param error the caught {@link Throwable}. */ default void error(Throwable error) { @@ -144,7 +146,7 @@ default void error(Throwable error) { * Should be called to end this {@link Step} as {@link #isFailure() failure} with an explicit error message and/or {@link Throwable exception}. May be called * only once. * - * @param error the catched {@link Throwable}. + * @param error the caught {@link Throwable}. * @param suppress to suppress the error logging (if error will be rethrown and duplicated error messages shall be avoided). */ default void error(Throwable error, boolean suppress) { @@ -169,7 +171,7 @@ default void error(Throwable error, String message) { * Should be called to end this {@link Step} as {@link #isFailure() failure} with an explicit error message and/or {@link Throwable exception}. May be called * only once. * - * @param error the catched {@link Throwable}. May be {@code null} if only a {@code message} is provided. + * @param error the caught {@link Throwable}. May be {@code null} if only a {@code message} is provided. * @param message the explicit message to log as error. * @param args the optional arguments to fill as placeholder into the {@code message}. */ @@ -182,18 +184,13 @@ default void error(Throwable error, String message, Object... args) { * Should be called to end this {@link Step} as {@link #isFailure() failure} with an explicit error message and/or {@link Throwable exception}. May be called * only once. * - * @param error the catched {@link Throwable}. May be {@code null} if only a {@code message} is provided. + * @param error the caught {@link Throwable}. May be {@code null} if only a {@code message} is provided. * @param suppress to suppress the error logging (if error will be rethrown and duplicated error messages shall be avoided). * @param message the explicit message to log as error. * @param args the optional arguments to fill as placeholder into the {@code message}. */ void error(Throwable error, boolean suppress, String message, Object... args); - /** - * @return the {@link IdeSubLogger} for error messages allowing generic code sharing logger fallback. - */ - IdeSubLogger asError(); - /** * @return the parent {@link Step} or {@code null} if there is no parent. */ diff --git a/cli/src/main/java/com/devonfw/tools/ide/step/StepImpl.java b/cli/src/main/java/com/devonfw/tools/ide/step/StepImpl.java index e31275625f..5c7723b0b6 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/step/StepImpl.java +++ b/cli/src/main/java/com/devonfw/tools/ide/step/StepImpl.java @@ -5,16 +5,21 @@ import java.util.Arrays; import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.event.Level; + import com.devonfw.tools.ide.context.AbstractIdeContext; import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.log.IdeLogLevel; -import com.devonfw.tools.ide.log.IdeSubLogger; /** * Regular implementation of {@link Step}. */ public final class StepImpl implements Step { + private static final Logger LOG = LoggerFactory.getLogger(StepImpl.class); + private final AbstractIdeContext context; private final StepImpl parent; @@ -58,12 +63,12 @@ public StepImpl(AbstractIdeContext context, StepImpl parent, String name, boolea parent.children.add(this); } if (params.length == 0) { - this.context.trace("Starting step {}...", name); + LOG.trace("Starting step {}...", name); } else { - this.context.trace("Starting step {} with params {}...", name, Arrays.toString(params)); + LOG.trace("Starting step {} with params {}...", name, Arrays.toString(params)); } if (!this.silent) { - this.context.step("Start: {}", name); + IdeLogLevel.STEP.log(LOG, "Start: {}", name); } } @@ -118,63 +123,12 @@ public void success(String message, Object... args) { end(Boolean.TRUE, null, false, message, args); } - @Override - public IdeSubLogger asSuccess() { - - return new IdeSubLogger() { - @Override - public String log(Throwable error, String message, Object... args) { - - assert (error == null); - success(message, args); - return message; - } - - @Override - public boolean isEnabled() { - - return true; - } - - @Override - public IdeLogLevel getLevel() { - - return IdeLogLevel.SUCCESS; - } - }; - } - @Override public void error(Throwable error, boolean suppress, String message, Object... args) { end(Boolean.FALSE, error, suppress, message, args); } - @Override - public IdeSubLogger asError() { - - return new IdeSubLogger() { - @Override - public String log(Throwable error, String message, Object... args) { - - error(error, message, args); - return message; - } - - @Override - public boolean isEnabled() { - - return true; - } - - @Override - public IdeLogLevel getLevel() { - - return IdeLogLevel.ERROR; - } - }; - } - @Override public void close() { @@ -187,7 +141,7 @@ private void end(Boolean newSuccess, Throwable error, boolean suppress, String m if (!firstCallOfEnd) { assert (this.duration > 0); if ((newSuccess != null) && (newSuccess != this.success)) { - this.context.warning("Step '{}' already ended with {} and now ended again with {}.", this.name, this.success, newSuccess); + LOG.warn("Step '{}' already ended with {} and now ended again with {}.", this.name, this.success, newSuccess); } else { return; } @@ -206,13 +160,13 @@ private void end(Boolean newSuccess, Throwable error, boolean suppress, String m if (newSuccess.booleanValue()) { assert (error == null); if (message != null) { - this.context.success(message, args); + IdeLogLevel.SUCCESS.log(LOG, message, args); } else if (!this.silent) { - this.context.success("Successfully ended step '{}'.", this.name); + IdeLogLevel.SUCCESS.log(LOG, "Successfully ended step '{}'.", this.name); } - this.context.debug("Step '{}' ended successfully.", this.name); + LOG.debug("Step '{}' ended successfully.", this.name); } else { - IdeSubLogger logger; + Level level; if ((message != null) || (error != null)) { if (suppress) { if (error != null) { @@ -220,19 +174,26 @@ private void end(Boolean newSuccess, Throwable error, boolean suppress, String m } else { this.errorMessage = message; } - logger = this.context.debug(); + level = Level.DEBUG; } else { - this.errorMessage = this.context.error().log(error, message, args); + if (message == null) { + message = error.getMessage(); + } + if (args == null) { + LOG.atError().setCause(error).log(message); + } else { + LOG.atError().setCause(error).log(message, args); + } if (error == null) { - logger = this.context.debug(); + level = Level.DEBUG; } else { - logger = this.context.error(); + level = Level.ERROR; } } } else { - logger = this.context.info(); + level = Level.INFO; } - logger.log("Step '{}' ended with failure.", this.name); + LOG.atLevel(level).log("Step '{}' ended with failure.", this.name); } if (firstCallOfEnd) { this.context.endStep(this); @@ -246,8 +207,8 @@ private void end(Boolean newSuccess, Throwable error, boolean suppress, String m */ public void logSummary(boolean suppressSuccess) { - if (this.context.trace().isEnabled()) { - this.context.trace(toString()); + if (LOG.isTraceEnabled()) { + LOG.trace(toString()); } if (this.context.isQuietMode() || (this.children.isEmpty())) { return; @@ -256,10 +217,10 @@ public void logSummary(boolean suppressSuccess) { logErrorSummary(0, summary); if (summary.getError() == 0) { if (!suppressSuccess) { - this.context.success("Successfully completed {}", getNameWithParams()); + IdeLogLevel.SUCCESS.log(LOG, "Successfully completed {}", getNameWithParams()); } } else { - this.context.error(summary.toString()); + LOG.error(summary.toString()); } } @@ -272,7 +233,7 @@ private void logErrorSummary(int depth, StepSummary summary) { if (error == null) { error = "unexpected error"; } - this.context.error("{}Step '{}' failed: {}", getIndent(depth), getNameWithParams(), error); + LOG.error("{}Step '{}' failed: {}", getIndent(depth), getNameWithParams(), error); } depth++; for (StepImpl child : this.children) { diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java index 824276ceb1..95c520a3b6 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java @@ -6,13 +6,18 @@ import java.util.List; import java.util.Set; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.cli.CliException; import com.devonfw.tools.ide.common.Tag; import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.io.FileAccess; +import com.devonfw.tools.ide.log.IdeLogLevel; import com.devonfw.tools.ide.process.ProcessContext; import com.devonfw.tools.ide.process.ProcessErrorHandling; import com.devonfw.tools.ide.process.ProcessMode; +import com.devonfw.tools.ide.step.Step; import com.devonfw.tools.ide.tool.repository.ToolRepository; import com.devonfw.tools.ide.version.VersionIdentifier; @@ -21,6 +26,8 @@ */ public abstract class GlobalToolCommandlet extends ToolCommandlet { + private static final Logger LOG = LoggerFactory.getLogger(GlobalToolCommandlet.class); + /** * The constructor. * @@ -59,7 +66,7 @@ protected boolean runWithPackageManager(boolean silent, List getInstallPackageManagerCommands() { @Override public VersionIdentifier getInstalledVersion() { //TODO: handle "get-version " - this.context.error("Couldn't get installed version of " + this.getName()); + LOG.error("Couldn't get installed version of " + this.getName()); return null; } @Override public String getInstalledEdition() { //TODO: handle "get-edition " - this.context.error("Couldn't get installed edition of " + this.getName()); + LOG.error("Couldn't get installed edition of " + this.getName()); return null; } @@ -207,6 +219,6 @@ protected Path getInstallationPath(String edition, VersionIdentifier resolvedVer @Override public void uninstall() { //TODO: handle "uninstall " - this.context.error("Couldn't uninstall " + this.getName()); + LOG.error("Couldn't uninstall " + this.getName()); } } diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/IdeasyCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/tool/IdeasyCommandlet.java index f7d45adcc3..f435c12995 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/IdeasyCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/IdeasyCommandlet.java @@ -9,6 +9,9 @@ import java.util.List; import java.util.Set; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.cli.CliException; import com.devonfw.tools.ide.commandlet.UpgradeMode; import com.devonfw.tools.ide.common.SimpleSystemPath; @@ -17,6 +20,7 @@ import com.devonfw.tools.ide.io.FileAccess; import com.devonfw.tools.ide.io.ini.IniFile; import com.devonfw.tools.ide.io.ini.IniSection; +import com.devonfw.tools.ide.log.IdeLogLevel; import com.devonfw.tools.ide.os.WindowsHelper; import com.devonfw.tools.ide.os.WindowsPathSyntax; import com.devonfw.tools.ide.process.ProcessMode; @@ -37,6 +41,8 @@ */ public class IdeasyCommandlet extends MvnBasedLocalToolCommandlet { + private static final Logger LOG = LoggerFactory.getLogger(IdeasyCommandlet.class); + /** The {@link MvnArtifact} for IDEasy. */ public static final MvnArtifact ARTIFACT = MvnArtifact.ofIdeasyCli("*!", "tar.gz", "${os}-${arch}"); @@ -121,7 +127,7 @@ protected ToolInstallation doInstall(ToolInstallRequest request) { if (IdeVersion.isUndefined() && !this.context.isForceMode()) { VersionIdentifier version = IdeVersion.getVersionIdentifier(); - this.context.warning("You are using IDEasy version {} which indicates local development - skipping upgrade.", version); + LOG.warn("You are using IDEasy version {} which indicates local development - skipping upgrade.", version); return toolAlreadyInstalled(request); } return super.doInstall(request); @@ -149,21 +155,22 @@ public VersionIdentifier getLatestVersion() { */ public boolean checkIfUpdateIsAvailable() { VersionIdentifier installedVersion = getInstalledVersion(); - this.context.success("Your version of IDEasy is {}.", installedVersion); + IdeLogLevel.SUCCESS.log(LOG, "Your version of IDEasy is {}.", installedVersion); if (IdeVersion.isSnapshot()) { - this.context.warning("You are using a SNAPSHOT version of IDEasy. For stability consider switching to a stable release via 'ide upgrade --mode=stable'"); + LOG.warn("You are using a SNAPSHOT version of IDEasy. For stability consider switching to a stable release via 'ide upgrade --mode=stable'"); } if (this.context.isOffline()) { - this.context.warning("Skipping check for newer version of IDEasy because you are offline."); + LOG.warn("Skipping check for newer version of IDEasy because you are offline."); return false; } VersionIdentifier latestVersion = getLatestVersion(); if (installedVersion.equals(latestVersion)) { - this.context.success("Your are using the latest version of IDEasy and no update is available."); + IdeLogLevel.SUCCESS.log(LOG, "Your are using the latest version of IDEasy and no update is available."); return false; } else { - this.context.interaction("Your version of IDEasy is {} but version {} is available. Please run the following command to upgrade to the latest version:\n" - + "ide upgrade", installedVersion, latestVersion); + IdeLogLevel.INTERACTION.log(LOG, + "Your version of IDEasy is {} but version {} is available. Please run the following command to upgrade to the latest version:\n" + + "ide upgrade", installedVersion, latestVersion); return true; } } @@ -183,7 +190,7 @@ public void installIdeasy(Path cwd) { Path ideasyVersionPath = ideasySoftwarePath.resolve(IdeVersion.getVersionString()); FileAccess fileAccess = this.context.getFileAccess(); if (Files.isDirectory(ideasyVersionPath)) { - this.context.error("IDEasy is already installed at {} - if your installation is broken, delete it manually and rerun setup!", ideasyVersionPath); + LOG.error("IDEasy is already installed at {} - if your installation is broken, delete it manually and rerun setup!", ideasyVersionPath); } else { List installationArtifacts = new ArrayList<>(); boolean success = true; @@ -207,8 +214,8 @@ public void installIdeasy(Path cwd) { addToShellRc(BASHRC, ideRoot, null); addToShellRc(ZSHRC, ideRoot, "autoload -U +X bashcompinit && bashcompinit"); installIdeasyWindowsEnv(ideRoot, installationPath); - this.context.success("IDEasy has been installed successfully on your system."); - this.context.warning("IDEasy has been setup for new shells but it cannot work in your current shell(s).\n" + IdeLogLevel.SUCCESS.log(LOG, "IDEasy has been installed successfully on your system."); + LOG.warn("IDEasy has been setup for new shells but it cannot work in your current shell(s).\n" + "Reboot or open a new terminal to make it work."); } @@ -220,13 +227,13 @@ private void installIdeasyWindowsEnv(Path ideRoot, Path installationPath) { helper.setUserEnvironmentValue(IdeVariables.IDE_ROOT.getName(), ideRoot.toString()); String userPath = helper.getUserEnvironmentValue(IdeVariables.PATH.getName()); if (userPath == null) { - this.context.error("Could not read user PATH from registry!"); + LOG.error("Could not read user PATH from registry!"); } else { - this.context.info("Found user PATH={}", userPath); + LOG.info("Found user PATH={}", userPath); Path ideasyBinPath = installationPath.resolve("bin"); SimpleSystemPath path = SimpleSystemPath.of(userPath, ';'); if (path.getEntries().isEmpty()) { - this.context.warning("ATTENTION:\n" + LOG.warn("ATTENTION:\n" + "Your user specific PATH variable seems to be empty.\n" + "You can double check this by pressing [Windows][r] and launch the program SystemPropertiesAdvanced.\n" + "Then click on 'Environment variables' and check if 'PATH' is set in the 'user variables' from the upper list.\n" @@ -264,7 +271,7 @@ public void setupWindowsTerminal() { try { installWindowsTerminal(); } catch (Exception e) { - this.context.error(e, "Failed to install Windows Terminal!"); + LOG.error("Failed to install Windows Terminal!", e); } } configureWindowsTerminalGitBash(); @@ -283,7 +290,7 @@ private boolean isWindowsTerminalInstalled() { .run(ProcessMode.DEFAULT_CAPTURE); return result.isSuccessful() && !result.getOut().isEmpty(); } catch (Exception e) { - this.context.debug("Failed to check Windows Terminal installation: {}", e.getMessage()); + LOG.debug("Failed to check Windows Terminal installation.", e); return false; } } @@ -293,18 +300,18 @@ private boolean isWindowsTerminalInstalled() { */ private void installWindowsTerminal() { try { - this.context.info("Installing Windows Terminal..."); + LOG.info("Installing Windows Terminal..."); ProcessResult result = this.context.newProcess() .executable("winget") .addArgs("install", "Microsoft.WindowsTerminal") .run(ProcessMode.DEFAULT); if (result.isSuccessful()) { - this.context.success("Windows Terminal has been installed successfully."); + IdeLogLevel.SUCCESS.log(LOG, "Windows Terminal has been installed successfully."); } else { - this.context.warning("Failed to install Windows Terminal. Please install it manually from Microsoft Store."); + LOG.warn("Failed to install Windows Terminal. Please install it manually from Microsoft Store."); } } catch (Exception e) { - this.context.warning("Failed to install Windows Terminal: {}. Please install it manually from Microsoft Store.", e.getMessage()); + LOG.warn("Failed to install Windows Terminal: {}. Please install it manually from Microsoft Store.", e.toString()); } } @@ -314,21 +321,21 @@ private void installWindowsTerminal() { protected void configureWindowsTerminalGitBash() { Path settingsPath = getWindowsTerminalSettingsPath(); if (settingsPath == null || !Files.exists(settingsPath)) { - this.context.warning("Windows Terminal settings file not found. Cannot configure Git Bash integration."); + LOG.warn("Windows Terminal settings file not found. Cannot configure Git Bash integration."); return; } try { Path bashPath = this.context.findBash(); if (bashPath == null) { - this.context.warning("Git Bash not found. Cannot configure Windows Terminal integration."); + LOG.warn("Git Bash not found. Cannot configure Windows Terminal integration."); return; } configureGitBashProfile(settingsPath, bashPath.toString()); - this.context.success("Git Bash has been configured in Windows Terminal."); + IdeLogLevel.SUCCESS.log(LOG, "Git Bash has been configured in Windows Terminal."); } catch (Exception e) { - this.context.warning("Failed to configure Git Bash in Windows Terminal: {}", e.getMessage()); + LOG.warn("Failed to configure Git Bash in Windows Terminal: {}", e.getMessage()); } } @@ -398,7 +405,7 @@ private void configureGitBashProfile(Path settingsPath, String bashPath) throws // Add Git Bash profile if it doesn't exist if (gitBashProfileExists) { - this.context.info("Git Bash profile already exists in {}.", settingsPath); + LOG.info("Git Bash profile already exists in {}.", settingsPath); } else { ObjectNode gitBashProfile = mapper.createObjectNode(); String newGuid = "{2ece5bfe-50ed-5f3a-ab87-5cd4baafed2b}"; @@ -431,10 +438,10 @@ private String getGitBashIconPath(String bashPathString) { if (parent != null) { Path iconPath = parent.resolve("mingw64/share/git/git-for-windows.ico"); if (Files.exists(iconPath)) { - this.context.debug("Found git-bash icon at {}", iconPath); + LOG.debug("Found git-bash icon at {}", iconPath); return iconPath.toString(); } - this.context.debug("Git Bash icon not found at {}. Using default icon.", iconPath); + LOG.debug("Git Bash icon not found at {}. Using default icon.", iconPath); } return "ms-appx:///ProfileIcons/{0caa0dad-35be-5f56-a8ff-afceeeaa6101}.png"; } @@ -495,9 +502,9 @@ private void removeFromShellRc(String filename, Path ideRoot) { private void modifyShellRc(String filename, Path ideRoot, boolean add, String extraLine) { if (add) { - this.context.info("Configuring IDEasy in {}", filename); + LOG.info("Configuring IDEasy in {}", filename); } else { - this.context.info("Removing IDEasy from {}", filename); + LOG.info("Removing IDEasy from {}", filename); } Path rcFile = this.context.getUserHome().resolve(filename); FileAccess fileAccess = this.context.getFileAccess(); @@ -517,7 +524,7 @@ private void modifyShellRc(String filename, Path ideRoot, boolean add, String ex String line = iterator.next(); line = line.trim(); if (isObsoleteRcLine(line)) { - this.context.info("Removing obsolete line from {}: {}", filename, line); + LOG.info("Removing obsolete line from {}: {}", filename, line); iterator.remove(); removeCount++; } else if (line.equals(extraLine)) { @@ -534,7 +541,7 @@ private void modifyShellRc(String filename, Path ideRoot, boolean add, String ex lines.add(BASH_CODE_SOURCE_FUNCTIONS); } fileAccess.writeFileLines(lines, rcFile); - this.context.debug("Successfully updated {}", filename); + LOG.debug("Successfully updated {}", filename); } private static boolean isObsoleteRcLine(String line) { @@ -558,7 +565,7 @@ private boolean addInstallationArtifact(Path cwd, String artifactName, boolean r if (Files.exists(artifactPath)) { installationArtifacts.add(artifactPath); } else if (required) { - this.context.error("Missing required file {}", artifactName); + LOG.error("Missing required file {}", artifactName); return false; } return true; @@ -593,8 +600,8 @@ public void uninstallIdeasy() { uninstallIdeasyWindowsEnv(ideRoot); uninstallIdeasyIdePath(idePath); deleteDownloadCache(); - this.context.success("IDEasy has been uninstalled from your system."); - this.context.interaction("ATTENTION:\n" + IdeLogLevel.SUCCESS.log(LOG, "IDEasy has been uninstalled from your system."); + IdeLogLevel.INTERACTION.log(LOG, "ATTENTION:\n" + "In order to prevent data-loss, we do not delete your projects and git repositories!\n" + "To entirely get rid of IDEasy, also check your IDE_ROOT folder at:\n" + "{}", ideRoot); @@ -602,7 +609,7 @@ public void uninstallIdeasy() { private void deleteDownloadCache() { Path downloadPath = this.context.getDownloadPath(); - this.context.info("Deleting download cache from {}", downloadPath); + LOG.info("Deleting download cache from {}", downloadPath); this.context.getFileAccess().delete(downloadPath); } @@ -610,10 +617,11 @@ private void uninstallIdeasyIdePath(Path idePath) { if (this.context.getSystemInfo().isWindows()) { this.context.newProcess().executable("bash").addArgs("-c", "sleep 10 && rm -rf \"" + WindowsPathSyntax.MSYS.format(idePath) + "\"").run(ProcessMode.BACKGROUND); - this.context.interaction("To prevent windows file locking errors, we perform an asynchronous deletion of {} in background now.\n" - + "Please close all terminals and wait a minute for the deletion to complete before running other commands.", idePath); + IdeLogLevel.INTERACTION.log(LOG, + "To prevent windows file locking errors, we perform an asynchronous deletion of {} in background now.\n" + + "Please close all terminals and wait a minute for the deletion to complete before running other commands.", idePath); } else { - this.context.info("Finally deleting {}", idePath); + LOG.info("Finally deleting {}", idePath); this.context.getFileAccess().delete(idePath); } } @@ -626,9 +634,9 @@ private void uninstallIdeasyWindowsEnv(Path ideRoot) { helper.removeUserEnvironmentValue(IdeVariables.IDE_ROOT.getName()); String userPath = helper.getUserEnvironmentValue(IdeVariables.PATH.getName()); if (userPath == null) { - this.context.error("Could not read user PATH from registry!"); + LOG.error("Could not read user PATH from registry!"); } else { - this.context.info("Found user PATH={}", userPath); + LOG.info("Found user PATH={}", userPath); String newUserPath = userPath; if (!userPath.isEmpty()) { SimpleSystemPath path = SimpleSystemPath.of(userPath, ';'); @@ -636,7 +644,7 @@ private void uninstallIdeasyWindowsEnv(Path ideRoot) { newUserPath = path.toString(); } if (newUserPath.equals(userPath)) { - this.context.error("Could not find IDEasy in PATH:\n{}", userPath); + LOG.error("Could not find IDEasy in PATH:\n{}", userPath); } else { helper.setUserEnvironmentValue(IdeVariables.PATH.getName(), newUserPath); } diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/LocalToolCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/tool/LocalToolCommandlet.java index ea0c55c9fa..70e519dc47 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/LocalToolCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/LocalToolCommandlet.java @@ -6,10 +6,14 @@ import java.util.Collection; import java.util.Set; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.cli.CliOfflineException; import com.devonfw.tools.ide.common.Tag; import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.io.FileAccess; +import com.devonfw.tools.ide.log.IdeLogLevel; import com.devonfw.tools.ide.process.ProcessContext; import com.devonfw.tools.ide.step.Step; import com.devonfw.tools.ide.tool.repository.ToolRepository; @@ -23,6 +27,8 @@ */ public abstract class LocalToolCommandlet extends ToolCommandlet { + private static final Logger LOG = LoggerFactory.getLogger(LocalToolCommandlet.class); + /** * The constructor. * @@ -102,7 +108,7 @@ private ToolInstallation doInstallStep(ToolInstallRequest request) { if (request.isAlreadyInstalled()) { return installation; } else { - this.context.debug("Installation from {} to {}.", request.getInstalled(), request.getRequested()); + LOG.debug("Installation from {} to {}.", request.getInstalled(), request.getRequested()); } FileAccess fileAccess = this.context.getFileAccess(); boolean ignoreSoftwareRepo = isIgnoreSoftwareRepo(); @@ -128,10 +134,13 @@ private ToolInstallation doInstallStep(ToolInstallRequest request) { ToolEdition toolEdition = requested.getEdition(); Step step = request.getStep(); if (installedVersion == null) { - asSuccess(step).log("Successfully installed {} in version {} at {}", toolEdition, resolvedVersion, toolPath); + IdeLogLevel.SUCCESS.log(LOG, "Successfully installed {} in version {} at {}", toolEdition, resolvedVersion, toolPath); } else { - asSuccess(step).log("Successfully installed {} in version {} replacing previous version {} of {} at {}", toolEdition, resolvedVersion, - installedVersion, installed.getEdition(), toolPath); + IdeLogLevel.SUCCESS.log(LOG, "Successfully installed {} in version {} replacing previous version {} of {} at {}", toolEdition, + resolvedVersion, installedVersion, installed.getEdition(), toolPath); + } + if (step != null) { + step.success(true); } return installation; } @@ -157,7 +166,7 @@ protected boolean isIgnoreSoftwareRepo() { public ToolInstallation installTool(ToolInstallRequest request) { completeRequest(request); // most likely already done, but if installTool was called directly and not from install - if (request.isInstallLoop(this.context)) { + if (request.isInstallLoop()) { return toolAlreadyInstalled(request); } ToolEditionAndVersion requested = request.getRequested(); @@ -172,7 +181,7 @@ public ToolInstallation installTool(ToolInstallRequest request) { return toolAlreadyInstalled(request); } else { ToolEditionAndVersion installed = request.getInstalled(); - this.context.debug("Installation from {} to {}.", installed, requested); + LOG.debug("Installation from {} to {}.", installed, requested); } Path installationPath = getInstallationPath(edition, resolvedVersion); @@ -186,16 +195,16 @@ public ToolInstallation installTool(ToolInstallRequest request) { if (!ignoreSoftwareRepo) { assert resolvedVersion.equals(getInstalledVersion(installationPath)) : "Found version " + getInstalledVersion(installationPath) + " in " + toolVersionFile + " but expected " + resolvedVersion; - this.context.debug("Version {} of tool {} is already installed at {}", resolvedVersion, toolEdition, installationPath); + LOG.debug("Version {} of tool {} is already installed at {}", resolvedVersion, toolEdition, installationPath); return createToolInstallation(installationPath, resolvedVersion, false, processContext, additionalInstallation); } } else { // Makes sure that IDEasy will not delete itself if (this.tool.equals(IdeasyCommandlet.TOOL_NAME)) { - this.context.warning("Your IDEasy installation is missing the version file at {}", toolVersionFile); + LOG.warn("Your IDEasy installation is missing the version file at {}", toolVersionFile); return createToolInstallation(installationPath, resolvedVersion, false, processContext, additionalInstallation); } else if (!isIgnoreMissingSoftwareVersionFile()) { - this.context.warning("Deleting corrupted installation at {}", installationPath); + LOG.warn("Deleting corrupted installation at {}", installationPath); fileAccess.delete(installationPath); } } @@ -207,7 +216,8 @@ public ToolInstallation installTool(ToolInstallRequest request) { // If we are offline and cannot download, check if we can continue with an existing installation ToolEditionAndVersion installed = request.getInstalled(); if ((installed != null) && (installed.getResolvedVersion() != null)) { - this.context.warning("Cannot download {} in version {} because we are offline. Continuing with already installed version {}.", this.tool, resolvedVersion, installed.getResolvedVersion()); + LOG.warn("Cannot download {} in version {} because we are offline. Continuing with already installed version {}.", this.tool, + resolvedVersion, installed.getResolvedVersion()); // If offline and could not download, actualInstalledVersion will be the old version, not resolvedVersion // In that case, we need to recalculate the installation path for the actually installed version actualInstalledVersion = installed.getResolvedVersion(); @@ -238,11 +248,11 @@ protected void performToolInstallation(ToolInstallRequest request, Path installa Path downloadedToolFile = downloadTool(requested.getEdition().edition(), resolvedVersion); boolean extract = isExtract(); if (!extract) { - this.context.trace("Extraction is disabled for '{}' hence just moving the downloaded file {}.", this.tool, downloadedToolFile); + LOG.trace("Extraction is disabled for '{}' hence just moving the downloaded file {}.", this.tool, downloadedToolFile); } if (Files.isDirectory(installationPath)) { if (this.tool.equals(IdeasyCommandlet.TOOL_NAME)) { - this.context.warning("Your IDEasy installation is missing the version file."); + LOG.warn("Your IDEasy installation is missing the version file."); } else { fileAccess.backup(installationPath); } @@ -250,7 +260,7 @@ protected void performToolInstallation(ToolInstallRequest request, Path installa fileAccess.mkdirs(installationPath.getParent()); fileAccess.extract(downloadedToolFile, installationPath, this::postExtract, extract); this.context.writeVersionFile(resolvedVersion, installationPath); - this.context.debug("Installed {} in version {} at {}", this.tool, resolvedVersion, installationPath); + LOG.debug("Installed {} in version {} at {}", this.tool, resolvedVersion, installationPath); } /** @@ -287,7 +297,7 @@ public ToolInstallation installAsDependency(VersionRange versionRange, ToolInsta + configuredVersion + " and this tool does not support the software repository."); } - this.context.info( + 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); @@ -308,9 +318,9 @@ protected void installToolDependencies(ToolInstallRequest request) { ToolEdition toolEdition = requested.getEdition(); Collection dependencies = getToolRepository().findDependencies(this.tool, toolEdition.edition(), version); int size = dependencies.size(); - this.context.debug("Tool {} has {} other tool(s) as dependency", toolEdition, size); + LOG.debug("Tool {} has {} other tool(s) as dependency", toolEdition, size); for (ToolDependency dependency : dependencies) { - this.context.trace("Ensuring dependency {} for tool {}", dependency.tool(), toolEdition); + LOG.trace("Ensuring dependency {} for tool {}", dependency.tool(), toolEdition); LocalToolCommandlet dependencyTool = this.context.getCommandletManager().getRequiredLocalToolCommandlet(dependency.tool()); dependencyTool.installAsDependency(dependency.versionRange(), request); } @@ -346,7 +356,7 @@ protected VersionIdentifier getInstalledVersion(Path toolPath) { if (Files.exists(legacyToolVersionFile)) { toolVersionFile = legacyToolVersionFile; } else { - this.context.warning("Tool {} is missing version file in {}", getName(), toolVersionFile); + LOG.warn("Tool {} is missing version file in {}", getName(), toolVersionFile); return null; } } @@ -373,7 +383,7 @@ protected String getInstalledEdition(Path toolPath) { // if the realPath changed, a link has been resolved if (realPath.equals(toolPath)) { if (!isIgnoreSoftwareRepo()) { - this.context.warning("Tool {} is not installed via software repository (maybe from devonfw-ide). Please consider reinstalling it.", this.tool); + LOG.warn("Tool {} is not installed via software repository (maybe from devonfw-ide). Please consider reinstalling it.", this.tool); } // I do not see any reliable way how we could determine the edition of a tool that does not use software repo or that was installed by devonfw-ide return getConfiguredEdition(); @@ -384,7 +394,7 @@ protected String getInstalledEdition(Path toolPath) { edition = this.tool; } if (!getToolRepository().getSortedEditions(this.tool).contains(edition)) { - this.context.warning("Undefined edition {} of tool {}", edition, this.tool); + LOG.warn("Undefined edition {} of tool {}", edition, this.tool); } return edition; } @@ -413,7 +423,7 @@ private Path getInstalledSoftwareRepoPath(Path toolPath) { // if the installPath changed, a link has been resolved if (installPath.equals(toolPath)) { if (!isIgnoreSoftwareRepo()) { - this.context.warning("Tool {} is not installed via software repository (maybe from devonfw-ide). Please consider reinstalling it.", this.tool); + LOG.warn("Tool {} is not installed via software repository (maybe from devonfw-ide). Please consider reinstalling it.", this.tool); } // I do not see any reliable way how we could determine the edition of a tool that does not use software repo or that was installed by devonfw-ide return null; @@ -429,13 +439,13 @@ Path getValidInstalledSoftwareRepoPath(Path installPath, Path softwareRepoPath) // installPath can't be shorter than softwareRepoPath if (toolInstallNameCount < softwareRepoNameCount) { - this.context.warning("The installation path is not located within the software repository {}.", installPath); + LOG.warn("The installation path is not located within the software repository {}.", installPath); return null; } // ensure installPath starts with $IDE_ROOT/_ide/software/ for (int i = 0; i < softwareRepoNameCount; i++) { if (!softwareRepoPath.getName(i).toString().equals(installPath.getName(i).toString())) { - this.context.warning("The installation path is not located within the software repository {}.", installPath); + LOG.warn("The installation path is not located within the software repository {}.", installPath); return null; } } @@ -449,7 +459,7 @@ Path getValidInstalledSoftwareRepoPath(Path installPath, Path softwareRepoPath) } return validInstallPath; } else { - this.context.warning("The installation path is faulty {}.", installPath); + LOG.warn("The installation path is faulty {}.", installPath); return null; } } @@ -457,7 +467,7 @@ Path getValidInstalledSoftwareRepoPath(Path installPath, Path softwareRepoPath) private boolean isToolNotInstalled(Path toolPath) { if ((toolPath == null) || !Files.isDirectory(toolPath)) { - this.context.debug("Tool {} not installed in {}", this.tool, toolPath); + LOG.debug("Tool {} not installed in {}", this.tool, toolPath); return true; } return false; @@ -468,11 +478,11 @@ public void uninstall() { try { Path toolPath = getToolPath(); if (!Files.exists(toolPath)) { - this.context.warning("An installed version of {} does not exist.", this.tool); + LOG.warn("An installed version of {} does not exist.", this.tool); return; } if (this.context.isForceMode() && !isIgnoreSoftwareRepo()) { - this.context.warning( + LOG.warn( "You triggered an uninstall of {} in version {} with force mode!\n" + "This will physically delete the currently installed version from the machine.\n" + "This may cause issues with other projects, that use the same version of that tool." @@ -480,9 +490,9 @@ public void uninstall() { uninstallFromSoftwareRepository(toolPath); } performUninstall(toolPath); - this.context.success("Successfully uninstalled {}", this.tool); + IdeLogLevel.SUCCESS.log(LOG, "Successfully uninstalled {}", this.tool); } catch (Exception e) { - this.context.error(e, "Failed to uninstall {}", this.tool); + LOG.error("Failed to uninstall {}", this.tool, e); } } @@ -501,12 +511,12 @@ protected void performUninstall(Path toolPath) { private void uninstallFromSoftwareRepository(Path toolPath) { Path repoPath = getInstalledSoftwareRepoPath(toolPath); if ((repoPath == null) || !Files.exists(repoPath)) { - this.context.warning("An installed version of {} does not exist in software repository.", this.tool); + LOG.warn("An installed version of {} does not exist in software repository.", this.tool); return; } - this.context.info("Physically deleting {} as requested by the user via force mode.", repoPath); + LOG.info("Physically deleting {} as requested by the user via force mode.", repoPath); this.context.getFileAccess().delete(repoPath); - this.context.success("Successfully deleted {} from your computer.", repoPath); + IdeLogLevel.SUCCESS.log(LOG, "Successfully deleted {} from your computer.", repoPath); } @Override @@ -546,7 +556,7 @@ protected Path findWrapper(String wrapperFileName) { while ((dir != null) && (findBuildDescriptor(dir) != null)) { Path wrapper = dir.resolve(wrapperFileName); if (Files.exists(wrapper)) { - context.debug("Using wrapper: {}", wrapper); + LOG.debug("Using wrapper: {}", wrapper); return wrapper; } dir = dir.getParent(); diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/PackageManagerBasedLocalToolCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/tool/PackageManagerBasedLocalToolCommandlet.java index 0e8c879786..10769d760e 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/PackageManagerBasedLocalToolCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/PackageManagerBasedLocalToolCommandlet.java @@ -4,6 +4,9 @@ import java.util.List; import java.util.Set; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.cache.CachedValue; import com.devonfw.tools.ide.common.Tag; import com.devonfw.tools.ide.context.IdeContext; @@ -20,6 +23,8 @@ */ public abstract class PackageManagerBasedLocalToolCommandlet

extends LocalToolCommandlet { + private static final Logger LOG = LoggerFactory.getLogger(PackageManagerBasedLocalToolCommandlet.class); + private final CachedValue installedVersion; /** @@ -156,7 +161,7 @@ private VersionIdentifier determineInstalledVersion() { try { return computeInstalledVersion(); } catch (Exception e) { - this.context.debug().log(e, "Failed to compute installed version of {}", this.tool); + LOG.debug("Failed to compute installed version of {}", this.tool, e); return null; } } @@ -198,7 +203,7 @@ protected final void performUninstall(Path toolPath) { runPackageManager(request).failOnError(); this.installedVersion.invalidate(); } else { - this.context.info("IDEasy does not support uninstalling the tool {} since this will break your installation.\n" + LOG.info("IDEasy does not support uninstalling the tool {} since this will break your installation.\n" + "If you really want to uninstall it, please uninstall its parent tool via:\n" + "ide uninstall {}", this.tool, getParentTool().getName()); } diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java index 7c7bd1b753..60a1668feb 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java @@ -10,6 +10,10 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.event.Level; + import com.devonfw.tools.ide.commandlet.Commandlet; import com.devonfw.tools.ide.common.Tag; import com.devonfw.tools.ide.common.Tags; @@ -17,7 +21,7 @@ import com.devonfw.tools.ide.environment.EnvironmentVariables; import com.devonfw.tools.ide.environment.EnvironmentVariablesFiles; import com.devonfw.tools.ide.io.FileCopyMode; -import com.devonfw.tools.ide.log.IdeSubLogger; +import com.devonfw.tools.ide.log.IdeLogLevel; import com.devonfw.tools.ide.nls.NlsBundle; import com.devonfw.tools.ide.os.MacOsHelper; import com.devonfw.tools.ide.process.EnvironmentContext; @@ -42,6 +46,8 @@ */ public abstract class ToolCommandlet extends Commandlet implements Tags { + private static final Logger LOG = LoggerFactory.getLogger(ToolCommandlet.class); + /** @see #getName() */ protected final String tool; @@ -156,7 +162,7 @@ protected final ToolEdition getToolWithConfiguredEdition() { } @Override - public void run() { + protected void doRun() { runTool(this.arguments.asList()); } @@ -220,7 +226,7 @@ public ProcessResult runTool(ToolInstallRequest request, ProcessMode processMode // if the CVE check has already been done, we can assume that the install(request) has already been called before // most likely a postInstall* method was overridden calling this method with the same request what is a programming error // we render this warning so the error gets detected and can be fixed but we do not block the user by skipping the installation. - this.context.warning().log(new RuntimeException(), "Preventing infinity loop during installation of {}", request.getRequested()); + LOG.warn("Preventing infinity loop during installation of {}", request.getRequested(), new RuntimeException()); } else { install(request); } @@ -291,7 +297,7 @@ public ToolInstallation install(boolean silent) { public ToolInstallation install(ToolInstallRequest request) { completeRequest(request); - if (request.isInstallLoop(this.context)) { + if (request.isInstallLoop()) { return toolAlreadyInstalled(request); } return doInstall(request); @@ -547,14 +553,14 @@ protected ToolInstallation toolAlreadyInstalled(ToolInstallRequest request) { * @param request the {@link ToolInstallRequest}. */ protected void logToolAlreadyInstalled(ToolInstallRequest request) { - IdeSubLogger logger; + Level level; if (request.isSilent()) { - logger = this.context.debug(); + level = Level.DEBUG; } else { - logger = this.context.info(); + level = Level.INFO; } ToolEditionAndVersion installed = request.getInstalled(); - logger.log("Version {} of tool {} is already installed", installed.getVersion(), installed.getEdition()); + LOG.atLevel(level).log("Version {} of tool {} is already installed", installed.getVersion(), installed.getEdition()); } /** @@ -619,10 +625,10 @@ protected VersionIdentifier cveCheck(ToolInstallRequest request) { } ToolSecurity toolSecurity = this.context.getDefaultToolRepository().findSecurity(this.tool, toolEdition.edition()); double minSeverity = IdeVariables.CVE_MIN_SEVERITY.get(context); - ToolVulnerabilities currentVulnerabilities = toolSecurity.findCves(resolvedVersion, this.context, minSeverity); + ToolVulnerabilities currentVulnerabilities = toolSecurity.findCves(resolvedVersion, minSeverity); ToolVersionChoice currentChoice = ToolVersionChoice.ofCurrent(requested, currentVulnerabilities); request.setCveCheckDone(); - if (currentChoice.logAndCheckIfEmpty(this.context)) { + if (currentChoice.logAndCheckIfEmpty()) { return resolvedVersion; } boolean alreadyInstalled = request.isAlreadyInstalled(); @@ -631,7 +637,7 @@ protected VersionIdentifier cveCheck(ToolInstallRequest request) { // currently for a transitive dependency it does not make sense to suggest alternative versions, since the choice is not stored anywhere, // and we then would ask the user again every time the tool having this dependency is started. So we only log the problem and the user needs to react // (e.g. upgrade the tool with the dependency that is causing this). - this.context.interaction("Please run 'ide -f install {}' to check for update suggestions!", this.tool); + IdeLogLevel.INTERACTION.log(LOG, "Please run 'ide -f install {}' to check for update suggestions!", this.tool); return resolvedVersion; } ToolVersionChoice latest = null; @@ -646,7 +652,7 @@ protected VersionIdentifier cveCheck(ToolInstallRequest request) { } if (acceptVersion(version, allowedVersions, requireStableVersion)) { - ToolVulnerabilities newVulnerabilities = toolSecurity.findCves(version, this.context, minSeverity); + ToolVulnerabilities newVulnerabilities = toolSecurity.findCves(version, minSeverity); if (newVulnerabilities.isSafer(latestVulnerabilities)) { // we found a better/safer version ToolEditionAndVersion toolEditionAndVersion = new ToolEditionAndVersion(toolEdition, version); @@ -667,7 +673,7 @@ protected VersionIdentifier cveCheck(ToolInstallRequest request) { } } if ((latest == null) && (nearest == null)) { - this.context.warning( + LOG.warn( "Could not find any other version resolving your CVEs.\nPlease keep attention to this tool and consider updating as soon as security fixes are available."); if (alreadyInstalled) { // we came here via "ide -f install ..." but no alternative is available @@ -687,17 +693,16 @@ protected VersionIdentifier cveCheck(ToolInstallRequest request) { if (addSuggestions) { choices.add(nearest); } - nearest.logAndCheckIfEmpty(this.context); + nearest.logAndCheckIfEmpty(); } if (latest != null) { if (addSuggestions) { choices.add(latest); } - latest.logAndCheckIfEmpty(this.context); + latest.logAndCheckIfEmpty(); } ToolVersionChoice[] choicesArray = choices.toArray(ToolVersionChoice[]::new); - this.context.warning( - "Please note that by selecting an unsafe version to install, you accept the risk to be attacked."); + LOG.warn("Please note that by selecting an unsafe version to install, you accept the risk to be attacked."); ToolVersionChoice answer = this.context.question(choicesArray, "Which version do you want to install?"); VersionIdentifier version = answer.toolEditionAndVersion().getResolvedVersion(); requested.setResolvedVersion(version); @@ -762,7 +767,7 @@ public void listEditions() { List editions = getToolRepository().getSortedEditions(getName()); for (String edition : editions) { - this.context.info(edition); + LOG.info(edition); } } @@ -773,7 +778,7 @@ public void listVersions() { List versions = getToolRepository().getSortedVersions(getName(), getConfiguredEdition(), this); for (VersionIdentifier vi : versions) { - this.context.info(vi.toString()); + LOG.info(vi.toString()); } } @@ -797,7 +802,7 @@ public void setVersion(String version) { } VersionIdentifier configuredVersion = VersionIdentifier.of(version); if (!configuredVersion.isPattern() && !configuredVersion.isValid()) { - this.context.warning("Version {} seems to be invalid", version); + LOG.warn("Version {} seems to be invalid", version); } setVersion(configuredVersion, true); } @@ -838,12 +843,12 @@ public void setVersion(VersionIdentifier version, boolean hint, EnvironmentVaria settingsVariables.save(); EnvironmentVariables declaringVariables = variables.findVariable(name); if ((declaringVariables != null) && (declaringVariables != settingsVariables)) { - this.context.warning("The variable {} is overridden in {}. Please remove the overridden declaration in order to make the change affect.", name, + LOG.warn("The variable {} is overridden in {}. Please remove the overridden declaration in order to make the change affect.", name, declaringVariables.getSource()); } if (hint) { - this.context.info("To install that version call the following command:"); - this.context.info("ide install {}", this.tool); + LOG.info("To install that version call the following command:"); + LOG.info("ide install {}", this.tool); } } @@ -887,7 +892,7 @@ public void setEdition(String edition, boolean hint, EnvironmentVariablesFiles d } if (!getToolRepository().getSortedEditions(this.tool).contains(edition)) { - this.context.warning("Edition {} seems to be invalid", edition); + LOG.warn("Edition {} seems to be invalid", edition); } EnvironmentVariables variables = this.context.getVariables(); EnvironmentVariables settingsVariables = variables.getByType(destination.toType()); @@ -895,15 +900,15 @@ public void setEdition(String edition, boolean hint, EnvironmentVariablesFiles d settingsVariables.set(name, edition, false); settingsVariables.save(); - this.context.info("{}={} has been set in {}", name, edition, settingsVariables.getSource()); + LOG.info("{}={} has been set in {}", name, edition, settingsVariables.getSource()); EnvironmentVariables declaringVariables = variables.findVariable(name); if ((declaringVariables != null) && (declaringVariables != settingsVariables)) { - this.context.warning("The variable {} is overridden in {}. Please remove the overridden declaration in order to make the change affect.", name, + LOG.warn("The variable {} is overridden in {}. Please remove the overridden declaration in order to make the change affect.", name, declaringVariables.getSource()); } if (hint) { - this.context.info("To install that edition call the following command:"); - this.context.info("ide install {}", this.tool); + LOG.info("To install that edition call the following command:"); + LOG.info("ide install {}", this.tool); } } @@ -1008,29 +1013,16 @@ protected VersionIdentifier resolveVersionWithPattern(String output, Pattern pat } /** - * @param step the {@link Step} to get {@link Step#asSuccess() success logger} from. May be {@code null}. - * @return the {@link IdeSubLogger} from {@link Step#asSuccess()} or {@link IdeContext#success()} as fallback. + * @deprecated directly log success message and then report success on step if not null. */ - protected IdeSubLogger asSuccess(Step step) { + @Deprecated + protected void success(Step step, String message, Object... args) { if (step == null) { - return this.context.success(); + IdeLogLevel.SUCCESS.log(LOG, message, args); } else { - return step.asSuccess(); + step.success(message, args); } } - - /** - * @param step the {@link Step} to get {@link Step#asError() error logger} from. May be {@code null}. - * @return the {@link IdeSubLogger} from {@link Step#asError()} or {@link IdeContext#error()} as fallback. - */ - protected IdeSubLogger asError(Step step) { - - if (step == null) { - return this.context.error(); - } else { - return step.asError(); - } - } } diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/ToolInstallRequest.java b/cli/src/main/java/com/devonfw/tools/ide/tool/ToolInstallRequest.java index ba958820c0..083d6b47f7 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/ToolInstallRequest.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/ToolInstallRequest.java @@ -2,7 +2,9 @@ import java.nio.file.Path; -import com.devonfw.tools.ide.log.IdeLogger; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.process.ProcessContext; import com.devonfw.tools.ide.step.Step; import com.devonfw.tools.ide.version.GenericVersionRange; @@ -14,6 +16,8 @@ */ public final class ToolInstallRequest { + private static final Logger LOG = LoggerFactory.getLogger(ToolInstallRequest.class); + private final ToolInstallRequest parent; private final boolean silent; @@ -69,10 +73,9 @@ private ToolInstallRequest(ToolInstallRequest parent, boolean silent, boolean di } /** - * @param logger the {@link IdeLogger} used to log an installation loop if found. * @return {@code true} if an installation loop was found and logged, {@code false} otherwise. */ - public boolean isInstallLoop(IdeLogger logger) { + public boolean isInstallLoop() { if ((this.requested == null) || (this.requested.getEdition() == null)) { throw new IllegalStateException(); // this method was called too early @@ -80,7 +83,7 @@ public boolean isInstallLoop(IdeLogger logger) { StringBuilder sb = new StringBuilder(); boolean loopFound = detectInstallLoopRecursively(this.requested, sb); if (loopFound) { - logger.warning("Found installation loop:\n" + LOG.warn("Found installation loop:\n" + "{}\n" + "This typically indicates an internal bug in IDEasy.\n" + "Please report this bug, when you see this and include this entire warning message.\n" diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/aws/Aws.java b/cli/src/main/java/com/devonfw/tools/ide/tool/aws/Aws.java index 13043a6261..8dc31d374d 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/aws/Aws.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/aws/Aws.java @@ -4,6 +4,9 @@ import java.nio.file.Path; import java.util.Set; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.common.Tag; import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.io.FileAccess; @@ -19,6 +22,8 @@ */ public class Aws extends LocalToolCommandlet { + private static final Logger LOG = LoggerFactory.getLogger(Aws.class); + /** * The constructor. * @@ -69,7 +74,7 @@ protected void postExtract(Path extractedDir) { @Override public void printHelp(NlsBundle bundle) { - this.context.info("To get detailed help about the usage of the AWS CLI, use \"aws help\""); + LOG.info("To get detailed help about the usage of the AWS CLI, use \"aws help\""); } @Override diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/custom/CustomToolsMapper.java b/cli/src/main/java/com/devonfw/tools/ide/tool/custom/CustomToolsMapper.java index 605847de9d..e29d5f3e86 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/custom/CustomToolsMapper.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/custom/CustomToolsMapper.java @@ -3,6 +3,9 @@ import java.util.ArrayList; import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.environment.VariableLine; import com.devonfw.tools.ide.json.JsonMapping; @@ -17,6 +20,8 @@ */ public class CustomToolsMapper extends StandardJsonObjectMapper { + private static final Logger LOG = LoggerFactory.getLogger(CustomToolsMapper.class); + private static final CustomToolsMapper INSTANCE = new CustomToolsMapper(); private final ObjectMapper MAPPER = JsonMapping.create(); @@ -101,10 +106,9 @@ private static CustomToolMetadata convert(CustomTool customTool, String reposito * Retrieves custom tools from a devonfw-ide legacy config. * * @param customToolsContent String of custom tools - * @param context the {@link IdeContext}. * @return {@link CustomTools}. */ - public static CustomTools parseCustomToolsFromLegacyConfig(String customToolsContent, IdeContext context) { + public static CustomTools parseCustomToolsFromLegacyConfig(String customToolsContent) { List customToolEntries = VariableLine.parseArray(customToolsContent); if (customToolEntries.isEmpty()) { return null; @@ -114,12 +118,12 @@ public static CustomTools parseCustomToolsFromLegacyConfig(String customToolsCon for (String customToolConfig : customToolEntries) { CustomTool customTool = parseCustomToolFromLegacyConfig(customToolConfig); if (customTool == null) { - context.warning("Invalid custom tool entry: {}", customToolConfig); + LOG.warn("Invalid custom tool entry: {}", customToolConfig); } else { String url = customTool.url(); if (defaultUrl == null) { if ((url == null) || url.isEmpty()) { - context.warning("First custom tool entry has no URL specified: {}", customToolConfig); + LOG.warn("First custom tool entry has no URL specified: {}", customToolConfig); } else { defaultUrl = url; customTool = customTool.withoutUrl(); diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/docker/Docker.java b/cli/src/main/java/com/devonfw/tools/ide/tool/docker/Docker.java index 84c2de715d..01b3881c82 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/docker/Docker.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/docker/Docker.java @@ -1,16 +1,17 @@ package com.devonfw.tools.ide.tool.docker; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.Set; import java.util.regex.Pattern; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.common.Tag; import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.os.SystemArchitecture; import com.devonfw.tools.ide.os.WindowsHelper; -import com.devonfw.tools.ide.os.WindowsHelperImpl; import com.devonfw.tools.ide.tool.GlobalToolCommandlet; import com.devonfw.tools.ide.tool.NativePackageManager; import com.devonfw.tools.ide.tool.PackageManagerCommand; @@ -24,11 +25,12 @@ */ public class Docker extends GlobalToolCommandlet { - private static final String PODMAN = "podman"; + private static final Logger LOG = LoggerFactory.getLogger(Docker.class); + private static final String PODMAN = "podman"; private static final Pattern RDCTL_CLIENT_VERSION_PATTERN = Pattern.compile("client version:\\s*v([\\d.]+)", Pattern.CASE_INSENSITIVE); - + private static final Pattern DOCKER_DESKTOP_LINUX_VERSION_PATTERN = Pattern.compile("^([0-9]+(?:\\.[0-9]+){1,2})"); /** @@ -98,7 +100,7 @@ protected List getInstallPackageManagerCommands() { public VersionIdentifier getInstalledVersion() { if (!isDockerInstalled()) { - this.context.error("Couldn't get installed version of " + this.getName()); + LOG.error("Couldn't get installed version of " + this.getName()); return null; } @@ -112,7 +114,7 @@ public VersionIdentifier getInstalledVersion() { }; if (parsedVersion == null) { - this.context.error("Couldn't get installed version of " + this.getName()); + LOG.error("Couldn't get installed version of " + this.getName()); } return parsedVersion; @@ -146,7 +148,7 @@ private VersionIdentifier getRancherDesktopClientVersion() { public String getInstalledEdition() { if (!isDockerInstalled()) { - this.context.error("Couldn't get installed edition of " + this.getName()); + LOG.error("Couldn't get installed edition of {}", this.getName()); return null; } @@ -172,9 +174,9 @@ private List getPackageManagerCommandsUninstall() { List pmCommands = new ArrayList<>(); pmCommands.add( - new PackageManagerCommand(NativePackageManager.ZYPPER, Arrays.asList("sudo zypper remove rancher-desktop"))); + new PackageManagerCommand(NativePackageManager.ZYPPER, List.of("sudo zypper remove rancher-desktop"))); pmCommands.add( - new PackageManagerCommand(NativePackageManager.APT, Arrays.asList("sudo apt -y autoremove rancher-desktop"))); + new PackageManagerCommand(NativePackageManager.APT, List.of("sudo apt -y autoremove rancher-desktop"))); return pmCommands; } diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/eclipse/Eclipse.java b/cli/src/main/java/com/devonfw/tools/ide/tool/eclipse/Eclipse.java index 62e2358e36..eef00ea911 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/eclipse/Eclipse.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/eclipse/Eclipse.java @@ -8,6 +8,9 @@ import java.util.List; import java.util.Set; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.cli.CliException; import com.devonfw.tools.ide.common.Tag; import com.devonfw.tools.ide.context.IdeContext; @@ -27,6 +30,8 @@ */ public class Eclipse extends IdeToolCommandlet { + private static final Logger LOG = LoggerFactory.getLogger(Eclipse.class); + // version must correspond to eclipse-import.xml private static final String GROOVY_VERSION = "3.0.23"; @@ -93,13 +98,13 @@ public boolean installPlugin(ToolPluginDescriptor plugin, Step step, ProcessCont if (result.isSuccessful()) { for (String line : result.getOut()) { if (line.contains("Overall install request is satisfiable")) { - this.context.success("Successfully installed plugin: {}", plugin.name()); + IdeLogLevel.SUCCESS.log(LOG, "Successfully installed plugin: {}", plugin.name()); step.success(); return true; } } } - result.log(IdeLogLevel.DEBUG, context, IdeLogLevel.ERROR); + result.log(IdeLogLevel.DEBUG, IdeLogLevel.ERROR); step.error("Failed to install plugin {} ({}): exit code was {}", plugin.name(), plugin.id(), result.getExitCode()); return false; } @@ -121,8 +126,8 @@ protected void configureWorkspace() { private static boolean isLocked(Path lockfile) { if (Files.isRegularFile(lockfile)) { - try (RandomAccessFile raFile = new RandomAccessFile(lockfile.toFile(), "rw")) { - FileLock fileLock = raFile.getChannel().tryLock(0, 1, false); + try (RandomAccessFile raFile = new RandomAccessFile(lockfile.toFile(), "rw"); + FileLock fileLock = raFile.getChannel().tryLock(0, 1, false)) { // success, file was not locked so we immediately unlock again... fileLock.release(); return false; diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/gcviewer/GcViewer.java b/cli/src/main/java/com/devonfw/tools/ide/tool/gcviewer/GcViewer.java index 6c55833153..6934ec2015 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/gcviewer/GcViewer.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/gcviewer/GcViewer.java @@ -32,7 +32,7 @@ protected boolean isExtract() { } @Override - public void run() { + protected void doRun() { getCommandlet(Java.class).install(); install(true); diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/ide/IdeToolCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/tool/ide/IdeToolCommandlet.java index 4c9c78ae2e..6f0256c581 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/ide/IdeToolCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/ide/IdeToolCommandlet.java @@ -5,6 +5,9 @@ import java.util.List; import java.util.Set; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.common.Tag; import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.io.FileAccess; @@ -24,6 +27,8 @@ */ public abstract class IdeToolCommandlet extends PluginBasedCommandlet { + private static final Logger LOG = LoggerFactory.getLogger(IdeToolCommandlet.class); + /** * The constructor. * @@ -48,8 +53,8 @@ private boolean hasIde(Set tags) { } @Override - public final void run() { - super.run(); + protected final void doRun() { + super.doRun(); } @Override @@ -73,7 +78,7 @@ protected void configureWorkspace() { FileAccess fileAccess = this.context.getFileAccess(); Path workspaceFolder = this.context.getWorkspacePath(); if (!fileAccess.isExpectedFolder(workspaceFolder)) { - this.context.warning("Current workspace does not exist: {}", workspaceFolder); + LOG.warn("Current workspace does not exist: {}", workspaceFolder); return; // should actually never happen... } Step step = this.context.newStep("Configuring workspace " + workspaceFolder.getFileName() + " for IDE " + this.tool); @@ -110,10 +115,10 @@ private int mergeWorkspaceSingle(Path templatesFolder, Path workspaceFolder, int Path setupFolder = templatesFolder.resolve(IdeContext.FOLDER_SETUP); Path updateFolder = templatesFolder.resolve(IdeContext.FOLDER_UPDATE); if (!Files.isDirectory(setupFolder) && !Files.isDirectory(updateFolder)) { - this.context.trace("Skipping empty or non-existing workspace template folder {}.", templatesFolder); + LOG.trace("Skipping empty or non-existing workspace template folder {}.", templatesFolder); return errors; } - this.context.debug("Merging workspace templates from {}...", templatesFolder); + LOG.debug("Merging workspace templates from {}...", templatesFolder); return errors + this.context.getWorkspaceMerger().merge(setupFolder, updateFolder, this.context.getVariables(), workspaceFolder); } diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/ide/IdeaBasedIdeToolCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/tool/ide/IdeaBasedIdeToolCommandlet.java index 3064204d33..837da202fd 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/ide/IdeaBasedIdeToolCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/ide/IdeaBasedIdeToolCommandlet.java @@ -4,8 +4,12 @@ import java.util.List; import java.util.Set; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.common.Tag; import com.devonfw.tools.ide.context.IdeContext; +import com.devonfw.tools.ide.log.IdeLogLevel; import com.devonfw.tools.ide.process.ProcessContext; import com.devonfw.tools.ide.process.ProcessMode; import com.devonfw.tools.ide.process.ProcessResult; @@ -18,6 +22,8 @@ */ public class IdeaBasedIdeToolCommandlet extends IdeToolCommandlet { + private static final Logger LOG = LoggerFactory.getLogger(IdeaBasedIdeToolCommandlet.class); + /** * The constructor. * @@ -42,7 +48,7 @@ public boolean installPlugin(ToolPluginDescriptor plugin, final Step step, Proce } ProcessResult result = runTool(pc, ProcessMode.DEFAULT, args); if (result.isSuccessful()) { - this.context.success("Successfully installed plugin: {}", plugin.name()); + IdeLogLevel.SUCCESS.log(LOG, "Successfully installed plugin: {}", plugin.name()); step.success(); return true; } else { diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/ide/IdeaPluginDownloader.java b/cli/src/main/java/com/devonfw/tools/ide/tool/ide/IdeaPluginDownloader.java index e7ef401085..216c6a26b0 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/ide/IdeaPluginDownloader.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/ide/IdeaPluginDownloader.java @@ -14,6 +14,9 @@ import java.time.Duration; import java.util.Optional; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.io.FileAccess; import com.devonfw.tools.ide.os.MacOsHelper; @@ -26,6 +29,8 @@ */ public class IdeaPluginDownloader { + private static final Logger LOG = LoggerFactory.getLogger(IdeaPluginDownloader.class); + private static final String BUILD_FILE = "build.txt"; private final IdeContext context; private final IdeaBasedIdeToolCommandlet commandlet; @@ -130,7 +135,7 @@ private Path downloadPlugin(FileAccess fileAccess, String downloadUrl, Path tmpD private void extractDownloadedPlugin(FileAccess fileAccess, Path downloadedFile, String pluginId) throws IOException { Path targetDir = this.commandlet.getPluginsInstallationPath().resolve(pluginId); if (Files.exists(targetDir)) { - context.info("Plugin already installed, target directory already existing: {}", targetDir); + LOG.info("Plugin already installed, target directory already existing: {}", targetDir); } else { fileAccess.extract(downloadedFile, targetDir); } diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/intellij/Intellij.java b/cli/src/main/java/com/devonfw/tools/ide/tool/intellij/Intellij.java index 7943fd317f..ba089a640f 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/intellij/Intellij.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/intellij/Intellij.java @@ -6,6 +6,8 @@ import java.util.Map.Entry; import java.util.Set; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import com.devonfw.tools.ide.cli.CliException; @@ -30,6 +32,8 @@ */ public class Intellij extends IdeaBasedIdeToolCommandlet { + private static final Logger LOG = LoggerFactory.getLogger(Intellij.class); + private static final String IDEA = "idea"; private static final String IDEA64_EXE = IDEA + "64.exe"; @@ -118,12 +122,12 @@ public void importRepository(Path repositoryPath) { Path buildDescriptor = buildTool.findBuildDescriptor(repositoryPath); if (buildDescriptor != null) { String templateFilename = entry.getValue(); - this.context.debug("Found build descriptor {} so merging template {}", buildDescriptor, templateFilename); + LOG.debug("Found build descriptor {} so merging template {}", buildDescriptor, templateFilename); mergeConfig(repositoryPath, templateFilename); return; } } - this.context.warning("No supported build descriptor was found for project import in {}", repositoryPath); + LOG.warn("No supported build descriptor was found for project import in {}", repositoryPath); } } diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/jmc/Jmc.java b/cli/src/main/java/com/devonfw/tools/ide/tool/jmc/Jmc.java index 096cf9946b..f374f56285 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/jmc/Jmc.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/jmc/Jmc.java @@ -1,12 +1,5 @@ package com.devonfw.tools.ide.tool.jmc; -import com.devonfw.tools.ide.common.Tag; -import com.devonfw.tools.ide.context.IdeContext; -import com.devonfw.tools.ide.io.FileAccess; -import com.devonfw.tools.ide.process.ProcessMode; -import com.devonfw.tools.ide.tool.LocalToolCommandlet; -import com.devonfw.tools.ide.tool.ToolCommandlet; - import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -14,12 +7,24 @@ import java.util.Set; import java.util.stream.Stream; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.devonfw.tools.ide.common.Tag; +import com.devonfw.tools.ide.context.IdeContext; +import com.devonfw.tools.ide.io.FileAccess; +import com.devonfw.tools.ide.process.ProcessMode; +import com.devonfw.tools.ide.tool.LocalToolCommandlet; +import com.devonfw.tools.ide.tool.ToolCommandlet; + /** * {@link ToolCommandlet} for JDK Mission Control, An advanced set of tools for * managing, monitoring, profiling, and troubleshooting Java applications. */ public class Jmc extends LocalToolCommandlet { + private static final Logger LOG = LoggerFactory.getLogger(Jmc.class); + /** * The constructor. * @@ -31,7 +36,7 @@ public Jmc(IdeContext context) { } @Override - public void run() { + protected void doRun() { runTool(ProcessMode.BACKGROUND, null, this.arguments.asList()); } @@ -47,9 +52,7 @@ protected void postExtract(Path extractedDir) { moveFilesAndDirs(oldBinaryPath, extractedDir); fileAccess.delete(oldBinaryPath); } else { - this.context.debug( - "JMC binary folder not found at {} - ignoring as this legacy problem may be resolved in newer versions.", - oldBinaryPath); + LOG.debug("JMC binary folder not found at {} - ignoring as this legacy problem may be resolved in newer versions.", oldBinaryPath); } } } diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/lazydocker/LazyDocker.java b/cli/src/main/java/com/devonfw/tools/ide/tool/lazydocker/LazyDocker.java index b6a87ef072..4619a7bce9 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/lazydocker/LazyDocker.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/lazydocker/LazyDocker.java @@ -54,7 +54,7 @@ private void verifyDockerVersion(ProcessResult result, VersionIdentifier minimum // we have this pattern a lot that we want to get a single line output of a successful ProcessResult. // we should create a generic method in ProcessResult for this use-case. if (!result.isSuccessful()) { - result.log(IdeLogLevel.WARNING, this.context); + result.log(IdeLogLevel.WARNING); } if (result.getOut().isEmpty()) { throw new CliException("Docker is not installed, but required for lazydocker.\n" // diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/mvn/Mvn.java b/cli/src/main/java/com/devonfw/tools/ide/tool/mvn/Mvn.java index 03d940c37f..cf26227fa4 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/mvn/Mvn.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/mvn/Mvn.java @@ -10,6 +10,9 @@ import java.util.Set; import java.util.regex.Matcher; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.common.Tag; import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.git.GitContext; @@ -29,14 +32,12 @@ */ public class Mvn extends LocalToolCommandlet { - /** - * The name of the mvn folder - */ + private static final Logger LOG = LoggerFactory.getLogger(Mvn.class); + + /** The name of the mvn folder. */ public static final String MVN_CONFIG_FOLDER = "mvn"; - /** - * The name of the m2 repository - */ + /** The name of the m2 repository. */ public static final String MVN_CONFIG_LEGACY_FOLDER = ".m2"; /** The name of the settings-security.xml */ @@ -48,9 +49,7 @@ public class Mvn extends LocalToolCommandlet { /** The pom.xml file name. */ public static final String POM_XML = "pom.xml"; - /** - * The name of the settings.xml - */ + /** The name of the file settings.xml. */ public static final String SETTINGS_FILE = "settings.xml"; private static final String DOCUMENTATION_PAGE_CONF = "https://github.com/devonfw/IDEasy/blob/main/documentation/conf.adoc"; @@ -135,7 +134,7 @@ private void createSettingsFile(Path settingsFile, Path settingsTemplateFile, Pa return; } if (!Files.exists(settingsTemplateFile)) { - this.context.warning("Missing maven settings template at {}. ", settingsTemplateFile); + LOG.warn("Missing maven settings template at {}. ", settingsTemplateFile); return; } Step step = this.context.newStep("Create mvn settings file at " + settingsFile); @@ -150,7 +149,7 @@ private void doCreateSettingsFile(Path settingsFile, Path settingsTemplateFile, GitContext gitContext = this.context.getGitContext(); String gitSettingsUrl = gitContext.retrieveGitUrl(this.context.getSettingsPath()); if (gitSettingsUrl == null) { - this.context.warning("Failed to determine git remote URL for settings folder."); + LOG.warn("Failed to determine git remote URL for settings folder."); } else if (!gitSettingsUrl.equals(GitContext.DEFAULT_SETTINGS_GIT_URL) && Files.exists(settingsSecurityFile)) { Set variables = findVariables(content); for (String variable : variables) { @@ -168,9 +167,8 @@ private void doCreateSettingsFile(Path settingsFile, Path settingsTemplateFile, private String getEncryptedPassword(String variable) { String input = this.context.askForInput("Please enter secret value for variable " + variable + ":"); - String encryptedPassword = retrievePassword("--encrypt-password", input); - this.context.info("Encrypted as " + encryptedPassword); + LOG.info("Encrypted as {}", encryptedPassword); return encryptedPassword; } @@ -214,7 +212,7 @@ public Path getMavenTemplatesFolder() { if (!Files.isDirectory(templatesConfMvnFolder)) { Path templatesConfMvnLegacyFolder = templatesConfFolder.resolve(MVN_CONFIG_LEGACY_FOLDER); if (!Files.isDirectory(templatesConfMvnLegacyFolder)) { - this.context.warning("No maven templates found neither in {} nor in {} - configuration broken", templatesConfMvnFolder, + LOG.warn("No maven templates found neither in {} nor in {} - configuration broken", templatesConfMvnFolder, templatesConfMvnLegacyFolder); return null; } diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/mvn/MvnRepository.java b/cli/src/main/java/com/devonfw/tools/ide/tool/mvn/MvnRepository.java index 3274855bd6..fb8de6f82e 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/mvn/MvnRepository.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/mvn/MvnRepository.java @@ -199,7 +199,7 @@ public VersionIdentifier resolveVersion(MvnArtifact artifact, GenericVersionRang artifact = artifact.withVersion(versionString); } List versions = fetchVersions(artifact); - VersionIdentifier resolvedVersion = VersionIdentifier.resolveVersionPattern(version, versions, this.context); + VersionIdentifier resolvedVersion = VersionIdentifier.resolveVersionPattern(version, versions); versionString = resolvedVersion.toString(); if (versionString.endsWith("-SNAPSHOT")) { artifact = artifact.withVersion(versionString); diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/node/Node.java b/cli/src/main/java/com/devonfw/tools/ide/tool/node/Node.java index d4ea787276..c478896c6c 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/node/Node.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/node/Node.java @@ -2,8 +2,12 @@ import java.util.Set; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.common.Tag; import com.devonfw.tools.ide.context.IdeContext; +import com.devonfw.tools.ide.log.IdeLogLevel; import com.devonfw.tools.ide.nls.NlsBundle; import com.devonfw.tools.ide.process.ProcessResult; import com.devonfw.tools.ide.tool.LocalToolCommandlet; @@ -17,6 +21,8 @@ */ public class Node extends LocalToolCommandlet { + private static final Logger LOG = LoggerFactory.getLogger(Node.class); + /** * The constructor. * @@ -40,14 +46,14 @@ protected void postInstallOnNewInstallation(ToolInstallRequest request) { .addArg(getToolPath().toString()); ProcessResult result = npm.runPackageManager(packageManagerRequest, true); if (result.isSuccessful()) { - this.context.success("Setting npm config prefix to: {} was successful", getToolPath()); + IdeLogLevel.SUCCESS.log(LOG, "Setting npm config prefix to: {} was successful", getToolPath()); } } @Override public void printHelp(NlsBundle bundle) { - this.context.info("For a list of supported options and arguments, use \"node --help\""); + LOG.info("For a list of supported options and arguments, use \"node --help\""); } @Override diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/npm/NpmBasedCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/tool/npm/NpmBasedCommandlet.java index 24b3d1911d..93eeb39768 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/npm/NpmBasedCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/npm/NpmBasedCommandlet.java @@ -4,6 +4,9 @@ import java.util.List; import java.util.Set; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.common.Tag; import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.process.ProcessContext; @@ -21,6 +24,8 @@ */ public abstract class NpmBasedCommandlet extends NodeBasedCommandlet { + private static final Logger LOG = LoggerFactory.getLogger(NpmBasedCommandlet.class); + /** * The constructor. * @@ -52,7 +57,7 @@ protected VersionIdentifier computeInstalledVersion() { private VersionIdentifier runPackageManagerGetInstalledVersion(String npmPackage) { if (!Files.isDirectory(this.context.getSoftwarePath().resolve("node"))) { - this.context.trace("Since node is not installed, also package {} for tool {} cannot be installed.", npmPackage, this.tool); + LOG.trace("Since node is not installed, also package {} for tool {} cannot be installed.", npmPackage, this.tool); return null; } PackageManagerRequest request = new PackageManagerRequest("list", npmPackage).addArg("list").addArg("-g").addArg(npmPackage).addArg("--depth=0") @@ -74,7 +79,7 @@ private VersionIdentifier runPackageManagerGetInstalledVersion(String npmPackage return VersionIdentifier.of(parsedVersion); } } else { - this.context.debug("The npm package {} for tool {} is not installed.", npmPackage, this.tool); + LOG.debug("The npm package {} for tool {} is not installed.", npmPackage, this.tool); } return null; } diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/pip/PipBasedCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/tool/pip/PipBasedCommandlet.java index 47b09afd1c..b94a4124d0 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/pip/PipBasedCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/pip/PipBasedCommandlet.java @@ -4,6 +4,9 @@ import java.nio.file.Path; import java.util.Set; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.common.Tag; import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.log.IdeLogLevel; @@ -24,6 +27,8 @@ */ public abstract class PipBasedCommandlet extends PackageManagerBasedLocalToolCommandlet { + private static final Logger LOG = LoggerFactory.getLogger(PipBasedCommandlet.class); + private static final String PIP_SHOW_VERSION_PREFIX = "Version:"; /** @@ -54,7 +59,7 @@ protected Class getPackageManagerClass() { case "pip" -> Pip.class; case "uv" -> Uv.class; default -> { - this.context.warning("Undefined value: PIP_EDITION={}", edition); + LOG.warn("Undefined value: PIP_EDITION={}", edition); yield Pip.class; } }; @@ -115,8 +120,8 @@ protected VersionIdentifier computeInstalledVersion() { } } } - this.context.debug("Could not find version from pip show output:"); - processResult.log(IdeLogLevel.DEBUG, this.context); + LOG.debug("Could not find version from pip show output:"); + processResult.log(IdeLogLevel.DEBUG); return null; } diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/plugin/PluginBasedCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/tool/plugin/PluginBasedCommandlet.java index 694d8c374a..75eec695b1 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/plugin/PluginBasedCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/plugin/PluginBasedCommandlet.java @@ -6,6 +6,9 @@ import java.util.List; import java.util.Set; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.cli.CliException; import com.devonfw.tools.ide.common.Tag; import com.devonfw.tools.ide.context.IdeContext; @@ -22,6 +25,8 @@ */ public abstract class PluginBasedCommandlet extends LocalToolCommandlet { + private static final Logger LOG = LoggerFactory.getLogger(PluginBasedCommandlet.class); + private ToolPlugins plugins; /** @@ -42,7 +47,7 @@ public PluginBasedCommandlet(IdeContext context, String tool, Set tags) { public ToolPlugins getPlugins() { if (this.plugins == null) { - ToolPlugins toolPlugins = new ToolPlugins(this.context); + ToolPlugins toolPlugins = new ToolPlugins(); // Load project-specific plugins Path pluginsPath = getPluginsConfigPath(); @@ -109,7 +114,7 @@ protected void postInstall(ToolInstallRequest request) { List markerFiles = fileAccess.listChildren(this.context.getIdeHome().resolve(IdeContext.FOLDER_DOT_IDE), Files::isRegularFile); for (Path path : markerFiles) { if (path.getFileName().toString().startsWith("plugin." + getName())) { - this.context.debug("Plugin marker file {} got deleted.", path); + LOG.debug("Plugin marker file {} got deleted.", path); fileAccess.delete(path); } } @@ -133,14 +138,14 @@ protected void installPlugins(Collection plugins, ProcessC Path pluginMarkerFile = retrievePluginMarkerFilePath(plugin); boolean pluginMarkerFileExists = pluginMarkerFile != null && Files.exists(pluginMarkerFile); if (pluginMarkerFileExists) { - this.context.debug("Markerfile for IDE {} and plugin '{}' already exists.", getName(), plugin.name()); + LOG.debug("Markerfile for IDE {} and plugin '{}' already exists.", getName(), plugin.name()); } if (plugin.active()) { if (this.context.isForcePlugins() || !pluginMarkerFileExists) { Step step = this.context.newStep("Install plugin " + plugin.name()); step.run(() -> doInstallPluginStep(plugin, step, pc)); } else { - this.context.debug("Skipping installation of plugin '{}' due to existing marker file: {}", plugin.name(), pluginMarkerFile); + LOG.debug("Skipping installation of plugin '{}' due to existing marker file: {}", plugin.name(), pluginMarkerFile); } } else { if (!pluginMarkerFileExists) { @@ -211,22 +216,22 @@ public void uninstallPlugin(ToolPluginDescriptor plugin) { boolean error = false; Path pluginsPath = getPluginsInstallationPath(); if (!Files.isDirectory(pluginsPath)) { - this.context.debug("Omitting to uninstall plugin {} ({}) as plugins folder does not exist at {}", + LOG.debug("Omitting to uninstall plugin {} ({}) as plugins folder does not exist at {}", plugin.name(), plugin.id(), pluginsPath); error = true; } FileAccess fileAccess = this.context.getFileAccess(); Path match = fileAccess.findFirst(pluginsPath, p -> p.getFileName().toString().startsWith(plugin.id()), false); if (match == null) { - this.context.debug("Omitting to uninstall plugin {} ({}) as plugins folder does not contain a match at {}", + LOG.debug("Omitting to uninstall plugin {} ({}) as plugins folder does not contain a match at {}", plugin.name(), plugin.id(), pluginsPath); error = true; } if (error) { - context.error("Could not uninstall plugin " + plugin + " because we could not find an installation"); + LOG.error("Could not uninstall plugin {} because we could not find an installation", plugin); } else { fileAccess.delete(match); - context.info("Successfully uninstalled plugin " + plugin); + LOG.info("Successfully uninstalled plugin {}", plugin); } } @@ -257,6 +262,6 @@ public ToolPluginDescriptor getPlugin(String key) { */ protected void handleInstallForInactivePlugin(ToolPluginDescriptor plugin) { - this.context.debug("Omitting installation of inactive plugin {} ({}).", plugin.name(), plugin.id()); + LOG.debug("Omitting installation of inactive plugin {} ({}).", plugin.name(), plugin.id()); } } diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/plugin/ToolPluginDescriptor.java b/cli/src/main/java/com/devonfw/tools/ide/tool/plugin/ToolPluginDescriptor.java index da7fc8d056..7d115a540c 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/plugin/ToolPluginDescriptor.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/plugin/ToolPluginDescriptor.java @@ -5,10 +5,12 @@ import java.util.Properties; import java.util.Set; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.common.Tag; import com.devonfw.tools.ide.common.Tags; import com.devonfw.tools.ide.context.IdeContext; -import com.devonfw.tools.ide.log.IdeLogger; /** * Implementation of {@link ToolPluginDescriptor}. @@ -21,6 +23,8 @@ */ public record ToolPluginDescriptor(String id, String name, String url, boolean active, Set tags) implements Tags { + private static final Logger LOG = LoggerFactory.getLogger(ToolPluginDescriptor.class); + @Override public Set getTags() { @@ -42,16 +46,15 @@ public static ToolPluginDescriptor of(Path propertiesFile, IdeContext context, b String id = getString(properties, "id", "plugin_id"); String url = getString(properties, "url", "plugin_url"); if (needUrl && ((url == null) || url.isBlank())) { - context.warning("Missing plugin URL in {}", propertiesFile); + LOG.warn("Missing plugin URL in {}", propertiesFile); } - boolean active = getBoolean(properties, "active", "plugin_active", propertiesFile, context); + boolean active = getBoolean(properties, "active", "plugin_active", propertiesFile); String tagsCsv = getString(properties, "tags", "plugin_tags"); Set tags = Tag.parseCsv(tagsCsv); return new ToolPluginDescriptor(id, name, url, active, tags); } - private static boolean getBoolean(Properties properties, String key, String legacyKey, Path propertiesFile, - IdeLogger logger) { + private static boolean getBoolean(Properties properties, String key, String legacyKey, Path propertiesFile) { String value = getString(properties, key, legacyKey); if (value == null) { @@ -63,7 +66,7 @@ private static boolean getBoolean(Properties properties, String key, String lega } else if ("false".equals(lower)) { return false; } - logger.warning("Invalid boolean value '{}' for property '{}' in {}", value, key, propertiesFile); + LOG.warn("Invalid boolean value '{}' for property '{}' in {}", value, key, propertiesFile); return false; } diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/plugin/ToolPlugins.java b/cli/src/main/java/com/devonfw/tools/ide/tool/plugin/ToolPlugins.java index 4374210eb3..ca626ad6be 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/plugin/ToolPlugins.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/plugin/ToolPlugins.java @@ -5,27 +5,24 @@ import java.util.HashMap; import java.util.Map; -import com.devonfw.tools.ide.context.IdeContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * A wrapper class for holding two maps of plugin descriptors: one keyed by plugin ID and the other keyed by plugin name. */ public class ToolPlugins { + private static final Logger LOG = LoggerFactory.getLogger(ToolPlugins.class); + private final Map mapById; private final Map mapByName; - - private final IdeContext context; - /** * The constructor. - * - * @param context the {@link IdeContext}. */ - public ToolPlugins(IdeContext context) { + public ToolPlugins() { super(); - this.context = context; this.mapById = new HashMap<>(); this.mapByName = new HashMap<>(); } @@ -72,7 +69,7 @@ protected void add(ToolPluginDescriptor descriptor) { private void put(String key, ToolPluginDescriptor descriptor, Map map) { ToolPluginDescriptor duplicate = map.put(key, descriptor); if (duplicate != null) { - this.context.info("Plugin with key {} was {} but got overridden by {}", key, duplicate, descriptor); + LOG.info("Plugin with key {} was {} but got overridden by {}", key, duplicate, descriptor); } } } diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/python/Python.java b/cli/src/main/java/com/devonfw/tools/ide/tool/python/Python.java index 78df0ea958..caa38b5a3e 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/python/Python.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/python/Python.java @@ -5,6 +5,9 @@ import java.nio.file.StandardCopyOption; import java.util.Set; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.cli.CliException; import com.devonfw.tools.ide.common.Tag; import com.devonfw.tools.ide.context.IdeContext; @@ -22,6 +25,8 @@ */ public class Python extends LocalToolCommandlet { + private static final Logger LOG = LoggerFactory.getLogger(Python.class); + private final VersionIdentifier PYTHON_MIN_VERSION = VersionIdentifier.of("3.8.2"); /** @@ -53,7 +58,7 @@ protected void performToolInstallation(ToolInstallRequest request, Path installa renameVenvFolderToPython(fileAccess, softwarePath, installationPath); this.context.writeVersionFile(resolvedVersion, installationPath); createWindowsSymlinkBinFolder(fileAccess, installationPath); - this.context.debug("Installed {} in version {} at {}", this.tool, resolvedVersion, installationPath); + LOG.debug("Installed {} in version {} at {}", this.tool, resolvedVersion, installationPath); } @Override diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/repository/AbstractToolRepository.java b/cli/src/main/java/com/devonfw/tools/ide/tool/repository/AbstractToolRepository.java index f1cc935a36..90d34d4f1c 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/repository/AbstractToolRepository.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/repository/AbstractToolRepository.java @@ -8,6 +8,10 @@ import java.util.List; import java.util.Set; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.event.Level; + import com.devonfw.tools.ide.cli.CliException; import com.devonfw.tools.ide.cli.CliOfflineException; import com.devonfw.tools.ide.context.IdeContext; @@ -32,6 +36,8 @@ */ public abstract class AbstractToolRepository implements ToolRepository { + private static final Logger LOG = LoggerFactory.getLogger(AbstractToolRepository.class); + private static final int MAX_TEMP_DOWNLOADS = 9; /** The owning {@link IdeContext}. */ @@ -88,14 +94,14 @@ protected Path doDownload(UrlDownloadFileMetadata metadata) { Path downloadCache = this.context.getDownloadPath().resolve(getId()); this.context.getFileAccess().mkdirs(downloadCache); Path target = downloadCache.resolve(downloadFilename); - + if (Files.exists(target)) { // File is already cached if (this.context.getNetworkStatus().isOffline()) { - this.context.debug("Using cached download of {} in version {} from {} (offline mode)", + LOG.debug("Using cached download of {} in version {} from {} (offline mode)", metadata.getTool(), metadata.getVersion(), target); } else { - this.context.interaction("Artifact already exists at {}\nTo force update please delete the file and run again.", target); + IdeLogLevel.INTERACTION.log(LOG, "Artifact already exists at {}\nTo force update please delete the file and run again.", target); } } else { if (this.context.getNetworkStatus().isOffline()) { @@ -130,7 +136,7 @@ private Path download(UrlDownloadFileMetadata metadata, Path target) { error = e; } if (i < max) { - this.context.error(error, "Failed to download from " + url); + LOG.error("Failed to download from " + url, error); } } throw new IllegalStateException("Download of " + target.getFileName() + " failed after trying " + size + " URL(s).", error); @@ -178,8 +184,7 @@ protected String createDownloadFilename(String tool, String edition, VersionIden } else { extension = "zip"; } - this.context.warning("Could not determine file extension from URL {} - guess was {} but may be incorrect.", url, - extension); + LOG.warn("Could not determine file extension from URL {} - guess was {} but may be incorrect.", url, extension); } sb.append("."); sb.append(extension); @@ -256,11 +261,11 @@ private void verifyChecksums(Path file, UrlChecksums expectedChecksums, Object v checksumVerified = true; } if (!checksumVerified) { - IdeLogLevel level = IdeLogLevel.WARNING; + Level level = Level.WARN; if (isLatestVersion(version)) { - level = IdeLogLevel.DEBUG; + level = Level.DEBUG; } - this.context.level(level).log("No checksum found for {}", file); + LOG.atLevel(level).log("No checksum found for {}", file); } } @@ -275,7 +280,7 @@ protected void verifyChecksum(Path file, UrlGenericChecksum expectedChecksum) { String hashAlgorithm = expectedChecksum.getHashAlgorithm(); String actualChecksum = this.context.getFileAccess().checksum(file, hashAlgorithm); if (expectedChecksum.getChecksum().equals(actualChecksum)) { - this.context.success("{} checksum {} is correct.", hashAlgorithm, actualChecksum); + IdeLogLevel.SUCCESS.log(LOG, "{} checksum {} is correct.", hashAlgorithm, actualChecksum); } else { throw new CliException("Downloaded file " + file + " has the wrong " + hashAlgorithm + " checksum!\n" // + "Expected " + expectedChecksum + "\n" // @@ -291,7 +296,7 @@ protected void verifyChecksum(Path file, UrlGenericChecksum expectedChecksum) { public VersionIdentifier resolveVersion(String tool, String edition, GenericVersionRange version, ToolCommandlet toolCommandlet) { List versions = getSortedVersions(tool, edition, toolCommandlet); - return VersionIdentifier.resolveVersionPattern(version, versions, this.context); + return VersionIdentifier.resolveVersionPattern(version, versions); } @Override @@ -304,9 +309,9 @@ public Collection findDependencies(String tool, String edition, dependencies = urlTool.getDependencyFile().getDependencies(); } if (dependencies != ToolDependencies.getEmpty()) { - this.context.trace("Found dependencies in {}", dependencies); + LOG.trace("Found dependencies in {}", dependencies); } - return dependencies.findDependencies(version, this.context); + return dependencies.findDependencies(version); } @Override @@ -318,7 +323,7 @@ public ToolSecurity findSecurity(String tool, String edition) { security = urlTool.getSecurityFile().getSecurity(); } if (security != ToolSecurity.getEmpty()) { - this.context.trace("Found dependencies in {}", security); + LOG.trace("Found CVE information in {}", security); } return security; } diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/sonar/Sonar.java b/cli/src/main/java/com/devonfw/tools/ide/tool/sonar/Sonar.java index c7637c90fb..5e2063e177 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/sonar/Sonar.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/sonar/Sonar.java @@ -5,6 +5,9 @@ import java.util.Properties; import java.util.Set; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.common.Tag; import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.property.EnumProperty; @@ -13,8 +16,14 @@ import com.devonfw.tools.ide.tool.java.Java; import com.devonfw.tools.ide.tool.mvn.Mvn; +/** + * {@link LocalToolCommandlet} for SonarQube. + */ public class Sonar extends LocalToolCommandlet { + private static final Logger LOG = LoggerFactory.getLogger(Sonar.class); + + /** The {@link SonarCommand} to run. */ public final EnumProperty command; /** @@ -44,7 +53,7 @@ public ToolInstallation install(boolean silent) { } @Override - public void run() { + protected void doRun() { SonarCommand command = this.command.getValue(); @@ -88,13 +97,13 @@ protected String getBinaryName() { private void printSonarWebPort() { - this.context.info("SonarQube is running at localhost on the following port (default 9000):"); + LOG.info("SonarQube is running at localhost on the following port (default 9000):"); Path sonarPropertiesPath = getToolPath().resolve("conf/sonar.properties"); Properties sonarProperties = this.context.getFileAccess().readProperties(sonarPropertiesPath); String sonarWebPort = sonarProperties.getProperty("sonar.web.port"); if (sonarWebPort != null) { - this.context.info(sonarWebPort); + LOG.info(sonarWebPort); } } } diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/tomcat/Tomcat.java b/cli/src/main/java/com/devonfw/tools/ide/tool/tomcat/Tomcat.java index 5d3ddd5719..abab95ec13 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/tomcat/Tomcat.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/tomcat/Tomcat.java @@ -9,6 +9,8 @@ import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; @@ -30,6 +32,8 @@ */ public class Tomcat extends LocalToolCommandlet { + private static final Logger LOG = LoggerFactory.getLogger(Tomcat.class); + private static final String CATALINA = "catalina"; private static final String CATALINA_BAT = CATALINA + ".bat"; private static final String CATALINA_BASH_SCRIPT = CATALINA + ".sh"; @@ -83,8 +87,8 @@ private void printTomcatPort() { String portNumber = findTomcatPort(); if (!portNumber.isEmpty()) { - this.context.info("Tomcat is running at localhost on HTTP port {}:", portNumber); - this.context.info("http://localhost:{}", portNumber); + LOG.info("Tomcat is running at localhost on HTTP port {}:", portNumber); + LOG.info("http://localhost:{}", portNumber); } } @@ -102,14 +106,14 @@ private String findTomcatPort() { Element ConnectorElement = (Element) connectorNodes.item(0); portNumber = ConnectorElement.getAttribute("port"); } else { - this.context.warning("Port element not found in server.xml"); + LOG.warn("Port element not found in server.xml"); } } catch (ParserConfigurationException | IOException | SAXException e) { - this.context.error(e); + LOG.error(e.toString(), e); } } if (portNumber.isEmpty()) { - this.context.warning("Could not find HTTP port in {}", tomcatPropertiesPath); + LOG.warn("Could not find HTTP port in {}", tomcatPropertiesPath); } return portNumber; } diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/vscode/Vscode.java b/cli/src/main/java/com/devonfw/tools/ide/tool/vscode/Vscode.java index f626eaaf44..9cfc99407c 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/vscode/Vscode.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/vscode/Vscode.java @@ -6,9 +6,13 @@ import java.util.List; import java.util.Set; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.common.Tag; import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.io.IdeProgressBar; +import com.devonfw.tools.ide.log.IdeLogLevel; import com.devonfw.tools.ide.process.ProcessContext; import com.devonfw.tools.ide.process.ProcessMode; import com.devonfw.tools.ide.process.ProcessResult; @@ -22,6 +26,8 @@ */ public class Vscode extends IdeToolCommandlet { + private static final Logger LOG = LoggerFactory.getLogger(Vscode.class); + /** * The constructor. * @@ -61,11 +67,11 @@ public boolean installPlugin(ToolPluginDescriptor plugin, Step step, ProcessCont extensionsCommands.add(plugin.id()); ProcessResult result = runTool(pc, ProcessMode.DEFAULT_CAPTURE, extensionsCommands); if (result.isSuccessful()) { - this.context.success("Successfully installed plugin: {}", plugin.name()); + IdeLogLevel.SUCCESS.log(LOG, "Successfully installed plugin: {}", plugin.name()); step.success(); return true; } else { - this.context.warning("An error occurred while installing plugin: {}", plugin.name()); + LOG.warn("An error occurred while installing plugin: {}", plugin.name()); return false; } } diff --git a/cli/src/main/java/com/devonfw/tools/ide/url/model/UrlMetadata.java b/cli/src/main/java/com/devonfw/tools/ide/url/model/UrlMetadata.java index 5160e14712..48167a7150 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/url/model/UrlMetadata.java +++ b/cli/src/main/java/com/devonfw/tools/ide/url/model/UrlMetadata.java @@ -9,6 +9,9 @@ import java.util.List; import java.util.Map; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.cli.CliException; import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.os.SystemInfo; @@ -25,6 +28,8 @@ */ public class UrlMetadata implements AbstractUrlMetadata { + private static final Logger LOG = LoggerFactory.getLogger(UrlMetadata.class); + private final IdeContext context; private final UrlRepository repository; @@ -80,7 +85,7 @@ public List getSortedEditions(String tool) { List list = new ArrayList<>(); UrlTool urlTool = this.repository.getChild(tool); if (urlTool == null) { - this.context.warning("Can't get sorted editions for tool {} because it does not exist in {}.", tool, this.repository.getPath()); + LOG.warn("Can't get sorted editions for tool {} because it does not exist in {}.", tool, this.repository.getPath()); } else { for (UrlEdition urlEdition : urlTool.getChildren()) { list.add(urlEdition.getName()); @@ -128,7 +133,7 @@ private List computeSortedVersions(String tool, String editio public VersionIdentifier resolveVersion(String tool, String edition, GenericVersionRange version, ToolCommandlet toolCommandlet) { List versions = getSortedVersions(tool, edition, toolCommandlet); - return VersionIdentifier.resolveVersionPattern(version, versions, this.context); + return VersionIdentifier.resolveVersionPattern(version, versions); } /** diff --git a/cli/src/main/java/com/devonfw/tools/ide/url/model/file/json/ToolDependencies.java b/cli/src/main/java/com/devonfw/tools/ide/url/model/file/json/ToolDependencies.java index 92600ed96b..ab48f98299 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/url/model/file/json/ToolDependencies.java +++ b/cli/src/main/java/com/devonfw/tools/ide/url/model/file/json/ToolDependencies.java @@ -8,8 +8,10 @@ import java.util.Map; import java.util.TreeMap; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.json.JsonMapping; -import com.devonfw.tools.ide.log.IdeLogger; import com.devonfw.tools.ide.version.VersionIdentifier; import com.devonfw.tools.ide.version.VersionRange; import com.fasterxml.jackson.core.type.TypeReference; @@ -22,6 +24,8 @@ */ public class ToolDependencies { + private static final Logger LOG = LoggerFactory.getLogger(ToolDependencies.class); + private static final ObjectMapper MAPPER = JsonMapping.create(); private static final ToolDependencies EMPTY = new ToolDependencies(Collections.emptyMap(), Path.of("empty")); @@ -40,7 +44,7 @@ private ToolDependencies(Map> dependencies, P * @param version the {@link VersionIdentifier} of the tool to install. * @return The {@link List} of {@link ToolDependency}s for the given tool version. */ - public List findDependencies(VersionIdentifier version, IdeLogger logger) { + public List findDependencies(VersionIdentifier version) { for (Map.Entry> entry : this.dependencies.entrySet()) { VersionRange versionRange = entry.getKey(); @@ -50,7 +54,7 @@ public List findDependencies(VersionIdentifier version, IdeLogge } int size = dependencies.size(); if (size > 0) { - logger.warning("No match for version {} while {} version ranges are configured in {} - configuration error?!", version, size, this.path); + LOG.warn("No match for version {} while {} version ranges are configured in {} - configuration error?!", version, size, this.path); } return Collections.emptyList(); } diff --git a/cli/src/main/java/com/devonfw/tools/ide/url/model/file/json/ToolSecurity.java b/cli/src/main/java/com/devonfw/tools/ide/url/model/file/json/ToolSecurity.java index 929846f489..0e90f47a73 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/url/model/file/json/ToolSecurity.java +++ b/cli/src/main/java/com/devonfw/tools/ide/url/model/file/json/ToolSecurity.java @@ -11,9 +11,11 @@ import java.util.TreeMap; import java.util.function.Predicate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.json.JsonMapping; import com.devonfw.tools.ide.json.JsonObject; -import com.devonfw.tools.ide.log.IdeLogger; import com.devonfw.tools.ide.security.ToolVulnerabilities; import com.devonfw.tools.ide.variable.IdeVariables; import com.devonfw.tools.ide.version.VersionIdentifier; @@ -27,6 +29,8 @@ */ public class ToolSecurity implements JsonObject { + private static final Logger LOG = LoggerFactory.getLogger(ToolSecurity.class); + static final String PROPERTY_ISSUES = "issues"; private static final ObjectMapper MAPPER = JsonMapping.create(); @@ -108,11 +112,10 @@ public void clearIssues() { * Finds all {@link Cve}s for the given {@link VersionIdentifier} that also match the given {@link Predicate}. * * @param version the {@link VersionIdentifier} to check. - * @param logger the {@link IdeLogger}. * @param predicate the {@link Predicate} deciding which matching {@link Cve}s are {@link Predicate#test(Object) accepted}. * @return all {@link Cve}s for the given {@link VersionIdentifier}. */ - public ToolVulnerabilities findCves(VersionIdentifier version, IdeLogger logger, Predicate predicate) { + public ToolVulnerabilities findCves(VersionIdentifier version, Predicate predicate) { List cvesOfVersion = new ArrayList<>(); for (Cve cve : this.issues) { for (VersionRange range : cve.versions()) { @@ -120,7 +123,7 @@ public ToolVulnerabilities findCves(VersionIdentifier version, IdeLogger logger, if (predicate.test(cve)) { cvesOfVersion.add(cve); } else { - logger.info("Ignoring CVE {} with severity {}", cve.id(), cve.severity()); + LOG.info("Ignoring CVE {} with severity {}", cve.id(), cve.severity()); } } } @@ -132,12 +135,11 @@ public ToolVulnerabilities findCves(VersionIdentifier version, IdeLogger logger, * Finds all {@link Cve}s for the given {@link VersionIdentifier} and {@code minSeverity}. * * @param version the {@link VersionIdentifier} to check. - * @param logger the {@link IdeLogger}. * @param minSeverity the {@link IdeVariables#CVE_MIN_SEVERITY minimum severity}. * @return the {@link ToolVulnerabilities} for the given {@link VersionIdentifier}. */ - public ToolVulnerabilities findCves(VersionIdentifier version, IdeLogger logger, double minSeverity) { - return findCves(version, logger, cve -> cve.severity() >= minSeverity); + public ToolVulnerabilities findCves(VersionIdentifier version, double minSeverity) { + return findCves(version, cve -> cve.severity() >= minSeverity); } /** diff --git a/cli/src/main/java/com/devonfw/tools/ide/util/PrivacyUtil.java b/cli/src/main/java/com/devonfw/tools/ide/util/PrivacyUtil.java index 1577ee6501..c230d35814 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/util/PrivacyUtil.java +++ b/cli/src/main/java/com/devonfw/tools/ide/util/PrivacyUtil.java @@ -17,13 +17,24 @@ public final class PrivacyUtil { "tbz2", "zip", "compress", "compression", "global", "value", "code", "branch", "string", "long", "number", "numeric", "apache", "commons", "hibernate", "storage", "db", "spring", "springframework", "boot", "quarkus", "mnt", "usr", "user", "users", "windows", "etc", "var", "log", "lib", "drivers", "system", "system32", "appdata", "module", "info", "sha1", "md5", "sha256", "sha512", "pkcs", "p12", "cert", "file", "files", "bin", "bash", "program", - "mingw64"); + "mingw64", "dummy", "hosts"); // construction forbidden private PrivacyUtil() { } + private static int indexOfSlash(String arg, int start) { + int index = arg.indexOf('/', start); + int index2 = arg.indexOf('\\', start); + if (index2 < 0) { + return index; + } else if ((index < 0) || (index2 < index)) { + return index2; + } + return index; + } + /** * @param arg the path or any {@link String} containing one or multiple paths. * @return a normalized form of the @@ -72,23 +83,24 @@ public static String removeSensitivePathInformation(String arg) { } index = indexOfSlash(arg, index); if (index < 0) { - result.append(arg, start, length); // append rest + // append rest + int end = start; + while (end < length) { + int cp = arg.codePointAt(end); + if ((cp == ' ') || (cp == '"') || (cp == '\'')) { + break; + } + end++; + } + appendSegment(arg, result, start, end); + if (end < length) { + result.append(arg, end, length); + } } } return result.toString(); } - private static int indexOfSlash(String arg, int start) { - int index = arg.indexOf('/', start); - int index2 = arg.indexOf('\\', start); - if (index2 < 0) { - return index; - } else if ((index < 0) || (index2 < index)) { - return index2; - } - return index; - } - private static void appendSegment(String arg, StringBuilder result, int start, int index) { String segment = arg.substring(start, index); diff --git a/cli/src/main/java/com/devonfw/tools/ide/variable/AbstractVariableDefinitionList.java b/cli/src/main/java/com/devonfw/tools/ide/variable/AbstractVariableDefinitionList.java index 2cbecac83e..e9b0f53c48 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/variable/AbstractVariableDefinitionList.java +++ b/cli/src/main/java/com/devonfw/tools/ide/variable/AbstractVariableDefinitionList.java @@ -5,6 +5,9 @@ import java.util.List; import java.util.function.Function; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.context.IdeContext; /** @@ -12,6 +15,8 @@ */ public abstract class AbstractVariableDefinitionList extends AbstractVariableDefinition> { + private static final Logger LOG = LoggerFactory.getLogger(AbstractVariableDefinitionList.class); + /** * The constructor. * @@ -87,7 +92,7 @@ protected List parseList(String value, IdeContext context) { try { list.add(parseValue(item.trim(), context)); } catch (Exception e) { - context.warning().log(e, "Invalid value '{}' for element of variable {}", item, getName()); + LOG.warn("Invalid value '{}' for element of variable {}", item, getName(), e); return null; } diff --git a/cli/src/main/java/com/devonfw/tools/ide/variable/IdeVariables.java b/cli/src/main/java/com/devonfw/tools/ide/variable/IdeVariables.java index e7ef0e2167..86ee95027c 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/variable/IdeVariables.java +++ b/cli/src/main/java/com/devonfw/tools/ide/variable/IdeVariables.java @@ -103,11 +103,17 @@ public interface IdeVariables { c -> Boolean.TRUE); /** - * {@link VariableDefinition} for support of legacy xml templates without XML merge namespace + * {@link VariableDefinition} for support of legacy xml templates without XML merge namespace. */ VariableDefinitionBoolean IDE_XML_MERGE_LEGACY_SUPPORT_ENABLED = new VariableDefinitionBoolean("IDE_XML_MERGE_LEGACY_SUPPORT_ENABLED", null, c -> Boolean.FALSE); + /** + * {@link VariableDefinition} to enable writing logfiles to disc. + */ + VariableDefinitionBoolean IDE_WRITE_LOGFILE = new VariableDefinitionBoolean("IDE_WRITE_LOGFILE", null, + c -> Boolean.TRUE); + /** {@link VariableDefinition} for {@link com.devonfw.tools.ide.context.IdeContext#getProjectName() DEVON_IDE_CUSTOM_TOOLS}. */ VariableDefinitionString DEVON_IDE_CUSTOM_TOOLS = new VariableDefinitionString("DEVON_IDE_CUSTOM_TOOLS"); diff --git a/cli/src/main/java/com/devonfw/tools/ide/variable/VariableDefinitionBoolean.java b/cli/src/main/java/com/devonfw/tools/ide/variable/VariableDefinitionBoolean.java index ae318e0f11..9ef45bcde5 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/variable/VariableDefinitionBoolean.java +++ b/cli/src/main/java/com/devonfw/tools/ide/variable/VariableDefinitionBoolean.java @@ -3,6 +3,9 @@ import java.util.Locale; import java.util.function.Function; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.context.IdeContext; /** @@ -10,6 +13,8 @@ */ public class VariableDefinitionBoolean extends AbstractVariableDefinition { + private static final Logger LOG = LoggerFactory.getLogger(VariableDefinitionBoolean.class); + /** * The constructor. * @@ -85,7 +90,7 @@ public Boolean fromString(String value, IdeContext context) { case "true", "yes" -> Boolean.TRUE; case "false", "no" -> Boolean.FALSE; default -> { - context.warning("Variable {} has invalid boolean value {} - using false as fallback"); + LOG.warn("Variable {} has invalid boolean value {} - using false as fallback", getName(), value); yield Boolean.FALSE; } }; diff --git a/cli/src/main/java/com/devonfw/tools/ide/version/VersionIdentifier.java b/cli/src/main/java/com/devonfw/tools/ide/version/VersionIdentifier.java index 8644ef13d1..bafadc950e 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/version/VersionIdentifier.java +++ b/cli/src/main/java/com/devonfw/tools/ide/version/VersionIdentifier.java @@ -3,8 +3,10 @@ import java.util.List; import java.util.Objects; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.cli.CliException; -import com.devonfw.tools.ide.log.IdeLogger; import com.devonfw.tools.ide.tool.ToolCommandlet; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.databind.annotation.JsonSerialize; @@ -15,6 +17,8 @@ */ public final class VersionIdentifier implements VersionObject, GenericVersionRange { + private static final Logger LOG = LoggerFactory.getLogger(VersionIdentifier.class); + /** {@link VersionIdentifier} "*" that will resolve to the latest stable version. */ public static final VersionIdentifier LATEST = new VersionIdentifier(VersionSegment.of("*")); @@ -64,24 +68,23 @@ private VersionIdentifier(VersionSegment start) { * @param versions the * {@link com.devonfw.tools.ide.tool.repository.ToolRepository#getSortedVersions(String, String, ToolCommandlet) available versions, sorted in descending * order}. - * @param logger the {@link IdeLogger}. * @return the resolved version */ - public static VersionIdentifier resolveVersionPattern(GenericVersionRange version, List versions, IdeLogger logger) { + public static VersionIdentifier resolveVersionPattern(GenericVersionRange version, List versions) { if (version == null) { version = LATEST; } if (!version.isPattern()) { for (VersionIdentifier vi : versions) { if (vi.equals(version)) { - logger.debug("Resolved version {} to version {}", version, vi); + LOG.debug("Resolved version {} to version {}", version, vi); return vi; } } } for (VersionIdentifier vi : versions) { if (version.contains(vi)) { - logger.debug("Resolved version pattern {} to version {}", version, vi); + LOG.debug("Resolved version pattern {} to version {}", version, vi); return vi; } } diff --git a/cli/src/main/resources/META-INF/native-image/com.devonfw.tools.IDEasy/ide-cli/reflect-config.json b/cli/src/main/resources/META-INF/native-image/com.devonfw.tools.IDEasy/ide-cli/reflect-config.json index e9a098dbd0..5eb3b81a7d 100644 --- a/cli/src/main/resources/META-INF/native-image/com.devonfw.tools.IDEasy/ide-cli/reflect-config.json +++ b/cli/src/main/resources/META-INF/native-image/com.devonfw.tools.IDEasy/ide-cli/reflect-config.json @@ -44,5 +44,19 @@ "allPublicConstructors": true, "allDeclaredFields": true, "allDeclaredMethods": true + }, + { + "name": "com.devonfw.tools.ide.log.JulConsoleHandler", + "allDeclaredConstructors": false, + "allPublicConstructors": true, + "allDeclaredFields": false, + "allDeclaredMethods": false + }, + { + "name": "java.util.logging.FileHandler", + "allDeclaredConstructors": false, + "allPublicConstructors": true, + "allDeclaredFields": false, + "allDeclaredMethods": false } ] diff --git a/cli/src/main/resources/META-INF/services/org.slf4j.spi.SLF4JServiceProvider b/cli/src/main/resources/META-INF/services/org.slf4j.spi.SLF4JServiceProvider new file mode 100644 index 0000000000..1ace08ba64 --- /dev/null +++ b/cli/src/main/resources/META-INF/services/org.slf4j.spi.SLF4JServiceProvider @@ -0,0 +1 @@ +com.devonfw.tools.ide.log.Slf4jProviderIdeasy diff --git a/cli/src/test/java/com/devonfw/tools/ide/commandlet/HelpCommandletTest.java b/cli/src/test/java/com/devonfw/tools/ide/commandlet/HelpCommandletTest.java index 1057801485..e059ae73e3 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/commandlet/HelpCommandletTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/commandlet/HelpCommandletTest.java @@ -15,7 +15,6 @@ import com.devonfw.tools.ide.context.AbstractIdeContextTest; import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.context.IdeTestContext; -import com.devonfw.tools.ide.context.IdeTestContextMock; import com.devonfw.tools.ide.nls.NlsBundle; import com.devonfw.tools.ide.property.KeywordProperty; import com.devonfw.tools.ide.property.Property; @@ -32,7 +31,7 @@ class HelpCommandletTest extends AbstractIdeContextTest { void testThatHomeIsNotRequired() { // arrange - IdeContext context = IdeTestContextMock.get(); + IdeContext context = new IdeTestContext(); // act HelpCommandlet help = new HelpCommandlet(context); // assert @@ -110,7 +109,7 @@ void testRunWithCommandlet() { void testEnsureAllNlsPropertiesPresent(String locale) throws IOException { // arrange - IdeContext context = IdeTestContextMock.get(); + IdeContext context = new IdeTestContext(); NlsBundle bundleRoot = new NlsBundle(context, Locale.ROOT); NlsBundle bundle = new NlsBundle(context, Locale.forLanguageTag(locale)); SoftAssertions soft = new SoftAssertions(); diff --git a/cli/src/test/java/com/devonfw/tools/ide/commandlet/InstallCommandletTest.java b/cli/src/test/java/com/devonfw/tools/ide/commandlet/InstallCommandletTest.java index daa12ea169..a453275307 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/commandlet/InstallCommandletTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/commandlet/InstallCommandletTest.java @@ -1,5 +1,7 @@ package com.devonfw.tools.ide.commandlet; +import static org.junit.jupiter.api.Assertions.assertThrows; + import java.util.List; import org.junit.jupiter.api.Test; @@ -13,8 +15,6 @@ import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo; import com.github.tomakehurst.wiremock.junit5.WireMockTest; -import static org.junit.jupiter.api.Assertions.assertThrows; - /** * Test of {@link InstallCommandlet}. */ @@ -130,14 +130,14 @@ void testInstallCommandletWithSkipUpdates(WireMockRuntimeInfo wmRuntimeInfo) { install.version.setValueAsString("17*", context); // Record the log entry count before the action - int logCountBefore = context.getLogger().getEntries().size(); + int logCountBefore = context.getTestStartContext().getEntries().size(); // act - try to install with --skip-updates // Should skip the update to 17.0.10 since 17.0.6 matches the pattern install.run(); // assert - should NOT download 17.0.10, should stay on 17.0.6 - List newLogEntries = context.getLogger().getEntries().subList(logCountBefore, context.getLogger().getEntries().size()); + List newLogEntries = context.getTestStartContext().getEntries().subList(logCountBefore, context.getTestStartContext().getEntries().size()); boolean hasDownloadMessage = newLogEntries.stream().anyMatch(e -> e.message().contains("Trying to download")); assertThat(hasDownloadMessage).as("Should not download when --skip-updates is enabled and version matches pattern").isFalse(); assertThat(context.getSoftwarePath().resolve("java/.ide.software.version")).exists().hasContent(installedVersion); @@ -194,13 +194,13 @@ void testInstallCommandletWithSkipUpdatesInstallsWhenVersionMismatch(WireMockRun install.tool.setValueAsString("java", context); install.version.setValueAsString("21*", context); - int logCountBefore = context.getLogger().getEntries().size(); + int logCountBefore = context.getTestStartContext().getEntries().size(); // act - install with --skip-updates but with non-matching version install.run(); // assert - SHOULD download and install 21.x because installed 17.0.6 does NOT match pattern "21*" - List newLogEntries = context.getLogger().getEntries().subList(logCountBefore, context.getLogger().getEntries().size()); + List newLogEntries = context.getTestStartContext().getEntries().subList(logCountBefore, context.getTestStartContext().getEntries().size()); boolean hasDownloadMessage = newLogEntries.stream().anyMatch(e -> e.message().contains("Trying to download") && e.message().contains("21.")); assertThat(hasDownloadMessage).as("Should download when --skip-updates is enabled but version does not match").isTrue(); assertThat(context.getSoftwarePath().resolve("java/.ide.software.version")).exists().hasContent("21.0.8_9"); @@ -242,7 +242,7 @@ public void testInstallCommandletOfflineWithCachedDownload(WireMockRuntimeInfo w // Determine the correct file extension and OS name based on the current OS String fileExtension = context.getSystemInfo().isWindows() ? "zip" : "tgz"; String osName = context.getSystemInfo().getOs().toString().toLowerCase(); - assertThat(context).logAtDebug().hasMessage("Using cached download of java in version " + version + " from " + assertThat(context).logAtDebug().hasMessage("Using cached download of java in version " + version + " from " + context.getDownloadPath().resolve("default").resolve("java-" + version + "-" + osName + "-x64." + fileExtension) + " (offline mode)"); } @@ -299,7 +299,7 @@ public void testInstallCommandletOfflineUpdateWithoutCachedDownload(WireMockRunt // assert - should continue using the old version and log a warning assertThat(context.getSoftwarePath().resolve("java/.ide.software.version")).exists().hasContent(installedVersion); - assertThat(context).logAtWarning().hasMessage("Cannot download java in version " + targetVersion + assertThat(context).logAtWarning().hasMessage("Cannot download java in version " + targetVersion + " because we are offline. Continuing with already installed version " + installedVersion + "."); } } diff --git a/cli/src/test/java/com/devonfw/tools/ide/completion/CompletionCandidateCollectorDefaultTest.java b/cli/src/test/java/com/devonfw/tools/ide/completion/CompletionCandidateCollectorDefaultTest.java index 3d295a41ff..b6e034de83 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/completion/CompletionCandidateCollectorDefaultTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/completion/CompletionCandidateCollectorDefaultTest.java @@ -6,7 +6,7 @@ import com.devonfw.tools.ide.commandlet.VersionCommandlet; import com.devonfw.tools.ide.context.AbstractIdeContextTest; import com.devonfw.tools.ide.context.IdeContext; -import com.devonfw.tools.ide.context.IdeTestContextMock; +import com.devonfw.tools.ide.context.IdeTestContext; import com.devonfw.tools.ide.property.Property; import com.devonfw.tools.ide.property.VersionProperty; @@ -27,7 +27,7 @@ void testAddAllMatches() { String[] expectedCandidates = { "2.0", "2.1", "20", "200" }; VersionProperty versionProperty = new VersionProperty("", false, "version"); - IdeContext context = IdeTestContextMock.get(); + IdeContext context = new IdeTestContext(); CompletionCandidateCollector collector = new CompletionCandidateCollectorDefault(context); // act @@ -46,7 +46,7 @@ void testAddAllMatchesEmptyInput() { String input = ""; VersionProperty versionProperty = new VersionProperty("", false, "version"); - IdeContext context = IdeTestContextMock.get(); + IdeContext context = new IdeTestContext(); CompletionCandidateCollector collector = new CompletionCandidateCollectorDefault(context); // act @@ -66,7 +66,7 @@ void testClearCandidates() { String[] expectedCandidates = sortedCandidates; VersionProperty versionProperty = new VersionProperty("", false, "version"); - IdeContext context = IdeTestContextMock.get(); + IdeContext context = new IdeTestContext(); CompletionCandidateCollector collector = new CompletionCandidateCollectorDefault(context); // act diff --git a/cli/src/test/java/com/devonfw/tools/ide/context/AbstractIdeContextTest.java b/cli/src/test/java/com/devonfw/tools/ide/context/AbstractIdeContextTest.java index 51f204d60c..ad5d37022a 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/context/AbstractIdeContextTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/context/AbstractIdeContextTest.java @@ -14,9 +14,9 @@ import org.assertj.core.api.Assertions; import com.devonfw.tools.ide.io.FileAccess; -import com.devonfw.tools.ide.io.FileAccessImpl; import com.devonfw.tools.ide.io.FileCopyMode; import com.devonfw.tools.ide.io.IdeProgressBarTestImpl; +import com.devonfw.tools.ide.io.IdeProgressBarTestImpl.ProgressEvent; import com.devonfw.tools.ide.log.IdeLogLevel; import com.devonfw.tools.ide.tool.repository.ToolRepositoryMock; import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo; @@ -99,7 +99,7 @@ protected static IdeTestContext newContext(String testProject, String projectPat */ protected static IdeTestContext newContext(String testProject, String projectPath, boolean copyForMutation, WireMockRuntimeInfo wmRuntimeInfo) { - return newContext(testProject, projectPath, copyForMutation, wmRuntimeInfo, IdeLogLevel.TRACE); + return newContext(testProject, projectPath, copyForMutation, wmRuntimeInfo, IdeLogLevel.DEBUG); } /** @@ -118,7 +118,7 @@ protected static IdeTestContext newContext(String testProject, String projectPat Path ideRoot = TEST_PROJECTS.resolve(testProject); if (copyForMutation) { Path ideRootCopy = TEST_PROJECTS_COPY.resolve(testProject); - FileAccess fileAccess = new FileAccessImpl(IdeTestContextMock.get()); + FileAccess fileAccess = new IdeTestContext().getFileAccess(); fileAccess.delete(ideRootCopy); fileAccess.mkdirs(TEST_PROJECTS_COPY); fileAccess.copy(ideRoot, TEST_PROJECTS_COPY, FileCopyMode.COPY_TREE_OVERRIDE_TREE); @@ -158,11 +158,11 @@ protected static IdeTestContextAssertion assertThat(IdeTestContext context) { return new IdeTestContextAssertion(context); } - private static List assertProgressEventsAndSize(AbstractIdeTestContext context, String taskName, int chunkCount, + private static List assertProgressEventsAndSize(AbstractIdeTestContext context, String taskName, int chunkCount, long maxSize) { IdeProgressBarTestImpl progressBar = context.getProgressBarMap().get(taskName); assertThat(progressBar).as(taskName).isNotNull(); - List eventList = progressBar.getEventList(); + List eventList = progressBar.getEventList(); assertThat(eventList).hasSize(chunkCount + 1); // extra case for unknown file size (indefinite progress bar) if (progressBar.getMaxSize() != -1L) { diff --git a/cli/src/test/java/com/devonfw/tools/ide/context/AbstractIdeTestContext.java b/cli/src/test/java/com/devonfw/tools/ide/context/AbstractIdeTestContext.java index 26c2b4659a..84022d2a05 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/context/AbstractIdeTestContext.java +++ b/cli/src/test/java/com/devonfw/tools/ide/context/AbstractIdeTestContext.java @@ -6,6 +6,9 @@ import java.util.Map; import java.util.Properties; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.commandlet.Commandlet; import com.devonfw.tools.ide.commandlet.CommandletManager; import com.devonfw.tools.ide.commandlet.TestCommandletManager; @@ -18,7 +21,7 @@ import com.devonfw.tools.ide.environment.IdeSystemTestImpl; import com.devonfw.tools.ide.io.IdeProgressBar; import com.devonfw.tools.ide.io.IdeProgressBarTestImpl; -import com.devonfw.tools.ide.log.IdeLogger; +import com.devonfw.tools.ide.log.IdeLogLevel; import com.devonfw.tools.ide.network.NetworkStatusMock; import com.devonfw.tools.ide.os.SystemInfo; import com.devonfw.tools.ide.os.SystemInfoImpl; @@ -35,6 +38,8 @@ */ public class AbstractIdeTestContext extends AbstractIdeContext { + private static final Logger LOG = LoggerFactory.getLogger(AbstractIdeTestContext.class); + /** {@link Path} to use as workingDirectory for mocking. */ public static final Path PATH_MOCK = Path.of("/"); @@ -63,13 +68,13 @@ public class AbstractIdeTestContext extends AbstractIdeContext { /** * The constructor. * - * @param logger the {@link IdeLogger}. + * @param startContext the {@link IdeStartContextImpl}. * @param workingDirectory the optional {@link Path} to current working directory. * @param wireMockRuntimeInfo wireMock server on a random port. */ - public AbstractIdeTestContext(IdeStartContextImpl logger, Path workingDirectory, WireMockRuntimeInfo wireMockRuntimeInfo) { + public AbstractIdeTestContext(IdeStartContextImpl startContext, Path workingDirectory, WireMockRuntimeInfo wireMockRuntimeInfo) { - super(logger, workingDirectory); + super(startContext, workingDirectory); this.answers = new String[0]; this.progressBarMap = new HashMap<>(); this.systemInfo = super.getSystemInfo(); @@ -119,7 +124,7 @@ protected IdeHomeAndWorkspace findIdeHome(Path workingDirectory) { // Validate that the detected IDE home (if any) is within test boundaries Path ideHome = result.home(); if (ideHome != null && testBoundary != null && !ideHome.startsWith(testBoundary)) { - debug("Test isolation violation: Detected IDE home '{}' is outside test boundary '{}'.\n" + LOG.debug("Test isolation violation: Detected IDE home '{}' is outside test boundary '{}'.\n" + "This indicates the test project structure is incomplete or improperly configured.\n" + "A valid IDE home directories is determined by isIdeHome() method.\n" + "Please ensure your test project has the required structure.", ideHome, testBoundary); @@ -157,7 +162,7 @@ protected String readLine() { throw new IllegalStateException("End of answers reached!"); } String answer = this.answers[this.answerIndex++]; - interaction(answer); + IdeLogLevel.INTERACTION.log(LOG, answer); return answer; } @@ -216,7 +221,7 @@ protected AbstractEnvironmentVariables createSystemVariables() { public IdeSystemTestImpl getSystem() { if (this.system == null) { - this.system = new IdeSystemTestImpl(this); + this.system = new IdeSystemTestImpl(); } return (IdeSystemTestImpl) this.system; } @@ -407,4 +412,11 @@ public String getDefaultWindowsGitPath() { protected Path findBashInWindowsRegistry() { return null; } + + @Override + protected boolean isWriteLogfile(Commandlet cmd) { + + return false; + } + } diff --git a/cli/src/test/java/com/devonfw/tools/ide/context/IdeContextTest.java b/cli/src/test/java/com/devonfw/tools/ide/context/IdeContextTest.java index 9aeaa0e761..a81b81b47f 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/context/IdeContextTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/context/IdeContextTest.java @@ -4,6 +4,8 @@ import java.util.Properties; import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.devonfw.tools.ide.cli.CliArguments; import com.devonfw.tools.ide.common.SystemPath; @@ -22,6 +24,8 @@ */ class IdeContextTest extends AbstractIdeContextTest { + private static final Logger LOG = LoggerFactory.getLogger(IdeContextTest.class); + /** * Test of {@link IdeContext} initialization from basic project. */ @@ -182,19 +186,19 @@ void testRunWithoutLogging() { String testDebugMessage = "Test debug message that will be suppressed because of threshold"; IdeTestContext context = newContext(PROJECT_BASIC, null, false); // act - context.warning(testWarningMessage); + LOG.warn(testWarningMessage); // assert assertThat(context).logAtWarning().hasMessage(testWarningMessage); // and act context.runWithoutLogging(() -> { - context.warning(testWarningMessage2); - context.info(testInfoMessage); - context.debug(testDebugMessage); + LOG.warn(testWarningMessage2); + LOG.info(testInfoMessage); + LOG.debug(testDebugMessage); assertThat(context).log().hasNoMessage(testWarningMessage2); assertThat(context).log().hasNoMessage(testInfoMessage); assertThat(context).log().hasNoMessage(testDebugMessage); }, IdeLogLevel.INFO); - context.warning(testWarningMessage3); + LOG.warn(testWarningMessage3); assertThat(context).log() .hasEntries(IdeLogEntry.ofWarning(testWarningMessage), IdeLogEntry.ofWarning(testWarningMessage2), IdeLogEntry.ofInfo(testInfoMessage), diff --git a/cli/src/test/java/com/devonfw/tools/ide/context/IdeSlf4jContext.java b/cli/src/test/java/com/devonfw/tools/ide/context/IdeSlf4jContext.java deleted file mode 100644 index b587bedd36..0000000000 --- a/cli/src/test/java/com/devonfw/tools/ide/context/IdeSlf4jContext.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.devonfw.tools.ide.context; - -import java.nio.file.Path; - -import com.devonfw.tools.ide.log.IdeLogLevel; -import com.devonfw.tools.ide.log.IdeSubLoggerSlf4j; - -/** - * Implementation of {@link IdeContext} for testing. - */ -public class IdeSlf4jContext extends AbstractIdeTestContext { - - private static final Path PATH_MOCK = Path.of("/"); - - /** - * The constructor. - */ - public IdeSlf4jContext() { - this(PATH_MOCK); - } - - /** - * The constructor. - * - * @param workingDirectory the optional {@link Path} to current working directory. - */ - public IdeSlf4jContext(Path workingDirectory) { - - super(new IdeStartContextImpl(IdeLogLevel.TRACE, IdeSubLoggerSlf4j::new), workingDirectory, null); - } - -} diff --git a/cli/src/test/java/com/devonfw/tools/ide/context/IdeTestContext.java b/cli/src/test/java/com/devonfw/tools/ide/context/IdeTestContext.java index 918b9b4245..88b1934e1a 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/context/IdeTestContext.java +++ b/cli/src/test/java/com/devonfw/tools/ide/context/IdeTestContext.java @@ -7,7 +7,7 @@ import com.devonfw.tools.ide.git.GitContext; import com.devonfw.tools.ide.git.GitContextMock; import com.devonfw.tools.ide.log.IdeLogLevel; -import com.devonfw.tools.ide.log.IdeTestLogger; +import com.devonfw.tools.ide.log.IdeTestStartContext; import com.devonfw.tools.ide.process.ProcessContext; import com.devonfw.tools.ide.tool.mvn.MvnRepository; import com.devonfw.tools.ide.tool.npm.NpmRepository; @@ -20,8 +20,6 @@ */ public class IdeTestContext extends AbstractIdeTestContext { - private final IdeTestLogger logger; - private GitContext gitContext; /** @@ -40,7 +38,7 @@ public IdeTestContext() { */ public IdeTestContext(Path workingDirectory, WireMockRuntimeInfo wireMockRuntimeInfo) { - this(workingDirectory, IdeLogLevel.TRACE, wireMockRuntimeInfo); + this(workingDirectory, IdeLogLevel.DEBUG, wireMockRuntimeInfo); } /** @@ -52,13 +50,12 @@ public IdeTestContext(Path workingDirectory, WireMockRuntimeInfo wireMockRuntime */ public IdeTestContext(Path workingDirectory, IdeLogLevel logLevel, WireMockRuntimeInfo wireMockRuntimeInfo) { - this(new IdeTestLogger(logLevel), workingDirectory, wireMockRuntimeInfo); + this(new IdeTestStartContext(logLevel), workingDirectory, wireMockRuntimeInfo); } - private IdeTestContext(IdeTestLogger logger, Path workingDirectory, WireMockRuntimeInfo wireMockRuntimeInfo) { + private IdeTestContext(IdeTestStartContext startContext, Path workingDirectory, WireMockRuntimeInfo wireMockRuntimeInfo) { - super(logger, workingDirectory, wireMockRuntimeInfo); - this.logger = logger; + super(startContext, workingDirectory, wireMockRuntimeInfo); this.gitContext = new GitContextMock(); } @@ -90,11 +87,11 @@ public static IdeTestContext of() { } /** - * @return the {@link IdeTestLogger}. + * @return the {@link IdeTestStartContext}. */ - public IdeTestLogger getLogger() { + public IdeTestStartContext getTestStartContext() { - return logger; + return (IdeTestStartContext) getStartContext(); } /** diff --git a/cli/src/test/java/com/devonfw/tools/ide/context/IdeTestContextAssertion.java b/cli/src/test/java/com/devonfw/tools/ide/context/IdeTestContextAssertion.java index 76a685eaaa..8a259bc311 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/context/IdeTestContextAssertion.java +++ b/cli/src/test/java/com/devonfw/tools/ide/context/IdeTestContextAssertion.java @@ -26,7 +26,7 @@ public IdeTestContextAssertion(IdeTestContext context) { */ public IdeTestLoggerAssertion log(IdeLogLevel level) { - return new IdeTestLoggerAssertion(context.getLogger().getEntries(), level); + return new IdeTestLoggerAssertion(context.getTestStartContext().getEntries(), level); } /** diff --git a/cli/src/test/java/com/devonfw/tools/ide/context/IdeTestContextMock.java b/cli/src/test/java/com/devonfw/tools/ide/context/IdeTestContextMock.java deleted file mode 100644 index 75c92e6829..0000000000 --- a/cli/src/test/java/com/devonfw/tools/ide/context/IdeTestContextMock.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.devonfw.tools.ide.context; - -/** - * Mock instance of {@link com.devonfw.tools.ide.context.IdeContext}. - * - * @see #get() - */ -public class IdeTestContextMock extends IdeSlf4jContext { - - private static final IdeTestContextMock INSTANCE = new IdeTestContextMock(); - - private IdeTestContextMock() { - - super(); - } - - @Override - protected boolean isMutable() { - - return false; - } - - /** - * @return the singleton mock instance of {@link com.devonfw.tools.ide.context.IdeContext}. Does NOT have {@link #getIdeHome() IDE_HOME}. - */ - public static IdeTestContextMock get() { - - return INSTANCE; - } - -} diff --git a/cli/src/test/java/com/devonfw/tools/ide/context/ProcessContextTestImpl.java b/cli/src/test/java/com/devonfw/tools/ide/context/ProcessContextTestImpl.java index a12b721a37..1d1d63ec16 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/context/ProcessContextTestImpl.java +++ b/cli/src/test/java/com/devonfw/tools/ide/context/ProcessContextTestImpl.java @@ -32,7 +32,7 @@ public ProcessResult run(ProcessMode processMode) { ProcessResult result = super.run(ProcessMode.DEFAULT_CAPTURE); // this hack is still required to capture test script output if (result.isSuccessful() && (processMode == ProcessMode.DEFAULT || processMode == ProcessMode.BACKGROUND)) { - result.log(IdeLogLevel.INFO, context); + result.log(IdeLogLevel.INFO); } return result; } diff --git a/cli/src/test/java/com/devonfw/tools/ide/environment/EnvironmentVariablesPropertiesFileTest.java b/cli/src/test/java/com/devonfw/tools/ide/environment/EnvironmentVariablesPropertiesFileTest.java index 25e58a7240..0ee2013957 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/environment/EnvironmentVariablesPropertiesFileTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/environment/EnvironmentVariablesPropertiesFileTest.java @@ -11,7 +11,6 @@ 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.log.IdeLogLevel; import com.devonfw.tools.ide.version.VersionIdentifier; @@ -80,7 +79,7 @@ void testSave(@TempDir Path tempDir) throws Exception { assertThat(lines).containsExactlyElementsOf(linesToWrite); EnvironmentVariablesPropertiesFile variables = new EnvironmentVariablesPropertiesFile(null, TYPE, - propertiesFilePath, IdeTestContextMock.get()); + propertiesFilePath, new IdeTestContext()); // act variables.set("var5", "5", true); @@ -125,7 +124,7 @@ void testSaveWithMissingParentFilePath(@TempDir Path tempDir) throws Exception { Path propertiesFilePath = tempDir.resolve("test.properties"); EnvironmentVariablesPropertiesFile variables = new EnvironmentVariablesPropertiesFile(null, TYPE, - propertiesFilePath, IdeTestContextMock.get()); + propertiesFilePath, new IdeTestContext()); // act variables.set("var1", "1.0", false); diff --git a/cli/src/test/java/com/devonfw/tools/ide/environment/EnvironmentVariablesPropertiesMock.java b/cli/src/test/java/com/devonfw/tools/ide/environment/EnvironmentVariablesPropertiesMock.java index 59f57753b7..25181a7619 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/environment/EnvironmentVariablesPropertiesMock.java +++ b/cli/src/test/java/com/devonfw/tools/ide/environment/EnvironmentVariablesPropertiesMock.java @@ -7,6 +7,9 @@ import java.util.Objects; import java.util.Set; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.context.IdeContext; /** @@ -14,6 +17,8 @@ */ public final class EnvironmentVariablesPropertiesMock extends EnvironmentVariablesMap { + private static final Logger LOG = LoggerFactory.getLogger(EnvironmentVariablesPropertiesMock.class); + private static final Path PROPERTIES_FILE_PATH = Path.of(DEFAULT_PROPERTIES); private static final Path LEGACY_PROPERTIES_FILE_PATH = Path.of(LEGACY_PROPERTIES); @@ -49,7 +54,7 @@ public EnvironmentVariablesPropertiesMock(AbstractEnvironmentVariables parent, E public void save() { if (this.modifiedVariables.isEmpty()) { - this.context.trace("No changes to save in properties file {}", getPropertiesFilePath()); + LOG.trace("No changes to save in properties file {}", getPropertiesFilePath()); return; } this.modifiedVariables.clear(); @@ -103,9 +108,9 @@ public String set(String name, String value, boolean export) { String oldValue = this.variables.put(name, value); boolean flagChanged = export != this.exportedVariables.contains(name); if (Objects.equals(value, oldValue) && !flagChanged) { - this.context.trace("Set variable '{}={}' caused no change in {}", name, value, getPropertiesFilePath()); + LOG.trace("Set variable '{}={}' caused no change in {}", name, value, getPropertiesFilePath()); } else { - this.context.debug("Set variable '{}={}' in {}", name, value, getPropertiesFilePath()); + LOG.debug("Set variable '{}={}' in {}", name, value, getPropertiesFilePath()); this.modifiedVariables.add(name); if (export && (value != null)) { this.exportedVariables.add(name); diff --git a/cli/src/test/java/com/devonfw/tools/ide/environment/IdeSystemTestImpl.java b/cli/src/test/java/com/devonfw/tools/ide/environment/IdeSystemTestImpl.java index 0486ce956b..aa9f4566bb 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/environment/IdeSystemTestImpl.java +++ b/cli/src/test/java/com/devonfw/tools/ide/environment/IdeSystemTestImpl.java @@ -4,31 +4,30 @@ import java.util.Map; import java.util.Properties; -import com.devonfw.tools.ide.log.IdeLogger; - /** * Extends {@link IdeSystemImpl} for testing. It will not modify your {@link System} and allows to modify environment variables for testing. */ public class IdeSystemTestImpl extends IdeSystemImpl { /** - * @param logger the {@link IdeLogger}. + * The constructor. */ - public IdeSystemTestImpl(IdeLogger logger) { + public IdeSystemTestImpl() { - this(logger, new Properties(), new HashMap<>()); + this(new Properties(), new HashMap<>()); this.environmentVariables.put("PATH", System.getenv("PATH")); } /** - * @param logger the {@link IdeLogger}. + * The constructor. + * * @param systemProperties the {@link System#getProperties() system properties} for testing. * @param environmentVariables the {@link System#getenv() environment variables} for testing. */ - public IdeSystemTestImpl(IdeLogger logger, Properties systemProperties, + public IdeSystemTestImpl(Properties systemProperties, Map environmentVariables) { - super(logger, systemProperties, environmentVariables); + super(systemProperties, environmentVariables); } /** @@ -49,11 +48,10 @@ public Properties getProperties() { } /** - * @param logger the {@link IdeLogger}. * @return a new instance of {@link IdeSystemTestImpl} initialized with {@link System} values but decoupled so changes do not affect {@link System}. */ - public static IdeSystemTestImpl ofSystemDefaults(IdeLogger logger) { + public static IdeSystemTestImpl ofSystemDefaults() { - return new IdeSystemTestImpl(logger, new Properties(System.getProperties()), new HashMap<>(System.getenv())); + return new IdeSystemTestImpl(new Properties(System.getProperties()), new HashMap<>(System.getenv())); } } diff --git a/cli/src/test/java/com/devonfw/tools/ide/environment/VariableLineTest.java b/cli/src/test/java/com/devonfw/tools/ide/environment/VariableLineTest.java index d8cdce43f0..00d44ca7a3 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/environment/VariableLineTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/environment/VariableLineTest.java @@ -7,18 +7,15 @@ import com.devonfw.tools.ide.environment.VariableLine.Empty; import com.devonfw.tools.ide.environment.VariableLine.Garbage; import com.devonfw.tools.ide.environment.VariableLine.Variable; -import com.devonfw.tools.ide.log.IdeSlf4jRootLogger; /** * Test of {@link VariableLine}. */ class VariableLineTest extends Assertions { - private static final IdeSlf4jRootLogger LOGGER = IdeSlf4jRootLogger.of(); - private VariableLine line(String line) { - return VariableLine.of(line, LOGGER, new VariableSource(EnvironmentVariablesType.RESOLVED, null)); + return VariableLine.of(line, new VariableSource(EnvironmentVariablesType.RESOLVED, null)); } /** diff --git a/cli/src/test/java/com/devonfw/tools/ide/io/FileAccessImplTest.java b/cli/src/test/java/com/devonfw/tools/ide/io/FileAccessImplTest.java index 6e6b4d4739..7cd4750ad8 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/io/FileAccessImplTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/io/FileAccessImplTest.java @@ -25,9 +25,7 @@ import org.junit.jupiter.api.io.TempDir; import com.devonfw.tools.ide.context.AbstractIdeContextTest; -import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.context.IdeTestContext; -import com.devonfw.tools.ide.context.IdeTestContextMock; /** * Test of {@link FileAccessImpl}. @@ -43,7 +41,7 @@ void testSymlinkAbsolute(@TempDir Path tempDir) { // relative links are checked in testRelativeLinksWorkAfterMoving // arrange - IdeContext context = IdeTestContextMock.get(); + IdeTestContext context = new IdeTestContext(); FileAccess fileAccess = new FileAccessImpl(context); Path dir = tempDir.resolve("parent"); createDirs(fileAccess, dir); @@ -65,7 +63,7 @@ void testSymlinkAbsolute(@TempDir Path tempDir) { void testSymlinkAbsolutePassingRelativeSource(@TempDir Path tempDir) { // arrange - IdeContext context = IdeTestContextMock.get(); + IdeTestContext context = new IdeTestContext(); FileAccess fileAccess = new FileAccessImpl(context); Path dir = tempDir.resolve("parent"); createDirs(fileAccess, dir); @@ -89,7 +87,7 @@ void testSymlinkAbsolutePassingRelativeSource(@TempDir Path tempDir) { void testSymlinkAbsoluteAsFallback(@TempDir Path tempDir) { // arrange - IdeContext context = IdeTestContextMock.get(); + IdeTestContext context = new IdeTestContext(); FileAccess fileAccess = new FileAccessImpl(context); Path dir = tempDir.resolve("parent"); createDirs(fileAccess, dir); @@ -112,7 +110,7 @@ void testSymlinkAbsoluteAsFallback(@TempDir Path tempDir) { void testSymlinkAbsoluteBreakAfterMoving(@TempDir Path tempDir) throws IOException { // arrange - IdeContext context = IdeTestContextMock.get(); + IdeTestContext context = new IdeTestContext(); FileAccess fileAccess = new FileAccessImpl(context); Path dir = tempDir.resolve("parent"); createDirs(fileAccess, dir); @@ -138,7 +136,7 @@ void testSymlinkAbsoluteBreakAfterMoving(@TempDir Path tempDir) throws IOExcepti void testSymlinkRelativeWorkAfterMovingPassingRelativeSource(@TempDir Path tempDir) { // arrange - IdeContext context = IdeTestContextMock.get(); + IdeTestContext context = new IdeTestContext(); FileAccess fileAccess = new FileAccessImpl(context); Path dir = tempDir.resolve("parent"); createDirs(fileAccess, dir); @@ -163,7 +161,7 @@ void testSymlinkRelativeWorkAfterMovingPassingRelativeSource(@TempDir Path tempD void testSymlinkRelativeWorkAfterMoving(@TempDir Path tempDir) { // arrange - IdeContext context = IdeTestContextMock.get(); + IdeTestContext context = new IdeTestContext(); FileAccess fileAccess = new FileAccessImpl(context); Path dir = tempDir.resolve("parent"); createDirs(fileAccess, dir); @@ -189,7 +187,7 @@ void testSymlinkWindowsJunctionsCanNotPointToFiles(@TempDir Path tempDir) throws // arrange WindowsSymlinkTestHelper.assumeSymlinksSupported(); - IdeContext context = IdeTestContextMock.get(); + IdeTestContext context = new IdeTestContext(); FileAccess fileAccess = context.getFileAccess(); Path file = tempDir.resolve("file"); Files.createFile(file); @@ -210,7 +208,7 @@ void testSymlinkWindowsJunctionsCanNotPointToFiles(@TempDir Path tempDir) throws void testSymlinkShortcutPaths(@TempDir Path tempDir) { // arrange - IdeContext context = IdeTestContextMock.get(); + IdeTestContext context = new IdeTestContext(); FileAccess fileAccess = new FileAccessImpl(context); Path dir = tempDir.resolve("parent"); createDirs(fileAccess, dir); @@ -447,7 +445,7 @@ private void assertSymlinkRead(Path link, Path trueTarget) { void testUnzip(@TempDir Path tempDir) { // arrange - IdeContext context = IdeTestContextMock.get(); + IdeTestContext context = new IdeTestContext(); // act context.getFileAccess() @@ -467,7 +465,7 @@ void testUnzip(@TempDir Path tempDir) { void testUntarWithNoneCompressionWithFilePermissions(@TempDir Path tempDir) { // arrange - IdeContext context = IdeTestContextMock.get(); + IdeTestContext context = new IdeTestContext(); if (context.getSystemInfo().isWindows()) { return; } @@ -489,7 +487,7 @@ void testUntarWithNoneCompressionWithFilePermissions(@TempDir Path tempDir) { void testUntarWithGzCompressionWithFilePermissions(@TempDir Path tempDir) { // arrange - IdeContext context = IdeTestContextMock.get(); + IdeTestContext context = new IdeTestContext(); if (context.getSystemInfo().isWindows()) { return; } @@ -512,7 +510,8 @@ void testUntarWithGzCompressionWithFilePermissions(@TempDir Path tempDir) { void testUntarWithBzip2CompressionWithFilePermissions(@TempDir Path tempDir) { // arrange - IdeContext context = IdeTestContextMock.get(); + IdeTestContext context = new IdeTestContext(); + new IdeTestContext(); if (context.getSystemInfo().isWindows()) { return; } @@ -543,7 +542,7 @@ void testUntarWithGzipCompressionWithSymbolicLink(@TempDir Path tempDir) { // arrange WindowsSymlinkTestHelper.assumeSymlinksSupported(); - IdeContext context = IdeTestContextMock.get(); + IdeTestContext context = new IdeTestContext(); Path linkTarGz = Path.of("src/test/resources/com/devonfw/tools/ide/io/link.tar.gz"); FileAccess fileAccess = context.getFileAccess(); @@ -577,7 +576,7 @@ void testGeneratePermissionString() { @Test void testDisabledExtractMovesArchive(@TempDir Path tempDir) { // arrange - IdeContext context = IdeTestContextMock.get(); + IdeTestContext context = new IdeTestContext(); FileAccessImpl fileAccess = new FileAccessImpl(context); Path downloadArchive = tempDir.resolve("downloaded.zip"); fileAccess.touch(downloadArchive); @@ -600,7 +599,7 @@ void testDisabledExtractMovesArchive(@TempDir Path tempDir) { @Test void testExtractTgzArchive(@TempDir Path tempDir) throws IOException { // arrange - IdeContext context = IdeTestContextMock.get(); + IdeTestContext context = new IdeTestContext(); FileAccessImpl fileAccess = new FileAccessImpl(context); Path downloadedTgz = tempDir.resolve("downloaded.tgz"); fileAccess.touch(downloadedTgz); @@ -642,7 +641,7 @@ void testExtractTgzArchive(@TempDir Path tempDir) throws IOException { */ @Test void testFindExistingFileInFolders(@TempDir Path tempDir) { - IdeContext context = IdeTestContextMock.get(); + IdeTestContext context = new IdeTestContext(); FileAccessImpl fileAccess = new FileAccessImpl(context); Path subfolder1 = tempDir.resolve("subfolder1"); fileAccess.mkdirs(subfolder1); @@ -728,7 +727,7 @@ void testDownloadSmallFileWithoutProgressBar(@TempDir Path tempDir) throws IOExc void testSymlinkOverwritesBrokenJunction(@TempDir Path tempDir) throws IOException { // arrange - IdeContext context = IdeTestContextMock.get(); + IdeTestContext context = new IdeTestContext(); FileAccess fileAccess = new FileAccessImpl(context); Path sourceDir = tempDir.resolve("source"); Path targetLink = tempDir.resolve("junction"); @@ -768,7 +767,7 @@ void testSymlinkOverwritesBrokenJunction(@TempDir Path tempDir) throws IOExcepti void testIsJunctionHandlesBrokenLinks(@TempDir Path tempDir) throws IOException { // arrange - IdeContext context = IdeTestContextMock.get(); + IdeTestContext context = new IdeTestContext(); FileAccess fileAccess = new FileAccessImpl(context); if (!context.getSystemInfo().isWindows()) { @@ -798,7 +797,7 @@ void testIsJunctionHandlesBrokenLinks(@TempDir Path tempDir) throws IOException fileAccess.symlink(newSource, brokenLink, false); assertThat(brokenLink.toRealPath()).isEqualTo(newSource); } else { - context.info("Test adapted for Windows environment - testing basic junction functionality"); + System.out.println("Test adapted for Windows environment - testing basic junction functionality"); // On Windows, just test that basic junction functionality works Path sourceDir = tempDir.resolve("source"); Path junctionLink = tempDir.resolve("junction"); @@ -818,7 +817,7 @@ void testIsJunctionHandlesBrokenLinks(@TempDir Path tempDir) throws IOException void testBinPath() { // arrange - FileAccess fileAccess = IdeTestContextMock.get().getFileAccess(); + FileAccess fileAccess = new IdeTestContext().getFileAccess(); Path projects = Path.of("src/test/resources/ide-projects"); Path rootPath = projects.resolve("basic/project/software/java"); Path binPath = rootPath.resolve("bin"); @@ -847,7 +846,7 @@ void testFindAncestor() { private void verifyFindAncestor(String path, String baseDir, int subfolderCount, String expectedResult) { - FileAccess fileAccess = IdeTestContextMock.get().getFileAccess(); + FileAccess fileAccess = new IdeTestContext().getFileAccess(); Path result = fileAccess.findAncestor(asPath(path), asPath(baseDir), subfolderCount); AbstractPathAssert assertion = assertThat(result).as("findAncestor(" + path + ", " + baseDir + ", " + subfolderCount); if (expectedResult == null) { @@ -868,7 +867,7 @@ private static Path asPath(String path) { void testIsNonEmptyFile(@TempDir Path tempDir) throws IOException { // arrange - FileAccess fileAccess = IdeTestContextMock.get().getFileAccess(); + FileAccess fileAccess = new IdeTestContext().getFileAccess(); // act + assert assertThat(fileAccess.isNonEmptyFile(tempDir)).isFalse(); diff --git a/cli/src/test/java/com/devonfw/tools/ide/io/IdeProgressBarTest.java b/cli/src/test/java/com/devonfw/tools/ide/io/IdeProgressBarTest.java index 2e4626b805..94ccd02d53 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/io/IdeProgressBarTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/io/IdeProgressBarTest.java @@ -26,48 +26,49 @@ class IdeProgressBarTest extends AbstractIdeContextTest { private static final String TEST_URL = "/os/windows_x64_url.tgz"; + @TempDir + Path tempDir; + /** * Tests if a download of a file with a valid content length was displaying an {@link IdeProgressBar} properly. * - * @param tempDir temporary directory to use. * @param wmRuntimeInfo wireMock server on a random port */ @Test - void testProgressBarDownloadWithValidContentLength(@TempDir Path tempDir, WireMockRuntimeInfo wmRuntimeInfo) { + void testProgressBarDownloadWithValidContentLength(WireMockRuntimeInfo wmRuntimeInfo) { stubFor(any(urlMatching("/os/.*")).willReturn( aResponse().withStatus(200).withBody(new byte[MAX_LENGTH]).withHeader("Content-Length", String.valueOf(MAX_LENGTH)))); - IdeContext context = newContext(tempDir); + IdeContext context = newContext(this.tempDir); FileAccess impl = context.getFileAccess(); - impl.download(wmRuntimeInfo.getHttpBaseUrl() + TEST_URL, tempDir.resolve("windows_x64_url.tgz")); - assertThat(tempDir.resolve("windows_x64_url.tgz")).exists(); + impl.download(wmRuntimeInfo.getHttpBaseUrl() + TEST_URL, this.tempDir.resolve("windows_x64_url.tgz")); + assertThat(this.tempDir.resolve("windows_x64_url.tgz")).exists(); assertProgressBar(context, "Downloading", MAX_LENGTH); } /** * Tests if {@link FileAccess#download(String, Path)} with missing content length is working properly. * - * @param tempDir temporary directory to use. * @param wmRuntimeInfo wireMock server on a random port */ @Test - void testProgressBarDownloadWithMissingContentLength(@TempDir Path tempDir, WireMockRuntimeInfo wmRuntimeInfo) { + void testProgressBarDownloadWithMissingContentLength(WireMockRuntimeInfo wmRuntimeInfo) { //arrange String taskName = "Downloading"; stubFor(any(urlMatching("/os/.*")).willReturn(aResponse().withStatus(200).withBody(new byte[MAX_LENGTH]))); - IdeTestContext context = newContext(tempDir); + IdeTestContext context = newContext(this.tempDir); FileAccess impl = context.getFileAccess(); //act String testUrl = wmRuntimeInfo.getHttpBaseUrl() + TEST_URL; - impl.download(testUrl, tempDir.resolve("windows_x64_url.tgz")); + impl.download(testUrl, this.tempDir.resolve("windows_x64_url.tgz")); //assert assertUnknownProgressBar(context, "Downloading", MAX_LENGTH); assertThat(context).logAtWarning().hasMessage( "Content-Length was not provided by download from " + testUrl); - assertThat(tempDir.resolve("windows_x64_url.tgz")).exists(); + assertThat(this.tempDir.resolve("windows_x64_url.tgz")).exists(); IdeProgressBarTestImpl progressBar = context.getProgressBarMap().get(taskName); assertThat(progressBar.getMaxSize()).isEqualTo(-1); diff --git a/cli/src/test/java/com/devonfw/tools/ide/io/IniFileImplTest.java b/cli/src/test/java/com/devonfw/tools/ide/io/IniFileImplTest.java index 231b3c789f..628c14a0fe 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/io/IniFileImplTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/io/IniFileImplTest.java @@ -10,7 +10,7 @@ import com.devonfw.tools.ide.context.AbstractIdeContextTest; import com.devonfw.tools.ide.context.IdeContext; -import com.devonfw.tools.ide.context.IdeTestContextMock; +import com.devonfw.tools.ide.context.IdeTestContext; import com.devonfw.tools.ide.io.ini.IniFile; import com.devonfw.tools.ide.io.ini.IniFileImpl; import com.devonfw.tools.ide.io.ini.IniSection; @@ -64,7 +64,7 @@ private IniFile getIniFile(IdeContext context, String content) throws IOExceptio @Test void testGetSectionNames() throws IOException { // arrange - IdeContext context = IdeTestContextMock.get(); + IdeTestContext context = new IdeTestContext(); IniFile iniFileA = getIniFile(context, iniContentWithInitialProperties); IniFile iniFIleB = getIniFile(context, iniContent); @@ -88,7 +88,7 @@ void testGetSectionNames() throws IOException { @Test void testRemoveSection() throws IOException { // arrange - IdeContext context = IdeTestContextMock.get(); + IdeContext context = new IdeTestContext(); IniFile iniFileA = getIniFile(context, iniContentWithInitialProperties); IniFile iniFileB = getIniFile(context, iniContent); String[] expectedSections = { "filter \"lfs\"", "credential", "credential.details", "core" }; @@ -113,7 +113,7 @@ void testRemoveSection() throws IOException { @Test void testGetSection() throws IOException { // arrange - IdeContext context = IdeTestContextMock.get(); + IdeContext context = new IdeTestContext(); IniFile iniFileA = getIniFile(context, iniContentWithInitialProperties); IniFile iniFileB = getIniFile(context, iniContent); String sectionName = "credential"; @@ -143,7 +143,7 @@ void testGetSection() throws IOException { @Test void testGetOrCreateSection() throws IOException { // arrange - IdeContext context = IdeTestContextMock.get(); + IdeContext context = new IdeTestContext(); IniFile iniFileA = getIniFile(context, iniContentWithInitialProperties); IniFile iniFileB = getIniFile(context, iniContent); String sectionName = "credential"; @@ -186,7 +186,7 @@ void testGetOrCreateSection() throws IOException { @Test void testToString() throws IOException { // arrange - IdeContext context = IdeTestContextMock.get(); + IdeContext context = new IdeTestContext(); IniFile iniFileA = getIniFile(context, iniContentWithInitialProperties); IniFile iniFileB = getIniFile(context, iniContent); @@ -207,7 +207,7 @@ void testToString() throws IOException { @Test void testAddProperty() throws IOException { // arrange - IdeContext context = IdeTestContextMock.get(); + IdeContext context = new IdeTestContext(); IniFile iniFileB = getIniFile(context, iniContent); String expectedContent = "variable = value\n" + iniContent; diff --git a/cli/src/main/java/com/devonfw/tools/ide/log/IdeLogListenerCollector.java b/cli/src/test/java/com/devonfw/tools/ide/log/IdeLogListenerCollector.java similarity index 89% rename from cli/src/main/java/com/devonfw/tools/ide/log/IdeLogListenerCollector.java rename to cli/src/test/java/com/devonfw/tools/ide/log/IdeLogListenerCollector.java index 5950be0c78..6099578011 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/log/IdeLogListenerCollector.java +++ b/cli/src/test/java/com/devonfw/tools/ide/log/IdeLogListenerCollector.java @@ -1,7 +1,7 @@ package com.devonfw.tools.ide.log; -import java.util.ArrayList; import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; /** * Implementation of {@link IdeLogListener} that collects all events as {@link IdeLogEntry}. @@ -15,7 +15,7 @@ public class IdeLogListenerCollector extends IdeLogListenerBuffer { */ public IdeLogListenerCollector() { super(false); - this.entries = new ArrayList<>(512); + this.entries = new CopyOnWriteArrayList<>(); } /** diff --git a/cli/src/test/java/com/devonfw/tools/ide/log/IdeSlf4jRootLogger.java b/cli/src/test/java/com/devonfw/tools/ide/log/IdeSlf4jRootLogger.java deleted file mode 100644 index 5aa4e17336..0000000000 --- a/cli/src/test/java/com/devonfw/tools/ide/log/IdeSlf4jRootLogger.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.devonfw.tools.ide.log; - -import java.util.HashMap; -import java.util.Map; - -/** - * {@link IdeLogger} that delegates to SLF4J used for testing. - */ -public class IdeSlf4jRootLogger implements IdeLogger { - - private static final IdeSlf4jRootLogger INSTANCE = new IdeSlf4jRootLogger(); - - private final Map loggers; - - /** - * The constructor. - */ - public IdeSlf4jRootLogger() { - - super(); - this.loggers = new HashMap<>(); - for (IdeLogLevel level : IdeLogLevel.values()) { - this.loggers.put(level, new IdeSubLoggerSlf4j(level, null)); - } - } - - @Override - public IdeSubLogger level(IdeLogLevel level) { - - return this.loggers.get(level); - } - - /** - * @return the singleton instance. - */ - public static IdeSlf4jRootLogger of() { - - return INSTANCE; - } - -} diff --git a/cli/src/test/java/com/devonfw/tools/ide/log/IdeSubLoggerSlf4j.java b/cli/src/test/java/com/devonfw/tools/ide/log/IdeSubLoggerSlf4j.java deleted file mode 100644 index e39bb3f283..0000000000 --- a/cli/src/test/java/com/devonfw/tools/ide/log/IdeSubLoggerSlf4j.java +++ /dev/null @@ -1,60 +0,0 @@ -package com.devonfw.tools.ide.log; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.slf4j.event.Level; -import org.slf4j.spi.LoggingEventBuilder; - -/** - * Implementation of {@link IdeSubLogger} for testing that delegates to slf4j. - */ -public class IdeSubLoggerSlf4j extends AbstractIdeSubLogger { - - private static final Logger LOG = LoggerFactory.getLogger(IdeSubLoggerSlf4j.class); - - private final Level logLevel; - - /** - * The constructor. - * - * @param level the {@link #getLevel() log-level}. - */ - public IdeSubLoggerSlf4j(IdeLogLevel level) { - this(level, null); - } - - /** - * The constructor. - * - * @param level the {@link #getLevel() log-level}. - */ - public IdeSubLoggerSlf4j(IdeLogLevel level, IdeLogListener listener) { - - super(level, false, IdeLogExceptionDetails.NONE, listener); - this.logLevel = switch (level) { - case TRACE -> Level.TRACE; - case DEBUG -> Level.DEBUG; - case WARNING -> Level.WARN; - case ERROR -> Level.ERROR; - default -> Level.INFO; - }; - } - - @Override - protected void doLog(String message, Throwable error) { - - LoggingEventBuilder builder = LOG.atLevel(this.logLevel); - String msg = message; - if (error != null) { - builder = builder.setCause(error); - if (msg == null) { - msg = error.toString(); - } - } - if (this.level.isCustom()) { - msg = this.level.name() + ":" + message; - } - builder.log(msg); - } - -} diff --git a/cli/src/test/java/com/devonfw/tools/ide/log/IdeTestLogger.java b/cli/src/test/java/com/devonfw/tools/ide/log/IdeTestLogger.java deleted file mode 100644 index ca889bbc22..0000000000 --- a/cli/src/test/java/com/devonfw/tools/ide/log/IdeTestLogger.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.devonfw.tools.ide.log; - -import java.util.ArrayList; -import java.util.List; - -import com.devonfw.tools.ide.context.IdeStartContextImpl; - -/** - * Extends {@link IdeStartContextImpl} for testing. - */ -public class IdeTestLogger extends IdeStartContextImpl { - - private final IdeLogListenerCollector collector; - - public IdeTestLogger() { - - this(IdeLogLevel.DEBUG); - } - - public IdeTestLogger(IdeLogLevel minLogLevel) { - - this(new ArrayList<>(), minLogLevel, new IdeLogListenerCollector()); - } - - private IdeTestLogger(List entries, IdeLogLevel minLogLevel, IdeLogListenerCollector collector) { - - super(minLogLevel, level -> new IdeSubLoggerSlf4j(level, collector)); - this.collector = collector; - } - - /** - * @return the {@link List} of {@link IdeLogEntry} that have been logged for test assertions. - */ - public List getEntries() { - - return this.collector.getEntries(); - } -} diff --git a/cli/src/test/java/com/devonfw/tools/ide/log/IdeTestLoggerAssertion.java b/cli/src/test/java/com/devonfw/tools/ide/log/IdeTestLoggerAssertion.java index e67bc6c5be..3676fb1759 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/log/IdeTestLoggerAssertion.java +++ b/cli/src/test/java/com/devonfw/tools/ide/log/IdeTestLoggerAssertion.java @@ -21,7 +21,7 @@ public IdeTestLoggerAssertion(List entries, IdeLogLevel level) { } /** - * @param message the expected {@link com.devonfw.tools.ide.log.IdeSubLogger#log(String) log message}. + * @param message the expected {@link IdeLogEntry#message() log message}. * @return this assertion itself for fluent API calls. */ public IdeTestLoggerAssertion hasMessage(String message) { @@ -30,8 +30,7 @@ public IdeTestLoggerAssertion hasMessage(String message) { } /** - * @param message the {@link String} expected to be {@link String#contains(CharSequence) contained} in a - * {@link com.devonfw.tools.ide.log.IdeSubLogger#log(String) log message}. + * @param message the {@link String} expected to be {@link String#contains(CharSequence) contained} in a {@link IdeLogEntry}. * @return this assertion itself for fluent API calls. */ public IdeTestLoggerAssertion hasMessageContaining(String message) { @@ -40,7 +39,7 @@ public IdeTestLoggerAssertion hasMessageContaining(String message) { } /** - * @param message the {@link com.devonfw.tools.ide.log.IdeSubLogger#log(String) log message} that is not expected and should not have been logged. + * @param message the {@link IdeLogEntry#message() log message} that is not expected and should not have been logged. * @return this assertion itself for fluent API calls. */ public IdeTestLoggerAssertion hasNoMessage(String message) { @@ -49,8 +48,7 @@ public IdeTestLoggerAssertion hasNoMessage(String message) { } /** - * @param message the {@link String} expected not be {@link String#contains(CharSequence) contained} in any - * {@link com.devonfw.tools.ide.log.IdeSubLogger#log(String) log message}. + * @param message the {@link String} expected not be {@link String#contains(CharSequence) contained} in any {@link IdeLogEntry}. * @return this assertion itself for fluent API calls. */ public IdeTestLoggerAssertion hasNoMessageContaining(String message) { @@ -69,7 +67,7 @@ public IdeTestLoggerAssertion hasNoEntryWithException() { } /** - * @param messages the expected {@link com.devonfw.tools.ide.log.IdeSubLogger#log(String) log message}s in order. + * @param messages the expected {@link IdeLogEntry#message()} message}s in order. * @return this assertion itself for fluent API calls. */ public IdeTestLoggerAssertion hasEntries(String... messages) { diff --git a/cli/src/test/java/com/devonfw/tools/ide/log/IdeTestStartContext.java b/cli/src/test/java/com/devonfw/tools/ide/log/IdeTestStartContext.java new file mode 100644 index 0000000000..4b174eb778 --- /dev/null +++ b/cli/src/test/java/com/devonfw/tools/ide/log/IdeTestStartContext.java @@ -0,0 +1,37 @@ +package com.devonfw.tools.ide.log; + +import java.util.List; + +import com.devonfw.tools.ide.context.IdeStartContextImpl; + +/** + * Extends {@link IdeStartContextImpl} for testing. + */ +public class IdeTestStartContext extends IdeStartContextImpl { + + private final IdeLogListenerCollector collector; + + /** + * The constructor. + * + * @param logLevelConsole the {@link IdeLogLevel} acting as threshold for the console. + */ + public IdeTestStartContext(IdeLogLevel logLevelConsole) { + + this(logLevelConsole, new IdeLogListenerCollector()); + } + + private IdeTestStartContext(IdeLogLevel logLevelConsole, IdeLogListenerCollector logListener) { + + super(logLevelConsole, logListener); + this.collector = logListener; + } + + /** + * @return the {@link List} of {@link IdeLogEntry} that have been logged for test assertions. + */ + public List getEntries() { + + return this.collector.getEntries(); + } +} diff --git a/cli/src/test/java/com/devonfw/tools/ide/merge/xml/XmlMergerTest.java b/cli/src/test/java/com/devonfw/tools/ide/merge/xml/XmlMergerTest.java index c0f1d52a51..e3be322fb1 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/merge/xml/XmlMergerTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/merge/xml/XmlMergerTest.java @@ -17,7 +17,6 @@ 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; @@ -51,7 +50,7 @@ void testMerger(Path folder, @TempDir Path tempDir) throws Exception { Path targetPath = tempDir.resolve(TARGET_XML); Path resultPath = folder.resolve(RESULT_XML); Files.copy(folder.resolve(TARGET_XML), targetPath, REPLACE_EXISTING); - IdeTestContextMock context = IdeTestContextMock.get(); + IdeTestContext context = new IdeTestContext(); EnvironmentVariablesPropertiesMock mockVariables = new EnvironmentVariablesPropertiesMock(null, EnvironmentVariablesType.SETTINGS, context); mockVariables.set("JAVA_HOME", "/projects/myproject", false); mockVariables.set("JAVA_VERSION", "21", false); diff --git a/cli/src/test/java/com/devonfw/tools/ide/migration/IdeMigratorTest.java b/cli/src/test/java/com/devonfw/tools/ide/migration/IdeMigratorTest.java index 87b6d7cc3f..01365bc96e 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/migration/IdeMigratorTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/migration/IdeMigratorTest.java @@ -3,6 +3,8 @@ import java.util.List; import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.devonfw.tools.ide.context.AbstractIdeContextTest; import com.devonfw.tools.ide.context.IdeContext; @@ -14,6 +16,8 @@ */ class IdeMigratorTest extends AbstractIdeContextTest { + private static final Logger LOG = LoggerFactory.getLogger(IdeMigratorTest.class); + /** Test that no migration is executed when outside of project. */ @Test void testDoesNothingWithoutIdeHome() { @@ -77,7 +81,7 @@ public Dummy202501002() { @Override public void run(IdeContext context) { - context.info("202501002 migration was done"); + LOG.info("202501002 migration was done"); } } @@ -90,7 +94,7 @@ public Dummy202502003() { @Override public void run(IdeContext context) { - context.info("202502003 migration completed"); + LOG.info("202502003 migration completed"); } } diff --git a/cli/src/test/java/com/devonfw/tools/ide/os/MacOsHelperTest.java b/cli/src/test/java/com/devonfw/tools/ide/os/MacOsHelperTest.java index d694301281..3c11e90a0d 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/os/MacOsHelperTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/os/MacOsHelperTest.java @@ -23,7 +23,7 @@ void testJava() { // arrange String tool = "java"; Path rootDir = APPS_DIR.resolve(tool); - MacOsHelper helper = new MacOsHelper(CONTEXT.getFileAccess(), SystemInfoMock.MAC_X64, CONTEXT); + MacOsHelper helper = new MacOsHelper(CONTEXT.getFileAccess(), SystemInfoMock.MAC_X64); // act Path linkDir = helper.findLinkDir(rootDir, tool); // assert @@ -37,7 +37,7 @@ void testSpecial() { // arrange String tool = "special"; Path rootDir = APPS_DIR.resolve(tool); - MacOsHelper helper = new MacOsHelper(CONTEXT.getFileAccess(), SystemInfoMock.MAC_X64, CONTEXT); + MacOsHelper helper = new MacOsHelper(CONTEXT.getFileAccess(), SystemInfoMock.MAC_X64); // act Path linkDir = helper.findLinkDir(rootDir, tool); // assert @@ -51,7 +51,7 @@ void testNotMac() { // arrange String tool = "java"; Path rootDir = APPS_DIR.resolve(tool); - MacOsHelper helper = new MacOsHelper(CONTEXT.getFileAccess(), SystemInfoMock.LINUX_X64, CONTEXT); + MacOsHelper helper = new MacOsHelper(CONTEXT.getFileAccess(), SystemInfoMock.LINUX_X64); // act Path linkDir = helper.findLinkDir(rootDir, tool); // assert @@ -65,7 +65,7 @@ void testJmc() { // arrange String tool = "jmc"; Path rootDir = APPS_DIR.resolve(tool); - MacOsHelper helper = new MacOsHelper(CONTEXT.getFileAccess(), SystemInfoMock.MAC_X64, CONTEXT); + MacOsHelper helper = new MacOsHelper(CONTEXT.getFileAccess(), SystemInfoMock.MAC_X64); // act Path linkDir = helper.findLinkDir(rootDir, tool); // assert diff --git a/cli/src/test/java/com/devonfw/tools/ide/os/WindowsHelperImplTest.java b/cli/src/test/java/com/devonfw/tools/ide/os/WindowsHelperImplTest.java index b9c8f95cde..85935fb72a 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/os/WindowsHelperImplTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/os/WindowsHelperImplTest.java @@ -7,7 +7,7 @@ import com.devonfw.tools.ide.context.AbstractIdeContextTest; import com.devonfw.tools.ide.context.AbstractIdeTestContext; -import com.devonfw.tools.ide.context.IdeSlf4jContext; +import com.devonfw.tools.ide.context.IdeTestContext; /** * Tests for {@link WindowsHelperImpl}. @@ -20,7 +20,7 @@ class WindowsHelperImplTest extends AbstractIdeContextTest { @Test void testWindowsHelperParseRegString() { // arrange - AbstractIdeTestContext context = new IdeSlf4jContext(); + AbstractIdeTestContext context = new IdeTestContext(); WindowsHelperImpl helper = new WindowsHelperImpl(context); List output = new ArrayList<>(); output.add(""); @@ -39,7 +39,7 @@ void testWindowsHelperParseRegString() { @Test void testWindowsHelperParseEmptyRegStringReturnsNull() { // arrange - AbstractIdeTestContext context = new IdeSlf4jContext(); + AbstractIdeTestContext context = new IdeTestContext(); WindowsHelperImpl helper = new WindowsHelperImpl(context); List output = new ArrayList<>(); // act diff --git a/cli/src/test/java/com/devonfw/tools/ide/property/BooleanPropertyTest.java b/cli/src/test/java/com/devonfw/tools/ide/property/BooleanPropertyTest.java index 9935bb4706..432f921e8c 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/property/BooleanPropertyTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/property/BooleanPropertyTest.java @@ -6,7 +6,7 @@ import org.junit.jupiter.api.Test; import com.devonfw.tools.ide.context.IdeContext; -import com.devonfw.tools.ide.context.IdeTestContextMock; +import com.devonfw.tools.ide.context.IdeTestContext; /** * Test of {@link BooleanProperty}. @@ -15,7 +15,7 @@ class BooleanPropertyTest { @Test void testParse() { - IdeContext context = IdeTestContextMock.get(); + IdeContext context = new IdeTestContext(); BooleanProperty boolProp = new BooleanProperty("name", false, "alias"); assertThat(boolProp.parse("true", context)).isTrue(); diff --git a/cli/src/test/java/com/devonfw/tools/ide/property/CommandletPropertyTest.java b/cli/src/test/java/com/devonfw/tools/ide/property/CommandletPropertyTest.java index 9015efb1b2..ca3c841723 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/property/CommandletPropertyTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/property/CommandletPropertyTest.java @@ -10,7 +10,7 @@ import com.devonfw.tools.ide.completion.CompletionCandidateCollector; import com.devonfw.tools.ide.completion.CompletionCandidateCollectorDefault; import com.devonfw.tools.ide.context.IdeContext; -import com.devonfw.tools.ide.context.IdeTestContextMock; +import com.devonfw.tools.ide.context.IdeTestContext; import com.devonfw.tools.ide.tool.helm.Helm; import com.devonfw.tools.ide.tool.intellij.Intellij; @@ -23,7 +23,7 @@ class CommandletPropertyTest { void testCompleteValue() { // arrange - IdeContext context = IdeTestContextMock.get(); + IdeContext context = new IdeTestContext(); String[] expectedCandidates = { "help", "helm" }; String input = "he"; CompletionCandidateCollector collector = new CompletionCandidateCollectorDefault(context); @@ -40,7 +40,7 @@ void testCompleteValue() { void testParse() { // arrange - IdeContext context = IdeTestContextMock.get(); + IdeContext context = new IdeTestContext(); // act CommandletProperty cmdProp = new CommandletProperty("", false, ""); diff --git a/cli/src/test/java/com/devonfw/tools/ide/property/EnumPropertyTest.java b/cli/src/test/java/com/devonfw/tools/ide/property/EnumPropertyTest.java index 6f942a357c..769ff113bb 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/property/EnumPropertyTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/property/EnumPropertyTest.java @@ -10,7 +10,7 @@ import com.devonfw.tools.ide.completion.CompletionCandidateCollector; import com.devonfw.tools.ide.completion.CompletionCandidateCollectorDefault; import com.devonfw.tools.ide.context.IdeContext; -import com.devonfw.tools.ide.context.IdeTestContextMock; +import com.devonfw.tools.ide.context.IdeTestContext; /** * Test of {@link EnumProperty}. @@ -32,7 +32,7 @@ void testGetValueType() { @Test void testParse() { - IdeContext context = IdeTestContextMock.get(); + IdeContext context = new IdeTestContext(); EnumProperty enumProp = new EnumProperty<>("", false, "", TestEnum.class); assertThat(enumProp.parse("elementzero", context)).isEqualTo(TestEnum.ELEMENTZERO); @@ -42,7 +42,7 @@ void testParse() { @Test void testCompleteValue() { - IdeContext context = IdeTestContextMock.get(); + IdeContext context = new IdeTestContext(); String[] expectedCandidates = { "elementzero", "elementone", "elementtwo" }; String input = "ele"; CompletionCandidateCollector collector = new CompletionCandidateCollectorDefault(context); diff --git a/cli/src/test/java/com/devonfw/tools/ide/property/LocalePropertyTest.java b/cli/src/test/java/com/devonfw/tools/ide/property/LocalePropertyTest.java index 34588c0f85..8ccdac5f90 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/property/LocalePropertyTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/property/LocalePropertyTest.java @@ -10,7 +10,7 @@ import com.devonfw.tools.ide.completion.CompletionCandidateCollector; import com.devonfw.tools.ide.completion.CompletionCandidateCollectorDefault; import com.devonfw.tools.ide.context.IdeContext; -import com.devonfw.tools.ide.context.IdeTestContextMock; +import com.devonfw.tools.ide.context.IdeTestContext; /** * Test of {@link LocaleProperty}. @@ -22,7 +22,7 @@ class LocalePropertyTest extends Assertions { void testGermany() { // arrange - IdeContext context = IdeTestContextMock.get(); + IdeContext context = new IdeTestContext(); Locale germany = Locale.GERMANY; // act LocaleProperty property = new LocaleProperty("--locale", true, null); @@ -39,7 +39,7 @@ void testGermany() { void testCompletion() { // arrange - IdeContext context = IdeTestContextMock.get(); + IdeTestContext context = new IdeTestContext(); String[] expectedCandidates = { "de", "de-AT", "de-BE", "de-CH", "de-DE", "de-IT", "de-LI", "de-LU", "de-Latn-DE" }; String input = "de"; CompletionCandidateCollector collector = new CompletionCandidateCollectorDefault(context); diff --git a/cli/src/test/java/com/devonfw/tools/ide/property/NumberPropertyTest.java b/cli/src/test/java/com/devonfw/tools/ide/property/NumberPropertyTest.java index b8719743ca..6210b80580 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/property/NumberPropertyTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/property/NumberPropertyTest.java @@ -6,7 +6,7 @@ import org.junit.jupiter.api.Test; import com.devonfw.tools.ide.context.IdeContext; -import com.devonfw.tools.ide.context.IdeTestContextMock; +import com.devonfw.tools.ide.context.IdeTestContext; /** * Test of {@link NumberProperty}. @@ -16,7 +16,7 @@ class NumberPropertyTest { @Test void testParse() { // arrange - IdeContext context = IdeTestContextMock.get(); + IdeContext context = new IdeTestContext(); // act NumberProperty numberProp = new NumberProperty("", false, ""); diff --git a/cli/src/test/java/com/devonfw/tools/ide/property/ToolPropertyTest.java b/cli/src/test/java/com/devonfw/tools/ide/property/ToolPropertyTest.java index 16a4f17240..11d028c48c 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/property/ToolPropertyTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/property/ToolPropertyTest.java @@ -10,7 +10,7 @@ import com.devonfw.tools.ide.completion.CompletionCandidateCollector; import com.devonfw.tools.ide.completion.CompletionCandidateCollectorDefault; import com.devonfw.tools.ide.context.IdeContext; -import com.devonfw.tools.ide.context.IdeTestContextMock; +import com.devonfw.tools.ide.context.IdeTestContext; import com.devonfw.tools.ide.tool.intellij.Intellij; import com.devonfw.tools.ide.tool.java.Java; @@ -21,7 +21,7 @@ class ToolPropertyTest { @Test void testCompleteValue() { - IdeContext context = IdeTestContextMock.get(); + IdeContext context = new IdeTestContext(); String[] expectedCandidates = { "az", "android-studio", "aws" }; String input = "a"; CompletionCandidateCollector collector = new CompletionCandidateCollectorDefault(context); @@ -34,7 +34,7 @@ void testCompleteValue() { @Test void testParse() { - IdeContext context = IdeTestContextMock.get(); + IdeContext context = new IdeTestContext(); ToolProperty toolProp = new ToolProperty("", false, ""); assertThat(toolProp.parse("intellij", context)).isInstanceOf(Intellij.class); diff --git a/cli/src/test/java/com/devonfw/tools/ide/property/VersionPropertyTest.java b/cli/src/test/java/com/devonfw/tools/ide/property/VersionPropertyTest.java index d17d5edab5..1105b1f441 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/property/VersionPropertyTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/property/VersionPropertyTest.java @@ -11,7 +11,7 @@ import com.devonfw.tools.ide.completion.CompletionCandidateCollector; import com.devonfw.tools.ide.completion.CompletionCandidateCollectorDefault; import com.devonfw.tools.ide.context.IdeContext; -import com.devonfw.tools.ide.context.IdeTestContextMock; +import com.devonfw.tools.ide.context.IdeTestContext; import com.devonfw.tools.ide.version.VersionIdentifier; /** @@ -21,7 +21,7 @@ class VersionPropertyTest { @Test void testParse() { - IdeContext context = IdeTestContextMock.get(); + IdeContext context = new IdeTestContext(); VersionProperty versionProp = new VersionProperty("", false, ""); assertThat(versionProp.parse("1", context)).isEqualTo(VersionIdentifier.of("1")); @@ -34,7 +34,7 @@ void testParse() { */ @Test void testCompleteValueUnfitCommandlet() { - IdeContext context = IdeTestContextMock.get(); + IdeContext context = new IdeTestContext(); CompletionCandidateCollector collector = new CompletionCandidateCollectorDefault(context); VersionProperty versionProp = new VersionProperty("", false, ""); @@ -49,7 +49,7 @@ void testCompleteValueUnfitCommandlet() { */ @Test void testCompleteValuePatternGiven() { - IdeContext context = IdeTestContextMock.get(); + IdeContext context = new IdeTestContext(); String anyVersion = "*"; String anyVersionAfter2 = "2.*"; CompletionCandidateCollector collector = new CompletionCandidateCollectorDefault(context); diff --git a/cli/src/test/java/com/devonfw/tools/ide/step/StepTest.java b/cli/src/test/java/com/devonfw/tools/ide/step/StepTest.java index 8f6eb4f4d8..0a5b87d12c 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/step/StepTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/step/StepTest.java @@ -5,6 +5,7 @@ import com.devonfw.tools.ide.context.AbstractIdeContextTest; import com.devonfw.tools.ide.context.IdeTestContext; import com.devonfw.tools.ide.log.IdeLogEntry; +import com.devonfw.tools.ide.log.IdeLogLevel; /** * Test of {@link Step}. @@ -15,7 +16,7 @@ class StepTest extends AbstractIdeContextTest { void testValidUsageSuccess() { // arrage - IdeTestContext context = newContext(PROJECT_BASIC, "project", false); + IdeTestContext context = newContext(PROJECT_BASIC, "project", false, null, IdeLogLevel.TRACE); // act Step step = context.newStep("Test-Step"); try { @@ -36,7 +37,7 @@ void testValidUsageSuccess() { void testValidUsageSuccessSilent() { // arrage - IdeTestContext context = newContext(PROJECT_BASIC, "project", false); + IdeTestContext context = newContext(PROJECT_BASIC, "project", false, null, IdeLogLevel.TRACE); // act Step step = context.newStep(true, "Test-Step", "arg1", "arg2"); try { @@ -61,7 +62,7 @@ void testValidUsageSuccessSilent() { void testValidUsageError() { // arrage - IdeTestContext context = newContext(PROJECT_BASIC, "project", false); + IdeTestContext context = newContext(PROJECT_BASIC, "project", false, null, IdeLogLevel.TRACE); // act Step step = context.newStep("Test-Step"); try { @@ -82,14 +83,14 @@ void testValidUsageError() { void testInvalidUsageSuccessError() { // arrage - IdeTestContext context = newContext(PROJECT_BASIC, "project", false); + IdeTestContext context = newContext(PROJECT_BASIC, "project", false, null, IdeLogLevel.TRACE); // act Step step = context.newStep("Test-Step"); try { step.success("The Test-Step succeeded as expected"); throw new IllegalStateException("unexpected situation!"); } catch (IllegalStateException e) { - step.error(e); + step.error(e, e.toString()); } finally { step.close(); } @@ -107,7 +108,7 @@ void testInvalidUsageSuccessError() { void testInvalidUsageErrorSuccess() { // arrage - IdeTestContext context = newContext(PROJECT_BASIC, "project", false); + IdeTestContext context = newContext(PROJECT_BASIC, "project", false, null, IdeLogLevel.TRACE); // act Step step = context.newStep("Test-Step"); try { diff --git a/cli/src/test/java/com/devonfw/tools/ide/tool/LocalToolCommandletTest.java b/cli/src/test/java/com/devonfw/tools/ide/tool/LocalToolCommandletTest.java index dec62d8e0e..c5f3f34df5 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/tool/LocalToolCommandletTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/tool/LocalToolCommandletTest.java @@ -131,7 +131,7 @@ void testRunToolWithDependencies() { private static void runIntellijAndCheckInstallationWithJavaDependency(IdeTestContext context) { // arrange - context.getLogger().getEntries().clear(); // clear logs from previous run(s) + context.getTestStartContext().getEntries().clear(); // clear logs from previous run(s) Intellij intellij = context.getCommandletManager().getCommandlet(Intellij.class); // act intellij.run(); diff --git a/cli/src/test/java/com/devonfw/tools/ide/tool/custom/CustomToolsMapperTest.java b/cli/src/test/java/com/devonfw/tools/ide/tool/custom/CustomToolsMapperTest.java index 4fbddc8ed8..cdc644432c 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/tool/custom/CustomToolsMapperTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/tool/custom/CustomToolsMapperTest.java @@ -9,7 +9,6 @@ import com.devonfw.tools.ide.context.AbstractIdeTestContext; import com.devonfw.tools.ide.context.IdeContext; -import com.devonfw.tools.ide.context.IdeSlf4jContext; import com.devonfw.tools.ide.context.IdeTestContext; import com.devonfw.tools.ide.os.OperatingSystem; import com.devonfw.tools.ide.os.SystemArchitecture; @@ -43,7 +42,7 @@ void testReadCustomToolsFromLegacyConfig() { IdeContext context = new IdeTestContext(); String legacyProperties = "(jboss-eap:7.1.4.GA:all:https://host.tld/projects/my-project firefox:70.0.1:all:)"; // act - CustomTools customTools = CustomToolsMapper.parseCustomToolsFromLegacyConfig(legacyProperties, context); + CustomTools customTools = CustomToolsMapper.parseCustomToolsFromLegacyConfig(legacyProperties); // assert assertThat(customTools.url()).isEqualTo("https://host.tld/projects/my-project"); assertThat(customTools.tools()).containsExactly(new CustomTool("jboss-eap", "7.1.4.GA", true, true, @@ -57,7 +56,7 @@ void testReadEmptyCustomToolsFromLegacyConfig() { IdeContext context = new IdeTestContext(); String legacyProperties = "()"; // act - CustomTools customTools = CustomToolsMapper.parseCustomToolsFromLegacyConfig(legacyProperties, context); + CustomTools customTools = CustomToolsMapper.parseCustomToolsFromLegacyConfig(legacyProperties); // assert assertThat(customTools).isNull(); } @@ -68,7 +67,7 @@ void testReadFaultyCustomToolsFromLegacyConfig() { IdeContext context = new IdeTestContext(); String legacyProperties = "(jboss-eap:7.1.4.GA:all)"; // act - CustomTools customTools = CustomToolsMapper.parseCustomToolsFromLegacyConfig(legacyProperties, context); + CustomTools customTools = CustomToolsMapper.parseCustomToolsFromLegacyConfig(legacyProperties); // assert assertThat(customTools).isNull(); } @@ -80,7 +79,7 @@ void testReadFaultyCustomToolsFromLegacyConfig() { void testProperConvertFromCustomToolsJsonToCustomToolMetaData() { // arrange - AbstractIdeTestContext context = new IdeSlf4jContext(Path.of("")); + AbstractIdeTestContext context = new IdeTestContext(); context.setSystemInfo(SystemInfoMock.LINUX_X64); String name = "jboss-eap"; String version = "7.4.5.GA"; diff --git a/cli/src/test/java/com/devonfw/tools/ide/tool/dotnet/DotNetTest.java b/cli/src/test/java/com/devonfw/tools/ide/tool/dotnet/DotNetTest.java index 4ba8c644da..fbb783a889 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/tool/dotnet/DotNetTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/tool/dotnet/DotNetTest.java @@ -81,7 +81,6 @@ private void runExecutable(String operatingSystem) { SystemInfo systemInfo = SystemInfoMock.of(operatingSystem); this.context.setSystemInfo(systemInfo); - this.context.info("Running dotnet binary from: {}", this.commandlet.getToolBinPath()); this.commandlet.run(); } diff --git a/cli/src/test/java/com/devonfw/tools/ide/tool/ide/IdeToolDummyCommandletTest.java b/cli/src/test/java/com/devonfw/tools/ide/tool/ide/IdeToolDummyCommandletTest.java index 582e287919..9478f37ffd 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/tool/ide/IdeToolDummyCommandletTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/tool/ide/IdeToolDummyCommandletTest.java @@ -13,7 +13,7 @@ import com.devonfw.tools.ide.context.AbstractIdeContextTest; import com.devonfw.tools.ide.context.AbstractIdeTestContext; import com.devonfw.tools.ide.context.IdeContext; -import com.devonfw.tools.ide.context.IdeSlf4jContext; +import com.devonfw.tools.ide.context.IdeTestContext; import com.devonfw.tools.ide.process.ProcessContext; import com.devonfw.tools.ide.process.ProcessErrorHandling; import com.devonfw.tools.ide.process.ProcessMode; @@ -37,7 +37,7 @@ class IdeToolDummyCommandletTest extends AbstractIdeContextTest { @Test void testDummyCommandlet(@TempDir Path tempDir) { - AbstractIdeTestContext context = new IdeSlf4jContext(); + AbstractIdeTestContext context = new IdeTestContext(); context.setPluginsPath(tempDir); context.setIdeHome(tempDir); context.setSettingsPath(Path.of("src/test/resources/settings/dummy")); diff --git a/cli/src/test/java/com/devonfw/tools/ide/tool/intellij/IntellijTest.java b/cli/src/test/java/com/devonfw/tools/ide/tool/intellij/IntellijTest.java index 1f537a2a9b..8047049eeb 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/tool/intellij/IntellijTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/tool/intellij/IntellijTest.java @@ -90,7 +90,7 @@ void testIntellijRun(String os) { SystemInfo systemInfo = SystemInfoMock.of(os); this.context.setSystemInfo(systemInfo); Intellij commandlet = new Intellij(this.context); - this.context.info("Starting testIntellijRun on {}", os); + System.out.println("Starting testIntellijRun on " + os); // act commandlet.run(); @@ -121,7 +121,7 @@ void testCheckPluginInstallation() { // part 2 of test // arrange - context.getLogger().getEntries().clear(); + context.getTestStartContext().getEntries().clear(); // act commandlet.run(); // assert diff --git a/cli/src/test/java/com/devonfw/tools/ide/tool/mvn/MvnRepositoryTest.java b/cli/src/test/java/com/devonfw/tools/ide/tool/mvn/MvnRepositoryTest.java index 4b980e39ce..142617013e 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/tool/mvn/MvnRepositoryTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/tool/mvn/MvnRepositoryTest.java @@ -13,7 +13,6 @@ 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.os.OperatingSystem; import com.devonfw.tools.ide.os.SystemArchitecture; import com.devonfw.tools.ide.tool.ToolCommandlet; @@ -221,7 +220,7 @@ void testGetMetadataWithSnapshot() { void testResolveSnapshotVersion() { // arrange - IdeTestContextMock context = IdeTestContextMock.get(); + IdeTestContext context = new IdeTestContext(); MvnRepository mvnRepository = context.getMvnRepository(); Document metadata = parseXml(XML_SNAPSNOT_METADATA); @@ -237,7 +236,7 @@ void testResolveSnapshotVersion() { void testResolveVersion() { // arrange - IdeTestContextMock context = IdeTestContextMock.get(); + IdeTestContext context = new IdeTestContext(); MvnRepository mvnRepository = context.getMvnRepository(); Document metadata = parseXml(XML_RELEASE_METADATA); diff --git a/cli/src/test/java/com/devonfw/tools/ide/tool/pycharm/PycharmTest.java b/cli/src/test/java/com/devonfw/tools/ide/tool/pycharm/PycharmTest.java index 6ea76228b3..b82803d48c 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/tool/pycharm/PycharmTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/tool/pycharm/PycharmTest.java @@ -88,7 +88,7 @@ void testPycharmRun(String os) { SystemInfo systemInfo = SystemInfoMock.of(os); this.context.setSystemInfo(systemInfo); Pycharm commandlet = new Pycharm(this.context); - this.context.info("Starting testPycharmRun on {}", os); + System.out.println("Starting testPycharmRun on " + os); // act commandlet.run(); @@ -119,7 +119,7 @@ void testCheckPluginInstallation() { // part 2 of test // arrange - context.getLogger().getEntries().clear(); + context.getTestStartContext().getEntries().clear(); // act commandlet.run(); // assert diff --git a/cli/src/test/java/com/devonfw/tools/ide/tool/repository/ToolRepositoryMock.java b/cli/src/test/java/com/devonfw/tools/ide/tool/repository/ToolRepositoryMock.java index abadfdbca0..06a53d7717 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/tool/repository/ToolRepositoryMock.java +++ b/cli/src/test/java/com/devonfw/tools/ide/tool/repository/ToolRepositoryMock.java @@ -13,6 +13,9 @@ import java.util.Set; import java.util.stream.Stream; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.tool.ToolCommandlet; import com.devonfw.tools.ide.url.model.file.UrlDownloadFile; @@ -26,6 +29,8 @@ */ public class ToolRepositoryMock extends DefaultToolRepository { + private static final Logger LOG = LoggerFactory.getLogger(ToolRepositoryMock.class); + private static final String VERSION_DEFAULT = "default"; /** Variable to be used as base url for WireMock url replacement */ @@ -63,7 +68,7 @@ public Path download(String tool, String edition, VersionIdentifier version, Too String versionString = version.toString(); Path versionFolder = editionFolder.resolve(versionString); if (!Files.isDirectory(versionFolder)) { - this.context.debug("Could not find version {} so using 'default' for {}/{}", version, tool, edition); + LOG.debug("Could not find version {} so using 'default' for {}/{}", version, tool, edition); versionString = VERSION_DEFAULT; versionFolder = editionFolder.resolve(versionString); } @@ -82,7 +87,7 @@ public Path download(String tool, String edition, VersionIdentifier version, Too Path child = iterator.next(); if (Files.isRegularFile(child) && child.getFileName().startsWith("content.")) { contentArchive = child; - this.context.debug("Using compressed archive {} for mock download of {}/{}", child.getFileName(), tool, + LOG.debug("Using compressed archive {} for mock download of {}/{}", child.getFileName(), tool, edition); } else { break; diff --git a/cli/src/test/java/com/devonfw/tools/ide/tool/spring/SpringTest.java b/cli/src/test/java/com/devonfw/tools/ide/tool/spring/SpringTest.java index cadb6a38de..da24f0048a 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/tool/spring/SpringTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/tool/spring/SpringTest.java @@ -28,7 +28,6 @@ void testSpringInstall(WireMockRuntimeInfo wireMockRuntimeInfo) { // arrange IdeTestContext context = newContext(PROJECT_SPRING, wireMockRuntimeInfo); Spring commandlet = new Spring(context); - context.info("Starting testSpringInstall"); // act commandlet.install(); @@ -48,7 +47,6 @@ void testSpringRun(WireMockRuntimeInfo wireMockRuntimeInfo) { // arrange IdeTestContext context = newContext(PROJECT_SPRING, wireMockRuntimeInfo); Spring commandlet = new Spring(context); - context.info("Starting testSpringRun"); commandlet.arguments.addValue("foo"); // act diff --git a/cli/src/test/java/com/devonfw/tools/ide/tool/vscode/VscodeTest.java b/cli/src/test/java/com/devonfw/tools/ide/tool/vscode/VscodeTest.java index 434c4ffe8b..23c2007bc1 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/tool/vscode/VscodeTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/tool/vscode/VscodeTest.java @@ -61,7 +61,7 @@ void testCheckPluginInstallation() { // part 2 of test // arrange - context.getLogger().getEntries().clear(); + context.getTestStartContext().getEntries().clear(); // act commandlet.run(); // assert diff --git a/cli/src/test/java/com/devonfw/tools/ide/url/model/AbstractUrlModelTest.java b/cli/src/test/java/com/devonfw/tools/ide/url/model/AbstractUrlModelTest.java index e6e1d91de8..8e7c180662 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/url/model/AbstractUrlModelTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/url/model/AbstractUrlModelTest.java @@ -6,7 +6,7 @@ import com.devonfw.tools.ide.context.AbstractIdeTestContext; import com.devonfw.tools.ide.context.IdeContext; -import com.devonfw.tools.ide.context.IdeSlf4jContext; +import com.devonfw.tools.ide.context.IdeTestContext; import com.devonfw.tools.ide.url.model.folder.UrlRepository; /** @@ -30,7 +30,7 @@ protected UrlRepository newRepo() { */ protected IdeContext newContext() { - AbstractIdeTestContext context = new IdeSlf4jContext(Path.of("")); + AbstractIdeTestContext context = new IdeTestContext(); context.setUrlsPath(URLS_PATH); return context; } diff --git a/cli/src/test/java/com/devonfw/tools/ide/variable/IdeVariablesTest.java b/cli/src/test/java/com/devonfw/tools/ide/variable/IdeVariablesTest.java index 691553c0e8..b6617caa12 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/variable/IdeVariablesTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/variable/IdeVariablesTest.java @@ -6,8 +6,7 @@ import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; -import com.devonfw.tools.ide.context.IdeContext; -import com.devonfw.tools.ide.context.IdeTestContextMock; +import com.devonfw.tools.ide.context.IdeTestContext; /** * Test of {@link IdeVariables}. @@ -19,7 +18,7 @@ class IdeVariablesTest extends Assertions { void testIdeTools() { // arrange - IdeContext context = IdeTestContextMock.get(); + IdeTestContext context = new IdeTestContext(); // act List ideTools = IdeVariables.IDE_TOOLS.get(context); // assert @@ -31,7 +30,7 @@ void testIdeTools() { void testHttpProtocols() { // arrange - IdeContext context = IdeTestContextMock.get(); + IdeTestContext context = new IdeTestContext(); // act List httpVersionsEmpty = IdeVariables.HTTP_VERSIONS.get(context); List httpVersions2_11 = IdeVariables.HTTP_VERSIONS.fromString("HTTP_2, http_1_1", context); @@ -45,7 +44,7 @@ void testHttpProtocols() { void testIdeToolsWithCommasInBashArray() { // arrange - IdeContext context = IdeTestContextMock.get(); + IdeTestContext context = new IdeTestContext(); // act - using bash array syntax with commas (supported for convenience) List ideTools = IdeVariables.IDE_TOOLS.fromString("(java, maven, python, node)", context); // assert - should parse correctly with comma as separator diff --git a/documentation/variables.adoc b/documentation/variables.adoc index 14a797fdd4..fde4a03242 100644 --- a/documentation/variables.adoc +++ b/documentation/variables.adoc @@ -40,4 +40,5 @@ See also link:https://github.com/devonfw/IDEasy/blob/main/cli/src/main/java/com/ |`HTTP_VERSIONS`|e.g. `HTTP_2, HTTP_1_1`| The optional list of HTTP versions to try in the given order (e.g. "HTTP_2, HTTP_1_1"). This can be used as a workaround for network/VPN related issues - see issue https://github.com/devonfw/IDEasy/issues/1393[#1393]. |`JASYPT_OPTS`|`algorithm=PBEWITHHMACSHA512ANDAES_256 ivGeneratorClassName=org.jasypt.iv.RandomIvGenerator`|Options of jasypt. |`IDE_XML_MERGE_LEGACY_SUPPORT_ENABLED`|e.g. `false`|Support of legacy xml templates without XML merge namespace. +|`IDE_WRITE_LOGFILE`|`true`|Automatically write logfiles to `$IDE_ROOT/_ide/logs/YYYY/MM/dd/«project»-ide-«command»-HH-mm-ss.log`. If you are not inside an IDEasy project or your command is not related to a project then `«project»` will be `_ide`. The logfile structure is designed in a way that allows you to quickly find and cleanup based on date but also based on details like the project and sub-command. |======================= diff --git a/gui/src/main/java/com/devonfw/ide/gui/MainController.java b/gui/src/main/java/com/devonfw/ide/gui/MainController.java index 1bb6f0905b..0e64f0a47e 100644 --- a/gui/src/main/java/com/devonfw/ide/gui/MainController.java +++ b/gui/src/main/java/com/devonfw/ide/gui/MainController.java @@ -12,7 +12,6 @@ import com.devonfw.tools.ide.context.IdeStartContextImpl; import com.devonfw.tools.ide.log.IdeLogLevel; import com.devonfw.tools.ide.log.IdeLogListenerBuffer; -import com.devonfw.tools.ide.log.IdeSubLoggerOut; import com.devonfw.tools.ide.variable.IdeVariables; /** @@ -22,14 +21,19 @@ public class MainController { @FXML private ComboBox selectedProject; + @FXML private ComboBox selectedWorkspace; + @FXML private Button androidStudioOpen; + @FXML private Button eclipseOpen; + @FXML private Button intellijOpen; + @FXML private Button vsCodeOpen; @@ -130,7 +134,7 @@ private void openIDE(String inIde) { final IdeLogListenerBuffer buffer = new IdeLogListenerBuffer(); IdeLogLevel logLevel = IdeLogLevel.INFO; - IdeStartContextImpl startContext = new IdeStartContextImpl(logLevel, level -> new IdeSubLoggerOut(level, null, true, logLevel, buffer)); + IdeStartContextImpl startContext = new IdeStartContextImpl(logLevel, buffer); IdeGuiContext context = new IdeGuiContext(startContext, Path.of(this.directoryPath).resolve(this.projectValue).resolve(this.workspaceValue)); context.getCommandletManager().getCommandlet(inIde).run(); } diff --git a/security/src/main/java/com/devonfw/tools/IDEasy/dev/BuildSecurityJsonFiles.java b/security/src/main/java/com/devonfw/tools/IDEasy/dev/BuildSecurityJsonFiles.java index b1e0ec6a49..33662b1eb4 100644 --- a/security/src/main/java/com/devonfw/tools/IDEasy/dev/BuildSecurityJsonFiles.java +++ b/security/src/main/java/com/devonfw/tools/IDEasy/dev/BuildSecurityJsonFiles.java @@ -16,7 +16,6 @@ import org.slf4j.LoggerFactory; import com.devonfw.tools.ide.context.IdeContextConsole; -import com.devonfw.tools.ide.log.IdeLogLevel; import com.devonfw.tools.ide.url.model.UrlMetadata; import com.devonfw.tools.ide.url.model.file.UrlSecurityFile; import com.devonfw.tools.ide.url.model.file.json.Cve; @@ -62,7 +61,7 @@ private BuildSecurityJsonFiles(Path urlsPath) { super(); UrlFinalReport report = new UrlFinalReport(); this.updateManager = new UpdateManager(urlsPath, report, Instant.now()); - IdeContextConsole context = new IdeContextConsole(IdeLogLevel.INFO, null, false); + IdeContextConsole context = new IdeContextConsole(); this.urlMetadata = new UrlMetadata(context, this.updateManager.getUrlRepository()); Settings settings = new Settings(); engine = new Engine(settings); diff --git a/url-updater/src/main/resources/META-INF/services/org.slf4j.spi.SLF4JServiceProvider b/url-updater/src/main/resources/META-INF/services/org.slf4j.spi.SLF4JServiceProvider new file mode 100644 index 0000000000..0bb90a9c2b --- /dev/null +++ b/url-updater/src/main/resources/META-INF/services/org.slf4j.spi.SLF4JServiceProvider @@ -0,0 +1 @@ +ch.qos.logback.classic.spi.LogbackServiceProvider diff --git a/url-updater/src/test/java/com/devonfw/tools/ide/url/updater/UrlUpdaterTest.java b/url-updater/src/test/java/com/devonfw/tools/ide/url/updater/UrlUpdaterTest.java index 2f414ff38b..602367858e 100644 --- a/url-updater/src/test/java/com/devonfw/tools/ide/url/updater/UrlUpdaterTest.java +++ b/url-updater/src/test/java/com/devonfw/tools/ide/url/updater/UrlUpdaterTest.java @@ -39,7 +39,7 @@ class UrlUpdaterTest extends AbstractUrlUpdaterTest { private final static String TEST_DATA_ROOT = "src/test/resources/integrationtest/UrlUpdaterTest"; /** - * Tests if the {@link com.devonfw.tools.ide.url.updater.UrlUpdater} can automatically add a missing OS (in this case the linux_x64) + * Tests if the {@link UrlUpdater} can automatically add a missing OS (in this case the linux_x64) * * @param tempDir Temporary directory * @param wmRuntimeInfo wireMock server on a random port @@ -251,7 +251,7 @@ void testVersionRemovedIfErrorPersists(@TempDir Path tempDir, WireMockRuntimeInf } /** - * Tests if the {@link com.devonfw.tools.ide.url.updater.UrlUpdater} will fail resolving a server with a Content-Type:text header response. + * Tests if the {@link UrlUpdater} will fail resolving a server with a Content-Type:text header response. *

* See: #1343 for reference. * @@ -278,7 +278,7 @@ void testUrlUpdaterWithTextContentTypeWillNotCreateStatusJson(@TempDir Path temp } /** - * Tests if the {@link com.devonfw.tools.ide.url.updater.UrlUpdater} will handle the literally latest version of a tool correctly + * Tests if the {@link UrlUpdater} will handle the literally latest version of a tool correctly * * @param tempDir Temporary directory * @param wmRuntimeInfo wireMock server on a random port