Skip to content

Commit 824b5e9

Browse files
authored
#37: Tool commandlet for visual studio code (#538)
1 parent 3ddcdd7 commit 824b5e9

File tree

10 files changed

+203
-10
lines changed

10 files changed

+203
-10
lines changed

CHANGELOG.adoc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ This file documents all notable changes to https://github.com/devonfw/IDEasy[IDE
77
Release with new features and bugfixes:
88

99
* https://github.com/devonfw/IDEasy/issues/628[#638]: Fixed update fails on first error
10-
* https://github.com/devonfw/IDEasy/issues/553[#554]: Missmatch of IDE_ROOT
10+
* https://github.com/devonfw/IDEasy/issues/37[#37]: Added Visual Studio Code (vscode) with plugin installation and plugin recommendation support
11+
* https://github.com/devonfw/IDEasy/issues/553[#553]: Mismatch of IDE_ROOT
1112
* https://github.com/devonfw/IDEasy/issues/556[#556]: ProcessContext should compute PATH on run and not in constructor
1213
* https://github.com/devonfw/IDEasy/issues/557[#557]: Failed to update tomcat: Cannot find a (Map) Key deserializer for type VersionRange
1314
* https://github.com/devonfw/IDEasy/issues/623[#623]: CliArgument prepand and append methods inconsistent

cli/src/main/java/com/devonfw/tools/ide/tool/plugin/PluginBasedCommandlet.java

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import java.nio.file.Files;
44
import java.nio.file.Path;
5+
import java.util.Collection;
56
import java.util.List;
67
import java.util.Set;
78

@@ -151,19 +152,35 @@ protected boolean doInstall(boolean silent) {
151152
} else if (!Files.isDirectory(pluginsInstallationPath)) {
152153
installPlugins = true;
153154
}
155+
createExtensionFolder();
154156
if (installPlugins) {
155157
PluginMaps pluginMaps = getPluginsMap();
156-
for (PluginDescriptor plugin : pluginMaps.getPlugins()) {
157-
if (plugin.isActive()) {
158-
installPlugin(plugin);
159-
} else {
160-
handleInstall4InactivePlugin(plugin);
161-
}
162-
}
158+
Collection<PluginDescriptor> plugins = pluginMaps.getPlugins();
159+
installPlugins(plugins);
163160
}
164161
return newlyInstalled;
165162
}
166163

164+
private void createExtensionFolder() {
165+
Path extensionFolder = this.context.getIdeHome().resolve("plugins").resolve(this.tool);
166+
this.context.getFileAccess().mkdirs(extensionFolder);
167+
}
168+
169+
/**
170+
* Method to install active plugins or to handle install for inactive plugins
171+
*
172+
* @param plugins as {@link Collection} of plugins to install.
173+
*/
174+
protected void installPlugins(Collection<PluginDescriptor> plugins) {
175+
for (PluginDescriptor plugin : plugins) {
176+
if (plugin.isActive()) {
177+
installPlugin(plugin);
178+
} else {
179+
handleInstall4InactivePlugin(plugin);
180+
}
181+
}
182+
}
183+
167184
/**
168185
* @param plugin the in{@link PluginDescriptor#isActive() active} {@link PluginDescriptor} that is skipped for regular plugin installation.
169186
*/

cli/src/main/java/com/devonfw/tools/ide/tool/vscode/Vscode.java

Lines changed: 117 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,33 @@
11
package com.devonfw.tools.ide.tool.vscode;
22

3+
import java.io.BufferedReader;
4+
import java.io.IOException;
5+
import java.nio.file.Files;
6+
import java.nio.file.Path;
7+
import java.util.ArrayList;
8+
import java.util.Arrays;
9+
import java.util.Collection;
10+
import java.util.HashMap;
11+
import java.util.HashSet;
12+
import java.util.List;
13+
import java.util.Map;
314
import java.util.Set;
415

516
import com.devonfw.tools.ide.common.Tag;
617
import com.devonfw.tools.ide.context.IdeContext;
7-
import com.devonfw.tools.ide.tool.LocalToolCommandlet;
18+
import com.devonfw.tools.ide.process.ProcessContext;
19+
import com.devonfw.tools.ide.process.ProcessErrorHandling;
20+
import com.devonfw.tools.ide.process.ProcessMode;
821
import com.devonfw.tools.ide.tool.ToolCommandlet;
22+
import com.devonfw.tools.ide.tool.ide.IdeToolCommandlet;
23+
import com.devonfw.tools.ide.tool.plugin.PluginDescriptor;
24+
import com.devonfw.tools.ide.version.VersionIdentifier;
25+
import com.fasterxml.jackson.databind.ObjectMapper;
926

1027
/**
1128
* {@link ToolCommandlet} for <a href="https://code.visualstudio.com/">vscode</a>.
1229
*/
13-
public class Vscode extends LocalToolCommandlet {
30+
public class Vscode extends IdeToolCommandlet {
1431

1532
/**
1633
* The constructor.
@@ -28,4 +45,102 @@ protected String getBinaryName() {
2845
return "code";
2946
}
3047

48+
@Override
49+
public void installPlugin(PluginDescriptor plugin) {
50+
51+
}
52+
53+
@Override
54+
protected void installPlugins(Collection<PluginDescriptor> plugins) {
55+
56+
List<PluginDescriptor> pluginsToInstall = new ArrayList<>();
57+
List<PluginDescriptor> pluginsToRecommend = new ArrayList<>();
58+
59+
for (PluginDescriptor plugin : plugins) {
60+
if (plugin.isActive()) {
61+
pluginsToInstall.add(plugin);
62+
} else {
63+
pluginsToRecommend.add(plugin);
64+
}
65+
}
66+
doAddRecommendations(pluginsToRecommend);
67+
doInstallPlugins(pluginsToInstall);
68+
69+
}
70+
71+
private void doInstallPlugins(List<PluginDescriptor> pluginsToInstall) {
72+
73+
List<String> extensionsCommands = new ArrayList<>();
74+
75+
if (pluginsToInstall.isEmpty()) {
76+
this.context.info("No plugins to be installed");
77+
} else {
78+
79+
for (PluginDescriptor plugin : pluginsToInstall) {
80+
extensionsCommands.add("--install-extension");
81+
extensionsCommands.add(plugin.getId());
82+
}
83+
}
84+
runTool(ProcessMode.DEFAULT, null, extensionsCommands.toArray(new String[0]));
85+
}
86+
87+
private void doAddRecommendations(List<PluginDescriptor> recommendations) {
88+
Path extensionsJsonPath = this.context.getWorkspacePath().resolve(".vscode/extensions.json");
89+
90+
ObjectMapper objectMapper = new ObjectMapper();
91+
Map<String, Object> recommendationsMap;
92+
93+
if (Files.exists(extensionsJsonPath)) {
94+
try (BufferedReader reader = Files.newBufferedReader(extensionsJsonPath)) {
95+
recommendationsMap = objectMapper.readValue(reader, Map.class);
96+
} catch (IOException e) {
97+
throw new RuntimeException(e);
98+
}
99+
} else {
100+
recommendationsMap = new HashMap<>();
101+
}
102+
103+
List<String> existingRecommendations = (List<String>) recommendationsMap.getOrDefault("recommendations", new ArrayList<>());
104+
105+
try {
106+
int addedRecommendations = 0;
107+
Set<String> existingRecommendationsSet = new HashSet<>(existingRecommendations);
108+
for (PluginDescriptor recommendation : recommendations) {
109+
String recommendationId = recommendation.getId();
110+
if (existingRecommendationsSet.add(recommendationId)) {
111+
existingRecommendations.add(recommendationId);
112+
addedRecommendations++;
113+
}
114+
}
115+
116+
if (addedRecommendations > 0) {
117+
objectMapper.writeValue(extensionsJsonPath.toFile(), recommendationsMap);
118+
}
119+
120+
} catch (IOException e) {
121+
this.context.error(e);
122+
}
123+
}
124+
125+
@Override
126+
public void runTool(ProcessMode processMode, VersionIdentifier toolVersion, String... args) {
127+
128+
install(true);
129+
130+
Path vsCodeConf = this.context.getWorkspacePath().resolve(".vscode/.userdata");
131+
Path vsCodeExtensionFolder = this.context.getIdeHome().resolve("plugins/vscode");
132+
133+
List<String> command = new ArrayList<>();
134+
command.add("--new-window");
135+
command.add("--user-data-dir=" + vsCodeConf);
136+
command.add("--extensions-dir=" + vsCodeExtensionFolder);
137+
138+
command.addAll(Arrays.asList(args));
139+
140+
Path binaryPath;
141+
binaryPath = Path.of(getBinaryName());
142+
ProcessContext pc = this.context.newProcess().errorHandling(ProcessErrorHandling.THROW).executable(binaryPath).addArgs(command.toArray());
143+
pc.run(processMode);
144+
}
145+
31146
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package com.devonfw.tools.ide.tool.vscode;
2+
3+
import org.junit.jupiter.api.Test;
4+
5+
import com.devonfw.tools.ide.context.AbstractIdeContextTest;
6+
import com.devonfw.tools.ide.context.IdeTestContext;
7+
8+
/**
9+
* Test of {@link Vscode} class.
10+
*/
11+
public class VscodeTest extends AbstractIdeContextTest {
12+
13+
private static final String PROJECT_VSCODE = "vscode";
14+
15+
16+
@Test
17+
public void testVscodeInstall() {
18+
19+
// arrange
20+
IdeTestContext context = newContext(PROJECT_VSCODE);
21+
Vscode vscodeCommandlet = new Vscode(context);
22+
23+
// install
24+
vscodeCommandlet.install();
25+
26+
// assert
27+
checkInstallation(context);
28+
}
29+
30+
private void checkInstallation(IdeTestContext context) {
31+
32+
assertThat(context.getSoftwarePath().resolve("vscode/bin/code.cmd")).exists().hasContent("@echo test for windows");
33+
assertThat(context.getSoftwarePath().resolve("vscode/bin/code")).exists().hasContent("#!/bin/bash\n" + "echo \"Test for linux and Mac\"");
34+
35+
assertThat(context.getSoftwarePath().resolve("vscode/.ide.software.version")).exists().hasContent("1.92.1");
36+
assertThat(context).logAtSuccess().hasMessage("Successfully installed vscode in version 1.92.1");
37+
38+
//check plugins folder
39+
assertThat(context.getIdeHome().resolve("plugins").resolve("vscode")).exists();
40+
41+
//check Recommendations
42+
assertThat(context.getWorkspacePath().resolve(".vscode").resolve("extensions.json")).exists()
43+
.hasContent("{\"recommendations\":[\"esbenp.prettier-vscode\",\"mockedPlugin2\"]}");
44+
}
45+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
VSCODE_VERSION=1.92.1
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
plugin_id=mockedPlugin2
2+
plugin_active=false
3+
tags=mocking
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
plugin_id=mockedPlugin
2+
plugin_active=true
3+
tags=mocking
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"recommendations": [
3+
"esbenp.prettier-vscode"
4+
]
5+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#!/bin/bash
2+
echo "Test for linux and Mac"
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
@echo test for windows

0 commit comments

Comments
 (0)