Mercurial > cgi-bin > hgweb.cgi > PassMan
annotate src/main/kotlin/name/blackcap/passman/Main.kt @ 23:af86b8e0b88c
Clean up exit output.
author | David Barts <n5jrn@me.com> |
---|---|
date | Tue, 02 Jul 2024 18:18:29 -0700 |
parents | 07406c4af4a5 |
children | 2188b2f13326 |
rev | line source |
---|---|
0
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
1 package name.blackcap.passman |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
2 |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
3 import java.io.BufferedReader |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
4 import java.io.InputStreamReader |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
5 import java.util.* |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
6 import java.util.stream.Collectors |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
7 import kotlin.reflect.jvm.javaMethod |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
8 import kotlin.reflect.jvm.kotlinFunction |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
9 import kotlin.system.exitProcess |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
10 |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
11 fun main(args: Array<String>) { |
22 | 12 val NOPASSWORD = setOf<String>("help") |
0
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
13 if (args.isEmpty()) { |
22 | 14 openDatabase() |
15 runInteractive() | |
16 } | |
17 val subcommand = args[0] | |
18 val scArgs = args.sliceArray(1 until args.size) | |
19 if (subcommand !in NOPASSWORD) { | |
20 openDatabase() | |
21 } | |
22 runNonInteractive(subcommand, scArgs) | |
23 } | |
24 | |
25 fun openDatabase() { | |
26 try { | |
27 Database.default = Database.open() | |
28 } catch (e: DatabaseException) { | |
29 handleMessagedException(e) | |
0
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
30 exitProcess(2) |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
31 } |
22 | 32 } |
33 | |
34 fun runNonInteractive(subcommand: String, scArgs: Array<String>): Unit { | |
35 try { | |
36 runSubcommand(subcommand, scArgs) | |
37 } catch (e: SubcommandException) { | |
38 handleSubcommandException(e) | |
39 exitProcess(e.status) | |
40 } catch (e: MessagedException) { | |
41 handleMessagedException(e) | |
42 exitProcess(1) | |
43 } | |
44 exitProcess(0) | |
45 } | |
46 | |
47 fun runInteractive() { | |
48 val DISALLOWED = setOf<String>("password") | |
49 val QUIT = setOf<String>("exit", "quit") | |
50 var lastStatus = 0 | |
51 while (true) { | |
23 | 52 val rawLine = System.console()?.readLine("passman> ") |
53 if (rawLine == null) { | |
54 println() // ensure shell prompt comes out on a line of its own | |
55 break | |
56 } | |
22 | 57 val s = Shplitter() |
58 s.feed(rawLine) | |
59 if (!s.complete) { | |
60 error("unterminated quoting") | |
61 lastStatus = 1 | |
62 continue | |
63 } | |
64 val line = s.split().toList() | |
65 if (line.isEmpty()) { | |
66 continue | |
67 } | |
68 val subcommand = line.first() | |
69 val scArgs = line.drop(1).toTypedArray() | |
70 if (subcommand in QUIT) { | |
71 break | |
72 } | |
73 if (subcommand in DISALLOWED) { | |
74 error("$subcommand subcommand not allowed in interactive mode") | |
75 lastStatus = 2 | |
76 continue | |
77 } | |
78 try { | |
79 runSubcommand(subcommand, scArgs) | |
80 lastStatus = 0 | |
81 } catch(e: SubcommandException) { | |
82 handleSubcommandException(e) | |
83 lastStatus = e.status | |
84 } catch(e: MessagedException) { | |
85 handleMessagedException(e) | |
86 lastStatus = 1 | |
87 } | |
88 } | |
89 exitProcess(lastStatus) | |
0
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
90 } |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
91 |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
92 fun runSubcommand(name: String, args: Array<String>): Unit { |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
93 val instance = getInstanceForClass(getClassForSubcommand(name)) |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
94 if (instance == null) { |
22 | 95 throw SubcommandException(message = "${see(name)} - unknown subcommand", status = 2) |
0
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
96 } else { |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
97 instance.run(args) |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
98 } |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
99 } |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
100 |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
101 fun getClassForSubcommand(name: String): Class<Subcommand>? = try { |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
102 val shortName = name.replace('-', '_') |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
103 .lowercase() |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
104 .replaceFirstChar { it.titlecase(Locale.getDefault()) } |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
105 Class.forName("$MAIN_PACKAGE.${shortName}Subcommand") as? Class<Subcommand> |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
106 } catch (e: ClassNotFoundException) { |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
107 null |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
108 } |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
109 |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
110 fun getInstanceForClass(klass: Class<Subcommand>?) = try { |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
111 klass?.getDeclaredConstructor()?.newInstance() |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
112 } catch (e: ReflectiveOperationException) { |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
113 null |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
114 } |
22 | 115 |
116 fun handleMessagedException(e: MessagedException) = error(e.message) | |
117 | |
118 fun handleSubcommandException(e: SubcommandException): Unit { | |
119 if (e.message != null) { | |
120 error(e.message!!) | |
121 } | |
122 } |