-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Rewrite the GeneratePluginList task, now uses properties/providers
- Loading branch information
Showing
8 changed files
with
186 additions
and
163 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
15 changes: 8 additions & 7 deletions
15
plugin/src/main/kotlin/org/openstreetmap/josm/gradle/plugin/io/PluginInfo.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
148 changes: 89 additions & 59 deletions
148
plugin/src/main/kotlin/org/openstreetmap/josm/gradle/plugin/task/GeneratePluginList.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,100 +1,130 @@ | ||
package org.openstreetmap.josm.gradle.plugin.task | ||
|
||
import org.gradle.api.DefaultTask | ||
import org.gradle.api.file.RegularFileProperty | ||
import org.gradle.api.provider.Property | ||
import org.gradle.api.provider.Provider | ||
import org.gradle.api.provider.SetProperty | ||
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.TaskExecutionException | ||
import org.openstreetmap.josm.gradle.plugin.config.JosmManifest | ||
import org.openstreetmap.josm.gradle.plugin.io.PluginInfo | ||
import org.openstreetmap.josm.gradle.plugin.util.toBase64DataUrl | ||
import java.io.File | ||
import java.io.IOException | ||
import java.io.Serializable | ||
import java.net.URL | ||
import java.util.GregorianCalendar | ||
import javax.inject.Inject | ||
|
||
open class GeneratePluginList : DefaultTask() { | ||
/** | ||
* A task that can write a plugin update site. JOSM can be pointed to a URL of such an update site, | ||
* so the plugins in that list can be installed via the regular JOSM update mechanism in the JOSM settings. | ||
* | ||
* @property iconPathToFile a function that returns a [File] object for a (relative) icon path. | ||
* This is used to convert a manifest entry for [JosmManifest.Attribute.PLUGIN_ICON] from a relative path | ||
* to a Base64-Data-URL. If you don't need this functionality, just pass `{ it -> null }`, which will always return `null`. | ||
*/ | ||
public open class GeneratePluginList @Inject constructor( | ||
private val iconPathToFile: (String) -> File? | ||
): DefaultTask() { | ||
|
||
/** | ||
* Maps the plugin name to the manifest attributes and the download URL of the plugin | ||
* All plugins that should appear in the list (as [PluginInfo]s). | ||
*/ | ||
private val plugins: MutableList<PluginInfo> = mutableListOf() | ||
|
||
@Input | ||
val immutablePlugins = plugins.toList() | ||
@get:Input | ||
public val plugins: SetProperty<PluginInfo> = project.objects.setProperty(PluginInfo::class.java) | ||
|
||
/** | ||
* The file to which this task writes the plugin list, will be overwritten if it exists. | ||
* This parameter is required. | ||
*/ | ||
@OutputFile | ||
lateinit var outputFile: File | ||
@get:OutputFile | ||
public val outputFile: RegularFileProperty = project.objects.fileProperty() | ||
|
||
/** | ||
* Optional parameter, converts a relative icon path (you decide relative to what, | ||
* this class does not make assumptions about that) to a Base64 representation. | ||
* This parameter is optional, by default or if it returns `null`, the icon path is added as-is to the list. | ||
* Maps plugins to icon files, helper to connect [plugins] and [iconFiles]. | ||
*/ | ||
@Internal | ||
var iconBase64Provider: (String) -> String? = { _ -> null } | ||
private val iconFileMap: Provider<Map<PluginInfo, File>> = plugins.map { plugins -> | ||
plugins.mapNotNull { pi -> | ||
pi.manifestAtts.entries | ||
.firstOrNull { (key, _) -> key == JosmManifest.Attribute.PLUGIN_ICON.manifestKey } | ||
?.value | ||
?.let { iconPathToFile(it) } | ||
?.let { pi to it } | ||
}.toMap() | ||
} | ||
|
||
/** | ||
* This field is only here, so Gradle can serialize [iconBase64Provider] for up-to-date-checking/caching | ||
* A list of icon files derived from [plugins] and [iconPathToFile]. | ||
* This is marked as input files, so that changes in the icon files are detected and trigger a regeneration. | ||
*/ | ||
@Input | ||
val serializableIconProvider = iconBase64Provider as Serializable | ||
@get:InputFiles | ||
public val iconFiles: Provider<Set<File>> = iconFileMap.map { prop -> prop.values.map { it.canonicalFile }.toSet() } | ||
|
||
/** | ||
* A function that gives you a suffix that's appended to the plugin version. It takes the plugin name as an argument. | ||
* A version suffix that's appended to the plugin version(s). | ||
*/ | ||
@Internal | ||
var versionSuffix: (String) -> String? = { _ -> '#' + String.format("%1\$tY-%1\$tm-%1\$tdT%1\$tH:%1\$tM:%1\$tS%1\$tz", GregorianCalendar()) } | ||
@get:Input | ||
public val versionSuffix: Property<String> = project.objects.property(String::class.java).convention("") | ||
|
||
/** | ||
* This field is only here, so Gradle can serialize [versionSuffix] for up-to-date-checking/caching | ||
*/ | ||
@Input | ||
val serializableVersionSuffix = versionSuffix as Serializable | ||
@Internal | ||
final override fun getGroup(): String = "JOSM" | ||
final override fun setGroup(group: String?): Nothing = throw UnsupportedOperationException( | ||
"Can't change group of ${javaClass.name}!" | ||
) | ||
|
||
@TaskAction | ||
fun action() { | ||
logger.lifecycle("Writing list of ${plugins.size} plugins to ${outputFile.absolutePath} …") | ||
val fileBuilder = StringBuilder() | ||
public open fun action() { | ||
val plugins: Set<PluginInfo> = plugins.also{ it.finalizeValue() }.get() | ||
val outputFile: File = outputFile.also { it.finalizeValue() }.asFile.get() | ||
|
||
plugins.sortedBy { it.pluginName }.forEach { (name, url, manifestAtts) -> | ||
fileBuilder | ||
.append(name) | ||
.append(';') | ||
.append(url) | ||
.append('\n') | ||
manifestAtts.forEach { key, value -> | ||
fileBuilder | ||
.append('\t') | ||
.append(key) | ||
.append(": ") | ||
.append(when (key) { | ||
JosmManifest.Attribute.PLUGIN_ICON.manifestKey -> iconBase64Provider.invoke(value) ?: value | ||
JosmManifest.Attribute.PLUGIN_VERSION.manifestKey -> value + versionSuffix.invoke(name) | ||
else -> value | ||
}) | ||
.append('\n') | ||
} | ||
} | ||
logger.lifecycle("Writing list of ${plugins.size} plugin${if (plugins.size > 1) "s" else ""} to ${outputFile.absolutePath} …") | ||
|
||
if (!outputFile.parentFile.exists() && !outputFile.parentFile.mkdirs()) { | ||
throw TaskExecutionException(this, IOException("Can't create directory ${outputFile.parentFile.absolutePath}!")) | ||
} | ||
outputFile.writeText(fileBuilder.toString(), Charsets.UTF_8) | ||
} | ||
|
||
/** | ||
* Add a plugin that should appear in the list | ||
* @param name the name of the plugin *.jar file (including file extension), e.g. `MyAwesomePlugin.jar` | ||
* @param atts the main attributes of the plugin manifest, e.g. supplied by [JosmManifest.createJosmPluginJarManifest] | ||
* @param downloadUrl the URL from which the plugin can be downloaded | ||
*/ | ||
fun addPlugin(name: String, atts: Map<String, String>, downloadUrl: URL) { | ||
plugins.add(PluginInfo(name, downloadUrl, atts)) | ||
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 -> | ||
try { | ||
iconFileMap.get()[it]?.toBase64DataUrl() | ||
} catch (e: IOException) { | ||
logger.lifecycle("Error reading") | ||
} ?: value | ||
JosmManifest.Attribute.PLUGIN_VERSION.manifestKey -> | ||
value + versionSuffix.get() | ||
else -> value | ||
} | ||
} | ||
}.joinToString("\n", "", "\n") | ||
) | ||
|
||
logger.lifecycle(""" | ||
| | ||
|The list contains: | ||
|${ | ||
plugins.joinToString("\n", " * ") { pluginInfo -> | ||
pluginInfo.pluginName + | ||
( | ||
pluginInfo.manifestAtts.entries | ||
.firstOrNull { (key, _) -> key == JosmManifest.Attribute.PLUGIN_VERSION.manifestKey } | ||
?.value | ||
?.let { " ($it)" } | ||
?: "" | ||
) | ||
} | ||
} | ||
| | ||
|${"By adding the following URL as a JOSM plugin update site (see tab 'Plugins' in expert mode), " + | ||
"you can load the current development state into a JOSM instance via the regular plugin update mechanism:"} | ||
| ${outputFile.toURI()} | ||
""".trimMargin()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.