mocobeta commented on a change in pull request #571: URL: https://github.com/apache/lucene/pull/571#discussion_r776724487
########## 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: > the internal sourceset outputs are treated differently (eh...) and they will require a slightly different arrangement I think. Yes, I maybe got it. Both of main and test jars are on the module path when running in-module tests and there are package conflicts between jars; this is the cause of test failure (when I delete the main jar from the module path right before test execution, it passed.) ``` > Task :lucene:analysis:kuromoji:test FAILED Caching disabled for task ':lucene:analysis:kuromoji:test' because: Build cache is disabled Task ':lucene:analysis:kuromoji:test' is not up-to-date because: Task.upToDateWhen is false. Watching 599 directories to track changes Watching 597 directories to track changes Modular extension, runtime paths, source set=test (module), mode=DEPENDENCIES_ON_MODULE_PATH: Module path: /mnt/hdd/home.moco/.gradle/caches/modules-2/files-2.1/com.carrotsearch.randomizedtesting/randomizedtesting-runner/2.7.6/17894fe98cce53f9bd994044d9bea7bd7801cafa/randomizedtesting-runner-2.7.6.jar /mnt/hdd/home.moco/.gradle/caches/modules-2/files-2.1/junit/junit/4.13.1/cdd00374f1fee76b11e2a9d127405aa3f6be5b6a/junit-4.13.1.jar /mnt/hdd/home.moco/.gradle/caches/modules-2/files-2.1/org.hamcrest/hamcrest/2.2/1820c0968dba3a11a1b30669bb1f01978a91dedc/hamcrest-2.2.jar /mnt/hdd/repo/lucene/lucene/analysis/common/build/libs/lucene-analysis-common-10.0.0-SNAPSHOT.jar /mnt/hdd/repo/lucene/lucene/analysis/kuromoji/build/libs/lucene-analysis-kuromoji-10.0.0-SNAPSHOT-test.jar /mnt/hdd/repo/lucene/lucene/analysis/kuromoji/build/libs/lucene-analysis-kuromoji-10.0.0-SNAPSHOT.jar // This is problematic /mnt/hdd/repo/lucene/lucene/codecs/build/libs/lucene-codecs-10.0.0-SNAPSHOT.jar /mnt/hdd/repo/lucene/lucene/core/build/libs/lucene-core-10.0.0-SNAPSHOT.jar /mnt/hdd/repo/lucene/lucene/test-framework/build/libs/lucene-test-framework-10.0.0-SNAPSHOT.jar Class path: [empty] ``` Besides the module path, "resources" in the main jar should be included in the test jar as well as main classes (of course)... -- 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