Skip to content

Commit

Permalink
resolveDownloadSrc
Browse files Browse the repository at this point in the history
  • Loading branch information
liplum committed Dec 19, 2023
1 parent d1908ae commit 8bcd898
Show file tree
Hide file tree
Showing 3 changed files with 130 additions and 128 deletions.
3 changes: 2 additions & 1 deletion main/src/run/model/Games.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ sealed interface IGameLoc : Serializable {

sealed interface IDownloadableGameLoc : IGameLoc {
/**
* Generate a [URL] deterministically.
* Generate a deterministic URL.
* It can be an expensive task if it requests any data.
*/
fun resolveDownloadSrc(): URL
}
Expand Down
126 changes: 125 additions & 1 deletion main/src/run/model/Mods.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package io.github.liplum.mindustry

import arc.util.serialization.Jval
import io.github.liplum.dsl.*
import org.gradle.api.GradleException
import org.gradle.api.logging.Logger
import java.io.File
import java.io.Serializable
import java.net.URL
Expand All @@ -14,7 +17,15 @@ sealed interface IMod : Serializable {
fun resolveCacheFile(): File
}

sealed interface IGitHubMod : IMod {
sealed interface IDownloadableMod : IMod {
/**
* Generate a deterministic URL.
* It can be an expensive task if it requests any data.
*/
fun resolveDownloadSrc(): URL
}

sealed interface IGitHubMod : IDownloadableMod {
override fun resolveCacheFile(): File {
return SharedCache.modsDir.resolve("github").resolve(fileName4Local)
}
Expand Down Expand Up @@ -74,6 +85,19 @@ data class GitHubUntypedMod(
*/
val repo: String,
) : IGitHubMod {
override fun resolveDownloadSrc(): URL {
updateGitHubModUpdateToDate(modFile = resolveCacheFile())
val jsonText = URL("https://api.github.com/repos/$repo").readText()
val json = Jval.read(jsonText)
val lan = json.getString("language")
return if (isJvmMod(lan)) {
resolveJvmModSrc(repo)
} else {
val mainBranch = json.getString("default_branch")
resolvePlainModSrc(repo, mainBranch)
}
}

override val fileName4Local = repo.repo2Path() + ".zip"
}

Expand All @@ -82,6 +106,15 @@ data class GitHubPlainMod(
val repo: String, val branch: String? = null,
) : IGitHubMod {
val fileNameWithoutExtension = linkString(separator = "-", repo.repo2Path(), branch)
override fun resolveDownloadSrc(): URL {
updateGitHubModUpdateToDate(modFile = resolveCacheFile())
val jsonText = URL("https://api.github.com/repos/$repo").readText()
val json = Jval.read(jsonText)
val branch = if (!branch.isNullOrBlank()) branch
else json.getString("default_branch")
return resolvePlainModSrc(repo, branch)
}

override val fileName4Local = "$fileNameWithoutExtension.zip"
}

Expand All @@ -91,5 +124,96 @@ data class GitHubJvmMod(
val tag: String? = null,
) : IGitHubMod {
val fileNameWithoutExtension = linkString(separator = "-", repo.repo2Path(), tag)
override fun resolveDownloadSrc(): URL {
updateGitHubModUpdateToDate(modFile = resolveCacheFile())
return if (tag == null) {
resolveJvmModSrc(repo)
} else {
val releaseJson = URL("https://api.github.com/repos/$repo/releases").readText()
val json = Jval.read(releaseJson)
val releases = json.asArray()
val release = releases.find { it.getString("tag_name") == tag }
?: throw GradleException("Tag<$tag> of $repo not found.")
val url = URL(release.getString("url"))
resolveJvmModSrc(url)
}
}

override val fileName4Local = "$fileNameWithoutExtension.jar"
}

private
fun isJvmMod(lang: String) = lang == "Java" || lang == "Kotlin" ||
lang == "Groovy" || lang == "Scala" ||
lang == "Clojure"

private
fun resolveJvmModSrc(releaseEntryUrl: URL): URL {
val releaseJson = releaseEntryUrl.readText()
val json = Jval.read(releaseJson)
val assets = json["assets"].asArray()
val dexedAsset = assets.find {
it.getString("name").startsWith("dexed") &&
it.getString("name").endsWith(".jar")
}
val asset = dexedAsset ?: assets.find { it.getString("name").endsWith(".jar") }
?: throw GradleException("Failed to find the mod.")
val url = asset.getString("browser_download_url")
return URL(url)
}

private
fun resolveJvmModSrc(repo: String, tag: String = "latest"): URL {
return resolveJvmModSrc(releaseEntryUrl = URL("https://api.github.com/repos/$repo/releases/$tag"))
}


internal
fun resolvePlainModSrc(repo: String, branch: String): URL {
val url = "https://api.github.com/repos/$repo/zipball/$branch"
return URL(url)
}


internal fun updateGitHubModUpdateToDate(
modFile: File,
newTimestamp: Long = System.currentTimeMillis(),
logger: Logger? = null,
) {
val infoFi = File("$modFile.$infoX")
if (infoFi.isDirectory) {
infoFi.deleteRecursively()
}
val meta = GihHubModDownloadMeta(lastUpdateTimestamp = newTimestamp)
val json = gson.toJson(meta)
try {
infoFi.writeText(json)
} catch (e: Exception) {
logger?.warn("Failed to write into \"info.json\"", e)
}
}

internal
fun tryReadGitHubModInfo(infoFi: File, logger: Logger? = null): GihHubModDownloadMeta {
fun writeAndGetDefault(): GihHubModDownloadMeta {
val meta = GihHubModDownloadMeta(lastUpdateTimestamp = System.currentTimeMillis())
val infoContent = gson.toJson(meta)
try {
infoFi.ensureParentDir().writeText(infoContent)
logger?.info("[MGPP] $infoFi is created.")
} catch (e: Exception) {
logger?.warn("Failed to write into \"info.json\"", e)
}
return meta
}
return if (infoFi.isFile) {
try {
val infoContent = infoFi.readText()
gson.fromJson(infoContent)
} catch (e: Exception) {
writeAndGetDefault()
}
} else {
writeAndGetDefault()
}
}
129 changes: 3 additions & 126 deletions main/src/task/ResolveMods.kt
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
package io.github.liplum.mindustry

import arc.util.serialization.Jval
import io.github.liplum.dsl.*
import io.github.liplum.dsl.copyTo
import io.github.liplum.dsl.listProp
import org.gradle.api.DefaultTask
import org.gradle.api.GradleException
import org.gradle.api.logging.Logger
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.OutputFiles
import org.gradle.api.tasks.TaskAction
import java.io.File
import java.net.URL
import kotlin.math.absoluteValue

internal
Expand Down Expand Up @@ -63,57 +60,16 @@ open class ResolveMods : DefaultTask() {
if (!this.isUpdateToDate()) {
val temp = File.createTempFile(this.fileName4Local, null)
try {
this.downloadTo(temp)
this.resolveDownloadSrc().openStream().use {
it.copyTo(temp)
}
} catch (e: Exception) {
logger.warn("Failed to update $this", e)
}
temp.copyTo(cacheFile)
}
}

fun IGitHubMod.downloadTo(cacheFile: File) {
when (this) {
is GitHubUntypedMod -> {
updateGitHubModUpdateToDate(modFile = cacheFile, logger = logger)
val jsonText = URL("https://api.github.com/repos/$repo").readText()
val json = Jval.read(jsonText)
val lan = json.getString("language")
if (lan.isJvmMod()) {
importJvmMod(repo, writeIn = cacheFile)
} else {
val mainBranch = json.getString("default_branch")
importPlainMod(repo, mainBranch, cacheFile)
}
}

is GitHubJvmMod -> {
updateGitHubModUpdateToDate(modFile = cacheFile, logger = logger)
if (tag == null) {
importJvmMod(repo, writeIn = cacheFile)
} else {
val releaseJson = URL("https://api.github.com/repos/$repo/releases").readText()
val json = Jval.read(releaseJson)
val releases = json.asArray()
val release = releases.find { it.getString("tag_name") == tag }
?: throw GradleException("Tag<$tag> of $repo not found.")
val url = URL(release.getString("url"))
importJvmMod(url, cacheFile)
}
}

is GitHubPlainMod -> {
updateGitHubModUpdateToDate(modFile = cacheFile, logger = logger)
val jsonText = URL("https://api.github.com/repos/$repo").readText()
val json = Jval.read(jsonText)
val branch = if (!branch.isNullOrBlank()) branch
else json.getString("default_branch")
importPlainMod(repo, branch, cacheFile)
}

else -> {}
}
}

fun IGitHubMod.isUpdateToDate(): Boolean {
val cacheFile = this.resolveCacheFile()
val infoFi = File("$cacheFile.$infoX")
Expand All @@ -131,82 +87,3 @@ open class ResolveMods : DefaultTask() {
url.copyTo(cacheFile)
}
}

private
fun String.isJvmMod() = this == "Java" || this == "Kotlin" ||
this == "Groovy" || this == "Scala" ||
this == "Clojure"

private
fun importJvmMod(releaseEntryUrl: URL, writeIn: File) {
val releaseJson = releaseEntryUrl.readText()
val json = Jval.read(releaseJson)
val assets = json["assets"].asArray()
val dexedAsset = assets.find {
it.getString("name").startsWith("dexed") &&
it.getString("name").endsWith(".jar")
}
val asset = dexedAsset ?: assets.find { it.getString("name").endsWith(".jar") }
if (asset != null) {
val url = asset.getString("browser_download_url")
URL(url).copyTo(writeIn)
} else {
throw GradleException("Failed to find the mod.")
}
}

private
fun importJvmMod(repo: String, tag: String = "latest", writeIn: File) {
importJvmMod(releaseEntryUrl = URL("https://api.github.com/repos/$repo/releases/$tag"), writeIn)
}


internal
fun importPlainMod(repo: String, branch: String, dest: File) {
val url = "https://api.github.com/repos/$repo/zipball/$branch"
URL(url).copyTo(dest)
}


internal fun updateGitHubModUpdateToDate(
modFile: File,
newTimestamp: Long = System.currentTimeMillis(),
logger: Logger? = null,
) {
val infoFi = File("$modFile.$infoX")
if (infoFi.isDirectory) {
infoFi.deleteRecursively()
}
val meta = GihHubModDownloadMeta(lastUpdateTimestamp = newTimestamp)
val json = gson.toJson(meta)
try {
infoFi.writeText(json)
} catch (e: Exception) {
logger?.warn("Failed to write into \"info.json\"", e)
}
}

internal
fun tryReadGitHubModInfo(infoFi: File, logger: Logger? = null): GihHubModDownloadMeta {
fun writeAndGetDefault(): GihHubModDownloadMeta {
val meta = GihHubModDownloadMeta(lastUpdateTimestamp = System.currentTimeMillis())
val infoContent = gson.toJson(meta)
try {
infoFi.ensureParentDir().writeText(infoContent)
logger?.info("[MGPP] $infoFi is created.")
} catch (e: Exception) {
logger?.warn("Failed to write into \"info.json\"", e)
}
return meta
}
return if (infoFi.isFile) {
try {
val infoContent = infoFi.readText()
gson.fromJson(infoContent)
} catch (e: Exception) {
writeAndGetDefault()
}
} else {
writeAndGetDefault()
}
}

0 comments on commit 8bcd898

Please sign in to comment.