Compare commits

...

6 Commits

7 changed files with 75 additions and 41 deletions

27
.github/workflows/pr.yml vendored Normal file
View File

@@ -0,0 +1,27 @@
name: Java Gradle Build
on:
pull_request
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Set up JDK 8
uses: actions/setup-java@v2
with:
java-version: '8'
distribution: 'temurin'
cache: gradle
- name: Build with Gradle
run: ./gradlew build
- name: Cleanup Gradle Cache
# Remove some files from the Gradle cache, so they aren't cached by GitHub Actions.
# Restoring these files from a GitHub Actions cache might cause problems for future builds.
run: |
rm -f ~/.gradle/caches/modules-2/modules-2.lock
rm -f ~/.gradle/caches/modules-2/gc.properties

View File

@@ -1,6 +1,9 @@
name: Java Gradle Snapshot name: Java Gradle Snapshot
on: ["push", "pull_request"] on:
push:
branches:
- 'main'
jobs: jobs:
build: build:

View File

@@ -109,9 +109,9 @@ internal class DownloadTask private constructor(val metadata: IndexFile.File, va
cachedFile.optionValue = linkedFile.option.defaultValue cachedFile.optionValue = linkedFile.option.defaultValue
} }
} }
cachedFile.isOptional = isOptional
cachedFile.onlyOtherSide = !correctSide()
} }
cachedFile.isOptional = isOptional
cachedFile.onlyOtherSide = !correctSide()
} }
} }
} }

View File

