Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
209 changes: 108 additions & 101 deletions src/main/kotlin/nmcp/internal/task/nmcpPublishFileByFile.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import gratatouille.GInputFiles
import gratatouille.GLogger
import gratatouille.GTask
import java.security.MessageDigest
import kotlin.text.lastIndexOf
import kotlin.text.substring
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import okio.ByteString.Companion.toByteString
Expand Down Expand Up @@ -37,123 +39,128 @@ fun nmcpPublishFileByFile(
}
}

inputFiles
.filter { it.file.isFile }
.groupBy {
it.normalizedPath.substringBeforeLast('/')
}.forEach { (gavPath, files) ->
val gav = Gav.from(gavPath)
val version = gav.version

if (files.all { it.normalizedPath.substringAfterLast('/').startsWith("maven-metadata") }) {
/**
* Update the [artifact metadata](https://maven.apache.org/repositories/metadata.html).
*
* See https://repo1.maven.org/maven2/com/apollographql/apollo/apollo-api-jvm/maven-metadata.xml for an example.
*/
val localArtifactMetadataFile = files.firstOrNull {it.normalizedPath.substringAfterLast('/') == "maven-metadata.xml" }
if (localArtifactMetadataFile == null) {
error("Nmcp: cannot find artifact maven-metadata.xml in '${gav.groupId.toPath()}/${gav.artifactId}'")
}
val artifactMetadataPath = localArtifactMetadataFile.normalizedPath
val allFiles = inputFiles.filter { it.file.isFile }
val gavPaths = allFiles.filter { it.normalizedPath.endsWith(".pom") || it.normalizedPath.endsWith(".module") }
.map { it.normalizedPath.substringBeforeLast('/') }
.distinct()

val localArtifactMetadata = xml.decodeFromString<ArtifactMetadata>(localArtifactMetadataFile.file.readText())
val remoteArtifactMetadata = transport.get(artifactMetadataPath)
gavPaths.forEach { gavPath ->
val gav = Gav.from(gavPath)
val version = gav.version
val gavFiles = allFiles.filter { it.normalizedPath.startsWith(gavPath) }

val existingVersions = if (remoteArtifactMetadata != null) {
xml.decodeFromString<ArtifactMetadata>(remoteArtifactMetadata.use { it.readUtf8() }).versioning.versions
} else {
emptyList()
}
/**
* This is a proper directory containing artifacts
*/
if (version.endsWith("-SNAPSHOT")) {
/**
* This is a snapshot:
* - update the [version metadata](https://maven.apache.org/repositories/metadata.html).
* - path the file names to include the new build number.
*
* See https://s01.oss.sonatype.org/content/repositories/snapshots/com/apollographql/apollo/apollo-api-jvm/maven-metadata.xml for an example.
*
* For snapshots, it's not 100% clear who owns the metadata as the repository might expire some snapshot and therefore need to rewrite the
* metadata to keep things consistent. This means, there are 2 possibly concurrent writers to maven-metadata.xml: the repository and the
* publisher. Hopefully it's not too much of a problem in practice.
*
* See https://github.com/gradle/gradle/blob/d1ee068b1ee7f62ffcbb549352469307781af72e/platforms/software/maven/src/main/java/org/gradle/api/publish/maven/internal/publisher/MavenRemotePublisher.java#L70.
*/
val versionMetadataPath = "$gavPath/maven-metadata.xml"
val localVersionMetadataFile = gavFiles.firstOrNull {
it.normalizedPath == versionMetadataPath
}
if (localVersionMetadataFile == null) {
error("Nmcp: cannot find version maven-metadata.xml in '$gavPath'")
}

/**
* See https://github.com/gradle/gradle/blob/cb0c615fb8e3690971bb7f89ad80f58943360624/platforms/software/maven/src/main/java/org/gradle/api/publish/maven/internal/publisher/AbstractMavenPublisher.java#L116.
*/
val versions = existingVersions.toMutableList()
if (!versions.none { it == gav.version }) {
versions.add(gav.version)
}
val newArtifactMetadata = localArtifactMetadata.copy(
versioning = localArtifactMetadata.versioning.copy(
versions = versions,
),
)

val bytes = encodeToXml(newArtifactMetadata).toByteArray()
transport.put(artifactMetadataPath, bytes)
setOf("md5", "sha1", "sha256", "sha512").forEach {
transport.put("$artifactMetadataPath.$it", bytes.digest(it.uppercase()))
val localVersionMetadata =
xml.decodeFromString<VersionMetadata>(localVersionMetadataFile.file.readText())
val remoteVersionMetadata = transport.get(versionMetadataPath)

val buildNumber = if (remoteVersionMetadata == null) {
1
} else {
xml.decodeFromString<VersionMetadata>(remoteVersionMetadata.use { it.readUtf8() }).versioning.snapshot.buildNumber + 1
}

val newVersionMetadata = localVersionMetadata.copy(
versioning = localVersionMetadata.versioning.copy(
snapshot = localVersionMetadata.versioning.snapshot.copy(buildNumber = buildNumber),
),
)

val renamedFiles = gavFiles.mapNotNull {
if (it.file.name.startsWith("maven-metadata.xml")) {
return@mapNotNull null
}
val newName = it.file.name.replaceBuildNumber(gav.artifactId, gav.version, buildNumber)
FileWithPath(it.file, "$gavPath/$newName")
}

transport.uploadFiles(renamedFiles)

return@forEach
val bytes = encodeToXml(newVersionMetadata).toByteArray()
transport.put(versionMetadataPath, bytes)
setOf("md5", "sha1", "sha256", "sha512").forEach {
transport.put("$versionMetadataPath.$it", bytes.digest(it.uppercase()))
}
} else {
/**
* This is a proper directory containing artifacts
* Not a snapshot, plainly update all the files
*/
if (version.endsWith("-SNAPSHOT")) {
/**
* This is a snapshot:
* - update the [version metadata](https://maven.apache.org/repositories/metadata.html).
* - path the file names to include the new build number.
*
* See https://s01.oss.sonatype.org/content/repositories/snapshots/com/apollographql/apollo/apollo-api-jvm/maven-metadata.xml for an example.
*
* For snapshots, it's not 100% clear who owns the metadata as the repository might expire some snapshot and therefore need to rewrite the
* metadata to keep things consistent. This means, there are 2 possibly concurrent writers to maven-metadata.xml: the repository and the
* publisher. Hopefully it's not too much of a problem in practice.
*
* See https://github.com/gradle/gradle/blob/d1ee068b1ee7f62ffcbb549352469307781af72e/platforms/software/maven/src/main/java/org/gradle/api/publish/maven/internal/publisher/MavenRemotePublisher.java#L70.
*/
val versionMetadataPath = "$gavPath/maven-metadata.xml"
val localVersionMetadataFile = files.firstOrNull {
it.normalizedPath == versionMetadataPath
}
if (localVersionMetadataFile == null) {
error("Nmcp: cannot find version maven-metadata.xml in '$gavPath'")
}

val localVersionMetadata =
xml.decodeFromString<VersionMetadata>(localVersionMetadataFile.file.readText())
val remoteVersionMetadata = transport.get(versionMetadataPath)
transport.uploadFiles(gavFiles)
}

val buildNumber = if (remoteVersionMetadata == null) {
1
} else {
xml.decodeFromString<VersionMetadata>(remoteVersionMetadata.use { it.readUtf8() }).versioning.snapshot.buildNumber + 1
}
/**
* Update the [artifact metadata](https://maven.apache.org/repositories/metadata.html).
*
* See https://repo1.maven.org/maven2/com/apollographql/apollo/apollo-api-jvm/maven-metadata.xml for an example.
*/
val index = gavPath.lastIndexOf('/')
check (index != -1) {
"Nmcp: invalid gav path: '$gavPath'"
}
val artifactMetadataPath = "${gavPath.substring(0, index)}/maven-metadata.xml"
val localArtifactMetadataFile = allFiles.firstOrNull { it.normalizedPath == artifactMetadataPath }
if (localArtifactMetadataFile == null) {
error("Nmcp: cannot find artifact metadata at '${artifactMetadataPath}'")
}

val newVersionMetadata = localVersionMetadata.copy(
versioning = localVersionMetadata.versioning.copy(
snapshot = localVersionMetadata.versioning.snapshot.copy(buildNumber = buildNumber),
),
)

val renamedFiles = files.mapNotNull {
if (it.file.name.startsWith("maven-metadata.xml")) {
return@mapNotNull null
}
val newName = it.file.name.replaceBuildNumber(gav.artifactId, gav.version, buildNumber)
FileWithPath(it.file, "$gavPath/$newName")
}
val localArtifactMetadata =
xml.decodeFromString<ArtifactMetadata>(localArtifactMetadataFile.file.readText())
val remoteArtifactMetadata = transport.get(artifactMetadataPath)

transport.uploadFiles(renamedFiles)
val existingVersions = if (remoteArtifactMetadata != null) {
xml.decodeFromString<ArtifactMetadata>(remoteArtifactMetadata.use { it.readUtf8() }).versioning.versions
} else {
emptyList()
}

val bytes = encodeToXml(newVersionMetadata).toByteArray()
transport.put(versionMetadataPath, bytes)
setOf("md5", "sha1", "sha256", "sha512").forEach {
transport.put("$versionMetadataPath.$it", bytes.digest(it.uppercase()))
}
} else {
/**
* Not a snapshot, plainly update all the files
*/
transport.uploadFiles(files)
}
/**
* See https://github.com/gradle/gradle/blob/cb0c615fb8e3690971bb7f89ad80f58943360624/platforms/software/maven/src/main/java/org/gradle/api/publish/maven/internal/publisher/AbstractMavenPublisher.java#L116.
*/
val versions = existingVersions.toMutableList()
if (!versions.none { it == gav.version }) {
versions.add(gav.version)
}
val newArtifactMetadata = localArtifactMetadata.copy(
versioning = localArtifactMetadata.versioning.copy(
versions = versions,
),
)

val bytes = encodeToXml(newArtifactMetadata).toByteArray()
transport.put(artifactMetadataPath, bytes)
setOf("md5", "sha1", "sha256", "sha512").forEach {
transport.put("$artifactMetadataPath.$it", bytes.digest(it.uppercase()))
}

}
}

private fun Transport.uploadFiles(filesWithPath: List<FileWithPath>) {
filesWithPath.forEach {
filesWithPath.sortedBy { it.normalizedPath }.forEach {
put(it.normalizedPath, it.file)
}
}
Expand Down
2 changes: 0 additions & 2 deletions src/main/kotlin/nmcp/internal/utils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ import org.gradle.api.attributes.HasConfigurableAttributes
import org.gradle.api.attributes.Usage
import org.gradle.api.attributes.Usage.USAGE_ATTRIBUTE
import org.gradle.api.file.FileCollection
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.bundling.Zip

internal fun Project.withRequiredPlugin(id: String, block: () -> Unit) {
var hasPlugin = false
Expand Down