diff --git a/src/funcTest/groovy/com/github/jengelman/gradle/plugins/shadow/BasePluginSpecification.groovy b/src/funcTest/groovy/com/github/jengelman/gradle/plugins/shadow/BasePluginSpecification.groovy index 9341154f1..9998368d3 100644 --- a/src/funcTest/groovy/com/github/jengelman/gradle/plugins/shadow/BasePluginSpecification.groovy +++ b/src/funcTest/groovy/com/github/jengelman/gradle/plugins/shadow/BasePluginSpecification.groovy @@ -1,7 +1,7 @@ package com.github.jengelman.gradle.plugins.shadow import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar -import com.github.jengelman.gradle.plugins.shadow.util.AppendableMavenFileRepository +import com.github.jengelman.gradle.plugins.shadow.util.AppendableMavenRepository import org.apache.commons.lang3.StringUtils import org.gradle.testkit.runner.BuildResult import org.gradle.testkit.runner.GradleRunner @@ -17,13 +17,13 @@ abstract class BasePluginSpecification extends Specification { @TempDir Path root - AppendableMavenFileRepository repo + AppendableMavenRepository repo def setup() { - repo = new AppendableMavenFileRepository(root.resolve('maven-repo')) - repo.module('junit', 'junit', '3.8.2') - .use(Paths.get(this.class.classLoader.getResource('junit-3.8.2.jar').toURI())) - .publish() + repo = new AppendableMavenRepository(root.resolve('local-maven-repo'), runner) + repo.module('junit', 'junit', '3.8.2') { module -> + module.useJar(Paths.get(this.class.classLoader.getResource('junit-3.8.2.jar').toURI())) + }.publish() projectScriptFile << getDefaultProjectBuildScript('java', true, true) settingsScriptFile << getDefaultSettingsBuildScript() @@ -57,7 +57,7 @@ abstract class BasePluginSpecification extends Specification { return """ dependencyResolutionManagement { repositories { - maven { url = "${repo.uri}" } + maven { url = "${repo.root.toUri()}" } mavenCentral() } } diff --git a/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/BasePluginTest.kt b/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/BasePluginTest.kt index 2a1319432..8565abac4 100644 --- a/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/BasePluginTest.kt +++ b/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/BasePluginTest.kt @@ -4,7 +4,7 @@ import com.github.jengelman.gradle.plugins.shadow.ShadowApplicationPlugin.Compan import com.github.jengelman.gradle.plugins.shadow.ShadowJavaPlugin.Companion.SHADOW_JAR_TASK_NAME import com.github.jengelman.gradle.plugins.shadow.tasks.JavaJarExec import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar -import com.github.jengelman.gradle.plugins.shadow.util.AppendableMavenFileRepository +import com.github.jengelman.gradle.plugins.shadow.util.AppendableMavenRepository import com.github.jengelman.gradle.plugins.shadow.util.JarPath import java.nio.file.Path import java.util.Properties @@ -30,16 +30,16 @@ import org.junit.jupiter.api.TestInstance @TestInstance(TestInstance.Lifecycle.PER_CLASS) abstract class BasePluginTest { private lateinit var root: Path - lateinit var repo: AppendableMavenFileRepository + lateinit var localRepo: AppendableMavenRepository @BeforeEach open fun setup() { root = createTempDirectory() - repo = repo() - repo.module("junit", "junit", "3.8.2") - .use(testJar) - .publish() + localRepo = repo() + localRepo.module("junit", "junit", "3.8.2") { + useJar(testJar) + }.publish() projectScriptPath.writeText(getDefaultProjectBuildScript(withGroup = true, withVersion = true)) settingsScriptPath.writeText(getDefaultSettingsBuildScript()) @@ -81,7 +81,7 @@ abstract class BasePluginTest { $startBlock dependencyResolutionManagement { repositories { - maven { url = '${repo.uri}' } + maven { url = '${localRepo.root.toUri()}' } mavenCentral() } } @@ -90,27 +90,28 @@ abstract class BasePluginTest { } fun publishArtifactA() { - repo.module("shadow", "a", "1.0") - .insertFile("a.properties", "a") - .insertFile("a2.properties", "a2") - .publish() + localRepo.module("shadow", "a", "1.0") { + insert("a.properties", "a") + insert("a2.properties", "a2") + }.publish() } fun publishArtifactB() { - repo.module("shadow", "b", "1.0") - .insertFile("b.properties", "b") - .publish() + localRepo.module("shadow", "b", "1.0") { + insert("b.properties", "b") + }.publish() } fun publishArtifactCD(circular: Boolean = false) { - repo.module("shadow", "c", "1.0") - .insertFile("c.properties", "c") - .apply { if (circular) dependsOn("d") } - .publish() - repo.module("shadow", "d", "1.0") - .insertFile("d.properties", "d") - .dependsOn("c") - .publish() + localRepo.module("shadow", "c", "1.0") { + insert("c.properties", "c") + if (circular) { + addDependency("shadow", "d", "1.0") + } + }.module("shadow", "d", "1.0") { + insert("d.properties", "d") + addDependency("shadow", "c", "1.0") + }.publish() } open val shadowJarTask = SHADOW_JAR_TASK_NAME @@ -146,8 +147,8 @@ abstract class BasePluginTest { } } - fun repo(path: String = "maven-repo"): AppendableMavenFileRepository { - return AppendableMavenFileRepository(root.resolve(path)) + fun repo(path: String = "local-maven-repo"): AppendableMavenRepository { + return AppendableMavenRepository(root.resolve(path), runner) } private val runner: GradleRunner @@ -160,12 +161,7 @@ abstract class BasePluginTest { } fun runner(arguments: Iterable): GradleRunner { - val allArguments = listOf( - "--warning-mode=fail", - "--configuration-cache", - "--stacktrace", - ) + arguments - return runner.withArguments(allArguments) + return runner.withArguments(commonArguments + arguments) } inline fun run( @@ -319,6 +315,12 @@ abstract class BasePluginTest { tasks.named('$SHADOW_RUN_TASK_NAME', ${JavaJarExec::class.java.name}) """.trimIndent() + val commonArguments = listOf( + "--warning-mode=fail", + "--configuration-cache", + "--stacktrace", + ) + fun String.toProperties(): Properties = Properties().apply { load(byteInputStream()) } fun fromJar(vararg paths: Path): String { diff --git a/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/PublishingTest.kt b/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/PublishingTest.kt index 7310688b9..951c7cdc2 100644 --- a/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/PublishingTest.kt +++ b/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/PublishingTest.kt @@ -5,7 +5,7 @@ import assertk.assertThat import assertk.assertions.containsOnly import assertk.assertions.isEmpty import assertk.assertions.isEqualTo -import com.github.jengelman.gradle.plugins.shadow.util.AppendableMavenFileRepository +import com.github.jengelman.gradle.plugins.shadow.util.AppendableMavenRepository import com.github.jengelman.gradle.plugins.shadow.util.GradleModuleMetadata import com.github.jengelman.gradle.plugins.shadow.util.Issue import com.github.jengelman.gradle.plugins.shadow.util.JarPath @@ -34,12 +34,12 @@ class PublishingTest : BasePluginTest() { private val gmmAdapter = moshi.adapter(GradleModuleMetadata::class.java) private val pomReader = MavenXpp3Reader() - private lateinit var publishingRepo: AppendableMavenFileRepository + private lateinit var remoteRepo: AppendableMavenRepository @BeforeEach override fun setup() { super.setup() - publishingRepo = repo("remote-repo") + remoteRepo = repo("remote-maven-repo") publishArtifactA() publishArtifactB() @@ -217,7 +217,7 @@ class PublishingTest : BasePluginTest() { } private fun repoPath(path: String): Path { - return publishingRepo.rootDir.resolve(path).also { + return remoteRepo.root.resolve(path).also { check(it.exists()) { "Path not found: $it" } check(it.isRegularFile()) { "Path is not a regular file: $it" } } @@ -258,7 +258,7 @@ class PublishingTest : BasePluginTest() { } repositories { maven { - url = '${publishingRepo.uri}' + url = '${remoteRepo.root.toUri()}' } } } diff --git a/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/RelocationTest.kt b/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/RelocationTest.kt index 3a5038030..43793f62a 100644 --- a/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/RelocationTest.kt +++ b/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/RelocationTest.kt @@ -288,9 +288,9 @@ class RelocationTest : BasePluginTest() { ) @Test fun relocateResourceFiles() { - repo.module("shadow", "dep", "1.0") - .insertFile("foo/dep.properties", "c") - .publish() + localRepo.module("shadow", "dep", "1.0") { + insert("foo/dep.properties", "c") + }.publish() path("src/main/java/foo/Foo.java").writeText( """ package foo; diff --git a/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/ShadowPluginTest.kt b/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/ShadowPluginTest.kt index 67f71634e..a06ad13e5 100644 --- a/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/ShadowPluginTest.kt +++ b/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/ShadowPluginTest.kt @@ -382,15 +382,15 @@ class ShadowPluginTest : BasePluginTest() { @Test fun excludeSomeMetaInfFilesByDefault() { - repo.module("shadow", "a", "1.0") - .insertFile("a.properties", "a") - .insertFile("META-INF/INDEX.LIST", "JarIndex-Version: 1.0") - .insertFile("META-INF/a.SF", "Signature File") - .insertFile("META-INF/a.DSA", "DSA Signature Block") - .insertFile("META-INF/a.RSA", "RSA Signature Block") - .insertFile("META-INF/a.properties", "key=value") - .insertFile("module-info.class", "module myModuleName {}") - .publish() + localRepo.module("shadow", "a", "1.0") { + insert("a.properties", "a") + insert("META-INF/INDEX.LIST", "JarIndex-Version: 1.0") + insert("META-INF/a.SF", "Signature File") + insert("META-INF/a.DSA", "DSA Signature Block") + insert("META-INF/a.RSA", "RSA Signature Block") + insert("META-INF/a.properties", "key=value") + insert("module-info.class", "module myModuleName {}") + }.publish() path("src/main/java/shadow/Passed.java").writeText( """ @@ -449,19 +449,16 @@ class ShadowPluginTest : BasePluginTest() { @Test fun includeJavaLibraryConfigurationsByDefault() { - repo.module("shadow", "api", "1.0") - .insertFile("api.properties", "api") - .publish() - repo.module("shadow", "implementation-dep", "1.0") - .insertFile("implementation-dep.properties", "implementation-dep") - .publish() - repo.module("shadow", "implementation", "1.0") - .insertFile("implementation.properties", "implementation") - .dependsOn("implementation-dep") - .publish() - repo.module("shadow", "runtimeOnly", "1.0") - .insertFile("runtimeOnly.properties", "runtimeOnly") - .publish() + localRepo.module("shadow", "api", "1.0") { + insert("api.properties", "api") + }.module("shadow", "implementation-dep", "1.0") { + insert("implementation-dep.properties", "implementation-dep") + }.module("shadow", "implementation", "1.0") { + insert("implementation.properties", "implementation") + addDependency("shadow", "implementation-dep", "1.0") + }.module("shadow", "runtimeOnly", "1.0") { + insert("runtimeOnly.properties", "runtimeOnly") + }.publish() projectScriptPath.writeText( """ @@ -511,12 +508,11 @@ class ShadowPluginTest : BasePluginTest() { @Test fun defaultCopyingStrategy() { - repo.module("shadow", "a", "1.0") - .insertFile("META-INF/MANIFEST.MF", "MANIFEST A") - .publish() - repo.module("shadow", "b", "1.0") - .insertFile("META-INF/MANIFEST.MF", "MANIFEST B") - .publish() + localRepo.module("shadow", "a", "1.0") { + insert("META-INF/MANIFEST.MF", "MANIFEST A") + }.module("shadow", "b", "1.0") { + insert("META-INF/MANIFEST.MF", "MANIFEST B") + }.publish() projectScriptPath.appendText( """ diff --git a/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/BaseTransformerTest.kt b/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/BaseTransformerTest.kt index c38ad8a12..7f09688a6 100644 --- a/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/BaseTransformerTest.kt +++ b/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/BaseTransformerTest.kt @@ -1,14 +1,14 @@ package com.github.jengelman.gradle.plugins.shadow.transformers import com.github.jengelman.gradle.plugins.shadow.BasePluginTest -import com.github.jengelman.gradle.plugins.shadow.util.AppendableJar +import com.github.jengelman.gradle.plugins.shadow.util.JarBuilder import java.nio.file.Path import kotlin.io.path.writeText sealed class BaseTransformerTest : BasePluginTest() { fun buildJarOne( - builder: AppendableJar.() -> Unit = { + builder: JarBuilder.() -> Unit = { insert(ENTRY_SERVICES_SHADE, CONTENT_ONE) insert(ENTRY_SERVICES_FOO, "one") }, @@ -17,7 +17,7 @@ sealed class BaseTransformerTest : BasePluginTest() { } fun buildJarTwo( - builder: AppendableJar.() -> Unit = { + builder: JarBuilder.() -> Unit = { insert(ENTRY_SERVICES_SHADE, CONTENT_TWO) insert(ENTRY_SERVICES_FOO, "two") }, @@ -25,8 +25,8 @@ sealed class BaseTransformerTest : BasePluginTest() { return buildJar("two.jar", builder) } - inline fun buildJar(path: String, builder: AppendableJar.() -> Unit): Path { - return AppendableJar(path(path)).apply(builder).write() + inline fun buildJar(path: String, builder: JarBuilder.() -> Unit): Path { + return JarBuilder(path(path)).apply(builder).write() } fun writeMainClass() { diff --git a/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/ServiceFileTransformerTest.kt b/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/ServiceFileTransformerTest.kt index 00de08e5a..6b0f8fec4 100644 --- a/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/ServiceFileTransformerTest.kt +++ b/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/ServiceFileTransformerTest.kt @@ -178,9 +178,9 @@ class ServiceFileTransformerTest : BaseTransformerTest() { val one = buildJarOne { insert(servicesShadowEntry, CONTENT_ONE) }.toUri().toURL().path - repo.module("shadow", "two", "1.0") - .insertFile(servicesShadowEntry, CONTENT_TWO) - .publish() + localRepo.module("shadow", "two", "1.0") { + insert(servicesShadowEntry, CONTENT_TWO) + }.publish() projectScriptPath.appendText( """ diff --git a/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/util/AppendableJar.kt b/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/util/AppendableJar.kt deleted file mode 100644 index 41b102d82..000000000 --- a/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/util/AppendableJar.kt +++ /dev/null @@ -1,28 +0,0 @@ -package com.github.jengelman.gradle.plugins.shadow.util - -import java.io.OutputStream -import java.nio.file.Path -import kotlin.io.path.outputStream - -class AppendableJar(private val outputPath: Path) { - private val contents = mutableMapOf() - - fun insert(path: String, content: String): AppendableJar = apply { - contents[path] = content - } - - fun write(): Path { - write(contents, outputPath.outputStream()) - return outputPath - } - - companion object { - fun write(contents: Map, outputStream: OutputStream) { - val builder = JarBuilder(outputStream) - contents.forEach { (path, content) -> - builder.withPath(path, content) - } - builder.build() - } - } -} diff --git a/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/util/AppendableMavenFileModule.kt b/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/util/AppendableMavenFileModule.kt deleted file mode 100644 index d41213392..000000000 --- a/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/util/AppendableMavenFileModule.kt +++ /dev/null @@ -1,46 +0,0 @@ -package com.github.jengelman.gradle.plugins.shadow.util - -import com.github.jengelman.gradle.plugins.shadow.util.repo.maven.MavenFileModule -import java.nio.file.Path -import kotlin.io.path.inputStream - -class AppendableMavenFileModule(module: MavenFileModule) : MavenFileModule(module.moduleDir, module.groupId, module.artifactId, module.version) { - - private val contents = mutableMapOf>().withDefault { mutableMapOf() } - private val paths = mutableMapOf() - - fun use(path: Path): AppendableMavenFileModule { - return use("", path) - } - - fun use(classifier: String, path: Path): AppendableMavenFileModule = apply { - paths[classifier] = path - } - - fun insertFile(path: String, content: String): AppendableMavenFileModule { - return insertFile("", path, content) - } - - fun insertFile(classifier: String, path: String, content: String): AppendableMavenFileModule = apply { - contents.getOrPut(classifier) { mutableMapOf() }[path] = content - } - - override fun publishArtifact(artifact: Map): Path { - val artifactPath = artifactPath(artifact) - if (type == "pom") { - return artifactPath - } - val classifier = artifact["classifier"] as? String ?: "" - val classifierPath = paths[classifier] - if (classifierPath != null) { - publish(artifactPath) { os -> - classifierPath.inputStream().copyTo(os) - } - } else { - publish(artifactPath) { os -> - AppendableJar.write(contents[classifier].orEmpty(), os) - } - } - return artifactPath - } -} diff --git a/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/util/AppendableMavenFileRepository.kt b/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/util/AppendableMavenFileRepository.kt deleted file mode 100644 index e2ce40630..000000000 --- a/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/util/AppendableMavenFileRepository.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.github.jengelman.gradle.plugins.shadow.util - -import com.github.jengelman.gradle.plugins.shadow.util.repo.maven.MavenFileRepository -import java.nio.file.Path - -class AppendableMavenFileRepository(rootDir: Path) : MavenFileRepository(rootDir) { - - override fun module(groupId: String, artifactId: String, version: String): AppendableMavenFileModule { - return AppendableMavenFileModule(super.module(groupId, artifactId, version)) - } -} diff --git a/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/util/AppendableMavenRepository.kt b/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/util/AppendableMavenRepository.kt new file mode 100644 index 000000000..c37ac190a --- /dev/null +++ b/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/util/AppendableMavenRepository.kt @@ -0,0 +1,126 @@ +package com.github.jengelman.gradle.plugins.shadow.util + +import com.github.jengelman.gradle.plugins.shadow.BasePluginTest.Companion.commonArguments +import java.nio.file.Path +import kotlin.io.path.createDirectories +import kotlin.io.path.createFile +import kotlin.io.path.name +import kotlin.io.path.writeText +import org.apache.maven.model.Dependency +import org.apache.maven.model.Model +import org.gradle.testkit.runner.GradleRunner + +class AppendableMavenRepository( + val root: Path, + private val gradleRunner: GradleRunner, +) { + private val projectBuildScript: Path + private val modules = mutableListOf() + + init { + root.createDirectories() + root.resolve("settings.gradle").createFile() + .writeText("rootProject.name = '${root.name}'") + projectBuildScript = root.resolve("build.gradle").createFile() + } + + fun module( + groupId: String, + artifactId: String, + version: String, + action: Module.() -> Unit, + ) = apply { + modules += Module(groupId, artifactId, version).also(action) + } + + fun publish() { + if (modules.isEmpty()) return + projectBuildScript.writeText( + """ + plugins { + id 'maven-publish' + } + publishing { + publications { + ${modules.joinToString(System.lineSeparator()) { createPublication(it) }} + } + repositories { + maven { + url = '${root.toUri()}' + } + } + } + """.trimIndent(), + ) + gradleRunner.withProjectDir(root.toFile()).withArguments(commonArguments + "publish").build() + modules.clear() + } + + private fun createPublication(module: Module) = with(module) { + val outputJar = build(root) + val pubName = outputJar.name.replace(".", "") + + var index = -1 + val nodes = dependencies.joinToString(System.lineSeparator()) { + index++ + val node = "dependencyNode$index" + """ + def $node = dependenciesNode.appendNode('dependency') + $node.appendNode('groupId', '${it.groupId}') + $node.appendNode('artifactId', '${it.artifactId}') + $node.appendNode('version', '${it.version}') + $node.appendNode('scope', '${it.scope}') + """.trimIndent() + } + + """ + create('$pubName', MavenPublication) { + artifactId = '$artifactId' + groupId = '$groupId' + version = '$version' + artifact '${outputJar.toUri().toURL().path}' + pom.withXml { xml -> + def dependenciesNode = xml.asNode().get('dependencies') ?: xml.asNode().appendNode('dependencies') + $nodes + } + } + """.trimIndent() + System.lineSeparator() + } + + class Module( + groupId: String, + artifactId: String, + version: String, + ) : Model() { + private val contents = mutableMapOf() + private var existingJar: Path? = null + + init { + this.groupId = groupId + this.artifactId = artifactId + this.version = version + } + + fun useJar(existingJar: Path) { + this.existingJar = existingJar + } + + fun insert(entry: String, content: String) { + contents[entry] = content + } + + fun addDependency(groupId: String, artifactId: String, version: String, scope: String = "runtime") { + val dependency = Dependency().also { + it.groupId = groupId + it.artifactId = artifactId + it.version = version + it.scope = scope + } + addDependency(dependency) + } + + fun build(root: Path): Path { + return existingJar ?: JarBuilder(root.resolve("$groupId-$artifactId-$version.jar"), contents).write() + } + } +} diff --git a/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/util/JarBuilder.kt b/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/util/JarBuilder.kt index 2372d5823..1ed63a2d7 100644 --- a/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/util/JarBuilder.kt +++ b/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/util/JarBuilder.kt @@ -1,12 +1,36 @@ package com.github.jengelman.gradle.plugins.shadow.util -import java.io.OutputStream +import java.nio.file.Path import java.util.jar.JarEntry import java.util.jar.JarOutputStream +import kotlin.io.path.outputStream -class JarBuilder(os: OutputStream) { +class JarBuilder( + private val outputPath: Path, + private val contents: MutableMap = mutableMapOf(), +) { private val entries = mutableSetOf() - private val jos = JarOutputStream(os) + private val jos = JarOutputStream(outputPath.outputStream()) + + fun insert(path: String, content: String): JarBuilder = apply { + contents[path] = content + } + + fun write(): Path { + jos.use { + contents.forEach { (entry, content) -> + val idx = entry.lastIndexOf('/') + if (idx != -1) { + addDirectory(entry.substring(0, idx)) + } + if (entries.add(entry)) { + jos.putNextEntry(JarEntry(entry)) + content.byteInputStream().copyTo(jos) + } + } + } + return outputPath + } private fun addDirectory(name: String) { if (entries.add(name)) { @@ -18,20 +42,4 @@ class JarBuilder(os: OutputStream) { jos.putNextEntry(JarEntry("$name/")) } } - - fun withPath(path: String, data: String): JarBuilder { - val idx = path.lastIndexOf('/') - if (idx != -1) { - addDirectory(path.substring(0, idx)) - } - if (entries.add(path)) { - jos.putNextEntry(JarEntry(path)) - data.byteInputStream().copyTo(jos) - } - return this - } - - fun build() { - jos.close() - } } diff --git a/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/util/repo/AbstractModule.kt b/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/util/repo/AbstractModule.kt deleted file mode 100644 index 827964aa4..000000000 --- a/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/util/repo/AbstractModule.kt +++ /dev/null @@ -1,79 +0,0 @@ -package com.github.jengelman.gradle.plugins.shadow.util.repo - -import java.io.OutputStream -import java.io.UncheckedIOException -import java.math.BigInteger -import java.nio.file.Path -import kotlin.io.path.absolutePathString -import kotlin.io.path.exists -import kotlin.io.path.moveTo -import kotlin.io.path.name -import kotlin.io.path.outputStream -import kotlin.io.path.readBytes -import kotlin.io.path.writeText -import okio.ByteString.Companion.toByteString - -abstract class AbstractModule { - - protected open fun postPublish(path: Path) = Unit - - protected fun publish(path: Path, action: (OutputStream) -> Unit) { - val hashBefore = if (path.exists()) getHash(path, "sha1") else null - val tempPath = path.resolveSibling("${path.name}.tmp") - tempPath.outputStream().use(action) - - val hashAfter = getHash(tempPath, "sha1") - if (hashAfter == hashBefore) { - // Already published - return - } - - tempPath.moveTo(path, true) - check(path.exists()) - writeSha1Path(path) - writeMd5Path(path) - - postPublish(path) - } - - companion object { - fun writeSha1Path(path: Path): Path { - return writeHashPath(path, "sha1", 40) - } - - fun writeMd5Path(path: Path): Path { - return writeHashPath(path, "md5", 32) - } - - private fun writeHashPath(path: Path, algorithm: String, len: Int): Path { - val hashPath = getHashPath(path, algorithm) - val hash = getHash(path, algorithm) - hashPath.writeText("$hash${len}x") - return hashPath - } - - private fun getHashPath(path: Path, algorithm: String): Path { - return path.resolveSibling("${path.name}.$algorithm") - } - - private fun getHash(path: Path, algorithm: String): BigInteger { - try { - val byteString = path.readBytes().toByteString() - val byteArray = when (algorithm.uppercase()) { - "MD5" -> byteString.md5() - "SHA1" -> byteString.sha1() - "SHA256" -> byteString.sha256() - "SHA512" -> byteString.sha512() - else -> throw IllegalArgumentException("Unsupported algorithm: $algorithm") - }.toByteArray() - return BigInteger(1, byteArray) - } catch (e: UncheckedIOException) { - // Catch any unchecked io exceptions and add the file path for troubleshooting - throw UncheckedIOException( - "Failed to create $algorithm hash for file ${path.absolutePathString()}.", - e.cause, - ) - } - } - } -} diff --git a/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/util/repo/maven/AbstractMavenModule.kt b/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/util/repo/maven/AbstractMavenModule.kt deleted file mode 100644 index 8d4ada5d6..000000000 --- a/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/util/repo/maven/AbstractMavenModule.kt +++ /dev/null @@ -1,184 +0,0 @@ -package com.github.jengelman.gradle.plugins.shadow.util.repo.maven - -import com.github.jengelman.gradle.plugins.shadow.util.repo.AbstractModule -import java.nio.file.Path -import java.text.SimpleDateFormat -import java.util.Date -import kotlin.io.path.createDirectories -import kotlin.io.path.exists -import kotlin.io.path.isRegularFile -import kotlin.io.path.name -import kotlin.io.path.reader -import org.apache.maven.artifact.repository.metadata.Metadata -import org.apache.maven.artifact.repository.metadata.Snapshot -import org.apache.maven.artifact.repository.metadata.Versioning -import org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Reader -import org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Writer -import org.apache.maven.model.Dependency -import org.apache.maven.model.Model -import org.apache.maven.model.io.xpp3.MavenXpp3Writer - -abstract class AbstractMavenModule( - val moduleDir: Path, - val groupId: String, - val artifactId: String, - val version: String, -) : AbstractModule(), - MavenModule { - - protected val updateFormat = SimpleDateFormat("yyyyMMddHHmmss") - protected val timestampFormat = SimpleDateFormat("yyyyMMdd.HHmmss") - protected val dependencies = mutableListOf() - protected val artifacts = mutableListOf>() - - protected var type: String = "jar" - protected var packaging: String? = null - protected var publishCount: Int = 1 - - protected abstract val isUniqueSnapshots: Boolean - protected abstract val isPublishesMetaDataFile: Boolean - - fun dependsOn(artifactId: String): MavenModule { - return dependsOn(groupId = groupId, artifactId = artifactId, version = version) - } - - override fun dependsOn(groupId: String, artifactId: String, version: String): MavenModule = apply { - val dep = Dependency().also { - it.groupId = groupId - it.artifactId = artifactId - it.version = version - } - dependencies.add(dep) - } - - override val pomPath: Path - get() = moduleDir.resolve("$artifactId-$publishArtifactVersion.pom") - - override val metaDataPath: Path - get() = moduleDir.resolve(MAVEN_METADATA_FILE) - - val rootMetaDataPath: Path - get() = moduleDir.resolveSibling(MAVEN_METADATA_FILE) - - fun artifactPath(options: Map): Path { - val artifact = toArtifact(options) - var fileName = "$artifactId-$publishArtifactVersion.${artifact["type"]}" - if (artifact["classifier"] != null) { - fileName = "$artifactId-$publishArtifactVersion-${artifact["classifier"]}.${artifact["type"]}" - } - return moduleDir.resolve(fileName) - } - - override fun publishPom(): MavenModule = apply { - moduleDir.createDirectories() - val rootMavenMetaData = rootMetaDataPath - updateRootMavenMetaData(rootMavenMetaData) - - if (isPublishesMetaDataFile) { - publish(metaDataPath) { outputStream -> - MetadataXpp3Writer().write(outputStream, getMetaData(emptyList())) - } - } - - publish(pomPath) { outputStream -> - val pomPackaging = packaging ?: type - val model = Model().also { - it.modelVersion = "4.0.0" - it.groupId = groupId - it.artifactId = artifactId - it.version = version - it.packaging = pomPackaging - it.description = "Published on $publishTimestamp" - it.dependencies = dependencies - } - MavenXpp3Writer().write(outputStream, model) - } - } - - open fun getMetaData(versions: List): Metadata = Metadata().also { - it.groupId = groupId - it.artifactId = artifactId - it.version = version - it.versioning = Versioning().also { versioning -> - versioning.versions = versions - versioning.lastUpdated = updateFormat.format(publishTimestamp) - if (isUniqueSnapshots && version.endsWith("-SNAPSHOT")) { - versioning.snapshot = Snapshot().apply { - timestamp = timestampFormat.format(publishTimestamp) - buildNumber = publishCount - } - } - } - } - - override fun publish(): MavenModule = apply { - publishPom() - artifacts.forEach { artifact -> - publishArtifact(artifact) - } - publishArtifact(emptyMap()) - } - - open fun publishArtifact(artifact: Map): Path { - val artifactPath = artifactPath(artifact) - if (type == "pom") { - return artifactPath - } - publish(artifactPath) { outputStream -> - outputStream.write("${artifactPath.name} : $artifactContent".toByteArray()) - } - return artifactPath - } - - protected fun toArtifact(options: Map): Map { - val artifact = mutableMapOf( - "type" to (options["type"] ?: type), - "classifier" to options["classifier"], - ) - require(options.keys.isEmpty()) { "Unknown options : ${options.keys}" } - return artifact - } - - protected val publishArtifactVersion: String - get() = if (isUniqueSnapshots && version.endsWith("-SNAPSHOT")) { - "${version.removeSuffix("-SNAPSHOT")}-$uniqueSnapshotVersion" - } else { - version - } - - protected val publishTimestamp: Date - get() = Date(updateFormat.parse("20100101120000").time + publishCount * 1000) - - private fun updateRootMavenMetaData(rootMavenMetaData: Path) { - val allVersions = if (rootMavenMetaData.exists()) { - MetadataXpp3Reader().read(rootMavenMetaData.reader()).versioning.versions - } else { - mutableListOf() - } - allVersions.add(version) - publish(rootMavenMetaData) { outputStream -> - MetadataXpp3Writer().write(outputStream, getMetaData(allVersions)) - } - } - - private val artifactContent: String - // Some content to include in each artifact, so that its size and content varies on each pu - get() = (0..publishCount).joinToString("-") - - private val uniqueSnapshotVersion: String - get() { - require(isUniqueSnapshots && version.endsWith("-SNAPSHOT")) - return if (metaDataPath.isRegularFile()) { - val metaData = MetadataXpp3Reader().read(metaDataPath.reader()) - val timestamp = metaData.versioning.snapshot.timestamp - val build = metaData.versioning.snapshot.buildNumber - "$timestamp-$build" - } else { - "${timestampFormat.format(publishTimestamp)}-$publishCount" - } - } - - protected companion object { - const val MAVEN_METADATA_FILE = "maven-metadata.xml" - } -} diff --git a/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/util/repo/maven/MavenFileModule.kt b/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/util/repo/maven/MavenFileModule.kt deleted file mode 100644 index 0807d4021..000000000 --- a/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/util/repo/maven/MavenFileModule.kt +++ /dev/null @@ -1,35 +0,0 @@ -package com.github.jengelman.gradle.plugins.shadow.util.repo.maven - -import java.nio.file.Path -import org.apache.maven.artifact.repository.metadata.Metadata -import org.apache.maven.artifact.repository.metadata.Snapshot -import org.apache.maven.artifact.repository.metadata.Versioning - -open class MavenFileModule( - moduleDir: Path, - groupId: String, - artifactId: String, - version: String, -) : AbstractMavenModule(moduleDir, groupId, artifactId, version) { - - override val isUniqueSnapshots: Boolean = true - - override fun getMetaData(versions: List): Metadata { - return Metadata().also { - it.groupId = groupId - it.artifactId = artifactId - it.version = version - it.versioning = Versioning().also { versioning -> - versioning.versions = versions - versioning.snapshot = Snapshot().apply { - timestamp = timestampFormat.format(publishTimestamp) - buildNumber = publishCount - } - versioning.lastUpdated = updateFormat.format(publishTimestamp) - } - } - } - - override val isPublishesMetaDataFile: Boolean - get() = isUniqueSnapshots && version.endsWith("-SNAPSHOT") -} diff --git a/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/util/repo/maven/MavenFileRepository.kt b/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/util/repo/maven/MavenFileRepository.kt deleted file mode 100644 index e1ba0c089..000000000 --- a/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/util/repo/maven/MavenFileRepository.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.github.jengelman.gradle.plugins.shadow.util.repo.maven - -import java.net.URI -import java.nio.file.Path - -/** - * A fixture for dealing with file Maven repositories. - */ -open class MavenFileRepository(val rootDir: Path) : MavenRepository { - - override val uri: URI = rootDir.toUri() - - override fun module(groupId: String, artifactId: String, version: String): MavenFileModule { - val artifactDir = rootDir.resolve("${groupId.replace('.', '/')}/$artifactId/$version") - return MavenFileModule(artifactDir, groupId, artifactId, version) - } -} diff --git a/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/util/repo/maven/MavenModule.kt b/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/util/repo/maven/MavenModule.kt deleted file mode 100644 index e484f2a96..000000000 --- a/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/util/repo/maven/MavenModule.kt +++ /dev/null @@ -1,22 +0,0 @@ -package com.github.jengelman.gradle.plugins.shadow.util.repo.maven - -import java.nio.file.Path - -interface MavenModule { - /** - * Publishes the `pom.xml` plus main artifact, plus any additional artifacts for this module. - * Publishes only those artifacts whose content has changed since the last call to `publish()`. - */ - fun publish(): MavenModule - - /** - * Publishes the `pom.xml` only - */ - fun publishPom(): MavenModule - - fun dependsOn(groupId: String, artifactId: String, version: String): MavenModule - - val pomPath: Path - - val metaDataPath: Path -} diff --git a/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/util/repo/maven/MavenRepository.kt b/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/util/repo/maven/MavenRepository.kt deleted file mode 100644 index 95ca83c86..000000000 --- a/src/intiTest/kotlin/com/github/jengelman/gradle/plugins/shadow/util/repo/maven/MavenRepository.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.github.jengelman.gradle.plugins.shadow.util.repo.maven - -import java.net.URI - -/** - * A fixture for dealing with Maven repositories. - */ -interface MavenRepository { - val uri: URI - - fun module(groupId: String, artifactId: String, version: String): MavenModule -}