Skip to content

Commit

Permalink
devonfw#37: Tool commandlet for visual studio code (devonfw#538)
Browse files Browse the repository at this point in the history
  • Loading branch information
aBega2000 authored Sep 24, 2024
1 parent 3ddcdd7 commit 824b5e9
Show file tree
Hide file tree
Showing 10 changed files with 203 additions and 10 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ This file documents all notable changes to https://github.com/devonfw/IDEasy[IDE
Release with new features and bugfixes:

* https://github.com/devonfw/IDEasy/issues/628[#638]: Fixed update fails on first error
* https://github.com/devonfw/IDEasy/issues/553[#554]: Missmatch of IDE_ROOT
* https://github.com/devonfw/IDEasy/issues/37[#37]: Added Visual Studio Code (vscode) with plugin installation and plugin recommendation support
* https://github.com/devonfw/IDEasy/issues/553[#553]: Mismatch of IDE_ROOT
* https://github.com/devonfw/IDEasy/issues/556[#556]: ProcessContext should compute PATH on run and not in constructor
* https://github.com/devonfw/IDEasy/issues/557[#557]: Failed to update tomcat: Cannot find a (Map) Key deserializer for type VersionRange
* https://github.com/devonfw/IDEasy/issues/623[#623]: CliArgument prepand and append methods inconsistent
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collection;
import java.util.List;
import java.util.Set;

Expand Down Expand Up @@ -151,19 +152,35 @@ protected boolean doInstall(boolean silent) {
} else if (!Files.isDirectory(pluginsInstallationPath)) {
installPlugins = true;
}
createExtensionFolder();
if (installPlugins) {
PluginMaps pluginMaps = getPluginsMap();
for (PluginDescriptor plugin : pluginMaps.getPlugins()) {
if (plugin.isActive()) {
installPlugin(plugin);
} else {
handleInstall4InactivePlugin(plugin);
}
}
Collection<PluginDescriptor> plugins = pluginMaps.getPlugins();
installPlugins(plugins);
}
return newlyInstalled;
}

private void createExtensionFolder() {
Path extensionFolder = this.context.getIdeHome().resolve("plugins").resolve(this.tool);
this.context.getFileAccess().mkdirs(extensionFolder);
}

/**
* Method to install active plugins or to handle install for inactive plugins
*
* @param plugins as {@link Collection} of plugins to install.
*/
protected void installPlugins(Collection<PluginDescriptor> plugins) {
for (PluginDescriptor plugin : plugins) {
if (plugin.isActive()) {
installPlugin(plugin);
} else {
handleInstall4InactivePlugin(plugin);
}
}
}

/**
* @param plugin the in{@link PluginDescriptor#isActive() active} {@link PluginDescriptor} that is skipped for regular plugin installation.
*/
Expand Down
119 changes: 117 additions & 2 deletions cli/src/main/java/com/devonfw/tools/ide/tool/vscode/Vscode.java
Original file line number Diff line number Diff line change
@@ -1,16 +1,33 @@
package com.devonfw.tools.ide.tool.vscode;

