CLI client: more robust
This commit is contained in:
@@ -80,9 +80,10 @@ object Client {
|
||||
val res = route.call(client, body)
|
||||
res
|
||||
} catch (e: CancellationException) {
|
||||
println("Coroutine calling ${route.verb} ${route.pattern} was cancelled.")
|
||||
ErrorResponse("Coroutine calling ${route.verb} ${route.pattern} was cancelled.").error()
|
||||
} catch (e: Exception) {
|
||||
// println("Call to ${route.pattern} ran into an exception")
|
||||
println("Call to ${route.pattern} ran into an exception: ${e.message} (${e::class.simpleName})")
|
||||
ErrorResponse(e.message ?: "Unknown error.").error()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
package com.jaytux.phoebench.clients.cli
|
||||
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
Client.forceGloballyInitialized()
|
||||
CLI.main(args)
|
||||
Client.shutdown()
|
||||
exitProcess(0) // because D-Bus threads...
|
||||
}
|
||||
@@ -1,14 +1,63 @@
|
||||
package com.jaytux.phoebench.clients.cli
|
||||
|
||||
import com.github.javakeyring.BackendNotSupportedException
|
||||
import com.github.javakeyring.Keyring
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.serializer
|
||||
import java.util.prefs.Preferences
|
||||
import kotlin.uuid.Uuid
|
||||
|
||||
object PersistentStorage {
|
||||
private val json = Json
|
||||
const val SERVICE = "com.jaytux.phoebench.cli"
|
||||
private var _backend: IBackend = KeyringBackend
|
||||
|
||||
interface IBackend {
|
||||
fun read(key: String): String?
|
||||
fun write(key: String, value: String)
|
||||
fun erase(key: String)
|
||||
}
|
||||
|
||||
private object KeyringBackend : IBackend {
|
||||
override fun read(key: String): String? = try {
|
||||
Keyring.create().use { it.getPassword(SERVICE, key) }
|
||||
} catch(e: Exception) {
|
||||
_backend = PreferencesBackend
|
||||
_backend.read(key)
|
||||
}
|
||||
|
||||
override fun write(key: String, value: String) {
|
||||
try {
|
||||
Keyring.create().use { it.setPassword(SERVICE, key, value) }
|
||||
} catch(e: Exception) {
|
||||
_backend = PreferencesBackend
|
||||
_backend.write(key, value)
|
||||
}
|
||||
}
|
||||
|
||||
override fun erase(key: String) {
|
||||
try {
|
||||
Keyring.create().use { it.deletePassword(SERVICE, key) }
|
||||
} catch (e: Exception) {
|
||||
_backend = PreferencesBackend
|
||||
_backend.erase(key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private object PreferencesBackend : IBackend {
|
||||
private val prefs = Preferences.userNodeForPackage(this::class.java)
|
||||
override fun read(key: String): String? = prefs.get(key, null)
|
||||
|
||||
override fun write(key: String, value: String) {
|
||||
prefs.put(key, value)
|
||||
}
|
||||
|
||||
override fun erase(key: String) {
|
||||
prefs.remove(key)
|
||||
}
|
||||
}
|
||||
|
||||
class StoredProperty<T>(
|
||||
private val _key: String,
|
||||
@@ -20,21 +69,15 @@ object PersistentStorage {
|
||||
)
|
||||
|
||||
fun load(): T? = runCatching {
|
||||
Keyring.create().use {
|
||||
it.getPassword(SERVICE, _key)
|
||||
}
|
||||
_backend.read(_key)
|
||||
}.getOrNull()?.let { _fromString(it) }
|
||||
|
||||
fun save(value: T) = runCatching {
|
||||
val keyring = Keyring.create().use {
|
||||
it.setPassword(SERVICE, _key, _toString(value))
|
||||
}
|
||||
_backend.write(_key, _toString(value))
|
||||
}.onFailure { println("Failed to write to OS keyring: ${it.message}") }.ignore()
|
||||
|
||||
fun erase() = runCatching {
|
||||
val keyring = Keyring.create().use {
|
||||
it.deletePassword(SERVICE, _key)
|
||||
}
|
||||
_backend.erase(_key)
|
||||
}.ignore()
|
||||
}
|
||||
|
||||
|
||||
@@ -67,15 +67,15 @@ object ProjectHandlers {
|
||||
System.err.println("Failed to get project details: ${it.msg}")
|
||||
}) {
|
||||
println("Project ${it.owner.name}/${it.name} [${it.id}]:")
|
||||
println("${it.usedLabels.size} labels:")
|
||||
it.usedLabels.forEach { l ->
|
||||
println(" - [${l.id}] ${l.name} (with color ${l.color})")
|
||||
println("${it.usedLabels.size} versions:")
|
||||
it.usedLabels.forEach { v ->
|
||||
println(" - [${v.id}] VERSION ${v.name} (with color ${v.color}); metadata: ${v.meta}")
|
||||
}
|
||||
val map = it.usedLabels.associateBy { l -> l.id }
|
||||
|
||||
println("\n${it.entries.size} entries:")
|
||||
it.entries.forEach { e ->
|
||||
println(" - [${e.id}] Entry labeled ${map[e.labelId]?.name ?: "<invalid label>"} at ${e.timestamp.fmt()} " +
|
||||
println(" - [${e.id}] ENTRY versioned ${map[e.labelId]?.name ?: "<invalid version>"} at ${e.timestamp.fmt()} " +
|
||||
"(${e.warmups.size} warmup data points, ${e.measurements.size} measurement data points; in ${e.unit.disp})")
|
||||
}
|
||||
}
|
||||
@@ -94,7 +94,7 @@ object ProjectHandlers {
|
||||
|
||||
fun newVersion(name: String?, color: String?, project: CLI.Commands.Project.IProjectIdentification?, version: String?) {
|
||||
val id = ensureProjectIdentification(project)
|
||||
val useName = name.maybePrompt("label name") { it }
|
||||
val useName = name.maybePrompt("version name") { it }
|
||||
val useColor = color.maybePrompt("color") {
|
||||
val check = it.length == 7 && it[0] == '#' && it.substring(1, it.length).all { c -> c.isDigit() || c in "ABCDEF" }
|
||||
if(check) it
|
||||
@@ -110,7 +110,7 @@ object ProjectHandlers {
|
||||
Client.callRoute(Routes.Version.new, VersionRequest(useName, useColor, useVersion, projectId))
|
||||
}
|
||||
}.fold({
|
||||
System.err.println("Could not create label: ${it.msg}")
|
||||
System.err.println("Could not create version: ${it.msg}")
|
||||
}) {
|
||||
println("Label ${it.name} (${it.color}) [${it.id}] created.")
|
||||
}
|
||||
@@ -164,7 +164,7 @@ object ProjectHandlers {
|
||||
is CLI.Commands.Project.ID -> versionId.id.value()
|
||||
is CLI.Commands.Project.VersionName -> Client.callRoute(Routes.Project.get, pId).bind {
|
||||
it.usedLabels.firstOrNull { l -> l.name == versionId.name }?.id?.value()
|
||||
?: ErrorResponse("Label ${versionId.name} does not exist in this project.").error()
|
||||
?: ErrorResponse("Version ${versionId.name} does not exist in this project.").error()
|
||||
}
|
||||
}.map { pId to it }
|
||||
}.bind { (pId, vId) ->
|
||||
|
||||
Reference in New Issue
Block a user