• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

devonfw / IDEasy / 8144002629

04 Mar 2024 04:56PM UTC coverage: 58.928% (+0.7%) from 58.254%
8144002629

push

github

web-flow
#208: improve test infrastructure # 219: fix wrong executable (#238)

* Add first implementation

* Add javadoc

* Add javadoc

* Using target path instead of ressource path to make sure one-to-one copy of set up folders is used

* Add JavaDoc and mac mock program

* Add support for multiple dependencies while testing

* Minor changes

* Modify mock programs for testing

* Refactored example JmcTest

* Add possibility to set execution path by using the context

* Reenable test after related issue 228 has been merged

* Replace ternary with regular if

* Add missing javadoc

* Add missing javadoc

* remove unnecessary semicolon

* Fix spelling typo

* Minor test changes

* Refactoring FileExtractor class for more modularity

* using const

* Add missing extensions

* Remove unnecessary execption declaration and minor rename

* Fix spelling

* Add javadoc

* Forget dot

* minor change

* Revert "minor change"

This reverts commit ec81c3ce6.

* Revert "Merge branch 'main' into feature/208-MockOutToolRepoRefactorTestInfra"

This reverts commit d58847230, reversing
changes made to f38b3105f.

* Revert "Revert "Merge branch 'main' into feature/208-MockOutToolRepoRefactorTestInfra""

This reverts commit 3e49a0b3d.

* Revert "Revert "minor change""

This reverts commit 2f7b94624.

* fix typo

* #208: review and complete rework

* #208: improved system path

* #208: found and fixed bug on windows

* #208: improve OS mocking

* #208: improve test logging

reveal logs/errors so the developer actually sees what is happening instead of leaving them in the dark

* #208: improve OS detection

* #208: fixed

found and fixed bug in MacOS app detection for JMC, fixed copy file to folder bug, moved !extract logic back to FileAccess, f... (continued)

1580 of 2930 branches covered (53.92%)

Branch coverage included in aggregate %.

4047 of 6619 relevant lines covered (61.14%)

2.65 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

59.18
cli/src/main/java/com/devonfw/tools/ide/tool/LocalToolCommandlet.java
1
package com.devonfw.tools.ide.tool;
2

3
import com.devonfw.tools.ide.common.Tag;
4
import com.devonfw.tools.ide.context.IdeContext;
5
import com.devonfw.tools.ide.io.FileAccess;
6
import com.devonfw.tools.ide.io.FileCopyMode;
7
import com.devonfw.tools.ide.log.IdeLogLevel;
8
import com.devonfw.tools.ide.repo.ToolRepository;
9
import com.devonfw.tools.ide.version.VersionIdentifier;
10

11
import java.io.IOException;
12
import java.nio.file.Files;
13
import java.nio.file.Path;
14
import java.nio.file.StandardOpenOption;
15
import java.util.Set;
16

17
/**
18
 * {@link ToolCommandlet} that is installed locally into the IDE.
19
 */
