Skip to content

Commit 78cf4b6

Browse files
authored
#479: android studio plugin support (#529)
1 parent 9d7a30a commit 78cf4b6

File tree

15 files changed

+75
-35
lines changed

15 files changed

+75
-35
lines changed

cli/src/main/java/com/devonfw/tools/ide/os/MacOsHelper.java

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import com.devonfw.tools.ide.context.IdeContext;
1111
import com.devonfw.tools.ide.io.FileAccess;
1212
import com.devonfw.tools.ide.log.IdeLogger;
13+
import com.devonfw.tools.ide.repo.ToolRepository;
1314
import com.devonfw.tools.ide.tool.ToolCommandlet;
1415

1516
/**
@@ -51,6 +52,15 @@ public MacOsHelper(FileAccess fileAccess, SystemInfo systemInfo, IdeLogger logge
5152
this.logger = logger;
5253
}
5354

55+
/**
56+
* @param rootDir the {@link Path} to the root directory.
57+
* @return the path to the app directory.
58+
*/
59+
public Path findAppDir(Path rootDir) {
60+
return this.fileAccess.findFirst(rootDir,
61+
p -> p.getFileName().toString().endsWith(".app") && Files.isDirectory(p), false);
62+
}
63+
5464
/**
5565
* @param rootDir the {@link Path} to the root directory.
5666
* @param tool the name of the tool to find the link directory for.
@@ -65,8 +75,7 @@ public Path findLinkDir(Path rootDir, String tool) {
6575
if (Files.isDirectory(contentsDir)) {
6676
return findLinkDir(contentsDir, rootDir, tool);
6777
}
68-
Path appDir = this.fileAccess.findFirst(rootDir,
69-
p -> p.getFileName().toString().endsWith(".app") && Files.isDirectory(p), false);
78+
Path appDir = findAppDir(rootDir);
7079
if (appDir != null) {
7180
contentsDir = appDir.resolve(IdeContext.FOLDER_CONTENTS);
7281
if (Files.isDirectory(contentsDir)) {
@@ -84,7 +93,8 @@ public Path findLinkDir(Path rootDir, String tool) {
8493
* @return a {@link String}
8594
*/
8695
public Path findRootToolPath(ToolCommandlet commandlet, IdeContext context) {
87-
return context.getSoftwareRepositoryPath().resolve("default").resolve(commandlet.getName()).resolve(commandlet.getName())
96+
return context.getSoftwareRepositoryPath().resolve(ToolRepository.ID_DEFAULT).resolve(commandlet.getName())
97+
.resolve(commandlet.getInstalledEdition().toString())
8898
.resolve(commandlet.getInstalledVersion().toString());
8999
}
90100

cli/src/main/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudio.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import com.devonfw.tools.ide.environment.EnvironmentVariablesType;
1010
import com.devonfw.tools.ide.process.ProcessMode;
1111
import com.devonfw.tools.ide.tool.ide.IdeToolCommandlet;
12+
import com.devonfw.tools.ide.tool.ide.IdeaBasedPluginInstaller;
1213
import com.devonfw.tools.ide.tool.ide.PluginDescriptor;
1314
import com.devonfw.tools.ide.version.VersionIdentifier;
1415

@@ -66,6 +67,9 @@ protected void postInstall() {
6667

6768
@Override
6869
public void installPlugin(PluginDescriptor plugin) {
69-
// TODO: needs to be implemented see: https://github.com/devonfw/IDEasy/issues/433
70+
71+
IdeaBasedPluginInstaller pluginInstaller = new IdeaBasedPluginInstaller(context, this);
72+
String downloadUrl = pluginInstaller.getDownloadUrl(plugin);
73+
pluginInstaller.installPlugin(plugin, downloadUrl);
7074
}
7175
}

cli/src/main/java/com/devonfw/tools/ide/tool/ide/IdeToolCommandlet.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,5 +234,4 @@ protected void configureWorkspace() {
234234
this.context.step("Configuring workspace {} for IDE {}", ideWorkspacePath.getFileName(), this.tool);
235235
this.context.getWorkspaceMerger().merge(setupFolder, updateFolder, this.context.getVariables(), ideWorkspacePath);
236236
}
237-
238237
}
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,27 @@
1-
package com.devonfw.tools.ide.tool.intellij;
1+
package com.devonfw.tools.ide.tool.ide;
22

