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

devonfw / IDEasy / 10162545933

30 Jul 2024 12:41PM UTC coverage: 61.685% (+0.5%) from 61.217%
10162545933

push

github

web-flow
#433: Implement Intellij plugins installation (#490)

2040 of 3641 branches covered (56.03%)

Branch coverage included in aggregate %.

5419 of 8451 relevant lines covered (64.12%)

2.82 hits per line

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

50.72
cli/src/main/java/com/devonfw/tools/ide/tool/ide/IdeToolCommandlet.java
1
package com.devonfw.tools.ide.tool.ide;
2

3
import java.io.IOException;
4
import java.nio.file.Files;
5
import java.nio.file.Path;
6
import java.util.Collection;
7
import java.util.Collections;
8
import java.util.HashMap;
9
import java.util.Iterator;
10
import java.util.Map;
11
import java.util.Set;
12
import java.util.stream.Stream;
13

14
import com.devonfw.tools.ide.cli.CliException;
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.process.ProcessMode;
19
import com.devonfw.tools.ide.tool.LocalToolCommandlet;
20
import com.devonfw.tools.ide.tool.ToolCommandlet;
21
import com.devonfw.tools.ide.tool.eclipse.Eclipse;
22
import com.devonfw.tools.ide.tool.intellij.Intellij;
23
import com.devonfw.tools.ide.tool.vscode.Vscode;
24

25
/**
26
 * {@link ToolCommandlet} for an IDE (integrated development environment) such as {@link Eclipse}, {@link Vscode}, or {@link Intellij}.
27
 */
