diff --git a/src/main/java/picocli/CommandLine.java b/src/main/java/picocli/CommandLine.java index ab95179f1..f52dbe89f 100644 --- a/src/main/java/picocli/CommandLine.java +++ b/src/main/java/picocli/CommandLine.java @@ -7745,6 +7745,11 @@ public static class UsageMessageSpec { public final static int DEFAULT_USAGE_WIDTH = 80; private final static int MINIMUM_USAGE_WIDTH = 55; final static int DEFAULT_USAGE_LONG_OPTIONS_WIDTH = 20; + // remembers the last invalid picocli.usage.width value warned about, so the warning is logged only once per value + private static String lastWarnedInvalidWidthValue; + + // resets the cached invalid picocli.usage.width value; intended for testing + static void resetUsageWidthWarningCache() { lastWarnedInvalidWidthValue = null; } private final static int DEFAULT_SYNOPSIS_INDENT = -1; // by default, fall back to aligning to the synopsis heading private final static double DEFAULT_SYNOPSIS_AUTO_INDENT_THRESHOLD = 0.5; private final static double MAX_SYNOPSIS_AUTO_INDENT_THRESHOLD = 0.9; @@ -7893,12 +7898,18 @@ private int getSysPropertyWidthOrDefault(int defaultWidth, boolean detectTermina try { int width = Integer.parseInt(userValue); if (width < MINIMUM_USAGE_WIDTH) { - CommandLine.tracer().warn("Invalid picocli.usage.width value %d. Using minimum usage width %d.", width, MINIMUM_USAGE_WIDTH); + if (!userValue.equals(lastWarnedInvalidWidthValue)) { + lastWarnedInvalidWidthValue = userValue; + CommandLine.tracer().warn("Invalid picocli.usage.width value %d. Using minimum usage width %d.", width, MINIMUM_USAGE_WIDTH); + } return MINIMUM_USAGE_WIDTH; } return width; } catch (NumberFormatException ex) { - CommandLine.tracer().warn("Invalid picocli.usage.width value '%s'. Using usage width %d.", userValue, defaultWidth); + if (!userValue.equals(lastWarnedInvalidWidthValue)) { + lastWarnedInvalidWidthValue = userValue; + CommandLine.tracer().warn("Invalid picocli.usage.width value '%s'. Using usage width %d.", userValue, defaultWidth); + } return defaultWidth; } } diff --git a/src/test/java/picocli/HelpTest.java b/src/test/java/picocli/HelpTest.java index f8f9357ab..6b9f6ee6f 100644 --- a/src/test/java/picocli/HelpTest.java +++ b/src/test/java/picocli/HelpTest.java @@ -3546,6 +3546,43 @@ public void testTooSmallUsageWidthPropertyValue() throws UnsupportedEncodingExce assertEquals(format("[picocli WARN] Invalid picocli.usage.width value 54. Using minimum usage width 55.%n"), baos.toString("UTF-8")); } + @Test + public void testInvalidUsageWidthPropertyValueWarnsOnlyOnce() throws UnsupportedEncodingException { + PrintStream originalErr = System.err; + ByteArrayOutputStream baos = new ByteArrayOutputStream(2500); + System.setErr(new PrintStream(baos)); + + System.clearProperty("picocli.trace"); + UsageMessageSpec.resetUsageWidthWarningCache(); + System.setProperty("picocli.usage.width", "bogus"); + new UsageMessageSpec().width(); + new UsageMessageSpec().width(); + new UsageMessageSpec().width(); + System.setErr(originalErr); + System.clearProperty("picocli.usage.width"); + + assertEquals(format("[picocli WARN] Invalid picocli.usage.width value 'bogus'. Using usage width 80.%n"), baos.toString("UTF-8")); + } + + @Test + public void testInvalidUsageWidthPropertyValueWarnsAgainForDifferentValue() throws UnsupportedEncodingException { + PrintStream originalErr = System.err; + ByteArrayOutputStream baos = new ByteArrayOutputStream(2500); + System.setErr(new PrintStream(baos)); + + System.clearProperty("picocli.trace"); + UsageMessageSpec.resetUsageWidthWarningCache(); + System.setProperty("picocli.usage.width", "first"); + new UsageMessageSpec().width(); + System.setProperty("picocli.usage.width", "second"); + new UsageMessageSpec().width(); + System.setErr(originalErr); + System.clearProperty("picocli.usage.width"); + + assertEquals(format("[picocli WARN] Invalid picocli.usage.width value 'first'. Using usage width 80.%n" + + "[picocli WARN] Invalid picocli.usage.width value 'second'. Using usage width 80.%n"), baos.toString("UTF-8")); + } + @SuppressWarnings("deprecation") @Test public void testTextTableWithLargeWidth() {