diff --git a/.github/workflows/nightly-build.yml b/.github/workflows/nightly-build.yml index bcecb5fd1..1a6866734 100644 --- a/.github/workflows/nightly-build.yml +++ b/.github/workflows/nightly-build.yml @@ -30,19 +30,16 @@ jobs: - uses: actions/checkout@v3 with: submodules: recursive - - uses: graalvm/setup-graalvm@v1 with: java-version: '21.0.2' distribution: 'graalvm' github-token: ${{ secrets.GITHUB_TOKEN }} native-image-job-reports: 'true' - - name: Build native images with nativ maven plugin and extract in tar.gz shell: bash run: | - mvn -B -ntp -Pnative -DskipTests=true package - + mvn -B -ntp -Pnative -DskipTests=true package -pl cli - uses: actions/upload-artifact@v3 with: name: natives @@ -72,17 +69,3 @@ jobs: SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }} SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }} run: mvn --settings .mvn/settings.xml -DskipTests=true -Darchetype.test.skip=true -Dmaven.install.skip=true -Dgpg.skip=true -Dstyle.color=always -B -ntp -P deploy deploy - - cancel: - name: Cancel this workflow - runs-on: ubuntu-latest - needs: verify_commit - if: ${{ needs.verify_commit.outputs.RUN_BUILD == 'false' }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - OWNER: ${{ github.repository_owner }} - REPO: ${{ github.event.repository.name }} - RUN_ID: ${{ github.run_id }} - steps: - - run: | - curl -X POST -H "Accept: application/vnd.github+json" -H "Authorization: Bearer $GITHUB_TOKEN" "https://api.github.com/repos/$OWNER/$REPO/actions/runs/$RUN_ID/cancel" diff --git a/.mvn/maven.config b/.mvn/maven.config index 08d772b0c..0016b24be 100644 --- a/.mvn/maven.config +++ b/.mvn/maven.config @@ -1 +1 @@ --Drevision=2024.06.001-alpha-SNAPSHOT +-Drevision=2024.06.002-alpha-SNAPSHOT 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 b7f3a08b3..e86ee5c0e 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 @@ -2,6 +2,7 @@ import com.devonfw.tools.ide.context.GitContext; import com.devonfw.tools.ide.context.IdeContext; +import com.devonfw.tools.ide.property.FlagProperty; import com.devonfw.tools.ide.property.StringProperty; import com.devonfw.tools.ide.repo.CustomTool; import com.devonfw.tools.ide.step.Step; @@ -23,6 +24,9 @@ public abstract class AbstractUpdateCommandlet extends Commandlet { /** {@link StringProperty} for the settings repository URL. */ protected final StringProperty settingsRepo; + /** {@link FlagProperty} for skipping installation/updating of tools */ + protected final FlagProperty skipTools; + /** * The constructor. * @@ -31,6 +35,8 @@ public abstract class AbstractUpdateCommandlet extends Commandlet { public AbstractUpdateCommandlet(IdeContext context) { super(context); + addKeyword(getName()); + this.skipTools = add(new FlagProperty("--skip-tools", false, null)); this.settingsRepo = new StringProperty("", false, "settingsRepository"); } @@ -38,8 +44,18 @@ public AbstractUpdateCommandlet(IdeContext context) { public void run() { updateSettings(); - Path templatesFolder = this.context.getSettingsPath().resolve(IdeContext.FOLDER_TEMPLATES); + updateConf(); + if (skipTools.isTrue()) { + this.context.info("Skipping installation/update of tools as specified by the user."); + } else { + updateSoftware(); + } + } + + private void updateConf() { + + Path templatesFolder = this.context.getSettingsPath().resolve(IdeContext.FOLDER_TEMPLATES); if (!Files.exists(templatesFolder)) { Path legacyTemplatesFolder = this.context.getSettingsPath().resolve(IdeContext.FOLDER_LEGACY_TEMPLATES); if (Files.exists(legacyTemplatesFolder)) { @@ -57,7 +73,6 @@ public void run() { } finally { step.end(); } - updateSoftware(); } private void setupConf(Path template, Path conf) { 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 1f32e6477..ce57cca9a 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 @@ -68,7 +68,18 @@ public List> getValues() { } /** - * @param nameOrAlias the potential {@link Property#getName() name} or {@link Property#getAlias() alias} of the requested {@link Property}. + * Clear the set values on all properties of the {@link Commandlet#propertiesList} + */ + public void clearProperties() { + + for (Property property : this.propertiesList) { + property.clearValue(); + } + } + + /** + * @param nameOrAlias the potential {@link Property#getName() name} or {@link Property#getAlias() alias} of the + * requested {@link Property}. * @return the requested {@link Property property} or {@code null} if not found. */ public Property getOption(String nameOrAlias) { 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 5768f4010..1c75c4ca5 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 @@ -2,6 +2,7 @@ import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.io.FileAccess; +import com.devonfw.tools.ide.property.FlagProperty; import com.devonfw.tools.ide.property.StringProperty; import java.nio.file.Path; @@ -11,8 +12,12 @@ */ public class CreateCommandlet extends AbstractUpdateCommandlet { + /** {@link StringProperty} for the name of the new project */ public final StringProperty newProject; + /** {@link FlagProperty} for skipping the setup of git repositories */ + public final FlagProperty skipRepositories; + /** * The constructor. * @@ -21,8 +26,8 @@ public class CreateCommandlet extends AbstractUpdateCommandlet { public CreateCommandlet(IdeContext context) { super(context); - addKeyword(getName()); newProject = add(new StringProperty("", true, "project")); + this.skipRepositories = add(new FlagProperty("--skip-repositories", false, null)); add(this.settingsRepo); } @@ -54,7 +59,11 @@ public void run() { initializeProject(newProjectPath); this.context.setIdeHome(newProjectPath); super.run(); - updateRepositories(); + if (this.skipRepositories.isTrue()) { + this.context.info("Skipping the cloning of project repositories as specified by the user."); + } else { + updateRepositories(); + } this.context.success("Successfully created new project '{}'.", newProjectName); } 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 c0dcd68b3..01cce0d12 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 @@ -1,12 +1,12 @@ package com.devonfw.tools.ide.commandlet; -import java.util.Collection; - +import com.devonfw.tools.ide.context.AbstractIdeContext; import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.environment.VariableLine; import com.devonfw.tools.ide.os.WindowsPathSyntax; import com.devonfw.tools.ide.property.FlagProperty; -import com.devonfw.tools.ide.variable.IdeVariables; + +import java.util.Collection; /** * {@link Commandlet} to print the environment variables. @@ -49,46 +49,22 @@ public boolean isSuppressStepSuccess() { @Override public void run() { + WindowsPathSyntax pathSyntax = null; + if (this.context.getSystemInfo().isWindows()) { + if (this.bash.isTrue()) { + pathSyntax = WindowsPathSyntax.MSYS; + } else { + pathSyntax = WindowsPathSyntax.WINDOWS; + } + } + ((AbstractIdeContext) this.context).setPathSyntax(pathSyntax); Collection variables = this.context.getVariables().collectVariables(); for (VariableLine line : variables) { - if (this.context.getSystemInfo().isWindows()) { - line = normalizeWindowsValue(line); - } String lineValue = line.getValue(); - if (IdeVariables.PATH.getName().equals(line.getName())) { - lineValue = this.context.getPath().toString(this.bash.isTrue()); - } lineValue = "\"" + lineValue + "\""; line = line.withValue(lineValue); this.context.info(line.toString()); } } - VariableLine normalizeWindowsValue(VariableLine line) { - - String value = line.getValue(); - String normalized = normalizeWindowsValue(value); - if (normalized != value) { - line = line.withValue(normalized); - } - return line; - } - - String normalizeWindowsValue(String value) { - - WindowsPathSyntax pathSyntax; - if (this.bash.isTrue()) { - pathSyntax = WindowsPathSyntax.MSYS; - } else { - pathSyntax = WindowsPathSyntax.WINDOWS; - } - String drive = WindowsPathSyntax.WINDOWS.getDrive(value); - if (drive == null) { - drive = WindowsPathSyntax.MSYS.getDrive(value); - } - if (drive != null) { - value = pathSyntax.replaceDrive(value, drive); - } - return value; - } } 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 cccbfc1ae..f55251096 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 @@ -82,6 +82,10 @@ public void run() { collectOptions(options, cmd, bundle); } options.print(); + if (cmd == null) { + this.context.info(""); + this.context.info(bundle.getDetail(this.context.getCommandletManager().getCommandlet(HelpCommandlet.class))); + } } private void printCommandletHelp(NlsBundle bundle, Commandlet cmd) { @@ -115,6 +119,7 @@ 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")); values.print(); 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 4aa77e153..4fc3a60b7 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 @@ -15,7 +15,6 @@ public class UpdateCommandlet extends AbstractUpdateCommandlet { public UpdateCommandlet(IdeContext context) { super(context); - addKeyword(getName()); } @Override diff --git a/cli/src/main/java/com/devonfw/tools/ide/common/SystemPath.java b/cli/src/main/java/com/devonfw/tools/ide/common/SystemPath.java index b2ea708e8..d3b55a84c 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/common/SystemPath.java +++ b/cli/src/main/java/com/devonfw/tools/ide/common/SystemPath.java @@ -2,6 +2,7 @@ import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.os.SystemInfoImpl; +import com.devonfw.tools.ide.os.WindowsPathSyntax; import com.devonfw.tools.ide.variable.IdeVariables; import java.io.File; @@ -30,6 +31,8 @@ */ public class SystemPath { + private static final Pattern REGEX_WINDOWS_PATH = Pattern.compile("([a-zA-Z]:)?(\\\\[a-zA-Z0-9\\s_.-]+)+\\\\?"); + private final String envPath; private final char pathSeparator; @@ -66,9 +69,9 @@ public SystemPath(IdeContext context, String envPath) { /** * The constructor. * - * @param context {@link IdeContext} for the output of information. - * @param envPath the value of the PATH variable. - * @param ideRoot the {@link IdeContext#getIdeRoot() IDE_ROOT}. + * @param context {@link IdeContext} for the output of information. + * @param envPath the value of the PATH variable. + * @param ideRoot the {@link IdeContext#getIdeRoot() IDE_ROOT}. * @param softwarePath the {@link IdeContext#getSoftwarePath() software path}. */ public SystemPath(IdeContext context, String envPath, Path ideRoot, Path softwarePath) { @@ -79,10 +82,10 @@ public SystemPath(IdeContext context, String envPath, Path ideRoot, Path softwar /** * The constructor. * - * @param context {@link IdeContext} for the output of information. - * @param envPath the value of the PATH variable. - * @param ideRoot the {@link IdeContext#getIdeRoot() IDE_ROOT}. - * @param softwarePath the {@link IdeContext#getSoftwarePath() software path}. + * @param context {@link IdeContext} for the output of information. + * @param envPath the value of the PATH variable. + * @param ideRoot the {@link IdeContext#getIdeRoot() IDE_ROOT}. + * @param softwarePath the {@link IdeContext#getSoftwarePath() software path}. * @param pathSeparator the path separator char (';' for Windows and ':' otherwise). */ public SystemPath(IdeContext context, String envPath, Path ideRoot, Path softwarePath, char pathSeparator) { @@ -219,62 +222,45 @@ public void setPath(String tool, Path path) { @Override public String toString() { - return toString(false); + return toString(null); } /** - * @param bash - {@code true} to convert the PATH to bash syntax (relevant for git-bash or cygwin on windows), - * {@code false} otherwise. + * @param pathSyntax the {@link WindowsPathSyntax} to convert to. * @return this {@link SystemPath} as {@link String} for the PATH environment variable. */ - public String toString(boolean bash) { + public String toString(WindowsPathSyntax pathSyntax) { char separator; - if (bash) { + if (pathSyntax == WindowsPathSyntax.MSYS) { separator = ':'; } else { separator = this.pathSeparator; } StringBuilder sb = new StringBuilder(this.envPath.length() + 128); for (Path path : this.tool2pathMap.values()) { - appendPath(path, sb, separator, bash); + appendPath(path, sb, separator, pathSyntax); } for (Path path : this.paths) { - appendPath(path, sb, separator, bash); + appendPath(path, sb, separator, pathSyntax); } return sb.toString(); } - private static void appendPath(Path path, StringBuilder sb, char separator, boolean bash) { + private static void appendPath(Path path, StringBuilder sb, char separator, WindowsPathSyntax pathSyntax) { if (sb.length() > 0) { sb.append(separator); } - String pathString = path.toString(); - if (bash && (pathString.length() > 3) && (pathString.charAt(1) == ':')) { - pathString = convertWindowsPathToUnixPath(pathString); + String pathString; + if (pathSyntax == null) { + pathString = path.toString(); + } else { + pathString = pathSyntax.format(path); } sb.append(pathString); } - /** - * Method to convert a valid Windows path string representation to its corresponding one in Unix format. - * - * @param pathString The Windows path string to convert. - * @return The converted Unix path string. - */ - public static String convertWindowsPathToUnixPath(String pathString) { - - char slash = pathString.charAt(2); - if ((slash == '\\') || (slash == '/')) { - char drive = Character.toLowerCase(pathString.charAt(0)); - if ((drive >= 'a') && (drive <= 'z')) { - pathString = "/" + drive + pathString.substring(2).replace('\\', '/'); - } - } - return pathString; - } - /** * Method to validate if a given path string is a Windows path or not * @@ -283,7 +269,6 @@ public static String convertWindowsPathToUnixPath(String pathString) { */ public static boolean isValidWindowsPath(String pathString) { - String windowsFilePathRegEx = "([a-zA-Z]:)?(\\\\[a-zA-Z0-9\\s_.-]+)+\\\\?"; - return Pattern.matches(windowsFilePathRegEx, pathString); + return REGEX_WINDOWS_PATH.matcher(pathString).matches(); } } 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 9ce391150..76daa9ef8 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 @@ -25,6 +25,7 @@ import com.devonfw.tools.ide.network.ProxyContext; import com.devonfw.tools.ide.os.SystemInfo; import com.devonfw.tools.ide.os.SystemInfoImpl; +import com.devonfw.tools.ide.os.WindowsPathSyntax; import com.devonfw.tools.ide.process.ProcessContext; import com.devonfw.tools.ide.process.ProcessContextImpl; import com.devonfw.tools.ide.process.ProcessResult; @@ -99,6 +100,8 @@ public abstract class AbstractIdeContext implements IdeContext { private SystemPath path; + private WindowsPathSyntax pathSyntax; + private final SystemInfo systemInfo; private EnvironmentVariables variables; @@ -174,14 +177,14 @@ public AbstractIdeContext(IdeLogLevel minLogLevel, Function collectVariables(boolean onlyExported) { for (String name : variableNames) { boolean export = isExported(name); if (!onlyExported || export) { - String value = get(name); + String value = get(name, false); if (value != null) { variables.add(VariableLine.of(export, name, value)); } @@ -143,7 +147,7 @@ protected void collectVariables(Set variables) { /** * @param propertiesFilePath the {@link #getPropertiesFilePath() propertiesFilePath} of the child {@link EnvironmentVariables}. - * @param type the {@link #getType() type}. + * @param type the {@link #getType() type}. * @return the new {@link EnvironmentVariables}. */ public AbstractEnvironmentVariables extend(Path propertiesFilePath, EnvironmentVariablesType type) { @@ -168,21 +172,21 @@ public String resolve(String string, Object src) { /** * This method is called recursively. This allows you to resolve variables that are defined by other variables. * - * @param value the {@link String} that potentially contains variables in the syntax "${«variable«}". Those will be resolved by this method and replaced with - * their {@link #get(String) value}. - * @param src the source where the {@link String} to resolve originates from. Should have a reasonable {@link Object#toString() string representation} that - * will be used in error or log messages if a variable could not be resolved. - * @param recursion the current recursion level. This is used to interrupt endless recursion. - * @param rootSrc the root source where the {@link String} to resolve originates from. - * @param rootValue the root value to resolve. + * @param value the {@link String} that potentially contains variables in the syntax "${«variable«}". Those will be resolved by this method and replaced with + * their {@link #get(String) value}. + * @param src the source where the {@link String} to resolve originates from. Should have a reasonable {@link Object#toString() string representation} that + * will be used in error or log messages if a variable could not be resolved. + * @param recursion the current recursion level. This is used to interrupt endless recursion. + * @param rootSrc the root source where the {@link String} to resolve originates from. + * @param rootValue the root value to resolve. * @param resolvedVars this is a reference to an object of {@link EnvironmentVariablesResolved} being the lowest level in the - * {@link EnvironmentVariablesType hierarchy} of variables. In case of a self-referencing variable {@code x} the resolving has to continue one level higher in - * the {@link EnvironmentVariablesType hierarchy} to avoid endless recursion. The {@link EnvironmentVariablesResolved} is then used if another variable - * {@code y} must be resolved, since resolving this variable has to again start at the lowest level. For example: For levels {@code l1, l2} with - * {@code l1 < l2} and {@code x=${x} foo} and {@code y=bar} defined at level {@code l1} and {@code x=test ${y}} defined at level {@code l2}, {@code x} is - * first resolved at level {@code l1} and then up the {@link EnvironmentVariablesType hierarchy} at {@code l2} to avoid endless recursion. However, {@code y} - * must be resolved starting from the lowest level in the {@link EnvironmentVariablesType hierarchy} and therefore {@link EnvironmentVariablesResolved} is - * used. + * {@link EnvironmentVariablesType hierarchy} of variables. In case of a self-referencing variable {@code x} the resolving has to continue one level higher in + * the {@link EnvironmentVariablesType hierarchy} to avoid endless recursion. The {@link EnvironmentVariablesResolved} is then used if another variable + * {@code y} must be resolved, since resolving this variable has to again start at the lowest level. For example: For levels {@code l1, l2} with + * {@code l1 < l2} and {@code x=${x} foo} and {@code y=bar} defined at level {@code l1} and {@code x=test ${y}} defined at level {@code l2}, {@code x} is + * first resolved at level {@code l1} and then up the {@link EnvironmentVariablesType hierarchy} at {@code l2} to avoid endless recursion. However, {@code y} + * must be resolved starting from the lowest level in the {@link EnvironmentVariablesType hierarchy} and therefore {@link EnvironmentVariablesResolved} is + * used. * @return the given {@link String} with the variables resolved. */ private String resolve(String value, Object src, int recursion, Object rootSrc, String rootValue, AbstractEnvironmentVariables resolvedVars) { @@ -228,7 +232,7 @@ private String resolve(String value, Object src, int recursion, Object rootSrc, // resolving a self referencing variable one level up the hierarchy of EnvironmentVariablesType, i.e. at "next", // to avoid endless recursion String replacement = ((AbstractEnvironmentVariables) next).resolve(next.getFlat(variableName), variableName, recursion, rootSrc, rootValue, - resolvedVars); + resolvedVars); matcher.appendReplacement(sb, Matcher.quoteReplacement(replacement)); } @@ -242,9 +246,9 @@ private String resolve(String value, Object src, int recursion, Object rootSrc, /** * Like {@link #get(String)} but with higher-level features including to resolve {@link IdeVariables} with their default values. * - * @param name the name of the variable to get. + * @param name the name of the variable to get. * @param ignoreDefaultValue - {@code true} if the {@link VariableDefinition#getDefaultValue(IdeContext) default value} of a potential - * {@link VariableDefinition} shall be ignored, {@code false} to return default instead of {@code null}. + * {@link VariableDefinition} shall be ignored, {@code false} to return default instead of {@code null}. * @return the value of the variable. */ protected String getValue(String name, boolean ignoreDefaultValue) { @@ -254,14 +258,14 @@ protected String getValue(String name, boolean ignoreDefaultValue) { if ((var != null) && var.isForceDefaultValue()) { value = var.getDefaultValueAsString(this.context); } else { - value = this.parent.get(name); + value = this.parent.get(name, false); } if ((value == null) && (var != null)) { String key = var.getName(); if (!name.equals(key)) { // try new name (e.g. IDE_TOOLS or IDE_HOME) if no value could be found by given legacy name (e.g. // DEVON_IDE_TOOLS or DEVON_IDE_HOME) - value = this.parent.get(key); + value = this.parent.get(key, false); } if ((value == null) && !ignoreDefaultValue) { value = var.getDefaultValueAsString(this.context); 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 320ee00f0..078721a6e 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 @@ -1,8 +1,9 @@ package com.devonfw.tools.ide.environment; -import java.util.Map; - import com.devonfw.tools.ide.context.IdeContext; +import com.devonfw.tools.ide.os.WindowsPathSyntax; + +import java.util.Map; /** * Implementation of {@link EnvironmentVariables}. @@ -12,7 +13,7 @@ abstract class EnvironmentVariablesMap extends AbstractEnvironmentVariables { /** * The constructor. * - * @param parent the parent {@link EnvironmentVariables} to inherit from. + * @param parent the parent {@link EnvironmentVariables} to inherit from. * @param context the {@link IdeContext}. */ EnvironmentVariablesMap(AbstractEnvironmentVariables parent, IdeContext context) { @@ -34,6 +35,14 @@ public String getFlat(String name) { this.context.trace("{}: Variable {} is undefined.", getSource(), name); } else { this.context.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); + value = normalized; + } + } } return value; } diff --git a/cli/src/main/java/com/devonfw/tools/ide/environment/EnvironmentVariablesResolved.java b/cli/src/main/java/com/devonfw/tools/ide/environment/EnvironmentVariablesResolved.java index 748860463..f88fc6ba4 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/environment/EnvironmentVariablesResolved.java +++ b/cli/src/main/java/com/devonfw/tools/ide/environment/EnvironmentVariablesResolved.java @@ -1,10 +1,10 @@ package com.devonfw.tools.ide.environment; -import java.util.Set; - import com.devonfw.tools.ide.variable.IdeVariables; import com.devonfw.tools.ide.variable.VariableDefinition; +import java.util.Set; + /** * Implementation of {@link EnvironmentVariables} that resolves variables recursively. */ 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 a72fb2b43..1bab5da06 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 @@ -54,6 +54,12 @@ */ public class FileAccessImpl implements FileAccess { + 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 = + "On Windows, file operations could fail due to file locks. Please ensure the files in the moved directory are not in use. For further details, see: \n" + + WINDOWS_FILE_LOCK_DOCUMENTATION_PAGE; + private final IdeContext context; /** @@ -275,7 +281,12 @@ public void move(Path source, Path targetDir) { try { Files.move(source, targetDir); } catch (IOException e) { - throw new IllegalStateException("Failed to move " + source + " to " + targetDir, e); + String fileType = Files.isSymbolicLink(source) ? "symlink" : isJunction(source) ? "junction" : Files.isDirectory(source) ? "directory" : "file"; + String message = "Failed to move " + fileType + ": " + source + " to " + targetDir + "."; + if (this.context.getSystemInfo().isWindows()) { + message = message + "\n" + WINDOWS_FILE_LOCK_WARNING; + } + throw new IllegalStateException(message, e); } } 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 493c6b979..59812cd82 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 @@ -1,12 +1,12 @@ package com.devonfw.tools.ide.nls; -import java.util.Locale; -import java.util.ResourceBundle; - import com.devonfw.tools.ide.commandlet.Commandlet; import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.property.Property; +import java.util.Locale; +import java.util.ResourceBundle; + /** * Wrapper for {@link ResourceBundle} to avoid {@link java.util.MissingResourceException}. */ @@ -22,7 +22,7 @@ public class NlsBundle { * The constructor. * * @param context the {@link IdeContext}. - * @param name the simple name of {@link ResourceBundle} (e.g. "Cli"). + * @param name the simple name of {@link ResourceBundle} (e.g. "Cli"). */ public NlsBundle(IdeContext context, String name) { @@ -33,7 +33,7 @@ public NlsBundle(IdeContext context, String name) { * The constructor. * * @param context the {@link IdeContext}. - * @param locale the explicit {@link Locale} to use. + * @param locale the explicit {@link Locale} to use. */ public NlsBundle(IdeContext context, Locale locale) { @@ -44,8 +44,8 @@ public NlsBundle(IdeContext context, Locale locale) { * The constructor. * * @param context the {@link IdeContext}. - * @param name the simple name of {@link ResourceBundle} (e.g. "Cli"). - * @param locale the explicit {@link Locale} to use. + * @param name the simple name of {@link ResourceBundle} (e.g. "Cli"). + * @param locale the explicit {@link Locale} to use. */ public NlsBundle(IdeContext context, String name, Locale locale) { @@ -81,8 +81,7 @@ public String getOrNull(String key) { } /** - * @param commandlet the {@link com.devonfw.tools.ide.commandlet.Commandlet#getName() name} of the - * {@link com.devonfw.tools.ide.commandlet.Commandlet}. + * @param commandlet the {@link com.devonfw.tools.ide.commandlet.Commandlet} to get the help summary for. * @return the localized message (translated to the users language). */ public String get(Commandlet commandlet) { @@ -90,9 +89,18 @@ public String get(Commandlet commandlet) { return get("cmd." + commandlet.getName()); } + /** + * @param commandlet the {@link com.devonfw.tools.ide.commandlet.Commandlet} to get the help detail for. + * @return the localized message (translated to the users language). + */ + public String getDetail(Commandlet commandlet) { + + return get("cmd." + commandlet.getName() + ".detail"); + } + /** * @param commandlet the {@link Commandlet} {@link Commandlet#getProperties() owning} the given {@link Property}. - * @param property the {@link Property} to the the description of. + * @param property the {@link Property} to the the description of. * @return the localized message describing the property. */ public String get(Commandlet commandlet, Property property) { diff --git a/cli/src/main/java/com/devonfw/tools/ide/os/WindowsPathSyntax.java b/cli/src/main/java/com/devonfw/tools/ide/os/WindowsPathSyntax.java index 92f573e8b..6a3535d51 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/os/WindowsPathSyntax.java +++ b/cli/src/main/java/com/devonfw/tools/ide/os/WindowsPathSyntax.java @@ -1,24 +1,35 @@ package com.devonfw.tools.ide.os; +import java.nio.file.Path; import java.util.Locale; import java.util.Objects; /** - * TODO hohwille This type ... - * + * Syntax of an absolute {@link Path} on Windows. The standard syntax is obviously {@link #WINDOWS}, however there is also + * {@link #MSYS} for shells based on MSYS like the famous git-bash that uses a linux compatible path syntax. */ public enum WindowsPathSyntax { - /** Windows path like "C:\..." or "D:\...". */ - WINDOWS, + /** + * Windows path like "C:\..." or "D:\...". + */ + WINDOWS('\\'), + + /** + * MSys (git-bash) path like "/c/..." or "/d/...". + */ + MSYS('/'); - /** MSys (git-bash) path like "/c/..." or "/d/...". */ - MSYS; + private final char separator; + + private WindowsPathSyntax(char separator) { + this.separator = separator; + } /** * @param path the potential path. May be any {@link String}. * @return the the drive letter (e.g. "C" or "D") or {@code null} if the given {@link String} is not a path in this - * {@link WindowsPathSyntax}. + * {@link WindowsPathSyntax}. */ public String getDrive(String path) { @@ -28,7 +39,7 @@ public String getDrive(String path) { char c2 = path.charAt(2); switch (this) { case WINDOWS: // 'C:\' - if ((c1 == ':') && (c2 == '\\') && (c0 >= 'A') && (c0 <= 'Z')) { + if ((c1 == ':') && isSlash(c2) && (c0 >= 'A') && (c0 <= 'Z')) { return Character.toString(c0); } break; @@ -44,17 +55,93 @@ public String getDrive(String path) { return null; } + private static boolean isSlash(char c2) { + // on Windows both slash (/) and backslash (\) are acceptable as folder separator in a Path + // While strict Windows syntax is to use backslash we are tolerant here so our Windows users can also configure + // a path in ide.properties using slashes since backslash is the escape character in Java properties files and then + // users have to use double backslash. + return (c2 == '\\') || (c2 == '/'); + } + private static boolean isLowerLatinLetter(char c) { return (c >= 'a') && (c <= 'z'); } /** - * @param path the path where to replace the drive letter. + * @param path the {@link Path} to format. + * @return the given {@link Path} formatted as {@link String} to this {@link WindowsPathSyntax}. + */ + public String format(Path path) { + + if (path == null) { + return null; + } + int nameCount = path.getNameCount(); + StringBuilder sb = new StringBuilder(nameCount * 6); + int start = formatRootPath(path, sb); + for (int i = start; i < nameCount; i++) { + if (i > 0) { + sb.append(this.separator); + } + Path segment = path.getName(i); + sb.append(segment); + } + return sb.toString(); + } + + private int formatRootPath(Path path, StringBuilder sb) { + + Path root = path.getRoot(); + if (root == null) { + return 0; + } + String rootString = root.toString(); + int length = rootString.length(); + if ((length == 3) && (rootString.charAt(1) == ':') && (rootString.charAt(2) == '\\')) { + // so we have a WINDOWS driver letter as root + char drive = Character.toLowerCase(rootString.charAt(0)); + if (isLowerLatinLetter(drive)) { + if (this == MSYS) { + sb.append(this.separator); + sb.append(drive); + sb.append(this.separator); + } else { + sb.append(rootString); // nothing to convert from WINDOWS to WINDOWS + } + return 0; + } + } + if ((length == 1) && (this == WINDOWS)) { + if (path.getNameCount() > 0) { + root = path.getName(0); + String drive = root.toString(); + if (drive.length() == 1) { + char c = drive.charAt(0); + if ((isLowerLatinLetter(c))) { + // so we have a path starting with a driver letter in MSYS syntax (e.g. "/c/") but want WINDOWS syntax + sb.append(Character.toUpperCase(c)); + sb.append(':'); + return 1; + } + } + } + } + sb.append(this.separator); + if (length > 1) { + // this should actually never happen and only exists for robustness in odd edge-cases + sb.append(rootString, 1, length); + sb.append(this.separator); + } + return 0; + } + + /** + * @param path the path where to replace the drive letter. * @param drive the new {@link #getDrive(String) drive letter}. * @return the new path pointing to the given {@code drive} in this {@link WindowsPathSyntax}. */ - public String replaceDrive(String path, String drive) { + public String normalize(String path, String drive) { Objects.requireNonNull(path); Objects.requireNonNull(drive); @@ -70,6 +157,18 @@ public String replaceDrive(String path, String drive) { return getRootPath(drive) + restPath; } + public String normalize(String value) { + + String drive = WindowsPathSyntax.WINDOWS.getDrive(value); + if (drive == null) { + drive = WindowsPathSyntax.MSYS.getDrive(value); + } + if (drive != null) { + value = normalize(value, drive); + } + return value; + } + /** * @param drive the drive letter (e.g. "C" or "D"). * @return the root path for the given {@code drive} (e.g. "C:\\" or "/c/"). @@ -87,4 +186,21 @@ public String getRootPath(String drive) { }; } + /** + * Normalizes a {@link String} that may be an absolute Windows {@link Path}. + * + * @param value the {@link String} to normalize. + * @param bash - {@code true} to convert paths to {@link #MSYS} (git-bash), {@code false} for {@link #WINDOWS}. + * @return the given {@code value} that was normalized if it has been an absolute Windows {@link Path}. + */ + public static String normalize(String value, boolean bash) { + + WindowsPathSyntax targetSyntax; + if (bash) { + targetSyntax = WindowsPathSyntax.MSYS; + } else { + targetSyntax = WindowsPathSyntax.WINDOWS; + } + return targetSyntax.normalize(value); + } } 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 4f7e5d382..f89abae9d 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 @@ -1,5 +1,14 @@ package com.devonfw.tools.ide.process; +import com.devonfw.tools.ide.cli.CliException; +import com.devonfw.tools.ide.common.SystemPath; +import com.devonfw.tools.ide.context.IdeContext; +import com.devonfw.tools.ide.environment.VariableLine; +import com.devonfw.tools.ide.log.IdeSubLogger; +import com.devonfw.tools.ide.os.SystemInfoImpl; +import com.devonfw.tools.ide.os.WindowsPathSyntax; +import com.devonfw.tools.ide.util.FilenameUtil; + import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; @@ -15,14 +24,6 @@ import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; -import com.devonfw.tools.ide.cli.CliException; -import com.devonfw.tools.ide.common.SystemPath; -import com.devonfw.tools.ide.context.IdeContext; -import com.devonfw.tools.ide.environment.VariableLine; -import com.devonfw.tools.ide.log.IdeSubLogger; -import com.devonfw.tools.ide.os.SystemInfoImpl; -import com.devonfw.tools.ide.util.FilenameUtil; - /** * Implementation of {@link ProcessContext}. */ @@ -76,7 +77,7 @@ public ProcessContext directory(Path directory) { this.processBuilder.directory(directory.toFile()); } else { this.context.debug( - "Could not set the process builder's working directory! Directory of the current java process is used."); + "Could not set the process builder's working directory! Directory of the current java process is used."); } return this; @@ -314,7 +315,7 @@ private void modifyArgumentsOnBackgroundProcess(ProcessMode processMode) { String bash = this.context.findBash(); if (bash == null) { context.warning( - "Cannot start background process via bash because no bash installation was found. Hence, output will be discarded."); + "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; } @@ -337,8 +338,8 @@ private String buildCommandToRunInBackground() { for (String argument : this.arguments) { - if (SystemPath.isValidWindowsPath(argument)) { - argument = SystemPath.convertWindowsPathToUnixPath(argument); + if (SystemInfoImpl.INSTANCE.isWindows() && SystemPath.isValidWindowsPath(argument)) { + argument = WindowsPathSyntax.MSYS.normalize(argument); } stringBuilder.append(argument); 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 a936f7b7f..30895f70f 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 @@ -231,12 +231,17 @@ protected String format(V valueToFormat) { */ public void setValue(V value) { - if (!this.multivalued) { - this.value.clear(); - } this.value.add(value); } + /** + * Clears the {@link #value value} list. + */ + public void clearValue() { + + this.value.clear(); + } + public void addValue(V value) { if (!this.multivalued) { @@ -454,7 +459,9 @@ public boolean validate() { return false; } if (this.validator != null) { - this.validator.accept(getValue()); + for (V value : this.value) { + this.validator.accept(value); + } } return true; } diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/jasypt/Jasypt.java b/cli/src/main/java/com/devonfw/tools/ide/tool/jasypt/Jasypt.java index a6f7aff99..c23272fd4 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/jasypt/Jasypt.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/jasypt/Jasypt.java @@ -9,18 +9,24 @@ import com.devonfw.tools.ide.tool.java.Java; import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import java.util.Set; /** - * {@link ToolCommandlet} for Jasypt, The java library which allows to add basic - * encryption capabilities with minimum effort. + * {@link ToolCommandlet} for Jasypt, The java library which allows to add basic encryption capabilities with minimum + * effort. */ public class Jasypt extends LocalToolCommandlet { + /** {@link EnumProperty} for the command (encrypt or decrypt) */ public final EnumProperty command; + /** {@link PasswordProperty} for the master password */ public final PasswordProperty masterPassword; + /** {@link PasswordProperty} for the secret to be encrypted or decrypted */ public final PasswordProperty secret; private static final String CLASS_NAME_ENCRYPTION = "org.jasypt.intf.cli.JasyptPBEStringEncryptionCLI"; @@ -84,14 +90,18 @@ public void run() { private void runJasypt(String className) { - Java java = getCommandlet(Java.class); + List arguments = new ArrayList<>( + Arrays.asList("-cp", resolveJasyptJarPath().toString(), className, "password=" + this.masterPassword.getValue(), "input=" + this.secret.getValue())); + + String jasyptOpts = this.context.getVariables().get("JASYPT_OPTS"); + if (jasyptOpts != null && !jasyptOpts.trim().isEmpty()) { + String[] jasyptOptions = jasyptOpts.split("\\s+"); - String[] jasyptOptions = this.context.getVariables().get("JASYPT_OPTS").split(" "); - String algorithm = jasyptOptions[0]; - String generatorClassName = jasyptOptions[1]; + arguments.addAll(Arrays.asList(jasyptOptions)); + } - java.runTool(null, "-cp", resolveJasyptJarPath().toString(), className, algorithm, generatorClassName, - "password=" + this.masterPassword.getValue(), "input=" + this.secret.getValue()); + Java java = getCommandlet(Java.class); + java.runTool(null, arguments.toArray(new String[0])); } private Path resolveJasyptJarPath() { diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/jasypt/JasyptUrlUpdater.java b/cli/src/main/java/com/devonfw/tools/ide/tool/jasypt/JasyptUrlUpdater.java index 5dd1629a3..a56caf0e2 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/jasypt/JasyptUrlUpdater.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/jasypt/JasyptUrlUpdater.java @@ -1,11 +1,15 @@ package com.devonfw.tools.ide.tool.jasypt; import com.devonfw.tools.ide.url.updater.MavenBasedUrlUpdater; +import com.devonfw.tools.ide.version.VersionIdentifier; /** * {@link MavenBasedUrlUpdater} for jasypt */ public class JasyptUrlUpdater extends MavenBasedUrlUpdater { + + public static final VersionIdentifier MIN_VERSION = VersionIdentifier.of("1.9.3"); + @Override protected String getTool() { @@ -24,4 +28,14 @@ protected String getMavenArtifcatId() { return "jasypt"; } + @Override + public boolean isValidVersion(String version) { + + VersionIdentifier artifactVersion = VersionIdentifier.of(version); + if (artifactVersion != null) { + return artifactVersion.isGreaterOrEqual(MIN_VERSION); + } + return false; + } + } diff --git a/cli/src/main/java/com/devonfw/tools/ide/url/updater/MavenBasedUrlUpdater.java b/cli/src/main/java/com/devonfw/tools/ide/url/updater/MavenBasedUrlUpdater.java index 46e0317e1..491968c1c 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/url/updater/MavenBasedUrlUpdater.java +++ b/cli/src/main/java/com/devonfw/tools/ide/url/updater/MavenBasedUrlUpdater.java @@ -1,13 +1,13 @@ package com.devonfw.tools.ide.url.updater; -import java.io.IOException; -import java.util.HashSet; -import java.util.Set; - import com.devonfw.tools.ide.maven.MavenMetadata; import com.devonfw.tools.ide.url.model.folder.UrlVersion; import com.fasterxml.jackson.dataformat.xml.XmlMapper; +import java.io.IOException; +import java.util.HashSet; +import java.util.Set; + /** * The MvnCrawler class is an abstract class that provides functionality for crawling Maven repositories. */ @@ -23,8 +23,7 @@ public abstract class MavenBasedUrlUpdater extends AbstractUrlUpdater { public MavenBasedUrlUpdater() { super(); - this.mavenBaseRepoUrl = "https://repo1.maven.org/maven2/" + getMavenGroupIdPath() + "/" + getMavenArtifcatId() - + "/"; + this.mavenBaseRepoUrl = "https://repo1.maven.org/maven2/" + getMavenGroupIdPath() + "/" + getMavenArtifcatId() + "/"; } @@ -74,7 +73,9 @@ private Set doGetVersionsFromMavenApi(String url) { XmlMapper mapper = new XmlMapper(); MavenMetadata metaData = mapper.readValue(response, MavenMetadata.class); for (String version : metaData.getVersioning().getVersions()) { - addVersion(version, versions); + if (isValidVersion(version)) { + addVersion(version, versions); + } } } catch (IOException e) { throw new IllegalStateException("Failed to get version from " + url, e); @@ -82,4 +83,15 @@ private Set doGetVersionsFromMavenApi(String url) { return versions; } + /** + * Subclasses should override this method to enforce version validation. + * + * @param version the version of the artifact. + * @return true as default implementation. + */ + protected boolean isValidVersion(String version) { + + return true; + } + } diff --git a/cli/src/main/java/com/devonfw/tools/ide/variable/VariableDefinition.java b/cli/src/main/java/com/devonfw/tools/ide/variable/VariableDefinition.java index 2c1a5301b..314160e80 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/variable/VariableDefinition.java +++ b/cli/src/main/java/com/devonfw/tools/ide/variable/VariableDefinition.java @@ -20,7 +20,7 @@ public interface VariableDefinition { /** * @return the optional legacy name that is still supported for downward compatibility. May be {@code null} if - * undefined (no legacy support). + * undefined (no legacy support). */ String getLegacyName(); @@ -39,7 +39,7 @@ public interface VariableDefinition { * @param context the {@link IdeContext}. * @return the default value as {@link String}. May be {@code null}. * @see #getDefaultValue(IdeContext) - * @see #toString(Object) + * @see #toString(Object, IdeContext) */ default String getDefaultValueAsString(IdeContext context) { @@ -47,18 +47,18 @@ default String getDefaultValueAsString(IdeContext context) { if (value == null) { return null; } - return toString(value); + return toString(value, context); } /** * @return {@code true} if the {@link #getDefaultValue(IdeContext) default value} shall be used without any - * {@link EnvironmentVariables#get(String) variable lookup} (to prevent odd overriding of build in variables - * like IDE_HOME), {@code false} otherwise (overriding of default value is allowed and intended). + * {@link EnvironmentVariables#get(String) variable lookup} (to prevent odd overriding of build in variables + * like IDE_HOME), {@code false} otherwise (overriding of default value is allowed and intended). */ boolean isForceDefaultValue(); /** - * @param value the value as {@link String}. May NOT be {@code null}. + * @param value the value as {@link String}. May NOT be {@code null}. * @param context the {@link IdeContext}. * @return the value converted to the {@link #getValueType() value type}. */ @@ -70,10 +70,11 @@ default String getDefaultValueAsString(IdeContext context) { boolean isExport(); /** - * @param value the typed value. + * @param value the typed value. + * @param context the {@link IdeContext}. * @return the value converted to {@link String}. */ - default String toString(V value) { + default String toString(V value, IdeContext context) { if (value == null) { return ""; diff --git a/cli/src/main/java/com/devonfw/tools/ide/variable/VariableDefinitionPath.java b/cli/src/main/java/com/devonfw/tools/ide/variable/VariableDefinitionPath.java index 55d3f0eae..776b3142d 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/variable/VariableDefinitionPath.java +++ b/cli/src/main/java/com/devonfw/tools/ide/variable/VariableDefinitionPath.java @@ -1,6 +1,7 @@ package com.devonfw.tools.ide.variable; import com.devonfw.tools.ide.context.IdeContext; +import com.devonfw.tools.ide.os.WindowsPathSyntax; import java.nio.file.Path; import java.util.function.Function; @@ -23,7 +24,7 @@ public VariableDefinitionPath(String name) { /** * The constructor. * - * @param name the {@link #getName() variable name}. + * @param name the {@link #getName() variable name}. * @param legacyName the {@link #getLegacyName() legacy name}. */ public VariableDefinitionPath(String name, String legacyName) { @@ -34,8 +35,8 @@ public VariableDefinitionPath(String name, String legacyName) { /** * The constructor. * - * @param name the {@link #getName() variable name}. - * @param legacyName the {@link #getLegacyName() legacy name}. + * @param name the {@link #getName() variable name}. + * @param legacyName the {@link #getLegacyName() legacy name}. * @param defaultValueFactory the factory {@link Function} for the {@link #getDefaultValue(IdeContext) default value}. */ public VariableDefinitionPath(String name, String legacyName, Function defaultValueFactory) { @@ -46,10 +47,10 @@ public VariableDefinitionPath(String name, String legacyName, Function defaultValueFactory, boolean forceDefaultValue) { @@ -59,11 +60,11 @@ public VariableDefinitionPath(String name, String legacyName, Function defaultValueFactory, boolean forceDefaultValue, boolean export) { @@ -81,4 +82,15 @@ public Path fromString(String value, IdeContext context) { return Path.of(value); } + + @Override + public String toString(Path value, IdeContext context) { + WindowsPathSyntax pathSyntax = context.getPathSyntax(); + if (pathSyntax != null) { + return pathSyntax.format(value); + } else { + // avoid backslashes since they can cause trouble in files like *.properties since they are treated as escape char + return value.toString().replace('\\', '/'); + } + } } diff --git a/cli/src/main/java/com/devonfw/tools/ide/variable/VariableDefinitionStringList.java b/cli/src/main/java/com/devonfw/tools/ide/variable/VariableDefinitionStringList.java index 58b081efb..b51c15b16 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/variable/VariableDefinitionStringList.java +++ b/cli/src/main/java/com/devonfw/tools/ide/variable/VariableDefinitionStringList.java @@ -1,13 +1,13 @@ package com.devonfw.tools.ide.variable; +import com.devonfw.tools.ide.context.IdeContext; +import com.devonfw.tools.ide.environment.VariableLine; + import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.function.Function; -import com.devonfw.tools.ide.context.IdeContext; -import com.devonfw.tools.ide.environment.VariableLine; - /** * Implementation of {@link VariableDefinition} for a variable with the {@link #getValueType() value type} * {@link String}. @@ -27,7 +27,7 @@ public VariableDefinitionStringList(String name) { /** * The constructor. * - * @param name the {@link #getName() variable name}. + * @param name the {@link #getName() variable name}. * @param legacyName the {@link #getLegacyName() legacy name}. */ public VariableDefinitionStringList(String name, String legacyName) { @@ -38,12 +38,12 @@ public VariableDefinitionStringList(String name, String legacyName) { /** * The constructor. * - * @param name the {@link #getName() variable name}. - * @param legacyName the {@link #getLegacyName() legacy name}. + * @param name the {@link #getName() variable name}. + * @param legacyName the {@link #getLegacyName() legacy name}. * @param defaultValueFactory the factory {@link Function} for the {@link #getDefaultValue(IdeContext) default value}. */ public VariableDefinitionStringList(String name, String legacyName, - Function> defaultValueFactory) { + Function> defaultValueFactory) { super(name, legacyName, defaultValueFactory); } @@ -51,18 +51,18 @@ public VariableDefinitionStringList(String name, String legacyName, /** * The constructor. * - * @param name the {@link #getName() variable name}. - * @param legacyName the {@link #getLegacyName() legacy name}. + * @param name the {@link #getName() variable name}. + * @param legacyName the {@link #getLegacyName() legacy name}. * @param defaultValueFactory the factory {@link Function} for the {@link #getDefaultValue(IdeContext) default value}. - * @param forceDefaultValue the {@link #isForceDefaultValue() forceDefaultValue} flag. + * @param forceDefaultValue the {@link #isForceDefaultValue() forceDefaultValue} flag. */ public VariableDefinitionStringList(String name, String legacyName, - Function> defaultValueFactory, boolean forceDefaultValue) { + Function> defaultValueFactory, boolean forceDefaultValue) { super(name, legacyName, defaultValueFactory, forceDefaultValue); } - @SuppressWarnings({ "unchecked", "rawtypes" }) + @SuppressWarnings({"unchecked", "rawtypes"}) @Override public Class> getValueType() { @@ -108,7 +108,7 @@ public VariableLine migrateLine(VariableLine line) { } @Override - public String toString(List value) { + public String toString(List value, IdeContext context) { if (value == null) { return ""; diff --git a/cli/src/main/java/com/devonfw/tools/ide/variable/VariableDefinitionSystemPath.java b/cli/src/main/java/com/devonfw/tools/ide/variable/VariableDefinitionSystemPath.java index 8bc7810b4..9105910c1 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/variable/VariableDefinitionSystemPath.java +++ b/cli/src/main/java/com/devonfw/tools/ide/variable/VariableDefinitionSystemPath.java @@ -25,7 +25,7 @@ public VariableDefinitionSystemPath(String name) { /** * The constructor. * - * @param name the {@link #getName() variable name}. + * @param name the {@link #getName() variable name}. * @param legacyName the {@link #getLegacyName() legacy name}. */ public VariableDefinitionSystemPath(String name, String legacyName) { @@ -36,13 +36,13 @@ public VariableDefinitionSystemPath(String name, String legacyName) { /** * The constructor. * - * @param name the {@link #getName() variable name}. - * @param legacyName the {@link #getLegacyName() legacy name}. + * @param name the {@link #getName() variable name}. + * @param legacyName the {@link #getLegacyName() legacy name}. * @param defaultValueFactory the factory {@link Function} for the - * {@link #getDefaultValue(IdeContext) default value}. + * {@link #getDefaultValue(IdeContext) default value}. */ public VariableDefinitionSystemPath(String name, String legacyName, - Function defaultValueFactory) { + Function defaultValueFactory) { super(name, legacyName, defaultValueFactory); } @@ -50,14 +50,14 @@ public VariableDefinitionSystemPath(String name, String legacyName, /** * The constructor. * - * @param name the {@link #getName() variable name}. - * @param legacyName the {@link #getLegacyName() legacy name}. + * @param name the {@link #getName() variable name}. + * @param legacyName the {@link #getLegacyName() legacy name}. * @param defaultValueFactory the factory {@link Function} for the - * {@link #getDefaultValue(IdeContext) default value}. - * @param forceDefaultValue the {@link #isForceDefaultValue() forceDefaultValue} flag. + * {@link #getDefaultValue(IdeContext) default value}. + * @param forceDefaultValue the {@link #isForceDefaultValue() forceDefaultValue} flag. */ public VariableDefinitionSystemPath(String name, String legacyName, - Function defaultValueFactory, boolean forceDefaultValue) { + Function defaultValueFactory, boolean forceDefaultValue) { super(name, legacyName, defaultValueFactory, forceDefaultValue); } @@ -65,15 +65,15 @@ public VariableDefinitionSystemPath(String name, String legacyName, /** * The constructor. * - * @param name the {@link #getName() variable name}. - * @param legacyName the {@link #getLegacyName() legacy name}. + * @param name the {@link #getName() variable name}. + * @param legacyName the {@link #getLegacyName() legacy name}. * @param defaultValueFactory the factory {@link Function} for the - * {@link #getDefaultValue(IdeContext) default value}. - * @param forceDefaultValue the {@link #isForceDefaultValue() forceDefaultValue} flag. - * @param export the {@link #isExport() export} flag. + * {@link #getDefaultValue(IdeContext) default value}. + * @param forceDefaultValue the {@link #isForceDefaultValue() forceDefaultValue} flag. + * @param export the {@link #isExport() export} flag. */ public VariableDefinitionSystemPath(String name, String legacyName, - Function defaultValueFactory, boolean forceDefaultValue, boolean export) { + Function defaultValueFactory, boolean forceDefaultValue, boolean export) { super(name, legacyName, defaultValueFactory, forceDefaultValue, export); } @@ -89,4 +89,9 @@ public SystemPath fromString(String value, IdeContext context) { return new SystemPath(context, value); } + + @Override + public String toString(SystemPath value, IdeContext context) { + return value.toString(context.getPathSyntax()); + } } diff --git a/cli/src/main/resources/nls/Help.properties b/cli/src/main/resources/nls/Help.properties index ff1db33e1..2fe92f2e4 100644 --- a/cli/src/main/resources/nls/Help.properties +++ b/cli/src/main/resources/nls/Help.properties @@ -1,52 +1,93 @@ cmd.--version=Print the version of IDEasy. +cmd.--version.detail=TODO --version cmd.aws=Tool commandlet for AWS CLI. +cmd.aws.detail=TODO AWS cmd.az=Tool commandlet for Azure CLI. +cmd.az.detail=TODO AZ cmd.cobigen=Tool commandlet for Cobigen (code-generator). +cmd.cobigen.detail=TODO cobigen cmd.complete=Internal commandlet for bash auto-completion. +cmd.complete.detail=TODO complete cmd.create=Create a new IDEasy project. +cmd.create.detail=TODO create cmd.create.val.project=The name of the new project that will be created. cmd.docker=Tool commandlet for Docker. +cmd.docker.detail=TODO docker cmd.dotnet=Tool commandlet for dotnet. +cmd.dotnet.detail=TODO dotnet cmd.eclipse=Tool commandlet for Eclipse (IDE). +cmd.eclipse.detail=TODO eclipse cmd.env=Print the environment variables to set and export. +cmd.env.detail=TODO env cmd.env.opt.--bash=Convert Windows path syntax to bash for usage in git-bash. cmd.gcviewer=Tool commandlet for GC Viewer (View garbarge collector logs of Java). +cmd.gcviewer.detail=TODO GCViewer cmd.get-edition=Get the edition of the selected tool. +cmd.get-edition.detail=TODO get-edition cmd.get-version=Get the version of the selected tool. +cmd.get-version.detail=TODO get-version cmd.gh=Tool commandlet for GitHub CLI. +cmd.gh.detail=TODO GH cmd.graalvm=Tool commandlet for GraalVm (Java with native-image). +cmd.graalvm.detail=TODO GraalVM cmd.gradle=Tool commandlet for Gradle (Build-Tool). +cmd.gradle.detail=TODO Gralde cmd.helm=Tool commandlet for Helm (Kubernetes Package Manager). +cmd.helm.detail=TODO Helm cmd.help=Prints this help. +cmd.help.detail=To get help details about a commandlet, simply call "ide help ". cmd.install=Install the selected tool. +cmd.install.detail=TODO Install cmd.intellij=Tool commandlet for IntelliJ (IDE) +cmd.intellij.detail=TODO IntelliJ cmd.jasypt=Tool commandlet for Jasypt (encryption/decryption). +cmd.jasypt.detail=TODO Jasypt cmd.jasypt.val.command=Modues (encrypt | decrypt) cmd.jasypt.val.masterPassword=master password. cmd.jasypt.val.secret=The secret to be encrypted or decrypted. cmd.java=Tool commandlet for Java (OpenJDK). +cmd.java.detail=TODO Java cmd.jmc=Tool commandlet for JDK Mission Control (performance analysis). +cmd.jmc.detail=TODO JMC cmd.kotlinc=Tool commandlet for Kotlin (compiler for JRE language). +cmd.kotlinc.detail=TODO kotlinc cmd.kotlincnative=Tool commandlet for Kotlin-Native (compiler for JRE language). +cmd.kotlincnative.detail=TODO kotlincnative cmd.list-editions=List the available editions of the selected tool. +cmd.list-editions.detail=TODO list-editions cmd.list-versions=List the available versions of the selected tool. +cmd.list-versions.detail=TODO list-versions cmd.mvn=Tool commandlet for Maven (Build-Tool). +cmd.mvn.detail=TODO mvn cmd.node=Tool commandlet for Node.js (JavaScript runtime). +cmd.node.detail=TODO node cmd.npm=Tool commandlet for Npm (JavaScript Node Package Manager). +cmd.npm.detail=TODO npm cmd.oc=Tool commandlet for Openshift CLI (Kubernetes management tool). +cmd.oc.detail=TODO oc cmd.quarkus=Tool commandlet for Quarkus (framework for cloud-native apps). +cmd.quarkus.detail=TODO quarkus cmd.repository=Setup pre-configured git repositories (clone, build, import). +cmd.repository.detail=TODO repository cmd.repository.val.repository=The name of the properties file of the pre-configured git repository to setup, omit to setup all active repositories. cmd.set-edition=Set the edition of the selected tool. +cmd.set-edition.detail=TODO set-edition cmd.set-version=Set the version of the selected tool. +cmd.set-version.detail=TODO set-version cmd.set-version.val.version=The tool version to set. cmd.shell=Commandlet to start built-in shell with advanced auto-completion. +cmd.shell.detail=TODO shell cmd.sonar=Tool commandlet for SonarQube. +cmd.sonar.detail=TODO sonar cmd.sonar.val.command=Action to perform (START|STOP|ANALYZE) cmd.terraform=Tool commandlet for Terraform. +cmd.terraform.detail=TODO terraform cmd.uninstall=Uninstall the selected tool. +cmd.uninstall.detail=TODO uninstall cmd.update=Pull your settings and apply updates (software, configuration and repositories). +cmd.update.detail=TODO update cmd.vscode=Tool commandlet for Visual Studio Code (IDE). +cmd.vscode.detail=TODO vscode commandlets=Available commandlets: opt.--batch=enable batch mode (non-interactive). opt.--debug=enable debug logging. @@ -54,6 +95,8 @@ opt.--force=enable force mode. opt.--locale=the locale (e.g. '--locale=de' for German language). opt.--offline=enable offline mode (skip updates or git pull, fail downloads or git clone). opt.--quiet=disable info logging (only log success, warning or error). +opt.--skip-repositories=skip the setup of repositories. +opt.--skip-tools=skip the installation/update of tools. opt.--trace=enable trace logging. opt.--version=Print the IDE version and exit. options=Options: diff --git a/cli/src/main/resources/nls/Help_de.properties b/cli/src/main/resources/nls/Help_de.properties index 44301e50f..598ddbec0 100644 --- a/cli/src/main/resources/nls/Help_de.properties +++ b/cli/src/main/resources/nls/Help_de.properties @@ -1,52 +1,93 @@ cmd.--version=Gibt die Version von IDEasy aus. +cmd.--version.detail=TODO DE --version cmd.aws=Werkzeug Kommando für AWS Kommandoschnittstelle. +cmd.aws.detail=TODO DE AWS cmd.az=Werkzeug Kommando für Azure Kommandoschnittstelle. +cmd.az.detail=TODO DE AZ cmd.cobigen=Werkzeug Kommando für Cobigen. +cmd.cobigen.detail=TODO DE cobigen cmd.complete=Internes Werkzeug für bash Autovervollständigung. +cmd.complete.detail=TODO DE complete cmd.create=Erstellt ein neues IDEasy Projekt. +cmd.create.detail=TODO DE create cmd.create.val.project=Der Name des zu erstellenden Projekts. cmd.docker=Werkzeug Kommando für Docker. +cmd.docker.detail=TODO DE docker cmd.dotnet=Werkzeug Kommando für dotnet Kommandoschnittstelle. +cmd.dotnet.detail=TODO DE dotnet cmd.eclipse=Werkzeug Kommando für Eclipse (IDE). +cmd.eclipse.detail=TODO DE eclipse cmd.env=Gibt die zu setzenden und exportierenden Umgebungsvariablen aus. +cmd.env.detail=TODO DE env cmd.env.opt.--bash=Konvertiert Windows-Pfad-Syntax nach Bash zur Verwendung in git-bash. cmd.gcviewer=Werkzeug Kommando für GC Viewer (Anzeige von Garbage-Collector Logs von Java). +cmd.gcviewer.detail=TODO DE GCViewer cmd.get-edition=Zeigt die Edition des selektierten Werkzeugs an. +cmd.get-edition.detail=TODO DE get-edition cmd.get-version=Zeigt die Version des selektierten Werkzeugs an. +cmd.get-version.detail=TODO DE get-version cmd.gh=Werkzeug Kommando für die Github Kommandoschnittstelle. +cmd.gh.detail=TODO DE GH cmd.graalvm=Werkzeug Kommando für GraalVm. +cmd.graalvm.detail=TODO DE GraalVM cmd.gradle=Werkzeug Kommando für Gradle (Build-Tool). +cmd.gradle.detail=TODO DE Gralde cmd.helm=Werkzeug Kommando für Helm (Kubernetes Package Manager). +cmd.helm.detail=TODO DE Helm cmd.help=Zeigt diese Hilfe an. +cmd.help.detail=Die Hilfe-Details eines Kommandos können mit dem Befehl "ide help " ausgegeben werden. cmd.install=Installiert das selektierte Werkzeug. +cmd.install.detail=TODO DE Install cmd.intellij=Werkzeug Kommando für Intellij (IDE) +cmd.intellij.detail=TODO DE IntelliJ cmd.jasypt=Werkzeug Kommando für Jasypt. +cmd.jasypt.detail=TODO DE Jasypt cmd.jasypt.val.command=Mode (encrypt | decrypt) cmd.jasypt.val.masterPassword=master Passwort. cmd.jasypt.val.secret=Das zu verschlüsselnde oder zu entschlüsselnde Geheimnis. cmd.java=Werkzeug Kommando für Java (OpenJDK). +cmd.java.detail=TODO DE Java cmd.jmc=Werkzeug Kommando für JDK Mission Control (Performance Analyse). +cmd.jmc.detail=TODO DE JMC cmd.kotlinc=Werkzeug Kommando für Kotlin (Compiler für JRE Sprache). +cmd.kotlinc.detail=TODO DE kotlinc cmd.kotlincnative=Werkzeug Kommando für Kotlin-Native (Compiler für JRE Sprache). +cmd.kotlincnative.detail=TODO DE kotlincnative cmd.list-editions=Listet die verfügbaren Editionen des selektierten Werkzeugs auf. +cmd.list-editions.detail=TODO DE list-editions cmd.list-versions=Listet die verfügbaren Versionen des selektierten Werkzeugs auf. +cmd.list-versions.detail=TODO DE list-versions cmd.mvn=Werkzeug Kommando für Maven (Build-Werkzeug). +cmd.mvn.detail=TODO DE mvn cmd.node=Werkzeug Kommando für Node.js (JavaScript Laufzeitumgebung). +cmd.node.detail=TODO DE node cmd.npm=Werkzeug Kommando für Npm (JavaScript Node Package Manager). +cmd.npm.detail=TODO DE npm cmd.oc=Werkzeug Kommando für Openshift CLI (Kubernetes Management Tool). +cmd.oc.detail=TODO DE oc cmd.quarkus=Werkzeug Kommando für Quarkus (Framework für Cloud-native Anwendungen). +cmd.quarkus.detail=TODO DE quarkus cmd.repository=Richtet das vorkonfigurierte Git Repository ein. +cmd.repository.detail=TODO DE repository cmd.repository.val.repository=Der Name der Properties-Datei des vorkonfigurierten Git Repositories zum Einrichten. Falls nicht angegeben, werden alle aktiven Projekte eingerichtet. cmd.set-edition=Setzt die Edition des selektierten Werkzeugs. +cmd.set-edition.detail=TODO DE set-edition cmd.set-version=Setzt die Version des selektierten Werkzeugs. +cmd.set-version.detail=TODO DE set-version cmd.set-version.val.version=Die zu setzende Werkzeug Version. cmd.shell=Kommando zum Starten der integrierten Shell mit erweiterter Autovervollständigung. +cmd.shell.detail=TODO DE shell cmd.sonar=Werkzeug Kommando für SonarQube. +cmd.sonar.detail=TODO DE sonar cmd.sonar.val.command=Auszuführende Aktion (START|STOP|ANALYZE) cmd.terraform=Werkzeug Kommando für Terraform. +cmd.terraform.detail=TODO DE terraform cmd.uninstall=Deinstalliert das ausgewählte Werkzeug. +cmd.uninstall.detail=TODO DE uninstall cmd.update=Updatet die Settings, Software und Repositories. +cmd.update.detail=TODO DE update cmd.vscode=Werkzeug Kommando für Visual Studio Code (IDE). +cmd.vscode.detail=TODO DE vscode commandlets=Verfügbare Kommandos: opt.--batch=Aktiviert den Batch-Modus (nicht-interaktive Stapelverarbeitung). opt.--debug=Aktiviert Debug-Ausgaben (Fehleranalyse). @@ -54,6 +95,8 @@ opt.--force=Aktiviert den Force-Modus (Erzwingen). opt.--locale=Die Spracheinstellungen (z.B. 'en' für Englisch). opt.--offline=Aktiviert den Offline-Modus (Überspringt Aktualisierungen oder git pull, schlägt fehl bei Downloads or git clone). opt.--quiet=Deaktiviert Info Logging ( nur success, warning und error). +opt.--skip-repositories=überspringt die Einrichtung der Repositories. +opt.--skip-tools=überspringt die Installation/Aktualisierung der Tools. opt.--trace=Aktiviert Trace-Ausgaben (detaillierte Fehleranalyse). opt.--version=Zeigt die IDE Version an und beendet das Programm. options=Optionen: diff --git a/cli/src/test/java/com/devonfw/tools/ide/commandlet/CreateCommandletTest.java b/cli/src/test/java/com/devonfw/tools/ide/commandlet/CreateCommandletTest.java index 167a62dcb..a0aa2c4c2 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/commandlet/CreateCommandletTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/commandlet/CreateCommandletTest.java @@ -23,6 +23,7 @@ public void testCreateCommandletRun() { CreateCommandlet cc = context.getCommandletManager().getCommandlet(CreateCommandlet.class); cc.newProject.setValueAsString(NEW_PROJECT_NAME, context); cc.settingsRepo.setValue(IdeContext.DEFAULT_SETTINGS_REPO_URL); + cc.skipTools.setValue(true); // act cc.run(); // assert diff --git a/cli/src/test/java/com/devonfw/tools/ide/commandlet/EnvironmentCommandletTest.java b/cli/src/test/java/com/devonfw/tools/ide/commandlet/EnvironmentCommandletTest.java index 1bc1efc48..8fc2e3ceb 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/commandlet/EnvironmentCommandletTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/commandlet/EnvironmentCommandletTest.java @@ -1,71 +1,16 @@ package com.devonfw.tools.ide.commandlet; -import org.junit.jupiter.api.Test; - 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.VariableLine; import com.devonfw.tools.ide.log.IdeLogLevel; +import org.junit.jupiter.api.Test; /** * Test of {@link EnvironmentCommandlet}. */ public class EnvironmentCommandletTest extends AbstractIdeContextTest { - /** - * Test of {@link EnvironmentCommandlet#normalizeWindowsValue(String)} for Windows. - */ - @Test - public void testNormalizeWindowsValue2Windows() { - - EnvironmentCommandlet env = new EnvironmentCommandlet(IdeTestContextMock.get()); - assertThat(env.normalizeWindowsValue("")).isEqualTo(""); - assertThat(env.normalizeWindowsValue("*")).isEqualTo("*"); - assertThat(env.normalizeWindowsValue("$:\\\\{garbage}§")).isEqualTo("$:\\\\{garbage}§"); - assertThat(env.normalizeWindowsValue("/c/Windows/system32/drivers/etc/hosts")) - .isEqualTo("C:\\Windows\\system32\\drivers\\etc\\hosts"); - assertThat(env.normalizeWindowsValue("C:\\Windows\\system32\\drivers\\etc\\hosts")) - .isEqualTo("C:\\Windows\\system32\\drivers\\etc\\hosts"); - assertThat(env.normalizeWindowsValue("C:\\Users\\login/.ide/scripts/ide")) - .isEqualTo("C:\\Users\\login\\.ide\\scripts\\ide"); - assertThat(env.normalizeWindowsValue("\\login/.ide/scripts/ide")).isEqualTo("\\login/.ide/scripts/ide"); - } - - /** - * Test of {@link EnvironmentCommandlet#normalizeWindowsValue(String)} for (Git-)Bash. - */ - @Test - public void testNormalizeWindowsValue2Bash() { - - EnvironmentCommandlet env = new EnvironmentCommandlet(IdeTestContextMock.get()); - env.bash.setValue(true); - assertThat(env.normalizeWindowsValue("")).isEqualTo(""); - assertThat(env.normalizeWindowsValue("*")).isEqualTo("*"); - assertThat(env.normalizeWindowsValue("$:\\\\{garbage}§")).isEqualTo("$:\\\\{garbage}§"); - assertThat(env.normalizeWindowsValue("C:\\Windows\\system32\\drivers\\etc\\hosts")) - .isEqualTo("/c/Windows/system32/drivers/etc/hosts"); - assertThat(env.normalizeWindowsValue("/c/Windows/system32/drivers/etc/hosts")) - .isEqualTo("/c/Windows/system32/drivers/etc/hosts"); - } - - /** - * Test of {@link EnvironmentCommandlet#normalizeWindowsValue(VariableLine)} for Windows. - */ - @Test - public void testNormalizeWindowsLine() { - - // arrange - VariableLine line = VariableLine.of(true, "MAGIC_PATH", "/c/Windows/system32/drivers/etc/hosts"); - EnvironmentCommandlet env = new EnvironmentCommandlet(IdeTestContextMock.get()); - // act - VariableLine normalized = env.normalizeWindowsValue(line); - // assert - assertThat(normalized.getValue()).isEqualTo("C:\\Windows\\system32\\drivers\\etc\\hosts"); - assertThat(normalized.isExport()).isTrue(); - assertThat(normalized.getName()).isEqualTo("MAGIC_PATH"); - } - /** * Test of {@link EnvironmentCommandlet} run. */ 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 d43d5969f..6372ed48d 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 @@ -80,10 +80,10 @@ public void testRunWithCommandlet() { * Ensure that for every {@link Commandlet} and each of their {@link Property} a help text is defined. * * @param locale the {@link String} representation of the {@link Locale} to test. The empty {@link String} will be - * used for {@link Locale#ROOT}. + * used for {@link Locale#ROOT}. */ @ParameterizedTest - @ValueSource(strings = { "", "de" }) + @ValueSource(strings = {"", "de"}) public void testEnsureAllNlsPropertiesPresent(String locale) throws IOException { // arrange @@ -95,8 +95,11 @@ public void testEnsureAllNlsPropertiesPresent(String locale) throws IOException for (Commandlet commandlet : context.getCommandletManager().getCommandlets()) { String message = bundle.get(commandlet); soft.assertThat(message).doesNotStartWith("?"); + String detail = bundle.getDetail(commandlet); + soft.assertThat(detail).doesNotStartWith("?"); if (!locale.isEmpty()) { soft.assertThat(message).isNotEqualTo(bundleRoot.get(commandlet)); + soft.assertThat(detail).isNotEqualTo(bundleRoot.getDetail(commandlet)); } for (Property property : commandlet.getProperties()) { if (!(property instanceof KeywordProperty)) { diff --git a/cli/src/test/java/com/devonfw/tools/ide/common/SystemPathTest.java b/cli/src/test/java/com/devonfw/tools/ide/common/SystemPathTest.java index 0b8656bee..5099cd99a 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/common/SystemPathTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/common/SystemPathTest.java @@ -1,49 +1,36 @@ package com.devonfw.tools.ide.common; -import static org.assertj.core.api.Assertions.assertThat; - -import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; +import static org.assertj.core.api.Assertions.assertThat; + /** * Unit tests of {@link SystemPath}. */ public class SystemPathTest { @ParameterizedTest - @ValueSource(strings = { "C:\\Users\\User\\Documents\\My Pictures\\photo.jpg", - "C:\\Windows\\System32\\drivers\\etc.sys", "D:\\Projects\\ProjectA\\source\\main.py" }) - public void SystemPathShouldRecognizeWindowsPaths(String pathStringToTest) { + // arrange + @ValueSource(strings = {"C:\\Users\\User\\Documents\\My Pictures\\photo.jpg", + "C:\\Windows\\System32\\drivers\\etc.sys", "D:\\Projects\\ProjectA\\source\\main.py"}) + public void systemPathShouldRecognizeWindowsPaths(String pathStringToTest) { // act boolean testResult = SystemPath.isValidWindowsPath(pathStringToTest); + // assert assertThat(testResult).isTrue(); - } @ParameterizedTest - @ValueSource(strings = { "-kill", "none", "--help", "/usr/local/bin/firefox.exe" }) - public void SystemPathShouldRecognizeNonWindowsPaths(String pathStringToTest) { + // arrange + @ValueSource(strings = {"-kill", "none", "--help", "/usr/local/bin/firefox.exe"}) + public void systemPathShouldRecognizeNonWindowsPaths(String pathStringToTest) { // act boolean testResult = SystemPath.isValidWindowsPath(pathStringToTest); - assertThat(testResult).isFalse(); - - } - - @Test - public void SystemPathShouldConvertWindowsPathToUnixPath() { - - // arrange - String windowsPathString = "C:\\Users\\User\\test.exe"; - String expectedUnixPathString = "/c/Users/User/test.exe"; - - // act - String resultPath = SystemPath.convertWindowsPathToUnixPath(windowsPathString); - // assert - assertThat(resultPath).isEqualTo(expectedUnixPathString); + assertThat(testResult).isFalse(); } } diff --git a/cli/src/test/java/com/devonfw/tools/ide/os/WindowsPathSyntaxTest.java b/cli/src/test/java/com/devonfw/tools/ide/os/WindowsPathSyntaxTest.java index a36fd92f9..715cc4f08 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/os/WindowsPathSyntaxTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/os/WindowsPathSyntaxTest.java @@ -3,19 +3,26 @@ import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; +import java.nio.file.Path; + /** * Test of {@link WindowsPathSyntax}. */ public class WindowsPathSyntaxTest extends Assertions { - /** Test of {@link WindowsPathSyntax#WINDOWS}. */ + public static final String WINDOWS_HOSTS = "C:\\Windows\\system32\\drivers\\etc\\hosts"; + public static final String MSYS_HOSTS = "/c/Windows/system32/drivers/etc/hosts"; + + /** + * Test of {@link WindowsPathSyntax#WINDOWS}. + */ @Test public void testWindows() { // arrange WindowsPathSyntax syntax = WindowsPathSyntax.WINDOWS; // act && assert - assertThat(syntax.getDrive("C:\\Windows\\system32\\drivers\\etc\\hosts")).isEqualTo("C"); + assertThat(syntax.getDrive(WINDOWS_HOSTS)).isEqualTo("C"); assertThat(syntax.getDrive("D:\\projects\\ide\\settings\\ide.properties")).isEqualTo("D"); assertThat(syntax.getDrive("https://host.com:8443/context/path/collection/id?key=value")).isNull(); assertThat(syntax.getDrive("$:\\{garbage}§")).isNull(); @@ -23,16 +30,25 @@ public void testWindows() { assertThat(syntax.getRootPath("C")).isEqualTo("C:\\"); assertThat(syntax.getRootPath("c")).isEqualTo("C:\\"); assertThat(syntax.getRootPath("Z")).isEqualTo("Z:\\"); + assertThat(syntax.format(Path.of(MSYS_HOSTS))).isEqualTo(WINDOWS_HOSTS); + if (SystemInfoImpl.INSTANCE.isWindows()) { + assertThat(syntax.format(Path.of(WINDOWS_HOSTS))).isEqualTo(WINDOWS_HOSTS); + } + assertThat(syntax.format(Path.of("/foo/bar/some.txt"))).isEqualTo("\\foo\\bar\\some.txt"); + assertThat(syntax.format(Path.of("foo/bar/some.txt"))).isEqualTo("foo\\bar\\some.txt"); + assertThat(syntax.format(Path.of("./foo/bar/some.txt"))).isEqualTo(".\\foo\\bar\\some.txt"); } - /** Test of {@link WindowsPathSyntax#MSYS}. */ + /** + * Test of {@link WindowsPathSyntax#MSYS}. + */ @Test public void testMsys() { // arrange WindowsPathSyntax syntax = WindowsPathSyntax.MSYS; // act && assert - assertThat(syntax.getDrive("/c/Windows/system32/drivers/etc/hosts")).isEqualTo("c"); + assertThat(syntax.getDrive(MSYS_HOSTS)).isEqualTo("c"); assertThat(syntax.getDrive("/d/projects/ide/settings/ide.properties")).isEqualTo("d"); assertThat(syntax.getDrive("https://host.com:8443/context/path/collection/id?key=value")).isNull(); assertThat(syntax.getDrive("$:\\{garbage}§")).isNull(); @@ -40,6 +56,76 @@ public void testMsys() { assertThat(syntax.getRootPath("c")).isEqualTo("/c/"); assertThat(syntax.getRootPath("C")).isEqualTo("/c/"); assertThat(syntax.getRootPath("z")).isEqualTo("/z/"); + assertThat(syntax.format(Path.of(MSYS_HOSTS))).isEqualTo(MSYS_HOSTS); + if (SystemInfoImpl.INSTANCE.isWindows()) { + assertThat(syntax.format(Path.of(WINDOWS_HOSTS))).isEqualTo(MSYS_HOSTS); + assertThat(syntax.format(Path.of("\\foo\\bar\\some.txt"))).isEqualTo("/foo/bar/some.txt"); + assertThat(syntax.format(Path.of("foo\\bar\\some.txt"))).isEqualTo("foo/bar/some.txt"); + assertThat(syntax.format(Path.of(".\\foo\\bar\\some.txt"))).isEqualTo("./foo/bar/some.txt"); + } + } + + /** + * Test of {@link WindowsPathSyntax#normalize(String, boolean)} for Windows. + */ + @Test + public void testNormalizeWindowsValue2Windows() { + + boolean bash = false; + assertThat(WindowsPathSyntax.normalize("", bash)).isEqualTo(""); + assertThat(WindowsPathSyntax.normalize("*", bash)).isEqualTo("*"); + assertThat(WindowsPathSyntax.normalize("$:\\\\{garbage}§", bash)).isEqualTo("$:\\\\{garbage}§"); + assertThat(WindowsPathSyntax.normalize("/c/Windows/system32/drivers/etc/hosts", bash)) + .isEqualTo("C:\\Windows\\system32\\drivers\\etc\\hosts"); + assertThat(WindowsPathSyntax.normalize("C:\\Windows\\system32\\drivers\\etc\\hosts", bash)) + .isEqualTo("C:\\Windows\\system32\\drivers\\etc\\hosts"); + assertThat(WindowsPathSyntax.normalize("C:\\Users\\login/.ide/scripts/ide", bash)) + .isEqualTo("C:\\Users\\login\\.ide\\scripts\\ide"); + assertThat(WindowsPathSyntax.normalize("\\login/.ide/scripts/ide", bash)).isEqualTo("\\login/.ide/scripts/ide"); + } + + /** + * Test of {@link WindowsPathSyntax#normalize(String, boolean)} for (Git-)Bash. + */ + @Test + public void testNormalizeWindowsValue2Bash() { + + boolean bash = true; + assertThat(WindowsPathSyntax.normalize("", bash)).isEqualTo(""); + assertThat(WindowsPathSyntax.normalize("*", bash)).isEqualTo("*"); + assertThat(WindowsPathSyntax.normalize("$:\\\\{garbage}§", bash)).isEqualTo("$:\\\\{garbage}§"); + assertThat(WindowsPathSyntax.normalize("C:\\Windows\\system32\\drivers\\etc\\hosts", bash)) + .isEqualTo("/c/Windows/system32/drivers/etc/hosts"); + assertThat(WindowsPathSyntax.normalize("/c/Windows/system32/drivers/etc/hosts", bash)) + .isEqualTo("/c/Windows/system32/drivers/etc/hosts"); + } + + /** + * Test of {@link WindowsPathSyntax#normalize(String, boolean)} for Windows. + */ + @Test + public void testNormalizeWindowsPath() { + + // arrange + String path = "/c/Windows/system32/drivers/etc/hosts"; + // act + String normalized = WindowsPathSyntax.normalize(path, false); + // assert + assertThat(normalized).isEqualTo("C:\\Windows\\system32\\drivers\\etc\\hosts"); + } + + @Test + public void systemPathShouldConvertWindowsPathToUnixPath() { + + // arrange + String windowsPathString = "C:\\Users\\User\\test.exe"; + String expectedUnixPathString = "/c/Users/User/test.exe"; + + // act + String resultPath = WindowsPathSyntax.normalize(windowsPathString, true); + + // assert + assertThat(resultPath).isEqualTo(expectedUnixPathString); } } diff --git a/cli/src/test/java/com/devonfw/tools/ide/tool/jasypt/JasyptTest.java b/cli/src/test/java/com/devonfw/tools/ide/tool/jasypt/JasyptTest.java index 32eb612af..3d6603e91 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/tool/jasypt/JasyptTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/tool/jasypt/JasyptTest.java @@ -5,14 +5,24 @@ import com.devonfw.tools.ide.context.IdeTestContext; import com.devonfw.tools.ide.log.IdeLogLevel; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import uk.org.webcompere.systemstubs.environment.EnvironmentVariables; +import uk.org.webcompere.systemstubs.jupiter.SystemStub; +import uk.org.webcompere.systemstubs.jupiter.SystemStubsExtension; /** * Integration test of {@link Jasypt}. */ +@ExtendWith(SystemStubsExtension.class) public class JasyptTest extends AbstractIdeContextTest { - private static final String PROJECT_JASYPT = "jasypt"; + private static final String JASYPT_OPTS = "custom_argument"; + private static final String PROJECT_JASYPT = "jasypt"; + + /** + * Tests if {@link Jasypt} is properly installed by the {@link InstallCommandlet} + */ @Test public void testJasyptInstallCommandlet() { @@ -27,6 +37,9 @@ public void testJasyptInstallCommandlet() { checkInstallation(context); } + /** + * Tests if {@link Jasypt} Commandlet installation is properly working + */ @Test public void testJasyptInstall() { @@ -42,6 +55,9 @@ public void testJasyptInstall() { checkInstallation(context); } + /** + * Tests if {@link Jasypt} Commandlet is properly running + */ @Test public void testJasyptRun() { @@ -57,8 +73,35 @@ public void testJasyptRun() { commandlet.run(); // assert - assertLogMessage(context, IdeLogLevel.INFO, "executing java:"); - assertLogMessage(context, IdeLogLevel.INFO, "This is a jar file."); + assertLogMessage(context, IdeLogLevel.INFO, context.getVariables().get("JASYPT_OPTS")); + checkInstallation(context); + } + + @SystemStub + private final EnvironmentVariables environment = new EnvironmentVariables(); + + /** + * Tests if {@link Jasypt} Commandlet is properly running with a user-defined JASYPT_OPTS env variable + */ + @Test + public void testJasyptRunWithCustomVariable() { + + // arrange + environment.set("JASYPT_OPTS", JASYPT_OPTS); + + IdeTestContext context = newContext(PROJECT_JASYPT); + Jasypt commandlet = new Jasypt(context); + + commandlet.command.setValue(JasyptCommand.ENCRYPT); + commandlet.masterPassword.setValue("password"); + commandlet.secret.setValue("input"); + + // act + commandlet.run(); + + // assert + assertLogMessage(context, IdeLogLevel.INFO, context.getVariables().get("JASYPT_OPTS")); + checkInstallation(context); } diff --git a/cli/src/test/resources/ide-projects/jasypt/repository/java/java/default/bin/java b/cli/src/test/resources/ide-projects/jasypt/repository/java/java/default/bin/java index 655040e33..11fa988f3 100644 --- a/cli/src/test/resources/ide-projects/jasypt/repository/java/java/default/bin/java +++ b/cli/src/test/resources/ide-projects/jasypt/repository/java/java/default/bin/java @@ -1,3 +1,2 @@ #!/bin/bash -echo "executing java:" -cat $2 # .jar file \ No newline at end of file +echo "${@:6}" # optional arguments \ No newline at end of file diff --git a/documentation/software.adoc b/documentation/software.adoc index 4e9ab706a..8512a46c4 100644 --- a/documentation/software.adoc +++ b/documentation/software.adoc @@ -13,7 +13,7 @@ Technically we "install" (extract) all tools into a local repository (in `$IDE_R This has the following benefits: * Switching a tool version forth and back is lightning fast since only a symbolic link needs to be updated. -* We avoid severe issues with link:how-to-unlock-files.adoc[Windows file-locking]. +* We avoid severe issues with link:windows-file-lock.adoc[Windows file-locking]. * Multiple IDEasy projects can share the same physical tool versions to save disc-space. However, we keep previous tool version on updates what can also waste disc-space. Therefore, you can run `ide cleanup` to find and release old tool versions and free disc-space. @@ -23,6 +23,7 @@ Therefore, you can run `ide cleanup` to find and release old tool versions and f In some cases, a project might need a (proprietary) tools that are not directly supported by `IDEasy`. As a solution for this need, `IDEasy` let's you configure custom tools via `settings/ide-custom-tools.json`. The following example illustrates how to configure custom tools: + ```json { "url": "https://some-file-server.company.com/projects/my-project", diff --git a/documentation/how-to-unlock-files.adoc b/documentation/windows-file-lock.adoc similarity index 100% rename from documentation/how-to-unlock-files.adoc rename to documentation/windows-file-lock.adoc