mirror of
https://codeberg.org/PGPainless/sop-java.git
synced 2024-12-22 04:57:56 +01:00
Kotlin conversion: SopCLI
This commit is contained in:
parent
0c2cf5cb19
commit
baa44a6b1a
4 changed files with 114 additions and 138 deletions
|
@ -1,129 +0,0 @@
|
|||
// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package sop.cli.picocli;
|
||||
|
||||
import picocli.AutoComplete;
|
||||
import picocli.CommandLine;
|
||||
import sop.SOP;
|
||||
import sop.cli.picocli.commands.ArmorCmd;
|
||||
import sop.cli.picocli.commands.ChangeKeyPasswordCmd;
|
||||
import sop.cli.picocli.commands.DearmorCmd;
|
||||
import sop.cli.picocli.commands.DecryptCmd;
|
||||
import sop.cli.picocli.commands.InlineDetachCmd;
|
||||
import sop.cli.picocli.commands.EncryptCmd;
|
||||
import sop.cli.picocli.commands.ExtractCertCmd;
|
||||
import sop.cli.picocli.commands.GenerateKeyCmd;
|
||||
import sop.cli.picocli.commands.InlineSignCmd;
|
||||
import sop.cli.picocli.commands.InlineVerifyCmd;
|
||||
import sop.cli.picocli.commands.ListProfilesCmd;
|
||||
import sop.cli.picocli.commands.RevokeKeyCmd;
|
||||
import sop.cli.picocli.commands.SignCmd;
|
||||
import sop.cli.picocli.commands.VerifyCmd;
|
||||
import sop.cli.picocli.commands.VersionCmd;
|
||||
import sop.exception.SOPGPException;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
@CommandLine.Command(
|
||||
name = "sop",
|
||||
resourceBundle = "msg_sop",
|
||||
exitCodeOnInvalidInput = SOPGPException.UnsupportedSubcommand.EXIT_CODE,
|
||||
subcommands = {
|
||||
// Meta Subcommands
|
||||
VersionCmd.class,
|
||||
ListProfilesCmd.class,
|
||||
// Key and Certificate Management Subcommands
|
||||
GenerateKeyCmd.class,
|
||||
ChangeKeyPasswordCmd.class,
|
||||
RevokeKeyCmd.class,
|
||||
ExtractCertCmd.class,
|
||||
// Messaging Subcommands
|
||||
SignCmd.class,
|
||||
VerifyCmd.class,
|
||||
EncryptCmd.class,
|
||||
DecryptCmd.class,
|
||||
InlineDetachCmd.class,
|
||||
InlineSignCmd.class,
|
||||
InlineVerifyCmd.class,
|
||||
// Transport Subcommands
|
||||
ArmorCmd.class,
|
||||
DearmorCmd.class,
|
||||
// Miscellaneous Subcommands
|
||||
CommandLine.HelpCommand.class,
|
||||
AutoComplete.GenerateCompletion.class
|
||||
}
|
||||
)
|
||||
public class SopCLI {
|
||||
// Singleton
|
||||
static SOP SOP_INSTANCE;
|
||||
static ResourceBundle cliMsg = ResourceBundle.getBundle("msg_sop");
|
||||
|
||||
public static String EXECUTABLE_NAME = "sop";
|
||||
|
||||
@CommandLine.Option(names = {"--stacktrace"},
|
||||
scope = CommandLine.ScopeType.INHERIT)
|
||||
static boolean stacktrace;
|
||||
|
||||
public static void main(String[] args) {
|
||||
int exitCode = execute(args);
|
||||
if (exitCode != 0) {
|
||||
System.exit(exitCode);
|
||||
}
|
||||
}
|
||||
|
||||
public static int execute(String[] args) {
|
||||
|
||||
// Set locale
|
||||
new CommandLine(new InitLocale()).parseArgs(args);
|
||||
|
||||
// get error message bundle
|
||||
cliMsg = ResourceBundle.getBundle("msg_sop");
|
||||
|
||||
// Prepare CLI
|
||||
CommandLine cmd = new CommandLine(SopCLI.class);
|
||||
|
||||
// explicitly set help command resource bundle
|
||||
cmd.getSubcommands().get("help").setResourceBundle(ResourceBundle.getBundle("msg_help"));
|
||||
|
||||
// Hide generate-completion command
|
||||
cmd.getSubcommands().get("generate-completion").getCommandSpec().usageMessage().hidden(true);
|
||||
|
||||
cmd.setCommandName(EXECUTABLE_NAME)
|
||||
.setExecutionExceptionHandler(new SOPExecutionExceptionHandler())
|
||||
.setExitCodeExceptionMapper(new SOPExceptionExitCodeMapper())
|
||||
.setCaseInsensitiveEnumValuesAllowed(true);
|
||||
|
||||
return cmd.execute(args);
|
||||
}
|
||||
|
||||
public static SOP getSop() {
|
||||
if (SOP_INSTANCE == null) {
|
||||
String errorMsg = cliMsg.getString("sop.error.runtime.no_backend_set");
|
||||
throw new IllegalStateException(errorMsg);
|
||||
}
|
||||
return SOP_INSTANCE;
|
||||
}
|
||||
|
||||
public static void setSopInstance(SOP instance) {
|
||||
SOP_INSTANCE = instance;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Control the locale.
|
||||
*
|
||||
* @see <a href="https://picocli.info/#_controlling_the_locale">Picocli Readme</a>
|
||||
*/
|
||||
class InitLocale {
|
||||
@CommandLine.Option(names = { "-l", "--locale" }, descriptionKey = "sop.locale")
|
||||
void setLocale(String locale) {
|
||||
Locale.setDefault(new Locale(locale));
|
||||
}
|
||||
|
||||
@CommandLine.Unmatched
|
||||
List<String> remainder; // ignore any other parameters and options in the first parsing phase
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
/**
|
||||
* Implementation of the Stateless OpenPGP Command Line Interface using Picocli.
|
||||
*/
|
||||
package sop.cli.picocli;
|
113
sop-java-picocli/src/main/kotlin/sop/cli/picocli/SopCLI.kt
Normal file
113
sop-java-picocli/src/main/kotlin/sop/cli/picocli/SopCLI.kt
Normal file
|
@ -0,0 +1,113 @@
|
|||
// SPDX-FileCopyrightText: 2023 Paul Schaub <vanitasvitae@fsfe.org>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package sop.cli.picocli
|
||||
|
||||
import java.util.*
|
||||
import kotlin.system.exitProcess
|
||||
import picocli.AutoComplete.GenerateCompletion
|
||||
import picocli.CommandLine
|
||||
import picocli.CommandLine.*
|
||||
import sop.SOP
|
||||
import sop.cli.picocli.commands.*
|
||||
import sop.exception.SOPGPException
|
||||
|
||||
@Command(
|
||||
name = "sop",
|
||||
resourceBundle = "msg_sop",
|
||||
exitCodeOnInvalidInput = SOPGPException.UnsupportedSubcommand.EXIT_CODE,
|
||||
subcommands =
|
||||
[
|
||||
// Meta subcommands
|
||||
VersionCmd::class,
|
||||
ListProfilesCmd::class,
|
||||
// Key and certificate management
|
||||
GenerateKeyCmd::class,
|
||||
ChangeKeyPasswordCmd::class,
|
||||
RevokeKeyCmd::class,
|
||||
ExtractCertCmd::class,
|
||||
// Messaging subcommands
|
||||
SignCmd::class,
|
||||
VerifyCmd::class,
|
||||
EncryptCmd::class,
|
||||
DecryptCmd::class,
|
||||
InlineDetachCmd::class,
|
||||
InlineSignCmd::class,
|
||||
InlineVerifyCmd::class,
|
||||
// Transport
|
||||
ArmorCmd::class,
|
||||
DearmorCmd::class,
|
||||
// misc
|
||||
HelpCommand::class,
|
||||
GenerateCompletion::class])
|
||||
class SopCLI {
|
||||
|
||||
companion object {
|
||||
@JvmStatic private var sopInstance: SOP? = null
|
||||
|
||||
@JvmStatic
|
||||
fun getSop(): SOP =
|
||||
checkNotNull(sopInstance) { cliMsg.getString("sop.error.runtime.no_backend_set") }
|
||||
|
||||
@JvmStatic
|
||||
fun setSopInstance(sop: SOP?) {
|
||||
sopInstance = sop
|
||||
}
|
||||
|
||||
@JvmField var cliMsg: ResourceBundle = ResourceBundle.getBundle("msg_sop")
|
||||
|
||||
@JvmField var EXECUTABLE_NAME = "sop"
|
||||
|
||||
@JvmField
|
||||
@Option(names = ["--stacktrace"], scope = CommandLine.ScopeType.INHERIT)
|
||||
var stacktrace = false
|
||||
|
||||
@JvmStatic
|
||||
fun main(vararg args: String) {
|
||||
val exitCode = execute(*args)
|
||||
if (exitCode != 0) {
|
||||
exitProcess(exitCode)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun execute(vararg args: String): Int {
|
||||
// Set locale
|
||||
CommandLine(InitLocale()).parseArgs(*args)
|
||||
|
||||
// Re-set bundle with updated locale
|
||||
cliMsg = ResourceBundle.getBundle("msg_sop")
|
||||
|
||||
return CommandLine(SopCLI::class.java)
|
||||
.apply {
|
||||
// explicitly set help command resource bundle
|
||||
subcommands["help"]?.setResourceBundle(ResourceBundle.getBundle("msg_help"))
|
||||
// Hide generate-completion command
|
||||
subcommands["generate-completion"]?.commandSpec?.usageMessage()?.hidden(true)
|
||||
// overwrite executable name
|
||||
commandName = EXECUTABLE_NAME
|
||||
// setup exception handling
|
||||
executionExceptionHandler = SOPExecutionExceptionHandler()
|
||||
exitCodeExceptionMapper = SOPExceptionExitCodeMapper()
|
||||
isCaseInsensitiveEnumValuesAllowed = true
|
||||
}
|
||||
.execute(*args)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Control the locale.
|
||||
*
|
||||
* @see <a href="https://picocli.info/#_controlling_the_locale">Picocli Readme</a>
|
||||
*/
|
||||
@Command
|
||||
class InitLocale {
|
||||
@Option(names = ["-l", "--locale"], descriptionKey = "sop.locale")
|
||||
fun setLocale(locale: String) = Locale.setDefault(Locale(locale))
|
||||
|
||||
@Unmatched
|
||||
var remainder: MutableList<String> =
|
||||
mutableListOf() // ignore any other parameters and options in the first parsing phase
|
||||
}
|
||||
}
|
|
@ -45,7 +45,7 @@ public class SOPTest {
|
|||
@Test
|
||||
@ExpectSystemExitWithStatus(1)
|
||||
public void assertThrowsIfNoSOPBackendSet() {
|
||||
SopCLI.SOP_INSTANCE = null;
|
||||
SopCLI.setSopInstance(null);
|
||||
// At this point, no SOP backend is set, so an InvalidStateException triggers exit(1)
|
||||
SopCLI.main(new String[] {"armor"});
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue