mirror of
https://github.com/tadfisher/gradle2nix.git
synced 2026-01-12 07:50:53 -05:00
Update build; improve caching; improve tests
This commit is contained in:
15
plugin/src/main/java/org/nixos/gradle2nix/ApiHack.java
Normal file
15
plugin/src/main/java/org/nixos/gradle2nix/ApiHack.java
Normal file
@@ -0,0 +1,15 @@
|
||||
package org.nixos.gradle2nix;
|
||||
|
||||
import org.gradle.api.artifacts.Dependency;
|
||||
import org.gradle.api.internal.artifacts.dependencies.DefaultExternalModuleDependency;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Workarounds for APIs improperly marked with @NonNullApi.
|
||||
*/
|
||||
interface ApiHack {
|
||||
static Dependency defaultExternalModuleDependency(String group, String name, @Nullable String version) {
|
||||
return new DefaultExternalModuleDependency(group, name, version);
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import org.apache.ivy.plugins.parser.m2.PomReader
|
||||
import org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorParser
|
||||
import org.apache.ivy.plugins.repository.url.URLResource
|
||||
import org.apache.ivy.plugins.resolver.ChainResolver
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.artifacts.Configuration
|
||||
import org.gradle.api.artifacts.ModuleIdentifier
|
||||
import org.gradle.api.artifacts.ResolvedArtifact
|
||||
@@ -23,12 +24,21 @@ import org.gradle.kotlin.dsl.withArtifacts
|
||||
import org.gradle.maven.MavenModule
|
||||
import org.gradle.maven.MavenPomArtifact
|
||||
import org.gradle.util.GradleVersion
|
||||
import java.io.File
|
||||
|
||||
internal class ConfigurationResolverFactory(repositories: RepositoryHandler) {
|
||||
enum class ConfigurationScope {
|
||||
BUILDSCRIPT,
|
||||
PLUGIN,
|
||||
PROJECT
|
||||
}
|
||||
|
||||
internal class ConfigurationResolverFactory(
|
||||
project: Project,
|
||||
scope: ConfigurationScope,
|
||||
repositories: RepositoryHandler
|
||||
) {
|
||||
private val ivySettings = IvySettings().apply {
|
||||
defaultInit()
|
||||
setDefaultRepositoryCacheBasedir(createTempDir("gradle2nix-cache").apply(File::deleteOnExit).absolutePath)
|
||||
defaultRepositoryCacheManager = null
|
||||
setDictatorResolver(ChainResolver().also { chain ->
|
||||
chain.settings = this@apply
|
||||
for (resolver in resolvers) chain.add(resolver)
|
||||
@@ -38,7 +48,7 @@ internal class ConfigurationResolverFactory(repositories: RepositoryHandler) {
|
||||
private val resolvers = repositories
|
||||
.filterIsInstance<ResolutionAwareRepository>()
|
||||
.filterNot { it.createResolver().isLocal }
|
||||
.mapNotNull { it.repositoryResolver(ivySettings) }
|
||||
.mapNotNull { it.repositoryResolver(project, scope, ivySettings) }
|
||||
|
||||
fun create(dependencies: DependencyHandler): ConfigurationResolver =
|
||||
ConfigurationResolver(ivySettings, resolvers, dependencies)
|
||||
@@ -49,11 +59,23 @@ internal class ConfigurationResolver(
|
||||
private val resolvers: List<RepositoryResolver>,
|
||||
private val dependencies: DependencyHandler
|
||||
) {
|
||||
private val failed = mutableListOf<ArtifactIdentifier>()
|
||||
private val ivy = Ivy.newInstance(ivySettings)
|
||||
|
||||
val unresolved: List<ArtifactIdentifier> = failed.toList()
|
||||
|
||||
fun resolve(configuration: Configuration): List<DefaultArtifact> {
|
||||
val resolved = configuration.resolvedConfiguration.lenientConfiguration
|
||||
|
||||
failed.addAll(resolved.unresolvedModuleDependencies.map {
|
||||
DefaultArtifactIdentifier(
|
||||
group = it.selector.group,
|
||||
name = it.selector.name,
|
||||
version = it.selector.version ?: "",
|
||||
type = "module"
|
||||
)
|
||||
})
|
||||
|
||||
val topLevelMetadata = resolved.firstLevelModuleDependencies
|
||||
.flatMap { resolveMetadata(it.moduleGroup, it.moduleName, it.moduleVersion) }
|
||||
|
||||
@@ -78,6 +100,7 @@ internal class ConfigurationResolver(
|
||||
|
||||
val sha256 = resolvedArtifact.file.sha256()
|
||||
val artifacts = resolvers.mapNotNull { it.resolve(artifactId, sha256) }.merge()
|
||||
if (artifacts.isEmpty()) failed.add(artifactId)
|
||||
return artifacts + componentId.run { resolveMetadata(group, module, version) }
|
||||
}
|
||||
|
||||
@@ -113,7 +136,9 @@ internal class ConfigurationResolver(
|
||||
type = "pom"
|
||||
)
|
||||
val sha256 = resolvedPom.file.sha256()
|
||||
resolvers.mapNotNull { it.resolve(artifactId, sha256) }.merge()
|
||||
val artifacts = resolvers.mapNotNull { it.resolve(artifactId, sha256) }.merge()
|
||||
if (artifacts.isEmpty()) failed.add(artifactId)
|
||||
artifacts
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,7 +165,9 @@ internal class ConfigurationResolver(
|
||||
extension = "xml"
|
||||
)
|
||||
val sha256 = resolvedDesc.file.sha256()
|
||||
resolvers.mapNotNull { it.resolve(artifactId, sha256) }.merge()
|
||||
val artifacts = resolvers.mapNotNull { it.resolve(artifactId, sha256) }.merge()
|
||||
if (artifacts.isEmpty()) failed.add(artifactId)
|
||||
artifacts
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,7 +182,9 @@ internal class ConfigurationResolver(
|
||||
version = version,
|
||||
type = "module"
|
||||
)
|
||||
return resolvers.mapNotNull { it.resolve(artifactId) }.merge()
|
||||
val artifacts = resolvers.mapNotNull { it.resolve(artifactId) }.merge()
|
||||
if (artifacts.isEmpty()) failed.add(artifactId)
|
||||
return artifacts
|
||||
}
|
||||
|
||||
private fun ResolvedArtifactResult.parentPom(): ResolvedArtifactResult? {
|
||||
|
||||
@@ -18,7 +18,7 @@ import org.gradle.tooling.provider.model.ToolingModelBuilder
|
||||
import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry
|
||||
import org.gradle.util.GradleVersion
|
||||
import java.net.URL
|
||||
import java.util.Locale
|
||||
import java.util.*
|
||||
|
||||
@Suppress("unused")
|
||||
open class Gradle2NixPlugin : Plugin<Gradle> {
|
||||
@@ -127,7 +127,7 @@ private fun Project.buildGradle(): DefaultGradle =
|
||||
}
|
||||
|
||||
private fun Project.buildPlugins(pluginRequests: List<PluginRequest>): List<DefaultArtifact> {
|
||||
return objects.newInstance<PluginResolver>().resolve(pluginRequests).distinct().sorted()
|
||||
return objects.newInstance<PluginResolver>(this).resolve(pluginRequests).distinct().sorted()
|
||||
}
|
||||
|
||||
private fun Project.includedBuilds(): List<DefaultIncludedBuild> =
|
||||
@@ -141,37 +141,64 @@ private fun Project.buildProject(
|
||||
pluginArtifacts: List<DefaultArtifact>
|
||||
): DefaultProject {
|
||||
logger.lifecycle(" Subproject: $path")
|
||||
|
||||
val (buildscriptDependencies, buildscriptUnresolved) = buildscriptDependencies(pluginArtifacts)
|
||||
|
||||
if (buildscriptUnresolved.isNotEmpty()) {
|
||||
logger.warn(buildString {
|
||||
append(" Failed to resolve buildscript dependencies:\n")
|
||||
for (id in buildscriptUnresolved) {
|
||||
append(" - $id\n")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
val (projectDependencies, projectUnresolved) = projectDependencies(explicitConfigurations)
|
||||
|
||||
if (projectUnresolved.isNotEmpty()) {
|
||||
logger.warn(buildString {
|
||||
append(" Failed to resolve project dependencies:\n")
|
||||
for (id in projectUnresolved) {
|
||||
append(" - $id\n")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return DefaultProject(
|
||||
name = name,
|
||||
version = version.toString(),
|
||||
path = path,
|
||||
projectDir = projectDir.toRelativeString(rootProject.projectDir),
|
||||
buildscriptDependencies = buildscriptDependencies(pluginArtifacts),
|
||||
projectDependencies = projectDependencies(explicitConfigurations),
|
||||
buildscriptDependencies = buildscriptDependencies,
|
||||
projectDependencies = projectDependencies,
|
||||
children = explicitSubprojects.map {
|
||||
it.buildProject(explicitConfigurations, emptyList(), pluginArtifacts)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private fun Project.buildscriptDependencies(pluginArtifacts: List<DefaultArtifact>): List<DefaultArtifact> {
|
||||
val resolverFactory = ConfigurationResolverFactory(buildscript.repositories)
|
||||
private fun Project.buildscriptDependencies(
|
||||
pluginArtifacts: List<DefaultArtifact>
|
||||
): Pair<List<DefaultArtifact>, List<ArtifactIdentifier>> {
|
||||
val resolverFactory = ConfigurationResolverFactory(this, ConfigurationScope.BUILDSCRIPT, buildscript.repositories)
|
||||
val resolver = resolverFactory.create(buildscript.dependencies)
|
||||
val pluginIds = pluginArtifacts.map(DefaultArtifact::id)
|
||||
return buildscript.configurations
|
||||
.flatMap(resolver::resolve)
|
||||
.distinct()
|
||||
.filter { it.id !in pluginIds }
|
||||
.sorted()
|
||||
.sorted() to resolver.unresolved
|
||||
}
|
||||
|
||||
private fun Project.projectDependencies(explicitConfigurations: List<String>): List<DefaultArtifact> {
|
||||
val resolverFactory = ConfigurationResolverFactory(repositories)
|
||||
private fun Project.projectDependencies(
|
||||
explicitConfigurations: List<String>
|
||||
): Pair<List<DefaultArtifact>, List<ArtifactIdentifier>> {
|
||||
val resolverFactory = ConfigurationResolverFactory(this, ConfigurationScope.PROJECT, repositories)
|
||||
val resolver = resolverFactory.create(dependencies)
|
||||
return collectConfigurations(explicitConfigurations)
|
||||
.flatMap(resolver::resolve)
|
||||
.distinct()
|
||||
.sorted()
|
||||
.sorted() to resolver.unresolved
|
||||
}
|
||||
|
||||
private fun Project.dependentSubprojects(explicitConfigurations: List<String>): Set<Project> {
|
||||
|
||||
@@ -1,25 +1,28 @@
|
||||
package org.nixos.gradle2nix
|
||||
|
||||
import org.gradle.api.internal.artifacts.dependencies.DefaultExternalModuleDependency
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.plugin.management.PluginRequest
|
||||
import org.gradle.plugin.use.internal.PluginDependencyResolutionServices
|
||||
import javax.inject.Inject
|
||||
|
||||
internal open class PluginResolver @Inject constructor(
|
||||
project: Project,
|
||||
pluginDependencyResolutionServices: PluginDependencyResolutionServices
|
||||
) {
|
||||
private val configurations = pluginDependencyResolutionServices.configurationContainer
|
||||
|
||||
private val resolver = ConfigurationResolverFactory(
|
||||
project,
|
||||
ConfigurationScope.PLUGIN,
|
||||
pluginDependencyResolutionServices.resolveRepositoryHandler
|
||||
).create(pluginDependencyResolutionServices.dependencyHandler)
|
||||
|
||||
fun resolve(pluginRequests: List<PluginRequest>): List<DefaultArtifact> {
|
||||
val markerDependencies = pluginRequests.map {
|
||||
it.module?.let { selector ->
|
||||
DefaultExternalModuleDependency(selector.group, selector.name, selector.version)
|
||||
} ?: it.id.run {
|
||||
DefaultExternalModuleDependency(id, "$id.gradle.plugin", it.version)
|
||||
val markerDependencies = pluginRequests.map { request ->
|
||||
request.module?.let { module ->
|
||||
ApiHack.defaultExternalModuleDependency(module.group, module.name, module.version)
|
||||
} ?: request.id.id.let { id ->
|
||||
ApiHack.defaultExternalModuleDependency(id, "$id.gradle.plugin", request.version)
|
||||
}
|
||||
}
|
||||
return resolver.resolve(configurations.detachedConfiguration(*markerDependencies.toTypedArray()))
|
||||
|
||||
@@ -15,6 +15,7 @@ import org.apache.ivy.plugins.resolver.URLResolver
|
||||
import org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Reader
|
||||
import org.codehaus.plexus.util.ReaderFactory
|
||||
import org.codehaus.plexus.util.xml.pull.XmlPullParserException
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.artifacts.repositories.ArtifactRepository
|
||||
import org.gradle.api.artifacts.repositories.IvyArtifactRepository
|
||||
import org.gradle.api.artifacts.repositories.MavenArtifactRepository
|
||||
@@ -27,10 +28,14 @@ import org.apache.ivy.core.module.descriptor.Artifact as IvyArtifact
|
||||
import org.apache.ivy.core.module.descriptor.DefaultArtifact as IvyDefaultArtifact
|
||||
import org.apache.ivy.plugins.resolver.RepositoryResolver as IvyRepositoryResolver
|
||||
|
||||
internal fun ResolutionAwareRepository.repositoryResolver(ivySettings: IvySettings): RepositoryResolver? =
|
||||
internal fun ResolutionAwareRepository.repositoryResolver(
|
||||
project: Project,
|
||||
scope: ConfigurationScope,
|
||||
ivySettings: IvySettings
|
||||
): RepositoryResolver? =
|
||||
when(this) {
|
||||
is MavenArtifactRepository -> MavenResolver(ivySettings, this)
|
||||
is IvyArtifactRepository -> IvyResolver(ivySettings, this)
|
||||
is MavenArtifactRepository -> MavenResolver(project, scope, ivySettings, this)
|
||||
is IvyArtifactRepository -> IvyResolver(project, scope, ivySettings, this)
|
||||
else -> null
|
||||
}
|
||||
|
||||
@@ -49,6 +54,8 @@ internal sealed class RepositoryResolver {
|
||||
}
|
||||
|
||||
internal class MavenResolver(
|
||||
project: Project,
|
||||
scope: ConfigurationScope,
|
||||
ivySettings: IvySettings,
|
||||
repository: MavenArtifactRepository
|
||||
) : RepositoryResolver() {
|
||||
@@ -58,7 +65,7 @@ internal class MavenResolver(
|
||||
root = repository.url.toString()
|
||||
isM2compatible = true
|
||||
settings = ivySettings
|
||||
setCache(cacheManager(ivySettings, repository).name)
|
||||
setCache(cacheManager(project, scope, ivySettings, repository).name)
|
||||
}
|
||||
|
||||
override fun resolve(artifactId: DefaultArtifactIdentifier, sha256: String?): DefaultArtifact? {
|
||||
@@ -121,6 +128,8 @@ internal class MavenResolver(
|
||||
}
|
||||
|
||||
internal class IvyResolver(
|
||||
project: Project,
|
||||
scope: ConfigurationScope,
|
||||
ivySettings: IvySettings,
|
||||
repository: IvyArtifactRepository
|
||||
) : RepositoryResolver() {
|
||||
@@ -132,7 +141,7 @@ internal class IvyResolver(
|
||||
for (p in ivyResolver.ivyPatterns) addIvyPattern(p)
|
||||
for (p in ivyResolver.artifactPatterns) addArtifactPattern(p)
|
||||
settings = ivySettings
|
||||
setCache(cacheManager(ivySettings, repository).name)
|
||||
setCache(cacheManager(project, scope, ivySettings, repository).name)
|
||||
}
|
||||
|
||||
override fun resolve(artifactId: DefaultArtifactIdentifier, sha256: String?): DefaultArtifact? {
|
||||
@@ -149,11 +158,16 @@ internal class IvyResolver(
|
||||
}
|
||||
}
|
||||
|
||||
private fun cacheManager(ivySettings: IvySettings, repository: ArtifactRepository): RepositoryCacheManager {
|
||||
private fun cacheManager(
|
||||
project: Project,
|
||||
scope: ConfigurationScope,
|
||||
ivySettings: IvySettings,
|
||||
repository: ArtifactRepository
|
||||
): RepositoryCacheManager {
|
||||
return DefaultRepositoryCacheManager(
|
||||
"${repository.name}-cache",
|
||||
"${scope.name.toLowerCase()}-${repository.name}-cache",
|
||||
ivySettings,
|
||||
createTempDir("gradle2nix-${repository.name}-cache")
|
||||
project.buildDir.resolve("tmp/gradle2nix/${scope.name.toLowerCase()}/${repository.name}")
|
||||
).also {
|
||||
ivySettings.addRepositoryCacheManager(it)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user