Support downloading additional artifacts (sources, javadoc, etc.)

This commit is contained in:
Tad Fisher
2025-01-17 11:44:31 -08:00
committed by Tad Fisher
parent f8c0afcd29
commit 96a444c22b
30 changed files with 1985 additions and 366 deletions

View File

@@ -1,20 +1,61 @@
package org.nixos.gradle2nix
import org.gradle.api.Project
import org.gradle.api.tasks.TaskAction
import org.gradle.api.tasks.TaskProvider
import org.nixos.gradle2nix.model.RESOLVE_PROJECT_TASK
import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.component.ModuleComponentIdentifier
import org.gradle.api.attributes.Bundling
import org.gradle.api.attributes.Category
import org.gradle.api.attributes.DocsType
import org.gradle.api.attributes.Usage
import org.gradle.api.file.FileCollection
import org.nixos.gradle2nix.model.ArtifactType
private fun Configuration.artifactConfigurationName(artifactType: ArtifactType): String =
"$name-${artifactType.name.toLowerCase()}-artifacts"
object ResolveAllArtifactsApplierBase : AbstractResolveAllArtifactsApplier() {
override fun Project.registerProjectTask(): TaskProvider<*> =
tasks.register(RESOLVE_PROJECT_TASK, ResolveProjectDependenciesTaskBase::class.java)
}
@Suppress("UnstableApiUsage")
override fun Project.addConfigurationArtifactResolver(
configuration: Configuration,
artifactType: ArtifactType,
): FileCollection {
val artifactConfiguration =
configurations.register(configuration.artifactConfigurationName(artifactType)) { artifactConfig ->
val usage = configuration.attributes.getAttribute(Usage.USAGE_ATTRIBUTE)
artifactConfig.extendsFrom(configuration)
artifactConfig.isCanBeConsumed = false
artifactConfig.attributes { attrs ->
with(attrs) {
if (usage != null) {
attribute(Usage.USAGE_ATTRIBUTE, usage)
}
attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category::class.java, Category.DOCUMENTATION))
attribute(Bundling.BUNDLING_ATTRIBUTE, objects.named(Bundling::class.java, Bundling.EXTERNAL))
attribute(
DocsType.DOCS_TYPE_ATTRIBUTE,
objects.named(
DocsType::class.java,
when (artifactType) {
ArtifactType.DOXYGEN -> DocsType.DOXYGEN
ArtifactType.JAVADOC -> DocsType.JAVADOC
ArtifactType.SAMPLES -> DocsType.SAMPLES
ArtifactType.SOURCES -> DocsType.SOURCES
ArtifactType.USERMANUAL -> DocsType.USER_MANUAL
},
),
)
}
}
}
abstract class ResolveProjectDependenciesTaskBase : ResolveProjectDependenciesTask() {
@TaskAction
fun action() {
for (configuration in getReportableConfigurations()) {
configuration.artifactFiles().count()
}
return objects.fileCollection().from(
artifactConfiguration.map { config ->
config.incoming
.artifactView { view ->
view.isLenient = true
view.componentFilter { it is ModuleComponentIdentifier }
}.files
},
)
}
}

View File

