[devkit] include native roots of libraries to the plugin distribution (IDEA-81939)

GitOrigin-RevId: b93969fde8fe36effd4b0852b211c2926b31bf0c
This commit is contained in:
Nikolay Chashnikov
2020-05-08 10:13:26 +00:00
committed by intellij-monorepo-bot
parent b7aa39cca2
commit df562b6ea7
5 changed files with 116 additions and 30 deletions
@@ -247,19 +247,7 @@ public abstract class JpsBuildTestCase extends UsefulTestCase {
@Nullable String testOutputPath,
JpsSdk<T> sdk) {
JpsModule module = myProject.addModule(moduleName, JpsJavaModuleType.INSTANCE);
final JpsSdkType<T> sdkType = sdk.getSdkType();
final JpsSdkReferencesTable sdkTable = module.getSdkReferencesTable();
sdkTable.setSdkReference(sdkType, sdk.createReference());
if (sdkType instanceof JpsJavaSdkTypeWrapper) {
final JpsSdkReference<T> wrapperRef = sdk.createReference();
sdkTable.setSdkReference(JpsJavaSdkType.INSTANCE, JpsJavaExtensionService.
getInstance().createWrappedJavaSdkReference((JpsJavaSdkTypeWrapper)sdkType, wrapperRef));
}
// ensure jdk entry is the first one in dependency list
module.getDependenciesList().clear();
module.getDependenciesList().addSdkDependency(sdkType);
module.getDependenciesList().addModuleSourceDependency();
setupModuleSdk(module, sdk);
if (srcPaths.length > 0 || outputPath != null) {
for (String srcPath : srcPaths) {
module.getContentRootsList().addUrl(JpsPathUtil.pathToUrl(srcPath));
@@ -282,6 +270,22 @@ public abstract class JpsBuildTestCase extends UsefulTestCase {
return module;
}
protected <T extends JpsElement> void setupModuleSdk(JpsModule module, JpsSdk<T> sdk) {
final JpsSdkType<T> sdkType = sdk.getSdkType();
final JpsSdkReferencesTable sdkTable = module.getSdkReferencesTable();
sdkTable.setSdkReference(sdkType, sdk.createReference());
if (sdkType instanceof JpsJavaSdkTypeWrapper) {
final JpsSdkReference<T> wrapperRef = sdk.createReference();
sdkTable.setSdkReference(JpsJavaSdkType.INSTANCE, JpsJavaExtensionService.
getInstance().createWrappedJavaSdkReference((JpsJavaSdkTypeWrapper)sdkType, wrapperRef));
}
// ensure jdk entry is the first one in dependency list
module.getDependenciesList().clear();
module.getDependenciesList().addSdkDependency(sdkType);
module.getDependenciesList().addModuleSourceDependency();
}
protected void rebuildAllModules() {
doBuild(CompileScopeTestBuilder.rebuild().allModules()).assertSuccessful();
}
@@ -20,6 +20,7 @@ import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.CompilerModuleExtension;
import com.intellij.openapi.roots.NativeLibraryOrderRootType;
import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.ui.Messages;
@@ -192,10 +193,10 @@ public class PrepareToDeployAction extends AnAction {
try (Compressor zip = new Compressor.Zip(zipFile)) {
zip.addDirectory(getZipPath(pluginName, ""));
Set<String> usedJarNames = new HashSet<>();
Set<String> usedFileNames = new HashSet<>();
String entryName = pluginName + JAR_EXTENSION;
zip.addFile(getZipPath(pluginName, entryName), jarFile);
usedJarNames.add(entryName);
usedFileNames.add(entryName);
for (Map.Entry<Module, String> entry : jpsModules.entrySet()) {
File jpsPluginJar = jarModulesOutput(Collections.singleton(entry.getKey()), null, null);
@@ -213,13 +214,19 @@ public class PrepareToDeployAction extends AnAction {
for (VirtualFile libRoot : roots) {
if (jarredVirtualFiles.add(libRoot)) {
if (libRoot.getFileSystem() instanceof JarFileSystem) {
addLibraryJar(libRoot, pluginName, zip, usedJarNames);
addLibraryFile(libRoot, pluginName, zip, usedFileNames);
}
else {
makeAndAddLibraryJar(libRoot, pluginName, zip, usedJarNames, library.getName());
makeAndAddLibraryJar(libRoot, pluginName, zip, usedFileNames, library.getName());
}
}
}
VirtualFile[] nativeRoots = library.getFiles(NativeLibraryOrderRootType.getInstance());
for (VirtualFile root : nativeRoots) {
if (!root.isDirectory()) {
addLibraryFile(root, pluginName, zip, usedFileNames);
}
}
}
}
}
@@ -229,10 +236,10 @@ public class PrepareToDeployAction extends AnAction {
return pluginName + "/lib/" + entryName;
}
private static void addLibraryJar(VirtualFile root, String pluginName, Compressor zip, Set<String> usedJarNames) throws IOException {
private static void addLibraryFile(VirtualFile root, String pluginName, Compressor zip, Set<String> usedFileNames) throws IOException {
File ioFile = VfsUtilCore.virtualToIoFile(root);
String jarName = getLibraryJarName(ioFile.getName(), usedJarNames, null);
zip.addFile(getZipPath(pluginName, jarName), ioFile);
String fileName = getLibraryFileName(ioFile.getName(), usedFileNames, null);
zip.addFile(getZipPath(pluginName, fileName), ioFile);
}
private static void makeAndAddLibraryJar(VirtualFile root,
@@ -247,7 +254,7 @@ public class PrepareToDeployAction extends AnAction {
tempZip.filter((entryName, file) -> !manager.isFileIgnored(PathUtil.getFileName(entryName)));
tempZip.addDirectory(VfsUtilCore.virtualToIoFile(root));
}
String jarName = getLibraryJarName(root.getName() + JAR_EXTENSION, usedJarNames, preferredName == null ? null : preferredName + JAR_EXTENSION);
String jarName = getLibraryFileName(root.getName() + JAR_EXTENSION, usedJarNames, preferredName == null ? null : preferredName + JAR_EXTENSION);
zip.addFile(getZipPath(pluginName, jarName), tempFile);
}
finally {
@@ -255,14 +262,14 @@ public class PrepareToDeployAction extends AnAction {
}
}
private static String getLibraryJarName(String fileName, Set<String> usedJarNames, @Nullable String preferredName) {
private static String getLibraryFileName(String fileName, Set<String> usedFileNames, @Nullable String preferredName) {
String uniqueName;
if (preferredName != null && !usedJarNames.contains(preferredName)) {
if (preferredName != null && !usedFileNames.contains(preferredName)) {
uniqueName = preferredName;
}
else {
uniqueName = fileName;
if (usedJarNames.contains(uniqueName)) {
if (usedFileNames.contains(uniqueName)) {
int dotPos = uniqueName.lastIndexOf('.');
String name = dotPos < 0 ? uniqueName : uniqueName.substring(0, dotPos);
String ext = dotPos < 0 ? "" : uniqueName.substring(dotPos);
@@ -271,10 +278,10 @@ public class PrepareToDeployAction extends AnAction {
i++;
uniqueName = name + i + ext;
}
while (usedJarNames.contains(uniqueName));
while (usedFileNames.contains(uniqueName));
}
}
usedJarNames.add(uniqueName);
usedFileNames.add(uniqueName);
return uniqueName;
}
@@ -10,10 +10,12 @@ import com.intellij.openapi.projectRoots.ProjectJdkTable
import com.intellij.openapi.projectRoots.Sdk
import com.intellij.openapi.projectRoots.SdkType
import com.intellij.openapi.roots.ModuleRootModificationUtil
import com.intellij.openapi.roots.NativeLibraryOrderRootType
import com.intellij.openapi.roots.OrderRootType
import com.intellij.openapi.util.io.FileUtil
import com.intellij.openapi.util.io.FileUtilRt
import com.intellij.openapi.vfs.LocalFileSystem
import com.intellij.testFramework.PsiTestUtil
import com.intellij.util.SmartList
import com.intellij.util.io.assertMatches
import com.intellij.util.io.directoryContent
@@ -92,6 +94,36 @@ class PluginModuleCompilationTest : BaseCompilerTestCase() {
})
}
fun testNativeLibraries() {
val module = setupSimplePluginProject()
ModuleRootModificationUtil.updateModel(module) { model ->
val library = model.moduleLibraryTable.createLibrary()
val libModel = library.modifiableModel
libModel.addRoot(createFile("lib/a.so"), NativeLibraryOrderRootType.getInstance())
libModel.commit()
}
rebuild()
prepareForDeployment(module)
val outputFile = File("$projectBasePath/pluginProject.zip")
outputFile.assertMatches(zipFile {
dir("pluginProject") {
dir("lib") {
zip("pluginProject.jar") {
dir("META-INF") {
file("plugin.xml")
file("MANIFEST.MF")
}
dir("xxx") {
file("MyAction.class")
}
}
file("a.so")
}
}
})
}
fun testBuildProjectWithJpsModule() {
val module = setupPluginProjectWithJpsModule()
rebuild()
@@ -33,11 +33,9 @@ import org.jetbrains.jps.model.artifact.DirectoryArtifactType;
import org.jetbrains.jps.model.artifact.JpsArtifact;
import org.jetbrains.jps.model.artifact.JpsArtifactService;
import org.jetbrains.jps.model.artifact.elements.JpsCompositePackagingElement;
import org.jetbrains.jps.model.artifact.elements.JpsPackagingElement;
import org.jetbrains.jps.model.artifact.elements.JpsPackagingElementFactory;
import org.jetbrains.jps.model.java.JpsJavaClasspathKind;
import org.jetbrains.jps.model.java.JpsJavaDependenciesEnumerator;
import org.jetbrains.jps.model.java.JpsJavaExtensionService;
import org.jetbrains.jps.model.java.JpsJavaModuleType;
import org.jetbrains.jps.model.java.*;
import org.jetbrains.jps.model.library.JpsLibrary;
import org.jetbrains.jps.model.library.JpsOrderRootType;
import org.jetbrains.jps.model.library.sdk.JpsSdk;
@@ -109,6 +107,16 @@ public class JpsPluginSyntheticArtifactProvider extends JpsSyntheticArtifactProv
parent = factory.getOrCreateDirectory(root, "lib");
}
parent.addChild(factory.createLibraryElement(library.createReference()));
for (File nativeRoot : library.getFiles(JpsNativeLibraryRootType.INSTANCE)) {
JpsPackagingElement copy;
if (nativeRoot.isDirectory()) {
copy = factory.createDirectoryCopy(nativeRoot.getAbsolutePath());
}
else {
copy = factory.createFileCopy(nativeRoot.getAbsolutePath(), null);
}
factory.getOrCreateDirectory(root, "lib").addChild(copy);
}
}
String name = module.getName() + ":plugin";
@@ -1,12 +1,23 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.jps.devkit.build
import com.intellij.openapi.util.io.FileUtil
import com.intellij.openapi.util.io.systemIndependentPath
import com.intellij.util.PathUtil
import com.intellij.util.io.assertMatches
import com.intellij.util.io.directoryContent
import org.jetbrains.jps.builders.CompileScopeTestBuilder
import org.jetbrains.jps.builders.JpsBuildTestCase
import org.jetbrains.jps.devkit.model.JpsIdeaSdkProperties
import org.jetbrains.jps.devkit.model.JpsIdeaSdkType
import org.jetbrains.jps.devkit.model.JpsPluginModuleProperties
import org.jetbrains.jps.devkit.model.JpsPluginModuleType
import org.jetbrains.jps.incremental.messages.BuildMessage
import org.jetbrains.jps.model.JpsElementFactory
import org.jetbrains.jps.model.java.JpsJavaLibraryType
import org.jetbrains.jps.model.java.JpsNativeLibraryRootType
import org.jetbrains.jps.model.library.JpsOrderRootType
import java.io.File
class JpsPluginBuildTest : JpsBuildTestCase() {
fun `test show proper error message if jdk type is invalid`() {
@@ -21,4 +32,28 @@ class JpsPluginBuildTest : JpsBuildTestCase() {
val errorMessage = assertOneElement(result.getMessages(BuildMessage.Kind.ERROR))
assertEquals("Cannot find JDK for module 'm': '${jdkName}' points to IntelliJ Platform Plugin SDK", errorMessage.messageText)
}
fun `test build native libraries`() {
val pluginModuleProperties = JpsElementFactory.getInstance().createSimpleElement(JpsPluginModuleProperties(null, null))
val m = JpsElementFactory.getInstance().createModule("m", JpsPluginModuleType.INSTANCE, pluginModuleProperties)
myProject.addModule(m)
val sandboxDir = FileUtil.createTempDirectory("sandbox", null)
val sdkProperties = JpsElementFactory.getInstance().createSimpleElement(JpsIdeaSdkProperties(sandboxDir.systemIndependentPath, jdk.parent.name))
val pluginSdk = myModel.global.addSdk("plugin sdk", null, null, JpsIdeaSdkType.INSTANCE, sdkProperties)
setupModuleSdk(m, pluginSdk.properties)
val library = m.libraryCollection.addLibrary("l", JpsJavaLibraryType.INSTANCE)
m.dependenciesList.addLibraryDependency(library)
library.addRoot(File(createFile("lib/a.jar")), JpsOrderRootType.COMPILED)
library.addRoot(File(createFile("lib/a.so")), JpsNativeLibraryRootType.INSTANCE)
doBuild(CompileScopeTestBuilder.rebuild().allModules().allArtifacts()).assertSuccessful()
File(sandboxDir, "plugins/${m.name}").assertMatches(directoryContent {
dir("lib") {
file("a.jar")
file("a.so")
}
})
}
}