Skip to content

Commit 228c4d0

Browse files
committed
MLE-24984 Friendly error message when using removed short options
1 parent 3c57672 commit 228c4d0

File tree

3 files changed

+66
-2
lines changed

3 files changed

+66
-2
lines changed

.copyrightconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@ startyear: 2024
1111
# - Dotfiles already skipped automatically
1212
# Enable by removing the leading '# ' from the next line and editing values.
1313
# filesexcluded: third_party/*, docs/generated/*.md, assets/*.png, scripts/temp_*.py, vendor/lib.js
14-
filesexcluded: .github/*, README.md, CONTRIBUTING.md, Jenkinsfile, gradle/*, docker-compose.yml, *.gradle, gradle.properties, gradlew, gradlew.bat, *.json, *.xml, *.txt, **/test/resources/**, docs/**, flux-cli/hadoop/*, CODEOWNERS
14+
filesexcluded: .github/*, README.md, CONTRIBUTING.md, Jenkinsfile, gradle/*, docker-compose.yml, *.gradle, gradlew, gradlew.bat, *.json, *.xml, *.txt, **/test/resources/**, docs/**, flux-cli/hadoop/*, CODEOWNERS, *.properties

flux-cli/src/main/java/com/marklogic/flux/cli/ShortErrorMessageHandler.java

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import picocli.CommandLine;
77

88
import java.io.PrintWriter;
9+
import java.util.Map;
910
import java.util.Objects;
1011

1112
/**
@@ -14,6 +15,16 @@
1415
*/
1516
class ShortErrorMessageHandler implements CommandLine.IParameterExceptionHandler {
1617

18+
private static final Map<String, String> SHORT_OPTIONS_REPLACED_IN_TWO_DOT_ZERO_RELEASE = Map.of(
19+
"-P", "--spark-prop",
20+
"-R", "--doc-prop",
21+
"-M", "--doc-metadata",
22+
"-S", "--splitter-prop",
23+
"-X", "--xpath-namespace",
24+
"-L", "--classifier-prop",
25+
"-E", "--embedder-prop"
26+
);
27+
1728
public int handleParseException(CommandLine.ParameterException ex, String[] args) {
1829
final CommandLine commandLine = ex.getCommandLine();
1930
Objects.requireNonNull(commandLine);
@@ -29,7 +40,8 @@ public int handleParseException(CommandLine.ParameterException ex, String[] args
2940

3041
final String exceptionMessage = getErrorMessageToPrint(ex);
3142
if (exceptionMessage != null) {
32-
err.println(colorScheme.errorText(exceptionMessage)); // bold red
43+
err.println(colorScheme.errorText(exceptionMessage));
44+
printHelpfulMessageForReplacedSingleLetterOption(exceptionMessage, err, colorScheme);
3345
}
3446

3547
CommandLine.UnmatchedArgumentException.printSuggestions(ex, err);
@@ -55,4 +67,24 @@ private String getErrorMessageToPrint(Exception ex) {
5567
}
5668
return message;
5769
}
70+
71+
private void printHelpfulMessageForReplacedSingleLetterOption(String exceptionMessage, PrintWriter err, CommandLine.Help.ColorScheme colorScheme) {
72+
SHORT_OPTIONS_REPLACED_IN_TWO_DOT_ZERO_RELEASE.keySet().forEach(shortOption -> {
73+
final String indicatorOfReplacedShortOption = "Unknown option: '" + shortOption;
74+
if (exceptionMessage.startsWith(indicatorOfReplacedShortOption)) {
75+
String longOption = SHORT_OPTIONS_REPLACED_IN_TWO_DOT_ZERO_RELEASE.get(shortOption);
76+
err.println("");
77+
err.println(colorScheme.errorText("Did you mean to use %s instead of %s, as %s was replaced in the 2.0 release with %s?"
78+
.formatted(longOption, shortOption, shortOption, longOption)));
79+
80+
String optionValue = exceptionMessage.substring(indicatorOfReplacedShortOption.length());
81+
if (optionValue.endsWith("'")) {
82+
optionValue = optionValue.substring(0, optionValue.length() - 1);
83+
}
84+
85+
err.println(colorScheme.errorText("If so, use %s %s instead.".formatted(longOption, optionValue)));
86+
err.println("");
87+
}
88+
});
89+
}
5890
}

flux-cli/src/test/java/com/marklogic/flux/impl/HandleErrorTest.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@
55

66
import com.marklogic.flux.AbstractTest;
77
import org.junit.jupiter.api.Test;
8+
import org.junit.jupiter.params.ParameterizedTest;
9+
import org.junit.jupiter.params.provider.CsvSource;
810
import picocli.CommandLine;
911

1012
import static org.junit.jupiter.api.Assertions.assertFalse;
13+
import static org.junit.jupiter.api.Assertions.assertTrue;
1114

1215
/**
1316
* Note that some tests will print a "An illegal reflective access operation has occurred" warning that occurs
@@ -142,4 +145,33 @@ void dontAbortOnWriteFailure() {
142145
assertFalse(stderr.contains("Command failed"), "The command should not have failed since it defaults to not " +
143146
"aborting on a write failure. Actual stderr: " + stderr);
144147
}
148+
149+
@ParameterizedTest
150+
@CsvSource({
151+
"-P,--spark-prop",
152+
"-E,--embedder-prop",
153+
"-L,--classifier-prop",
154+
"-S,--splitter-prop",
155+
"-R,--doc-prop",
156+
"-M,--doc-metadata",
157+
"-X,--xpath-namespace",
158+
})
159+
void niceErrorMessageForShortOptionsRemovedInTwoDotZeroRelease(String shortOption, String longOption) {
160+
// Verifying we get a helpful error message for each short option removed in the 2.0 release. The command here
161+
// is not important.
162+
String stderr = runAndReturnStderr(
163+
CommandLine.ExitCode.USAGE,
164+
"import-orc-files",
165+
"--path", "src/test/resources/orc-files/authors.orc",
166+
"--connection-string", makeConnectionString(),
167+
"--permissions", DEFAULT_PERMISSIONS,
168+
"%stheKey=theValue".formatted(shortOption)
169+
);
170+
171+
assertTrue(stderr.contains("Did you mean to use %s instead of %s, as %s was replaced in the 2.0 release with %s?"
172+
.formatted(longOption, shortOption, shortOption, longOption)), "Unexpected stderr: " + stderr);
173+
174+
assertTrue(stderr.contains("If so, use %s theKey=theValue instead.".formatted(longOption)),
175+
"Unexpected stderr: " + stderr);
176+
}
145177
}

0 commit comments

Comments
 (0)