From e0e6f355d4794dc26541cf5b9a6afe162b4ae7d6 Mon Sep 17 00:00:00 2001 From: jan-vcapgemini <59438728+jan-vcapgemini@users.noreply.github.com> Date: Mon, 22 Apr 2024 16:11:32 +0200 Subject: [PATCH] Fix/line endings (#304) * adjusted .gitattributes * fixed line endings --- .gitattributes | 7 +- .../java/com/devonfw/tools/ide/step/Step.java | 488 +++++++-------- .../com/devonfw/tools/ide/step/StepImpl.java | 590 +++++++++--------- .../tools/ide/tool/PackageManagerCommand.java | 52 +- .../tools/ide/variable/IdeVariables.java | 150 ++--- .../devonfw/tools/ide/log/IdeSlf4jLogger.java | 154 ++--- .../com/devonfw/tools/ide/step/StepTest.java | 266 ++++---- documentation/symlink.adoc | 44 +- 8 files changed, 878 insertions(+), 873 deletions(-) diff --git a/.gitattributes b/.gitattributes index 1ffaa5d71..931eb4a75 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,8 @@ * eol=lf *.bat eol=crlf -*.png -text +*.png binary +*.zip binary +*.tgz binary +*.tar binary +*.bz2 binary +*.gz binary \ No newline at end of file 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 94e8e85d0..2536733c2 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 @@ -1,245 +1,245 @@ -package com.devonfw.tools.ide.step; - -import java.util.concurrent.Callable; - -/** - * Interface for a {@link Step} of the process. Allows to split larger processes into smaller steps that are traced and - * measured. At the end you can get a report with the hierarchy of all steps and their success/failure status, duration - * in absolute and relative numbers to gain transparency.
The typical use should follow this pattern: - * - *
- * Step step = context.{@link com.devonfw.tools.ide.context.IdeContext#newStep(String) newStep}("My step description");
- * try {
- *   // ... do something ...
- *   step.{@link #success(String) success}("Did something successfully.");
- * } catch (Exception e) {
- *   step.{@link #error(Throwable, String)}(e, "Failed to do something.");
- * } finally {
- *   step.{@link #end() end()};
- * }
- * 
- */ -public interface Step { - - /** Empty object array for no parameters. */ - Object[] NO_PARAMS = new Object[0]; - - /** - * @return the name of this {@link Step} as given to constructor. - */ - String getName(); - - /** - * @return the duration of this {@link Step} from construction to {@link #success()} or {@link #end()}. Will be - * {@code 0} if not {@link #end() ended}. - */ - long getDuration(); - - /** - * @return {@code Boolean#TRUE} if this {@link Step} has {@link #success() succeeded}, {@code Boolean#FALSE} if the - * {@link Step} has {@link #end() ended} without {@link #success() success} and {@code null} if the {@link Step} is - * still running. - */ - Boolean getSuccess(); - - /** - * @return {@code true} if this step completed {@link #success() successfully}, {@code false} otherwise. - */ - default boolean isSuccess() { - - return Boolean.TRUE.equals(getSuccess()); - } - - /** - * @return {@code true} if this step {@link #end() ended} without {@link #success() success} e.g. with an - * {@link #error(String) error}, {@code false} otherwise. - */ - default boolean isFailure() { - - return Boolean.FALSE.equals(getSuccess()); - } - - /** - * @return {@code true} if this step is silent and not logged by default, {@code false} otherwise (default). - */ - boolean isSilent(); - - /** - * Should be called to end this {@link Step} {@link #getSuccess() successfully}. May be called only once. - */ - default void success() { - - success(null); - } - - /** - * Should be called to end this {@link Step} {@link #getSuccess() successfully}. May be called only once. - * - * @param message the explicit message to log as success. - */ - default void success(String message) { - - success(message, (Object[]) null); - } - - /** - * Should be called to end this {@link Step} {@link #getSuccess() successfully}. May be called only once. - * - * @param message the explicit message to log as success. - * @param args the optional arguments to fill as placeholder into the {@code message}. - */ - void success(String message, Object... args); - - /** - * Ensures this {@link Step} is properly ended. Has to be called from a finally block. - */ - void end(); - - /** - * Should be called to end this {@link Step} as {@link #isFailure() failure} with an explicit error message. May be - * called only once. - * - * @param message the explicit message to log as error. - */ - default void error(String message) { - - error(null, 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 message the explicit message to log as error. - * @param args the optional arguments to fill as placeholder into the {@code message}. - */ - default void error(String message, Object... args) { - - error(null, message, 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}. - */ - default void error(Throwable error) { - - error(error, false); - } - - /** - * 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 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) { - - assert (error != null); - error(error, suppress, null, (Object[]) null); - } - - /** - * 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 message the explicit message to log as error. - */ - default void error(Throwable error, String message) { - - error(error, message, (Object[]) null); - } - - /** - * 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 message the explicit message to log as error. - * @param args the optional arguments to fill as placeholder into the {@code message}. - */ - default void error(Throwable error, String message, Object... args) { - - error(error, false, message, 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 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 parent {@link Step} or {@code null} if there is no parent. - */ - Step getParent(); - - /** - * @param i the index of the requested parameter. Should be in the range from {@code 0} to - * {@link #getParameterCount()}-1. - * @return the parameter at the given index {@code i} or {@code null} if no such parameter exists. - */ - Object getParameter(int i); - - /** - * @return the number of {@link #getParameter(int) parameters}. - */ - int getParameterCount(); - - /** - * @param stepCode the {@link Runnable} to {@link Runnable#run() execute} for this {@link Step}. - */ - default void run(Runnable stepCode) { - - try { - stepCode.run(); - if (getSuccess() == null) { - success(); - } - } catch (RuntimeException | Error e) { - error(e); - throw e; - } finally { - end(); - } - } - - /** - * @param stepCode the {@link Callable} to {@link Callable#call() execute} for this {@link Step}. - * @param type of the return value. - * @return the value returned from {@link Callable#call()}. - */ - default R call(Callable stepCode) { - - try { - R result = stepCode.call(); - if (getSuccess() == null) { - success(); - } - return result; - } catch (Throwable e) { - error(e); - if (e instanceof RuntimeException re) { - throw re; - } else if (e instanceof Error error) { - throw error; - } else { - throw new IllegalStateException(e); - } - } finally { - end(); - } - } - +package com.devonfw.tools.ide.step; + +import java.util.concurrent.Callable; + +/** + * Interface for a {@link Step} of the process. Allows to split larger processes into smaller steps that are traced and + * measured. At the end you can get a report with the hierarchy of all steps and their success/failure status, duration + * in absolute and relative numbers to gain transparency.
The typical use should follow this pattern: + * + *
+ * Step step = context.{@link com.devonfw.tools.ide.context.IdeContext#newStep(String) newStep}("My step description");
+ * try {
+ *   // ... do something ...
+ *   step.{@link #success(String) success}("Did something successfully.");
+ * } catch (Exception e) {
+ *   step.{@link #error(Throwable, String)}(e, "Failed to do something.");
+ * } finally {
+ *   step.{@link #end() end()};
+ * }
+ * 
+ */ +public interface Step { + + /** Empty object array for no parameters. */ + Object[] NO_PARAMS = new Object[0]; + + /** + * @return the name of this {@link Step} as given to constructor. + */ + String getName(); + + /** + * @return the duration of this {@link Step} from construction to {@link #success()} or {@link #end()}. Will be + * {@code 0} if not {@link #end() ended}. + */ + long getDuration(); + + /** + * @return {@code Boolean#TRUE} if this {@link Step} has {@link #success() succeeded}, {@code Boolean#FALSE} if the + * {@link Step} has {@link #end() ended} without {@link #success() success} and {@code null} if the {@link Step} is + * still running. + */ + Boolean getSuccess(); + + /** + * @return {@code true} if this step completed {@link #success() successfully}, {@code false} otherwise. + */ + default boolean isSuccess() { + + return Boolean.TRUE.equals(getSuccess()); + } + + /** + * @return {@code true} if this step {@link #end() ended} without {@link #success() success} e.g. with an + * {@link #error(String) error}, {@code false} otherwise. + */ + default boolean isFailure() { + + return Boolean.FALSE.equals(getSuccess()); + } + + /** + * @return {@code true} if this step is silent and not logged by default, {@code false} otherwise (default). + */ + boolean isSilent(); + + /** + * Should be called to end this {@link Step} {@link #getSuccess() successfully}. May be called only once. + */ + default void success() { + + success(null); + } + + /** + * Should be called to end this {@link Step} {@link #getSuccess() successfully}. May be called only once. + * + * @param message the explicit message to log as success. + */ + default void success(String message) { + + success(message, (Object[]) null); + } + + /** + * Should be called to end this {@link Step} {@link #getSuccess() successfully}. May be called only once. + * + * @param message the explicit message to log as success. + * @param args the optional arguments to fill as placeholder into the {@code message}. + */ + void success(String message, Object... args); + + /** + * Ensures this {@link Step} is properly ended. Has to be called from a finally block. + */ + void end(); + + /** + * Should be called to end this {@link Step} as {@link #isFailure() failure} with an explicit error message. May be + * called only once. + * + * @param message the explicit message to log as error. + */ + default void error(String message) { + + error(null, 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 message the explicit message to log as error. + * @param args the optional arguments to fill as placeholder into the {@code message}. + */ + default void error(String message, Object... args) { + + error(null, message, 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}. + */ + default void error(Throwable error) { + + error(error, false); + } + + /** + * 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 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) { + + assert (error != null); + error(error, suppress, null, (Object[]) null); + } + + /** + * 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 message the explicit message to log as error. + */ + default void error(Throwable error, String message) { + + error(error, message, (Object[]) null); + } + + /** + * 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 message the explicit message to log as error. + * @param args the optional arguments to fill as placeholder into the {@code message}. + */ + default void error(Throwable error, String message, Object... args) { + + error(error, false, message, 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 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 parent {@link Step} or {@code null} if there is no parent. + */ + Step getParent(); + + /** + * @param i the index of the requested parameter. Should be in the range from {@code 0} to + * {@link #getParameterCount()}-1. + * @return the parameter at the given index {@code i} or {@code null} if no such parameter exists. + */ + Object getParameter(int i); + + /** + * @return the number of {@link #getParameter(int) parameters}. + */ + int getParameterCount(); + + /** + * @param stepCode the {@link Runnable} to {@link Runnable#run() execute} for this {@link Step}. + */ + default void run(Runnable stepCode) { + + try { + stepCode.run(); + if (getSuccess() == null) { + success(); + } + } catch (RuntimeException | Error e) { + error(e); + throw e; + } finally { + end(); + } + } + + /** + * @param stepCode the {@link Callable} to {@link Callable#call() execute} for this {@link Step}. + * @param type of the return value. + * @return the value returned from {@link Callable#call()}. + */ + default R call(Callable stepCode) { + + try { + R result = stepCode.call(); + if (getSuccess() == null) { + success(); + } + return result; + } catch (Throwable e) { + error(e); + if (e instanceof RuntimeException re) { + throw re; + } else if (e instanceof Error error) { + throw error; + } else { + throw new IllegalStateException(e); + } + } finally { + end(); + } + } + } \ No newline at end of file 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 a8b8ad523..a0745faf8 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 @@ -1,295 +1,295 @@ -package com.devonfw.tools.ide.step; - -import com.devonfw.tools.ide.context.AbstractIdeContext; -import com.devonfw.tools.ide.context.IdeContext; -import com.devonfw.tools.ide.log.IdeSubLogger; - -import java.time.Duration; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -/** - * Regular implementation of {@link Step}. - */ -public final class StepImpl implements Step { - - private final AbstractIdeContext context; - - private final StepImpl parent; - - private final String name; - - private final Object[] params; - - private final List children; - - private final long start; - - private final boolean silent; - - private Boolean success; - - private String errorMessage; - - private long duration; - - /** - * Creates and starts a new {@link StepImpl}. - * - * @param context the {@link IdeContext}. - * @param parent the {@link #getParent() parent step}. - * @param name the {@link #getName() step name}. - * @param silent the {@link #isSilent() silent flag}. - * @param params the parameters. Should have reasonable {@link Object#toString() string representations}. - */ - public StepImpl(AbstractIdeContext context, StepImpl parent, String name, boolean silent, Object... params) { - - super(); - this.context = context; - this.parent = parent; - this.name = name; - this.params = params; - this.silent = silent; - this.children = new ArrayList<>(); - this.start = System.currentTimeMillis(); - if (parent != null) { - parent.children.add(this); - } - if (params.length == 0) { - this.context.trace("Starting step {}...", name); - } else { - this.context.trace("Starting step {} with params {}...", name, Arrays.toString(params)); - } - if (!this.silent) { - this.context.step("Start: {}", name); - } - } - - @Override - public StepImpl getParent() { - - return this.parent; - } - - @Override - public String getName() { - - return this.name; - } - - @Override - public Object getParameter(int i) { - - if ((i < 0) || (i >= this.params.length)) { - return null; - } - return this.params[i]; - } - - @Override - public int getParameterCount() { - - return this.params.length; - } - - @Override - public boolean isSilent() { - - return this.silent; - } - - @Override - public long getDuration() { - - return this.duration; - } - - @Override - public Boolean getSuccess() { - - return this.success; - } - - @Override - public void success(String message, Object... args) { - - end(Boolean.TRUE, null, false, message, args); - } - - @Override - public void error(Throwable error, boolean suppress, String message, Object... args) { - - end(Boolean.FALSE, error, suppress, message, args); - } - - @Override - public void end() { - - end(null, null, false, null, null); - } - - private void end(Boolean newSuccess, Throwable error, boolean suppress, String message, Object[] args) { - - boolean firstCallOfEnd = (this.success == null); - if (!firstCallOfEnd) { - assert (this.duration > 0); - if (newSuccess != null) { - this.context.warning("Step '{}' already ended with {} and now ended again with {}.", this.name, this.success, - newSuccess); - } else { - return; - } - } - long delay = System.currentTimeMillis() - this.start; - if (delay == 0) { - delay = 1; - } - if (newSuccess == null) { - newSuccess = Boolean.FALSE; - } - if (this.success != Boolean.FALSE) { // never allow a failed step to change to success - this.duration = delay; - this.success = newSuccess; - } - if (newSuccess.booleanValue()) { - assert (error == null); - if (message != null) { - this.context.success(message, args); - } else if (!this.silent) { - this.context.success(this.name); - } - this.context.debug("Step '{}' ended successfully.", this.name); - } else { - IdeSubLogger logger; - if ((message != null) || (error != null)) { - if (suppress) { - if (error != null) { - this.errorMessage = error.toString(); - } else { - this.errorMessage = message; - } - } else { - this.errorMessage = this.context.error().log(error, message, args); - } - logger = this.context.debug(); - } else { - logger = this.context.info(); - } - logger.log("Step '{}' ended with failure.", this.name); - } - if (firstCallOfEnd) { - this.context.endStep(this); - } - } - - /** - * Logs the summary of this {@link Step}. Should typically only be called on the top-level {@link Step}. - * - * @param suppressSuccess - {@code true} to suppress the success message, {@code false} otherwise. - */ - public void logSummary(boolean suppressSuccess) { - - if (this.context.trace().isEnabled()) { - this.context.trace(toString()); - } - if (this.context.isQuietMode()) { - return; - } - StepSummary summary = new StepSummary(); - logErrorSummary(0, summary); - if (summary.getError() == 0) { - if (!suppressSuccess) { - this.context.success("Successfully completed {}", getNameWithParams()); - } - } else { - this.context.error(summary.toString()); - } - } - - private void logErrorSummary(int depth, StepSummary summary) { - - boolean failure = isFailure(); - summary.add(failure); - if (failure) { - this.context.error("{}Step '{}' failed: {}", getIndent(depth), getNameWithParams(), this.errorMessage); - } - depth++; - for (StepImpl child : this.children) { - child.logErrorSummary(depth, summary); - } - } - - private String getNameWithParams() { - - if ((this.params == null) || (this.params.length == 0)) { - return this.name; - } - StringBuilder sb = new StringBuilder(this.name.length() + 3 + this.params.length * 6); - getNameWithParams(sb); - return sb.toString(); - } - - private void getNameWithParams(StringBuilder sb) { - - sb.append(this.name); - sb.append(" ("); - String seperator = ""; - if (this.params != null) { - for (Object param : this.params) { - sb.append(seperator); - sb.append(param); - seperator = ","; - } - } - sb.append(')'); - } - - private void append(int depth, long totalDuration, long parentDuration, StringBuilder sb) { - - // indent - sb.append(getIndent(depth)); - getNameWithParams(sb); - sb.append(' '); - if (this.success == null) { - sb.append("is still running or was not properly ended due to programming error not using finally block "); - } else { - if (this.success.booleanValue()) { - sb.append("succeeded after "); - } else { - sb.append("failed after "); - } - sb.append(Duration.ofMillis(this.duration)); - } - if (this.duration < totalDuration) { - sb.append(" "); - double percentageBase = this.duration * 100; - double totalPercentage = percentageBase / totalDuration; - sb.append(totalPercentage); - sb.append("% of total "); - if (parentDuration < totalDuration) { - double parentPercentage = percentageBase / parentDuration; - sb.append(parentPercentage); - sb.append("% of parent"); - } - } - sb.append('\n'); - int childDepth = depth + 1; - for (StepImpl child : this.children) { - child.append(childDepth, totalDuration, this.duration, sb); - } - } - - private String getIndent(int depth) { - - return " ".repeat(depth); - } - - @Override - public String toString() { - - StringBuilder sb = new StringBuilder(4096); - append(0, this.duration, this.duration, sb); - return sb.toString(); - } -} +package com.devonfw.tools.ide.step; + +import com.devonfw.tools.ide.context.AbstractIdeContext; +import com.devonfw.tools.ide.context.IdeContext; +import com.devonfw.tools.ide.log.IdeSubLogger; + +import java.time.Duration; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Regular implementation of {@link Step}. + */ +public final class StepImpl implements Step { + + private final AbstractIdeContext context; + + private final StepImpl parent; + + private final String name; + + private final Object[] params; + + private final List children; + + private final long start; + + private final boolean silent; + + private Boolean success; + + private String errorMessage; + + private long duration; + + /** + * Creates and starts a new {@link StepImpl}. + * + * @param context the {@link IdeContext}. + * @param parent the {@link #getParent() parent step}. + * @param name the {@link #getName() step name}. + * @param silent the {@link #isSilent() silent flag}. + * @param params the parameters. Should have reasonable {@link Object#toString() string representations}. + */ + public StepImpl(AbstractIdeContext context, StepImpl parent, String name, boolean silent, Object... params) { + + super(); + this.context = context; + this.parent = parent; + this.name = name; + this.params = params; + this.silent = silent; + this.children = new ArrayList<>(); + this.start = System.currentTimeMillis(); + if (parent != null) { + parent.children.add(this); + } + if (params.length == 0) { + this.context.trace("Starting step {}...", name); + } else { + this.context.trace("Starting step {} with params {}...", name, Arrays.toString(params)); + } + if (!this.silent) { + this.context.step("Start: {}", name); + } + } + + @Override + public StepImpl getParent() { + + return this.parent; + } + + @Override + public String getName() { + + return this.name; + } + + @Override + public Object getParameter(int i) { + + if ((i < 0) || (i >= this.params.length)) { + return null; + } + return this.params[i]; + } + + @Override + public int getParameterCount() { + + return this.params.length; + } + + @Override + public boolean isSilent() { + + return this.silent; + } + + @Override + public long getDuration() { + + return this.duration; + } + + @Override + public Boolean getSuccess() { + + return this.success; + } + + @Override + public void success(String message, Object... args) { + + end(Boolean.TRUE, null, false, message, args); + } + + @Override + public void error(Throwable error, boolean suppress, String message, Object... args) { + + end(Boolean.FALSE, error, suppress, message, args); + } + + @Override + public void end() { + + end(null, null, false, null, null); + } + + private void end(Boolean newSuccess, Throwable error, boolean suppress, String message, Object[] args) { + + boolean firstCallOfEnd = (this.success == null); + if (!firstCallOfEnd) { + assert (this.duration > 0); + if (newSuccess != null) { + this.context.warning("Step '{}' already ended with {} and now ended again with {}.", this.name, this.success, + newSuccess); + } else { + return; + } + } + long delay = System.currentTimeMillis() - this.start; + if (delay == 0) { + delay = 1; + } + if (newSuccess == null) { + newSuccess = Boolean.FALSE; + } + if (this.success != Boolean.FALSE) { // never allow a failed step to change to success + this.duration = delay; + this.success = newSuccess; + } + if (newSuccess.booleanValue()) { + assert (error == null); + if (message != null) { + this.context.success(message, args); + } else if (!this.silent) { + this.context.success(this.name); + } + this.context.debug("Step '{}' ended successfully.", this.name); + } else { + IdeSubLogger logger; + if ((message != null) || (error != null)) { + if (suppress) { + if (error != null) { + this.errorMessage = error.toString(); + } else { + this.errorMessage = message; + } + } else { + this.errorMessage = this.context.error().log(error, message, args); + } + logger = this.context.debug(); + } else { + logger = this.context.info(); + } + logger.log("Step '{}' ended with failure.", this.name); + } + if (firstCallOfEnd) { + this.context.endStep(this); + } + } + + /** + * Logs the summary of this {@link Step}. Should typically only be called on the top-level {@link Step}. + * + * @param suppressSuccess - {@code true} to suppress the success message, {@code false} otherwise. + */ + public void logSummary(boolean suppressSuccess) { + + if (this.context.trace().isEnabled()) { + this.context.trace(toString()); + } + if (this.context.isQuietMode()) { + return; + } + StepSummary summary = new StepSummary(); + logErrorSummary(0, summary); + if (summary.getError() == 0) { + if (!suppressSuccess) { + this.context.success("Successfully completed {}", getNameWithParams()); + } + } else { + this.context.error(summary.toString()); + } + } + + private void logErrorSummary(int depth, StepSummary summary) { + + boolean failure = isFailure(); + summary.add(failure); + if (failure) { + this.context.error("{}Step '{}' failed: {}", getIndent(depth), getNameWithParams(), this.errorMessage); + } + depth++; + for (StepImpl child : this.children) { + child.logErrorSummary(depth, summary); + } + } + + private String getNameWithParams() { + + if ((this.params == null) || (this.params.length == 0)) { + return this.name; + } + StringBuilder sb = new StringBuilder(this.name.length() + 3 + this.params.length * 6); + getNameWithParams(sb); + return sb.toString(); + } + + private void getNameWithParams(StringBuilder sb) { + + sb.append(this.name); + sb.append(" ("); + String seperator = ""; + if (this.params != null) { + for (Object param : this.params) { + sb.append(seperator); + sb.append(param); + seperator = ","; + } + } + sb.append(')'); + } + + private void append(int depth, long totalDuration, long parentDuration, StringBuilder sb) { + + // indent + sb.append(getIndent(depth)); + getNameWithParams(sb); + sb.append(' '); + if (this.success == null) { + sb.append("is still running or was not properly ended due to programming error not using finally block "); + } else { + if (this.success.booleanValue()) { + sb.append("succeeded after "); + } else { + sb.append("failed after "); + } + sb.append(Duration.ofMillis(this.duration)); + } + if (this.duration < totalDuration) { + sb.append(" "); + double percentageBase = this.duration * 100; + double totalPercentage = percentageBase / totalDuration; + sb.append(totalPercentage); + sb.append("% of total "); + if (parentDuration < totalDuration) { + double parentPercentage = percentageBase / parentDuration; + sb.append(parentPercentage); + sb.append("% of parent"); + } + } + sb.append('\n'); + int childDepth = depth + 1; + for (StepImpl child : this.children) { + child.append(childDepth, totalDuration, this.duration, sb); + } + } + + private String getIndent(int depth) { + + return " ".repeat(depth); + } + + @Override + public String toString() { + + StringBuilder sb = new StringBuilder(4096); + append(0, this.duration, this.duration, sb); + return sb.toString(); + } +} diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/PackageManagerCommand.java b/cli/src/main/java/com/devonfw/tools/ide/tool/PackageManagerCommand.java index d39516ac9..6c687e969 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/PackageManagerCommand.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/PackageManagerCommand.java @@ -1,26 +1,26 @@ -package com.devonfw.tools.ide.tool; - -import java.util.List; - -/** - * Represents a command to be executed by a package manager. Each command consists of a {@link PackageManager} and a - * list of commands to be executed by that package manager. - * - * @param packageManager The package manager associated with this command. - * @param commands The list of commands to be executed by the package manager. - */ -public record PackageManagerCommand(PackageManager packageManager, List commands) { - - /** - * Constructs a {@code PackageManagerCommand} based on the provided command string. The package manager is retrieved - * from the command string using {@link PackageManager#extractPackageManager(String)}. - * - * @param command The command string. - * @return A {@code PackageManagerCommand} based on the provided command string. - */ - public static PackageManagerCommand of(String command) { - - PackageManager pm = PackageManager.extractPackageManager(command); - return new PackageManagerCommand(pm, List.of(command)); - } -} +package com.devonfw.tools.ide.tool; + +import java.util.List; + +/** + * Represents a command to be executed by a package manager. Each command consists of a {@link PackageManager} and a + * list of commands to be executed by that package manager. + * + * @param packageManager The package manager associated with this command. + * @param commands The list of commands to be executed by the package manager. + */ +public record PackageManagerCommand(PackageManager packageManager, List commands) { + + /** + * Constructs a {@code PackageManagerCommand} based on the provided command string. The package manager is retrieved + * from the command string using {@link PackageManager#extractPackageManager(String)}. + * + * @param command The command string. + * @return A {@code PackageManagerCommand} based on the provided command string. + */ + public static PackageManagerCommand of(String command) { + + PackageManager pm = PackageManager.extractPackageManager(command); + return new PackageManagerCommand(pm, List.of(command)); + } +} 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 9e6259a82..6c01c1ad1 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 @@ -1,75 +1,75 @@ -package com.devonfw.tools.ide.variable; - -import java.util.Collection; -import java.util.List; - -/** - * Interface (mis)used to define all the available variables. - */ -public interface IdeVariables { - - /** {@link VariableDefinition} for {@link com.devonfw.tools.ide.context.IdeContext#getIdeHome() IDE_HOME}. */ - VariableDefinitionPath IDE_HOME = new VariableDefinitionPath("IDE_HOME", "DEVON_IDE_HOME", c -> c.getIdeHome(), true); - - /** {@link VariableDefinition} for {@link com.devonfw.tools.ide.context.IdeContext#getIdeRoot() IDE_ROOT}. */ - VariableDefinitionPath IDE_ROOT = new VariableDefinitionPath("IDE_ROOT", null, c -> c.getIdeRoot()); - - /** {@link VariableDefinition} for {@link com.devonfw.tools.ide.context.IdeContext#getUserHome() HOME}. */ - VariableDefinitionPath HOME = new VariableDefinitionPath("HOME", null, c -> c.getUserHome(), true); - - /** {@link VariableDefinition} for {@link com.devonfw.tools.ide.context.IdeContext#getWorkspaceName() WORKSPACE}. */ - VariableDefinitionString WORKSPACE = new VariableDefinitionString("WORKSPACE", null, c -> c.getWorkspaceName(), true); - - /** {@link VariableDefinition} for {@link com.devonfw.tools.ide.context.IdeContext#getPath() PATH}. */ - VariableDefinitionSystemPath PATH = new VariableDefinitionSystemPath("PATH", null, c -> c.getPath(), true, true); - - /** - * {@link VariableDefinition} for {@link com.devonfw.tools.ide.context.IdeContext#getWorkspacePath() WORKSPACE_PATH}. - */ - VariableDefinitionPath WORKSPACE_PATH = new VariableDefinitionPath("WORKSPACE_PATH", null, c -> c.getWorkspacePath(), true); - - /** {@link VariableDefinition} for list of tools to install by default. */ - VariableDefinitionStringList IDE_TOOLS = new VariableDefinitionStringList("IDE_TOOLS", "DEVON_IDE_TOOLS", c -> List.of("mvn", "npm")); - - /** {@link VariableDefinition} for list of IDE tools to create start scripts for. */ - VariableDefinitionStringList CREATE_START_SCRIPTS = new VariableDefinitionStringList("CREATE_START_SCRIPTS", "DEVON_CREATE_START_SCRIPTS"); - - /** {@link VariableDefinition} for minimum IDE product version. */ - // TODO define initial IDEasy version as default value - VariableDefinitionVersion IDE_MIN_VERSION = new VariableDefinitionVersion("IDE_MIN_VERSION", "DEVON_IDE_MIN_VERSION"); - - /** {@link VariableDefinition} for version of maven (mvn). */ - VariableDefinitionVersion MVN_VERSION = new VariableDefinitionVersion("MVN_VERSION", "MAVEN_VERSION"); - - /** {@link VariableDefinition} arguments for maven to set the m2 repo location. */ - VariableDefinitionString MAVEN_ARGS = new VariableDefinitionString("MAVEN_ARGS", null, c -> c.getMavenArgs(), false, true); - - /** {@link VariableDefinition} for {@link com.devonfw.tools.ide.context.IdeContext#getWorkspaceName() WORKSPACE}. */ - VariableDefinitionString DOCKER_EDITION = new VariableDefinitionString("DOCKER_EDITION", null, c -> "rancher"); - - /** {@link VariableDefinition} for {@link com.devonfw.tools.ide.context.IdeContext#getWorkspaceName() WORKSPACE}. */ - VariableDefinitionString GRAALVM_EDITION = new VariableDefinitionString("GRAALVM_EDITION", null, c -> "community"); - - /** {@link VariableDefinition} for options of jasypt */ - VariableDefinitionString JASYPT_OPTS = new VariableDefinitionString("JASYPT_OPTS", null, - c -> "algorithm=PBEWITHHMACSHA512ANDAES_256 ivGeneratorClassName=org.jasypt.iv.RandomIvGenerator"); - - /** {@link VariableDefinition} for {@link com.devonfw.tools.ide.context.IdeContext#getProjectName() PROJECT_NAME}. */ - VariableDefinitionString PROJECT_NAME = new VariableDefinitionString("PROJECT_NAME", null, c -> c.getProjectName()); - - /** A {@link Collection} with all pre-defined {@link VariableDefinition}s. */ - Collection> VARIABLES = List.of(PATH, HOME, WORKSPACE_PATH, IDE_HOME, IDE_ROOT, WORKSPACE, IDE_TOOLS, CREATE_START_SCRIPTS, - IDE_MIN_VERSION, MVN_VERSION, DOCKER_EDITION, GRAALVM_EDITION, JASYPT_OPTS, MAVEN_ARGS, PROJECT_NAME); - - /** - * @param name the name of the requested {@link VariableDefinition}. - * @return the {@link VariableDefinition} for the given {@code name} or {@code null} if not defined. - * @see VariableDefinition#getName() - * @see VariableDefinition#getLegacyName() - */ - static VariableDefinition get(String name) { - - return IdeVariablesList.get(name); - } - -} +package com.devonfw.tools.ide.variable; + +import java.util.Collection; +import java.util.List; + +/** + * Interface (mis)used to define all the available variables. + */ +public interface IdeVariables { + + /** {@link VariableDefinition} for {@link com.devonfw.tools.ide.context.IdeContext#getIdeHome() IDE_HOME}. */ + VariableDefinitionPath IDE_HOME = new VariableDefinitionPath("IDE_HOME", "DEVON_IDE_HOME", c -> c.getIdeHome(), true); + + /** {@link VariableDefinition} for {@link com.devonfw.tools.ide.context.IdeContext#getIdeRoot() IDE_ROOT}. */ + VariableDefinitionPath IDE_ROOT = new VariableDefinitionPath("IDE_ROOT", null, c -> c.getIdeRoot()); + + /** {@link VariableDefinition} for {@link com.devonfw.tools.ide.context.IdeContext#getUserHome() HOME}. */ + VariableDefinitionPath HOME = new VariableDefinitionPath("HOME", null, c -> c.getUserHome(), true); + + /** {@link VariableDefinition} for {@link com.devonfw.tools.ide.context.IdeContext#getWorkspaceName() WORKSPACE}. */ + VariableDefinitionString WORKSPACE = new VariableDefinitionString("WORKSPACE", null, c -> c.getWorkspaceName(), true); + + /** {@link VariableDefinition} for {@link com.devonfw.tools.ide.context.IdeContext#getPath() PATH}. */ + VariableDefinitionSystemPath PATH = new VariableDefinitionSystemPath("PATH", null, c -> c.getPath(), true, true); + + /** + * {@link VariableDefinition} for {@link com.devonfw.tools.ide.context.IdeContext#getWorkspacePath() WORKSPACE_PATH}. + */ + VariableDefinitionPath WORKSPACE_PATH = new VariableDefinitionPath("WORKSPACE_PATH", null, c -> c.getWorkspacePath(), true); + + /** {@link VariableDefinition} for list of tools to install by default. */ + VariableDefinitionStringList IDE_TOOLS = new VariableDefinitionStringList("IDE_TOOLS", "DEVON_IDE_TOOLS", c -> List.of("mvn", "npm")); + + /** {@link VariableDefinition} for list of IDE tools to create start scripts for. */ + VariableDefinitionStringList CREATE_START_SCRIPTS = new VariableDefinitionStringList("CREATE_START_SCRIPTS", "DEVON_CREATE_START_SCRIPTS"); + + /** {@link VariableDefinition} for minimum IDE product version. */ + // TODO define initial IDEasy version as default value + VariableDefinitionVersion IDE_MIN_VERSION = new VariableDefinitionVersion("IDE_MIN_VERSION", "DEVON_IDE_MIN_VERSION"); + + /** {@link VariableDefinition} for version of maven (mvn). */ + VariableDefinitionVersion MVN_VERSION = new VariableDefinitionVersion("MVN_VERSION", "MAVEN_VERSION"); + + /** {@link VariableDefinition} arguments for maven to set the m2 repo location. */ + VariableDefinitionString MAVEN_ARGS = new VariableDefinitionString("MAVEN_ARGS", null, c -> c.getMavenArgs(), false, true); + + /** {@link VariableDefinition} for {@link com.devonfw.tools.ide.context.IdeContext#getWorkspaceName() WORKSPACE}. */ + VariableDefinitionString DOCKER_EDITION = new VariableDefinitionString("DOCKER_EDITION", null, c -> "rancher"); + + /** {@link VariableDefinition} for {@link com.devonfw.tools.ide.context.IdeContext#getWorkspaceName() WORKSPACE}. */ + VariableDefinitionString GRAALVM_EDITION = new VariableDefinitionString("GRAALVM_EDITION", null, c -> "community"); + + /** {@link VariableDefinition} for options of jasypt */ + VariableDefinitionString JASYPT_OPTS = new VariableDefinitionString("JASYPT_OPTS", null, + c -> "algorithm=PBEWITHHMACSHA512ANDAES_256 ivGeneratorClassName=org.jasypt.iv.RandomIvGenerator"); + + /** {@link VariableDefinition} for {@link com.devonfw.tools.ide.context.IdeContext#getProjectName() PROJECT_NAME}. */ + VariableDefinitionString PROJECT_NAME = new VariableDefinitionString("PROJECT_NAME", null, c -> c.getProjectName()); + + /** A {@link Collection} with all pre-defined {@link VariableDefinition}s. */ + Collection> VARIABLES = List.of(PATH, HOME, WORKSPACE_PATH, IDE_HOME, IDE_ROOT, WORKSPACE, IDE_TOOLS, CREATE_START_SCRIPTS, + IDE_MIN_VERSION, MVN_VERSION, DOCKER_EDITION, GRAALVM_EDITION, JASYPT_OPTS, MAVEN_ARGS, PROJECT_NAME); + + /** + * @param name the name of the requested {@link VariableDefinition}. + * @return the {@link VariableDefinition} for the given {@code name} or {@code null} if not defined. + * @see VariableDefinition#getName() + * @see VariableDefinition#getLegacyName() + */ + static VariableDefinition get(String name) { + + return IdeVariablesList.get(name); + } + +} diff --git a/cli/src/test/java/com/devonfw/tools/ide/log/IdeSlf4jLogger.java b/cli/src/test/java/com/devonfw/tools/ide/log/IdeSlf4jLogger.java index 102d40a8e..efd06b047 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/log/IdeSlf4jLogger.java +++ b/cli/src/test/java/com/devonfw/tools/ide/log/IdeSlf4jLogger.java @@ -1,77 +1,77 @@ -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 IdeSlf4jLogger extends AbstractIdeSubLogger { - - private static final Logger LOG = LoggerFactory.getLogger(IdeSlf4jLogger.class); - - private final Level logLevel; - - /** - * The constructor. - * - * @param level the {@link #getLevel() log-level}. - */ - public IdeSlf4jLogger(IdeLogLevel level) { - - super(level); - this.logLevel = switch (level) { - case TRACE -> Level.TRACE; - case DEBUG -> Level.DEBUG; - case INFO, STEP, INTERACTION, SUCCESS -> Level.INFO; - case WARNING -> Level.WARN; - case ERROR -> Level.ERROR; - default -> throw new IllegalArgumentException("" + level); - }; - } - - @Override - public String log(Throwable error, String message, Object... args) { - - if ((message == null) && (error != null)) { - message = error.getMessage(); - if (message == null) { - message = error.toString(); - } - } - String msg = message; - if ((this.level == IdeLogLevel.STEP) || (this.level == IdeLogLevel.INTERACTION) - || (this.level == IdeLogLevel.SUCCESS)) { - msg = this.level.name() + ":" + message; - } - LoggingEventBuilder builder = LOG.atLevel(this.logLevel); - if (error != null) { - builder.setCause(error); - } - if (args == null) { - builder.log(msg); - } else { - builder.log(msg, args); - } - if (message == null) { - if (error == null) { - return null; - } else { - return error.toString(); - } - } else if (args == null) { - return message; - } else { - return compose(message, args); - } - } - - @Override - public boolean isEnabled() { - - return LOG.isEnabledForLevel(this.logLevel); - } - -} +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 IdeSlf4jLogger extends AbstractIdeSubLogger { + + private static final Logger LOG = LoggerFactory.getLogger(IdeSlf4jLogger.class); + + private final Level logLevel; + + /** + * The constructor. + * + * @param level the {@link #getLevel() log-level}. + */ + public IdeSlf4jLogger(IdeLogLevel level) { + + super(level); + this.logLevel = switch (level) { + case TRACE -> Level.TRACE; + case DEBUG -> Level.DEBUG; + case INFO, STEP, INTERACTION, SUCCESS -> Level.INFO; + case WARNING -> Level.WARN; + case ERROR -> Level.ERROR; + default -> throw new IllegalArgumentException("" + level); + }; + } + + @Override + public String log(Throwable error, String message, Object... args) { + + if ((message == null) && (error != null)) { + message = error.getMessage(); + if (message == null) { + message = error.toString(); + } + } + String msg = message; + if ((this.level == IdeLogLevel.STEP) || (this.level == IdeLogLevel.INTERACTION) + || (this.level == IdeLogLevel.SUCCESS)) { + msg = this.level.name() + ":" + message; + } + LoggingEventBuilder builder = LOG.atLevel(this.logLevel); + if (error != null) { + builder.setCause(error); + } + if (args == null) { + builder.log(msg); + } else { + builder.log(msg, args); + } + if (message == null) { + if (error == null) { + return null; + } else { + return error.toString(); + } + } else if (args == null) { + return message; + } else { + return compose(message, args); + } + } + + @Override + public boolean isEnabled() { + + return LOG.isEnabledForLevel(this.logLevel); + } + +} 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 132cc869f..8477a9683 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 @@ -1,133 +1,133 @@ -package com.devonfw.tools.ide.step; - -import com.devonfw.tools.ide.context.AbstractIdeContextTest; -import com.devonfw.tools.ide.context.IdeTestContext; -import com.devonfw.tools.ide.log.IdeLogLevel; -import org.junit.jupiter.api.Test; - -/** - * Test of {@link Step}. - */ -public class StepTest extends AbstractIdeContextTest { - - @Test - public void testValidUsageSuccess() { - - // arrage - IdeTestContext context = newContext(PROJECT_BASIC, "project", false); - // act - Step step = context.newStep("Test-Step"); - try { - step.success("The Test-Step succeeded as expected"); - } finally { - step.end(); - } - // assert - assertThat(step.getSuccess()).isTrue(); - assertThat(step.getDuration()).isPositive(); - assertLogMessage(context, IdeLogLevel.TRACE, "Starting step Test-Step..."); - assertLogMessage(context, IdeLogLevel.STEP, "Start: Test-Step"); - assertLogMessage(context, IdeLogLevel.SUCCESS, "The Test-Step succeeded as expected"); - assertLogMessage(context, IdeLogLevel.DEBUG, "Step 'Test-Step' ended successfully."); - } - - @Test - public void testValidUsageSuccessSilent() { - - // arrage - IdeTestContext context = newContext(PROJECT_BASIC, "project", false); - // act - Step step = context.newStep(true, "Test-Step", "arg1", "arg2"); - try { - step.success(); - } finally { - step.end(); - } - // assert - assertThat(step.getSuccess()).isTrue(); - assertThat(step.getDuration()).isPositive(); - assertThat(step.getParameterCount()).isEqualTo(2); - assertThat(step.getParameter(0)).isEqualTo("arg1"); - assertThat(step.getParameter(1)).isEqualTo("arg2"); - assertThat(step.getParameter(2)).isNull(); - assertLogMessage(context, IdeLogLevel.TRACE, "Starting step Test-Step with params [arg1, arg2]..."); - assertNoLogMessage(context, IdeLogLevel.STEP, "Start: Test-Step"); - assertNoLogMessage(context, IdeLogLevel.SUCCESS, "Test-Step", true); - assertLogMessage(context, IdeLogLevel.DEBUG, "Step 'Test-Step' ended successfully."); - } - - @Test - public void testValidUsageError() { - - // arrage - IdeTestContext context = newContext(PROJECT_BASIC, "project", false); - // act - Step step = context.newStep("Test-Step"); - try { - step.error("The Test-Step failed as expected"); - } finally { - step.end(); - } - assertThat(step.getSuccess()).isFalse(); - assertThat(step.getDuration()).isPositive(); - // assert - assertLogMessage(context, IdeLogLevel.TRACE, "Starting step Test-Step..."); - assertLogMessage(context, IdeLogLevel.STEP, "Start: Test-Step"); - assertLogMessage(context, IdeLogLevel.ERROR, "The Test-Step failed as expected"); - assertLogMessage(context, IdeLogLevel.DEBUG, "Step 'Test-Step' ended with failure."); - } - - @Test - public void testInvalidUsageSuccessError() { - - // arrage - IdeTestContext context = newContext(PROJECT_BASIC, "project", false); - // 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); - } finally { - step.end(); - } - assertThat(step.getSuccess()).isFalse(); - assertThat(step.getDuration()).isPositive(); - // assert - assertLogMessage(context, IdeLogLevel.TRACE, "Starting step Test-Step..."); - assertLogMessage(context, IdeLogLevel.STEP, "Start: Test-Step"); - assertLogMessage(context, IdeLogLevel.WARNING, - "Step 'Test-Step' already ended with true and now ended again with false."); - assertLogMessage(context, IdeLogLevel.ERROR, "unexpected situation!"); - assertLogMessage(context, IdeLogLevel.DEBUG, "Step 'Test-Step' ended with failure."); - } - - @Test - public void testInvalidUsageErrorSuccess() { - - // arrage - IdeTestContext context = newContext(PROJECT_BASIC, "project", false); - // act - Step step = context.newStep("Test-Step"); - try { - step.error("The Test-Step failed as expected"); - // WOW this is really inconsistent and hopefully never happens elsewhere - step.success("The Test-Step succeeded as expected"); - } finally { - step.end(); - } - assertThat(step.getSuccess()).isFalse(); - assertThat(step.getDuration()).isPositive(); - // assert - assertLogMessage(context, IdeLogLevel.TRACE, "Starting step Test-Step..."); - assertLogMessage(context, IdeLogLevel.STEP, "Start: Test-Step"); - assertLogMessage(context, IdeLogLevel.ERROR, "The Test-Step failed as expected"); - assertLogMessage(context, IdeLogLevel.DEBUG, "Step 'Test-Step' ended with failure."); - assertLogMessage(context, IdeLogLevel.WARNING, - "Step 'Test-Step' already ended with false and now ended again with true."); - assertLogMessage(context, IdeLogLevel.SUCCESS, "The Test-Step succeeded as expected"); - assertLogMessage(context, IdeLogLevel.DEBUG, "Step 'Test-Step' ended successfully."); - } - -} +package com.devonfw.tools.ide.step; + +import com.devonfw.tools.ide.context.AbstractIdeContextTest; +import com.devonfw.tools.ide.context.IdeTestContext; +import com.devonfw.tools.ide.log.IdeLogLevel; +import org.junit.jupiter.api.Test; + +/** + * Test of {@link Step}. + */ +public class StepTest extends AbstractIdeContextTest { + + @Test + public void testValidUsageSuccess() { + + // arrage + IdeTestContext context = newContext(PROJECT_BASIC, "project", false); + // act + Step step = context.newStep("Test-Step"); + try { + step.success("The Test-Step succeeded as expected"); + } finally { + step.end(); + } + // assert + assertThat(step.getSuccess()).isTrue(); + assertThat(step.getDuration()).isPositive(); + assertLogMessage(context, IdeLogLevel.TRACE, "Starting step Test-Step..."); + assertLogMessage(context, IdeLogLevel.STEP, "Start: Test-Step"); + assertLogMessage(context, IdeLogLevel.SUCCESS, "The Test-Step succeeded as expected"); + assertLogMessage(context, IdeLogLevel.DEBUG, "Step 'Test-Step' ended successfully."); + } + + @Test + public void testValidUsageSuccessSilent() { + + // arrage + IdeTestContext context = newContext(PROJECT_BASIC, "project", false); + // act + Step step = context.newStep(true, "Test-Step", "arg1", "arg2"); + try { + step.success(); + } finally { + step.end(); + } + // assert + assertThat(step.getSuccess()).isTrue(); + assertThat(step.getDuration()).isPositive(); + assertThat(step.getParameterCount()).isEqualTo(2); + assertThat(step.getParameter(0)).isEqualTo("arg1"); + assertThat(step.getParameter(1)).isEqualTo("arg2"); + assertThat(step.getParameter(2)).isNull(); + assertLogMessage(context, IdeLogLevel.TRACE, "Starting step Test-Step with params [arg1, arg2]..."); + assertNoLogMessage(context, IdeLogLevel.STEP, "Start: Test-Step"); + assertNoLogMessage(context, IdeLogLevel.SUCCESS, "Test-Step", true); + assertLogMessage(context, IdeLogLevel.DEBUG, "Step 'Test-Step' ended successfully."); + } + + @Test + public void testValidUsageError() { + + // arrage + IdeTestContext context = newContext(PROJECT_BASIC, "project", false); + // act + Step step = context.newStep("Test-Step"); + try { + step.error("The Test-Step failed as expected"); + } finally { + step.end(); + } + assertThat(step.getSuccess()).isFalse(); + assertThat(step.getDuration()).isPositive(); + // assert + assertLogMessage(context, IdeLogLevel.TRACE, "Starting step Test-Step..."); + assertLogMessage(context, IdeLogLevel.STEP, "Start: Test-Step"); + assertLogMessage(context, IdeLogLevel.ERROR, "The Test-Step failed as expected"); + assertLogMessage(context, IdeLogLevel.DEBUG, "Step 'Test-Step' ended with failure."); + } + + @Test + public void testInvalidUsageSuccessError() { + + // arrage + IdeTestContext context = newContext(PROJECT_BASIC, "project", false); + // 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); + } finally { + step.end(); + } + assertThat(step.getSuccess()).isFalse(); + assertThat(step.getDuration()).isPositive(); + // assert + assertLogMessage(context, IdeLogLevel.TRACE, "Starting step Test-Step..."); + assertLogMessage(context, IdeLogLevel.STEP, "Start: Test-Step"); + assertLogMessage(context, IdeLogLevel.WARNING, + "Step 'Test-Step' already ended with true and now ended again with false."); + assertLogMessage(context, IdeLogLevel.ERROR, "unexpected situation!"); + assertLogMessage(context, IdeLogLevel.DEBUG, "Step 'Test-Step' ended with failure."); + } + + @Test + public void testInvalidUsageErrorSuccess() { + + // arrage + IdeTestContext context = newContext(PROJECT_BASIC, "project", false); + // act + Step step = context.newStep("Test-Step"); + try { + step.error("The Test-Step failed as expected"); + // WOW this is really inconsistent and hopefully never happens elsewhere + step.success("The Test-Step succeeded as expected"); + } finally { + step.end(); + } + assertThat(step.getSuccess()).isFalse(); + assertThat(step.getDuration()).isPositive(); + // assert + assertLogMessage(context, IdeLogLevel.TRACE, "Starting step Test-Step..."); + assertLogMessage(context, IdeLogLevel.STEP, "Start: Test-Step"); + assertLogMessage(context, IdeLogLevel.ERROR, "The Test-Step failed as expected"); + assertLogMessage(context, IdeLogLevel.DEBUG, "Step 'Test-Step' ended with failure."); + assertLogMessage(context, IdeLogLevel.WARNING, + "Step 'Test-Step' already ended with false and now ended again with true."); + assertLogMessage(context, IdeLogLevel.SUCCESS, "The Test-Step succeeded as expected"); + assertLogMessage(context, IdeLogLevel.DEBUG, "Step 'Test-Step' ended successfully."); + } + +} diff --git a/documentation/symlink.adoc b/documentation/symlink.adoc index 738c14c9f..3c1d11886 100644 --- a/documentation/symlink.adoc +++ b/documentation/symlink.adoc @@ -1,22 +1,22 @@ -:toc: -toc::[] - -= Symlink - -The creation of real symbolic links on Windows, requires the user to have according permissions. -In order to grant these permissions to yourself, run `secpol.msc` (`Local Security Policy`) and select `Local Policies/User Rights Assignment` - -1. Right click `Create Symbolic Link`, to open `Properties` and `Add User or Group` -+ -image::images/LocalSecurityPolicy.png[LocalSecurityPolicy] -+ -2. Add your own user account. -To do so you might need to be connected to a VPN depending on the company settings. - -[cols="3,1a,1a,3", frame=none, grid=none] -|=== -| -| image::images/LSPPoperty.png[] -| image::images/LSPAddUser.png[] -| -|=== +:toc: +toc::[] + += Symlink + +The creation of real symbolic links on Windows, requires the user to have according permissions. +In order to grant these permissions to yourself, run `secpol.msc` (`Local Security Policy`) and select `Local Policies/User Rights Assignment` + +1. Right click `Create Symbolic Link`, to open `Properties` and `Add User or Group` ++ +image::images/LocalSecurityPolicy.png[LocalSecurityPolicy] ++ +2. Add your own user account. +To do so you might need to be connected to a VPN depending on the company settings. + +[cols="3,1a,1a,3", frame=none, grid=none] +|=== +| +| image::images/LSPPoperty.png[] +| image::images/LSPAddUser.png[] +| +|===