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

devonfw / IDEasy / 12795814462

15 Jan 2025 07:42PM UTC coverage: 67.842% (+0.02%) from 67.826%
12795814462

Pull #909

github

web-flow
Merge 558a2ba77 into 6f167c101
Pull Request #909: #790: Fix intellij plugin installation

2697 of 4345 branches covered (62.07%)

Branch coverage included in aggregate %.

6978 of 9916 relevant lines covered (70.37%)

3.09 hits per line

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

71.43
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.process.ProcessContext;
20
import com.devonfw.tools.ide.process.ProcessErrorHandling;
21
import com.devonfw.tools.ide.process.ProcessMode;
22
import com.devonfw.tools.ide.step.Step;
23
import com.devonfw.tools.ide.tool.plugin.ToolPluginDescriptor;
24

25
public class IdeaBasedIdeToolCommandlet extends IdeToolCommandlet {
26

27
  private static final String BUILD_FILE = "build.txt";
28

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

40
  @Override
41
  protected void configureToolArgs(ProcessContext pc, ProcessMode processMode, ProcessErrorHandling errorHandling, String... args) {
42

43
    super.configureToolArgs(pc, processMode, errorHandling, args);
6✔
44
  }
1✔
45

46
  @Override
47
  public void installPlugin(ToolPluginDescriptor plugin, Step step) {
48
    String downloadUrl = getDownloadUrl(plugin);
4✔
49

50
    String pluginId = plugin.id();
3✔
51

52
    Path tmpDir = null;
2✔
53

54
    try {
55
      Path installationPath = this.getPluginsInstallationPath();
3✔
56
      ensureInstallationPathExists(installationPath);
3✔
57

58
      FileAccess fileAccess = context.getFileAccess();
4✔
59
      tmpDir = fileAccess.createTempDir(pluginId);
4✔
60

61
      Path downloadedFile = downloadPlugin(fileAccess, downloadUrl, tmpDir, pluginId);
7✔
62
      extractDownloadedPlugin(fileAccess, downloadedFile, pluginId);
5✔
63

64
      step.success();
2✔
65
    } catch (IOException e) {
×
66
      step.error(e);
×
67
      throw new IllegalStateException("Failed to process installation of plugin: " + pluginId, e);
×
68
    } finally {
69
      if (tmpDir != null) {
2!
70
        context.getFileAccess().delete(tmpDir);
5✔
71
      }
72
    }
73
  }
1✔
74

75
  @Override
76
  public void runTool(String... args) {
77
    List<String> extendedArgs = new ArrayList<>(Arrays.asList(args));
6✔
78
    extendedArgs.add(this.context.getWorkspacePath().toString());
7✔
79
    super.runTool(extendedArgs.toArray(new String[0]));
7✔
80
  }
1✔
81

82
  /**
83
   * @param plugin the {@link ToolPluginDescriptor} to be installer
84
   * @return a {@link String} representing the download URL.
85
   */
86
  private String getDownloadUrl(ToolPluginDescriptor plugin) {
87
    String downloadUrl = plugin.url();
3✔
88
    String pluginId = URLEncoder.encode(plugin.id(), StandardCharsets.UTF_8).replaceAll("\\+", "%20");
8✔
89

90
    String buildVersion = readBuildVersion();
3✔
91

92
    if (downloadUrl == null || downloadUrl.isEmpty()) {
5!
93
      downloadUrl = String.format("https://plugins.jetbrains.com/pluginManager?action=download&id=%s&build=%s", pluginId, buildVersion);
×
94
    }
95
    return downloadUrl;
2✔
96
  }
97

98
  private String readBuildVersion() {
99
    Path buildFile = this.getToolPath().resolve(BUILD_FILE);
5✔
100
    if (context.getSystemInfo().isMac()) {
5✔
101
      MacOsHelper macOsHelper = new MacOsHelper(context);
6✔
102
      Path appPath = macOsHelper.findAppDir(macOsHelper.findRootToolPath(this, context));
8✔
103
      buildFile = appPath.resolve("Contents/Resources").resolve(BUILD_FILE);
6✔
104
    }
105
    try {
106
      return Files.readString(buildFile);
3✔
107
    } catch (IOException e) {
×
108
      throw new IllegalStateException("Failed to read " + this.getName() + " build version: " + buildFile, e);
×
109
    }
110
  }
111

112
  private void ensureInstallationPathExists(Path installationPath) throws IOException {
113
    if (!Files.exists(installationPath)) {
5!
114
      try {
115
        Files.createDirectories(installationPath);
×
116
      } catch (IOException e) {
×
117
        throw new IllegalStateException("Failed to create directory " + installationPath, e);
×
118
      }
×
119
    }
120
  }
1✔
121

122
  private Path downloadPlugin(FileAccess fileAccess, String downloadUrl, Path tmpDir, String pluginId) throws IOException {
123
    String extension = getFileExtensionFromUrl(downloadUrl);
4✔
124
    if (extension.isEmpty()) {
3!
125
      throw new IllegalStateException("Unknown file type for URL: " + downloadUrl);
×
126
    }
127
    String fileName = String.format("%s-plugin-%s%s", this.getName(), pluginId, extension);
18✔
128
    Path downloadedFile = tmpDir.resolve(fileName);
4✔
129
    fileAccess.download(downloadUrl, downloadedFile);
4✔
130
    return downloadedFile;
2✔
131
  }
132

133
  private void extractDownloadedPlugin(FileAccess fileAccess, Path downloadedFile, String pluginId) throws IOException {
134
    Path targetDir = this.getPluginsInstallationPath().resolve(pluginId);
5✔
135
    if (Files.exists(targetDir)) {
5!
136
      context.info("Plugin already installed, target directory already existing: {}", targetDir);
×
137
    } else {
138
      fileAccess.extract(downloadedFile, targetDir);
4✔
139
    }
140
  }
1✔
141

142
  private String getFileExtensionFromUrl(String urlString) throws IOException {
143
    URL url = new URL(urlString);
5✔
144
    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
4✔
145
    connection.setRequestMethod("HEAD");
3✔
146
    connection.connect();
2✔
147

148
    int responseCode = connection.getResponseCode();
3✔
149
    if (responseCode != HttpURLConnection.HTTP_OK) {
3!
150
      throw new IOException("Failed to fetch file headers: HTTP " + responseCode);
×
151
    }
152

153
    String contentType = connection.getContentType();
3✔
154
    if (contentType == null) {
2!
155
      return "";
×
156
    }
157
    return switch (contentType) {
9!
158
      case "application/zip" -> ".zip";
×
159
      case "application/java-archive" -> ".jar";
2✔
160
      default -> "";
×
161
    };
162
  }
163

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