From e4929c786c1d816b4d8281fe54c407a202028b69 Mon Sep 17 00:00:00 2001 From: Ouchen Date: Thu, 22 Feb 2024 16:55:59 +0100 Subject: [PATCH 01/18] Add first implementation --- .../commandlet/CommandletFileExtractor.java | 31 ++++ .../CommandletFileExtractorImpl.java | 128 +++++++++++++++ .../tools/ide/context/AbstractIdeContext.java | 7 +- .../tools/ide/context/IdeContextConsole.java | 8 +- .../tools/ide/tool/GlobalToolCommandlet.java | 10 +- .../tools/ide/tool/LocalToolCommandlet.java | 18 ++- .../tools/ide/tool/ToolCommandlet.java | 146 ++++-------------- .../com/devonfw/tools/ide/tool/aws/Aws.java | 56 +------ .../tools/ide/tool/aws/AwsFileExtractor.java | 74 +++++++++ .../tools/ide/tool/ide/IdeToolCommandlet.java | 2 +- .../com/devonfw/tools/ide/tool/jmc/Jmc.java | 9 +- .../com/devonfw/tools/ide/tool/mvn/Mvn.java | 3 +- .../commandlet/CommandLetExtractorMock.java | 52 +++++++ .../ide/context/AbstractIdeContextTest.java | 21 ++- .../ide/context/AbstractIdeTestContext.java | 7 +- .../tools/ide/context/IdeSlf4jContext.java | 2 +- .../tools/ide/context/IdeTestContext.java | 16 +- .../tools/ide/repo/ToolRepositoryMock.java | 89 +++++++++++ .../devonfw/tools/ide/tool/jmc/JmcTest.java | 125 ++++++++++++--- .../default/deleteMeAfterSoftwareAdded.txt | 0 .../java/java/17.0.10_7/.ide.software.version | 1 + .../default/java/java/17.0.10_7/bin/readme | 1 + .../ide-projects/jmc/_ide/software/readme | 1 + .../urls/java/java/17.0.6/linux_x64.sha256 | 1 + .../_ide/urls/java/java/17.0.6/linux_x64.urls | 1 + .../_ide/urls/java/java/17.0.6/mac_x64.sha256 | 1 + .../_ide/urls/java/java/17.0.6/mac_x64.urls | 1 + .../_ide/urls/java/java/17.0.6}/status.json | 0 .../urls/java/java/17.0.6/windows_x64.urls | 1 + .../java/java/17.0.6/windows_x64.urls.sha256 | 1 + .../_ide/urls/jmc/jmc/8.3.0/linux_x64.sha256 | 0 .../_ide/urls/jmc/jmc/8.3.0/linux_x64.urls | 0 .../_ide/urls/jmc/jmc/8.3.0/mac_x64.sha256 | 0 .../_ide/urls/jmc/jmc/8.3.0/mac_x64.urls | 0 .../jmc/_ide/urls/jmc/jmc/8.3.0/status.json | 20 +++ .../_ide/urls/jmc/jmc/8.3.0/windows_x64.urls | 0 .../jmc/jmc/8.3.0/windows_x64.urls.sha256 | 0 .../ide-projects/jmc/_ide/urls/readme | 1 + .../InstallTest.txt | 1 + .../JDK Mission Control/HelloWorld.txt | 1 + .../JDK Mission Control/jmc | 1 + .../InstallTest.txt | 1 + .../InstallTest.txt | 1 + .../JDK Mission Control/HelloWorld.txt | 1 + .../JDK Mission Control/jmc.cmd | 1 + .../jmc/downloadMockLocation/readme | 1 + .../jmc/project/conf/ide.properties | 16 ++ .../jmc/project/home/.ide/ide.properties | 15 ++ .../eclipse/plugins/anyedit.properties | 3 + .../jmc/project/home/Downloads/ide/readme | 1 + .../ide-projects/jmc/project/home/readme | 1 + .../resources/ide-projects/jmc/project/readme | 1 + .../ide-projects/jmc/project/scripts/ide | 1 + .../eclipse/plugins/anyedit.properties | 3 + .../eclipse/plugins/checkstyle.properties | 3 + .../jmc/project/settings/ide.properties | 22 +++ .../resources/ide-projects/jmc/project/setup | 1 + .../software/java/.ide.software.version | 1 + .../jmc/project/software/java/bin/readme | 1 + .../workspaces/foo-test/ide.properties | 12 ++ .../workspaces/foo-test/my-git-repo/readme | 1 + .../jmc/project/workspaces/foo-test/readme | 1 + .../jmc/project/workspaces/main/readme | 1 + .../test/resources/ide-projects/jmc/readme | 1 + 64 files changed, 706 insertions(+), 221 deletions(-) create mode 100644 cli/src/main/java/com/devonfw/tools/ide/commandlet/CommandletFileExtractor.java create mode 100644 cli/src/main/java/com/devonfw/tools/ide/commandlet/CommandletFileExtractorImpl.java create mode 100644 cli/src/main/java/com/devonfw/tools/ide/tool/aws/AwsFileExtractor.java create mode 100644 cli/src/test/java/com/devonfw/tools/ide/commandlet/CommandLetExtractorMock.java create mode 100644 cli/src/test/java/com/devonfw/tools/ide/repo/ToolRepositoryMock.java create mode 100644 cli/src/test/resources/ide-projects/jmc/_ide/software/default/deleteMeAfterSoftwareAdded.txt create mode 100644 cli/src/test/resources/ide-projects/jmc/_ide/software/default/java/java/17.0.10_7/.ide.software.version create mode 100644 cli/src/test/resources/ide-projects/jmc/_ide/software/default/java/java/17.0.10_7/bin/readme create mode 100644 cli/src/test/resources/ide-projects/jmc/_ide/software/readme create mode 100644 cli/src/test/resources/ide-projects/jmc/_ide/urls/java/java/17.0.6/linux_x64.sha256 create mode 100644 cli/src/test/resources/ide-projects/jmc/_ide/urls/java/java/17.0.6/linux_x64.urls create mode 100644 cli/src/test/resources/ide-projects/jmc/_ide/urls/java/java/17.0.6/mac_x64.sha256 create mode 100644 cli/src/test/resources/ide-projects/jmc/_ide/urls/java/java/17.0.6/mac_x64.urls rename cli/src/test/resources/ide-projects/{basic/_ide/urls/jmc/jmc/8.3.0 => jmc/_ide/urls/java/java/17.0.6}/status.json (100%) create mode 100644 cli/src/test/resources/ide-projects/jmc/_ide/urls/java/java/17.0.6/windows_x64.urls create mode 100644 cli/src/test/resources/ide-projects/jmc/_ide/urls/java/java/17.0.6/windows_x64.urls.sha256 rename cli/src/test/resources/ide-projects/{basic => jmc}/_ide/urls/jmc/jmc/8.3.0/linux_x64.sha256 (100%) rename cli/src/test/resources/ide-projects/{basic => jmc}/_ide/urls/jmc/jmc/8.3.0/linux_x64.urls (100%) rename cli/src/test/resources/ide-projects/{basic => jmc}/_ide/urls/jmc/jmc/8.3.0/mac_x64.sha256 (100%) rename cli/src/test/resources/ide-projects/{basic => jmc}/_ide/urls/jmc/jmc/8.3.0/mac_x64.urls (100%) create mode 100644 cli/src/test/resources/ide-projects/jmc/_ide/urls/jmc/jmc/8.3.0/status.json rename cli/src/test/resources/ide-projects/{basic => jmc}/_ide/urls/jmc/jmc/8.3.0/windows_x64.urls (100%) rename cli/src/test/resources/ide-projects/{basic => jmc}/_ide/urls/jmc/jmc/8.3.0/windows_x64.urls.sha256 (100%) create mode 100644 cli/src/test/resources/ide-projects/jmc/_ide/urls/readme create mode 100644 cli/src/test/resources/ide-projects/jmc/downloadMockLocation/org.openjdk.jmc-8.3.0-linux.gtk.x86_64/InstallTest.txt create mode 100644 cli/src/test/resources/ide-projects/jmc/downloadMockLocation/org.openjdk.jmc-8.3.0-linux.gtk.x86_64/JDK Mission Control/HelloWorld.txt create mode 100644 cli/src/test/resources/ide-projects/jmc/downloadMockLocation/org.openjdk.jmc-8.3.0-linux.gtk.x86_64/JDK Mission Control/jmc create mode 100644 cli/src/test/resources/ide-projects/jmc/downloadMockLocation/org.openjdk.jmc-8.3.0-macosx.cocoa.x86_64/InstallTest.txt create mode 100644 cli/src/test/resources/ide-projects/jmc/downloadMockLocation/org.openjdk.jmc-8.3.0-win32.win32.x86_64/InstallTest.txt create mode 100644 cli/src/test/resources/ide-projects/jmc/downloadMockLocation/org.openjdk.jmc-8.3.0-win32.win32.x86_64/JDK Mission Control/HelloWorld.txt create mode 100644 cli/src/test/resources/ide-projects/jmc/downloadMockLocation/org.openjdk.jmc-8.3.0-win32.win32.x86_64/JDK Mission Control/jmc.cmd create mode 100644 cli/src/test/resources/ide-projects/jmc/downloadMockLocation/readme create mode 100644 cli/src/test/resources/ide-projects/jmc/project/conf/ide.properties create mode 100644 cli/src/test/resources/ide-projects/jmc/project/home/.ide/ide.properties create mode 100644 cli/src/test/resources/ide-projects/jmc/project/home/.ide/settings/eclipse/plugins/anyedit.properties create mode 100644 cli/src/test/resources/ide-projects/jmc/project/home/Downloads/ide/readme create mode 100644 cli/src/test/resources/ide-projects/jmc/project/home/readme create mode 100644 cli/src/test/resources/ide-projects/jmc/project/readme create mode 100644 cli/src/test/resources/ide-projects/jmc/project/scripts/ide create mode 100644 cli/src/test/resources/ide-projects/jmc/project/settings/eclipse/plugins/anyedit.properties create mode 100644 cli/src/test/resources/ide-projects/jmc/project/settings/eclipse/plugins/checkstyle.properties create mode 100644 cli/src/test/resources/ide-projects/jmc/project/settings/ide.properties create mode 100644 cli/src/test/resources/ide-projects/jmc/project/setup create mode 100644 cli/src/test/resources/ide-projects/jmc/project/software/java/.ide.software.version create mode 100644 cli/src/test/resources/ide-projects/jmc/project/software/java/bin/readme create mode 100644 cli/src/test/resources/ide-projects/jmc/project/workspaces/foo-test/ide.properties create mode 100644 cli/src/test/resources/ide-projects/jmc/project/workspaces/foo-test/my-git-repo/readme create mode 100644 cli/src/test/resources/ide-projects/jmc/project/workspaces/foo-test/readme create mode 100644 cli/src/test/resources/ide-projects/jmc/project/workspaces/main/readme create mode 100644 cli/src/test/resources/ide-projects/jmc/readme diff --git a/cli/src/main/java/com/devonfw/tools/ide/commandlet/CommandletFileExtractor.java b/cli/src/main/java/com/devonfw/tools/ide/commandlet/CommandletFileExtractor.java new file mode 100644 index 000000000..5090c33c9 --- /dev/null +++ b/cli/src/main/java/com/devonfw/tools/ide/commandlet/CommandletFileExtractor.java @@ -0,0 +1,31 @@ +package com.devonfw.tools.ide.commandlet; + +import com.devonfw.tools.ide.tool.ToolCommandlet; + +import java.nio.file.Path; + +/** + * {@link CommandletFileExtractor} class which handles the extraction of downloaded installations of a + * {@link ToolCommandlet}. + */ +public interface CommandletFileExtractor { + + /** + * + * @param file file the {@link Path} to the file to extract. + * @param targetDir targetDir the {@link Path} to the directory where to extract (or copy) the file. + * @param isExtract {@code true} if the tool is truly extracted, {@code false} the tool will be moved to the targetDir + * (e.g. when an installer exists). + */ + void extract(Path file, Path targetDir, boolean isExtract); + + /** + * Moves the extracted content to the final destination {@link Path}. May be overridden to customize the extraction + * process. + * + * @param from the source {@link Path} to move. + * @param to the target {@link Path} to move to. + */ + void moveAndProcessExtraction(Path from, Path to); + +} diff --git a/cli/src/main/java/com/devonfw/tools/ide/commandlet/CommandletFileExtractorImpl.java b/cli/src/main/java/com/devonfw/tools/ide/commandlet/CommandletFileExtractorImpl.java new file mode 100644 index 000000000..e27f5994c --- /dev/null +++ b/cli/src/main/java/com/devonfw/tools/ide/commandlet/CommandletFileExtractorImpl.java @@ -0,0 +1,128 @@ +package com.devonfw.tools.ide.commandlet; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.stream.Stream; + +import com.devonfw.tools.ide.cli.CliException; +import com.devonfw.tools.ide.context.IdeContext; +import com.devonfw.tools.ide.io.FileAccess; +import com.devonfw.tools.ide.io.TarCompression; +import com.devonfw.tools.ide.process.ProcessContext; +import com.devonfw.tools.ide.tool.ToolCommandlet; +import com.devonfw.tools.ide.util.FilenameUtil; + +/** + * Implements common {@link CommandletFileExtractor} for a {@link ToolCommandlet} + */ +public class CommandletFileExtractorImpl implements CommandletFileExtractor { + + protected final IdeContext context; + + protected final ToolCommandlet commandlet; + + public CommandletFileExtractorImpl(IdeContext context, ToolCommandlet commandlet) { + + this.context = context; + this.commandlet = commandlet; + } + + @Override + public void extract(Path file, Path targetDir, boolean isExtract) { + + FileAccess fileAccess = this.context.getFileAccess(); + if (isExtract) { + Path tmpDir = this.context.getFileAccess().createTempDir("extract-" + file.getFileName()); + this.context.trace("Trying to extract the downloaded file {} to {} and move it to {}.", file, tmpDir, targetDir); + String extension = FilenameUtil.getExtension(file.getFileName().toString()); + this.context.trace("Determined file extension {}", extension); + TarCompression tarCompression = TarCompression.of(extension); + if (tarCompression != null) { + fileAccess.untar(file, tmpDir, tarCompression); + } else if ("zip".equals(extension) || "jar".equals(extension)) { + fileAccess.unzip(file, tmpDir); + } else if ("dmg".equals(extension)) { + assert this.context.getSystemInfo().isMac(); + Path mountPath = this.context.getIdeHome().resolve(IdeContext.FOLDER_UPDATES).resolve(IdeContext.FOLDER_VOLUME); + fileAccess.mkdirs(mountPath); + ProcessContext pc = this.context.newProcess(); + pc.executable("hdiutil"); + pc.addArgs("attach", "-quiet", "-nobrowse", "-mountpoint", mountPath, file); + pc.run(); + Path appPath = fileAccess.findFirst(mountPath, p -> p.getFileName().toString().endsWith(".app"), false); + if (appPath == null) { + throw new IllegalStateException("Failed to unpack DMG as no MacOS *.app was found in file " + file); + } + fileAccess.copy(appPath, tmpDir); + pc.addArgs("detach", "-force", mountPath); + pc.run(); + } else if ("msi".equals(extension)) { + this.context.newProcess().executable("msiexec").addArgs("/a", file, "/qn", "TARGETDIR=" + tmpDir).run(); + // msiexec also creates a copy of the MSI + Path msiCopy = tmpDir.resolve(file.getFileName()); + fileAccess.delete(msiCopy); + } else if ("pkg".equals(extension)) { + + Path tmpDirPkg = fileAccess.createTempDir("ide-pkg-"); + ProcessContext pc = this.context.newProcess(); + // we might also be able to use cpio from commons-compression instead of external xar... + pc.executable("xar").addArgs("-C", tmpDirPkg, "-xf", file).run(); + Path contentPath = fileAccess.findFirst(tmpDirPkg, p -> p.getFileName().toString().equals("Payload"), true); + fileAccess.untar(contentPath, tmpDir, TarCompression.GZ); + fileAccess.delete(tmpDirPkg); + } else { + throw new IllegalStateException("Unknown archive format " + extension + ". Can not extract " + file); + } + moveAndProcessExtraction(getProperInstallationSubDirOf(tmpDir), targetDir); + fileAccess.delete(tmpDir); + } else { + this.context.trace("Extraction is disabled for '{}' hence just moving the downloaded file {}.", + commandlet.getName(), file); + + if (Files.isDirectory(file)) { + fileAccess.move(file, targetDir); + } else { + try { + Files.createDirectories(targetDir); + } catch (IOException e) { + throw new IllegalStateException("Failed to create folder " + targetDir); + } + fileAccess.move(file, targetDir.resolve(file.getFileName())); + } + } + } + + @Override + public void moveAndProcessExtraction(Path from, Path to) { + + this.context.getFileAccess().move(from, to); + } + + /** + * @param path the {@link Path} to start the recursive search from. + * @return the deepest subdir {@code s} of the passed path such that all directories between {@code s} and the passed + * path (including {@code s}) are the sole item in their respective directory and {@code s} is not named + * "bin". + */ + private Path getProperInstallationSubDirOf(Path path) { + + try (Stream stream = Files.list(path)) { + Path[] subFiles = stream.toArray(Path[]::new); + if (subFiles.length == 0) { + throw new CliException("The downloaded package for the tool " + commandlet.getName() + + " seems to be empty as you can check in the extracted folder " + path); + } else if (subFiles.length == 1) { + String filename = subFiles[0].getFileName().toString(); + if (!filename.equals(IdeContext.FOLDER_BIN) && !filename.equals(IdeContext.FOLDER_CONTENTS) + && !filename.endsWith(".app") && Files.isDirectory(subFiles[0])) { + return getProperInstallationSubDirOf(subFiles[0]); + } + } + return path; + } catch (IOException e) { + throw new IllegalStateException("Failed to get sub-files of " + path); + } + } + +} 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 9cb1533a3..0c63b4539 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 @@ -128,8 +128,11 @@ public abstract class AbstractIdeContext implements IdeContext { * @param minLogLevel the minimum {@link IdeLogLevel} to enable. Should be {@link IdeLogLevel#INFO} by default. * @param factory the {@link Function} to create {@link IdeSubLogger} per {@link IdeLogLevel}. * @param userDir the optional {@link Path} to current working directory. + * @param toolRepository @param toolRepository the {@link ToolRepository} of the context. If it is set to {@code null} + * {@link DefaultToolRepository} will be used. */ - public AbstractIdeContext(IdeLogLevel minLogLevel, Function factory, Path userDir) { + public AbstractIdeContext(IdeLogLevel minLogLevel, Function factory, Path userDir, + ToolRepository toolRepository) { super(); this.loggerFactory = factory; @@ -234,7 +237,7 @@ public AbstractIdeContext(IdeLogLevel minLogLevel, Function new IdeSubLoggerOut(level, out, colored), null); + super(minLogLevel, level -> new IdeSubLoggerOut(level, out, colored), null, null); if (System.console() == null) { debug("System console not available - using System.in as fallback"); this.scanner = new Scanner(System.in); @@ -51,12 +51,12 @@ public IdeProgressBar prepareProgressBar(String taskName, long size) { ProgressBarBuilder pbb = new ProgressBarBuilder(); // default (COLORFUL_UNICODE_BLOCK) pbb.setStyle(ProgressBarStyle.builder().refreshPrompt("\r").leftBracket("\u001b[33m│").delimitingSequence("") - .rightBracket("│\u001b[0m").block('█').space(' ').fractionSymbols(" ▏▎▍▌▋▊▉").rightSideFractionSymbol(' ') - .build()); + .rightBracket("│\u001b[0m").block('█').space(' ').fractionSymbols(" ▏▎▍▌▋▊▉").rightSideFractionSymbol(' ') + .build()); // set different style for Windows systems (ASCII) if (this.getSystemInfo().isWindows()) { pbb.setStyle(ProgressBarStyle.builder().refreshPrompt("\r").leftBracket("[").delimitingSequence("") - .rightBracket("]").block('=').space(' ').fractionSymbols(">").rightSideFractionSymbol(' ').build()); + .rightBracket("]").block('=').space(' ').fractionSymbols(">").rightSideFractionSymbol(' ').build()); } pbb.showSpeed(); pbb.setTaskName(taskName); diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java index 2b2498893..d3ade5632 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/GlobalToolCommandlet.java @@ -1,5 +1,9 @@ package com.devonfw.tools.ide.tool; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Set; + import com.devonfw.tools.ide.common.Tag; import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.io.FileAccess; @@ -9,10 +13,6 @@ import com.devonfw.tools.ide.repo.ToolRepository; import com.devonfw.tools.ide.version.VersionIdentifier; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Set; - /** * {@link ToolCommandlet} that is installed globally. */ @@ -58,7 +58,7 @@ protected boolean doInstall(boolean silent) { Path target = toolRepository.download(this.tool, edition, resolvedVersion); Path tmpDir = fileAccess.createTempDir(getName()); Path downloadBinaryPath = tmpDir.resolve(target.getFileName()); - extract(target, downloadBinaryPath); + commandletFileExtractor.extract(target, downloadBinaryPath, isExtract()); if (isExtract()) { downloadBinaryPath = fileAccess.findFirst(downloadBinaryPath, Files::isExecutable, false); } diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/LocalToolCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/tool/LocalToolCommandlet.java index 61a5c4656..7e9e207a9 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/LocalToolCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/LocalToolCommandlet.java @@ -6,7 +6,6 @@ import java.nio.file.StandardOpenOption; import java.util.Set; -import com.devonfw.tools.ide.commandlet.Commandlet; import com.devonfw.tools.ide.common.Tag; import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.io.FileAccess; @@ -92,8 +91,9 @@ protected boolean doInstall(boolean silent) { } /** - * Performs the installation of the {@link #getName() tool} managed by this {@link Commandlet} only in the central - * software repository without touching the IDE installation. + * Performs the installation of the {@link #getName() tool} managed by this + * {@link com.devonfw.tools.ide.commandlet.Commandlet} only in the central software repository without touching the + * IDE installation. * * @param version the {@link VersionIdentifier} requested to be installed. May also be a * {@link VersionIdentifier#isPattern() version pattern}. @@ -105,8 +105,9 @@ public ToolInstallation installInRepo(VersionIdentifier version) { } /** - * Performs the installation of the {@link #getName() tool} managed by this {@link Commandlet} only in the central - * software repository without touching the IDE installation. + * Performs the installation of the {@link #getName() tool} managed by this + * {@link com.devonfw.tools.ide.commandlet.Commandlet} only in the central software repository without touching the + * IDE installation. * * @param version the {@link VersionIdentifier} requested to be installed. May also be a * {@link VersionIdentifier#isPattern() version pattern}. @@ -119,8 +120,9 @@ public ToolInstallation installInRepo(VersionIdentifier version, String edition) } /** - * Performs the installation of the {@link #getName() tool} managed by this {@link Commandlet} only in the central - * software repository without touching the IDE installation. + * Performs the installation of the {@link #getName() tool} managed by this + * {@link com.devonfw.tools.ide.commandlet.Commandlet} only in the central software repository without touching the + * IDE installation. * * @param version the {@link VersionIdentifier} requested to be installed. May also be a * {@link VersionIdentifier#isPattern() version pattern}. @@ -151,7 +153,7 @@ public ToolInstallation installInRepo(VersionIdentifier version, String edition, } Path target = toolRepository.download(this.tool, edition, resolvedVersion); fileAccess.mkdirs(toolPath.getParent()); - extract(target, toolPath); + commandletFileExtractor.extract(target, toolPath, isExtract()); try { Files.writeString(toolVersionFile, resolvedVersion.toString(), StandardOpenOption.CREATE_NEW); } catch (IOException e) { diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java index be36fbc78..8a31520ca 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java @@ -5,22 +5,19 @@ import java.nio.file.Path; import java.util.List; import java.util.Set; -import java.util.stream.Stream; -import com.devonfw.tools.ide.cli.CliException; import com.devonfw.tools.ide.commandlet.Commandlet; +import com.devonfw.tools.ide.commandlet.CommandletFileExtractor; +import com.devonfw.tools.ide.commandlet.CommandletFileExtractorImpl; import com.devonfw.tools.ide.common.Tag; import com.devonfw.tools.ide.common.Tags; import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.environment.EnvironmentVariables; import com.devonfw.tools.ide.environment.EnvironmentVariablesType; -import com.devonfw.tools.ide.io.FileAccess; -import com.devonfw.tools.ide.io.TarCompression; import com.devonfw.tools.ide.os.MacOsHelper; import com.devonfw.tools.ide.process.ProcessContext; import com.devonfw.tools.ide.process.ProcessErrorHandling; import com.devonfw.tools.ide.property.StringListProperty; -import com.devonfw.tools.ide.util.FilenameUtil; import com.devonfw.tools.ide.version.VersionIdentifier; /** @@ -28,6 +25,8 @@ */ public abstract class ToolCommandlet extends Commandlet implements Tags { + public CommandletFileExtractor commandletFileExtractor; + /** @see #getName() */ protected final String tool; @@ -53,6 +52,9 @@ public ToolCommandlet(IdeContext context, String tool, Set tags) { this.tags = tags; addKeyword(tool); this.arguments = add(new StringListProperty("", false, "args")); + + // TODO MAKE THIS SETTABLE + commandletFileExtractor = new CommandletFileExtractorImpl(context, this); } /** @@ -104,7 +106,8 @@ public void runTool(boolean runInBackground, VersionIdentifier toolVersion, Stri } else { throw new UnsupportedOperationException("Not yet implemented!"); } - ProcessContext pc = this.context.newProcess().errorHandling(ProcessErrorHandling.WARNING).executable(binaryPath).addArgs(args); + ProcessContext pc = this.context.newProcess().errorHandling(ProcessErrorHandling.WARNING).executable(binaryPath) + .addArgs(args); pc.run(false, runInBackground); } @@ -160,7 +163,8 @@ public VersionIdentifier getConfiguredVersion() { } /** - * Method to be called for {@link #install(boolean)} from dependent {@link Commandlet}s. + * Method to be called for {@link #install(boolean)} from dependent + * {@link com.devonfw.tools.ide.commandlet.Commandlet}s. * * @return {@code true} if the tool was newly installed, {@code false} if the tool was already installed before and * nothing has changed. @@ -171,7 +175,8 @@ public boolean install() { } /** - * Performs the installation of the {@link #getName() tool} managed by this {@link Commandlet}. + * Performs the installation of the {@link #getName() tool} managed by this + * {@link com.devonfw.tools.ide.commandlet.Commandlet}. * * @param silent - {@code true} if called recursively to suppress verbose logging, {@code false} otherwise. * @return {@code true} if the tool was newly installed, {@code false} if the tool was already installed before and @@ -199,110 +204,6 @@ protected void postInstall() { // nothing to do by default } - /** - * @param path the {@link Path} to start the recursive search from. - * @return the deepest subdir {@code s} of the passed path such that all directories between {@code s} and the passed - * path (including {@code s}) are the sole item in their respective directory and {@code s} is not named - * "bin". - */ - private Path getProperInstallationSubDirOf(Path path) { - - try (Stream stream = Files.list(path)) { - Path[] subFiles = stream.toArray(Path[]::new); - if (subFiles.length == 0) { - throw new CliException("The downloaded package for the tool " + this.tool + " seems to be empty as you can check in the extracted folder " + path); - } else if (subFiles.length == 1) { - String filename = subFiles[0].getFileName().toString(); - if (!filename.equals(IdeContext.FOLDER_BIN) && !filename.equals(IdeContext.FOLDER_CONTENTS) && !filename.endsWith(".app") - && Files.isDirectory(subFiles[0])) { - return getProperInstallationSubDirOf(subFiles[0]); - } - } - return path; - } catch (IOException e) { - throw new IllegalStateException("Failed to get sub-files of " + path); - } - } - - /** - * @param file the {@link Path} to the file to extract. - * @param targetDir the {@link Path} to the directory where to extract (or copy) the file. - */ - protected void extract(Path file, Path targetDir) { - - FileAccess fileAccess = this.context.getFileAccess(); - if (isExtract()) { - Path tmpDir = this.context.getFileAccess().createTempDir("extract-" + file.getFileName()); - this.context.trace("Trying to extract the downloaded file {} to {} and move it to {}.", file, tmpDir, targetDir); - String extension = FilenameUtil.getExtension(file.getFileName().toString()); - this.context.trace("Determined file extension {}", extension); - TarCompression tarCompression = TarCompression.of(extension); - if (tarCompression != null) { - fileAccess.untar(file, tmpDir, tarCompression); - } else if ("zip".equals(extension) || "jar".equals(extension)) { - fileAccess.unzip(file, tmpDir); - } else if ("dmg".equals(extension)) { - assert this.context.getSystemInfo().isMac(); - Path mountPath = this.context.getIdeHome().resolve(IdeContext.FOLDER_UPDATES).resolve(IdeContext.FOLDER_VOLUME); - fileAccess.mkdirs(mountPath); - ProcessContext pc = this.context.newProcess(); - pc.executable("hdiutil"); - pc.addArgs("attach", "-quiet", "-nobrowse", "-mountpoint", mountPath, file); - pc.run(); - Path appPath = fileAccess.findFirst(mountPath, p -> p.getFileName().toString().endsWith(".app"), false); - if (appPath == null) { - throw new IllegalStateException("Failed to unpack DMG as no MacOS *.app was found in file " + file); - } - fileAccess.copy(appPath, tmpDir); - pc.addArgs("detach", "-force", mountPath); - pc.run(); - } else if ("msi".equals(extension)) { - this.context.newProcess().executable("msiexec").addArgs("/a", file, "/qn", "TARGETDIR=" + tmpDir).run(); - // msiexec also creates a copy of the MSI - Path msiCopy = tmpDir.resolve(file.getFileName()); - fileAccess.delete(msiCopy); - } else if ("pkg".equals(extension)) { - - Path tmpDirPkg = fileAccess.createTempDir("ide-pkg-"); - ProcessContext pc = this.context.newProcess(); - // we might also be able to use cpio from commons-compression instead of external xar... - pc.executable("xar").addArgs("-C", tmpDirPkg, "-xf", file).run(); - Path contentPath = fileAccess.findFirst(tmpDirPkg, p -> p.getFileName().toString().equals("Payload"), true); - fileAccess.untar(contentPath, tmpDir, TarCompression.GZ); - fileAccess.delete(tmpDirPkg); - } else { - throw new IllegalStateException("Unknown archive format " + extension + ". Can not extract " + file); - } - moveAndProcessExtraction(getProperInstallationSubDirOf(tmpDir), targetDir); - fileAccess.delete(tmpDir); - } else { - this.context.trace("Extraction is disabled for '{}' hence just moving the downloaded file {}.", getName(), file); - - if (Files.isDirectory(file)) { - fileAccess.move(file, targetDir); - } else { - try { - Files.createDirectories(targetDir); - } catch (IOException e) { - throw new IllegalStateException("Failed to create folder " + targetDir); - } - fileAccess.move(file, targetDir.resolve(file.getFileName())); - } - } - } - - /** - * Moves the extracted content to the final destination {@link Path}. May be overridden to customize the extraction - * process. - * - * @param from the source {@link Path} to move. - * @param to the target {@link Path} to move to. - */ - protected void moveAndProcessExtraction(Path from, Path to) { - - this.context.getFileAccess().move(from, to); - } - /** * @return {@code true} to extract (unpack) the downloaded binary file, {@code false} otherwise. */ @@ -384,8 +285,10 @@ public String getInstalledEdition(Path toolPath) { } return edition; } catch (IOException e) { - throw new IllegalStateException("Couldn't determine the edition of " + getName() + " from the directory structure of its software path " + toolPath - + ", assuming the name of the parent directory of the real path of the software path to be the edition " + "of the tool.", e); + throw new IllegalStateException("Couldn't determine the edition of " + getName() + + " from the directory structure of its software path " + toolPath + + ", assuming the name of the parent directory of the real path of the software path to be the edition " + + "of the tool.", e); } } @@ -450,8 +353,9 @@ public void setVersion(VersionIdentifier version, boolean hint) { this.context.info("{}={} has been set in {}", name, version, settingsVariables.getSource()); EnvironmentVariables declaringVariables = variables.findVariable(name); if ((declaringVariables != null) && (declaringVariables != settingsVariables)) { - this.context.warning("The variable {} is overridden in {}. Please remove the overridden declaration in order to make the change affect.", name, - declaringVariables.getSource()); + this.context.warning( + "The variable {} is overridden in {}. Please remove the overridden declaration in order to make the change affect.", + name, declaringVariables.getSource()); } if (hint) { this.context.info("To install that version call the following command:"); @@ -494,8 +398,9 @@ public void setEdition(String edition, boolean hint) { this.context.info("{}={} has been set in {}", name, edition, settingsVariables.getSource()); EnvironmentVariables declaringVariables = variables.findVariable(name); if ((declaringVariables != null) && (declaringVariables != settingsVariables)) { - this.context.warning("The variable {} is overridden in {}. Please remove the overridden declaration in order to make the change affect.", name, - declaringVariables.getSource()); + this.context.warning( + "The variable {} is overridden in {}. Please remove the overridden declaration in order to make the change affect.", + name, declaringVariables.getSource()); } if (hint) { this.context.info("To install that edition call the following command:"); @@ -503,4 +408,9 @@ public void setEdition(String edition, boolean hint) { } } + public void setCommandletFileExtractor(CommandletFileExtractor commandletFileExtractor) { + + this.commandletFileExtractor = commandletFileExtractor; + } + } diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/aws/Aws.java b/cli/src/main/java/com/devonfw/tools/ide/tool/aws/Aws.java index d2257228f..7d3e9a905 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/aws/Aws.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/aws/Aws.java @@ -1,16 +1,12 @@ package com.devonfw.tools.ide.tool.aws; -import java.io.IOException; -import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.attribute.PosixFilePermission; import java.util.Set; import com.devonfw.tools.ide.common.Tag; import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.environment.EnvironmentVariables; import com.devonfw.tools.ide.environment.EnvironmentVariablesType; -import com.devonfw.tools.ide.process.ProcessContext; import com.devonfw.tools.ide.tool.LocalToolCommandlet; /** @@ -29,57 +25,7 @@ public class Aws extends LocalToolCommandlet { public Aws(IdeContext context) { super(context, "aws", Set.of(Tag.CLOUD)); - } - - private void makeExecutable(Path file) { - - // TODO this can be removed if issue #132 is fixed. See https://github.com/devonfw/IDEasy/issues/132 - Set permissions = null; - try { - permissions = Files.getPosixFilePermissions(file); - permissions.add(PosixFilePermission.GROUP_EXECUTE); - permissions.add(PosixFilePermission.OWNER_EXECUTE); - permissions.add(PosixFilePermission.OTHERS_EXECUTE); - Files.setPosixFilePermissions(file, permissions); - } catch (IOException e) { - throw new RuntimeException("Adding execution permission for Group, Owner and Others did not work for " + file, e); - } - } - - @Override - protected void moveAndProcessExtraction(Path from, Path to) { - - if (this.context.getSystemInfo().isLinux()) { - // make binary executable using java nio because unpacking didn't preserve the file permissions - // TODO this can be removed if issue #132 is fixed - Path awsInDistPath = from.resolve("dist").resolve("aws"); - Path awsCompleterInDistPath = from.resolve("dist").resolve("aws_completer"); - makeExecutable(awsInDistPath); - makeExecutable(awsCompleterInDistPath); - - // running the install-script that aws shipped - ProcessContext pc = this.context.newProcess(); - Path linuxInstallScript = from.resolve("install"); - pc.executable(linuxInstallScript); - pc.addArgs("-i", from.toString(), "-b", from.toString()); - pc.run(); - - // The install-script that aws ships creates symbolic links to binaries but using absolute paths. - // Since the current process happens in a temporary dir, these links wouldn't be valid after moving the - // installation files to the target dir. So the absolute paths are replaced by relative ones. - for (String file : new String[] { "aws", "aws_completer", Path.of("v2").resolve("current").toString() }) { - Path link = from.resolve(file); - try { - this.context.getFileAccess().symlink(link.toRealPath(), link, true); - } catch (IOException e) { - throw new RuntimeException( - "Failed to replace absolute link (" + link + ") provided by AWS install script with relative link.", e); - } - } - this.context.getFileAccess().delete(linuxInstallScript); - this.context.getFileAccess().delete(from.resolve("dist")); - } - super.moveAndProcessExtraction(from, to); + setCommandletFileExtractor(new AwsFileExtractor(context, this)); } @Override diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/aws/AwsFileExtractor.java b/cli/src/main/java/com/devonfw/tools/ide/tool/aws/AwsFileExtractor.java new file mode 100644 index 000000000..fb7097807 --- /dev/null +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/aws/AwsFileExtractor.java @@ -0,0 +1,74 @@ +package com.devonfw.tools.ide.tool.aws; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.attribute.PosixFilePermission; +import java.util.Set; + +import com.devonfw.tools.ide.commandlet.CommandletFileExtractorImpl; +import com.devonfw.tools.ide.context.IdeContext; +import com.devonfw.tools.ide.process.ProcessContext; +import com.devonfw.tools.ide.tool.ToolCommandlet; + +/** + * Implements a {@link CommandletFileExtractorImpl} for {@link Aws} + */ +public class AwsFileExtractor extends CommandletFileExtractorImpl { + public AwsFileExtractor(IdeContext context, ToolCommandlet commandlet) { + + super(context, commandlet); + } + + @Override + public void moveAndProcessExtraction(Path from, Path to) { + + if (this.context.getSystemInfo().isLinux()) { + // make binary executable using java nio because unpacking didn't preserve the file permissions + // TODO this can be removed if issue #132 is fixed + Path awsInDistPath = from.resolve("dist").resolve("aws"); + Path awsCompleterInDistPath = from.resolve("dist").resolve("aws_completer"); + makeExecutable(awsInDistPath); + makeExecutable(awsCompleterInDistPath); + + // running the install-script that aws shipped + ProcessContext pc = this.context.newProcess(); + Path linuxInstallScript = from.resolve("install"); + pc.executable(linuxInstallScript); + pc.addArgs("-i", from.toString(), "-b", from.toString()); + pc.run(); + + // The install-script that aws ships creates symbolic links to binaries but using absolute paths. + // Since the current process happens in a temporary dir, these links wouldn't be valid after moving the + // installation files to the target dir. So the absolute paths are replaced by relative ones. + for (String file : new String[] { "aws", "aws_completer", Path.of("v2").resolve("current").toString() }) { + Path link = from.resolve(file); + try { + this.context.getFileAccess().symlink(link.toRealPath(), link, true); + } catch (IOException e) { + throw new RuntimeException( + "Failed to replace absolute link (" + link + ") provided by AWS install script with relative link.", e); + } + } + this.context.getFileAccess().delete(linuxInstallScript); + this.context.getFileAccess().delete(from.resolve("dist")); + } + super.moveAndProcessExtraction(from, to); + } + + private void makeExecutable(Path file) { + + // TODO this can be removed if issue #132 is fixed. See https://github.com/devonfw/IDEasy/issues/132 + Set permissions = null; + try { + permissions = Files.getPosixFilePermissions(file); + permissions.add(PosixFilePermission.GROUP_EXECUTE); + permissions.add(PosixFilePermission.OWNER_EXECUTE); + permissions.add(PosixFilePermission.OTHERS_EXECUTE); + Files.setPosixFilePermissions(file, permissions); + } catch (IOException e) { + throw new RuntimeException("Adding execution permission for Group, Owner and Others did not work for " + file, e); + } + } + +} diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/ide/IdeToolCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/tool/ide/IdeToolCommandlet.java index 4bb4800c8..1a5157e65 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/ide/IdeToolCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/ide/IdeToolCommandlet.java @@ -207,7 +207,7 @@ public void run() { */ protected void runIde(String... args) { - runTool(false,null, args); + runTool(false, null, args); } /** diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/jmc/Jmc.java b/cli/src/main/java/com/devonfw/tools/ide/tool/jmc/Jmc.java index 0c316cfbf..f9ac52d82 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/jmc/Jmc.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/jmc/Jmc.java @@ -10,8 +10,8 @@ import com.devonfw.tools.ide.common.Tag; import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.io.FileAccess; -import com.devonfw.tools.ide.tool.LocalToolCommandlet; import com.devonfw.tools.ide.tool.ToolCommandlet; +import com.devonfw.tools.ide.tool.LocalToolCommandlet; import com.devonfw.tools.ide.tool.java.Java; /** @@ -33,8 +33,7 @@ public Jmc(IdeContext context) { @Override public boolean doInstall(boolean silent) { - // TODO https://github.com/devonfw/IDEasy/issues/209 currently outcommented as this breaks the tests, real fix needed asap - // getCommandlet(Java.class).install(); + getCommandlet(Java.class).install(); return super.doInstall(silent); } @@ -57,7 +56,9 @@ public void postInstall() { moveFilesAndDirs(oldBinaryPath, toolPath); fileAccess.delete(oldBinaryPath); } else { - this.context.info("JMC binary folder not found at {} - ignoring as this legacy problem may be resolved in newer versions.", oldBinaryPath); + this.context.info( + "JMC binary folder not found at {} - ignoring as this legacy problem may be resolved in newer versions.", + oldBinaryPath); } } diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/mvn/Mvn.java b/cli/src/main/java/com/devonfw/tools/ide/tool/mvn/Mvn.java index 3f1b32299..c24a860fe 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/mvn/Mvn.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/mvn/Mvn.java @@ -36,7 +36,8 @@ public boolean install(boolean silent) { @Override public void installPlugin(PluginDescriptor plugin) { - Path mavenPlugin = this.context.getSoftwarePath().resolve(this.tool).resolve("lib/ext/" + plugin.getName() + ".jar"); + Path mavenPlugin = this.context.getSoftwarePath().resolve(this.tool) + .resolve("lib/ext/" + plugin.getName() + ".jar"); this.context.getFileAccess().download(plugin.getUrl(), mavenPlugin); if (Files.exists(mavenPlugin)) { this.context.success("Successfully added {} to {}", plugin.getName(), mavenPlugin.toString()); diff --git a/cli/src/test/java/com/devonfw/tools/ide/commandlet/CommandLetExtractorMock.java b/cli/src/test/java/com/devonfw/tools/ide/commandlet/CommandLetExtractorMock.java new file mode 100644 index 000000000..4b6fc9212 --- /dev/null +++ b/cli/src/test/java/com/devonfw/tools/ide/commandlet/CommandLetExtractorMock.java @@ -0,0 +1,52 @@ +package com.devonfw.tools.ide.commandlet; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Iterator; +import java.util.stream.Stream; + +import com.devonfw.tools.ide.context.IdeContext; +import com.devonfw.tools.ide.io.FileAccess; + +/** + * Implementation of {@link CommandletFileExtractor} for testing. + */ +public class CommandLetExtractorMock implements CommandletFileExtractor { + + private final IdeContext context; + + public CommandLetExtractorMock(IdeContext context) { + + this.context = context; + } + + @Override + public void extract(Path file, Path targetDir, boolean isExtract) { + + FileAccess fileAccess = context.getFileAccess(); + fileAccess.mkdirs(targetDir); + + if (Files.isDirectory(file)) { + + try (Stream childStream = Files.list(file)) { + Iterator iterator = childStream.iterator(); + while (iterator.hasNext()) { + Path child = iterator.next(); + fileAccess.copy(child, targetDir.resolve(child.getFileName())); + } + } catch (IOException e) { + throw new IllegalStateException("Failed to list files to copy in " + file, e); + } + + } else { + throw new IllegalStateException("Testing mocks only supports moving folders to install location!"); + } + } + + @Override + public void moveAndProcessExtraction(Path from, Path to) { + + // do nothing in mock + } +} diff --git a/cli/src/test/java/com/devonfw/tools/ide/context/AbstractIdeContextTest.java b/cli/src/test/java/com/devonfw/tools/ide/context/AbstractIdeContextTest.java index cdea75d8f..7131ee127 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/context/AbstractIdeContextTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/context/AbstractIdeContextTest.java @@ -13,6 +13,7 @@ import com.devonfw.tools.ide.io.IdeProgressBarTestImpl; import com.devonfw.tools.ide.log.IdeLogLevel; import com.devonfw.tools.ide.log.IdeTestLogger; +import com.devonfw.tools.ide.repo.ToolRepository; /** * Abstract base class for tests that need mocked instances of {@link IdeContext}. @@ -63,6 +64,22 @@ protected static IdeTestContext newContext(String projectTestCaseName, String pr */ protected static IdeTestContext newContext(String projectTestCaseName, String projectPath, boolean copyForMutation) { + return newContext(projectTestCaseName, projectPath, copyForMutation, null); + } + + /** + * @param projectTestCaseName the (folder)name of the project test case, in this folder a 'project' folder represents + * the test project in {@link #PATH_PROJECTS}. E.g. "basic". + * @param projectPath the relative path inside the test project where to create the context. + * @param copyForMutation - {@code true} to create a copy of the project that can be modified by the test, + * {@code false} otherwise (only to save resources if you are 100% sure that your test never modifies anything + * in that project.) + * @param toolRepository The ToolRepository implementation used by the context mock + * @return the {@link IdeTestContext} pointing to that project. + */ + protected static IdeTestContext newContext(String projectTestCaseName, String projectPath, boolean copyForMutation, + ToolRepository toolRepository) { + Path sourceDir = PATH_PROJECTS.resolve(projectTestCaseName); Path userDir = sourceDir.resolve("project"); IdeTestContext context; @@ -77,7 +94,9 @@ protected static IdeTestContext newContext(String projectTestCaseName, String pr if (projectPath != null) { userDir = userDir.resolve(projectPath); } - context = new IdeTestContext(userDir); + + context = new IdeTestContext(userDir, toolRepository); + return context; } diff --git a/cli/src/test/java/com/devonfw/tools/ide/context/AbstractIdeTestContext.java b/cli/src/test/java/com/devonfw/tools/ide/context/AbstractIdeTestContext.java index 9810990e9..ebf3f769c 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/context/AbstractIdeTestContext.java +++ b/cli/src/test/java/com/devonfw/tools/ide/context/AbstractIdeTestContext.java @@ -9,6 +9,7 @@ import com.devonfw.tools.ide.io.IdeProgressBarTestImpl; import com.devonfw.tools.ide.log.IdeLogLevel; import com.devonfw.tools.ide.log.IdeSubLogger; +import com.devonfw.tools.ide.repo.ToolRepository; /** * Implementation of {@link IdeContext} for testing. @@ -26,11 +27,13 @@ public class AbstractIdeTestContext extends AbstractIdeContext { * * @param factory the {@link Function} to create {@link IdeSubLogger} per {@link IdeLogLevel}. * @param userDir the optional {@link Path} to current working directory. + * @param toolRepository @param toolRepository the {@link ToolRepository} of the context. * @param answers the automatic answers simulating a user in test. */ - public AbstractIdeTestContext(Function factory, Path userDir, String... answers) { + public AbstractIdeTestContext(Function factory, Path userDir, + ToolRepository toolRepository, String... answers) { - super(IdeLogLevel.TRACE, factory, userDir); + super(IdeLogLevel.TRACE, factory, userDir, toolRepository); this.answers = answers; this.progressBarMap = new HashMap<>(); } diff --git a/cli/src/test/java/com/devonfw/tools/ide/context/IdeSlf4jContext.java b/cli/src/test/java/com/devonfw/tools/ide/context/IdeSlf4jContext.java index 94313c290..f3e515d74 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/context/IdeSlf4jContext.java +++ b/cli/src/test/java/com/devonfw/tools/ide/context/IdeSlf4jContext.java @@ -17,7 +17,7 @@ public class IdeSlf4jContext extends AbstractIdeTestContext { */ public IdeSlf4jContext(Path userDir, String... answers) { - super(level -> new IdeSlf4jLogger(level), userDir, answers); + super(level -> new IdeSlf4jLogger(level), userDir, null, answers); } } diff --git a/cli/src/test/java/com/devonfw/tools/ide/context/IdeTestContext.java b/cli/src/test/java/com/devonfw/tools/ide/context/IdeTestContext.java index 1ad4ee8bd..16c2880f2 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/context/IdeTestContext.java +++ b/cli/src/test/java/com/devonfw/tools/ide/context/IdeTestContext.java @@ -4,6 +4,7 @@ import com.devonfw.tools.ide.log.IdeLogLevel; import com.devonfw.tools.ide.log.IdeTestLogger; +import com.devonfw.tools.ide.repo.ToolRepository; /** * Implementation of {@link IdeContext} for testing. @@ -18,7 +19,20 @@ public class IdeTestContext extends AbstractIdeTestContext { */ public IdeTestContext(Path userDir, String... answers) { - super(level -> new IdeTestLogger(level), userDir, answers); + super(level -> new IdeTestLogger(level), userDir, null, answers); + } + + /** + * The constructor. + * + * @param userDir the optional {@link Path} to current working directory. + * @param toolRepository the {@link ToolRepository} of the context. If it is set to {@code null} * + * {@link com.devonfw.tools.ide.repo.DefaultToolRepository} will be used. + * @param answers the automatic answers simulating a user in test. + */ + public IdeTestContext(Path userDir, ToolRepository toolRepository, String... answers) { + + super(level -> new IdeTestLogger(level), userDir, toolRepository, answers); } @Override diff --git a/cli/src/test/java/com/devonfw/tools/ide/repo/ToolRepositoryMock.java b/cli/src/test/java/com/devonfw/tools/ide/repo/ToolRepositoryMock.java new file mode 100644 index 000000000..80e095cb3 --- /dev/null +++ b/cli/src/test/java/com/devonfw/tools/ide/repo/ToolRepositoryMock.java @@ -0,0 +1,89 @@ +package com.devonfw.tools.ide.repo; + +import java.nio.file.Path; +import java.util.Map; + +import com.devonfw.tools.ide.context.IdeContext; +import com.devonfw.tools.ide.version.VersionIdentifier; + +/** + * Implementation of {@link ToolRepository} for testing. + */ +public class ToolRepositoryMock implements ToolRepository { + + private static final Path PROJECTS_RESOURCE_PATH = Path.of("src/test/resources/ide-projects"); + + private static final String MOCK_DOWNLOAD_FOLDERNAME = "downloadMockLocation"; + + private final Map toolToVersion; + + private final String projectTestCaseName; + + private final String windowsFolderName; + + private final String linuxFolderName; + + private final String macFolderName; + + private IdeContext context; + + /** + * Constructor of a ToolRepository Mock + * + * @param toolToVersion Mapping of which Version of a tool should be mocked + * @param projectTestCaseName the (folder)name of the project test case, in this folder a 'project' folder represents + * the test project in {@link #PROJECTS_RESOURCE_PATH}. E.g. "basic". + * @param windowsFolderName Name of the folder which is used when test is run under Windows + * @param linuxFolderName Name of the folder which is used when test is run under Linux + * @param macFolderName Name of the folder which is used when test is run under Mac OS + */ + public ToolRepositoryMock(Map toolToVersion, String projectTestCaseName, String windowsFolderName, + String linuxFolderName, String macFolderName) { + + this.toolToVersion = toolToVersion; + this.projectTestCaseName = projectTestCaseName; + this.windowsFolderName = windowsFolderName; + this.linuxFolderName = linuxFolderName; + this.macFolderName = macFolderName; + } + + public void setContext(IdeContext context) { + + this.context = context; + + } + + @Override + public String getId() { + + return ID_DEFAULT; + } + + @Override + public VersionIdentifier resolveVersion(String tool, String edition, VersionIdentifier version) { + + return VersionIdentifier.of(toolToVersion.get(tool)); + } + + @Override + public Path download(String tool, String edition, VersionIdentifier version) { + + Path baseDownloadMockPath = PROJECTS_RESOURCE_PATH.resolve(projectTestCaseName).resolve(MOCK_DOWNLOAD_FOLDERNAME); + String mockProgram = ""; + + if (context == null) { + throw new IllegalStateException("Please set a IdeContext!"); + } + + // TODO MOCK CONTEXT SYSTEMINFO ??? + if (context.getSystemInfo().isWindows()) { + mockProgram = windowsFolderName; + } else if (context.getSystemInfo().isLinux()) { + mockProgram = linuxFolderName; + } else if (context.getSystemInfo().isMac()) { + mockProgram = macFolderName; + } + + return baseDownloadMockPath.resolve(mockProgram); + } +} diff --git a/cli/src/test/java/com/devonfw/tools/ide/tool/jmc/JmcTest.java b/cli/src/test/java/com/devonfw/tools/ide/tool/jmc/JmcTest.java index 59477d1de..2532a34bc 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/tool/jmc/JmcTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/tool/jmc/JmcTest.java @@ -7,14 +7,19 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.HashMap; +import java.util.Map; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; +import com.devonfw.tools.ide.commandlet.CommandLetExtractorMock; import com.devonfw.tools.ide.commandlet.InstallCommandlet; import com.devonfw.tools.ide.context.AbstractIdeContextTest; import com.devonfw.tools.ide.context.IdeContext; +import com.devonfw.tools.ide.repo.ToolRepositoryMock; import com.github.tomakehurst.wiremock.WireMockServer; import com.github.tomakehurst.wiremock.core.WireMockConfiguration; @@ -25,11 +30,14 @@ public class JmcTest extends AbstractIdeContextTest { private static WireMockServer server; - private static Path resourcePath = Path.of("src/test/resources"); + private static final Path RESOURCE_PATH = Path.of("src/test/resources"); @BeforeAll static void setUp() throws IOException { + + // TODO use random port number and create url file dynamically in project server = new WireMockServer(WireMockConfiguration.wireMockConfig().port(1112)); + server.start(); } @@ -41,31 +49,34 @@ static void tearDown() throws IOException { private void mockWebServer() throws IOException { + // Jmc under test String windowsFilenameJmc = "org.openjdk.jmc-8.3.0-win32.win32.x86_64.zip"; - String linuxFilenameJmc = "org.openjdk.jmc-8.3.0-linux.gtk.x86_64.tar.gz"; - String macOSFilenameJmc = "org.openjdk.jmc-8.3.0-macosx.cocoa.x86_64.tar.gz"; - String windowsFilenameJava = "java-17.0.6-windows-x64.zip"; - String linuxFilenameJava = "java-17.0.6-linux-x64.tgz"; - String resourceFilesDirName = "__files"; - - Path windowsFilePathJmc = resourcePath.resolve(resourceFilesDirName).resolve(windowsFilenameJmc); + Path windowsFilePathJmc = RESOURCE_PATH.resolve("__files").resolve(windowsFilenameJmc); String windowsLengthJmc = String.valueOf(Files.size(windowsFilePathJmc)); - Path linuxFilePathJmc = resourcePath.resolve(resourceFilesDirName).resolve(linuxFilenameJmc); + String linuxFilenameJmc = "org.openjdk.jmc-8.3.0-linux.gtk.x86_64.tar.gz"; + Path linuxFilePathJmc = RESOURCE_PATH.resolve("__files").resolve(linuxFilenameJmc); String linuxLengthJmc = String.valueOf(Files.size(linuxFilePathJmc)); - Path macOSFilePathJmc = resourcePath.resolve(resourceFilesDirName).resolve(macOSFilenameJmc); + String macOSFilenameJmc = "org.openjdk.jmc-8.3.0-macosx.cocoa.x86_64.tar.gz"; + Path macOSFilePathJmc = RESOURCE_PATH.resolve("__files").resolve(macOSFilenameJmc); String maxOSLengthJmc = String.valueOf(Files.size(macOSFilePathJmc)); - Path windowsFilePathJava = resourcePath.resolve(resourceFilesDirName).resolve(windowsFilenameJava); + setupMockServerResponse("/jmcTest/windows", "application/zip", windowsLengthJmc, windowsFilenameJmc); + setupMockServerResponse("/jmcTest/linux", "application/gz", linuxLengthJmc, linuxFilenameJmc); + setupMockServerResponse("/jmcTest/macOS", "application/gz", maxOSLengthJmc, macOSFilenameJmc); + + // Java prerequisite + + String windowsFilenameJava = "java-17.0.6-windows-x64.zip"; + String linuxFilenameJava = "java-17.0.6-linux-x64.tgz"; + + Path windowsFilePathJava = RESOURCE_PATH.resolve("__files").resolve(windowsFilenameJava); String windowsLengthJava = String.valueOf(Files.size(windowsFilePathJava)); - Path linuxFilePathJava = resourcePath.resolve(resourceFilesDirName).resolve(linuxFilenameJava); + Path linuxFilePathJava = RESOURCE_PATH.resolve("__files").resolve(linuxFilenameJava); String linuxLengthJava = String.valueOf(Files.size(linuxFilePathJava)); - setupMockServerResponse("/jmcTest/windows", "application/zip", windowsLengthJmc, windowsFilenameJmc); - setupMockServerResponse("/jmcTest/linux", "application/gz", linuxLengthJmc, linuxFilenameJmc); - setupMockServerResponse("/jmcTest/macOS", "application/gz", maxOSLengthJmc, macOSFilenameJmc); setupMockServerResponse("/installTest/windows", "application/zip", windowsLengthJava, windowsFilenameJava); setupMockServerResponse("/installTest/linux", "application/tgz", linuxLengthJava, linuxFilenameJava); setupMockServerResponse("/installTest/macOS", "application/tgz", linuxLengthJava, linuxFilenameJava); @@ -79,11 +90,11 @@ private void setupMockServerResponse(String testUrl, String contentType, String } @Test - public void jmcPostInstallShouldMoveFilesIfRequired() throws IOException { + public void jmcPostInstallShouldMoveFilesIfRequiredMockedServer() throws IOException { // arrange String path = "workspaces/foo-test/my-git-repo"; - IdeContext context = newContext("basic", path, true); + IdeContext context = newContext("jmc", path, true); InstallCommandlet install = context.getCommandletManager().getCommandlet(InstallCommandlet.class); install.tool.setValueAsString("jmc", context); mockWebServer(); @@ -91,15 +102,91 @@ public void jmcPostInstallShouldMoveFilesIfRequired() throws IOException { install.run(); // assert + performPostInstallAssertion(context); + } + + @Test + public void jmcPostInstallShouldMoveFilesIfRequired() throws IOException { + + // arrange + String path = "workspaces/foo-test/my-git-repo"; + String projectTestCaseName = "jmc"; + + ToolRepositoryMock toolRepositoryMock = buildToolRepositoryMock(projectTestCaseName); + + IdeContext context = newContext(projectTestCaseName, path, true, toolRepositoryMock); + toolRepositoryMock.setContext(context); + + CommandLetExtractorMock commandLetExtractorMock = new CommandLetExtractorMock(context); + Jmc commandlet = new Jmc(context); + commandlet.setCommandletFileExtractor(commandLetExtractorMock); + + // act + commandlet.install(); + + // assert + performPostInstallAssertion(context); + + } + + // run test, currently cannot find correct executeable TODO FIND BINARY BUGGY + @Test + @Disabled + public void jmcShouldRunExecuteableSuccessfully() throws IOException { + + // arrange + String path = "workspaces/foo-test/my-git-repo"; + String projectTestCaseName = "jmc"; + + ToolRepositoryMock toolRepositoryMock = buildToolRepositoryMock(projectTestCaseName); + + IdeContext context = newContext(projectTestCaseName, path, true, toolRepositoryMock); + toolRepositoryMock.setContext(context); + + CommandLetExtractorMock commandLetExtractorMock = new CommandLetExtractorMock(context); + Jmc commandlet = new Jmc(context); + commandlet.setCommandletFileExtractor(commandLetExtractorMock); + + commandlet.install(); + + // act + commandlet.run(); + + // assert, output stream probably + // System.out + + } + + private static ToolRepositoryMock buildToolRepositoryMock(String projectTestCaseName) { + + Map toolToVersion = new HashMap<>(); + toolToVersion.put("jmc", "8.3.0"); + toolToVersion.put("java", "17.0.10_7"); + + String windowsFileFolder = "org.openjdk.jmc-8.3.0-win32.win32.x86_64"; + String linuxFileFolder = "org.openjdk.jmc-8.3.0-linux.gtk.x86_64"; + String macFileFolder = "org.openjdk.jmc-8.3.0-macosx.cocoa.x86_64"; + + ToolRepositoryMock toolRepositoryMock = new ToolRepositoryMock(toolToVersion, projectTestCaseName, + windowsFileFolder, linuxFileFolder, macFileFolder); + return toolRepositoryMock; + } + + private void performPostInstallAssertion(IdeContext context) { + assertThat(context.getSoftwarePath().resolve("jmc")).exists(); assertThat(context.getSoftwarePath().resolve("jmc/InstallTest.txt")).hasContent("This is a test file."); + // Win if (context.getSystemInfo().isWindows()) { assertThat(context.getSoftwarePath().resolve("jmc/jmc.cmd")).exists(); - } else if (context.getSystemInfo().isLinux()) { + } + + if (context.getSystemInfo().isLinux()) { assertThat(context.getSoftwarePath().resolve("jmc/jmc")).exists(); } + // Win linux if (context.getSystemInfo().isWindows() || context.getSystemInfo().isLinux()) { assertThat(context.getSoftwarePath().resolve("jmc/HelloWorld.txt")).hasContent("Hello World!"); assertThat(context.getSoftwarePath().resolve("jmc/JDK Mission Control")).doesNotExist(); @@ -110,6 +197,8 @@ public void jmcPostInstallShouldMoveFilesIfRequired() throws IOException { assertThat(context.getSoftwarePath().resolve("jmc/JDK Mission Control.app/Contents")).exists(); } + assertThat(context.getSoftwarePath().resolve("jmc/.ide.software.version")).exists(); + assertThat(context.getSoftwarePath().resolve("jmc/.ide.software.version")).hasContent("8.3.0"); } } diff --git a/cli/src/test/resources/ide-projects/jmc/_ide/software/default/deleteMeAfterSoftwareAdded.txt b/cli/src/test/resources/ide-projects/jmc/_ide/software/default/deleteMeAfterSoftwareAdded.txt new file mode 100644 index 000000000..e69de29bb diff --git a/cli/src/test/resources/ide-projects/jmc/_ide/software/default/java/java/17.0.10_7/.ide.software.version b/cli/src/test/resources/ide-projects/jmc/_ide/software/default/java/java/17.0.10_7/.ide.software.version new file mode 100644 index 000000000..82da54c37 --- /dev/null +++ b/cli/src/test/resources/ide-projects/jmc/_ide/software/default/java/java/17.0.10_7/.ide.software.version @@ -0,0 +1 @@ +17.0.10_7 diff --git a/cli/src/test/resources/ide-projects/jmc/_ide/software/default/java/java/17.0.10_7/bin/readme b/cli/src/test/resources/ide-projects/jmc/_ide/software/default/java/java/17.0.10_7/bin/readme new file mode 100644 index 000000000..a4d7c09a6 --- /dev/null +++ b/cli/src/test/resources/ide-projects/jmc/_ide/software/default/java/java/17.0.10_7/bin/readme @@ -0,0 +1 @@ +here is the mocked java executeable location \ No newline at end of file diff --git a/cli/src/test/resources/ide-projects/jmc/_ide/software/readme b/cli/src/test/resources/ide-projects/jmc/_ide/software/readme new file mode 100644 index 000000000..c5be1dc4f --- /dev/null +++ b/cli/src/test/resources/ide-projects/jmc/_ide/software/readme @@ -0,0 +1 @@ +this is the tool repository \ No newline at end of file diff --git a/cli/src/test/resources/ide-projects/jmc/_ide/urls/java/java/17.0.6/linux_x64.sha256 b/cli/src/test/resources/ide-projects/jmc/_ide/urls/java/java/17.0.6/linux_x64.sha256 new file mode 100644 index 000000000..438dd2a03 --- /dev/null +++ b/cli/src/test/resources/ide-projects/jmc/_ide/urls/java/java/17.0.6/linux_x64.sha256 @@ -0,0 +1 @@ +c2de7dfbd9f8faaa21b4cdd8518f826dd558c9ab24a0616b3ed28437a674a97b \ No newline at end of file diff --git a/cli/src/test/resources/ide-projects/jmc/_ide/urls/java/java/17.0.6/linux_x64.urls b/cli/src/test/resources/ide-projects/jmc/_ide/urls/java/java/17.0.6/linux_x64.urls new file mode 100644 index 000000000..11266bb8a --- /dev/null +++ b/cli/src/test/resources/ide-projects/jmc/_ide/urls/java/java/17.0.6/linux_x64.urls @@ -0,0 +1 @@ +http://localhost:1112/installTest/linux \ No newline at end of file diff --git a/cli/src/test/resources/ide-projects/jmc/_ide/urls/java/java/17.0.6/mac_x64.sha256 b/cli/src/test/resources/ide-projects/jmc/_ide/urls/java/java/17.0.6/mac_x64.sha256 new file mode 100644 index 000000000..438dd2a03 --- /dev/null +++ b/cli/src/test/resources/ide-projects/jmc/_ide/urls/java/java/17.0.6/mac_x64.sha256 @@ -0,0 +1 @@ +c2de7dfbd9f8faaa21b4cdd8518f826dd558c9ab24a0616b3ed28437a674a97b \ No newline at end of file diff --git a/cli/src/test/resources/ide-projects/jmc/_ide/urls/java/java/17.0.6/mac_x64.urls b/cli/src/test/resources/ide-projects/jmc/_ide/urls/java/java/17.0.6/mac_x64.urls new file mode 100644 index 000000000..2d8af8437 --- /dev/null +++ b/cli/src/test/resources/ide-projects/jmc/_ide/urls/java/java/17.0.6/mac_x64.urls @@ -0,0 +1 @@ +http://localhost:1112/installTest/macOS \ No newline at end of file diff --git a/cli/src/test/resources/ide-projects/basic/_ide/urls/jmc/jmc/8.3.0/status.json b/cli/src/test/resources/ide-projects/jmc/_ide/urls/java/java/17.0.6/status.json similarity index 100% rename from cli/src/test/resources/ide-projects/basic/_ide/urls/jmc/jmc/8.3.0/status.json rename to cli/src/test/resources/ide-projects/jmc/_ide/urls/java/java/17.0.6/status.json diff --git a/cli/src/test/resources/ide-projects/jmc/_ide/urls/java/java/17.0.6/windows_x64.urls b/cli/src/test/resources/ide-projects/jmc/_ide/urls/java/java/17.0.6/windows_x64.urls new file mode 100644 index 000000000..79fd6654e --- /dev/null +++ b/cli/src/test/resources/ide-projects/jmc/_ide/urls/java/java/17.0.6/windows_x64.urls @@ -0,0 +1 @@ +http://localhost:1112/installTest/windows \ No newline at end of file diff --git a/cli/src/test/resources/ide-projects/jmc/_ide/urls/java/java/17.0.6/windows_x64.urls.sha256 b/cli/src/test/resources/ide-projects/jmc/_ide/urls/java/java/17.0.6/windows_x64.urls.sha256 new file mode 100644 index 000000000..fe3cecaad --- /dev/null +++ b/cli/src/test/resources/ide-projects/jmc/_ide/urls/java/java/17.0.6/windows_x64.urls.sha256 @@ -0,0 +1 @@ +aa64bee5f7ba56fbbd60d766f3a652600f81571ae5e996804694c69bf731af8b \ No newline at end of file diff --git a/cli/src/test/resources/ide-projects/basic/_ide/urls/jmc/jmc/8.3.0/linux_x64.sha256 b/cli/src/test/resources/ide-projects/jmc/_ide/urls/jmc/jmc/8.3.0/linux_x64.sha256 similarity index 100% rename from cli/src/test/resources/ide-projects/basic/_ide/urls/jmc/jmc/8.3.0/linux_x64.sha256 rename to cli/src/test/resources/ide-projects/jmc/_ide/urls/jmc/jmc/8.3.0/linux_x64.sha256 diff --git a/cli/src/test/resources/ide-projects/basic/_ide/urls/jmc/jmc/8.3.0/linux_x64.urls b/cli/src/test/resources/ide-projects/jmc/_ide/urls/jmc/jmc/8.3.0/linux_x64.urls similarity index 100% rename from cli/src/test/resources/ide-projects/basic/_ide/urls/jmc/jmc/8.3.0/linux_x64.urls rename to cli/src/test/resources/ide-projects/jmc/_ide/urls/jmc/jmc/8.3.0/linux_x64.urls diff --git a/cli/src/test/resources/ide-projects/basic/_ide/urls/jmc/jmc/8.3.0/mac_x64.sha256 b/cli/src/test/resources/ide-projects/jmc/_ide/urls/jmc/jmc/8.3.0/mac_x64.sha256 similarity index 100% rename from cli/src/test/resources/ide-projects/basic/_ide/urls/jmc/jmc/8.3.0/mac_x64.sha256 rename to cli/src/test/resources/ide-projects/jmc/_ide/urls/jmc/jmc/8.3.0/mac_x64.sha256 diff --git a/cli/src/test/resources/ide-projects/basic/_ide/urls/jmc/jmc/8.3.0/mac_x64.urls b/cli/src/test/resources/ide-projects/jmc/_ide/urls/jmc/jmc/8.3.0/mac_x64.urls similarity index 100% rename from cli/src/test/resources/ide-projects/basic/_ide/urls/jmc/jmc/8.3.0/mac_x64.urls rename to cli/src/test/resources/ide-projects/jmc/_ide/urls/jmc/jmc/8.3.0/mac_x64.urls diff --git a/cli/src/test/resources/ide-projects/jmc/_ide/urls/jmc/jmc/8.3.0/status.json b/cli/src/test/resources/ide-projects/jmc/_ide/urls/jmc/jmc/8.3.0/status.json new file mode 100644 index 000000000..b58452d90 --- /dev/null +++ b/cli/src/test/resources/ide-projects/jmc/_ide/urls/jmc/jmc/8.3.0/status.json @@ -0,0 +1,20 @@ +{ + "manual" : true, + "urls" : { + "-680270697" : { + "success" : { + "timestamp" : "2023-04-28T16:27:32.819394600Z" + } + }, + "-896197542" : { + "success" : { + "timestamp" : "2023-04-28T16:27:47.658175400Z" + } + }, + "-310367019" : { + "success" : { + "timestamp" : "2023-04-28T16:28:02.221367500Z" + } + } + } +} \ No newline at end of file diff --git a/cli/src/test/resources/ide-projects/basic/_ide/urls/jmc/jmc/8.3.0/windows_x64.urls b/cli/src/test/resources/ide-projects/jmc/_ide/urls/jmc/jmc/8.3.0/windows_x64.urls similarity index 100% rename from cli/src/test/resources/ide-projects/basic/_ide/urls/jmc/jmc/8.3.0/windows_x64.urls rename to cli/src/test/resources/ide-projects/jmc/_ide/urls/jmc/jmc/8.3.0/windows_x64.urls diff --git a/cli/src/test/resources/ide-projects/basic/_ide/urls/jmc/jmc/8.3.0/windows_x64.urls.sha256 b/cli/src/test/resources/ide-projects/jmc/_ide/urls/jmc/jmc/8.3.0/windows_x64.urls.sha256 similarity index 100% rename from cli/src/test/resources/ide-projects/basic/_ide/urls/jmc/jmc/8.3.0/windows_x64.urls.sha256 rename to cli/src/test/resources/ide-projects/jmc/_ide/urls/jmc/jmc/8.3.0/windows_x64.urls.sha256 diff --git a/cli/src/test/resources/ide-projects/jmc/_ide/urls/readme b/cli/src/test/resources/ide-projects/jmc/_ide/urls/readme new file mode 100644 index 000000000..befcdfa75 --- /dev/null +++ b/cli/src/test/resources/ide-projects/jmc/_ide/urls/readme @@ -0,0 +1 @@ +this is the download metadata \ No newline at end of file diff --git a/cli/src/test/resources/ide-projects/jmc/downloadMockLocation/org.openjdk.jmc-8.3.0-linux.gtk.x86_64/InstallTest.txt b/cli/src/test/resources/ide-projects/jmc/downloadMockLocation/org.openjdk.jmc-8.3.0-linux.gtk.x86_64/InstallTest.txt new file mode 100644 index 000000000..6de7b8c69 --- /dev/null +++ b/cli/src/test/resources/ide-projects/jmc/downloadMockLocation/org.openjdk.jmc-8.3.0-linux.gtk.x86_64/InstallTest.txt @@ -0,0 +1 @@ +This is a test file. diff --git a/cli/src/test/resources/ide-projects/jmc/downloadMockLocation/org.openjdk.jmc-8.3.0-linux.gtk.x86_64/JDK Mission Control/HelloWorld.txt b/cli/src/test/resources/ide-projects/jmc/downloadMockLocation/org.openjdk.jmc-8.3.0-linux.gtk.x86_64/JDK Mission Control/HelloWorld.txt new file mode 100644 index 000000000..980a0d5f1 --- /dev/null +++ b/cli/src/test/resources/ide-projects/jmc/downloadMockLocation/org.openjdk.jmc-8.3.0-linux.gtk.x86_64/JDK Mission Control/HelloWorld.txt @@ -0,0 +1 @@ +Hello World! diff --git a/cli/src/test/resources/ide-projects/jmc/downloadMockLocation/org.openjdk.jmc-8.3.0-linux.gtk.x86_64/JDK Mission Control/jmc b/cli/src/test/resources/ide-projects/jmc/downloadMockLocation/org.openjdk.jmc-8.3.0-linux.gtk.x86_64/JDK Mission Control/jmc new file mode 100644 index 000000000..07b255f6a --- /dev/null +++ b/cli/src/test/resources/ide-projects/jmc/downloadMockLocation/org.openjdk.jmc-8.3.0-linux.gtk.x86_64/JDK Mission Control/jmc @@ -0,0 +1 @@ +echo "Dummy jmc 8.3.0 on linux/macOs" \ No newline at end of file diff --git a/cli/src/test/resources/ide-projects/jmc/downloadMockLocation/org.openjdk.jmc-8.3.0-macosx.cocoa.x86_64/InstallTest.txt b/cli/src/test/resources/ide-projects/jmc/downloadMockLocation/org.openjdk.jmc-8.3.0-macosx.cocoa.x86_64/InstallTest.txt new file mode 100644 index 000000000..6de7b8c69 --- /dev/null +++ b/cli/src/test/resources/ide-projects/jmc/downloadMockLocation/org.openjdk.jmc-8.3.0-macosx.cocoa.x86_64/InstallTest.txt @@ -0,0 +1 @@ +This is a test file. diff --git a/cli/src/test/resources/ide-projects/jmc/downloadMockLocation/org.openjdk.jmc-8.3.0-win32.win32.x86_64/InstallTest.txt b/cli/src/test/resources/ide-projects/jmc/downloadMockLocation/org.openjdk.jmc-8.3.0-win32.win32.x86_64/InstallTest.txt new file mode 100644 index 000000000..6de7b8c69 --- /dev/null +++ b/cli/src/test/resources/ide-projects/jmc/downloadMockLocation/org.openjdk.jmc-8.3.0-win32.win32.x86_64/InstallTest.txt @@ -0,0 +1 @@ +This is a test file. diff --git a/cli/src/test/resources/ide-projects/jmc/downloadMockLocation/org.openjdk.jmc-8.3.0-win32.win32.x86_64/JDK Mission Control/HelloWorld.txt b/cli/src/test/resources/ide-projects/jmc/downloadMockLocation/org.openjdk.jmc-8.3.0-win32.win32.x86_64/JDK Mission Control/HelloWorld.txt new file mode 100644 index 000000000..980a0d5f1 --- /dev/null +++ b/cli/src/test/resources/ide-projects/jmc/downloadMockLocation/org.openjdk.jmc-8.3.0-win32.win32.x86_64/JDK Mission Control/HelloWorld.txt @@ -0,0 +1 @@ +Hello World! diff --git a/cli/src/test/resources/ide-projects/jmc/downloadMockLocation/org.openjdk.jmc-8.3.0-win32.win32.x86_64/JDK Mission Control/jmc.cmd b/cli/src/test/resources/ide-projects/jmc/downloadMockLocation/org.openjdk.jmc-8.3.0-win32.win32.x86_64/JDK Mission Control/jmc.cmd new file mode 100644 index 000000000..1ad2214fe --- /dev/null +++ b/cli/src/test/resources/ide-projects/jmc/downloadMockLocation/org.openjdk.jmc-8.3.0-win32.win32.x86_64/JDK Mission Control/jmc.cmd @@ -0,0 +1 @@ +echo "Dummy jmc 8.3.0 on windows" \ No newline at end of file diff --git a/cli/src/test/resources/ide-projects/jmc/downloadMockLocation/readme b/cli/src/test/resources/ide-projects/jmc/downloadMockLocation/readme new file mode 100644 index 000000000..9d835d54c --- /dev/null +++ b/cli/src/test/resources/ide-projects/jmc/downloadMockLocation/readme @@ -0,0 +1 @@ +this locations equals the download location of a commandlet \ No newline at end of file diff --git a/cli/src/test/resources/ide-projects/jmc/project/conf/ide.properties b/cli/src/test/resources/ide-projects/jmc/project/conf/ide.properties new file mode 100644 index 000000000..224a2cf25 --- /dev/null +++ b/cli/src/test/resources/ide-projects/jmc/project/conf/ide.properties @@ -0,0 +1,16 @@ +#******************************************************************************** +# This file contains project specific environment variables defined by the user +#******************************************************************************** + +M2_REPO=~/.m2/repository + +SOME=some-${UNDEFINED} + +TEST_ARGS1=${TEST_ARGS1} conf1 +TEST_ARGS2=${TEST_ARGS2} conf2 +TEST_ARGS5=${TEST_ARGS5} conf5 +TEST_ARGS6=${TEST_ARGS6} conf6 +TEST_ARGS7=${TEST_ARGS7} conf7 +TEST_ARGS8=${TEST_ARGS8} conf8 +TEST_ARGSa=${TEST_ARGS1} ${TEST_ARGS3} confa +TEST_ARGSc=${TEST_ARGSc} confc \ No newline at end of file diff --git a/cli/src/test/resources/ide-projects/jmc/project/home/.ide/ide.properties b/cli/src/test/resources/ide-projects/jmc/project/home/.ide/ide.properties new file mode 100644 index 000000000..ec0c3e7f6 --- /dev/null +++ b/cli/src/test/resources/ide-projects/jmc/project/home/.ide/ide.properties @@ -0,0 +1,15 @@ +#******************************************************************************** +# This file contains the global configuration from the user HOME directory. +#******************************************************************************** + +DOCKER_EDITION=docker +FOO=foo-${BAR} + +TEST_ARGS1=${TEST_ARGS1} user1 +TEST_ARGS2=${TEST_ARGS2} user2 +TEST_ARGS3=${TEST_ARGS3} user3 +TEST_ARGS7=user7 +TEST_ARGS10=user10 +TEST_ARGSb=userb +TEST_ARGSc=${TEST_ARGS1} userc +TEST_ARGSd=${TEST_ARGS1} userd \ No newline at end of file diff --git a/cli/src/test/resources/ide-projects/jmc/project/home/.ide/settings/eclipse/plugins/anyedit.properties b/cli/src/test/resources/ide-projects/jmc/project/home/.ide/settings/eclipse/plugins/anyedit.properties new file mode 100644 index 000000000..eb298f3bb --- /dev/null +++ b/cli/src/test/resources/ide-projects/jmc/project/home/.ide/settings/eclipse/plugins/anyedit.properties @@ -0,0 +1,3 @@ +plugin_url=https://raw.githubusercontent.com/iloveeclipse/plugins/latest/ +plugin_id=AnyEditTools.feature.group +plugin_active=false diff --git a/cli/src/test/resources/ide-projects/jmc/project/home/Downloads/ide/readme b/cli/src/test/resources/ide-projects/jmc/project/home/Downloads/ide/readme new file mode 100644 index 000000000..f0dc29025 --- /dev/null +++ b/cli/src/test/resources/ide-projects/jmc/project/home/Downloads/ide/readme @@ -0,0 +1 @@ +this is the download cache \ No newline at end of file diff --git a/cli/src/test/resources/ide-projects/jmc/project/home/readme b/cli/src/test/resources/ide-projects/jmc/project/home/readme new file mode 100644 index 000000000..5e8bc178c --- /dev/null +++ b/cli/src/test/resources/ide-projects/jmc/project/home/readme @@ -0,0 +1 @@ +this is the users HOME directory \ No newline at end of file diff --git a/cli/src/test/resources/ide-projects/jmc/project/readme b/cli/src/test/resources/ide-projects/jmc/project/readme new file mode 100644 index 000000000..256f5732c --- /dev/null +++ b/cli/src/test/resources/ide-projects/jmc/project/readme @@ -0,0 +1 @@ +this is the IDE_HOME directory \ No newline at end of file diff --git a/cli/src/test/resources/ide-projects/jmc/project/scripts/ide b/cli/src/test/resources/ide-projects/jmc/project/scripts/ide new file mode 100644 index 000000000..b0c2d7872 --- /dev/null +++ b/cli/src/test/resources/ide-projects/jmc/project/scripts/ide @@ -0,0 +1 @@ +the IDE CLI bash script \ No newline at end of file diff --git a/cli/src/test/resources/ide-projects/jmc/project/settings/eclipse/plugins/anyedit.properties b/cli/src/test/resources/ide-projects/jmc/project/settings/eclipse/plugins/anyedit.properties new file mode 100644 index 000000000..09a94b116 --- /dev/null +++ b/cli/src/test/resources/ide-projects/jmc/project/settings/eclipse/plugins/anyedit.properties @@ -0,0 +1,3 @@ +plugin_url=https://raw.githubusercontent.com/iloveeclipse/plugins/latest/ +plugin_id=AnyEditTools.feature.group +plugin_active=true diff --git a/cli/src/test/resources/ide-projects/jmc/project/settings/eclipse/plugins/checkstyle.properties b/cli/src/test/resources/ide-projects/jmc/project/settings/eclipse/plugins/checkstyle.properties new file mode 100644 index 000000000..6e402c7c5 --- /dev/null +++ b/cli/src/test/resources/ide-projects/jmc/project/settings/eclipse/plugins/checkstyle.properties @@ -0,0 +1,3 @@ +plugin_url=https://checkstyle.org/eclipse-cs-update-site +plugin_id=net.sf.eclipsecs.feature.group +plugin_active=true diff --git a/cli/src/test/resources/ide-projects/jmc/project/settings/ide.properties b/cli/src/test/resources/ide-projects/jmc/project/settings/ide.properties new file mode 100644 index 000000000..c80f1e604 --- /dev/null +++ b/cli/src/test/resources/ide-projects/jmc/project/settings/ide.properties @@ -0,0 +1,22 @@ +#******************************************************************************** +# This file contains project specific environment variables +#******************************************************************************** + +JAVA_VERSION=17* +MVN_VERSION=3.9.* +ECLIPSE_VERSION=2023-03 +INTELLIJ_EDITION=ultimate + +IDE_TOOLS=mvn,eclipse + +BAR=bar-${SOME} + +TEST_ARGS1=${TEST_ARGS1} settings1 +TEST_ARGS4=${TEST_ARGS4} settings4 +TEST_ARGS5=${TEST_ARGS5} settings5 +TEST_ARGS6=${TEST_ARGS6} settings6 +TEST_ARGS7=${TEST_ARGS7} settings7 +TEST_ARGS8=settings8 +TEST_ARGS9=settings9 +TEST_ARGSb=${TEST_ARGS10} settingsb ${TEST_ARGSa} ${TEST_ARGSb} +TEST_ARGSc=${TEST_ARGSc} settingsc \ No newline at end of file diff --git a/cli/src/test/resources/ide-projects/jmc/project/setup b/cli/src/test/resources/ide-projects/jmc/project/setup new file mode 100644 index 000000000..9c5d4b1be --- /dev/null +++ b/cli/src/test/resources/ide-projects/jmc/project/setup @@ -0,0 +1 @@ +just a marker for detection of IDE_HOME \ No newline at end of file diff --git a/cli/src/test/resources/ide-projects/jmc/project/software/java/.ide.software.version b/cli/src/test/resources/ide-projects/jmc/project/software/java/.ide.software.version new file mode 100644 index 000000000..82da54c37 --- /dev/null +++ b/cli/src/test/resources/ide-projects/jmc/project/software/java/.ide.software.version @@ -0,0 +1 @@ +17.0.10_7 diff --git a/cli/src/test/resources/ide-projects/jmc/project/software/java/bin/readme b/cli/src/test/resources/ide-projects/jmc/project/software/java/bin/readme new file mode 100644 index 000000000..a4d7c09a6 --- /dev/null +++ b/cli/src/test/resources/ide-projects/jmc/project/software/java/bin/readme @@ -0,0 +1 @@ +here is the mocked java executeable location \ No newline at end of file diff --git a/cli/src/test/resources/ide-projects/jmc/project/workspaces/foo-test/ide.properties b/cli/src/test/resources/ide-projects/jmc/project/workspaces/foo-test/ide.properties new file mode 100644 index 000000000..fefd6bede --- /dev/null +++ b/cli/src/test/resources/ide-projects/jmc/project/workspaces/foo-test/ide.properties @@ -0,0 +1,12 @@ +#******************************************************************************** +# Type of {@link EnvironmentVariables} from the +# {@link com.devonfw.tools.ide.context.IdeContext#getWorkspacePath() workspace directory}. +#******************************************************************************** +TEST_ARGS1=${TEST_ARGS1} workspace1 +TEST_ARGS3=${TEST_ARGS3} workspace3 +TEST_ARGS6=${TEST_ARGS6} workspace6 +TEST_ARGS7=${TEST_ARGS7} workspace7 +TEST_ARGS8=${TEST_ARGS8} workspace8 +TEST_ARGS9=${TEST_ARGS9} workspace9 +TEST_ARGS10=${TEST_ARGS10} workspace10 +TEST_ARGSd=${TEST_ARGSd} workspaced \ No newline at end of file diff --git a/cli/src/test/resources/ide-projects/jmc/project/workspaces/foo-test/my-git-repo/readme b/cli/src/test/resources/ide-projects/jmc/project/workspaces/foo-test/my-git-repo/readme new file mode 100644 index 000000000..7cf8ec575 --- /dev/null +++ b/cli/src/test/resources/ide-projects/jmc/project/workspaces/foo-test/my-git-repo/readme @@ -0,0 +1 @@ +my-git-repo in foo-test workspace of basic \ No newline at end of file diff --git a/cli/src/test/resources/ide-projects/jmc/project/workspaces/foo-test/readme b/cli/src/test/resources/ide-projects/jmc/project/workspaces/foo-test/readme new file mode 100644 index 000000000..948f8cfea --- /dev/null +++ b/cli/src/test/resources/ide-projects/jmc/project/workspaces/foo-test/readme @@ -0,0 +1 @@ +this is the foo-test workspace of basic \ No newline at end of file diff --git a/cli/src/test/resources/ide-projects/jmc/project/workspaces/main/readme b/cli/src/test/resources/ide-projects/jmc/project/workspaces/main/readme new file mode 100644 index 000000000..7146c2ad6 --- /dev/null +++ b/cli/src/test/resources/ide-projects/jmc/project/workspaces/main/readme @@ -0,0 +1 @@ +this is the main workspace of basic \ No newline at end of file diff --git a/cli/src/test/resources/ide-projects/jmc/readme b/cli/src/test/resources/ide-projects/jmc/readme new file mode 100644 index 000000000..15b91829e --- /dev/null +++ b/cli/src/test/resources/ide-projects/jmc/readme @@ -0,0 +1 @@ +this is the IDE_ROOT directory \ No newline at end of file From 9e2b83604011b0c7cbcaace0a686896baa7d485d Mon Sep 17 00:00:00 2001 From: Ouchen Date: Fri, 23 Feb 2024 08:17:30 +0100 Subject: [PATCH 02/18] Add javadoc --- .../java/com/devonfw/tools/ide/tool/ToolCommandlet.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java index 8a31520ca..fce98691e 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java @@ -53,7 +53,6 @@ public ToolCommandlet(IdeContext context, String tool, Set tags) { addKeyword(tool); this.arguments = add(new StringListProperty("", false, "args")); - // TODO MAKE THIS SETTABLE commandletFileExtractor = new CommandletFileExtractorImpl(context, this); } @@ -408,6 +407,11 @@ public void setEdition(String edition, boolean hint) { } } + /** + * Sets the {@link CommandletFileExtractor} of the commandlet. + * + * @param commandletFileExtractor + */ public void setCommandletFileExtractor(CommandletFileExtractor commandletFileExtractor) { this.commandletFileExtractor = commandletFileExtractor; From ce0437f9e412addf865c280567bc5903025086e6 Mon Sep 17 00:00:00 2001 From: Ouchen Date: Fri, 23 Feb 2024 08:17:30 +0100 Subject: [PATCH 03/18] Add javadoc --- .../java/com/devonfw/tools/ide/tool/ToolCommandlet.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java index 8a31520ca..571dc4366 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java @@ -53,7 +53,6 @@ public ToolCommandlet(IdeContext context, String tool, Set tags) { addKeyword(tool); this.arguments = add(new StringListProperty("", false, "args")); - // TODO MAKE THIS SETTABLE commandletFileExtractor = new CommandletFileExtractorImpl(context, this); } @@ -408,6 +407,11 @@ public void setEdition(String edition, boolean hint) { } } + /** + * Sets the {@link CommandletFileExtractor} of the commandlet. + * + * @param commandletFileExtractor an implementation of {@link CommandletFileExtractor} + */ public void setCommandletFileExtractor(CommandletFileExtractor commandletFileExtractor) { this.commandletFileExtractor = commandletFileExtractor; From b698aa8154ad485f33a21afb3e8b18cca31c484e Mon Sep 17 00:00:00 2001 From: Ouchen Date: Fri, 23 Feb 2024 08:42:07 +0100 Subject: [PATCH 04/18] Using target path instead of ressource path to make sure one-to-one copy of set up folders is used --- .../java/com/devonfw/tools/ide/repo/ToolRepositoryMock.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cli/src/test/java/com/devonfw/tools/ide/repo/ToolRepositoryMock.java b/cli/src/test/java/com/devonfw/tools/ide/repo/ToolRepositoryMock.java index 80e095cb3..8c8497a63 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/repo/ToolRepositoryMock.java +++ b/cli/src/test/java/com/devonfw/tools/ide/repo/ToolRepositoryMock.java @@ -11,7 +11,7 @@ */ public class ToolRepositoryMock implements ToolRepository { - private static final Path PROJECTS_RESOURCE_PATH = Path.of("src/test/resources/ide-projects"); + private static final Path PROJECTS_TARGET_PATH = Path.of("target/test-projects"); private static final String MOCK_DOWNLOAD_FOLDERNAME = "downloadMockLocation"; @@ -32,7 +32,7 @@ public class ToolRepositoryMock implements ToolRepository { * * @param toolToVersion Mapping of which Version of a tool should be mocked * @param projectTestCaseName the (folder)name of the project test case, in this folder a 'project' folder represents - * the test project in {@link #PROJECTS_RESOURCE_PATH}. E.g. "basic". + * the test project in {@link #PROJECTS_TARGET_PATH}. E.g. "basic". * @param windowsFolderName Name of the folder which is used when test is run under Windows * @param linuxFolderName Name of the folder which is used when test is run under Linux * @param macFolderName Name of the folder which is used when test is run under Mac OS @@ -68,7 +68,7 @@ public VersionIdentifier resolveVersion(String tool, String edition, VersionIden @Override public Path download(String tool, String edition, VersionIdentifier version) { - Path baseDownloadMockPath = PROJECTS_RESOURCE_PATH.resolve(projectTestCaseName).resolve(MOCK_DOWNLOAD_FOLDERNAME); + Path baseDownloadMockPath = PROJECTS_TARGET_PATH.resolve(projectTestCaseName).resolve(MOCK_DOWNLOAD_FOLDERNAME); String mockProgram = ""; if (context == null) { From c2497dfe674f358fed25415afdf3d294d86b1082 Mon Sep 17 00:00:00 2001 From: Ouchen Date: Fri, 23 Feb 2024 15:04:31 +0100 Subject: [PATCH 05/18] Add JavaDoc and mac mock program --- .../ide/commandlet/CommandletFileExtractorImpl.java | 9 +++++++-- .../JDK Mission Control.app/Contents/jmc | 1 + .../legal/legal.txt | 1 + 3 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 cli/src/test/resources/ide-projects/jmc/downloadMockLocation/org.openjdk.jmc-8.3.0-macosx.cocoa.x86_64/JDK Mission Control.app/Contents/jmc create mode 100644 cli/src/test/resources/ide-projects/jmc/downloadMockLocation/org.openjdk.jmc-8.3.0-macosx.cocoa.x86_64/legal/legal.txt diff --git a/cli/src/main/java/com/devonfw/tools/ide/commandlet/CommandletFileExtractorImpl.java b/cli/src/main/java/com/devonfw/tools/ide/commandlet/CommandletFileExtractorImpl.java index e27f5994c..76a271aed 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/commandlet/CommandletFileExtractorImpl.java +++ b/cli/src/main/java/com/devonfw/tools/ide/commandlet/CommandletFileExtractorImpl.java @@ -22,6 +22,12 @@ public class CommandletFileExtractorImpl implements CommandletFileExtractor { protected final ToolCommandlet commandlet; + /** + * The constructor + * + * @param context the {@link IdeContext}. + * @param commandlet the {@link ToolCommandlet} + */ public CommandletFileExtractorImpl(IdeContext context, ToolCommandlet commandlet) { this.context = context; @@ -124,5 +130,4 @@ private Path getProperInstallationSubDirOf(Path path) { throw new IllegalStateException("Failed to get sub-files of " + path); } } - -} +} \ No newline at end of file diff --git a/cli/src/test/resources/ide-projects/jmc/downloadMockLocation/org.openjdk.jmc-8.3.0-macosx.cocoa.x86_64/JDK Mission Control.app/Contents/jmc b/cli/src/test/resources/ide-projects/jmc/downloadMockLocation/org.openjdk.jmc-8.3.0-macosx.cocoa.x86_64/JDK Mission Control.app/Contents/jmc new file mode 100644 index 000000000..e4af7cc05 --- /dev/null +++ b/cli/src/test/resources/ide-projects/jmc/downloadMockLocation/org.openjdk.jmc-8.3.0-macosx.cocoa.x86_64/JDK Mission Control.app/Contents/jmc @@ -0,0 +1 @@ +echo "Dummy jmc 8.3.0 on macOs" \ No newline at end of file diff --git a/cli/src/test/resources/ide-projects/jmc/downloadMockLocation/org.openjdk.jmc-8.3.0-macosx.cocoa.x86_64/legal/legal.txt b/cli/src/test/resources/ide-projects/jmc/downloadMockLocation/org.openjdk.jmc-8.3.0-macosx.cocoa.x86_64/legal/legal.txt new file mode 100644 index 000000000..6308c936c --- /dev/null +++ b/cli/src/test/resources/ide-projects/jmc/downloadMockLocation/org.openjdk.jmc-8.3.0-macosx.cocoa.x86_64/legal/legal.txt @@ -0,0 +1 @@ +legal \ No newline at end of file From a4ccac019491df53915a17090a7e1a0fc957decf Mon Sep 17 00:00:00 2001 From: Ouchen Date: Fri, 23 Feb 2024 15:06:05 +0100 Subject: [PATCH 06/18] Add support for multiple dependencies while testing --- .../commandlet/CommandLetExtractorMock.java | 2 +- .../ide/context/AbstractIdeTestContext.java | 4 +- .../tools/ide/repo/ToolRepositoryMock.java | 74 ++++++++++++++----- .../devonfw/tools/ide/tool/jmc/JmcTest.java | 38 ++++++---- 4 files changed, 84 insertions(+), 34 deletions(-) diff --git a/cli/src/test/java/com/devonfw/tools/ide/commandlet/CommandLetExtractorMock.java b/cli/src/test/java/com/devonfw/tools/ide/commandlet/CommandLetExtractorMock.java index 4b6fc9212..da36ad249 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/commandlet/CommandLetExtractorMock.java +++ b/cli/src/test/java/com/devonfw/tools/ide/commandlet/CommandLetExtractorMock.java @@ -40,7 +40,7 @@ public void extract(Path file, Path targetDir, boolean isExtract) { } } else { - throw new IllegalStateException("Testing mocks only supports moving folders to install location!"); + throw new IllegalStateException("Testing mocks only supports copying folders to install location!"); } } diff --git a/cli/src/test/java/com/devonfw/tools/ide/context/AbstractIdeTestContext.java b/cli/src/test/java/com/devonfw/tools/ide/context/AbstractIdeTestContext.java index ebf3f769c..36747a01b 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/context/AbstractIdeTestContext.java +++ b/cli/src/test/java/com/devonfw/tools/ide/context/AbstractIdeTestContext.java @@ -9,6 +9,7 @@ import com.devonfw.tools.ide.io.IdeProgressBarTestImpl; import com.devonfw.tools.ide.log.IdeLogLevel; import com.devonfw.tools.ide.log.IdeSubLogger; +import com.devonfw.tools.ide.repo.DefaultToolRepository; import com.devonfw.tools.ide.repo.ToolRepository; /** @@ -27,7 +28,8 @@ public class AbstractIdeTestContext extends AbstractIdeContext { * * @param factory the {@link Function} to create {@link IdeSubLogger} per {@link IdeLogLevel}. * @param userDir the optional {@link Path} to current working directory. - * @param toolRepository @param toolRepository the {@link ToolRepository} of the context. + * @param toolRepository @param toolRepository the {@link ToolRepository} of the context. If it is set to {@code null} + * {@link DefaultToolRepository} will be used. * @param answers the automatic answers simulating a user in test. */ public AbstractIdeTestContext(Function factory, Path userDir, diff --git a/cli/src/test/java/com/devonfw/tools/ide/repo/ToolRepositoryMock.java b/cli/src/test/java/com/devonfw/tools/ide/repo/ToolRepositoryMock.java index 8c8497a63..e67775419 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/repo/ToolRepositoryMock.java +++ b/cli/src/test/java/com/devonfw/tools/ide/repo/ToolRepositoryMock.java @@ -1,6 +1,7 @@ package com.devonfw.tools.ide.repo; import java.nio.file.Path; +import java.util.HashMap; import java.util.Map; import com.devonfw.tools.ide.context.IdeContext; @@ -13,38 +14,40 @@ public class ToolRepositoryMock implements ToolRepository { private static final Path PROJECTS_TARGET_PATH = Path.of("target/test-projects"); - private static final String MOCK_DOWNLOAD_FOLDERNAME = "downloadMockLocation"; - - private final Map toolToVersion; + private static final String MOCK_DOWNLOAD_FOLDER = "downloadMockLocation"; private final String projectTestCaseName; - private final String windowsFolderName; + private IdeContext context; - private final String linuxFolderName; + // Save data of multiple tools to provide different faking for different tools + private final Map toolToToolData; - private final String macFolderName; + private record ToolDataForMock(String version, String windowsFolderName, String linuxFolderName, + String macFolderName) { + } - private IdeContext context; + ; /** - * Constructor of a ToolRepository Mock + * Constructor of a ToolRepository Mock with information of an initial tool * - * @param toolToVersion Mapping of which Version of a tool should be mocked + * @param tool The name of the main tool which is under test. * @param projectTestCaseName the (folder)name of the project test case, in this folder a 'project' folder represents - * the test project in {@link #PROJECTS_TARGET_PATH}. E.g. "basic". + * the test project in {@link #PROJECTS_TARGET_PATH}. E.g. "basic". * @param windowsFolderName Name of the folder which is used when test is run under Windows * @param linuxFolderName Name of the folder which is used when test is run under Linux * @param macFolderName Name of the folder which is used when test is run under Mac OS */ - public ToolRepositoryMock(Map toolToVersion, String projectTestCaseName, String windowsFolderName, + public ToolRepositoryMock(String tool, String toolVersion, String projectTestCaseName, String windowsFolderName, String linuxFolderName, String macFolderName) { - this.toolToVersion = toolToVersion; + toolToToolData = new HashMap<>(); + this.projectTestCaseName = projectTestCaseName; - this.windowsFolderName = windowsFolderName; - this.linuxFolderName = linuxFolderName; - this.macFolderName = macFolderName; + ToolDataForMock toolData = new ToolDataForMock(toolVersion, windowsFolderName, linuxFolderName, macFolderName); + toolToToolData.put(tool, toolData); + } public void setContext(IdeContext context) { @@ -53,6 +56,36 @@ public void setContext(IdeContext context) { } + /** + * Under the assumption that a tool is already installed (a .ide.software.version does exist in the path + * ..._ide/software/default/YOUR_TOOL/YOUR_TOOL/toolVersion). this method is used to configure that the correct + * version of the tool (the one in .ide.software.version) is used. + * + * @param tool The name of the tool. + * @param toolVersion The version of the tool. + */ + public void addAlreadyInstalledTool(String tool, String toolVersion) { + + addToolToInstall(tool, toolVersion, null, null, null); + } + + /** + * Method to add required information in order to mock out the tool installation. Please make sure that an + * installation folder does exist. + * + * @param tool The name of the tool. + * @param toolVersion The version of the tool. + * @param windowsFolderName Name of the folder which is used when test is run under Windows + * @param linuxFolderName Name of the folder which is used when test is run under Linux + * @param macFolderName Name of the folder which is used when test is run under Mac OS + */ + public void addToolToInstall(String tool, String toolVersion, String windowsFolderName, String linuxFolderName, + String macFolderName) { + + ToolDataForMock toolData = new ToolDataForMock(toolVersion, windowsFolderName, linuxFolderName, macFolderName); + toolToToolData.put(tool, toolData); + } + @Override public String getId() { @@ -62,20 +95,25 @@ public String getId() { @Override public VersionIdentifier resolveVersion(String tool, String edition, VersionIdentifier version) { - return VersionIdentifier.of(toolToVersion.get(tool)); + ToolDataForMock toolData = toolToToolData.get(tool); + return VersionIdentifier.of(toolData.version); } @Override public Path download(String tool, String edition, VersionIdentifier version) { - Path baseDownloadMockPath = PROJECTS_TARGET_PATH.resolve(projectTestCaseName).resolve(MOCK_DOWNLOAD_FOLDERNAME); + ToolDataForMock toolData = toolToToolData.get(tool); + String windowsFolderName = toolData.windowsFolderName; + String linuxFolderName = toolData.linuxFolderName; + String macFolderName = toolData.macFolderName; + + Path baseDownloadMockPath = PROJECTS_TARGET_PATH.resolve(projectTestCaseName).resolve(MOCK_DOWNLOAD_FOLDER); String mockProgram = ""; if (context == null) { throw new IllegalStateException("Please set a IdeContext!"); } - // TODO MOCK CONTEXT SYSTEMINFO ??? if (context.getSystemInfo().isWindows()) { mockProgram = windowsFolderName; } else if (context.getSystemInfo().isLinux()) { diff --git a/cli/src/test/java/com/devonfw/tools/ide/tool/jmc/JmcTest.java b/cli/src/test/java/com/devonfw/tools/ide/tool/jmc/JmcTest.java index 2532a34bc..78d327321 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/tool/jmc/JmcTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/tool/jmc/JmcTest.java @@ -7,11 +7,10 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -import java.util.HashMap; -import java.util.Map; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; @@ -19,6 +18,8 @@ import com.devonfw.tools.ide.commandlet.InstallCommandlet; import com.devonfw.tools.ide.context.AbstractIdeContextTest; import com.devonfw.tools.ide.context.IdeContext; +import com.devonfw.tools.ide.context.IdeTestContext; +import com.devonfw.tools.ide.log.IdeLogLevel; import com.devonfw.tools.ide.repo.ToolRepositoryMock; import com.github.tomakehurst.wiremock.WireMockServer; import com.github.tomakehurst.wiremock.core.WireMockConfiguration; @@ -47,6 +48,12 @@ static void tearDown() throws IOException { server.shutdownServer(); } + @BeforeEach + public void setUpStream() { + + // System.setOut(new PrintStream(outputStreamCaptor)); + } + private void mockWebServer() throws IOException { // Jmc under test @@ -112,7 +119,7 @@ public void jmcPostInstallShouldMoveFilesIfRequired() throws IOException { String path = "workspaces/foo-test/my-git-repo"; String projectTestCaseName = "jmc"; - ToolRepositoryMock toolRepositoryMock = buildToolRepositoryMock(projectTestCaseName); + ToolRepositoryMock toolRepositoryMock = buildToolRepositoryMockForJmc(projectTestCaseName); IdeContext context = newContext(projectTestCaseName, path, true, toolRepositoryMock); toolRepositoryMock.setContext(context); @@ -126,10 +133,9 @@ public void jmcPostInstallShouldMoveFilesIfRequired() throws IOException { // assert performPostInstallAssertion(context); - } - // run test, currently cannot find correct executeable TODO FIND BINARY BUGGY + // run test, currently cannot find correct executeable TODO FIND BINARY BUG @Test @Disabled public void jmcShouldRunExecuteableSuccessfully() throws IOException { @@ -137,8 +143,9 @@ public void jmcShouldRunExecuteableSuccessfully() throws IOException { // arrange String path = "workspaces/foo-test/my-git-repo"; String projectTestCaseName = "jmc"; + String expectedOutputWindows = "Dummy jmc 8.3.0 on windows"; - ToolRepositoryMock toolRepositoryMock = buildToolRepositoryMock(projectTestCaseName); + ToolRepositoryMock toolRepositoryMock = buildToolRepositoryMockForJmc(projectTestCaseName); IdeContext context = newContext(projectTestCaseName, path, true, toolRepositoryMock); toolRepositoryMock.setContext(context); @@ -152,28 +159,28 @@ public void jmcShouldRunExecuteableSuccessfully() throws IOException { // act commandlet.run(); - // assert, output stream probably - // System.out + // assert, TODO verify output stream } - private static ToolRepositoryMock buildToolRepositoryMock(String projectTestCaseName) { - - Map toolToVersion = new HashMap<>(); - toolToVersion.put("jmc", "8.3.0"); - toolToVersion.put("java", "17.0.10_7"); + private static ToolRepositoryMock buildToolRepositoryMockForJmc(String projectTestCaseName) { String windowsFileFolder = "org.openjdk.jmc-8.3.0-win32.win32.x86_64"; String linuxFileFolder = "org.openjdk.jmc-8.3.0-linux.gtk.x86_64"; String macFileFolder = "org.openjdk.jmc-8.3.0-macosx.cocoa.x86_64"; - ToolRepositoryMock toolRepositoryMock = new ToolRepositoryMock(toolToVersion, projectTestCaseName, + ToolRepositoryMock toolRepositoryMock = new ToolRepositoryMock("jmc", "8.3.0", projectTestCaseName, windowsFileFolder, linuxFileFolder, macFileFolder); + + toolRepositoryMock.addAlreadyInstalledTool("java", "17.0.10_7"); + return toolRepositoryMock; } private void performPostInstallAssertion(IdeContext context) { + String expectedMessage = "Successfully installed jmc in version 8.3.0"; + assertThat(context.getSoftwarePath().resolve("jmc")).exists(); assertThat(context.getSoftwarePath().resolve("jmc/InstallTest.txt")).hasContent("This is a test file."); @@ -199,6 +206,9 @@ private void performPostInstallAssertion(IdeContext context) { assertThat(context.getSoftwarePath().resolve("jmc/.ide.software.version")).exists(); assertThat(context.getSoftwarePath().resolve("jmc/.ide.software.version")).hasContent("8.3.0"); + + assertLogMessage((IdeTestContext) context, IdeLogLevel.SUCCESS, expectedMessage, false); + } } From 953f72817378debf2490a5cd21a9423712ea5152 Mon Sep 17 00:00:00 2001 From: Ouchen Date: Fri, 23 Feb 2024 15:06:28 +0100 Subject: [PATCH 07/18] Minor changes --- .../jmc/_ide/software/default/deleteMeAfterSoftwareAdded.txt | 0 .../JDK Mission Control/jmc | 2 +- .../jmc/project/workspaces/foo-test/my-git-repo/readme | 2 +- .../ide-projects/jmc/project/workspaces/foo-test/readme | 2 +- .../resources/ide-projects/jmc/project/workspaces/main/readme | 2 +- 5 files changed, 4 insertions(+), 4 deletions(-) delete mode 100644 cli/src/test/resources/ide-projects/jmc/_ide/software/default/deleteMeAfterSoftwareAdded.txt diff --git a/cli/src/test/resources/ide-projects/jmc/_ide/software/default/deleteMeAfterSoftwareAdded.txt b/cli/src/test/resources/ide-projects/jmc/_ide/software/default/deleteMeAfterSoftwareAdded.txt deleted file mode 100644 index e69de29bb..000000000 diff --git a/cli/src/test/resources/ide-projects/jmc/downloadMockLocation/org.openjdk.jmc-8.3.0-linux.gtk.x86_64/JDK Mission Control/jmc b/cli/src/test/resources/ide-projects/jmc/downloadMockLocation/org.openjdk.jmc-8.3.0-linux.gtk.x86_64/JDK Mission Control/jmc index 07b255f6a..b9b2c6991 100644 --- a/cli/src/test/resources/ide-projects/jmc/downloadMockLocation/org.openjdk.jmc-8.3.0-linux.gtk.x86_64/JDK Mission Control/jmc +++ b/cli/src/test/resources/ide-projects/jmc/downloadMockLocation/org.openjdk.jmc-8.3.0-linux.gtk.x86_64/JDK Mission Control/jmc @@ -1 +1 @@ -echo "Dummy jmc 8.3.0 on linux/macOs" \ No newline at end of file +echo "Dummy jmc 8.3.0 on linux" \ No newline at end of file diff --git a/cli/src/test/resources/ide-projects/jmc/project/workspaces/foo-test/my-git-repo/readme b/cli/src/test/resources/ide-projects/jmc/project/workspaces/foo-test/my-git-repo/readme index 7cf8ec575..059135125 100644 --- a/cli/src/test/resources/ide-projects/jmc/project/workspaces/foo-test/my-git-repo/readme +++ b/cli/src/test/resources/ide-projects/jmc/project/workspaces/foo-test/my-git-repo/readme @@ -1 +1 @@ -my-git-repo in foo-test workspace of basic \ No newline at end of file +my-git-repo in foo-test workspace of jmc test case \ No newline at end of file diff --git a/cli/src/test/resources/ide-projects/jmc/project/workspaces/foo-test/readme b/cli/src/test/resources/ide-projects/jmc/project/workspaces/foo-test/readme index 948f8cfea..144e7e389 100644 --- a/cli/src/test/resources/ide-projects/jmc/project/workspaces/foo-test/readme +++ b/cli/src/test/resources/ide-projects/jmc/project/workspaces/foo-test/readme @@ -1 +1 @@ -this is the foo-test workspace of basic \ No newline at end of file +this is the foo-test workspace of jmc test case \ No newline at end of file diff --git a/cli/src/test/resources/ide-projects/jmc/project/workspaces/main/readme b/cli/src/test/resources/ide-projects/jmc/project/workspaces/main/readme index 7146c2ad6..f04b5be39 100644 --- a/cli/src/test/resources/ide-projects/jmc/project/workspaces/main/readme +++ b/cli/src/test/resources/ide-projects/jmc/project/workspaces/main/readme @@ -1 +1 @@ -this is the main workspace of basic \ No newline at end of file +this is the main workspace of jmc test case \ No newline at end of file From b568555cb8c325e49a773d27b7f31947bb04d00c Mon Sep 17 00:00:00 2001 From: Ouchen Date: Mon, 26 Feb 2024 09:07:31 +0100 Subject: [PATCH 08/18] Modify mock programs for testing --- .../JDK Mission Control/jmc | 4 +++- .../JDK Mission Control.app/Contents/jmc | 4 +++- .../JDK Mission Control/jmc.cmd | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/cli/src/test/resources/ide-projects/jmc/downloadMockLocation/org.openjdk.jmc-8.3.0-linux.gtk.x86_64/JDK Mission Control/jmc b/cli/src/test/resources/ide-projects/jmc/downloadMockLocation/org.openjdk.jmc-8.3.0-linux.gtk.x86_64/JDK Mission Control/jmc index b9b2c6991..038eea977 100644 --- a/cli/src/test/resources/ide-projects/jmc/downloadMockLocation/org.openjdk.jmc-8.3.0-linux.gtk.x86_64/JDK Mission Control/jmc +++ b/cli/src/test/resources/ide-projects/jmc/downloadMockLocation/org.openjdk.jmc-8.3.0-linux.gtk.x86_64/JDK Mission Control/jmc @@ -1 +1,3 @@ -echo "Dummy jmc 8.3.0 on linux" \ No newline at end of file +#!/bin/bash + +echo "Dummy jmc 8.3.0 on linux" > jmcTestRestult.txt \ No newline at end of file diff --git a/cli/src/test/resources/ide-projects/jmc/downloadMockLocation/org.openjdk.jmc-8.3.0-macosx.cocoa.x86_64/JDK Mission Control.app/Contents/jmc b/cli/src/test/resources/ide-projects/jmc/downloadMockLocation/org.openjdk.jmc-8.3.0-macosx.cocoa.x86_64/JDK Mission Control.app/Contents/jmc index e4af7cc05..8b6eb3cd4 100644 --- a/cli/src/test/resources/ide-projects/jmc/downloadMockLocation/org.openjdk.jmc-8.3.0-macosx.cocoa.x86_64/JDK Mission Control.app/Contents/jmc +++ b/cli/src/test/resources/ide-projects/jmc/downloadMockLocation/org.openjdk.jmc-8.3.0-macosx.cocoa.x86_64/JDK Mission Control.app/Contents/jmc @@ -1 +1,3 @@ -echo "Dummy jmc 8.3.0 on macOs" \ No newline at end of file +#!/bin/bash + +echo "Dummy jmc 8.3.0 on macOs" > jmcTestRestult.txt \ No newline at end of file diff --git a/cli/src/test/resources/ide-projects/jmc/downloadMockLocation/org.openjdk.jmc-8.3.0-win32.win32.x86_64/JDK Mission Control/jmc.cmd b/cli/src/test/resources/ide-projects/jmc/downloadMockLocation/org.openjdk.jmc-8.3.0-win32.win32.x86_64/JDK Mission Control/jmc.cmd index 1ad2214fe..ab8e57341 100644 --- a/cli/src/test/resources/ide-projects/jmc/downloadMockLocation/org.openjdk.jmc-8.3.0-win32.win32.x86_64/JDK Mission Control/jmc.cmd +++ b/cli/src/test/resources/ide-projects/jmc/downloadMockLocation/org.openjdk.jmc-8.3.0-win32.win32.x86_64/JDK Mission Control/jmc.cmd @@ -1 +1 @@ -echo "Dummy jmc 8.3.0 on windows" \ No newline at end of file +echo Dummy jmc 8.3.0 on windows> jmcTestRestult.txt \ No newline at end of file From a1f77592c572ddbd31bf1fbb968099e1153db7ec Mon Sep 17 00:00:00 2001 From: Ouchen Date: Mon, 26 Feb 2024 09:07:59 +0100 Subject: [PATCH 09/18] Refactored example JmcTest --- .../devonfw/tools/ide/tool/jmc/JmcTest.java | 35 ++++++++++++++++--- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/cli/src/test/java/com/devonfw/tools/ide/tool/jmc/JmcTest.java b/cli/src/test/java/com/devonfw/tools/ide/tool/jmc/JmcTest.java index 78d327321..5a01291fd 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/tool/jmc/JmcTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/tool/jmc/JmcTest.java @@ -16,10 +16,12 @@ import com.devonfw.tools.ide.commandlet.CommandLetExtractorMock; import com.devonfw.tools.ide.commandlet.InstallCommandlet; +import com.devonfw.tools.ide.context.AbstractIdeContext; import com.devonfw.tools.ide.context.AbstractIdeContextTest; import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.context.IdeTestContext; import com.devonfw.tools.ide.log.IdeLogLevel; +import com.devonfw.tools.ide.os.SystemInfo; import com.devonfw.tools.ide.repo.ToolRepositoryMock; import com.github.tomakehurst.wiremock.WireMockServer; import com.github.tomakehurst.wiremock.core.WireMockConfiguration; @@ -135,7 +137,7 @@ public void jmcPostInstallShouldMoveFilesIfRequired() throws IOException { performPostInstallAssertion(context); } - // run test, currently cannot find correct executeable TODO FIND BINARY BUG + // TODO: Enable test as soon https://github.com/devonfw/IDEasy/pull/228 is merged @Test @Disabled public void jmcShouldRunExecuteableSuccessfully() throws IOException { @@ -144,11 +146,15 @@ public void jmcShouldRunExecuteableSuccessfully() throws IOException { String path = "workspaces/foo-test/my-git-repo"; String projectTestCaseName = "jmc"; String expectedOutputWindows = "Dummy jmc 8.3.0 on windows"; + String expectedOutputLinux = "Dummy jmc 8.3.0 on linux"; + String expectedOutputMacOs = "Dummy jmc 8.3.0 on macOs"; + Path mockResultPath = Path.of("target/test-projects/jmc/project"); ToolRepositoryMock toolRepositoryMock = buildToolRepositoryMockForJmc(projectTestCaseName); - IdeContext context = newContext(projectTestCaseName, path, true, toolRepositoryMock); + AbstractIdeContext context = newContext(projectTestCaseName, path, true, toolRepositoryMock); toolRepositoryMock.setContext(context); + context.setDefaultExecutionDirectory(mockResultPath); CommandLetExtractorMock commandLetExtractorMock = new CommandLetExtractorMock(context); Jmc commandlet = new Jmc(context); @@ -159,10 +165,31 @@ public void jmcShouldRunExecuteableSuccessfully() throws IOException { // act commandlet.run(); - // assert, TODO verify output stream + // assert + + String expectedOutput = determineExpectedOutput(context, expectedOutputWindows, expectedOutputLinux, + expectedOutputMacOs); + + assertThat(mockResultPath.resolve("jmcTestRestult.txt")).exists(); + assertThat(mockResultPath.resolve("jmcTestRestult.txt")).hasContent(expectedOutput); } + private String determineExpectedOutput(AbstractIdeContext context, String expectedOutputWindows, + String expectedOutputLinux, String expectedOutputMacOs) { + + SystemInfo systemInfo = context.getSystemInfo(); + if (systemInfo.isWindows()) { + return expectedOutputWindows; + } else if (systemInfo.isLinux()) { + return expectedOutputLinux; + } else if (systemInfo.isMac()) { + return expectedOutputMacOs; + } else { + throw new IllegalStateException("Unexpected operating system!"); + } + } + private static ToolRepositoryMock buildToolRepositoryMockForJmc(String projectTestCaseName) { String windowsFileFolder = "org.openjdk.jmc-8.3.0-win32.win32.x86_64"; @@ -184,7 +211,6 @@ private void performPostInstallAssertion(IdeContext context) { assertThat(context.getSoftwarePath().resolve("jmc")).exists(); assertThat(context.getSoftwarePath().resolve("jmc/InstallTest.txt")).hasContent("This is a test file."); - // Win if (context.getSystemInfo().isWindows()) { assertThat(context.getSoftwarePath().resolve("jmc/jmc.cmd")).exists(); } @@ -193,7 +219,6 @@ private void performPostInstallAssertion(IdeContext context) { assertThat(context.getSoftwarePath().resolve("jmc/jmc")).exists(); } - // Win linux if (context.getSystemInfo().isWindows() || context.getSystemInfo().isLinux()) { assertThat(context.getSoftwarePath().resolve("jmc/HelloWorld.txt")).hasContent("Hello World!"); assertThat(context.getSoftwarePath().resolve("jmc/JDK Mission Control")).doesNotExist(); From d8ee80109bc6b1ac37e182510b1f5995cee6bcb1 Mon Sep 17 00:00:00 2001 From: Ouchen Date: Mon, 26 Feb 2024 09:09:29 +0100 Subject: [PATCH 10/18] Add possibility to set execution path by using the context --- .../tools/ide/context/AbstractIdeContext.java | 18 ++++++++++++++++++ .../tools/ide/process/ProcessContextImpl.java | 8 +++++++- 2 files changed, 25 insertions(+), 1 deletion(-) 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 0c63b4539..d28be7c9b 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 @@ -122,6 +122,8 @@ public abstract class AbstractIdeContext implements IdeContext { private static final Duration GIT_PULL_CACHE_DELAY_MILLIS = Duration.ofMillis(30 * 60 * 1000); + private Path defaultExecutionDirectory; + /** * The constructor. * @@ -598,10 +600,26 @@ public DirectoryMerger getWorkspaceMerger() { return this.workspaceMerger; } + public Path getDefaultExecutionDirectory() { + + return defaultExecutionDirectory; + } + + /** + * @param defaultExecutionDirectory new value of {@link #getDefaultExecutionDirectory()}. + */ + public void setDefaultExecutionDirectory(Path defaultExecutionDirectory) { + + if (defaultExecutionDirectory != null) { + this.defaultExecutionDirectory = defaultExecutionDirectory; + } + } + @Override public ProcessContext newProcess() { ProcessContext processContext = new ProcessContextImpl(this); + processContext.directory(this.getDefaultExecutionDirectory()); return processContext; } 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 a3a0ef379..a35b5ea94 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 @@ -66,7 +66,13 @@ public ProcessContext errorHandling(ProcessErrorHandling handling) { @Override public ProcessContext directory(Path directory) { - this.processBuilder.directory(directory.toFile()); + if (directory != null) { + this.processBuilder.directory(directory.toFile()); + } else { + context.debug( + "Could not set the process builder's working directory! Directory of the current java process is used."); + } + return this; } From 6a89529e847de768ebb13843d5ab3a6cdf455d09 Mon Sep 17 00:00:00 2001 From: Ouchen Date: Tue, 27 Feb 2024 11:23:36 +0100 Subject: [PATCH 11/18] Reenable test after related issue 228 has been merged --- cli/src/test/java/com/devonfw/tools/ide/tool/jmc/JmcTest.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/cli/src/test/java/com/devonfw/tools/ide/tool/jmc/JmcTest.java b/cli/src/test/java/com/devonfw/tools/ide/tool/jmc/JmcTest.java index 5a01291fd..70d5c8e1c 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/tool/jmc/JmcTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/tool/jmc/JmcTest.java @@ -11,7 +11,6 @@ import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import com.devonfw.tools.ide.commandlet.CommandLetExtractorMock; @@ -137,9 +136,7 @@ public void jmcPostInstallShouldMoveFilesIfRequired() throws IOException { performPostInstallAssertion(context); } - // TODO: Enable test as soon https://github.com/devonfw/IDEasy/pull/228 is merged @Test - @Disabled public void jmcShouldRunExecuteableSuccessfully() throws IOException { // arrange From 8735efd3fe57842182c91fcef8ab278b692c474f Mon Sep 17 00:00:00 2001 From: Ouchen Date: Tue, 27 Feb 2024 11:37:21 +0100 Subject: [PATCH 12/18] Replace ternary with regular if --- .../com/devonfw/tools/ide/context/AbstractIdeContext.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) 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 bb76e553b..6717a8c31 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 @@ -237,7 +237,13 @@ public AbstractIdeContext(IdeLogLevel minLogLevel, Function Date: Tue, 27 Feb 2024 11:40:52 +0100 Subject: [PATCH 13/18] Add missing javadoc --- .../com/devonfw/tools/ide/context/AbstractIdeContext.java | 4 ++++ 1 file changed, 4 insertions(+) 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 6717a8c31..854f8377a 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 @@ -601,6 +601,10 @@ public DirectoryMerger getWorkspaceMerger() { return this.workspaceMerger; } + /** + * + * @return the {@link #defaultExecutionDirectory} the directory in which a command process is executed. + */ public Path getDefaultExecutionDirectory() { return defaultExecutionDirectory; From 6b81cdfe59fdd111bffcb10f5bead2c79455eace Mon Sep 17 00:00:00 2001 From: Ouchen Date: Tue, 27 Feb 2024 11:45:53 +0100 Subject: [PATCH 14/18] Add missing javadoc --- .../tools/ide/commandlet/CommandLetExtractorMock.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cli/src/test/java/com/devonfw/tools/ide/commandlet/CommandLetExtractorMock.java b/cli/src/test/java/com/devonfw/tools/ide/commandlet/CommandLetExtractorMock.java index da36ad249..616e8425f 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/commandlet/CommandLetExtractorMock.java +++ b/cli/src/test/java/com/devonfw/tools/ide/commandlet/CommandLetExtractorMock.java @@ -16,6 +16,11 @@ public class CommandLetExtractorMock implements CommandletFileExtractor { private final IdeContext context; + /** + * The constructor. + * + * @param context the {@link IdeContext} + */ public CommandLetExtractorMock(IdeContext context) { this.context = context; From e9cec8a23dab96c80bf8584438fb2a200b155ff7 Mon Sep 17 00:00:00 2001 From: Ouchen Date: Tue, 27 Feb 2024 11:48:46 +0100 Subject: [PATCH 15/18] remove unnecessary semicolon --- .../java/com/devonfw/tools/ide/repo/ToolRepositoryMock.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/cli/src/test/java/com/devonfw/tools/ide/repo/ToolRepositoryMock.java b/cli/src/test/java/com/devonfw/tools/ide/repo/ToolRepositoryMock.java index e67775419..95bfc507d 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/repo/ToolRepositoryMock.java +++ b/cli/src/test/java/com/devonfw/tools/ide/repo/ToolRepositoryMock.java @@ -27,8 +27,6 @@ private record ToolDataForMock(String version, String windowsFolderName, String String macFolderName) { } - ; - /** * Constructor of a ToolRepository Mock with information of an initial tool * From 2912ea3b765d8f15f6d4b19df04d3a25b3604c09 Mon Sep 17 00:00:00 2001 From: Ouchen Date: Tue, 27 Feb 2024 11:49:26 +0100 Subject: [PATCH 16/18] Fix spelling typo --- .../java/com/devonfw/tools/ide/repo/ToolRepositoryMock.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/src/test/java/com/devonfw/tools/ide/repo/ToolRepositoryMock.java b/cli/src/test/java/com/devonfw/tools/ide/repo/ToolRepositoryMock.java index 95bfc507d..b714e6049 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/repo/ToolRepositoryMock.java +++ b/cli/src/test/java/com/devonfw/tools/ide/repo/ToolRepositoryMock.java @@ -109,7 +109,7 @@ public Path download(String tool, String edition, VersionIdentifier version) { String mockProgram = ""; if (context == null) { - throw new IllegalStateException("Please set a IdeContext!"); + throw new IllegalStateException("Please set an IdeContext!"); } if (context.getSystemInfo().isWindows()) { From 73e4d13de60e322823c79801b91016ec387ecc94 Mon Sep 17 00:00:00 2001 From: Ouchen Date: Tue, 27 Feb 2024 11:54:54 +0100 Subject: [PATCH 17/18] Minor test changes --- .../java/com/devonfw/tools/ide/tool/jmc/JmcTest.java | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/cli/src/test/java/com/devonfw/tools/ide/tool/jmc/JmcTest.java b/cli/src/test/java/com/devonfw/tools/ide/tool/jmc/JmcTest.java index 70d5c8e1c..a02d1e5b5 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/tool/jmc/JmcTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/tool/jmc/JmcTest.java @@ -10,7 +10,6 @@ import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import com.devonfw.tools.ide.commandlet.CommandLetExtractorMock; @@ -38,6 +37,7 @@ public class JmcTest extends AbstractIdeContextTest { static void setUp() throws IOException { // TODO use random port number and create url file dynamically in project + // TODO ISSUE:https://github.com/devonfw/IDEasy/issues/223 server = new WireMockServer(WireMockConfiguration.wireMockConfig().port(1112)); server.start(); @@ -49,12 +49,6 @@ static void tearDown() throws IOException { server.shutdownServer(); } - @BeforeEach - public void setUpStream() { - - // System.setOut(new PrintStream(outputStreamCaptor)); - } - private void mockWebServer() throws IOException { // Jmc under test @@ -137,7 +131,7 @@ public void jmcPostInstallShouldMoveFilesIfRequired() throws IOException { } @Test - public void jmcShouldRunExecuteableSuccessfully() throws IOException { + public void jmcShouldRunExecuteableSuccessful() throws IOException { // arrange String path = "workspaces/foo-test/my-git-repo"; From c0399aa79ca64f6e2cbc36bb9fc87ae5fe73f970 Mon Sep 17 00:00:00 2001 From: Ouchen Date: Tue, 27 Feb 2024 12:37:35 +0100 Subject: [PATCH 18/18] Refactoring FileExtractor class for more modularity --- .../CommandletFileExtractor.java | 6 +- .../CommandletFileExtractorImpl.java | 88 ++++++++++++------- .../FileExtractor/ExctractorFileType.java | 5 ++ .../tools/ide/tool/ToolCommandlet.java | 4 +- .../tools/ide/tool/aws/AwsFileExtractor.java | 2 +- .../commandlet/CommandLetExtractorMock.java | 1 + 6 files changed, 68 insertions(+), 38 deletions(-) rename cli/src/main/java/com/devonfw/tools/ide/commandlet/{ => FileExtractor}/CommandletFileExtractor.java (94%) rename cli/src/main/java/com/devonfw/tools/ide/commandlet/{ => FileExtractor}/CommandletFileExtractorImpl.java (60%) create mode 100644 cli/src/main/java/com/devonfw/tools/ide/commandlet/FileExtractor/ExctractorFileType.java diff --git a/cli/src/main/java/com/devonfw/tools/ide/commandlet/CommandletFileExtractor.java b/cli/src/main/java/com/devonfw/tools/ide/commandlet/FileExtractor/CommandletFileExtractor.java similarity index 94% rename from cli/src/main/java/com/devonfw/tools/ide/commandlet/CommandletFileExtractor.java rename to cli/src/main/java/com/devonfw/tools/ide/commandlet/FileExtractor/CommandletFileExtractor.java index 5090c33c9..cc87f1374 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/commandlet/CommandletFileExtractor.java +++ b/cli/src/main/java/com/devonfw/tools/ide/commandlet/FileExtractor/CommandletFileExtractor.java @@ -1,9 +1,9 @@ -package com.devonfw.tools.ide.commandlet; - -import com.devonfw.tools.ide.tool.ToolCommandlet; +package com.devonfw.tools.ide.commandlet.FileExtractor; import java.nio.file.Path; +import com.devonfw.tools.ide.tool.ToolCommandlet; + /** * {@link CommandletFileExtractor} class which handles the extraction of downloaded installations of a * {@link ToolCommandlet}. diff --git a/cli/src/main/java/com/devonfw/tools/ide/commandlet/CommandletFileExtractorImpl.java b/cli/src/main/java/com/devonfw/tools/ide/commandlet/FileExtractor/CommandletFileExtractorImpl.java similarity index 60% rename from cli/src/main/java/com/devonfw/tools/ide/commandlet/CommandletFileExtractorImpl.java rename to cli/src/main/java/com/devonfw/tools/ide/commandlet/FileExtractor/CommandletFileExtractorImpl.java index 76a271aed..0df062a98 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/commandlet/CommandletFileExtractorImpl.java +++ b/cli/src/main/java/com/devonfw/tools/ide/commandlet/FileExtractor/CommandletFileExtractorImpl.java @@ -1,4 +1,4 @@ -package com.devonfw.tools.ide.commandlet; +package com.devonfw.tools.ide.commandlet.FileExtractor; import java.io.IOException; import java.nio.file.Files; @@ -39,44 +39,24 @@ public void extract(Path file, Path targetDir, boolean isExtract) { FileAccess fileAccess = this.context.getFileAccess(); if (isExtract) { - Path tmpDir = this.context.getFileAccess().createTempDir("extract-" + file.getFileName()); + Path tmpDir = fileAccess.createTempDir("extract-" + file.getFileName()); this.context.trace("Trying to extract the downloaded file {} to {} and move it to {}.", file, tmpDir, targetDir); String extension = FilenameUtil.getExtension(file.getFileName().toString()); this.context.trace("Determined file extension {}", extension); TarCompression tarCompression = TarCompression.of(extension); + ExtractorFileType fileType = ExtractorFileType.valueOf(extension.toUpperCase()); + if (tarCompression != null) { fileAccess.untar(file, tmpDir, tarCompression); - } else if ("zip".equals(extension) || "jar".equals(extension)) { + } else if (fileType == ExtractorFileType.ZIP || fileType == ExtractorFileType.JAR) { fileAccess.unzip(file, tmpDir); - } else if ("dmg".equals(extension)) { - assert this.context.getSystemInfo().isMac(); - Path mountPath = this.context.getIdeHome().resolve(IdeContext.FOLDER_UPDATES).resolve(IdeContext.FOLDER_VOLUME); - fileAccess.mkdirs(mountPath); - ProcessContext pc = this.context.newProcess(); - pc.executable("hdiutil"); - pc.addArgs("attach", "-quiet", "-nobrowse", "-mountpoint", mountPath, file); - pc.run(); - Path appPath = fileAccess.findFirst(mountPath, p -> p.getFileName().toString().endsWith(".app"), false); - if (appPath == null) { - throw new IllegalStateException("Failed to unpack DMG as no MacOS *.app was found in file " + file); - } - fileAccess.copy(appPath, tmpDir); - pc.addArgs("detach", "-force", mountPath); - pc.run(); - } else if ("msi".equals(extension)) { - this.context.newProcess().executable("msiexec").addArgs("/a", file, "/qn", "TARGETDIR=" + tmpDir).run(); - // msiexec also creates a copy of the MSI - Path msiCopy = tmpDir.resolve(file.getFileName()); - fileAccess.delete(msiCopy); - } else if ("pkg".equals(extension)) { - - Path tmpDirPkg = fileAccess.createTempDir("ide-pkg-"); - ProcessContext pc = this.context.newProcess(); - // we might also be able to use cpio from commons-compression instead of external xar... - pc.executable("xar").addArgs("-C", tmpDirPkg, "-xf", file).run(); - Path contentPath = fileAccess.findFirst(tmpDirPkg, p -> p.getFileName().toString().equals("Payload"), true); - fileAccess.untar(contentPath, tmpDir, TarCompression.GZ); - fileAccess.delete(tmpDirPkg); + } else if (fileType == ExtractorFileType.DMG) { + extractLinuxDmg(file, tmpDir); + } else if (fileType == ExtractorFileType.MSI) { + extractWindowsMsi(file, tmpDir); + } else if (fileType == ExtractorFileType.PKG) { + extractPkg(file, tmpDir); + } else { throw new IllegalStateException("Unknown archive format " + extension + ". Can not extract " + file); } @@ -130,4 +110,48 @@ private Path getProperInstallationSubDirOf(Path path) { throw new IllegalStateException("Failed to get sub-files of " + path); } } + + private void extractLinuxDmg(Path file, Path tmpDir) { + + assert this.context.getSystemInfo().isMac(); + + FileAccess fileAccess = this.context.getFileAccess(); + Path mountPath = this.context.getIdeHome().resolve(IdeContext.FOLDER_UPDATES).resolve(IdeContext.FOLDER_VOLUME); + fileAccess.mkdirs(mountPath); + ProcessContext pc = this.context.newProcess(); + pc.executable("hdiutil"); + pc.addArgs("attach", "-quiet", "-nobrowse", "-mountpoint", mountPath, file); + pc.run(); + Path appPath = fileAccess.findFirst(mountPath, p -> p.getFileName().toString().endsWith(".app"), false); + if (appPath == null) { + throw new IllegalStateException("Failed to unpack DMG as no MacOS *.app was found in file " + file); + } + fileAccess.copy(appPath, tmpDir); + pc.addArgs("detach", "-force", mountPath); + pc.run(); + } + + private void extractWindowsMsi(Path file, Path tmpDir) { + + FileAccess fileAccess = this.context.getFileAccess(); + this.context.newProcess().executable("msiexec").addArgs("/a", file, "/qn", "TARGETDIR=" + tmpDir).run(); + // msiexec also creates a copy of the MSI + Path msiCopy = tmpDir.resolve(file.getFileName()); + fileAccess.delete(msiCopy); + } + + private void extractPkg(Path file, Path tmpDir) { + + FileAccess fileAccess = this.context.getFileAccess(); + + Path tmpDirPkg = fileAccess.createTempDir("ide-pkg-"); + ProcessContext pc = this.context.newProcess(); + // we might also be able to use cpio from commons-compression instead of external xar... + pc.executable("xar").addArgs("-C", tmpDirPkg, "-xf", file).run(); + Path contentPath = fileAccess.findFirst(tmpDirPkg, p -> p.getFileName().toString().equals("Payload"), true); + fileAccess.untar(contentPath, tmpDir, TarCompression.GZ); + fileAccess.delete(tmpDirPkg); + + } + } \ No newline at end of file diff --git a/cli/src/main/java/com/devonfw/tools/ide/commandlet/FileExtractor/ExctractorFileType.java b/cli/src/main/java/com/devonfw/tools/ide/commandlet/FileExtractor/ExctractorFileType.java new file mode 100644 index 000000000..d760df788 --- /dev/null +++ b/cli/src/main/java/com/devonfw/tools/ide/commandlet/FileExtractor/ExctractorFileType.java @@ -0,0 +1,5 @@ +package com.devonfw.tools.ide.commandlet.FileExtractor; + +enum ExtractorFileType { + ZIP, JAR, DMG, MSI, PKG +} \ No newline at end of file diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java index d2062c5a3..a0883df82 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java @@ -7,8 +7,8 @@ import java.util.Set; import com.devonfw.tools.ide.commandlet.Commandlet; -import com.devonfw.tools.ide.commandlet.CommandletFileExtractor; -import com.devonfw.tools.ide.commandlet.CommandletFileExtractorImpl; +import com.devonfw.tools.ide.commandlet.FileExtractor.CommandletFileExtractor; +import com.devonfw.tools.ide.commandlet.FileExtractor.CommandletFileExtractorImpl; import com.devonfw.tools.ide.common.Tag; import com.devonfw.tools.ide.common.Tags; import com.devonfw.tools.ide.context.IdeContext; diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/aws/AwsFileExtractor.java b/cli/src/main/java/com/devonfw/tools/ide/tool/aws/AwsFileExtractor.java index fb7097807..4d764a4d6 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/aws/AwsFileExtractor.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/aws/AwsFileExtractor.java @@ -6,7 +6,7 @@ import java.nio.file.attribute.PosixFilePermission; import java.util.Set; -import com.devonfw.tools.ide.commandlet.CommandletFileExtractorImpl; +import com.devonfw.tools.ide.commandlet.FileExtractor.CommandletFileExtractorImpl; import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.process.ProcessContext; import com.devonfw.tools.ide.tool.ToolCommandlet; diff --git a/cli/src/test/java/com/devonfw/tools/ide/commandlet/CommandLetExtractorMock.java b/cli/src/test/java/com/devonfw/tools/ide/commandlet/CommandLetExtractorMock.java index 616e8425f..59efdcd02 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/commandlet/CommandLetExtractorMock.java +++ b/cli/src/test/java/com/devonfw/tools/ide/commandlet/CommandLetExtractorMock.java @@ -6,6 +6,7 @@ import java.util.Iterator; import java.util.stream.Stream; +import com.devonfw.tools.ide.commandlet.FileExtractor.CommandletFileExtractor; import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.io.FileAccess;