mirror of
https://github.com/packwiz/packwiz-installer.git
synced 2025-04-19 13:06: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 {
|
||||
implementation("commons-cli:commons-cli:1.4")
|
||||
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.squareup.okio:okio:2.2.2")
|
||||
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.ui.data.ExceptionDetails
|
||||
import link.infra.packwiz.installer.ui.data.IOptionDetails
|
||||
import link.infra.packwiz.installer.util.Log
|
||||
import okio.Buffer
|
||||
import okio.HashingSink
|
||||
import okio.buffer
|
||||
@ -125,6 +126,7 @@ internal class DownloadTask private constructor(val metadata: IndexFile.File, de
|
||||
fun download(packFolder: String, indexUri: SpaceSafeURI) {
|
||||
if (err != null) return
|
||||
|
||||
// TODO: is this necessary if we overwrite?
|
||||
// Ensure it is removed
|
||||
cachedFile?.let {
|
||||
if (!it.optionValue || !correctSide()) {
|
||||
@ -133,8 +135,7 @@ internal class DownloadTask private constructor(val metadata: IndexFile.File, de
|
||||
try {
|
||||
Files.deleteIfExists(Paths.get(packFolder, it.cachedLocation))
|
||||
} catch (e: IOException) {
|
||||
// TODO: how much of a problem is this? use log4j/other log library to show warning?
|
||||
e.printStackTrace()
|
||||
Log.warn("Failed to delete file before downloading", e)
|
||||
}
|
||||
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)
|
||||
data.clear()
|
||||
} else {
|
||||
// TODO: no more PRINTLN!!!!!!!!!
|
||||
// TODO: move println to something visible in the error window
|
||||
println("Invalid hash for " + metadata.destURI.toString())
|
||||
println("Calculated: " + fileSource.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.ui.cli.CLIHandler
|
||||
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.Options
|
||||
import org.apache.commons.cli.ParseException
|
||||
@ -29,7 +30,7 @@ class Main(args: Array<String>) {
|
||||
val cmd = try {
|
||||
parser.parse(options, args)
|
||||
} catch (e: ParseException) {
|
||||
e.printStackTrace()
|
||||
Log.fatal("Failed to parse command line arguments", e)
|
||||
if (guiEnabled) {
|
||||
EventQueue.invokeAndWait {
|
||||
try {
|
||||
@ -37,7 +38,8 @@ class Main(args: Array<String>) {
|
||||
} catch (ignored: Exception) {
|
||||
// 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)
|
||||
@ -51,33 +53,34 @@ class Main(args: Array<String>) {
|
||||
|
||||
val unparsedArgs = cmd.args
|
||||
if (unparsedArgs.size > 1) {
|
||||
ui.handleExceptionAndExit(RuntimeException("Too many arguments specified!"))
|
||||
ui.showErrorAndExit("Too many arguments specified!")
|
||||
} 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()
|
||||
|
||||
val uOptions = UpdateManager.Options().apply {
|
||||
side = cmd.getOptionValue("side")?.let((UpdateManager.Options.Side)::from) ?: side
|
||||
packFolder = cmd.getOptionValue("pack-folder") ?: packFolder
|
||||
manifestFile = cmd.getOptionValue("meta-file") ?: manifestFile
|
||||
}
|
||||
|
||||
try {
|
||||
uOptions.downloadURI = SpaceSafeURI(unparsedArgs[0])
|
||||
val uOptions = try {
|
||||
UpdateManager.Options.construct(
|
||||
downloadURI = SpaceSafeURI(unparsedArgs[0]),
|
||||
side = cmd.getOptionValue("side")?.let((UpdateManager.Options.Side)::from),
|
||||
packFolder = cmd.getOptionValue("pack-folder"),
|
||||
manifestFile = cmd.getOptionValue("meta-file")
|
||||
)
|
||||
} catch (e: URISyntaxException) {
|
||||
// TODO: better error message?
|
||||
ui.handleExceptionAndExit(e)
|
||||
ui.showErrorAndExit("Failed to read pack.toml URI", e)
|
||||
}
|
||||
|
||||
// Start update process!
|
||||
try {
|
||||
UpdateManager(uOptions, ui)
|
||||
} catch (e: Exception) { // TODO: better error message?
|
||||
ui.handleExceptionAndExit(e)
|
||||
} catch (e: Exception) {
|
||||
ui.showErrorAndExit("Update process failed", e)
|
||||
}
|
||||
println("Finished successfully!")
|
||||
ui.dispose()
|
||||
@ -111,17 +114,17 @@ class Main(args: Array<String>) {
|
||||
try {
|
||||
startup(args)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
Log.fatal("Error from main", e)
|
||||
if (guiEnabled) {
|
||||
EventQueue.invokeLater {
|
||||
JOptionPane.showMessageDialog(null,
|
||||
"A fatal error occurred: \n" + e.javaClass.canonicalName + ": " + e.message,
|
||||
"A fatal error occurred: \n$e",
|
||||
"packwiz-installer", JOptionPane.ERROR_MESSAGE)
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -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.ExceptionListResult
|
||||
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 java.io.FileNotFoundException
|
||||
import java.io.FileReader
|
||||
@ -43,11 +46,17 @@ class UpdateManager internal constructor(private val opts: Options, val ui: IUse
|
||||
}
|
||||
|
||||
data class Options(
|
||||
var downloadURI: SpaceSafeURI? = null,
|
||||
var manifestFile: String = "packwiz.json", // TODO: make configurable
|
||||
var packFolder: String = ".",
|
||||
var side: Side = Side.CLIENT
|
||||
val downloadURI: SpaceSafeURI,
|
||||
val manifestFile: String,
|
||||
val packFolder: String,
|
||||
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 {
|
||||
@SerializedName("client")
|
||||
CLIENT("client"),
|
||||
@ -111,11 +120,9 @@ class UpdateManager internal constructor(private val opts: Options, val ui: IUse
|
||||
} catch (e: FileNotFoundException) {
|
||||
ManifestFile()
|
||||
} catch (e: JsonSyntaxException) {
|
||||
ui.handleExceptionAndExit(e)
|
||||
return
|
||||
ui.showErrorAndExit("Invalid local manifest file, try deleting ${opts.manifestFile}", e)
|
||||
} catch (e: JsonIOException) {
|
||||
ui.handleExceptionAndExit(e)
|
||||
return
|
||||
ui.showErrorAndExit("Failed to read local manifest file, try deleting ${opts.manifestFile}", e)
|
||||
}
|
||||
|
||||
if (ui.cancelButtonPressed) {
|
||||
@ -125,19 +132,16 @@ class UpdateManager internal constructor(private val opts: Options, val ui: IUse
|
||||
|
||||
ui.submitProgress(InstallProgress("Loading pack file..."))
|
||||
val packFileSource = try {
|
||||
val src = getFileSource(opts.downloadURI!!)
|
||||
val src = getFileSource(opts.downloadURI)
|
||||
getHasher("sha256").getHashingSource(src)
|
||||
} catch (e: Exception) {
|
||||
// TODO: run cancellation window?
|
||||
ui.handleExceptionAndExit(e)
|
||||
return
|
||||
ui.showErrorAndExit("Failed to download pack.toml", e)
|
||||
}
|
||||
val pf = packFileSource.buffer().use {
|
||||
try {
|
||||
Toml().read(it.inputStream()).to(PackFile::class.java)
|
||||
} catch (e: IllegalStateException) {
|
||||
ui.handleExceptionAndExit(e)
|
||||
return
|
||||
ui.showErrorAndExit("Failed to parse pack.toml", e)
|
||||
}
|
||||
}
|
||||
|
||||
@ -169,40 +173,41 @@ class UpdateManager internal constructor(private val opts: Options, val ui: IUse
|
||||
}
|
||||
}
|
||||
if (invalid) {
|
||||
println("File $fileUri invalidated, marked for redownloading")
|
||||
Log.info("File $fileUri invalidated, marked for redownloading")
|
||||
invalidatedUris.add(fileUri)
|
||||
}
|
||||
}
|
||||
|
||||
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?
|
||||
if (!ui.optionsButtonPressed) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
println("Modpack name: " + pf.name)
|
||||
Log.info("Modpack name: ${pf.name}")
|
||||
|
||||
if (ui.cancelButtonPressed) {
|
||||
showCancellationDialog()
|
||||
handleCancellation()
|
||||
}
|
||||
try {
|
||||
val index = pf.index!!
|
||||
getNewLoc(opts.downloadURI, index.file)?.let { newLoc ->
|
||||
index.hashFormat?.let { hashFormat ->
|
||||
processIndex(
|
||||
newLoc,
|
||||
getHash(index.hashFormat!!, index.hash!!),
|
||||
hashFormat,
|
||||
manifest,
|
||||
invalidatedUris
|
||||
)
|
||||
ifletOrWarn(pf.index, "No index file found") { index ->
|
||||
ui.ifletOrErr(index.hashFormat, index.hash, "Pack has no hash or hashFormat for index") { hashFormat, hash ->
|
||||
ui.ifletOrErr(getNewLoc(opts.downloadURI, index.file), "Pack has invalid index file: " + index.file) { newLoc ->
|
||||
processIndex(
|
||||
newLoc,
|
||||
getHash(hashFormat, hash),
|
||||
hashFormat,
|
||||
manifest,
|
||||
invalidatedUris
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e1: Exception) {
|
||||
ui.handleExceptionAndExit(e1)
|
||||
ui.showErrorAndExit("Failed to process index file", e1)
|
||||
}
|
||||
|
||||
handleCancellation()
|
||||
@ -221,8 +226,7 @@ class UpdateManager internal constructor(private val opts: Options, val ui: IUse
|
||||
try {
|
||||
FileWriter(Paths.get(opts.packFolder, opts.manifestFile).toString()).use { writer -> gson.toJson(manifest, writer) }
|
||||
} catch (e: IOException) {
|
||||
// TODO: add message?
|
||||
ui.handleException(e)
|
||||
ui.showErrorAndExit("Failed to save local manifest file", 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>) {
|
||||
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) {
|
||||
return
|
||||
}
|
||||
@ -243,20 +247,18 @@ class UpdateManager internal constructor(private val opts: Options, val ui: IUse
|
||||
val src = getFileSource(indexUri)
|
||||
getHasher(hashFormat).getHashingSource(src)
|
||||
} catch (e: Exception) {
|
||||
// TODO: run cancellation window?
|
||||
ui.handleExceptionAndExit(e)
|
||||
return
|
||||
ui.showErrorAndExit("Failed to download index file", e)
|
||||
}
|
||||
|
||||
val indexFile = try {
|
||||
Toml().read(indexFileSource.buffer().inputStream()).to(IndexFile::class.java)
|
||||
} catch (e: IllegalStateException) {
|
||||
ui.handleExceptionAndExit(e)
|
||||
return
|
||||
ui.showErrorAndExit("Failed to parse index file", e)
|
||||
}
|
||||
if (!indexFileSource.hashIsEqual(indexHash)) {
|
||||
ui.handleExceptionAndExit(RuntimeException("Your index hash is invalid! Please run packwiz refresh on the pack again"))
|
||||
return
|
||||
ui.showErrorAndExit("Your index file hash is invalid! The pack developer should packwiz refresh on the pack again")
|
||||
}
|
||||
|
||||
if (ui.cancelButtonPressed) {
|
||||
showCancellationDialog()
|
||||
return
|
||||
@ -274,8 +276,7 @@ class UpdateManager internal constructor(private val opts: Options, val ui: IUse
|
||||
try {
|
||||
Files.deleteIfExists(Paths.get(opts.packFolder, file.cachedLocation))
|
||||
} catch (e: IOException) {
|
||||
// TODO: should this be shown to the user in some way?
|
||||
e.printStackTrace()
|
||||
Log.warn("Failed to delete optional disabled file", e)
|
||||
}
|
||||
// Set to null, as it doesn't exist anymore
|
||||
file.cachedLocation = null
|
||||
@ -285,8 +286,8 @@ class UpdateManager internal constructor(private val opts: Options, val ui: IUse
|
||||
if (!alreadyDeleted) {
|
||||
try {
|
||||
Files.deleteIfExists(Paths.get(opts.packFolder, file.cachedLocation))
|
||||
} catch (e: IOException) { // TODO: should this be shown to the user in some way?
|
||||
e.printStackTrace()
|
||||
} catch (e: IOException) {
|
||||
Log.warn("Failed to delete file removed from index", e)
|
||||
}
|
||||
}
|
||||
it.remove()
|
||||
@ -302,14 +303,14 @@ class UpdateManager internal constructor(private val opts: Options, val ui: IUse
|
||||
|
||||
// TODO: progress bar?
|
||||
if (indexFile.files.isEmpty()) {
|
||||
println("Warning: Index is empty!")
|
||||
Log.warn("Index is empty!")
|
||||
}
|
||||
val tasks = createTasksFromIndex(indexFile, indexFile.hashFormat, opts.side)
|
||||
// If the side changes, invalidate EVERYTHING just in case
|
||||
// Might not be needed, but done just to be safe
|
||||
val invalidateAll = opts.side != manifest.cachedSide
|
||||
if (invalidateAll) {
|
||||
println("Side changed, invalidating all mods")
|
||||
Log.info("Side changed, invalidating all mods")
|
||||
}
|
||||
tasks.forEach{ f ->
|
||||
// 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) {
|
||||
var task: DownloadTask?
|
||||
task = try {
|
||||
val task: DownloadTask = try {
|
||||
completionService.take().get()
|
||||
} catch (e: InterruptedException) {
|
||||
ui.handleException(e)
|
||||
null
|
||||
ui.showErrorAndExit("Interrupted when consuming download tasks", e)
|
||||
} catch (e: ExecutionException) {
|
||||
ui.handleException(e)
|
||||
null
|
||||
ui.showErrorAndExit("Failed to execute download task", e)
|
||||
}
|
||||
// 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()) {
|
||||
val oldFile = file.revert
|
||||
if (oldFile != null) {
|
||||
@ -399,17 +397,11 @@ class UpdateManager internal constructor(private val opts: Options, val ui: IUse
|
||||
}
|
||||
}
|
||||
|
||||
var progress: String
|
||||
if (task != null) {
|
||||
val exDetails = task.exceptionDetails
|
||||
if (exDetails != null) {
|
||||
progress = "Failed to download ${exDetails.name}: ${exDetails.exception.message}"
|
||||
exDetails.exception.printStackTrace()
|
||||
} else {
|
||||
progress = "Downloaded ${task.name}"
|
||||
}
|
||||
val exDetails = task.exceptionDetails
|
||||
val progress = if (exDetails != null) {
|
||||
"Failed to download ${exDetails.name}: ${exDetails.exception.message}"
|
||||
} else {
|
||||
progress = "Failed to download, unknown reason"
|
||||
"Downloaded ${task.name}"
|
||||
}
|
||||
ui.submitProgress(InstallProgress(progress, i + 1, tasks.size))
|
||||
|
||||
|
@ -14,6 +14,7 @@ object HandlerManager {
|
||||
RequestHandlerFile()
|
||||
)
|
||||
|
||||
// TODO: get rid of nullable stuff here
|
||||
@JvmStatic
|
||||
fun getNewLoc(base: SpaceSafeURI?, loc: SpaceSafeURI?): SpaceSafeURI? {
|
||||
if (loc == null) {
|
||||
@ -32,6 +33,8 @@ object HandlerManager {
|
||||
// Zip handler discards once read, requesting multiple times on other handlers would cause multiple downloads
|
||||
// Caching system? Copy from already downloaded files?
|
||||
|
||||
// TODO: change to use something more idiomatic than exceptions?
|
||||
|
||||
@JvmStatic
|
||||
@Throws(Exception::class)
|
||||
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.IOptionDetails
|
||||
import link.infra.packwiz.installer.ui.data.InstallProgress
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
interface IUserInterface {
|
||||
fun show()
|
||||
fun dispose()
|
||||
fun handleException(e: Exception)
|
||||
fun handleExceptionAndExit(e: Exception) {
|
||||
handleException(e)
|
||||
exitProcess(1)
|
||||
|
||||
fun showErrorAndExit(message: String): Nothing {
|
||||
showErrorAndExit(message, null)
|
||||
}
|
||||
fun showErrorAndExit(message: String, e: Exception?): Nothing
|
||||
|
||||
fun setTitle(title: String) {}
|
||||
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.IOptionDetails
|
||||
import link.infra.packwiz.installer.ui.data.InstallProgress
|
||||
import link.infra.packwiz.installer.util.Log
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
class CLIHandler : IUserInterface {
|
||||
@ -13,8 +14,13 @@ class CLIHandler : IUserInterface {
|
||||
@Volatile
|
||||
override var cancelButtonPressed = false
|
||||
|
||||
override fun handleException(e: Exception) {
|
||||
e.printStackTrace()
|
||||
override fun showErrorAndExit(message: String, e: Exception?): Nothing {
|
||||
if (e != null) {
|
||||
Log.fatal(message, e)
|
||||
} else {
|
||||
Log.fatal(message)
|
||||
}
|
||||
exitProcess(1)
|
||||
}
|
||||
|
||||
override fun show() {}
|
||||
@ -36,7 +42,7 @@ class CLIHandler : IUserInterface {
|
||||
for (opt in options) {
|
||||
opt.optionValue = true
|
||||
// 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!
|
||||
}
|
||||
@ -44,9 +50,9 @@ class CLIHandler : IUserInterface {
|
||||
override fun showExceptions(exceptions: List<ExceptionDetails>, numTotal: Int, allowsIgnore: Boolean): ExceptionListResult {
|
||||
println("Failed to download modpack, the following errors were encountered:")
|
||||
for (ex in exceptions) {
|
||||
println(ex.name + ": ")
|
||||
print(ex.name + ": ")
|
||||
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.IOptionDetails
|
||||
import link.infra.packwiz.installer.ui.data.InstallProgress
|
||||
import link.infra.packwiz.installer.util.Log
|
||||
import java.awt.EventQueue
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import javax.swing.JDialog
|
||||
@ -27,8 +28,7 @@ class GUIHandler : IUserInterface {
|
||||
try {
|
||||
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName())
|
||||
} catch (e: Exception) {
|
||||
println("Failed to set look and feel:")
|
||||
e.printStackTrace()
|
||||
Log.warn("Failed to set look and feel", e)
|
||||
}
|
||||
frmPackwizlauncher = InstallWindow(this).apply {
|
||||
title = this@GUIHandler.title
|
||||
@ -44,23 +44,23 @@ class GUIHandler : IUserInterface {
|
||||
frmPackwizlauncher.dispose()
|
||||
}
|
||||
|
||||
override fun handleException(e: Exception) {
|
||||
e.printStackTrace()
|
||||
EventQueue.invokeAndWait {
|
||||
JOptionPane.showMessageDialog(null,
|
||||
"An error occurred: \n" + e.javaClass.canonicalName + ": " + e.message,
|
||||
override fun showErrorAndExit(message: String, e: Exception?): Nothing {
|
||||
if (e != null) {
|
||||
Log.fatal(message, e)
|
||||
EventQueue.invokeAndWait {
|
||||
JOptionPane.showMessageDialog(null,
|
||||
"$message: $e",
|
||||
title, JOptionPane.ERROR_MESSAGE)
|
||||
}
|
||||
}
|
||||
|
||||
override fun handleExceptionAndExit(e: Exception) {
|
||||
e.printStackTrace()
|
||||
EventQueue.invokeAndWait {
|
||||
JOptionPane.showMessageDialog(null,
|
||||
"A fatal error occurred: \n" + e.javaClass.canonicalName + ": " + e.message,
|
||||
}
|
||||
} else {
|
||||
Log.fatal(message)
|
||||
EventQueue.invokeAndWait {
|
||||
JOptionPane.showMessageDialog(null,
|
||||
message,
|
||||
title, JOptionPane.ERROR_MESSAGE)
|
||||
exitProcess(1)
|
||||
}
|
||||
}
|
||||
exitProcess(1)
|
||||
}
|
||||
|
||||
override fun setTitle(title: String) {
|
||||
@ -78,8 +78,7 @@ class GUIHandler : IUserInterface {
|
||||
sb.append(") ")
|
||||
}
|
||||
sb.append(progress.message)
|
||||
// TODO: better logging library?
|
||||
println(sb.toString())
|
||||
Log.info(sb.toString())
|
||||
EventQueue.invokeLater {
|
||||
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