20
public abstract class LocalToolCommandlet extends ToolCommandlet {
1✔
21

22
  /**
23
   * The constructor.
24
   *
25
   * @param context the {@link IdeContext}.
26
   * @param tool the {@link #getName() tool name}.
27
   * @param tags the {@link #getTags() tags} classifying the tool. Should be created via {@link Set#of(Object) Set.of}
28
   * method.
29
   */
30
  public LocalToolCommandlet(IdeContext context, String tool, Set<Tag> tags) {
31

32
    super(context, tool, tags);
5✔
33
  }
1✔
34

35
  /**
36
   * @return the {@link Path} where the tool is located (installed).
37
   */
38
  public Path getToolPath() {
39

40
    return this.context.getSoftwarePath().resolve(getName());
7✔
41
  }
42

43
  /**
44
   * @return the {@link Path} where the executables of the tool can be found. Typically a "bin" folder inside
45
   * {@link #getToolPath() tool path}.
46
   */
47
  public Path getToolBinPath() {
48

49
    Path toolPath = getToolPath();
×
50
    Path binPath = this.context.getFileAccess()
×
51
        .findFirst(toolPath, path -> path.getFileName().toString().equals("bin"), false);
×
52
    if ((binPath != null) && Files.isDirectory(binPath)) {
×
53
      return binPath;
×
54
    }
55
    return toolPath;
×
56
  }
57

58
  @Override
59
  protected boolean doInstall(boolean silent) {
60

61
    VersionIdentifier configuredVersion = getConfiguredVersion();
3✔
62
    // get installed version before installInRepo actually may install the software
63
    VersionIdentifier installedVersion = getInstalledVersion();
3✔
64
    // install configured version of our tool in the software repository if not already installed
65
    ToolInstallation installation = installInRepo(configuredVersion);
4✔
66

67
    // check if we already have this version installed (linked) locally in IDE_HOME/software
68
    VersionIdentifier resolvedVersion = installation.resolvedVersion();
3✔
69
    if (resolvedVersion.equals(installedVersion) && !installation.newInstallation()) {
4!
70
      IdeLogLevel level = silent ? IdeLogLevel.DEBUG : IdeLogLevel.INFO;
×
71
      this.context.level(level)
×
72
          .log("Version {} of tool {} is already installed", installedVersion, getToolWithEdition());
×
73
      return false;
×
74
    }
75
    // we need to link the version or update the link.
76
    Path toolPath = getToolPath();
3✔
77
    FileAccess fileAccess = this.context.getFileAccess();
4✔
78
    if (Files.exists(toolPath)) {
5✔
79
      fileAccess.backup(toolPath);
3✔
80
    }
81
    fileAccess.mkdirs(toolPath.getParent());
4✔
82
    fileAccess.symlink(installation.linkDir(), toolPath);
5✔
83
    this.context.getPath().setPath(this.tool, installation.binDir());
8✔
84
    if (installedVersion == null) {
2!
85
      this.context.success("Successfully installed {} in version {}", this.tool, resolvedVersion);
16✔
86
    } else {
87
      this.context.success("Successfully installed {} in version {} replacing previous version {}", this.tool,
×
88
          resolvedVersion, installedVersion);
89
    }
90
    postInstall();
2✔
91
    return true;
2✔
92
  }
93

94
  /**
95
   * Performs the installation of the {@link #getName() tool} managed by this
96
   * {@link com.devonfw.tools.ide.commandlet.Commandlet} only in the central software repository without touching the
97
   * IDE installation.
98
   *
99
   * @param version the {@link VersionIdentifier} requested to be installed. May also be a
100
   * {@link VersionIdentifier#isPattern() version pattern}.
101
   * @return the {@link ToolInstallation} in the central software repository matching the given {@code version}.
102
   */
103
  public ToolInstallation installInRepo(VersionIdentifier version) {
104

105
    return installInRepo(version, getEdition());
6✔
106
  }
107

108
  /**
109
   * Performs the installation of the {@link #getName() tool} managed by this
110
   * {@link com.devonfw.tools.ide.commandlet.Commandlet} only in the central software repository without touching the
111
   * IDE installation.
112
   *
113
   * @param version the {@link VersionIdentifier} requested to be installed. May also be a
114
   * {@link VersionIdentifier#isPattern() version pattern}.
115
   * @param edition the specific edition to install.
116
   * @return the {@link ToolInstallation} in the central software repository matching the given {@code version}.
117
   */
118
  public ToolInstallation installInRepo(VersionIdentifier version, String edition) {
119

120
    return installInRepo(version, edition, this.context.getDefaultToolRepository());
8✔
121
  }
122

123
  /**
124
   * Performs the installation of the {@link #getName() tool} managed by this
125
   * {@link com.devonfw.tools.ide.commandlet.Commandlet} only in the central software repository without touching the
126
   * IDE installation.
127
   *
128
   * @param version the {@link VersionIdentifier} requested to be installed. May also be a
129
   * {@link VersionIdentifier#isPattern() version pattern}.
130
   * @param edition the specific edition to install.
131
   * @param toolRepository the {@link ToolRepository} to use.
132
   * @return the {@link ToolInstallation} in the central software repository matching the given {@code version}.
133
   */
134
  public ToolInstallation installInRepo(VersionIdentifier version, String edition, ToolRepository toolRepository) {
135

136
    VersionIdentifier resolvedVersion = toolRepository.resolveVersion(this.tool, edition, version);
7✔
137
    Path toolPath = this.context.getSoftwareRepositoryPath().resolve(toolRepository.getId()).resolve(this.tool)
10✔
138
        .resolve(edition).resolve(resolvedVersion.toString());
5✔
139
    Path toolVersionFile = toolPath.resolve(IdeContext.FILE_SOFTWARE_VERSION);
4✔
140
    FileAccess fileAccess = this.context.getFileAccess();
4✔
141
    if (Files.isDirectory(toolPath)) {
5!
142
      if (Files.exists(toolVersionFile)) {
×
143
        if (this.context.isForceMode()) {
×
144
          fileAccess.delete(toolPath);
×
145
        } else {
146
          this.context.debug("Version {} of tool {} is already installed at {}", resolvedVersion,
×
147
              getToolWithEdition(this.tool, edition), toolPath);
×
148
          return createToolInstallation(toolPath, resolvedVersion, toolVersionFile);
×
149
        }
150
      } else {
151
        this.context.warning("Deleting corrupted installation at {}", toolPath);
×
152
        fileAccess.delete(toolPath);
×
153
      }
154
    }
155
    Path target = toolRepository.download(this.tool, edition, resolvedVersion);
7✔
156
    fileAccess.mkdirs(toolPath.getParent());
4✔
157
    boolean extract = isExtract();
3✔
158
    if (!extract) {
2!
159
      this.context.trace("Extraction is disabled for '{}' hence just moving the downloaded file {}.", this.tool,
×
160
          target);
161
    }
162
    fileAccess.extract(target, toolPath, this::postExtract, extract);
7✔
163
    try {
164
      Files.writeString(toolVersionFile, resolvedVersion.toString(), StandardOpenOption.CREATE_NEW);
11✔
165
    } catch (IOException e) {
×
166
      throw new IllegalStateException("Failed to write version file " + toolVersionFile, e);
×
167
    }
1✔
168
    // newInstallation results in above conditions to be true if isForceMode is true or if the tool version file was
169
    // missing
170
    return createToolInstallation(toolPath, resolvedVersion, toolVersionFile, true);
7✔
171
  }
172

173
  /**
174
   * Post-extraction hook that can be overridden to add custom processing after unpacking and before moving to the final
175
   * destination folder.
176
   *
177
   * @param extractedDir the {@link Path} to the folder with the unpacked tool.
178
   */
179
  protected void postExtract(Path extractedDir) {
180

181
  }
1✔
182

183
  private ToolInstallation createToolInstallation(Path rootDir, VersionIdentifier resolvedVersion, Path toolVersionFile,
184
      boolean newInstallation) {
185

186
    Path linkDir = getMacOsHelper().findLinkDir(rootDir, this.tool);
7✔
187
    Path binDir = linkDir;
2✔
188
    Path binFolder = binDir.resolve(IdeContext.FOLDER_BIN);
4✔
189
    if (Files.isDirectory(binFolder)) {
5✔
190
      binDir = binFolder;
2✔
191
    }
192
    if (linkDir != rootDir) {
3✔
193
      assert (!linkDir.equals(rootDir));
5!
194
      this.context.getFileAccess()
6✔
195
          .copy(toolVersionFile, linkDir.resolve(IdeContext.FILE_SOFTWARE_VERSION), FileCopyMode.COPY_FILE_OVERRIDE);
3✔
196
    }
197
    return new ToolInstallation(rootDir, linkDir, binDir, resolvedVersion, newInstallation);
9✔
198
  }
199

200
  private ToolInstallation createToolInstallation(Path rootDir, VersionIdentifier resolvedVersion,
201
      Path toolVersionFile) {
202

203
    return createToolInstallation(rootDir, resolvedVersion, toolVersionFile, false);
×
204
  }
205

206
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc