Mercurial > cgi-bin > hgweb.cgi > PassMan
annotate 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 |
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) { | |
52 val rawLine = System.console()?.readLine("passman> ") ?: break | |
53 val s = Shplitter() | |
54 s.feed(rawLine) | |
55 if (!s.complete) { | |
56 error("unterminated quoting") | |
57 lastStatus = 1 | |
58 continue | |
59 } | |
60 val line = s.split().toList() | |
61 if (line.isEmpty()) { | |
62 continue | |
63 } | |
64 val subcommand = line.first() | |
65 val scArgs = line.drop(1).toTypedArray() | |
66 if (subcommand in QUIT) { | |
67 break | |
68 } | |
69 if (subcommand in DISALLOWED) { | |
70 error("$subcommand subcommand not allowed in interactive mode") | |
71 lastStatus = 2 | |
72 continue | |
73 } | |
74 try { | |
75 runSubcommand(subcommand, scArgs) | |
76 lastStatus = 0 | |
77 } catch(e: SubcommandException) { | |
78 handleSubcommandException(e) | |
79 lastStatus = e.status | |
80 } catch(e: MessagedException) { | |
81 handleMessagedException(e) | |
82 lastStatus = 1 | |
83 } | |
84 } | |
85 println() // ensure shell prompt comes out on a line of its own | |
86 exitProcess(lastStatus) | |
0
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
87 } |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
88 |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
89 fun runSubcommand(name: String, args: Array<String>): Unit { |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
90 val instance = getInstanceForClass(getClassForSubcommand(name)) |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
91 if (instance == null) { |
22 | 92 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
|
93 } else { |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
94 instance.run(args) |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
95 } |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
96 } |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
97 |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
98 fun getClassForSubcommand(name: String): Class<Subcommand>? = try { |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
99 val shortName = name.replace('-', '_') |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
100 .lowercase() |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
101 .replaceFirstChar { it.titlecase(Locale.getDefault()) } |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
102 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
|
103 } catch (e: ClassNotFoundException) { |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
104 null |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
105 } |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
106 |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
107 fun getInstanceForClass(klass: Class<Subcommand>?) = try { |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
108 klass?.getDeclaredConstructor()?.newInstance() |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
109 } catch (e: ReflectiveOperationException) { |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
110 null |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
111 } |
22 | 112 |
113 fun handleMessagedException(e: MessagedException) = error(e.message) | |
114 | |
115 fun handleSubcommandException(e: SubcommandException): Unit { | |
116 if (e.message != null) { | |
117 error(e.message!!) | |
118 } | |
119 } |