33
import java.io.IOException;
44
import java.nio.file.Files;
55
import java.nio.file.Path;
66

77
import com.devonfw.tools.ide.context.IdeContext;
88
import com.devonfw.tools.ide.os.MacOsHelper;
9-
import com.devonfw.tools.ide.tool.ide.IdeToolCommandlet;
10-
import com.devonfw.tools.ide.tool.ide.PluginDescriptor;
11-
import com.devonfw.tools.ide.tool.ide.PluginInstaller;
129

1310
/**
14-
* Plugin Installer for {@link Intellij}.
11+
* Manager class to install plugins for the {@link IdeToolCommandlet commandlet}.
1512
*/
16-
public class IntellijPluginInstaller extends PluginInstaller {
13+
public class IdeaBasedPluginInstaller extends PluginInstaller {
1714

1815
private static final String BUILD_FILE = "build.txt";
1916

2017
/**
21-
* The constructor.
18+
* The constructor
2219
*
2320
* @param context the {@link IdeContext}.
24-
* @param commandlet the {@link IdeToolCommandlet}
21+
* @param commandlet the {@link IdeToolCommandlet commandlet}.
2522
*/
26-
public IntellijPluginInstaller(IdeContext context, IdeToolCommandlet commandlet) {
23+
public IdeaBasedPluginInstaller(IdeContext context, IdeToolCommandlet commandlet) {
24+
2725
super(context, commandlet);
2826
}
2927

@@ -47,23 +45,14 @@ private String readBuildVersion() {
4745
Path buildFile = commandlet.getToolPath().resolve(BUILD_FILE);
4846
if (context.getSystemInfo().isMac()) {
4947
MacOsHelper macOsHelper = new MacOsHelper(context);
50-
Path rootToolPath = macOsHelper.findRootToolPath(this.commandlet, context);
51-
buildFile = rootToolPath.resolve("IntelliJ IDEA" + generateMacEditionString() + ".app").resolve("Contents/Resources").resolve(BUILD_FILE);
48+
Path appPath = macOsHelper.findAppDir(macOsHelper.findRootToolPath(this.commandlet, context));
49+
buildFile = appPath.resolve("Contents/Resources").resolve(BUILD_FILE);
5250
}
5351
try {
5452
return Files.readString(buildFile);
5553
} catch (IOException e) {
56-
throw new IllegalStateException("Failed to read IntelliJ build version: " + buildFile, e);
57-
}
58-
}
59-
60-
private String generateMacEditionString() {
61-
62-
String edition = "";
63-
if (commandlet.getConfiguredEdition().equals("intellij")) {
64-
edition = " CE";
54+
throw new IllegalStateException("Failed to read " + commandlet.getName() + " build version: " + buildFile, e);
6555
}
66-
return edition;
6756
}
6857

6958
}

cli/src/main/java/com/devonfw/tools/ide/tool/intellij/Intellij.java

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import com.devonfw.tools.ide.environment.EnvironmentVariablesType;
1010
import com.devonfw.tools.ide.process.ProcessMode;
1111
import com.devonfw.tools.ide.tool.ide.IdeToolCommandlet;
12+
import com.devonfw.tools.ide.tool.ide.IdeaBasedPluginInstaller;
1213
import com.devonfw.tools.ide.tool.ide.PluginDescriptor;
1314
import com.devonfw.tools.ide.tool.java.Java;
1415
import com.devonfw.tools.ide.version.VersionIdentifier;
@@ -73,14 +74,8 @@ protected void postInstall() {
7374
@Override
7475
public void installPlugin(PluginDescriptor plugin) {
7576

76-
IntellijPluginInstaller pluginInstaller = this.getPluginInstaller();
77+
IdeaBasedPluginInstaller pluginInstaller = new IdeaBasedPluginInstaller(context, this);
7778
String downloadUrl = pluginInstaller.getDownloadUrl(plugin);
7879
pluginInstaller.installPlugin(plugin, downloadUrl);
7980
}
80-
81-
@Override
82-
public IntellijPluginInstaller getPluginInstaller() {
83-
return new IntellijPluginInstaller(context, this);
84-
}
85-
8681
}

cli/src/test/java/com/devonfw/tools/ide/io/IdeProgressBarTest.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ public class IdeProgressBarTest extends AbstractIdeContextTest {
2525
* Tests if a download of a file with a valid content length was displaying an {@link IdeProgressBar} properly.
2626
*
2727
* @param tempDir temporary directory to use.
28+
* @param wmRuntimeInfo wireMock server on a random port
2829
*/
2930
@Test
3031
public void testProgressBarDownloadWithValidContentLength(@TempDir Path tempDir, WireMockRuntimeInfo wmRuntimeInfo) {

cli/src/test/java/com/devonfw/tools/ide/tool/UrlUpdaterTest.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ public class UrlUpdaterTest extends AbstractUrlUpdaterTest {
3434
* Tests if the {@link com.devonfw.tools.ide.url.updater.UrlUpdater} can automatically add a missing OS (in this case the linux_x64)
3535
*
3636
* @param tempDir Temporary directory
37+
* @param wmRuntimeInfo wireMock server on a random port
3738
* @throws IOException test fails
3839
*/
3940
@Test
@@ -99,6 +100,7 @@ public void testUrlUpdaterIsNotUpdatingWhenStatusManualIsTrue(@TempDir Path temp
99100
* See: <a href="https://github.com/devonfw/ide/issues/1343">#1343</a> for reference.
100101
*
101102
* @param tempDir Temporary directory
103+
* @param wmRuntimeInfo wireMock server on a random port
102104
*/
103105
@Test
104106
public void testUrlUpdaterStatusJsonRefreshBugStillExisting(@TempDir Path tempDir, WireMockRuntimeInfo wmRuntimeInfo) {
@@ -172,6 +174,7 @@ public void testUrlUpdaterStatusJsonRefreshBugStillExisting(@TempDir Path tempDi
172174
* See: <a href="https://github.com/devonfw/ide/issues/1343">#1343</a> for reference.
173175
*
174176
* @param tempDir Temporary directory
177+
* @param wmRuntimeInfo wireMock server on a random port
175178
*/
176179
@Test
177180
public void testUrlUpdaterWithTextContentTypeWillNotCreateStatusJson(@TempDir Path tempDir, WireMockRuntimeInfo wmRuntimeInfo) {

cli/src/test/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudioTest.java

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,47 @@
11
package com.devonfw.tools.ide.tool.androidstudio;
22

3+
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
4+
import static com.github.tomakehurst.wiremock.client.WireMock.any;
5+
import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
6+
import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
7+
8+
import java.io.IOException;
9+
import java.nio.charset.StandardCharsets;
10+
import java.nio.file.Files;
11+
import java.nio.file.Path;
12+
313
import org.junit.jupiter.params.ParameterizedTest;
414
import org.junit.jupiter.params.provider.ValueSource;
515

616
import com.devonfw.tools.ide.context.AbstractIdeContextTest;
717
import com.devonfw.tools.ide.context.IdeTestContext;
818
import com.devonfw.tools.ide.os.SystemInfo;
919
import com.devonfw.tools.ide.os.SystemInfoMock;
20+
import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo;
21+
import com.github.tomakehurst.wiremock.junit5.WireMockTest;
1022

1123
/**
1224
* Test class for {@link AndroidStudio Android Studio IDE} tests.
1325
*/
26+
@WireMockTest
1427
public class AndroidStudioTest extends AbstractIdeContextTest {
1528

1629
private static final String ANDROID_STUDIO = "android-studio";
30+
private static final String MOCKED_PLUGIN_JAR = "mocked-plugin.jar";
1731

1832
private final IdeTestContext context = newContext(ANDROID_STUDIO);
1933

2034
/**
2135
* Tests if {@link AndroidStudio Android Studio IDE} can be installed.
2236
*
2337
* @param os String of the OS to use.
38+
* @param wmRuntimeInfo wireMock server on a random port
2439
*/
2540
@ParameterizedTest
2641
@ValueSource(strings = { "windows", "mac", "linux" })
27-
public void testAndroidStudioInstall(String os) {
42+
public void testAndroidStudioInstall(String os, WireMockRuntimeInfo wmRuntimeInfo) throws IOException {
2843
// arrange
44+
setupMockedPlugin(wmRuntimeInfo);
2945
SystemInfo systemInfo = SystemInfoMock.of(os);
3046
this.context.setSystemInfo(systemInfo);
3147
AndroidStudio commandlet = new AndroidStudio(this.context);
@@ -41,11 +57,13 @@ public void testAndroidStudioInstall(String os) {
4157
* Tests if {@link AndroidStudio Android Studio IDE} can be run.
4258
*
4359
* @param os String of the OS to use.
60+
* @param wmRuntimeInfo wireMock server on a random port
4461
*/
4562
@ParameterizedTest
4663
@ValueSource(strings = { "windows", "mac", "linux" })
47-
public void testAndroidStudioRun(String os) {
64+
public void testAndroidStudioRun(String os, WireMockRuntimeInfo wmRuntimeInfo) throws IOException {
4865
// arrange
66+
setupMockedPlugin(wmRuntimeInfo);
4967
SystemInfo systemInfo = SystemInfoMock.of(os);
5068
this.context.setSystemInfo(systemInfo);
5169
AndroidStudio commandlet = new AndroidStudio(this.context);
@@ -64,6 +82,22 @@ private void checkInstallation(IdeTestContext context) {
6482
assertThat(context.getSoftwarePath().resolve("android-studio/.ide.software.version")).exists().hasContent("2024.1.1.1");
6583
assertThat(context.getVariables().get("STUDIO_PROPERTIES")).isEqualTo(context.getWorkspacePath().resolve("studio.properties").toString());
6684
assertThat(context).logAtSuccess().hasMessage("Successfully installed android-studio in version 2024.1.1.1");
85+
assertThat(context).logAtSuccess().hasMessage("Install plugin: mockedPlugin");
86+
assertThat(context.getPluginsPath().resolve("android-studio").resolve("mockedPlugin").resolve("MockedClass.class")).exists();
6787
}
6888

89+
private void setupMockedPlugin(WireMockRuntimeInfo wmRuntimeInfo) throws IOException {
90+
91+
String content = "plugin_id=mockedPlugin\nplugin_active=true\nplugin_url=" + wmRuntimeInfo.getHttpBaseUrl() + "/mockedPlugin";
92+
Files.write(this.context.getSettingsPath().resolve("android-studio").resolve("plugins").resolve("MockedPlugin.properties"),
93+
content.getBytes(StandardCharsets.UTF_8));
94+
95+
Path mockedPlugin = this.context.getIdeRoot().resolve("repository").resolve(MOCKED_PLUGIN_JAR);
96+
byte[] contentBytes = Files.readAllBytes(mockedPlugin);
97+
int contentLength = contentBytes.length;
98+
99+
stubFor(any(urlEqualTo("/mockedPlugin")).willReturn(
100+
aResponse().withStatus(200).withHeader("Content-Type", "application/java-archive").withHeader("Content-Length", String.valueOf(contentLength))
101+
.withBody(contentBytes)));
102+
}
69103
}

cli/src/test/java/com/devonfw/tools/ide/tool/intellij/IntellijTest.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ public class IntellijTest extends AbstractIdeContextTest {
3434
* Tests if the {@link Intellij} can be installed properly.
3535
*
3636
* @param os String of the OS to use.
37+
* @param wmRuntimeInfo wireMock server on a random port
3738
* @throws IOException if reading the content of the mocked plugin fails
3839
*/
3940
@ParameterizedTest

cli/src/test/java/com/devonfw/tools/ide/tool/pip/PipUrlUpdaterTest.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ public class PipUrlUpdaterTest extends AbstractUrlUpdaterTest {
3030
* See: <a href="https://github.com/devonfw/ide/issues/1343">#1343</a> for reference.
3131
*
3232
* @param tempDir Temporary directory
33+
* @param wmRuntimeInfo wireMock server on a random port
3334
*/
3435
@Test
3536
public void testPipUrlUpdaterWithTextContentTypeWillSucceed(@TempDir Path tempDir, WireMockRuntimeInfo wmRuntimeInfo) {

0 commit comments

Comments
 (0)