Mercurial > cgi-bin > hgweb.cgi > PassMan
diff src/main/kotlin/name/blackcap/passman/Main.kt @ 22:07406c4af4a5
More interactive mode stuff.
author | David Barts <n5jrn@me.com> |
---|---|
date | Tue, 02 Jul 2024 17:34:52 -0700 |
parents | ea65ab890f66 |
children | af86b8e0b88c |
line wrap: on
line diff
--- a/src/main/kotlin/name/blackcap/passman/Main.kt Tue Jul 02 11:27:39 2024 -0700 +++ b/src/main/kotlin/name/blackcap/passman/Main.kt Tue Jul 02 17:34:52 2024 -0700 @@ -9,20 +9,87 @@ import kotlin.system.exitProcess fun main(args: Array<String>) { + val NOPASSWORD = setOf<String>("help") if (args.isEmpty()) { - error("expecting subcommand") + openDatabase() + runInteractive() + } + val subcommand = args[0] + val scArgs = args.sliceArray(1 until args.size) + if (subcommand !in NOPASSWORD) { + openDatabase() + } + runNonInteractive(subcommand, scArgs) +} + +fun openDatabase() { + try { + Database.default = Database.open() + } catch (e: DatabaseException) { + handleMessagedException(e) exitProcess(2) } - val subcommand = args[0]; - val scArgs = args.sliceArray(1 until args.size) - Database.default = Database.open() - runSubcommand(subcommand, scArgs) +} + +fun runNonInteractive(subcommand: String, scArgs: Array<String>): Unit { + try { + runSubcommand(subcommand, scArgs) + } catch (e: SubcommandException) { + handleSubcommandException(e) + exitProcess(e.status) + } catch (e: MessagedException) { + handleMessagedException(e) + exitProcess(1) + } + exitProcess(0) +} + +fun runInteractive() { + val DISALLOWED = setOf<String>("password") + val QUIT = setOf<String>("exit", "quit") + var lastStatus = 0 + while (true) { + val rawLine = System.console()?.readLine("passman> ") ?: break + val s = Shplitter() + s.feed(rawLine) + if (!s.complete) { + error("unterminated quoting") + lastStatus = 1 + continue + } + val line = s.split().toList() + if (line.isEmpty()) { + continue + } + val subcommand = line.first() + val scArgs = line.drop(1).toTypedArray() + if (subcommand in QUIT) { + break + } + if (subcommand in DISALLOWED) { + error("$subcommand subcommand not allowed in interactive mode") + lastStatus = 2 + continue + } + try { + runSubcommand(subcommand, scArgs) + lastStatus = 0 + } catch(e: SubcommandException) { + handleSubcommandException(e) + lastStatus = e.status + } catch(e: MessagedException) { + handleMessagedException(e) + lastStatus = 1 + } + } + println() // ensure shell prompt comes out on a line of its own + exitProcess(lastStatus) } fun runSubcommand(name: String, args: Array<String>): Unit { val instance = getInstanceForClass(getClassForSubcommand(name)) if (instance == null) { - die("${see(name)} - unknown subcommand", 2) + throw SubcommandException(message = "${see(name)} - unknown subcommand", status = 2) } else { instance.run(args) } @@ -42,3 +109,11 @@ } catch (e: ReflectiveOperationException) { null } + +fun handleMessagedException(e: MessagedException) = error(e.message) + +fun handleSubcommandException(e: SubcommandException): Unit { + if (e.message != null) { + error(e.message!!) + } +}