@@ -23,7 +23,6 @@ import link.infra.packwiz.installer.ui.IUserInterface.ExceptionListResult
import link.infra.packwiz.installer.ui.data.InstallProgress import link.infra.packwiz.installer.ui.data.InstallProgress
import link.infra.packwiz.installer.util.Log import link.infra.packwiz.installer.util.Log
import okio.buffer import okio.buffer
import java.io.FileWriter
import java.io.IOException import java.io.IOException
import java.io.InputStreamReader import java.io.InputStreamReader
import java.nio.charset.StandardCharsets import java.nio.charset.StandardCharsets
@@ -197,7 +196,7 @@ class UpdateManager internal constructor(private val opts: Options, val ui: IUse
manifest.cachedSide = opts.side manifest.cachedSide = opts.side
try { try {
FileWriter(opts.manifestFile.nioPath.toFile()).use { writer -> gson.toJson(manifest, writer) } Files.newBufferedWriter(opts.manifestFile.nioPath, StandardCharsets.UTF_8).use { writer -> gson.toJson(manifest, writer) }
} catch (e: IOException) { } catch (e: IOException) {
ui.showErrorAndExit("Failed to save local manifest file", e) ui.showErrorAndExit("Failed to save local manifest file", e)
} }

View File

@@ -49,14 +49,15 @@ private val APIKey = "JDJhJDEwJHNBWVhqblU1N0EzSmpzcmJYM3JVdk92UWk2NHBLS3BnQ2VpbG
@Throws(JsonSyntaxException::class, JsonIOException::class) @Throws(JsonSyntaxException::class, JsonIOException::class)
fun resolveCfMetadata(mods: List<IndexFile.File>, packFolder: PackwizFilePath, clientHolder: ClientHolder): List<ExceptionDetails> { fun resolveCfMetadata(mods: List<IndexFile.File>, packFolder: PackwizFilePath, clientHolder: ClientHolder): List<ExceptionDetails> {
val failures = mutableListOf<ExceptionDetails>() val failures = mutableListOf<ExceptionDetails>()
val fileIdMap = mutableMapOf<Int, IndexFile.File>() val fileIdMap = mutableMapOf<Int, List<IndexFile.File>>()
for (mod in mods) { for (mod in mods) {
if (!mod.linkedFile!!.update.contains("curseforge")) { if (!mod.linkedFile!!.update.contains("curseforge")) {
failures.add(ExceptionDetails(mod.linkedFile!!.name, Exception("Failed to resolve CurseForge metadata: no CurseForge update section"))) failures.add(ExceptionDetails(mod.linkedFile!!.name, Exception("Failed to resolve CurseForge metadata: no CurseForge update section")))
continue continue
} }
fileIdMap[(mod.linkedFile!!.update["curseforge"] as CurseForgeUpdateData).fileId] = mod val fileId = (mod.linkedFile!!.update["curseforge"] as CurseForgeUpdateData).fileId
fileIdMap[fileId] = (fileIdMap[fileId] ?: listOf()) + mod
} }
val reqData = GetFilesRequest(fileIdMap.keys.toList()) val reqData = GetFilesRequest(fileIdMap.keys.toList())
@@ -77,7 +78,7 @@ fun resolveCfMetadata(mods: List<IndexFile.File>, packFolder: PackwizFilePath, c
val resData = Gson().fromJson(res.body!!.charStream(), GetFilesResponse::class.java) val resData = Gson().fromJson(res.body!!.charStream(), GetFilesResponse::class.java)
res.closeQuietly() res.closeQuietly()
val manualDownloadMods = mutableMapOf<Int, Pair<IndexFile.File, Int>>() val manualDownloadMods = mutableMapOf<Int, List<Int>>()
for (file in resData.data) { for (file in resData.data) {
if (!fileIdMap.contains(file.id)) { if (!fileIdMap.contains(file.id)) {
failures.add(ExceptionDetails(file.id.toString(), failures.add(ExceptionDetails(file.id.toString(),
@@ -85,12 +86,14 @@ fun resolveCfMetadata(mods: List<IndexFile.File>, packFolder: PackwizFilePath, c
continue continue
} }
if (file.downloadUrl == null) { if (file.downloadUrl == null) {
manualDownloadMods[file.modId] = Pair(fileIdMap[file.id]!!, file.id) manualDownloadMods[file.modId] = (manualDownloadMods[file.modId] ?: listOf()) + file.id
continue continue
} }
try { try {
fileIdMap[file.id]!!.linkedFile!!.resolvedUpdateData["curseforge"] = for (indexFile in fileIdMap[file.id]!!) {
HttpUrlPath(file.downloadUrl!!.toHttpUrl()) indexFile.linkedFile!!.resolvedUpdateData["curseforge"] =
HttpUrlPath(file.downloadUrl!!.toHttpUrl())
}
} catch (e: IllegalArgumentException) { } catch (e: IllegalArgumentException) {
failures.add(ExceptionDetails(file.id.toString(), failures.add(ExceptionDetails(file.id.toString(),
Exception("Failed to parse URL: ${file.downloadUrl} for ID ${file.id}, Project ID ${file.modId}", e))) Exception("Failed to parse URL: ${file.downloadUrl} for ID ${file.id}, Project ID ${file.modId}", e)))
@@ -99,10 +102,13 @@ fun resolveCfMetadata(mods: List<IndexFile.File>, packFolder: PackwizFilePath, c
// Some file types don't show up in the API at all! (e.g. shaderpacks) // Some file types don't show up in the API at all! (e.g. shaderpacks)
// Add unresolved files to manualDownloadMods // Add unresolved files to manualDownloadMods
for ((fileId, file) in fileIdMap) { for ((fileId, indexFiles) in fileIdMap) {
if (file.linkedFile != null) { for (file in indexFiles) {
if (file.linkedFile!!.resolvedUpdateData["curseforge"] == null) { if (file.linkedFile != null) {
manualDownloadMods[(file.linkedFile!!.update["curseforge"] as CurseForgeUpdateData).projectId] = Pair(file, fileId) if (file.linkedFile!!.resolvedUpdateData["curseforge"] == null) {
val projectId = (file.linkedFile!!.update["curseforge"] as CurseForgeUpdateData).projectId
manualDownloadMods[projectId] = (manualDownloadMods[projectId] ?: listOf()) + fileId
}
} }
} }
} }
@@ -133,9 +139,18 @@ fun resolveCfMetadata(mods: List<IndexFile.File>, packFolder: PackwizFilePath, c
continue continue
} }
val modFile = manualDownloadMods[mod.id]!! for (fileId in manualDownloadMods[mod.id]!!) {
failures.add(ExceptionDetails(mod.name, Exception("This mod is excluded from the CurseForge API and must be downloaded manually.\n" + if (!fileIdMap.contains(fileId)) {
"Please go to ${mod.links?.websiteUrl}/files/${modFile.second} and save this file to ${modFile.first.destURI.rebase(packFolder).nioPath.absolute()}"))) failures.add(ExceptionDetails(mod.name,
Exception("Failed to find file from result: file ID $fileId")))
continue
}
for (indexFile in fileIdMap[fileId]!!) {
failures.add(ExceptionDetails(indexFile.name, Exception("This mod is excluded from the CurseForge API and must be downloaded manually.\n" +
"Please go to ${mod.links?.websiteUrl}/files/${fileId} and save this file to ${indexFile.destURI.rebase(packFolder).nioPath.absolute()}")))
}
}
} }
} }

View File

@@ -4,42 +4,29 @@ import cc.ekblad.toml.model.TomlValue
import cc.ekblad.toml.tomlMapper import cc.ekblad.toml.tomlMapper
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
enum class Side { enum class Side(sideName: String) {
@SerializedName("client") @SerializedName("client")
CLIENT("client"), CLIENT("client"),
@SerializedName("server") @SerializedName("server")
SERVER("server"), SERVER("server"),
@SerializedName("both") @SerializedName("both")
@Suppress("unused") @Suppress("unused")
BOTH("both", arrayOf(CLIENT, SERVER)); BOTH("both") {
override fun hasSide(tSide: Side): Boolean {
return true
}
};
private val sideName: String private val sideName: String
private val depSides: Array<Side>?
constructor(sideName: String) { init {
this.sideName = sideName.lowercase() this.sideName = sideName.lowercase()
depSides = null
}
constructor(sideName: String, depSides: Array<Side>) {
this.sideName = sideName.lowercase()
this.depSides = depSides
} }
override fun toString() = sideName override fun toString() = sideName
fun hasSide(tSide: Side): Boolean { open fun hasSide(tSide: Side): Boolean {
if (this == tSide) { return this == tSide || tSide == BOTH
return true
}
if (depSides != null) {
for (depSide in depSides) {
if (depSide == tSide) {
return true
}
}
}
return false
} }
companion object { companion object {

View File

@@ -23,7 +23,10 @@ interface IUserInterface {
fun showCancellationDialog(): CancellationResult = CancellationResult.QUIT fun showCancellationDialog(): CancellationResult = CancellationResult.QUIT
fun showUpdateConfirmationDialog(oldVersions: List<Pair<String, String?>>, newVersions: List<Pair<String, String?>>): UpdateConfirmationResult = UpdateConfirmationResult.CANCELLED fun showUpdateConfirmationDialog(oldVersions: List<Pair<String, String?>>, newVersions: List<Pair<String, String?>>): UpdateConfirmationResult {
// Always update metadata when using the CLI
return UpdateConfirmationResult.UPDATE
}
fun awaitOptionalButton(showCancel: Boolean, timeout: Long) fun awaitOptionalButton(showCancel: Boolean, timeout: Long)