dweiss commented on a change in pull request #571:
URL: https://github.com/apache/lucene/pull/571#discussion_r776605201



##########
File path: gradle/java/modules.gradle
##########
@@ -237,24 +185,282 @@ allprojects {
 }
 
 
+//
+// For a source set, create explicit configurations for declaring modular 
dependencies.
+//
+// These "modular" configurations correspond 1:1 to Gradle's conventions but 
have a 'module' prefix
+// and a capitalized remaining part of the conventional name. For example, an 
'api' configuration in
+// the main source set would have a corresponding 'moduleApi' configuration 
for declaring modular
+// dependencies.
+//
+// Gradle's java plugin "convention" configurations extend from their modular 
counterparts
+// so all dependencies end up on classpath by default for backward 
compatibility with other
+// tasks and gradle infrastructure.
+//
+// At the same time, we also know which dependencies (and their transitive 
graph of dependencies!)
+// should be placed on module-path only.
+//
+// Note that an explicit configuration of modular dependencies also opens up 
the possibility of automatically
+// validating whether the dependency configuration for a gradle project is 
consistent with the information in
+// the module-info descriptor because there is a (nearly?) direct 
correspondence between the two:
+//
+// moduleApi            - 'requires transitive'
+// moduleImplementation - 'requires'
+// moduleCompileOnly    - 'requires static'
+//
 class ModularPathsExtension {
+  /**
+   * Determines how paths are split between module path and classpath.
+   */
+  enum Mode {
+    /**
+     * Dependencies and source set outputs are placed on classpath, even if 
declared on modular
+     * configurations. This would be the 'default' backward-compatible mode.
+     */
+    CLASSPATH_ONLY,
+
+    /**
+     * Dependencies from modular configurations are placed on module path. 
Source set outputs
+     * are placed on classpath.
+     */
+    DEPENDENCIES_ON_MODULE_PATH
+  }
+
   Project project
   SourceSet sourceSet
   Configuration compileModulePathConfiguration
   Configuration runtimeModulePathConfiguration
+  Configuration modulePatchOnlyConfiguration
+
+  // The mode of splitting paths for this source set.
+  Mode mode = Mode.DEPENDENCIES_ON_MODULE_PATH
+
+  /**
+   * A list of module name - path provider entries that will be converted
+   * into {@code --patch-module} options.
+   */
+  private List<Map.Entry<String, Provider<Path>>> modulePatches = new 
ArrayList<>()
 
-  ModularPathsExtension(Project project, SourceSet sourceSet,
-                        Configuration compileModulePathConfiguration,
-                        Configuration runtimeModulePathConfiguration) {
-    this.project =  project
+  ModularPathsExtension(Project project, SourceSet sourceSet) {
+    this.project = project
     this.sourceSet = sourceSet
-    this.compileModulePathConfiguration = compileModulePathConfiguration
-    this.runtimeModulePathConfiguration = runtimeModulePathConfiguration
+
+    ConfigurationContainer configurations = project.configurations
+
+    // Create modular configurations for gradle's java plugin convention 
configurations.
+    Configuration moduleApi = 
createModuleConfigurationForConvention(sourceSet.apiConfigurationName)
+    Configuration moduleImplementation = 
createModuleConfigurationForConvention(sourceSet.implementationConfigurationName)
+    Configuration moduleRuntimeOnly = 
createModuleConfigurationForConvention(sourceSet.runtimeOnlyConfigurationName)
+    Configuration moduleCompileOnly = 
createModuleConfigurationForConvention(sourceSet.compileOnlyConfigurationName)
+
+
+    // Apply hierarchy relationships to modular configurations.
+    moduleImplementation.extendsFrom(moduleApi)
+
+    // Patched modules have to end up in the implementation configuration for 
IDEs, which
+    // otherwise get terribly confused.
+    Configuration modulePatchOnly = createModuleConfigurationForConvention(
+        SourceSet.isMain(sourceSet) ? "patchOnly" : sourceSet.name + 
"PatchOnly")
+    modulePatchOnly.canBeResolved(true)
+    moduleImplementation.extendsFrom(modulePatchOnly)
+    this.modulePatchOnlyConfiguration = modulePatchOnly
+
+    // This part of convention configurations seems like a very esoteric use 
case, leave out for now.
+    // sourceSet.compileOnlyApiConfigurationName
+
+    // We have to ensure configurations are using assembled resources and 
classes (jar variant) as a single
+    // module can't be expanded into multiple folders.
+    Closure<Void> ensureJarVariant = { Configuration c ->
+      c.attributes.attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, 
project.objects.named(LibraryElements, LibraryElements.JAR))
+    }
+
+    // Set up compilation module path configuration combining corresponding 
convention configurations.
+    Closure<Configuration> createResolvableModuleConfiguration = { String 
configurationName ->
+      Configuration conventionConfiguration = 
configurations.maybeCreate(configurationName)
+      Configuration moduleConfiguration = 
configurations.maybeCreate(moduleConfigurationNameFor(conventionConfiguration.name))
+      moduleConfiguration.canBeConsumed(false)
+      moduleConfiguration.canBeResolved(true)
+      ensureJarVariant(moduleConfiguration)
+
+      project.logger.info("Created resolvable module configuration for 
'${conventionConfiguration.name}': ${moduleConfiguration.name}")
+      return moduleConfiguration
+    }
+
+    
ensureJarVariant(configurations.maybeCreate(sourceSet.compileClasspathConfigurationName))
+    
ensureJarVariant(configurations.maybeCreate(sourceSet.runtimeClasspathConfigurationName))
+
+    this.compileModulePathConfiguration = 
createResolvableModuleConfiguration(sourceSet.compileClasspathConfigurationName)
+    compileModulePathConfiguration.extendsFrom(moduleCompileOnly, 
moduleImplementation)
+
+    this.runtimeModulePathConfiguration = 
createResolvableModuleConfiguration(sourceSet.runtimeClasspathConfigurationName)
+    runtimeModulePathConfiguration.extendsFrom(moduleRuntimeOnly, 
moduleImplementation)
+  }
+
+  /**
+   * Adds {@code --patch-module} option for the provided module name and the 
provider of a
+   * folder or JAR file.
+   *
+   * @param moduleName
+   * @param pathProvider
+   */
+  void patchModule(String moduleName, Provider<Path> pathProvider) {
+    modulePatches.add(Map.entry(moduleName, pathProvider));
+  }

Review comment:
       Thanks for trying it out, @mocobeta. Nice catch - I'll correct this when 
I get a chance. It sadly does not work for me in IDEs - I've tried and had to 
revert the test module because Idea went nuts. Also, what I added is for 
external dependencies - the internal sourceset outputs are treated differently 
(eh...) and they will require a slightly different arrangement I think. ECJ 
stopped working too, argh.




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscr...@lucene.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscr...@lucene.apache.org
For additional commands, e-mail: issues-h...@lucene.apache.org

Reply via email to