@@ -3,27 +3,56 @@ package org.nixos.gradle2nix
import org.gradle.api.DefaultTask
import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.component.ModuleComponentIdentifier
import org.gradle.api.file.FileCollection
import org.gradle.api.invocation.Gradle
import org.gradle.api.logging.Logging
import org.gradle.api.model.ObjectFactory
import org.gradle.api.tasks.InputFiles
import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.TaskProvider
import org.gradle.api.tasks.TaskAction
import org.gradle.internal.deprecation.DeprecatableConfiguration
import org.nixos.gradle2nix.model.ARTIFACTS_PROPERTY
import org.nixos.gradle2nix.model.ArtifactType
import org.nixos.gradle2nix.model.RESOLVE_ALL_TASK
import org.nixos.gradle2nix.model.RESOLVE_PROJECT_TASK
import javax.inject.Inject
fun interface ResolveAllArtifactsApplier {
fun apply(gradle: Gradle)
}
val Project.reportableConfigurations: List<Configuration>
get() = configurations.filter { (it as? DeprecatableConfiguration)?.canSafelyBeResolved() ?: it.isCanBeResolved }
abstract class AbstractResolveAllArtifactsApplier : ResolveAllArtifactsApplier {
abstract fun Project.registerProjectTask(): TaskProvider<*>
abstract fun Project.addConfigurationArtifactResolver(
configuration: Configuration,
artifactType: ArtifactType,
): FileCollection
final override fun apply(gradle: Gradle) {
val resolveAll = gradle.rootProject.tasks.register(RESOLVE_ALL_TASK)
val artifacts =
System
.getProperty(ARTIFACTS_PROPERTY, "")
.split(",")
.filter { it.isNotBlank() }
.mapTo(mutableSetOf()) { ArtifactType.valueOf(it.toUpperCase()) }
// Depend on "dependencies" task in all projects
gradle.allprojects { project ->
val resolveProject = project.registerProjectTask()
val resolveProject =
project.tasks.register(RESOLVE_PROJECT_TASK, ResolveProjectDependenciesTask::class.java) { task ->
task.projectName.set(project.path)
for (configuration in project.reportableConfigurations) {
task.configurations.from(configuration)
for (artifactType in artifacts) {
task.configurations.from(project.addConfigurationArtifactResolver(configuration, artifactType))
}
}
}
resolveAll.configure { it.dependsOn(resolveProject) }
}
@@ -36,17 +65,25 @@ abstract class AbstractResolveAllArtifactsApplier : ResolveAllArtifactsApplier {
}
}
abstract class ResolveProjectDependenciesTask : DefaultTask() {
@Internal
protected fun getReportableConfigurations(): List<Configuration> =
project.configurations.filter {
(it as? DeprecatableConfiguration)?.canSafelyBeResolved() ?: true
@Suppress("UnstableApiUsage")
abstract class ResolveProjectDependenciesTask
@Inject
constructor(
objects: ObjectFactory,
) : DefaultTask() {
@get:Internal
val projectName = objects.property(String::class.java)
@get:InputFiles
val configurations = objects.fileCollection()
@TaskAction
fun resolve() {
val count = configurations.count()
LOGGER.info("${projectName.get()}: resolved $count artifacts")
}
protected fun Configuration.artifactFiles(): FileCollection =
incoming
.artifactView { viewConfiguration ->
viewConfiguration.isLenient = true
viewConfiguration.componentFilter { it is ModuleComponentIdentifier }
}.files
}
companion object {
private val LOGGER = Logging.getLogger(ResolveProjectDependenciesTask::class.java)
}
}

View File

@@ -0,0 +1,12 @@
plugins {
`plugin-conventions`
}
dependencies {
compileOnly(libs.gradle.api.get75())
implementation(project(":plugin:common"))
}
tasks.shadowJar {
archiveFileName = "plugin-gradle75.jar"
}

View File

@@ -0,0 +1,61 @@
package org.nixos.gradle2nix
import org.gradle.api.invocation.Gradle
import org.gradle.api.services.BuildService
import org.gradle.api.services.BuildServiceParameters
import org.gradle.internal.build.event.BuildEventListenerRegistryInternal
import org.gradle.internal.operations.BuildOperationDescriptor
import org.gradle.internal.operations.BuildOperationListener
import org.gradle.internal.operations.OperationFinishEvent
import org.gradle.internal.operations.OperationIdentifier
import org.gradle.internal.operations.OperationProgressEvent
import org.gradle.internal.operations.OperationStartEvent
object DependencyExtractorApplierG75 : DependencyExtractorApplier {
@Suppress("UnstableApiUsage")
override fun apply(
gradle: Gradle,
extractor: DependencyExtractor,
) {
val serviceProvider =
gradle.sharedServices
.registerIfAbsent(
"nixDependencyExtractor",
DependencyExtractorService::class.java,
) {}
.map { service ->
service.apply { this.extractor = extractor }
}
gradle.service<BuildEventListenerRegistryInternal>().onOperationCompletion(serviceProvider)
}
}
@Suppress("UnstableApiUsage")
internal abstract class DependencyExtractorService :
BuildService<BuildServiceParameters.None>,
BuildOperationListener,
AutoCloseable {
var extractor: DependencyExtractor? = null
override fun started(
buildOperation: BuildOperationDescriptor,
startEvent: OperationStartEvent,
) {}
override fun progress(
operationIdentifier: OperationIdentifier,
progressEvent: OperationProgressEvent,
) {}
override fun finished(
buildOperation: BuildOperationDescriptor,
finishEvent: OperationFinishEvent,
) {
extractor?.finished(buildOperation, finishEvent)
}
override fun close() {
extractor = null
}
}

View File

@@ -0,0 +1,8 @@
package org.nixos.gradle2nix
abstract class Gradle2NixPlugin :
AbstractGradle2NixPlugin(
GradleCacheAccessFactoryG75,
DependencyExtractorApplierG75,
ResolveAllArtifactsApplierG75,
)

View File

@@ -0,0 +1,18 @@
package org.nixos.gradle2nix
import org.gradle.api.internal.artifacts.ivyservice.ArtifactCachesProvider
import org.gradle.api.invocation.Gradle
object GradleCacheAccessFactoryG75 : GradleCacheAccessFactory {
override fun create(gradle: Gradle): GradleCacheAccess = GradleCacheAccessG75(gradle)
}
class GradleCacheAccessG75(
gradle: Gradle,
) : GradleCacheAccess {
private val artifactCachesProvider = gradle.service<ArtifactCachesProvider>()
override fun useCache(block: () -> Unit) {
artifactCachesProvider.writableCacheLockingManager.useCache(block)
}
}

View File

@@ -0,0 +1,47 @@
package org.nixos.gradle2nix
import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.component.ModuleComponentIdentifier
import org.gradle.api.attributes.Bundling
import org.gradle.api.attributes.DocsType
import org.gradle.api.file.FileCollection
import org.nixos.gradle2nix.model.ArtifactType
object ResolveAllArtifactsApplierG75 : AbstractResolveAllArtifactsApplier() {
@Suppress("UnstableApiUsage")
override fun Project.addConfigurationArtifactResolver(
configuration: Configuration,
artifactType: ArtifactType,
): FileCollection {
val result =
configuration.incoming
.artifactView { view ->
view.isLenient = true
view.withVariantReselection()
view.componentFilter { it is ModuleComponentIdentifier }
view.attributes { attrs ->
with(attrs) {
attribute(Bundling.BUNDLING_ATTRIBUTE, objects.named(Bundling::class.java, Bundling.EXTERNAL))
attribute(
DocsType.DOCS_TYPE_ATTRIBUTE,
objects.named(
DocsType::class.java,
when (artifactType) {
ArtifactType.DOXYGEN -> DocsType.DOXYGEN
ArtifactType.JAVADOC -> DocsType.JAVADOC
ArtifactType.SAMPLES -> DocsType.SAMPLES
ArtifactType.SOURCES -> DocsType.SOURCES
ArtifactType.USERMANUAL -> DocsType.USER_MANUAL
},
),
)
}
}
}.files
configuration.incoming.afterResolve { result.files.count() }
return result
}
}

View File

@@ -1,37 +1,49 @@
package org.nixos.gradle2nix
import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.component.ModuleComponentIdentifier
import org.gradle.api.attributes.Bundling
import org.gradle.api.attributes.DocsType
import org.gradle.api.file.FileCollection
import org.gradle.api.model.ObjectFactory
import org.gradle.api.tasks.TaskAction
import org.gradle.api.tasks.TaskProvider
import org.gradle.internal.serialization.Cached
import org.gradle.work.DisableCachingByDefault
import org.nixos.gradle2nix.model.RESOLVE_PROJECT_TASK
import javax.inject.Inject
import org.nixos.gradle2nix.model.ArtifactType
object ResolveAllArtifactsApplierG8 : AbstractResolveAllArtifactsApplier() {
override fun Project.registerProjectTask(): TaskProvider<*> =
tasks.register(RESOLVE_PROJECT_TASK, ResolveProjectDependenciesTaskG8::class.java)
}
@Suppress("UnstableApiUsage")
override fun Project.addConfigurationArtifactResolver(
configuration: Configuration,
artifactType: ArtifactType,
): FileCollection {
val result =
configuration.incoming
.artifactView { view ->
view.isLenient = true
view.withVariantReselection()
view.componentFilter { it is ModuleComponentIdentifier }
view.attributes { attrs ->
with(attrs) {
attribute(Bundling.BUNDLING_ATTRIBUTE, objects.named(Bundling::class.java, Bundling.EXTERNAL))
attribute(
DocsType.DOCS_TYPE_ATTRIBUTE,
objects.named(
DocsType::class.java,
when (artifactType) {
ArtifactType.DOXYGEN -> DocsType.DOXYGEN
ArtifactType.JAVADOC -> DocsType.JAVADOC
ArtifactType.SAMPLES -> DocsType.SAMPLES
ArtifactType.SOURCES -> DocsType.SOURCES
ArtifactType.USERMANUAL -> DocsType.USER_MANUAL
},
),
)
}
}
}.files
@DisableCachingByDefault(because = "Not worth caching")
abstract class ResolveProjectDependenciesTaskG8
@Inject
constructor(
private val objects: ObjectFactory,
) : ResolveProjectDependenciesTask() {
private val artifactFiles = Cached.of { artifactFiles() }
private fun artifactFiles(): FileCollection =
objects.fileCollection().from(
getReportableConfigurations().map { configuration ->
configuration.artifactFiles()
},
)
@TaskAction
fun action() {
artifactFiles.get().count()
configuration.incoming.afterResolve {
result.files.count()
}
return result
}
}

View File

@@ -3,8 +3,8 @@ plugins {
}
dependencies {
implementation(project(":plugin:gradle8"))
compileOnly(libs.gradle.api.get80())
implementation(project(":plugin:gradle8"))
}
tasks.shadowJar {

View File

@@ -3,8 +3,8 @@ plugins {
}
dependencies {
implementation(project(":plugin:gradle8"))
compileOnly(libs.gradle.api.get81())
implementation(project(":plugin:gradle8"))
}
tasks.shadowJar {