Rewrite plugin, use filenames in lockfile

This commit is contained in:
Tad Fisher
2024-05-17 14:52:02 -07:00
parent e83e42f9d4
commit 8d2ec45ad4
144 changed files with 8679 additions and 7507 deletions

View File

@@ -2,11 +2,6 @@ import org.jetbrains.kotlin.gradle.dsl.JvmTarget
plugins {
id("org.jetbrains.kotlin.jvm")
id("org.jetbrains.kotlin.plugin.serialization")
}
dependencies {
implementation(libs.serialization.json)
}
java {

View File

@@ -1,62 +1,33 @@
package org.nixos.gradle2nix.model
import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializable
import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import java.io.Serializable
@Serializable(DependencyCoordinates.Serializer::class)
data class DependencyCoordinates(
val group: String,
val module: String,
val version: String,
val timestamp: String? = null
) : Comparable<DependencyCoordinates> {
interface DependencyCoordinates : Serializable {
val group: String
val artifact: String
override fun toString(): String = if (timestamp != null) {
"$group:$module:$version:$timestamp"
/**
* For normal dependencies, the dependency version (e.g. "2.0.2").
*
* For Maven snapshot dependencies, the snapshot version (e.g. "2.0.2-SNAPSHOT").
*/
val version: String
/**
* For Maven snapshot dependencies, the snapshot timestamp (e.g. "20070310.18163-3").
*
* For normal dependencies, this is null.
*/
val timestamp: String?
val id: String get() = if (timestamp != null) {
"$group:$artifact:$version:$timestamp"
} else {
"$group:$module:$version"
"$group:$artifact:$version"
}
val artifactVersion: String get() =
timestamp?.let { version.replace("SNAPSHOT", it) } ?: version
val timestampedCoordinates: DependencyCoordinates
override fun compareTo(other: DependencyCoordinates): Int = comparator.compare(this, other)
object Serializer : KSerializer<DependencyCoordinates> {
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor(
DependencyCoordinates::class.qualifiedName!!,
PrimitiveKind.STRING
)
override fun deserialize(decoder: Decoder): DependencyCoordinates {
val encoded = decoder.decodeString()
return parse(encoded)
}
override fun serialize(encoder: Encoder, value: DependencyCoordinates) {
encoder.encodeString(value.toString())
}
}
companion object {
val comparator = compareBy<DependencyCoordinates> { it.group }
.thenBy { it.module }
.thenByDescending { it.artifactVersion }
fun parse(id: String): DependencyCoordinates {
val parts = id.split(":")
return when (parts.size) {
3 -> DependencyCoordinates(parts[0], parts[1], parts[2])
4 -> DependencyCoordinates(parts[0], parts[1], parts[2], parts[3])
else -> throw IllegalStateException(
"couldn't parse dependency coordinates: '$id'"
)
}
}
}
val timestampedVersion: String get() =
timestamp?.let { version.replace("-SNAPSHOT", "-$it") } ?: version
}

View File

@@ -0,0 +1,8 @@
package org.nixos.gradle2nix.model
import java.io.Serializable
import org.nixos.gradle2nix.model.impl.DefaultRepository
interface DependencySet : Serializable {
val dependencies: List<ResolvedDependency>
}

View File

@@ -1,26 +0,0 @@
package org.nixos.gradle2nix.model
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
/**
* The source of a dependency declaration, representing where the direct dependency is declared,
* or where the parent dependency is declared for transitive dependencies.
* In most cases, this will be the project component that declares the dependency,
* but may also be a Version Catalog or the build as a whole.
* We attempt to map this to an actual source file location when building a dependency report.
*/
@Serializable
data class DependencySource(
val targetType: ConfigurationTarget,
val targetPath: String,
val buildPath: String,
)
@Serializable
enum class ConfigurationTarget {
@SerialName("gradle") GRADLE,
@SerialName("settings") SETTINGS,
@SerialName("buildscript") BUILDSCRIPT,
@SerialName("project") PROJECT,
}

View File

@@ -1,7 +1,4 @@
package org.nixos.gradle2nix.model
const val PARAM_INCLUDE_PROJECTS = "NIX_INCLUDE_PROJECTS"
const val PARAM_INCLUDE_CONFIGURATIONS = "NIX_INCLUDE_CONFIGURATIONS"
const val PARAM_REPORT_DIR = "NIX_REPORT_DIR"
const val RESOLVE_PROJECT_TASK = "resolveProjectDependencies"
const val RESOLVE_ALL_TASK = "resolveAllDependencies"

View File

@@ -1,20 +1,16 @@
package org.nixos.gradle2nix.model
import kotlinx.serialization.Serializable
import java.io.Serializable
interface Repository : Serializable {
val id: String
val type: Type
val metadataSources: List<String>
val metadataResources: List<String>
val artifactResources: List<String>
@Serializable
data class Repository(
val id: String,
val type: Type,
val name: String,
val m2Compatible: Boolean,
val metadataSources: List<String>,
val metadataResources: List<String>,
val artifactResources: List<String>,
) {
enum class Type {
MAVEN,
IVY,
FLAT_DIR
}
}

View File

@@ -1,16 +1,9 @@
package org.nixos.gradle2nix.model
import kotlinx.serialization.Serializable
import java.io.Serializable
@Serializable
data class ResolvedArtifact(
val type: Type?,
val file: String,
) {
enum class Type {
SOURCES,
JAVADOC,
IVY_DESCRIPTOR,
MAVEN_POM,
}
interface ResolvedArtifact : Serializable {
val name: String
val filename: String
val urls: List<String>
}

View File

@@ -1,19 +0,0 @@
package org.nixos.gradle2nix.model
import kotlinx.serialization.Serializable
@Serializable
data class ResolvedConfiguration(
val rootSource: DependencySource,
val configurationName: String,
val repositories: List<Repository> = emptyList(),
val allDependencies: MutableList<ResolvedDependency> = mutableListOf()
) {
fun addDependency(component: ResolvedDependency) {
allDependencies.add(component)
}
fun hasDependency(componentId: DependencyCoordinates): Boolean {
return allDependencies.any { it.id == componentId }
}
}

View File

@@ -1,12 +1,8 @@
package org.nixos.gradle2nix.model
import kotlinx.serialization.Serializable
import java.io.Serializable
@Serializable
data class ResolvedDependency(
val id: DependencyCoordinates,
val source: DependencySource,
val direct: Boolean,
val repository: String?,
val dependencies: List<String> = emptyList(),
)
interface ResolvedDependency : Serializable {
val coordinates: DependencyCoordinates
val artifacts: List<ResolvedArtifact>
}

View File

@@ -1,9 +0,0 @@
package org.nixos.gradle2nix.model
import kotlinx.serialization.Serializable
@Serializable
data class ResolvedMetadata(
val moduleId: String,
val uri: String
)

View File

@@ -1,172 +0,0 @@
package org.nixos.gradle2nix.model
import java.util.concurrent.ConcurrentHashMap
import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializable
import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
@Serializable(Version.Serializer::class)
class Version(val source: String, val parts: List<String>, base: Version?) : Comparable<Version> {
private val base: Version
val numericParts: List<Long?>
init {
this.base = base ?: this
this.numericParts = parts.map {
try { it.toLong() } catch (e: NumberFormatException) { null }
}
}
override fun compareTo(other: Version): Int = compare(this, other)
override fun toString(): String = source
override fun equals(other: Any?): Boolean = when {
other === this -> true
other == null || other !is Version -> false
else -> source == other.source
}
override fun hashCode(): Int = source.hashCode()
object Comparator : kotlin.Comparator<Version> {
override fun compare(o1: Version, o2: Version): Int =
Version.compare(o1, o2)
}
internal object Serializer : KSerializer<Version> {
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor(
Version::class.qualifiedName!!,
PrimitiveKind.STRING
)
override fun serialize(encoder: Encoder, value: Version) {
encoder.encodeString(value.source)
}
override fun deserialize(decoder: Decoder): Version {
return Version(decoder.decodeString())
}
}
companion object {
private val SPECIAL_MEANINGS: Map<String, Int> = mapOf(
"dev" to -1,
"rc" to 1,
"snapshot" to 2,
"final" to 3,
"ga" to 4,
"release" to 5,
"sp" to 6
)
private val cache = ConcurrentHashMap<String, Version>()
// From org.gradle.api.internal.artifacts.ivyservice.ivyresolve.strategy.VersionParser
operator fun invoke(original: String): Version = cache.getOrPut(original) {
val parts = mutableListOf<String>()
var digit = false
var startPart = 0
var pos = 0
var endBase = 0
var endBaseStr = 0
while (pos < original.length) {
val ch = original[pos]
if (ch == '.' || ch == '_' || ch == '-' || ch == '+') {
parts.add(original.substring(startPart, pos))
startPart = pos + 1
digit = false
if (ch != '.' && endBaseStr == 0) {
endBase = parts.size
endBaseStr = pos
}
} else if (ch in '0'..'9') {
if (!digit && pos > startPart) {
if (endBaseStr == 0) {
endBase = parts.size + 1
endBaseStr = pos
}
parts.add(original.substring(startPart, pos))
startPart = pos
}
digit = true
} else {
if (digit) {
if (endBaseStr == 0) {
endBase = parts.size + 1
endBaseStr = pos
}
parts.add(original.substring(startPart, pos))
startPart = pos
}
digit = false
}
pos++
}
if (pos > startPart) {
parts.add(original.substring(startPart, pos))
}
var base: Version? = null
if (endBaseStr > 0) {
base = Version(original.substring(0, endBaseStr), parts.subList(0, endBase), null)
}
Version(original, parts, base)
}
// From org.gradle.api.internal.artifacts.ivyservice.ivyresolve.strategy.StaticVersionComparator
private fun compare(version1: Version, version2: Version): Int {
if (version1 == version2) {
return 0
}
val parts1 = version1.parts
val parts2 = version2.parts
val numericParts1 = version1.numericParts
val numericParts2 = version2.numericParts
var lastIndex = -1
for (i in 0..<(minOf(parts1.size, parts2.size))) {
lastIndex = i
val part1 = parts1[i]
val part2 = parts2[i]
val numericPart1 = numericParts1[i]
val numericPart2 = numericParts2[i]
when {
part1 == part2 -> continue
numericPart1 != null && numericPart2 == null -> return 1
numericPart2 != null && numericPart1 == null -> return -1
numericPart1 != null && numericPart2 != null -> {
val result = numericPart1.compareTo(numericPart2)
if (result == 0) continue
return result
}
else -> {
// both are strings, we compare them taking into account special meaning
val sm1 = SPECIAL_MEANINGS[part1.lowercase()]
val sm2 = SPECIAL_MEANINGS[part2.lowercase()]
if (sm1 != null) return sm1 - (sm2 ?: 0)
if (sm2 != null) return -sm2
return part1.compareTo(part2)
}
}
}
if (lastIndex < parts1.size) {
return if (numericParts1[lastIndex] == null) -1 else 1
}
if (lastIndex < parts2.size) {
return if (numericParts2[lastIndex] == null) 1 else -1
}
return 0
}
}
}

View File

@@ -0,0 +1,29 @@
package org.nixos.gradle2nix.model.impl
import org.nixos.gradle2nix.model.DependencyCoordinates
data class DefaultDependencyCoordinates(
override val group: String,
override val artifact: String,
override val version: String,
override val timestamp: String? = null
) : DependencyCoordinates {
override val timestampedCoordinates: DependencyCoordinates
get() = DefaultDependencyCoordinates(group, artifact, timestampedVersion)
override fun toString(): String = id
companion object {
fun parse(id: String): DependencyCoordinates {
val parts = id.split(":")
return when (parts.size) {
3 -> DefaultDependencyCoordinates(parts[0], parts[1], parts[2])
4 -> DefaultDependencyCoordinates(parts[0], parts[1], parts[2], parts[3])
else -> throw IllegalStateException(
"couldn't parse dependency coordinates: '$id'"
)
}
}
}
}

View File

@@ -0,0 +1,8 @@
package org.nixos.gradle2nix.model.impl
import org.nixos.gradle2nix.model.DependencySet
import org.nixos.gradle2nix.model.ResolvedDependency
data class DefaultDependencySet(
override val dependencies: List<ResolvedDependency>
) : DependencySet

View File

@@ -0,0 +1,11 @@
package org.nixos.gradle2nix.model.impl
import org.nixos.gradle2nix.model.Repository
data class DefaultRepository(
override val id: String,
override val type: Repository.Type,
override val metadataSources: List<String>,
override val metadataResources: List<String>,
override val artifactResources: List<String>,
) : Repository

View File

@@ -0,0 +1,9 @@
package org.nixos.gradle2nix.model.impl
import org.nixos.gradle2nix.model.ResolvedArtifact
data class DefaultResolvedArtifact(
override val name: String,
override val filename: String,
override val urls: List<String>
) : ResolvedArtifact

View File

@@ -0,0 +1,10 @@
package org.nixos.gradle2nix.model.impl
import org.nixos.gradle2nix.model.DependencyCoordinates
import org.nixos.gradle2nix.model.ResolvedArtifact
import org.nixos.gradle2nix.model.ResolvedDependency
data class DefaultResolvedDependency(
override val coordinates: DependencyCoordinates,
override val artifacts: List<ResolvedArtifact>,
) : ResolvedDependency