@@ -26,25 +26,30 @@ import org.gradle.api.artifacts.Configuration
2626import org.gradle.api.artifacts.ConfigurationContainer
2727import org.gradle.api.logging.Logger
2828import org.gradle.api.logging.Logging
29+ import org.gradle.api.provider.Property
30+ import org.gradle.api.provider.Provider
31+ import org.gradle.api.services.BuildService
32+ import org.gradle.api.services.BuildServiceParameters
2933import java.io.File
30- import java.util.*
34+ import java.io.Serializable
3135import java.util.zip.ZipEntry
3236import java.util.zip.ZipFile
3337import javax.inject.Inject
3438
3539const val RESOLUTION_RULES_CONFIG_NAME = " resolutionRules"
3640
3741class ResolutionRulesPlugin : Plugin <Project > {
38- private val logger: Logger = Logging .getLogger(ResolutionRulesPlugin ::class .java)
39- private val NEBULA_RECOMMENDER_BOM_CONFIG_NAME : String = " nebulaRecommenderBom"
4042 private lateinit var project: Project
4143 private lateinit var configurations: ConfigurationContainer
4244 private lateinit var extension: NebulaResolutionRulesExtension
4345 private val ignoredConfigurationPrefixes = listOf (RESOLUTION_RULES_CONFIG_NAME , SPRING_VERSION_MANAGEMENT_CONFIG_NAME ,
4446 NEBULA_RECOMMENDER_BOM_CONFIG_NAME , SCALA_INCREMENTAL_ANALYSIS_CONFIGURATION_PREFIX , KTLINT_CONFIGURATION_PREFIX , REPOSITORY_CONTENT_DESCRIPTOR_CONFIGURATION_PREFIX )
4547 private val ignoredConfigurationSuffixes = listOf (PMD_CONFIGURATION_SUFFIX )
4648
47- companion object Constants {
49+ companion object {
50+ val Logger : Logger = Logging .getLogger(ResolutionRulesPlugin ::class .java)
51+
52+ const val NEBULA_RECOMMENDER_BOM_CONFIG_NAME : String = " nebulaRecommenderBom"
4853 const val SPRING_VERSION_MANAGEMENT_CONFIG_NAME = " versionManagement"
4954 const val KTLINT_CONFIGURATION_PREFIX = " ktlint"
5055 const val PMD_CONFIGURATION_SUFFIX = " PmdAuxClasspath"
@@ -59,18 +64,32 @@ class ResolutionRulesPlugin : Plugin<Project> {
5964 override fun apply (project : Project ) {
6065 this .project = project
6166 configurations = project.configurations
62- extension = project.extensions.create(" nebulaResolutionRules" , NebulaResolutionRulesExtension ::class .java, project)
67+ extension =
68+ project.extensions.create(" nebulaResolutionRules" , NebulaResolutionRulesExtension ::class .java, project)
6369
6470 project.onExecute {
6571 if (isCoreAlignmentEnabled()) {
66- logger .info(" ${project.name} : coreAlignmentSupport feature enabled" )
72+ Logger .info(" ${project.name} : coreAlignmentSupport feature enabled" )
6773 }
6874 }
6975
7076 val rootProject = project.rootProject
71- rootProject.configurations.maybeCreate(RESOLUTION_RULES_CONFIG_NAME )
77+ val configuration = project.configurations.maybeCreate(RESOLUTION_RULES_CONFIG_NAME )
78+ if (project != rootProject) {
79+ configuration.isCanBeConsumed = false
80+ val rootProjectDependency = project.dependencies.project(
81+ mapOf (" path" to rootProject.path, " configuration" to RESOLUTION_RULES_CONFIG_NAME )
82+ )
83+ configuration.withDependencies { dependencies ->
84+ dependencies.add(rootProjectDependency)
85+ }
86+ }
7287 if (rootProject.extensions.findByType(NebulaResolutionRulesExtension ::class .java) == null ) {
73- rootProject.extensions.create(" nebulaResolutionRules" , NebulaResolutionRulesExtension ::class .java, rootProject)
88+ rootProject.extensions.create(
89+ " nebulaResolutionRules" ,
90+ NebulaResolutionRulesExtension ::class .java,
91+ rootProject
92+ )
7493 }
7594
7695 project.configurations.all { config ->
@@ -86,7 +105,9 @@ class ResolutionRulesPlugin : Plugin<Project> {
86105 project.onExecute {
87106 val ruleSet = extension.ruleSet()
88107 when {
89- config.state != Configuration .State .UNRESOLVED || config.getObservedState() != Configuration .State .UNRESOLVED -> logger.warn(" Dependency resolution rules will not be applied to $config , it was resolved before the project was executed" )
108+ config.state != Configuration .State .UNRESOLVED || config.getObservedState() != Configuration .State .UNRESOLVED -> Logger .warn(
109+ " Dependency resolution rules will not be applied to $config , it was resolved before the project was executed"
110+ )
90111 else -> {
91112 ruleSet.dependencyRulesPartOne().forEach { rule ->
92113 rule.apply (project, config, config.resolutionStrategy, extension)
@@ -102,7 +123,7 @@ class ResolutionRulesPlugin : Plugin<Project> {
102123
103124 config.onResolve {
104125 if (! dependencyRulesApplied) {
105- logger .debug(" Skipping resolve rules for $config - dependency rules have not been applied" )
126+ Logger .debug(" Skipping resolve rules for $config - dependency rules have not been applied" )
106127 } else {
107128 val ruleSet = extension.ruleSet()
108129 ruleSet.resolveRules(isCoreAlignmentEnabled()).forEach { rule ->
@@ -123,48 +144,91 @@ class ResolutionRulesPlugin : Plugin<Project> {
123144 }
124145}
125146
126- open class NebulaResolutionRulesExtension @Inject constructor(private val project : Project ) {
147+ @Suppress(" UnstableApiUsage" )
148+ abstract class NebulaResolutionRulesService : BuildService <NebulaResolutionRulesService .Params > {
127149 companion object {
128- private val logger: Logger = Logging .getLogger(ResolutionRulesPlugin ::class .java)
129- private val mapper = objectMapper()
130- }
131-
132- var include = ArrayList <String >()
133- var optional = ArrayList <String >()
134- var exclude = ArrayList <String >()
135- var useCoreGradleAlignment = false
150+ private val Logger : Logger = Logging .getLogger(NebulaResolutionRulesService ::class .java)
151+ private val Mapper = objectMapper()
152+
153+ fun registerService (project : Project ): Provider <NebulaResolutionRulesService > {
154+ return project.gradle.sharedServices.registerIfAbsent(
155+ " nebulaResolutionRules" ,
156+ NebulaResolutionRulesService ::class .java
157+ ) { spec ->
158+ val resolutionRules = resolveResolutionRules(project)
159+ spec.parameters.getResolutionRules().set(ResolutionRules (resolutionRules))
160+ }
161+ }
136162
137- private val rulesByFile by lazy {
138- check(project == project.rootProject) { " This should only be called on the root project extension " }
139- val configuration = project.configurations.getByName( RESOLUTION_RULES_CONFIG_NAME )
140- val files = project.copyConfiguration(configuration).resolve ()
141- val rules = LinkedHashMap < String , RuleSet >()
142- for (file in files) {
143- val filename = file.name
144- logger.debug( " nebula.resolution-rules uses: $ filename" )
145- if (filename.endsWith( ResolutionRulesPlugin . JSON_EXT )) {
146- rules.putRules(mapper.parseJsonFile(file))
147- } else if (filename.endsWith( ResolutionRulesPlugin . JAR_EXT ) || filename.endsWith( ResolutionRulesPlugin . ZIP_EXT )) {
148- logger.info( " nebula.resolution-rules is using ruleset: $filename " )
149- ZipFile (file).use { zip ->
150- val entries = zip. entries()
151- while ( entries.hasMoreElements()) {
152- val entry = entries.nextElement()
153- if (entry.name.endsWith( ResolutionRulesPlugin . JSON_EXT )) {
154- rules.putRules(mapper.parseJsonStream(zip, entry))
163+ private fun resolveResolutionRules ( project : Project ): Map < String , RuleSet > {
164+ val configuration = project.configurations.getByName( RESOLUTION_RULES_CONFIG_NAME )
165+ val files = configuration.resolve( )
166+ val rules = LinkedHashMap < String , RuleSet > ()
167+ for (file in files) {
168+ val filename = file.name
169+ Logger .debug( " nebula.resolution-rules uses: $filename " )
170+ if ( filename.endsWith( ResolutionRulesPlugin . JSON_EXT )) {
171+ rules.putRules( Mapper .parseJsonFile(file))
172+ } else if (filename.endsWith( ResolutionRulesPlugin . JAR_EXT ) || filename.endsWith( ResolutionRulesPlugin . ZIP_EXT )) {
173+ Logger .info( " nebula.resolution-rules is using ruleset: $ filename" )
174+ ZipFile (file).use { zip ->
175+ val entries = zip.entries()
176+ while ( entries.hasMoreElements()) {
177+ val entry = entries.nextElement()
178+ if (entry.name.endsWith( ResolutionRulesPlugin . JSON_EXT )) {
179+ rules.putRules( Mapper .parseJsonStream(zip, entry))
180+ }
155181 }
156182 }
183+ } else {
184+ Logger .debug(" Unsupported rules file extension for $file " )
157185 }
158- } else {
159- logger.debug(" Unsupported rules file extension for $file " )
186+ }
187+ return rules
188+ }
189+
190+ private fun MutableMap <String , RuleSet >.putRules (ruleSet : RuleSet ) {
191+ if (put(ruleSet.name!! , ruleSet) != null ) {
192+ Logger .info(" Found rules with the same name. Overriding existing ruleset ${ruleSet.name} " )
160193 }
161194 }
162- rules
195+
196+ private fun ruleSetName (filename : String ) =
197+ filename.substring(0 , filename.lastIndexOf(ResolutionRulesPlugin .JSON_EXT ))
198+
199+ private fun ObjectMapper.parseJsonFile (file : File ): RuleSet {
200+ val ruleSetName = ruleSetName(file.name)
201+ Logger .debug(" Using $ruleSetName (${file.name} ) a dependency rules source" )
202+ return readValue<RuleSet >(file).withName(ruleSetName)
203+ }
204+
205+ private fun ObjectMapper.parseJsonStream (zip : ZipFile , entry : ZipEntry ): RuleSet {
206+ val ruleSetName = ruleSetName(File (entry.name).name)
207+ Logger .debug(" Using $ruleSetName (${zip.name} ) a dependency rules source" )
208+ return readValue<RuleSet >(zip.getInputStream(entry)).withName(ruleSetName)
209+ }
210+ }
211+
212+ interface Params : BuildServiceParameters {
213+ fun getResolutionRules (): Property <ResolutionRules >
163214 }
164215
216+ class ResolutionRules (val byFile : Map <String , RuleSet >) : Serializable
217+ }
218+
219+ open class NebulaResolutionRulesExtension @Inject constructor(private val project : Project ) {
220+ var include = ArrayList <String >()
221+ var optional = ArrayList <String >()
222+ var exclude = ArrayList <String >()
223+ var useCoreGradleAlignment = false
224+
165225 fun ruleSet (): RuleSet {
166- val extension = project.rootProject.extensions.getByType(NebulaResolutionRulesExtension ::class .java)
167- return extension.rulesByFile.filterKeys { ruleSet ->
226+ val service = NebulaResolutionRulesService .registerService(project).get()
227+ @Suppress(" UnstableApiUsage" ) val rulesByFile = service.parameters
228+ .getResolutionRules()
229+ .get()
230+ .byFile
231+ return rulesByFile.filterKeys { ruleSet ->
168232 when {
169233 ruleSet.startsWith(ResolutionRulesPlugin .OPTIONAL_PREFIX ) -> {
170234 val ruleSetWithoutPrefix = ruleSet.substring(ResolutionRulesPlugin .OPTIONAL_PREFIX .length)
@@ -175,24 +239,4 @@ open class NebulaResolutionRulesExtension @Inject constructor(private val projec
175239 }
176240 }.values.flatten()
177241 }
178-
179- private fun MutableMap <String , RuleSet >.putRules (ruleSet : RuleSet ) {
180- if (put(ruleSet.name!! , ruleSet) != null ) {
181- logger.info(" Found rules with the same name. Overriding existing ruleset ${ruleSet.name} " )
182- }
183- }
184-
185- private fun ruleSetName (filename : String ) = filename.substring(0 , filename.lastIndexOf(ResolutionRulesPlugin .JSON_EXT ))
186-
187- private fun ObjectMapper.parseJsonFile (file : File ): RuleSet {
188- val ruleSetName = ruleSetName(file.name)
189- logger.debug(" Using $ruleSetName (${file.name} ) a dependency rules source" )
190- return readValue<RuleSet >(file).withName(ruleSetName)
191- }
192-
193- private fun ObjectMapper.parseJsonStream (zip : ZipFile , entry : ZipEntry ): RuleSet {
194- val ruleSetName = ruleSetName(File (entry.name).name)
195- logger.debug(" Using $ruleSetName (${zip.name} ) a dependency rules source" )
196- return readValue<RuleSet >(zip.getInputStream(entry)).withName(ruleSetName)
197- }
198242}
0 commit comments