name.remal.gradle_plugins.testing.dsl.org.gradle.api.Project-testMavenProject.kt Maven / Gradle / Ivy
package name.remal.gradle_plugins.testing.dsl
import name.remal.createDirectories
import name.remal.gradle_plugins.dsl.GradleEnumVersion.GRADLE_VERSION_6_0
import name.remal.gradle_plugins.dsl.extensions.compareTo
import name.remal.newTempDir
import org.gradle.api.Project
import org.gradle.api.artifacts.repositories.MavenArtifactRepository
import org.gradle.util.GradleVersion
import org.redundent.kotlin.xml.Node
import org.redundent.kotlin.xml.PrintOptions
import org.redundent.kotlin.xml.xml
import java.io.File
import java.nio.charset.Charset
import java.nio.charset.StandardCharsets.UTF_8
import java.nio.file.attribute.FileTime.fromMillis
import java.util.*
import java.util.zip.ZipEntry
import java.util.zip.ZipOutputStream
import kotlin.LazyThreadSafetyMode.NONE
val TEST_MAVEN_REPO_DEFAULT_GROUP_ID = "test"
val TEST_MAVEN_REPO_DEFAULT_VERSION = "0"
fun Project.testMavenRepository(init: TestMavenRepository.() -> Unit = {}): MavenArtifactRepository {
val directory = newTempDir(".maven-repository-", false, projectDir)
return repositories.mavenLocal().also {
it.setUrl(directory)
TestMavenRepository(directory).apply(init)
}
}
@MavenRepositoryDslMarker
class TestMavenRepository(private val repositoryDir: File) {
private val components = mutableListOf()
@Suppress("NestedBlockDepth", "ComplexMethod")
fun component(groupId: String = TEST_MAVEN_REPO_DEFAULT_GROUP_ID, artifactId: String, version: String = TEST_MAVEN_REPO_DEFAULT_VERSION, init: TestMavenComponent.() -> Unit = {}): TestMavenComponent {
if (version.endsWith("-SNAPSHOT")) {
throw IllegalArgumentException("SNAPSHOT versions aren't supported for " + TestMavenRepository::class.java.simpleName)
}
val componentDir = File([email protected], "${groupId.replace('.', '/')}/$artifactId/$version")
componentDir.createDirectories()
val component = TestMavenComponent(groupId, artifactId, version).apply(init).apply {
if (jars.isNotEmpty()) {
pom.rootNode.apply {
firstOrNull("packaging")?.let(this::removeNode)
element("packaging", "jar")
}
}
File(componentDir, "$artifactId-$version.pom").writeText(pom.rootNode.toString(PrintOptions(singleLineTextElements = true)), UTF_8)
jars.forEach { classifier, jar ->
val file = File(componentDir, if (classifier.isEmpty()) "$artifactId-$version.jar" else "$artifactId-$version-$classifier.jar")
if (jar.entries.isEmpty()) {
file.writeBytes(byteArrayOf(80, 75, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)) // empty zip archive
return@forEach
}
file.outputStream().use {
ZipOutputStream(it, UTF_8).use { out ->
jar.entries.forEach { name, content ->
out.putNextEntry(ZipEntry(name).apply {
creationTime = fromMillis(System.currentTimeMillis())
lastModifiedTime = creationTime
})
out.write(content)
}
}
}
}
}
components.add(component)
if (GradleVersion.current() >= GRADLE_VERSION_6_0) {
val versions = components.asSequence()
.filter { it.groupId == component.groupId && it.artifactId == component.artifactId }
.map(TestMavenComponent::version)
.toSet()
val mavenMetadata = xml("metadata", "UTF-8") {
element("groupId", component.groupId)
element("artifactId", component.artifactId)
element("versioning") {
element("versions") {
versions.forEach {
element("version", it)
}
}
}
}
val mavenMetadataFile = componentDir.resolve("../maven-metadata.xml")
mavenMetadataFile.writeText(mavenMetadata.toString(PrintOptions(singleLineTextElements = true)), UTF_8)
}
return component
}
}
@MavenRepositoryDslMarker
class TestMavenComponent(
override val groupId: String,
override val artifactId: String,
override val version: String
) : MavenCoordinates {
internal val pom: TestMavenPom = TestMavenPom(xml("project", "UTF-8") {
xmlns = "http://maven.apache.org/POM/4.0.0"
element("modelVersion", "4.0.0")
element("groupId", groupId)
element("artifactId", artifactId)
element("version", [email protected])
element("packaging", "pom")
})
fun pom(init: TestMavenPom.() -> Unit = {}) = apply { init(pom) }
internal val jars = sortedMapOf()
fun jar(classifier: String = "", init: TestMavenJar.() -> Unit = {}) = apply {
jars[classifier] = TestMavenJar().apply(init)
}
}
@MavenRepositoryDslMarker
class TestMavenPom(internal val rootNode: Node) {
private val dependenciesNode: Node by lazy(NONE) { rootNode.element("dependencies") }
fun dependency(groupId: String = TEST_MAVEN_REPO_DEFAULT_GROUP_ID, artifactId: String, version: String = TEST_MAVEN_REPO_DEFAULT_VERSION) = apply {
dependenciesNode.element("dependency") {
element("groupId", groupId)
element("artifactId", artifactId)
element("version", version)
}
}
fun dependency(coordinates: MavenCoordinates) = dependency(coordinates.groupId, coordinates.artifactId, coordinates.version)
private val distributionManagementNode: Node by lazy(NONE) { rootNode.element("distributionManagement") }
fun relocation(groupId: String = TEST_MAVEN_REPO_DEFAULT_GROUP_ID, artifactId: String, version: String = TEST_MAVEN_REPO_DEFAULT_VERSION) = apply {
distributionManagementNode.removeAllChildren().element("relocation") {
element("groupId", groupId)
element("artifactId", artifactId)
element("version", version)
}
}
fun relocation(coordinates: MavenCoordinates) = relocation(coordinates.groupId, coordinates.artifactId, coordinates.version)
}
@MavenRepositoryDslMarker
class TestMavenJar {
internal val entries = mutableMapOf()
fun binary(name: String, content: ByteArray) = apply {
entries[name] = content
}
fun text(name: String, content: String, charset: Charset = UTF_8) = binary(name, content.toByteArray(charset))
}
interface MavenCoordinates {
val groupId: String
val artifactId: String
val version: String
}
@DslMarker
private annotation class MavenRepositoryDslMarker
private fun Node.removeAllChildren() = apply {
val children = children
children as ArrayList
children.clear()
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy