Skip to content

HDDS-7957. Deprecate multi-char short options#10494

Merged
adoroszlai merged 7 commits into
apache:masterfrom
hani-fouladgar:HDDS-7957
Jun 14, 2026
Merged

HDDS-7957. Deprecate multi-char short options#10494
adoroszlai merged 7 commits into
apache:masterfrom
hani-fouladgar:HDDS-7957

Conversation

@hani-fouladgar

Copy link
Copy Markdown
Contributor

What changes were proposed in this pull request?

This PR deprecates multi-character short CLI options across Ozone PicoCLI tools, following the same pattern already used for -id and -host in OmAddressOptions. Long option names are now primary; old multi-char shorts remain supported but hidden from help. When a deprecated option is used, a warning is printed to stderr.

Deprecate multi-char short options

Multi-char short flags are split from their long equivalents. Long names are shown in help; deprecated shorts are @deprecated, hidden = true, and merged via getters or ArgGroup for backward compatibility.

Deprecation warnings

  • Added DeprecatedCliOption in hadoop-hdds/cli-common to detect deprecated options after parsing and print: WARNING: Option '-ffc' is deprecated. Use '--filter-by-factor' instead.

What is the link to the Apache JIRA

https://issues.apache.org/jira/browse/HDDS-7957

How was this patch tested?

Unit tests added

@adoroszlai adoroszlai changed the title Deprecate multi-char short options HDDS-7957. Deprecate multi-char short options Jun 11, 2026
@adoroszlai

Copy link
Copy Markdown
Contributor

Thanks @hani-fouladgar for the patch. Please enable workflows in your fork (but feel free to disable scheduled workflows).

@adoroszlai adoroszlai left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @hani-fouladgar for the patch.

