From 2d0229936a08544ea7d3c44c390e0e83071bccd5 Mon Sep 17 00:00:00 2001 From: nik Date: Fri, 12 May 2017 21:52:31 +0300 Subject: [PATCH] build scripts: support dynamic generation of resource files for plugins This way we can have statically defined PluginLayout even if some resources for the plugin are need to be generated during build, and it allows us to reuse PluginLayout for such plugins in different IDEs. --- .../intellij/build/ResourcesGenerator.groovy | 31 +++++++++++++++++++ .../intellij/build/impl/BaseLayout.groovy | 4 +++ .../build/impl/DistributionJARsBuilder.groovy | 27 ++++++++++++++-- .../intellij/build/impl/PluginLayout.groovy | 9 ++++++ 4 files changed, 68 insertions(+), 3 deletions(-) create mode 100644 platform/build-scripts/groovy/org/jetbrains/intellij/build/ResourcesGenerator.groovy diff --git a/platform/build-scripts/groovy/org/jetbrains/intellij/build/ResourcesGenerator.groovy b/platform/build-scripts/groovy/org/jetbrains/intellij/build/ResourcesGenerator.groovy new file mode 100644 index 000000000000..ee06dc2052ea --- /dev/null +++ b/platform/build-scripts/groovy/org/jetbrains/intellij/build/ResourcesGenerator.groovy @@ -0,0 +1,31 @@ +/* + * Copyright 2000-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.intellij.build + +import groovy.transform.CompileStatic + +/** + * @see org.jetbrains.intellij.build.impl.PluginLayout.PluginLayoutSpec#withGeneratedResources + * @author nik + */ +@CompileStatic +interface ResourcesGenerator { + /** + * Generate files which need to be included into the product distribution somewhere under {@code context.paths.temp} directory. + * @return path to the generated file or directory or {@code null} if nothing was generated + */ + File generateResources(BuildContext context) +} \ No newline at end of file diff --git a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/BaseLayout.groovy b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/BaseLayout.groovy index 41fb423b9f0f..5110d806ffdd 100644 --- a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/BaseLayout.groovy +++ b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/BaseLayout.groovy @@ -16,6 +16,9 @@ package org.jetbrains.intellij.build.impl import com.intellij.openapi.util.MultiValuesMap +import com.intellij.openapi.util.Pair +import org.jetbrains.intellij.build.ResourcesGenerator + /** * Describes layout of a plugin or the platform JARs in the product distribution * @@ -33,6 +36,7 @@ abstract class BaseLayout { final MultiValuesMap projectLibrariesToUnpack = new MultiValuesMap<>() protected final Set modulesWithLocalizableResourcesInCommonJar = new LinkedHashSet<>() final List modulesWithExcludedModuleLibraries = [] + final List> resourceGenerators = [] boolean packLocalizableResourcesInCommonJar(String moduleName) { return modulesWithLocalizableResourcesInCommonJar.contains(moduleName) diff --git a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/DistributionJARsBuilder.groovy b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/DistributionJARsBuilder.groovy index f884d3a51884..296b77d38c8b 100644 --- a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/DistributionJARsBuilder.groovy +++ b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/DistributionJARsBuilder.groovy @@ -16,6 +16,7 @@ package org.jetbrains.intellij.build.impl import com.intellij.openapi.util.MultiValuesMap +import com.intellij.openapi.util.Pair import com.intellij.openapi.util.io.FileUtil import org.apache.tools.ant.types.FileSet import org.apache.tools.ant.types.resources.FileProvider @@ -225,7 +226,7 @@ class DistributionJARsBuilder { layoutBuilder.patchModuleOutput("platform-resources", FileUtil.toSystemIndependentName(patchedKeyMapDir.absolutePath)) } - buildByLayout(layoutBuilder, platform, buildContext.paths.distAll, platform.moduleJars) + buildByLayout(layoutBuilder, platform, buildContext.paths.distAll, platform.moduleJars, []) if (buildContext.proprietaryBuildTools.scrambleTool != null) { def forbiddenJarNames = buildContext.proprietaryBuildTools.scrambleTool.namesOfJarsRequiredToBeScrambled @@ -301,7 +302,11 @@ class DistributionJARsBuilder { pluginsToInclude.each { plugin -> def actualModuleJars = plugin.getActualModules(enabledModulesSet) checkOutputOfPluginModules(plugin.mainModule, actualModuleJars.values(), plugin.moduleExcludes) - buildByLayout(layoutBuilder, plugin, "$targetDirectory/$plugin.directoryName", actualModuleJars) + List> generatedResources = plugin.resourceGenerators.collectMany { + File resourceFile = it.first.generateResources(buildContext) + resourceFile != null ? [Pair.create(resourceFile, it.second)] : [] + } + buildByLayout(layoutBuilder, plugin, "$targetDirectory/$plugin.directoryName", actualModuleJars, generatedResources) } } @@ -327,7 +332,12 @@ class DistributionJARsBuilder { }) } - private void buildByLayout(LayoutBuilder layoutBuilder, BaseLayout layout, String targetDirectory, MultiValuesMap moduleJars) { + /** + * @param moduleJars mapping from JAR path relative to 'lib' directory to names of modules + * @param additionalResources pairs of resources files and corresponding relative output paths + */ + private void buildByLayout(LayoutBuilder layoutBuilder, BaseLayout layout, String targetDirectory, MultiValuesMap moduleJars, + List> additionalResources) { def ant = buildContext.ant def resourceExcluded = RESOURCES_EXCLUDED def resourcesIncluded = RESOURCES_INCLUDED @@ -423,6 +433,17 @@ class DistributionJARsBuilder { } } } + additionalResources.each { + File resource = it.first + dir(it.second) { + if (resource.isFile()) { + ant.fileset(file: resource.absolutePath) + } + else { + ant.fileset(dir: resource.absolutePath) + } + } + } } } diff --git a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/PluginLayout.groovy b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/PluginLayout.groovy index f9ccdcc964b1..534f19cc3a7c 100644 --- a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/PluginLayout.groovy +++ b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/PluginLayout.groovy @@ -16,7 +16,9 @@ package org.jetbrains.intellij.build.impl import com.intellij.openapi.util.MultiValuesMap +import com.intellij.openapi.util.Pair import org.jetbrains.intellij.build.BuildContext +import org.jetbrains.intellij.build.ResourcesGenerator import java.util.function.Function @@ -126,6 +128,13 @@ class PluginLayout extends BaseLayout { layout.resourcePaths << new ModuleResourceData(layout.mainModule, resourcePath, relativeOutputFile, true) } + /** + * Copy output produced by {@code generator} to the directory specified by {@code relativeOutputPath} under the plugin directory. + */ + void withGeneratedResources(ResourcesGenerator generator, String relativeOutputPath) { + layout.resourceGenerators << Pair.create(generator, relativeOutputPath) + } + /** * Register an optional module which may be excluded from the plugin distribution in some products. These modules are included in plugin * distribution only if they are added to {@link org.jetbrains.intellij.build.ProductModulesLayout#bundledPluginModules} list.