From 123d4d1168101948d88f459a2a5c594bc9b74364 Mon Sep 17 00:00:00 2001 From: Geoff Bourne Date: Thu, 16 Jan 2025 08:13:58 -0600 Subject: [PATCH] cf: handle spaces around commas in exclude/include args (#509) --- .../java/me/itzg/helpers/McImageHelper.java | 182 +++++++++--------- .../me/itzg/helpers/cache/ApiCachingImpl.java | 4 +- .../curseforge/InstallCurseForgeCommand.java | 4 +- 3 files changed, 100 insertions(+), 90 deletions(-) diff --git a/src/main/java/me/itzg/helpers/McImageHelper.java b/src/main/java/me/itzg/helpers/McImageHelper.java index 59f12140..d9f2dc05 100644 --- a/src/main/java/me/itzg/helpers/McImageHelper.java +++ b/src/main/java/me/itzg/helpers/McImageHelper.java @@ -91,107 +91,117 @@ @Slf4j public class McImageHelper { - //language=RegExp - public static final String OPTION_SPLIT_COMMAS = "\\s*,\\s*"; - //language=RegExp - public static final String SPLIT_COMMA_NL = "\\n|\\s*,\\s*"; - public static final String SPLIT_SYNOPSIS_COMMA_NL = ",|"; - //language=RegExp - public static final String VERSION_REGEX = "\\d+(\\.\\d+)+"; - - @Option(names = {"-h", - "--help"}, usageHelp = true, description = "Show this usage and exit") - boolean showHelp; - - @Option(names = {"-V", "--version"}, versionHelp = true) - boolean showVersion; - - @ArgGroup - LoggingOptions loggingOptions = new LoggingOptions(); - - static class LoggingOptions { - @Option(names = "--debug", description = "Enable debug output." - + " Can also set environment variables DEBUG_HELPER or DEBUG", - defaultValue = "${env:DEBUG_HELPER:-${env:DEBUG}}") - void setDebug(boolean enabled) { - setLevel(enabled, Level.DEBUG); - } + //language=RegExp + public static final String OPTION_SPLIT_COMMAS = "\\s*,\\s*"; + //language=RegExp + public static final String SPLIT_COMMA_NL = "\\n|\\s*,\\s*"; + public static final String SPLIT_SYNOPSIS_COMMA_NL = ",|"; + /** + * Also works for newline delimited values. + */ + //language=RegExp + public static final String SPLIT_COMMA_WS = "\\s+|\\s*,\\s*"; + public static final String SPLIT_SYNOPSIS_COMMA_WS = ",|"; + //language=RegExp + public static final String VERSION_REGEX = "\\d+(\\.\\d+)+"; + + @Option(names = {"-h", + "--help"}, usageHelp = true, description = "Show this usage and exit") + boolean showHelp; + + @Option(names = {"-V", "--version"}, versionHelp = true) + boolean showVersion; + + @SuppressWarnings("unused") // processed by setters + @ArgGroup + LoggingOptions loggingOptions = new LoggingOptions(); + + static class LoggingOptions { + + @Option(names = "--debug", description = "Enable debug output." + + " Can also set environment variables DEBUG_HELPER or DEBUG", + defaultValue = "${env:DEBUG_HELPER:-${env:DEBUG}}") + void setDebug(boolean enabled) { + setLevel(enabled, Level.DEBUG); + } - @Option(names = "--logging", description = "Set logging to specific level.\nValid values: ${COMPLETION-CANDIDATES}", - defaultValue = "${env:HELPER_LOGGING_LEVEL}", - converter = LogbackLevelConverter.class - ) - void setLoggingLevel(Level level) { - setLevel(true, level); - } + @Option(names = "--logging", description = "Set logging to specific level.\nValid values: ${COMPLETION-CANDIDATES}", + defaultValue = "${env:HELPER_LOGGING_LEVEL}", + converter = LogbackLevelConverter.class + ) + void setLoggingLevel(Level level) { + setLevel(true, level); + } + + private static void setLevel(boolean enabled, Level level) { + ((Logger) LoggerFactory.getLogger("me.itzg.helpers")).setLevel( + enabled ? level : Level.INFO); + if (Level.TRACE.isGreaterOrEqual(level)) { + ((Logger) LoggerFactory.getLogger("org.apache.hc.client5.http")).setLevel( + enabled ? level : Level.INFO); + } + } - private static void setLevel(boolean enabled, Level level) { - ((Logger) LoggerFactory.getLogger("me.itzg.helpers")).setLevel( - enabled ? level : Level.INFO); - if (Level.TRACE.isGreaterOrEqual(level)) { - ((Logger) LoggerFactory.getLogger("org.apache.hc.client5.http")).setLevel( - enabled ? level : Level.INFO); - } } - } + @Option(names = {"-s", "--silent"}, description = "Don't output logs even if there's an error") + @Getter + boolean silent; - @Option(names = {"-s", "--silent"}, description = "Don't output logs even if there's an error") - @Getter - boolean silent; + @Getter + private static String version; - @Getter - private static String version; + public static void main(String[] args) { + final McImageHelper rootCommand = new McImageHelper(); + try { + version = McImageHelper.loadVersion(); + } catch (IOException e) { + log.error("Failed to load version", e); + System.exit(1); + } - public static void main(String[] args) { - final McImageHelper rootCommand = new McImageHelper(); - try { - version = McImageHelper.loadVersion(); - } catch (IOException e) { - log.error("Failed to load version", e); - System.exit(1); + System.exit( + new CommandLine(rootCommand) + .setExitCodeExceptionMapper(new ExitCodeMapper()) + .setExecutionExceptionHandler(new ExceptionHandler(rootCommand)) + .setCaseInsensitiveEnumValuesAllowed(true) + .execute(args) + ); } - System.exit( - new CommandLine(rootCommand) - .setExitCodeExceptionMapper(new ExitCodeMapper()) - .setExecutionExceptionHandler(new ExceptionHandler(rootCommand)) - .setCaseInsensitiveEnumValuesAllowed(true) - .execute(args) - ); - } - - private static String loadVersion() throws IOException { - final Enumeration resources = McImageHelper.class.getClassLoader().getResources("META-INF/MANIFEST.MF"); - while (resources.hasMoreElements()) { - final URL url = resources.nextElement(); - try (InputStream inputStream = url.openStream()) { - final Manifest manifest = new Manifest(inputStream); - final Attributes attributes = manifest.getMainAttributes(); - if ("mc-image-helper".equals(attributes.getValue(Name.IMPLEMENTATION_TITLE))) { - return attributes.getValue(Name.IMPLEMENTATION_VERSION); + private static String loadVersion() throws IOException { + final Enumeration resources = McImageHelper.class.getClassLoader().getResources("META-INF/MANIFEST.MF"); + while (resources.hasMoreElements()) { + final URL url = resources.nextElement(); + try (InputStream inputStream = url.openStream()) { + final Manifest manifest = new Manifest(inputStream); + final Attributes attributes = manifest.getMainAttributes(); + if ("mc-image-helper".equals(attributes.getValue(Name.IMPLEMENTATION_TITLE))) { + return attributes.getValue(Name.IMPLEMENTATION_VERSION); + } + } } - } + return "???"; } - return "???"; - } - public static class AppVersionProvider implements IVersionProvider { - @Override - public String[] getVersion() { + public static class AppVersionProvider implements IVersionProvider { + + @Override + public String[] getVersion() { - return new String[]{ - "${COMMAND-FULL-NAME}", - version - }; + return new String[]{ + "${COMMAND-FULL-NAME}", + version + }; + } } - } - private static class LogbackLevelConverter implements ITypeConverter { - @Override - public Level convert(String value) { - return Level.toLevel(value); + private static class LogbackLevelConverter implements ITypeConverter { + + @Override + public Level convert(String value) { + return Level.toLevel(value); + } } - } } diff --git a/src/main/java/me/itzg/helpers/cache/ApiCachingImpl.java b/src/main/java/me/itzg/helpers/cache/ApiCachingImpl.java index ae991111..e046ff61 100644 --- a/src/main/java/me/itzg/helpers/cache/ApiCachingImpl.java +++ b/src/main/java/me/itzg/helpers/cache/ApiCachingImpl.java @@ -62,7 +62,7 @@ private void pruneExpiredEntries() { if (entry.getExpiresAt().isBefore(now)) { final Path contentFile = resolveContentFile(operation, entry.getFilename()); try { - log.debug("Pruning cached content file {}", contentFile); + log.trace("Pruning cached content file {}", contentFile); Files.delete(contentFile); } catch (IOException e) { log.warn("Failed to delete cached content file {}", contentFile, e); @@ -162,7 +162,7 @@ private Mono saveToCache(String operation, String keys, R value) { ); } - log.debug("Saved cache content of {}({}) to {}", operation, keys, contentFile); + log.trace("Saved cache content of {}({}) to {}", operation, keys, contentFile); } catch (IOException e) { log.warn("Failed to cache file for operation={} keys={}", operation, keys, e); } diff --git a/src/main/java/me/itzg/helpers/curseforge/InstallCurseForgeCommand.java b/src/main/java/me/itzg/helpers/curseforge/InstallCurseForgeCommand.java index 4c481ff1..75eba706 100644 --- a/src/main/java/me/itzg/helpers/curseforge/InstallCurseForgeCommand.java +++ b/src/main/java/me/itzg/helpers/curseforge/InstallCurseForgeCommand.java @@ -102,13 +102,13 @@ static class ExcludeIncludeArgs { static class Listed { @Option(names = "--exclude-mods", paramLabel = "PROJECT_ID|SLUG", - split = "\\s+|,", splitSynopsisLabel = ",|", + split = McImageHelper.SPLIT_COMMA_WS, splitSynopsisLabel = McImageHelper.SPLIT_SYNOPSIS_COMMA_WS, description = "For mods that need to be excluded from server deployments, such as those that don't label as client" ) Set excludedMods; @Option(names = "--force-include-mods", paramLabel = "PROJECT_ID|SLUG", - split = "\\s+|,", splitSynopsisLabel = ",|", + split = McImageHelper.SPLIT_COMMA_WS, splitSynopsisLabel = McImageHelper.SPLIT_SYNOPSIS_COMMA_WS, description = "Some mods incorrectly declare client-only support, but still need to be included in a server deploy." + "%nThis can also be used to selectively override exclusions." )