diff --git a/jps/jps-builders/testSrc/org/jetbrains/jps/builders/JpsBuildTestCase.java b/jps/jps-builders/testSrc/org/jetbrains/jps/builders/JpsBuildTestCase.java index 503186a23246..2abe8360d07d 100644 --- a/jps/jps-builders/testSrc/org/jetbrains/jps/builders/JpsBuildTestCase.java +++ b/jps/jps-builders/testSrc/org/jetbrains/jps/builders/JpsBuildTestCase.java @@ -247,19 +247,7 @@ public abstract class JpsBuildTestCase extends UsefulTestCase { @Nullable String testOutputPath, JpsSdk sdk) { JpsModule module = myProject.addModule(moduleName, JpsJavaModuleType.INSTANCE); - final JpsSdkType sdkType = sdk.getSdkType(); - final JpsSdkReferencesTable sdkTable = module.getSdkReferencesTable(); - sdkTable.setSdkReference(sdkType, sdk.createReference()); - - if (sdkType instanceof JpsJavaSdkTypeWrapper) { - final JpsSdkReference 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 void setupModuleSdk(JpsModule module, JpsSdk sdk) { + final JpsSdkType sdkType = sdk.getSdkType(); + final JpsSdkReferencesTable sdkTable = module.getSdkReferencesTable(); + sdkTable.setSdkReference(sdkType, sdk.createReference()); + + if (sdkType instanceof JpsJavaSdkTypeWrapper) { + final JpsSdkReference 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(); } diff --git a/plugins/devkit/devkit-core/src/build/PrepareToDeployAction.java b/plugins/devkit/devkit-core/src/build/PrepareToDeployAction.java index d35f01e79396..0bcfd130579a 100644 --- a/plugins/devkit/devkit-core/src/build/PrepareToDeployAction.java +++ b/plugins/devkit/devkit-core/src/build/PrepareToDeployAction.java @@ -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 usedJarNames = new HashSet<>(); + Set usedFileNames = new HashSet<>(); String entryName = pluginName + JAR_EXTENSION; zip.addFile(getZipPath(pluginName, entryName), jarFile); - usedJarNames.add(entryName); + usedFileNames.add(entryName); for (Map.Entry 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 usedJarNames) throws IOException { + private static void addLibraryFile(VirtualFile root, String pluginName, Compressor zip, Set 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 usedJarNames, @Nullable String preferredName) { + private static String getLibraryFileName(String fileName, Set 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; } diff --git a/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/build/PluginModuleCompilationTest.kt b/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/build/PluginModuleCompilationTest.kt index 7d3839686aa3..391af8ffb615 100644 --- a/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/build/PluginModuleCompilationTest.kt +++ b/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/build/PluginModuleCompilationTest.kt @@ -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() diff --git a/plugins/devkit/jps-plugin/src/org/jetbrains/jps/devkit/builder/JpsPluginSyntheticArtifactProvider.java b/plugins/devkit/jps-plugin/src/org/jetbrains/jps/devkit/builder/JpsPluginSyntheticArtifactProvider.java index c908fa2d051b..12f0c6bf85af 100644 --- a/plugins/devkit/jps-plugin/src/org/jetbrains/jps/devkit/builder/JpsPluginSyntheticArtifactProvider.java +++ b/plugins/devkit/jps-plugin/src/org/jetbrains/jps/devkit/builder/JpsPluginSyntheticArtifactProvider.java @@ -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"; diff --git a/plugins/devkit/jps-plugin/testSrc/org/jetbrains/jps/devkit/build/JpsPluginBuildTest.kt b/plugins/devkit/jps-plugin/testSrc/org/jetbrains/jps/devkit/build/JpsPluginBuildTest.kt index f599e59c6676..803feecf6810 100644 --- a/plugins/devkit/jps-plugin/testSrc/org/jetbrains/jps/devkit/build/JpsPluginBuildTest.kt +++ b/plugins/devkit/jps-plugin/testSrc/org/jetbrains/jps/devkit/build/JpsPluginBuildTest.kt @@ -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") + } + }) + } } \ No newline at end of file