28
public abstract class IdeToolCommandlet extends LocalToolCommandlet {
1✔
29

30
  private Map<String, PluginDescriptor> pluginsMap;
31

32
  private Collection<PluginDescriptor> configuredPlugins;
33

34
  /**
35
   * The constructor.
36
   *
37
   * @param context the {@link IdeContext}.
38
   * @param tool the {@link #getName() tool name}.
39
   * @param tags the {@link #getTags() tags} classifying the tool. Should be created via {@link Set#of(Object) Set.of} method.
40
   */
41
  public IdeToolCommandlet(IdeContext context, String tool, Set<Tag> tags) {
42

43
    super(context, tool, tags);
5✔
44
    assert (hasIde(tags));
5!
45
  }
1✔
46

47
  private boolean hasIde(Set<Tag> tags) {
48

49
    for (Tag tag : tags) {
10!
50
      if (tag.isAncestorOf(Tag.IDE)) {
4!
51
        return true;
2✔
52
      }
53
    }
×
54
    throw new IllegalStateException("Tags of IdeTool hat to be connected with tag IDE: " + tags);
×
55
  }
56

57
  private Map<String, PluginDescriptor> getPluginsMap() {
58

59
    if (this.pluginsMap == null) {
3✔
60
      Map<String, PluginDescriptor> map = new HashMap<>();
4✔
61
      Path pluginsPath = getPluginsConfigPath();
3✔
62
      if (Files.isDirectory(pluginsPath)) {
5✔
63
        try (Stream<Path> childStream = Files.list(pluginsPath)) {
3✔
64
          Iterator<Path> iterator = childStream.iterator();
3✔
65
          while (iterator.hasNext()) {
3✔
66
            Path child = iterator.next();
4✔
67
            String filename = child.getFileName().toString();
4✔
68
            if (filename.endsWith(IdeContext.EXT_PROPERTIES) && Files.exists(child)) {
9!
69
              PluginDescriptor descriptor = PluginDescriptorImpl.of(child, this.context, isPluginUrlNeeded());
7✔
70
              map.put(descriptor.getName(), descriptor);
6✔
71
            }
72
          }
1✔
73
        } catch (IOException e) {
×
74
          throw new IllegalStateException("Failed to list children of directory " + pluginsPath, e);
×
75
        }
1✔
76
      }
77
      this.pluginsMap = map;
3✔
78
    }
79
    return this.pluginsMap;
3✔
80
  }
81

82
  private Path getPluginsConfigPath() {
83

84
    return this.context.getSettingsPath().resolve(this.tool).resolve(IdeContext.FOLDER_PLUGINS);
9✔
85
  }
86

87
  /**
88
   * @return {@code true} if {@link PluginDescriptor#getUrl() plugin URL} property is needed, {@code false} otherwise.
89
   */
90
  protected boolean isPluginUrlNeeded() {
91

92
    return false;
2✔
93
  }
94

95
  /**
96
   * @return the immutable {@link Collection} of {@link PluginDescriptor}s configured for this IDE tool.
97
   */
98
  public Collection<PluginDescriptor> getConfiguredPlugins() {
99

100
    if (this.configuredPlugins == null) {
×
101
      this.configuredPlugins = Collections.unmodifiableCollection(getPluginsMap().values());
×
102
    }
103
    return this.configuredPlugins;
×
104
  }
105

106
  /**
107
   * @return the {@link Path} where the plugins of this {@link IdeToolCommandlet} shall be installed.
108
   */
109
  public Path getPluginsInstallationPath() {
110

111
    // TODO add edition???
112
    return this.context.getPluginsPath().resolve(this.tool);
7✔
113
  }
114

115
  public PluginInstaller getPluginInstaller() {
116
    return new PluginInstaller(context, this);
×
117
  }
118

119
  /**
120
   * @param key the filename of the properties file configuring the requested plugin (typically excluding the ".properties" extension).
121
   * @return the {@link PluginDescriptor} for the given {@code key}.
122
   */
123
  public PluginDescriptor getPlugin(String key) {
124

125
    if (key == null) {
×
126
      return null;
×
127
    }
128
    if (key.endsWith(IdeContext.EXT_PROPERTIES)) {
×
129
      key = key.substring(0, key.length() - IdeContext.EXT_PROPERTIES.length());
×
130
    }
131
    PluginDescriptor pluginDescriptor = getPluginsMap().get(key);
×
132
    if (pluginDescriptor == null) {
×
133
      throw new CliException(
×
134
          "Could not find plugin " + key + " at " + getPluginsConfigPath().resolve(key) + ".properties");
×
135
    }
136
    return pluginDescriptor;
×
137
  }
138

139
  @Override
140
  protected boolean doInstall(boolean silent) {
141

142
    boolean newlyInstalled = super.doInstall(silent);
4✔
143
    // post installation...
144
    boolean installPlugins = newlyInstalled;
2✔
145
    Path pluginsInstallationPath = getPluginsInstallationPath();
3✔
146
    if (newlyInstalled) {
2✔
147
      this.context.getFileAccess().delete(pluginsInstallationPath);
6✔
148
    } else if (!Files.isDirectory(pluginsInstallationPath)) {
5✔
149
      installPlugins = true;
2✔
150
    }
151
    if (installPlugins) {
2✔
152
      for (PluginDescriptor plugin : getPluginsMap().values()) {
12✔
153
        if (plugin.isActive()) {
3!
154
          installPlugin(plugin);
4✔
155
        } else {
156
          handleInstall4InactivePlugin(plugin);
×
157
        }
158
      }
1✔
159
    }
160
    return newlyInstalled;
2✔
161
  }
162

163
  /**
164
   * @param plugin the in{@link PluginDescriptor#isActive() active} {@link PluginDescriptor} that is skipped for regular plugin installation.
165
   */
166
  protected void handleInstall4InactivePlugin(PluginDescriptor plugin) {
167

168
    this.context.debug("Omitting installation of inactive plugin {} ({}).", plugin.getName(), plugin.getId());
×
169
  }
×
170

171
  /**
172
   * @param plugin the {@link PluginDescriptor} to install.
173
   */
174
  public abstract void installPlugin(PluginDescriptor plugin);
175

176
  /**
177
   * @param plugin the {@link PluginDescriptor} to uninstall.
178
   */
179
  public void uninstallPlugin(PluginDescriptor plugin) {
180

181
    Path pluginsPath = getPluginsInstallationPath();
×
182
    if (!Files.isDirectory(pluginsPath)) {
×
183
      this.context.debug("Omitting to uninstall plugin {} ({}) as plugins folder does not exist at {}",
×
184
          plugin.getName(), plugin.getId(), pluginsPath);
×
185
      return;
×
186
    }
187
    FileAccess fileAccess = this.context.getFileAccess();
×
188
    Path match = fileAccess.findFirst(pluginsPath, p -> p.getFileName().toString().startsWith(plugin.getId()), false);
×
189
    if (match == null) {
×
190
      this.context.debug("Omitting to uninstall plugin {} ({}) as plugins folder does not contain a match at {}",
×
191
          plugin.getName(), plugin.getId(), pluginsPath);
×
192
      return;
×
193
    }
194
    fileAccess.delete(match);
×
195
  }
×
196

197
  @Override
198
  public void run() {
199

200
    configureWorkspace();
2✔
201
    runIde(this.arguments.asArray());
5✔
202
  }
1✔
203

204
  /**
205
   * Run the actual IDE.
206
   *
207
   * @param args the additional arguments to pass to the IDE.
208
   */
209
  protected void runIde(String... args) {
210

211
    runTool(ProcessMode.DEFAULT, null, args);
5✔
212
  }
1✔
213

214
  /**
215
   * Configure the workspace for this IDE using the templates from the settings.
216
   */
217
  protected void configureWorkspace() {
218

219
    Path settingsWorkspaceFolder = this.context.getSettingsPath().resolve(this.tool)
7✔
220
        .resolve(IdeContext.FOLDER_WORKSPACE);
2✔
221
    FileAccess fileAccess = this.context.getFileAccess();
4✔
222
    if (!fileAccess.isExpectedFolder(settingsWorkspaceFolder)) {
4!
223
      return;
1✔
224
    }
225
    Path setupFolder = settingsWorkspaceFolder.resolve(IdeContext.FOLDER_SETUP);
×
226
    Path updateFolder = settingsWorkspaceFolder.resolve(IdeContext.FOLDER_UPDATE);
×
227
    if (!fileAccess.isExpectedFolder(setupFolder) && !fileAccess.isExpectedFolder(updateFolder)) {
×
228
      return;
×
229
    }
230
    Path ideWorkspacePath = this.context.getWorkspacePath();
×
231
    if (!fileAccess.isExpectedFolder(ideWorkspacePath)) {
×
232
      return; // should actually never happen...
×
233
    }
234
    this.context.step("Configuring workspace {} for IDE {}", ideWorkspacePath.getFileName(), this.tool);
×
235
    this.context.getWorkspaceMerger().merge(setupFolder, updateFolder, this.context.getVariables(), ideWorkspacePath);
×
236
  }
×
237

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