Comment on lines +36 to +42
StringWriter err = new StringWriter();
CommandLine cli = new CommandLine(cmd);
cli.setErr(new PrintWriter(err, true));
cli.setExecutionStrategy(parseResult -> {
DeprecatedCliOption.warnIfMatched(parseResult);
return CommandLine.ExitCode.OK;
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please extract this to a helper function CommandLine createCommandLine(Object command) to reduce duplication. err will need to be changed to a member variable initialized in @BeforeEach.

This also makes it easier to add few more test cases for other commands.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

Comment on lines +60 to +63
PrintWriter err = parseResult.commandSpec().commandLine().getErr();
for (Map.Entry<String, String> entry : DEPRECATED_OPTIONS.entrySet()) {
if (parseResult.hasMatchedOption(entry.getKey())) {
warn(err, entry.getKey(), entry.getValue());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately this does not print warnings for subcommands, because parseResult.matchedOptions only contains options of the top-level command.

Example: warning for -conf, but no warning for -ffc.

$ ozone admin -conf etc/hadoop/ozone-site.xml pipeline list -ffc THREE
WARNING: Option '-conf' is deprecated. Use '--conf' instead.

The unit test works because the subcommand is used without parents.

Suggested change
PrintWriter err = parseResult.commandSpec().commandLine().getErr();
for (Map.Entry<String, String> entry : DEPRECATED_OPTIONS.entrySet()) {
if (parseResult.hasMatchedOption(entry.getKey())) {
warn(err, entry.getKey(), entry.getValue());
for (CommandLine cli : parseResult.asCommandLineList()) {
CommandLine.ParseResult subcommandResult = cli.getParseResult();
if (subcommandResult.matchedOptions().isEmpty()) {
continue;
}
for (Map.Entry<String, String> entry : DEPRECATED_OPTIONS.entrySet()) {
if (subcommandResult.hasMatchedOption(entry.getKey())) {
warn(cli.getErr(), entry.getKey(), entry.getValue());
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

private static Map<String, String> buildDeprecatedOptions() {
Map<String, String> options = new LinkedHashMap<>();
options.put("-conf", "--conf");
options.put("-id", "--service-id or --om-service-id");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's suggest only one replacement, double option in '' seems odd. Same for -al.

WARNING: Option '-al' is deprecated. Use '--acls or --acl' instead.

Comment on lines +66 to +78
if (!Strings.isNullOrEmpty(state)) {
if (!Strings.isNullOrEmpty(getState())) {
stream = stream.filter(p -> p.getPipelineState().toString()
.compareToIgnoreCase(state) == 0);
.compareToIgnoreCase(getState()) == 0);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: please store in local variable effectiveState like in some other classes

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

Comment on lines +209 to +211
return deprecatedTxnApplyWaitTimeSeconds != null
? deprecatedTxnApplyWaitTimeSeconds
: txnApplyWaitTimeSeconds;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the options are not exclusive, the non-deprecated one should be preferred.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

Comment on lines -70 to +71
@CommandLine.Option(names = {"-nodeid", "--nodeid"},
description = "NodeID of the OM to be decommissioned.",
required = true)
private String decommNodeId;
@CommandLine.ArgGroup(multiplicity = "1")
private NodeIdOptions nodeIdOptions;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How did you decide where to introduce an exclusive ArgGroup and where to add a plain option for the deprecated one? Behavior with ArgGroup matches original one (in that only one of the option names can be used), while two plain options reduce the change both now and when we will remove the deprecated options in a future release.

Should we use one of these styles consistently?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In DecommissionOMSubcommand and DecommissionScmSubcommand, the @Arggroup(multiplicity = "1") is not there just because of deprecation. It marks the parameter as required. Inside that group, --nodeid and -nodeid are just alternate names for the same value, resolved in a getter — the same pattern as OmAddressOptions
ScmOption, GenericCli, PrepareSubCommand, FilterPipelineOptions, etc. use plain options because those parameters are optional

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the explanation.

@hani-fouladgar hani-fouladgar marked this pull request as draft June 12, 2026 19:17
Comment on lines 136 to 141
public OzoneConfiguration getOzoneConf() {
String path = getConfigurationPath();
if (path != null) {
config.addResource(new Path(path));
}
return config;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getOzoneConf() may be called multiple times, we should add the extra resource only once.

/**
* Tests for {@link GenericCli} configuration option handling.
*/
public class TestGenericCliConfiguration {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for adding this test. Ideally it should be in hadoop-hdds/cli-common/src/test/java/org/apache/hadoop/hdds/cli.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

9fc7064 moved TestDeprecatedCliOption instead of TestGenericCliConfiguration (as suggested). While TestDeprecatedCliOption also exercises code in hdds-cli-common (DeprecatedCliOption), it used ListPipelinesSubcommand, so I thought we should keep it in ozone-cli-admin. During the move ListPipelinesSubcommand was replaced with TestCommand, which has a simplified option structure: each option has both the deprecated and non-deprecated names. I think that causes the test failure:

Tests run: 3, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.160 s <<< FAILURE! -- in org.apache.hadoop.hdds.cli.TestDeprecatedCliOption
org.apache.hadoop.hdds.cli.TestDeprecatedCliOption.doesNotWarnForLongOption -- Time elapsed: 0.012 s <<< FAILURE!
java.lang.AssertionError: 

Expecting empty but was: "WARNING: Option '-ffc' is deprecated. Use '--filter-by-factor' instead.
"
	at org.apache.hadoop.hdds.cli.TestDeprecatedCliOption.doesNotWarnForLongOption(TestDeprecatedCliOption.java:85)

Please restore TestDeprecatedCliOption to its previous state and move TestGenericCliConfiguration instead.

/**
* Tests for {@link GenericCli} configuration option handling.
*/
public class TestGenericCliConfiguration {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

9fc7064 moved TestDeprecatedCliOption instead of TestGenericCliConfiguration (as suggested). While TestDeprecatedCliOption also exercises code in hdds-cli-common (DeprecatedCliOption), it used ListPipelinesSubcommand, so I thought we should keep it in ozone-cli-admin. During the move ListPipelinesSubcommand was replaced with TestCommand, which has a simplified option structure: each option has both the deprecated and non-deprecated names. I think that causes the test failure:

Tests run: 3, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.160 s <<< FAILURE! -- in org.apache.hadoop.hdds.cli.TestDeprecatedCliOption
org.apache.hadoop.hdds.cli.TestDeprecatedCliOption.doesNotWarnForLongOption -- Time elapsed: 0.012 s <<< FAILURE!
java.lang.AssertionError: 

Expecting empty but was: "WARNING: Option '-ffc' is deprecated. Use '--filter-by-factor' instead.
"
	at org.apache.hadoop.hdds.cli.TestDeprecatedCliOption.doesNotWarnForLongOption(TestDeprecatedCliOption.java:85)

Please restore TestDeprecatedCliOption to its previous state and move TestGenericCliConfiguration instead.

Comment thread hadoop-hdds/cli-common/pom.xml Outdated
Comment on lines +54 to +60

<!-- Test dependencies -->
<dependency>
<groupId>org.apache.ozone</groupId>
<artifactId>hdds-test-utils</artifactId>
<scope>test</scope>
</dependency>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to be unnecessary. Neither TestGenericCliConfiguration nor TestDeprecatedCliOption use code from hdds-test-utils.

@adoroszlai adoroszlai marked this pull request as ready for review June 14, 2026 05:26
@adoroszlai adoroszlai merged commit 175e293 into apache:master Jun 14, 2026
60 of 61 checks passed
@adoroszlai

Copy link
Copy Markdown
Contributor

Thanks @hani-fouladgar for the patch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants