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

devonfw / IDEasy / 12890704917

21 Jan 2025 03:52PM UTC coverage: 68.444% (+0.3%) from 68.126%
12890704917

push

github

web-flow
#972: add CustomToolJsonDeserializer to prevent jackson error (#974)

2785 of 4459 branches covered (62.46%)

Branch coverage included in aggregate %.

7201 of 10131 relevant lines covered (71.08%)

3.09 hits per line

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

70.79
cli/src/main/java/com/devonfw/tools/ide/tool/ide/IdeaBasedIdeToolCommandlet.java
1
package com.devonfw.tools.ide.tool.ide;
2

3
import java.io.IOException;
4
import java.net.HttpURLConnection;
5
import java.net.URL;
6
import java.net.URLEncoder;
7
import java.nio.charset.StandardCharsets;
8
import java.nio.file.Files;
9
import java.nio.file.Path;
10
import java.util.ArrayList;
11
import java.util.Arrays;
12
import java.util.List;
13
import java.util.Set;
14

15
import com.devonfw.tools.ide.common.Tag;
16
import com.devonfw.tools.ide.context.IdeContext;
17
import com.devonfw.tools.ide.io.FileAccess;
18
import com.devonfw.tools.ide.os.MacOsHelper;
19
import com.devonfw.tools.ide.step.Step;
20
import com.devonfw.tools.ide.tool.plugin.ToolPluginDescriptor;
21

22
public class IdeaBasedIdeToolCommandlet extends IdeToolCommandlet {
23

24
  private static final String BUILD_FILE = "build.txt";
25

26
  /**
27
   * The constructor.
28
   *
29
   * @param context the {@link IdeContext}.
30
   * @param tool the {@link #getName() tool name}.
31
   * @param tags the {@link #getTags() tags} classifying the tool. Should be created via {@link Set#of(Object) Set.of} method.
32
   */
33
  public IdeaBasedIdeToolCommandlet(IdeContext context, String tool, Set<Tag> tags) {
34
    super(context, tool, tags);
5✔
35
  }
1✔
36

37
  @Override
38
  public void installPlugin(ToolPluginDescriptor plugin, Step step) {
39
    String downloadUrl = getDownloadUrl(plugin);
4✔
40

41
    String pluginId = plugin.id();
3✔
42

43
    Path tmpDir = null;
2✔
44

45
    try {
46
      Path installationPath = this.getPluginsInstallationPath();
3✔
47
      ensureInstallationPathExists(installationPath);
3✔
48

49
      FileAccess fileAccess = context.getFileAccess();
4✔
50
      tmpDir = fileAccess.createTempDir(pluginId);
4✔
51

52
      Path downloadedFile = downloadPlugin(fileAccess, downloadUrl, tmpDir, pluginId);
7✔
53
      extractDownloadedPlugin(fileAccess, downloadedFile, pluginId);
5✔
54

55
      step.success();
2✔
56
    } catch (IOException e) {
×
57
      step.error(e);
×
58
      throw new IllegalStateException("Failed to process installation of plugin: " + pluginId, e);
×
59
    } finally {
60
      if (tmpDir != null) {
2!
61
        context.getFileAccess().delete(tmpDir);
5✔
62
      }
63
    }
64
  }
1✔
65

66
  @Override
67
  public void runTool(String... args) {
68
    List<String> extendedArgs = new ArrayList<>(Arrays.asList(args));
6✔
69
    extendedArgs.add(this.context.getWorkspacePath().toString());
7✔
70
    super.runTool(extendedArgs.toArray(new String[0]));
7✔
71
  }
1✔
72

73
  /**
74
   * @param plugin the {@link ToolPluginDescriptor} to be installer
75
   * @return a {@link String} representing the download URL.
76
   */
77
  private String getDownloadUrl(ToolPluginDescriptor plugin) {
78
    String downloadUrl = plugin.url();
3✔
79
    String pluginId = URLEncoder.encode(plugin.id(), StandardCharsets.UTF_8).replaceAll("\\+", "%20");
8✔
80

81
    String buildVersion = readBuildVersion();
3✔
82

83
    if (downloadUrl == null || downloadUrl.isEmpty()) {
5!
84
      downloadUrl = String.format("https://plugins.jetbrains.com/pluginManager?action=download&id=%s&build=%s", pluginId, buildVersion);
×
85
    }
86
    return downloadUrl;
2✔
87
  }
88

89
  private String readBuildVersion() {
90
    Path buildFile = this.getToolPath().resolve(BUILD_FILE);
5✔
91
    if (context.getSystemInfo().isMac()) {
5✔
92
      MacOsHelper macOsHelper = new MacOsHelper(context);
6✔
93
      Path appPath = macOsHelper.findAppDir(macOsHelper.findRootToolPath(this, context));
8✔
94
      buildFile = appPath.resolve("Contents/Resources").resolve(BUILD_FILE);
6✔
95
    }
96
    try {
97
      return Files.readString(buildFile);
3✔
98
    } catch (IOException e) {
×
99
      throw new IllegalStateException("Failed to read " + this.getName() + " build version: " + buildFile, e);
×
100
    }
101
  }
102

103
  private void ensureInstallationPathExists(Path installationPath) throws IOException {
104
    if (!Files.exists(installationPath)) {
5!
105
      try {
106
        Files.createDirectories(installationPath);
×
107
      } catch (IOException e) {
×
108
        throw new IllegalStateException("Failed to create directory " + installationPath, e);
×
109
      }
×
110
    }
111
  }
1✔
112

113
  private Path downloadPlugin(FileAccess fileAccess, String downloadUrl, Path tmpDir, String pluginId) throws IOException {
114
    String extension = getFileExtensionFromUrl(downloadUrl);
4✔
115
    if (extension.isEmpty()) {
3!
116
      throw new IllegalStateException("Unknown file type for URL: " + downloadUrl);
×
117
    }
118
    String fileName = String.format("%s-plugin-%s%s", this.getName(), pluginId, extension);
18✔
119
    Path downloadedFile = tmpDir.resolve(fileName);
4✔
120
    fileAccess.download(downloadUrl, downloadedFile);
4✔
121
    return downloadedFile;
2✔
122
  }
123

124
  private void extractDownloadedPlugin(FileAccess fileAccess, Path downloadedFile, String pluginId) throws IOException {
125
    Path targetDir = this.getPluginsInstallationPath().resolve(pluginId);
5✔
126
    if (Files.exists(targetDir)) {
5!
127
      context.info("Plugin already installed, target directory already existing: {}", targetDir);
×
128
    } else {
129
      fileAccess.extract(downloadedFile, targetDir);
4✔
130
    }
131
  }
1✔
132

133
  private String getFileExtensionFromUrl(String urlString) throws IOException {
134
    URL url = new URL(urlString);
5✔
135
    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
4✔
136
    connection.setRequestMethod("HEAD");
3✔
137
    connection.connect();
2✔
138

139
    int responseCode = connection.getResponseCode();
3✔
140
    if (responseCode != HttpURLConnection.HTTP_OK) {
3!
141
      throw new IOException("Failed to fetch file headers: HTTP " + responseCode);
×
142
    }
143

144
    String contentType = connection.getContentType();
3✔
145
    if (contentType == null) {
2!
146
      return "";
×
147
    }
148
    return switch (contentType) {
9!
149
      case "application/zip" -> ".zip";
×
150
      case "application/java-archive" -> ".jar";
2✔
151
      default -> "";
×
152
    };
153
  }
154

155
}
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