import java.io.BufferedReader;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.devonfw.tools.ide.common.Tag;
import com.devonfw.tools.ide.context.IdeContext;
import com.devonfw.tools.ide.tool.LocalToolCommandlet;
import com.devonfw.tools.ide.process.ProcessContext;
import com.devonfw.tools.ide.process.ProcessErrorHandling;
import com.devonfw.tools.ide.process.ProcessMode;
import com.devonfw.tools.ide.tool.ToolCommandlet;
import com.devonfw.tools.ide.tool.ide.IdeToolCommandlet;
import com.devonfw.tools.ide.tool.plugin.PluginDescriptor;
import com.devonfw.tools.ide.version.VersionIdentifier;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
* {@link ToolCommandlet} for <a href="https://code.visualstudio.com/">vscode</a>.
*/
public class Vscode extends LocalToolCommandlet {
public class Vscode extends IdeToolCommandlet {

/**
* The constructor.
Expand All @@ -28,4 +45,102 @@ protected String getBinaryName() {
return "code";
}

@Override
public void installPlugin(PluginDescriptor plugin) {

}

@Override
protected void installPlugins(Collection<PluginDescriptor> plugins) {

List<PluginDescriptor> pluginsToInstall = new ArrayList<>();
List<PluginDescriptor> pluginsToRecommend = new ArrayList<>();

for (PluginDescriptor plugin : plugins) {
if (plugin.isActive()) {
pluginsToInstall.add(plugin);
} else {
pluginsToRecommend.add(plugin);
}
}
doAddRecommendations(pluginsToRecommend);
doInstallPlugins(pluginsToInstall);

}

private void doInstallPlugins(List<PluginDescriptor> pluginsToInstall) {

List<String> extensionsCommands = new ArrayList<>();

if (pluginsToInstall.isEmpty()) {
this.context.info("No plugins to be installed");
} else {

for (PluginDescriptor plugin : pluginsToInstall) {
extensionsCommands.add("--install-extension");
extensionsCommands.add(plugin.getId());
}
}
runTool(ProcessMode.DEFAULT, null, extensionsCommands.toArray(new String[0]));
}

private void doAddRecommendations(List<PluginDescriptor> recommendations) {
Path extensionsJsonPath = this.context.getWorkspacePath().resolve(".vscode/extensions.json");

ObjectMapper objectMapper = new ObjectMapper();
Map<String, Object> recommendationsMap;

if (Files.exists(extensionsJsonPath)) {
try (BufferedReader reader = Files.newBufferedReader(extensionsJsonPath)) {
recommendationsMap = objectMapper.readValue(reader, Map.class);
} catch (IOException e) {
throw new RuntimeException(e);
}
} else {
recommendationsMap = new HashMap<>();
}

List<String> existingRecommendations = (List<String>) recommendationsMap.getOrDefault("recommendations", new ArrayList<>());

try {
int addedRecommendations = 0;
Set<String> existingRecommendationsSet = new HashSet<>(existingRecommendations);
for (PluginDescriptor recommendation : recommendations) {
String recommendationId = recommendation.getId();
if (existingRecommendationsSet.add(recommendationId)) {
existingRecommendations.add(recommendationId);
addedRecommendations++;
}
}

if (addedRecommendations > 0) {
objectMapper.writeValue(extensionsJsonPath.toFile(), recommendationsMap);
}

} catch (IOException e) {
this.context.error(e);
}
}

@Override
public void runTool(ProcessMode processMode, VersionIdentifier toolVersion, String... args) {

install(true);

Path vsCodeConf = this.context.getWorkspacePath().resolve(".vscode/.userdata");
Path vsCodeExtensionFolder = this.context.getIdeHome().resolve("plugins/vscode");

List<String> command = new ArrayList<>();
command.add("--new-window");
command.add("--user-data-dir=" + vsCodeConf);
command.add("--extensions-dir=" + vsCodeExtensionFolder);

command.addAll(Arrays.asList(args));

Path binaryPath;
binaryPath = Path.of(getBinaryName());
ProcessContext pc = this.context.newProcess().errorHandling(ProcessErrorHandling.THROW).executable(binaryPath).addArgs(command.toArray());
pc.run(processMode);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.devonfw.tools.ide.tool.vscode;

import org.junit.jupiter.api.Test;

import com.devonfw.tools.ide.context.AbstractIdeContextTest;
import com.devonfw.tools.ide.context.IdeTestContext;

/**
* Test of {@link Vscode} class.
*/
public class VscodeTest extends AbstractIdeContextTest {

private static final String PROJECT_VSCODE = "vscode";


@Test
public void testVscodeInstall() {

// arrange
IdeTestContext context = newContext(PROJECT_VSCODE);
Vscode vscodeCommandlet = new Vscode(context);

// install
vscodeCommandlet.install();

// assert
checkInstallation(context);
}

private void checkInstallation(IdeTestContext context) {

assertThat(context.getSoftwarePath().resolve("vscode/bin/code.cmd")).exists().hasContent("@echo test for windows");
assertThat(context.getSoftwarePath().resolve("vscode/bin/code")).exists().hasContent("#!/bin/bash\n" + "echo \"Test for linux and Mac\"");

assertThat(context.getSoftwarePath().resolve("vscode/.ide.software.version")).exists().hasContent("1.92.1");
assertThat(context).logAtSuccess().hasMessage("Successfully installed vscode in version 1.92.1");

//check plugins folder
assertThat(context.getIdeHome().resolve("plugins").resolve("vscode")).exists();

//check Recommendations
assertThat(context.getWorkspacePath().resolve(".vscode").resolve("extensions.json")).exists()
.hasContent("{\"recommendations\":[\"esbenp.prettier-vscode\",\"mockedPlugin2\"]}");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
VSCODE_VERSION=1.92.1
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
plugin_id=mockedPlugin2
plugin_active=false
tags=mocking
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
plugin_id=mockedPlugin
plugin_active=true
tags=mocking
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"recommendations": [
"esbenp.prettier-vscode"
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/bin/bash
echo "Test for linux and Mac"
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@echo test for windows

0 comments on commit 824b5e9

Please sign in to comment.