Skip to content

Commit

Permalink
Various improvements to how tasks are setup, also actually swap the M…
Browse files Browse the repository at this point in the history
…ANIFEST.MF file for the tasks `dist` and `localDistJar`
  • Loading branch information
floscher committed Feb 6, 2022
1 parent 881551a commit 8e2c796
Show file tree
Hide file tree
Showing 8 changed files with 126 additions and 82 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ class JosmPlugin: Plugin<Project> {
project.extensions.create("josm", JosmPluginExtension::class.java, project)

val jarTask = project.tasks.withType(Jar::class.java).getByName("jar")
jarTask.outputs.upToDateWhen { false }
jarTask.doFirst<Jar> { task ->
task.from(
project.configurations.getByName("packIntoJar").files.map { file ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ import java.net.URI
* @constructor instantiates the extension, takes project properties into account
*/
open class JosmPluginExtension(val project: Project) {
var pluginName: String

public var pluginName: String
get() = project.extensions.getByType(BasePluginExtension::class.java).archivesName.get()
set(value) = project.extensions.getByType(BasePluginExtension::class.java).archivesName.set(value)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package org.openstreetmap.josm.gradle.plugin.task

import org.gradle.api.artifacts.Configuration
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.SourceSet
import org.gradle.api.tasks.TaskAction
import org.gradle.api.tasks.compile.JavaCompile
import org.gradle.execution.commandline.TaskConfigurationException
import org.gradle.work.InputChanges
import org.openstreetmap.josm.gradle.plugin.util.createJosm
import org.openstreetmap.josm.gradle.plugin.util.createJosmDependencyFuzzy
Expand All @@ -13,15 +16,16 @@ import javax.inject.Inject
/**
* This task compiles the given source set against a specific JOSM version.
*/
open class CustomJosmVersionCompile
public open class CustomJosmVersionCompile
@Inject
constructor(private val customVersionProvider: () -> String, private val findNextVersion: Boolean, private val sourceSet: SourceSet, private val additionalClasspath: Set<Configuration>): JavaCompile() {
constructor(private val customVersionProvider: () -> String?, private val findNextVersion: Boolean, private val sourceSet: SourceSet, private val additionalClasspath: Set<Configuration>): JavaCompile() {

private lateinit var customVersion: String
private val customVersion: String? by lazy { customVersionProvider() }

@OptIn(ExperimentalUnsignedTypes::class)
@TaskAction
final override fun compile(inputs: InputChanges) {
val customVersion = this.customVersion ?: throw TaskConfigurationException(path, "Custom version not defined!", IllegalStateException())
classpath += project.configurations.getByName(sourceSet.compileClasspathConfigurationName).copy().excludeJosm()
additionalClasspath.forEach {
classpath += it.copy()
Expand All @@ -38,17 +42,28 @@ open class CustomJosmVersionCompile
super.compile(inputs)
}

init {
group = "JOSM"

project.afterEvaluate {
source(sourceSet.java)
customVersion = customVersionProvider.invoke()
private val destinationDirectory = project.objects.directoryProperty().also {
if (customVersion != null) {
it.convention(
project.layout.buildDirectory.dir("classes/java/${sourceSet.name}_$customVersion")
)
}
}
final override fun getDestinationDirectory(): DirectoryProperty = destinationDirectory

description = "Compile the JOSM plugin against ${ if (findNextVersion) "the first available JOSM version since" else "JOSM version" } $customVersion"
destinationDirectory.set(project.buildDir.resolve("classes/java/${sourceSet.name}_$customVersion"))
@Internal
override fun getDescription(): String = if (customVersion == null) {
"This task will fail, because the custom version is unknown!"
} else {
"Compile the JOSM plugin against ${
if (findNextVersion) "the first available JOSM version since" else "JOSM version"
} $customVersion"
}
final override fun setDescription(description: String?): Nothing = throw UnsupportedOperationException("Can't change task description!")

classpath = project.files() // empty, will be filled later
}
init {
group = "JOSM"
source(project.provider { sourceSet.java })
classpath = project.files() // empty, will be filled later
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ import org.gradle.api.tasks.InputFiles
import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
import org.gradle.api.tasks.TaskContainer
import org.gradle.api.tasks.TaskExecutionException
import org.gradle.api.tasks.TaskProvider
import org.openstreetmap.josm.gradle.plugin.config.JosmManifest
import org.openstreetmap.josm.gradle.plugin.io.PluginInfo
import org.openstreetmap.josm.gradle.plugin.util.toBase64DataUrl
Expand All @@ -30,6 +32,15 @@ public open class GeneratePluginList @Inject constructor(
private val iconPathToFile: (String) -> File?
): DefaultTask() {

public companion object {
/** Typesafe constructor for [GeneratePluginList] task */
public fun <G:GeneratePluginList> TaskContainer.register(
name: String,
iconPathToFile: (String) -> File?,
config: (GeneratePluginList).() -> Unit
): TaskProvider<GeneratePluginList> = register(name, GeneratePluginList::class.java, iconPathToFile).also { it.configure(config) }
}

/**
* All plugins that should appear in the list (as [PluginInfo]s).
*/
Expand Down Expand Up @@ -80,28 +91,30 @@ public open class GeneratePluginList @Inject constructor(
val plugins: Set<PluginInfo> = plugins.also{ it.finalizeValue() }.get()
val outputFile: File = outputFile.also { it.finalizeValue() }.asFile.get()

logger.lifecycle("Writing list of ${plugins.size} plugin${if (plugins.size > 1) "s" else ""} to ${outputFile.absolutePath}")
logger.lifecycle("Writing list of ${plugins.size.takeIf { it != 1 }?.let { "$it plugins" } ?: "one plugin"} to ${outputFile.absolutePath}")

if (!outputFile.parentFile.exists() && !outputFile.parentFile.mkdirs()) {
throw TaskExecutionException(this, IOException("Can't create directory ${outputFile.parentFile.absolutePath}!"))
}

outputFile.writeText(
plugins.sortedBy { it.pluginName }.flatMap {
listOf("${it.pluginName}.jar;${it.downloadUri}") +
it.manifestAtts.map { (key, value) ->
"\t$key: " +
when (key) {
JosmManifest.Attribute.PLUGIN_ICON.manifestKey ->
plugins.sortedBy { it.pluginName }.flatMap { pluginInfo ->
listOf("${pluginInfo.pluginName}.jar;${pluginInfo.downloadUri}") +
pluginInfo.manifestAtts.map { (key, value) ->
"\t$key: " + (
if (key == JosmManifest.Attribute.PLUGIN_ICON.manifestKey) {
try {
iconFileMap.get()[it]?.toBase64DataUrl()
iconFileMap.get()[pluginInfo]?.toBase64DataUrl()
} catch (e: IOException) {
logger.lifecycle("Error reading")
} ?: value
JosmManifest.Attribute.PLUGIN_VERSION.manifestKey ->
logger.lifecycle("Error reading icon file $value . Falling back to the relative path instead of data-URL.")
null
}
} else if (key == JosmManifest.Attribute.PLUGIN_VERSION.manifestKey) {
value + versionSuffix.get()
else -> value
}
} else {
null
} ?: value
)
}
}.joinToString("\n", "", "\n")
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import org.gradle.api.tasks.InputFiles
import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.OutputDirectory
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.Sync
import org.gradle.api.tasks.TaskAction
import org.gradle.api.tasks.TaskProvider
import org.openstreetmap.josm.gradle.plugin.config.JosmPluginExtension
Expand Down
Original file line number Diff line number Diff line change
@@ -1,51 +1,76 @@
package org.openstreetmap.josm.gradle.plugin.task

import org.gradle.api.DefaultTask
import org.gradle.api.file.Directory
import org.gradle.api.file.DuplicatesStrategy
import org.gradle.api.file.RegularFile
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.InputFiles
import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
import org.gradle.api.tasks.TaskContainer
import org.gradle.api.tasks.TaskProvider
import org.gradle.api.tasks.bundling.AbstractArchiveTask
import org.gradle.api.tasks.bundling.Zip
import javax.inject.Inject

/**
* Task that simply copies the archive file produced by the given [archiverTask]
*/
public open class RenameArchiveFile @Inject constructor(
@get:InputFiles
public val archiverTask: TaskProvider<AbstractArchiveTask>,
public val archiverTask: TaskProvider<out AbstractArchiveTask>,
@get:InputFiles
public val manifestTask: Provider<GenerateJarManifest>,
@get:Internal
public val targetDir: Provider<out Directory>,
public val targetDir: Provider<Directory>,
@get:Input
public val fileBaseName: Provider<out String>
): DefaultTask() {
public val fileBaseName: Provider<String>
): Zip() {
// TODO: Add option to append file hash to manifest version number (useful for local update site, so JOSM detects changed plugin)

public companion object {
/** Typesafe constructor for [RenameArchiveFile] task */
public fun <R: RenameArchiveFile> TaskContainer.register(
name: String,
archiverTask: TaskProvider<out AbstractArchiveTask>,
manifestTask: Provider<GenerateJarManifest>,
targetDir: Provider<Directory>,
fileBaseName: Provider<String>
): TaskProvider<RenameArchiveFile> =
register(name, RenameArchiveFile::class.java, archiverTask, manifestTask, targetDir, fileBaseName)
}

init {
archiveFileName.let {
it.set(fileBaseName.map { fileBaseName -> "$fileBaseName.${archiverTask.get().archiveExtension.get()}" })
it.finalizeValue()
}
}

private val fileName: String by lazy(LazyThreadSafetyMode.PUBLICATION) {
"${fileBaseName.get()}.${archiverTask.get().archiveExtension.get()}"
init {
from(
archiverTask.map { project.zipTree(it.archiveFile).matching { it.exclude(GenerateJarManifest.MANIFEST_PATH) } },
manifestTask.map { project.fileTree(it.outputDirectory) { it.include(GenerateJarManifest.MANIFEST_PATH) } }
)
destinationDirectory.set(targetDir)
duplicatesStrategy = DuplicatesStrategy.FAIL
isPreserveFileTimestamps = false
isReproducibleFileOrder = true
includeEmptyDirs = false
}
@get:OutputFile
public val targetFile: Provider<RegularFile> = targetDir.map { it.file(fileName) }

@TaskAction
public fun copy() {
project.sync {
it.from(archiverTask.map { it.archiveFile })
it.into(targetDir)
it.rename { fileName }
it.duplicatesStrategy = DuplicatesStrategy.FAIL
}
public override fun copy() {
super.copy()
logger.lifecycle(
"""
Copied file
from ${archiverTask.get().archiveFile.get()}
into ${targetDir.get().asFile.canonicalPath}/$fileName
from ${archiverTask.get().archiveFile.get().asFile.canonicalPath}
into ${archiveFile.get().asFile.canonicalPath}
The file `${GenerateJarManifest.MANIFEST_PATH}` within the archive was swapped for ${
manifestTask.get().outputFile.get().asFile.canonicalPath
}
""".trimIndent()
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import org.gradle.api.tasks.TaskProvider
import org.gradle.jvm.tasks.Jar
import org.openstreetmap.josm.gradle.plugin.MainConfigurationSetup
import org.openstreetmap.josm.gradle.plugin.io.PluginInfo
import org.openstreetmap.josm.gradle.plugin.task.GeneratePluginList.Companion.register
import org.openstreetmap.josm.gradle.plugin.task.RenameArchiveFile.Companion.register
import org.openstreetmap.josm.gradle.plugin.task.github.CreateGithubReleaseTask
import org.openstreetmap.josm.gradle.plugin.task.github.PublishToGithubReleaseTask
import org.openstreetmap.josm.gradle.plugin.task.gitlab.ReleaseToGitlab
Expand Down Expand Up @@ -41,10 +43,10 @@ public fun Project.setupJosmTasks(mainConfigSetup: MainConfigurationSetup) {
)
}
project.afterEvaluate {
tasks.create(
tasks.register(
"${mainConfigSetup.mainSourceSet.compileJavaTaskName}_minJosm",
CustomJosmVersionCompile::class.java,
{ project.extensions.josm.manifest.minJosmVersion as String },
{ project.extensions.josm.manifest.minJosmVersion },
true,
mainConfigSetup.mainSourceSet,
setOf(mainConfigSetup.requiredPluginConfiguration, mainConfigSetup.packIntoJarConfiguration)
Expand All @@ -68,40 +70,36 @@ private fun setupPluginDistTasks(project: Project, sourceSetJosmPlugin: SourceSe
val distDir = project.layout.buildDirectory.map { it.dir("dist") }
val localDistDir = project.layout.buildDirectory.map { it.dir("localDist") }

val localDistJarTask = project.tasks.register(
val localDistJarTask = project.tasks.register<RenameArchiveFile>(
"localDistJar",
RenameArchiveFile::class.java,
archiverTask,
project.provider { project.tasks.named("generateManifest", GenerateJarManifest::class.java).get() }, // TODO: Don't reference by name
localDistDir,
project.provider { project.extensions.josm.pluginName + "-dev" }
)
val localDistTask = project.tasks.register(
val localDistTask = project.tasks.register<GeneratePluginList>(
"localDist",
GeneratePluginList::class.java,
{ relPath: String -> sourceSetJosmPlugin.resources.srcDirs.map { it.resolve(relPath) }.firstOrNull { it.exists() } }
).apply {
configure { t ->
t.description = "Creates a local plugin update site containing just the current development state of the ${project.extensions.josm.pluginName} plugin"
t.outputFile.set(localDistDir.map { it.file("list") })
//t.versionSuffix.set("#${DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(ZonedDateTime.now())}")
t.plugins.add(localDistJarTask.map { localDistJarTask ->
PluginInfo(
localDistJarTask.fileBaseName.get(),
localDistJarTask.targetFile.get().asFile.toURI(),
(localDistJarTask.archiverTask.get() as? Jar)
?.manifest
?.attributes
?.mapValues { it.value.toString() }
?: mapOf()
)
})
}
) {
description = "Creates a local plugin update site containing just the current development state of the ${project.extensions.josm.pluginName} plugin"
outputFile.set(localDistDir.map { it.file("list") })
plugins.add(localDistJarTask.map { localDistJarTask ->
PluginInfo(
localDistJarTask.fileBaseName.get(),
localDistJarTask.archiveFile.get().asFile.toURI(),
project.provider { project.tasks.named("generateManifest", GenerateJarManifest::class.java).get() } // TODO: Don't reference by name
?.flatMap { it.predefinedAttributes }
?.get()
?: mapOf()
)
})
versionSuffix.set("#${DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(ZonedDateTime.now())}")
}

val distTask = project.tasks.register(
val distTask = project.tasks.register<RenameArchiveFile>(
"dist",
RenameArchiveFile::class.java,
archiverTask,
project.provider { project.tasks.named("generateManifest", GenerateJarManifest::class.java).get() }, // TODO: Don't reference by name
distDir,
project.provider { project.extensions.josm.pluginName }
)
Expand All @@ -111,7 +109,7 @@ private fun setupPluginDistTasks(project: Project, sourceSetJosmPlugin: SourceSe

private fun setupI18nTasks(project: Project, sourceSetJosmPlugin: SourceSet) {

// Generates a *.pot file out of all *.java source files
// Generates a *.pot file out of all *.java and *.kt source files
project.tasks.create(
"generatePot",
GeneratePot::class.java,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,7 @@ class ProjectExtensionsTest {
@Test
fun testRequiredPlugins(testInfo: TestInfo) {
val result = createRequiredPluginsTestRepo(testInfo).getAllRequiredJosmPlugins(setOf("A"))
assertEquals(6, result.size)
assertEquals(1, result.count{ it.name == "A" })
assertEquals(1, result.count{ it.name == "B" })
assertEquals(1, result.count{ it.name == "C" })
assertEquals(1, result.count{ it.name == "D" })
assertEquals(1, result.count{ it.name == "E" })
assertEquals(1, result.count{ it.name == "F" })
assertEquals(listOf("A", "B", "C", "D", "E", "F"), result.map { it.name }.sorted().toList())
}

private fun createNextJosmTestRepo(testInfo: TestInfo): Project =
Expand Down

0 comments on commit 8e2c796

Please sign in to comment.