mirror of
https://github.com/packwiz/packwiz-installer.git
synced 2025-04-19 21:16:30 +02:00
Rework error handling to be more robust
This commit is contained in:
parent
1d4c94f5b6
commit
0858c90079
@ -14,8 +14,6 @@ java {
|
|||||||
dependencies {
|
dependencies {
|
||||||
implementation("commons-cli:commons-cli:1.4")
|
implementation("commons-cli:commons-cli:1.4")
|
||||||
implementation("com.moandjiezana.toml:toml4j:0.7.2")
|
implementation("com.moandjiezana.toml:toml4j:0.7.2")
|
||||||
// TODO: Implement tests
|
|
||||||
//testImplementation "junit:junit:4.12"
|
|
||||||
implementation("com.google.code.gson:gson:2.8.1")
|
implementation("com.google.code.gson:gson:2.8.1")
|
||||||
implementation("com.squareup.okio:okio:2.2.2")
|
implementation("com.squareup.okio:okio:2.2.2")
|
||||||
implementation(kotlin("stdlib-jdk8"))
|
implementation(kotlin("stdlib-jdk8"))
|
||||||
|
@ -8,6 +8,7 @@ import link.infra.packwiz.installer.metadata.hash.HashUtils.getHash
|
|||||||
import link.infra.packwiz.installer.metadata.hash.HashUtils.getHasher
|
import link.infra.packwiz.installer.metadata.hash.HashUtils.getHasher
|
||||||
import link.infra.packwiz.installer.ui.data.ExceptionDetails
|
import link.infra.packwiz.installer.ui.data.ExceptionDetails
|
||||||
import link.infra.packwiz.installer.ui.data.IOptionDetails
|
import link.infra.packwiz.installer.ui.data.IOptionDetails
|
||||||
|
import link.infra.packwiz.installer.util.Log
|
||||||
import okio.Buffer
|
import okio.Buffer
|
||||||
import okio.HashingSink
|
import okio.HashingSink
|
||||||
import okio.buffer
|
import okio.buffer
|
||||||
@ -125,6 +126,7 @@ internal class DownloadTask private constructor(val metadata: IndexFile.File, de
|
|||||||
fun download(packFolder: String, indexUri: SpaceSafeURI) {
|
fun download(packFolder: String, indexUri: SpaceSafeURI) {
|
||||||
if (err != null) return
|
if (err != null) return
|
||||||
|
|
||||||
|
// TODO: is this necessary if we overwrite?
|
||||||
// Ensure it is removed
|
// Ensure it is removed
|
||||||
cachedFile?.let {
|
cachedFile?.let {
|
||||||
if (!it.optionValue || !correctSide()) {
|
if (!it.optionValue || !correctSide()) {
|
||||||
@ -133,8 +135,7 @@ internal class DownloadTask private constructor(val metadata: IndexFile.File, de
|
|||||||
try {
|
try {
|
||||||
Files.deleteIfExists(Paths.get(packFolder, it.cachedLocation))
|
Files.deleteIfExists(Paths.get(packFolder, it.cachedLocation))
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
// TODO: how much of a problem is this? use log4j/other log library to show warning?
|
Log.warn("Failed to delete file before downloading", e)
|
||||||
e.printStackTrace()
|
|
||||||
}
|
}
|
||||||
it.cachedLocation = null
|
it.cachedLocation = null
|
||||||
}
|
}
|
||||||
@ -190,7 +191,7 @@ internal class DownloadTask private constructor(val metadata: IndexFile.File, de
|
|||||||
Files.copy(data.inputStream(), destPath, StandardCopyOption.REPLACE_EXISTING)
|
Files.copy(data.inputStream(), destPath, StandardCopyOption.REPLACE_EXISTING)
|
||||||
data.clear()
|
data.clear()
|
||||||
} else {
|
} else {
|
||||||
// TODO: no more PRINTLN!!!!!!!!!
|
// TODO: move println to something visible in the error window
|
||||||
println("Invalid hash for " + metadata.destURI.toString())
|
println("Invalid hash for " + metadata.destURI.toString())
|
||||||
println("Calculated: " + fileSource.hash)
|
println("Calculated: " + fileSource.hash)
|
||||||
println("Expected: $hash")
|
println("Expected: $hash")
|
||||||
|
@ -5,6 +5,7 @@ package link.infra.packwiz.installer
|
|||||||
import link.infra.packwiz.installer.metadata.SpaceSafeURI
|
import link.infra.packwiz.installer.metadata.SpaceSafeURI
|
||||||
import link.infra.packwiz.installer.ui.cli.CLIHandler
|
import link.infra.packwiz.installer.ui.cli.CLIHandler
|
||||||
import link.infra.packwiz.installer.ui.gui.GUIHandler
|
import link.infra.packwiz.installer.ui.gui.GUIHandler
|
||||||
|
import link.infra.packwiz.installer.util.Log
|
||||||
import org.apache.commons.cli.DefaultParser
|
import org.apache.commons.cli.DefaultParser
|
||||||
import org.apache.commons.cli.Options
|
import org.apache.commons.cli.Options
|
||||||
import org.apache.commons.cli.ParseException
|
import org.apache.commons.cli.ParseException
|
||||||
@ -29,7 +30,7 @@ class Main(args: Array<String>) {
|
|||||||
val cmd = try {
|
val cmd = try {
|
||||||
parser.parse(options, args)
|
parser.parse(options, args)
|
||||||
} catch (e: ParseException) {
|
} catch (e: ParseException) {
|
||||||
e.printStackTrace()
|
Log.fatal("Failed to parse command line arguments", e)
|
||||||
if (guiEnabled) {
|
if (guiEnabled) {
|
||||||
EventQueue.invokeAndWait {
|
EventQueue.invokeAndWait {
|
||||||
try {
|
try {
|
||||||
@ -37,7 +38,8 @@ class Main(args: Array<String>) {
|
|||||||
} catch (ignored: Exception) {
|
} catch (ignored: Exception) {
|
||||||
// Ignore the exceptions, just continue using the ugly L&F
|
// Ignore the exceptions, just continue using the ugly L&F
|
||||||
}
|
}
|
||||||
JOptionPane.showMessageDialog(null, e.message, "packwiz-installer", JOptionPane.ERROR_MESSAGE)
|
JOptionPane.showMessageDialog(null, "Failed to parse command line arguments: $e",
|
||||||
|
"packwiz-installer", JOptionPane.ERROR_MESSAGE)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
exitProcess(1)
|
exitProcess(1)
|
||||||
@ -51,33 +53,34 @@ class Main(args: Array<String>) {
|
|||||||
|
|
||||||
val unparsedArgs = cmd.args
|
val unparsedArgs = cmd.args
|
||||||
if (unparsedArgs.size > 1) {
|
if (unparsedArgs.size > 1) {
|
||||||
ui.handleExceptionAndExit(RuntimeException("Too many arguments specified!"))
|
ui.showErrorAndExit("Too many arguments specified!")
|
||||||
} else if (unparsedArgs.isEmpty()) {
|
} else if (unparsedArgs.isEmpty()) {
|
||||||
ui.handleExceptionAndExit(RuntimeException("URI to install from must be specified!"))
|
ui.showErrorAndExit("pack.toml URI to install from must be specified!")
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.getOptionValue("title")?.also(ui::setTitle)
|
val title = cmd.getOptionValue("title")
|
||||||
|
if (title != null) {
|
||||||
|
ui.setTitle(title)
|
||||||
|
}
|
||||||
|
|
||||||
ui.show()
|
ui.show()
|
||||||
|
|
||||||
val uOptions = UpdateManager.Options().apply {
|
val uOptions = try {
|
||||||
side = cmd.getOptionValue("side")?.let((UpdateManager.Options.Side)::from) ?: side
|
UpdateManager.Options.construct(
|
||||||
packFolder = cmd.getOptionValue("pack-folder") ?: packFolder
|
downloadURI = SpaceSafeURI(unparsedArgs[0]),
|
||||||
manifestFile = cmd.getOptionValue("meta-file") ?: manifestFile
|
side = cmd.getOptionValue("side")?.let((UpdateManager.Options.Side)::from),
|
||||||
}
|
packFolder = cmd.getOptionValue("pack-folder"),
|
||||||
|
manifestFile = cmd.getOptionValue("meta-file")
|
||||||
try {
|
)
|
||||||
uOptions.downloadURI = SpaceSafeURI(unparsedArgs[0])
|
|
||||||
} catch (e: URISyntaxException) {
|
} catch (e: URISyntaxException) {
|
||||||
// TODO: better error message?
|
ui.showErrorAndExit("Failed to read pack.toml URI", e)
|
||||||
ui.handleExceptionAndExit(e)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start update process!
|
// Start update process!
|
||||||
try {
|
try {
|
||||||
UpdateManager(uOptions, ui)
|
UpdateManager(uOptions, ui)
|
||||||
} catch (e: Exception) { // TODO: better error message?
|
} catch (e: Exception) {
|
||||||
ui.handleExceptionAndExit(e)
|
ui.showErrorAndExit("Update process failed", e)
|
||||||
}
|
}
|
||||||
println("Finished successfully!")
|
println("Finished successfully!")
|
||||||
ui.dispose()
|
ui.dispose()
|
||||||
@ -111,17 +114,17 @@ class Main(args: Array<String>) {
|
|||||||
try {
|
try {
|
||||||
startup(args)
|
startup(args)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
e.printStackTrace()
|
Log.fatal("Error from main", e)
|
||||||
if (guiEnabled) {
|
if (guiEnabled) {
|
||||||
EventQueue.invokeLater {
|
EventQueue.invokeLater {
|
||||||
JOptionPane.showMessageDialog(null,
|
JOptionPane.showMessageDialog(null,
|
||||||
"A fatal error occurred: \n" + e.javaClass.canonicalName + ": " + e.message,
|
"A fatal error occurred: \n$e",
|
||||||
"packwiz-installer", JOptionPane.ERROR_MESSAGE)
|
"packwiz-installer", JOptionPane.ERROR_MESSAGE)
|
||||||
exitProcess(1)
|
exitProcess(1)
|
||||||
}
|
}
|
||||||
|
// In case the EventQueue is broken, exit after 1 minute
|
||||||
|
Thread.sleep(60 * 1000.toLong())
|
||||||
}
|
}
|
||||||
// In case the EventQueue is broken, exit after 1 minute
|
|
||||||
Thread.sleep(60 * 1000.toLong())
|
|
||||||
exitProcess(1)
|
exitProcess(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,9 @@ import link.infra.packwiz.installer.ui.IUserInterface
|
|||||||
import link.infra.packwiz.installer.ui.IUserInterface.CancellationResult
|
import link.infra.packwiz.installer.ui.IUserInterface.CancellationResult
|
||||||
import link.infra.packwiz.installer.ui.IUserInterface.ExceptionListResult
|
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.ifletOrErr
|
||||||
|
import link.infra.packwiz.installer.util.ifletOrWarn
|
||||||
import okio.buffer
|
import okio.buffer
|
||||||
import java.io.FileNotFoundException
|
import java.io.FileNotFoundException
|
||||||
import java.io.FileReader
|
import java.io.FileReader
|
||||||
@ -43,11 +46,17 @@ class UpdateManager internal constructor(private val opts: Options, val ui: IUse
|
|||||||
}
|
}
|
||||||
|
|
||||||
data class Options(
|
data class Options(
|
||||||
var downloadURI: SpaceSafeURI? = null,
|
val downloadURI: SpaceSafeURI,
|
||||||
var manifestFile: String = "packwiz.json", // TODO: make configurable
|
val manifestFile: String,
|
||||||
var packFolder: String = ".",
|
val packFolder: String,
|
||||||
var side: Side = Side.CLIENT
|
val side: Side
|
||||||
) {
|
) {
|
||||||
|
// Horrible workaround for default params not working cleanly with nullable values
|
||||||
|
companion object {
|
||||||
|
fun construct(downloadURI: SpaceSafeURI, manifestFile: String?, packFolder: String?, side: Side?) =
|
||||||
|
Options(downloadURI, manifestFile ?: "packwiz.json", packFolder ?: ".", side ?: Side.CLIENT)
|
||||||
|
}
|
||||||
|
|
||||||
enum class Side {
|
enum class Side {
|
||||||
@SerializedName("client")
|
@SerializedName("client")
|
||||||
CLIENT("client"),
|
CLIENT("client"),
|
||||||
@ -111,11 +120,9 @@ class UpdateManager internal constructor(private val opts: Options, val ui: IUse
|
|||||||
} catch (e: FileNotFoundException) {
|
} catch (e: FileNotFoundException) {
|
||||||
ManifestFile()
|
ManifestFile()
|
||||||
} catch (e: JsonSyntaxException) {
|
} catch (e: JsonSyntaxException) {
|
||||||
ui.handleExceptionAndExit(e)
|
ui.showErrorAndExit("Invalid local manifest file, try deleting ${opts.manifestFile}", e)
|
||||||
return
|
|
||||||
} catch (e: JsonIOException) {
|
} catch (e: JsonIOException) {
|
||||||
ui.handleExceptionAndExit(e)
|
ui.showErrorAndExit("Failed to read local manifest file, try deleting ${opts.manifestFile}", e)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ui.cancelButtonPressed) {
|
if (ui.cancelButtonPressed) {
|
||||||
@ -125,19 +132,16 @@ class UpdateManager internal constructor(private val opts: Options, val ui: IUse
|
|||||||
|
|
||||||
ui.submitProgress(InstallProgress("Loading pack file..."))
|
ui.submitProgress(InstallProgress("Loading pack file..."))
|
||||||
val packFileSource = try {
|
val packFileSource = try {
|
||||||
val src = getFileSource(opts.downloadURI!!)
|
val src = getFileSource(opts.downloadURI)
|
||||||
getHasher("sha256").getHashingSource(src)
|
getHasher("sha256").getHashingSource(src)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
// TODO: run cancellation window?
|
ui.showErrorAndExit("Failed to download pack.toml", e)
|
||||||
ui.handleExceptionAndExit(e)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
val pf = packFileSource.buffer().use {
|
val pf = packFileSource.buffer().use {
|
||||||
try {
|
try {
|
||||||
Toml().read(it.inputStream()).to(PackFile::class.java)
|
Toml().read(it.inputStream()).to(PackFile::class.java)
|
||||||
} catch (e: IllegalStateException) {
|
} catch (e: IllegalStateException) {
|
||||||
ui.handleExceptionAndExit(e)
|
ui.showErrorAndExit("Failed to parse pack.toml", e)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -169,40 +173,41 @@ class UpdateManager internal constructor(private val opts: Options, val ui: IUse
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (invalid) {
|
if (invalid) {
|
||||||
println("File $fileUri invalidated, marked for redownloading")
|
Log.info("File $fileUri invalidated, marked for redownloading")
|
||||||
invalidatedUris.add(fileUri)
|
invalidatedUris.add(fileUri)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (manifest.packFileHash?.let { packFileSource.hashIsEqual(it) } == true && invalidatedUris.isEmpty()) {
|
if (manifest.packFileHash?.let { packFileSource.hashIsEqual(it) } == true && invalidatedUris.isEmpty()) {
|
||||||
println("Modpack is already up to date!")
|
Log.info("Modpack is already up to date!")
|
||||||
// todo: --force?
|
// todo: --force?
|
||||||
if (!ui.optionsButtonPressed) {
|
if (!ui.optionsButtonPressed) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
println("Modpack name: " + pf.name)
|
Log.info("Modpack name: ${pf.name}")
|
||||||
|
|
||||||
if (ui.cancelButtonPressed) {
|
if (ui.cancelButtonPressed) {
|
||||||
showCancellationDialog()
|
showCancellationDialog()
|
||||||
handleCancellation()
|
handleCancellation()
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
val index = pf.index!!
|
ifletOrWarn(pf.index, "No index file found") { index ->
|
||||||
getNewLoc(opts.downloadURI, index.file)?.let { newLoc ->
|
ui.ifletOrErr(index.hashFormat, index.hash, "Pack has no hash or hashFormat for index") { hashFormat, hash ->
|
||||||
index.hashFormat?.let { hashFormat ->
|
ui.ifletOrErr(getNewLoc(opts.downloadURI, index.file), "Pack has invalid index file: " + index.file) { newLoc ->
|
||||||
processIndex(
|
processIndex(
|
||||||
newLoc,
|
newLoc,
|
||||||
getHash(index.hashFormat!!, index.hash!!),
|
getHash(hashFormat, hash),
|
||||||
hashFormat,
|
hashFormat,
|
||||||
manifest,
|
manifest,
|
||||||
invalidatedUris
|
invalidatedUris
|
||||||
)
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e1: Exception) {
|
} catch (e1: Exception) {
|
||||||
ui.handleExceptionAndExit(e1)
|
ui.showErrorAndExit("Failed to process index file", e1)
|
||||||
}
|
}
|
||||||
|
|
||||||
handleCancellation()
|
handleCancellation()
|
||||||
@ -221,8 +226,7 @@ class UpdateManager internal constructor(private val opts: Options, val ui: IUse
|
|||||||
try {
|
try {
|
||||||
FileWriter(Paths.get(opts.packFolder, opts.manifestFile).toString()).use { writer -> gson.toJson(manifest, writer) }
|
FileWriter(Paths.get(opts.packFolder, opts.manifestFile).toString()).use { writer -> gson.toJson(manifest, writer) }
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
// TODO: add message?
|
ui.showErrorAndExit("Failed to save local manifest file", e)
|
||||||
ui.handleException(e)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -232,7 +236,7 @@ class UpdateManager internal constructor(private val opts: Options, val ui: IUse
|
|||||||
|
|
||||||
private fun processIndex(indexUri: SpaceSafeURI, indexHash: Hash, hashFormat: String, manifest: ManifestFile, invalidatedUris: List<SpaceSafeURI>) {
|
private fun processIndex(indexUri: SpaceSafeURI, indexHash: Hash, hashFormat: String, manifest: ManifestFile, invalidatedUris: List<SpaceSafeURI>) {
|
||||||
if (manifest.indexFileHash == indexHash && invalidatedUris.isEmpty()) {
|
if (manifest.indexFileHash == indexHash && invalidatedUris.isEmpty()) {
|
||||||
println("Modpack files are already up to date!")
|
Log.info("Modpack files are already up to date!")
|
||||||
if (!ui.optionsButtonPressed) {
|
if (!ui.optionsButtonPressed) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -243,20 +247,18 @@ class UpdateManager internal constructor(private val opts: Options, val ui: IUse
|
|||||||
val src = getFileSource(indexUri)
|
val src = getFileSource(indexUri)
|
||||||
getHasher(hashFormat).getHashingSource(src)
|
getHasher(hashFormat).getHashingSource(src)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
// TODO: run cancellation window?
|
ui.showErrorAndExit("Failed to download index file", e)
|
||||||
ui.handleExceptionAndExit(e)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val indexFile = try {
|
val indexFile = try {
|
||||||
Toml().read(indexFileSource.buffer().inputStream()).to(IndexFile::class.java)
|
Toml().read(indexFileSource.buffer().inputStream()).to(IndexFile::class.java)
|
||||||
} catch (e: IllegalStateException) {
|
} catch (e: IllegalStateException) {
|
||||||
ui.handleExceptionAndExit(e)
|
ui.showErrorAndExit("Failed to parse index file", e)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
if (!indexFileSource.hashIsEqual(indexHash)) {
|
if (!indexFileSource.hashIsEqual(indexHash)) {
|
||||||
ui.handleExceptionAndExit(RuntimeException("Your index hash is invalid! Please run packwiz refresh on the pack again"))
|
ui.showErrorAndExit("Your index file hash is invalid! The pack developer should packwiz refresh on the pack again")
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ui.cancelButtonPressed) {
|
if (ui.cancelButtonPressed) {
|
||||||
showCancellationDialog()
|
showCancellationDialog()
|
||||||
return
|
return
|
||||||
@ -274,8 +276,7 @@ class UpdateManager internal constructor(private val opts: Options, val ui: IUse
|
|||||||
try {
|
try {
|
||||||
Files.deleteIfExists(Paths.get(opts.packFolder, file.cachedLocation))
|
Files.deleteIfExists(Paths.get(opts.packFolder, file.cachedLocation))
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
// TODO: should this be shown to the user in some way?
|
Log.warn("Failed to delete optional disabled file", e)
|
||||||
e.printStackTrace()
|
|
||||||
}
|
}
|
||||||
// Set to null, as it doesn't exist anymore
|
// Set to null, as it doesn't exist anymore
|
||||||
file.cachedLocation = null
|
file.cachedLocation = null
|
||||||
@ -285,8 +286,8 @@ class UpdateManager internal constructor(private val opts: Options, val ui: IUse
|
|||||||
if (!alreadyDeleted) {
|
if (!alreadyDeleted) {
|
||||||
try {
|
try {
|
||||||
Files.deleteIfExists(Paths.get(opts.packFolder, file.cachedLocation))
|
Files.deleteIfExists(Paths.get(opts.packFolder, file.cachedLocation))
|
||||||
} catch (e: IOException) { // TODO: should this be shown to the user in some way?
|
} catch (e: IOException) {
|
||||||
e.printStackTrace()
|
Log.warn("Failed to delete file removed from index", e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
it.remove()
|
it.remove()
|
||||||
@ -302,14 +303,14 @@ class UpdateManager internal constructor(private val opts: Options, val ui: IUse
|
|||||||
|
|
||||||
// TODO: progress bar?
|
// TODO: progress bar?
|
||||||
if (indexFile.files.isEmpty()) {
|
if (indexFile.files.isEmpty()) {
|
||||||
println("Warning: Index is empty!")
|
Log.warn("Index is empty!")
|
||||||
}
|
}
|
||||||
val tasks = createTasksFromIndex(indexFile, indexFile.hashFormat, opts.side)
|
val tasks = createTasksFromIndex(indexFile, indexFile.hashFormat, opts.side)
|
||||||
// If the side changes, invalidate EVERYTHING just in case
|
// If the side changes, invalidate EVERYTHING just in case
|
||||||
// Might not be needed, but done just to be safe
|
// Might not be needed, but done just to be safe
|
||||||
val invalidateAll = opts.side != manifest.cachedSide
|
val invalidateAll = opts.side != manifest.cachedSide
|
||||||
if (invalidateAll) {
|
if (invalidateAll) {
|
||||||
println("Side changed, invalidating all mods")
|
Log.info("Side changed, invalidating all mods")
|
||||||
}
|
}
|
||||||
tasks.forEach{ f ->
|
tasks.forEach{ f ->
|
||||||
// TODO: should linkedfile be checked as well? should this be done in the download section?
|
// TODO: should linkedfile be checked as well? should this be done in the download section?
|
||||||
@ -377,18 +378,15 @@ class UpdateManager internal constructor(private val opts: Options, val ui: IUse
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (i in tasks.indices) {
|
for (i in tasks.indices) {
|
||||||
var task: DownloadTask?
|
val task: DownloadTask = try {
|
||||||
task = try {
|
|
||||||
completionService.take().get()
|
completionService.take().get()
|
||||||
} catch (e: InterruptedException) {
|
} catch (e: InterruptedException) {
|
||||||
ui.handleException(e)
|
ui.showErrorAndExit("Interrupted when consuming download tasks", e)
|
||||||
null
|
|
||||||
} catch (e: ExecutionException) {
|
} catch (e: ExecutionException) {
|
||||||
ui.handleException(e)
|
ui.showErrorAndExit("Failed to execute download task", e)
|
||||||
null
|
|
||||||
}
|
}
|
||||||
// Update manifest - If there were no errors cachedFile has already been modified in place (good old pass by reference)
|
// Update manifest - If there were no errors cachedFile has already been modified in place (good old pass by reference)
|
||||||
task?.cachedFile?.let { file ->
|
task.cachedFile?.let { file ->
|
||||||
if (task.failed()) {
|
if (task.failed()) {
|
||||||
val oldFile = file.revert
|
val oldFile = file.revert
|
||||||
if (oldFile != null) {
|
if (oldFile != null) {
|
||||||
@ -399,17 +397,11 @@ class UpdateManager internal constructor(private val opts: Options, val ui: IUse
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var progress: String
|
val exDetails = task.exceptionDetails
|
||||||
if (task != null) {
|
val progress = if (exDetails != null) {
|
||||||
val exDetails = task.exceptionDetails
|
"Failed to download ${exDetails.name}: ${exDetails.exception.message}"
|
||||||
if (exDetails != null) {
|
|
||||||
progress = "Failed to download ${exDetails.name}: ${exDetails.exception.message}"
|
|
||||||
exDetails.exception.printStackTrace()
|
|
||||||
} else {
|
|
||||||
progress = "Downloaded ${task.name}"
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
progress = "Failed to download, unknown reason"
|
"Downloaded ${task.name}"
|
||||||
}
|
}
|
||||||
ui.submitProgress(InstallProgress(progress, i + 1, tasks.size))
|
ui.submitProgress(InstallProgress(progress, i + 1, tasks.size))
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ object HandlerManager {
|
|||||||
RequestHandlerFile()
|
RequestHandlerFile()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// TODO: get rid of nullable stuff here
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun getNewLoc(base: SpaceSafeURI?, loc: SpaceSafeURI?): SpaceSafeURI? {
|
fun getNewLoc(base: SpaceSafeURI?, loc: SpaceSafeURI?): SpaceSafeURI? {
|
||||||
if (loc == null) {
|
if (loc == null) {
|
||||||
@ -32,6 +33,8 @@ object HandlerManager {
|
|||||||
// Zip handler discards once read, requesting multiple times on other handlers would cause multiple downloads
|
// Zip handler discards once read, requesting multiple times on other handlers would cause multiple downloads
|
||||||
// Caching system? Copy from already downloaded files?
|
// Caching system? Copy from already downloaded files?
|
||||||
|
|
||||||
|
// TODO: change to use something more idiomatic than exceptions?
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@Throws(Exception::class)
|
@Throws(Exception::class)
|
||||||
fun getFileSource(loc: SpaceSafeURI): Source {
|
fun getFileSource(loc: SpaceSafeURI): Source {
|
||||||
|
@ -3,16 +3,15 @@ package link.infra.packwiz.installer.ui
|
|||||||
import link.infra.packwiz.installer.ui.data.ExceptionDetails
|
import link.infra.packwiz.installer.ui.data.ExceptionDetails
|
||||||
import link.infra.packwiz.installer.ui.data.IOptionDetails
|
import link.infra.packwiz.installer.ui.data.IOptionDetails
|
||||||
import link.infra.packwiz.installer.ui.data.InstallProgress
|
import link.infra.packwiz.installer.ui.data.InstallProgress
|
||||||
import kotlin.system.exitProcess
|
|
||||||
|
|
||||||
interface IUserInterface {
|
interface IUserInterface {
|
||||||
fun show()
|
fun show()
|
||||||
fun dispose()
|
fun dispose()
|
||||||
fun handleException(e: Exception)
|
|
||||||
fun handleExceptionAndExit(e: Exception) {
|
fun showErrorAndExit(message: String): Nothing {
|
||||||
handleException(e)
|
showErrorAndExit(message, null)
|
||||||
exitProcess(1)
|
|
||||||
}
|
}
|
||||||
|
fun showErrorAndExit(message: String, e: Exception?): Nothing
|
||||||
|
|
||||||
fun setTitle(title: String) {}
|
fun setTitle(title: String) {}
|
||||||
fun submitProgress(progress: InstallProgress)
|
fun submitProgress(progress: InstallProgress)
|
||||||
|
@ -5,6 +5,7 @@ import link.infra.packwiz.installer.ui.IUserInterface.ExceptionListResult
|
|||||||
import link.infra.packwiz.installer.ui.data.ExceptionDetails
|
import link.infra.packwiz.installer.ui.data.ExceptionDetails
|
||||||
import link.infra.packwiz.installer.ui.data.IOptionDetails
|
import link.infra.packwiz.installer.ui.data.IOptionDetails
|
||||||
import link.infra.packwiz.installer.ui.data.InstallProgress
|
import link.infra.packwiz.installer.ui.data.InstallProgress
|
||||||
|
import link.infra.packwiz.installer.util.Log
|
||||||
import kotlin.system.exitProcess
|
import kotlin.system.exitProcess
|
||||||
|
|
||||||
class CLIHandler : IUserInterface {
|
class CLIHandler : IUserInterface {
|
||||||
@ -13,8 +14,13 @@ class CLIHandler : IUserInterface {
|
|||||||
@Volatile
|
@Volatile
|
||||||
override var cancelButtonPressed = false
|
override var cancelButtonPressed = false
|
||||||
|
|
||||||
override fun handleException(e: Exception) {
|
override fun showErrorAndExit(message: String, e: Exception?): Nothing {
|
||||||
e.printStackTrace()
|
if (e != null) {
|
||||||
|
Log.fatal(message, e)
|
||||||
|
} else {
|
||||||
|
Log.fatal(message)
|
||||||
|
}
|
||||||
|
exitProcess(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun show() {}
|
override fun show() {}
|
||||||
@ -36,7 +42,7 @@ class CLIHandler : IUserInterface {
|
|||||||
for (opt in options) {
|
for (opt in options) {
|
||||||
opt.optionValue = true
|
opt.optionValue = true
|
||||||
// TODO: implement option choice in the CLI?
|
// TODO: implement option choice in the CLI?
|
||||||
println("Warning: accepting option " + opt.name + " as option choosing is not implemented in the CLI")
|
Log.warn("Accepting option ${opt.name} as option choosing is not implemented in the CLI")
|
||||||
}
|
}
|
||||||
return false // Can't be cancelled!
|
return false // Can't be cancelled!
|
||||||
}
|
}
|
||||||
@ -44,9 +50,9 @@ class CLIHandler : IUserInterface {
|
|||||||
override fun showExceptions(exceptions: List<ExceptionDetails>, numTotal: Int, allowsIgnore: Boolean): ExceptionListResult {
|
override fun showExceptions(exceptions: List<ExceptionDetails>, numTotal: Int, allowsIgnore: Boolean): ExceptionListResult {
|
||||||
println("Failed to download modpack, the following errors were encountered:")
|
println("Failed to download modpack, the following errors were encountered:")
|
||||||
for (ex in exceptions) {
|
for (ex in exceptions) {
|
||||||
println(ex.name + ": ")
|
print(ex.name + ": ")
|
||||||
ex.exception.printStackTrace()
|
ex.exception.printStackTrace()
|
||||||
}
|
}
|
||||||
exitProcess(1)
|
return ExceptionListResult.CANCEL
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -5,6 +5,7 @@ import link.infra.packwiz.installer.ui.IUserInterface.ExceptionListResult
|
|||||||
import link.infra.packwiz.installer.ui.data.ExceptionDetails
|
import link.infra.packwiz.installer.ui.data.ExceptionDetails
|
||||||
import link.infra.packwiz.installer.ui.data.IOptionDetails
|
import link.infra.packwiz.installer.ui.data.IOptionDetails
|
||||||
import link.infra.packwiz.installer.ui.data.InstallProgress
|
import link.infra.packwiz.installer.ui.data.InstallProgress
|
||||||
|
import link.infra.packwiz.installer.util.Log
|
||||||
import java.awt.EventQueue
|
import java.awt.EventQueue
|
||||||
import java.util.concurrent.CompletableFuture
|
import java.util.concurrent.CompletableFuture
|
||||||
import javax.swing.JDialog
|
import javax.swing.JDialog
|
||||||
@ -27,8 +28,7 @@ class GUIHandler : IUserInterface {
|
|||||||
try {
|
try {
|
||||||
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName())
|
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName())
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
println("Failed to set look and feel:")
|
Log.warn("Failed to set look and feel", e)
|
||||||
e.printStackTrace()
|
|
||||||
}
|
}
|
||||||
frmPackwizlauncher = InstallWindow(this).apply {
|
frmPackwizlauncher = InstallWindow(this).apply {
|
||||||
title = this@GUIHandler.title
|
title = this@GUIHandler.title
|
||||||
@ -44,23 +44,23 @@ class GUIHandler : IUserInterface {
|
|||||||
frmPackwizlauncher.dispose()
|
frmPackwizlauncher.dispose()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handleException(e: Exception) {
|
override fun showErrorAndExit(message: String, e: Exception?): Nothing {
|
||||||
e.printStackTrace()
|
if (e != null) {
|
||||||
EventQueue.invokeAndWait {
|
Log.fatal(message, e)
|
||||||
JOptionPane.showMessageDialog(null,
|
EventQueue.invokeAndWait {
|
||||||
"An error occurred: \n" + e.javaClass.canonicalName + ": " + e.message,
|
JOptionPane.showMessageDialog(null,
|
||||||
|
"$message: $e",
|
||||||
title, JOptionPane.ERROR_MESSAGE)
|
title, JOptionPane.ERROR_MESSAGE)
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
|
Log.fatal(message)
|
||||||
override fun handleExceptionAndExit(e: Exception) {
|
EventQueue.invokeAndWait {
|
||||||
e.printStackTrace()
|
JOptionPane.showMessageDialog(null,
|
||||||
EventQueue.invokeAndWait {
|
message,
|
||||||
JOptionPane.showMessageDialog(null,
|
|
||||||
"A fatal error occurred: \n" + e.javaClass.canonicalName + ": " + e.message,
|
|
||||||
title, JOptionPane.ERROR_MESSAGE)
|
title, JOptionPane.ERROR_MESSAGE)
|
||||||
exitProcess(1)
|
}
|
||||||
}
|
}
|
||||||
|
exitProcess(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setTitle(title: String) {
|
override fun setTitle(title: String) {
|
||||||
@ -78,8 +78,7 @@ class GUIHandler : IUserInterface {
|
|||||||
sb.append(") ")
|
sb.append(") ")
|
||||||
}
|
}
|
||||||
sb.append(progress.message)
|
sb.append(progress.message)
|
||||||
// TODO: better logging library?
|
Log.info(sb.toString())
|
||||||
println(sb.toString())
|
|
||||||
EventQueue.invokeLater {
|
EventQueue.invokeLater {
|
||||||
frmPackwizlauncher.displayProgress(progress)
|
frmPackwizlauncher.displayProgress(progress)
|
||||||
}
|
}
|
||||||
|
38
src/main/kotlin/link/infra/packwiz/installer/util/Exts.kt
Normal file
38
src/main/kotlin/link/infra/packwiz/installer/util/Exts.kt
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
package link.infra.packwiz.installer.util
|
||||||
|
|
||||||
|
import link.infra.packwiz.installer.ui.IUserInterface
|
||||||
|
|
||||||
|
inline fun <T> iflet(value: T?, whenNotNull: (T) -> Unit) {
|
||||||
|
if (value != null) {
|
||||||
|
whenNotNull(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <T, U> IUserInterface.ifletOrErr(value: T?, message: String, whenNotNull: (T) -> U): U =
|
||||||
|
if (value != null) {
|
||||||
|
whenNotNull(value)
|
||||||
|
} else {
|
||||||
|
this.showErrorAndExit(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <T, U, V> IUserInterface.ifletOrErr(value: T?, value2: U?, message: String, whenNotNull: (T, U) -> V): V =
|
||||||
|
if (value != null && value2 != null) {
|
||||||
|
whenNotNull(value, value2)
|
||||||
|
} else {
|
||||||
|
this.showErrorAndExit(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <T> ifletOrWarn(value: T?, message: String, whenNotNull: (T) -> Unit) {
|
||||||
|
if (value != null) {
|
||||||
|
whenNotNull(value)
|
||||||
|
} else {
|
||||||
|
Log.warn(message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <T, U> iflet(value: T?, whenNotNull: (T) -> U, whenNull: () -> U): U =
|
||||||
|
if (value != null) {
|
||||||
|
whenNotNull(value)
|
||||||
|
} else {
|
||||||
|
whenNull()
|
||||||
|
}
|
16
src/main/kotlin/link/infra/packwiz/installer/util/Log.kt
Normal file
16
src/main/kotlin/link/infra/packwiz/installer/util/Log.kt
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package link.infra.packwiz.installer.util
|
||||||
|
|
||||||
|
object Log {
|
||||||
|
fun info(message: String) = println(message)
|
||||||
|
|
||||||
|
fun warn(message: String) = println("[Warning] $message")
|
||||||
|
fun warn(message: String, exception: Exception) = println("[Warning] $message: $exception")
|
||||||
|
|
||||||
|
fun fatal(message: String) {
|
||||||
|
println("[FATAL] $message")
|
||||||
|
}
|
||||||
|
fun fatal(message: String, exception: Exception) {
|
||||||
|
println("[FATAL] $message: ")
|
||||||
|
exception.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user