diff --git a/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/cli/ItemsFromStdin.java b/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/cli/ItemsFromStdin.java new file mode 100644 index 000000000000..1d01f0a18770 --- /dev/null +++ b/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/cli/ItemsFromStdin.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.hdds.cli; + +import static java.util.Collections.unmodifiableList; + +import jakarta.annotation.Nonnull; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Scanner; + +/** Parameter for specifying list of items, reading from stdin if "-" is given as first item. */ +public abstract class ItemsFromStdin implements Iterable { + + protected static final String FORMAT_DESCRIPTION = + ": one or more, separated by spaces. To read from stdin, specify '-' and supply one item per line."; + + private List items; + + protected void setItems(List arguments) { + items = readItemsFromStdinIfNeeded(arguments); + } + + public List getItems() { + return unmodifiableList(items); + } + + @Nonnull + @Override + public Iterator iterator() { + return items.iterator(); + } + + public int size() { + return items.size(); + } + + private static List readItemsFromStdinIfNeeded(List parameters) { + if (parameters.isEmpty() || !"-".equals(parameters.iterator().next())) { + return parameters; + } + + List items = new ArrayList<>(); + Scanner scanner = new Scanner(System.in, StandardCharsets.UTF_8.name()); + while (scanner.hasNextLine()) { + items.add(scanner.nextLine().trim()); + } + return items; + } +} diff --git a/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/container/ContainerIDParameters.java b/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/container/ContainerIDParameters.java new file mode 100644 index 000000000000..4b14b40c13f6 --- /dev/null +++ b/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/container/ContainerIDParameters.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.hdds.scm.cli.container; + +import java.util.List; +import org.apache.hadoop.hdds.cli.ItemsFromStdin; +import picocli.CommandLine; + +/** Parameter for specifying list of container IDs. */ +@CommandLine.Command +public class ContainerIDParameters extends ItemsFromStdin { + + @CommandLine.Parameters(description = "Container IDs" + FORMAT_DESCRIPTION, + arity = "1..*", + paramLabel = "") + public void setContainerIDs(List arguments) { + setItems(arguments); + } +} diff --git a/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/container/InfoSubcommand.java b/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/container/InfoSubcommand.java index aca99e84e7c4..c6e385b4c6af 100644 --- a/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/container/InfoSubcommand.java +++ b/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/container/InfoSubcommand.java @@ -25,7 +25,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Scanner; import java.util.stream.Collectors; import org.apache.hadoop.hdds.cli.HddsVersionProvider; import org.apache.hadoop.hdds.client.ReplicationConfig; @@ -43,7 +42,6 @@ import org.apache.hadoop.hdds.server.JsonUtils; import picocli.CommandLine; import picocli.CommandLine.Command; -import picocli.CommandLine.Parameters; /** * This is the handler that process container info command. @@ -60,40 +58,20 @@ public class InfoSubcommand extends ScmSubcommand { description = "Format output as JSON") private boolean json; - @Parameters(description = "One or more container IDs separated by spaces. " + - "To read from stdin, specify '-' and supply the container IDs " + - "separated by newlines.", - arity = "1..*", - paramLabel = "") - private String[] containerList; + @CommandLine.Mixin + private ContainerIDParameters containerList; private boolean multiContainer = false; @Override public void execute(ScmClient scmClient) throws IOException { boolean first = true; - boolean stdin = false; - if (containerList.length > 1) { - multiContainer = true; - } else if (containerList[0].equals("-")) { - stdin = true; - // Assume multiple containers if reading from stdin - multiContainer = true; - } + multiContainer = containerList.size() > 1; printHeader(); - if (stdin) { - Scanner scanner = new Scanner(System.in, "UTF-8"); - while (scanner.hasNextLine()) { - String id = scanner.nextLine().trim(); - printOutput(scmClient, id, first); - first = false; - } - } else { - for (String id : containerList) { - printOutput(scmClient, id, first); - first = false; - } + for (String id : containerList) { + printOutput(scmClient, id, first); + first = false; } printFooter(); } diff --git a/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/datanode/HostNameParameters.java b/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/datanode/HostNameParameters.java index c67f980aebc7..954f2fae92e0 100644 --- a/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/datanode/HostNameParameters.java +++ b/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/datanode/HostNameParameters.java @@ -17,36 +17,23 @@ package org.apache.hadoop.hdds.scm.cli.datanode; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; import java.util.List; -import java.util.Scanner; +import org.apache.hadoop.hdds.cli.ItemsFromStdin; import picocli.CommandLine; /** Parameter for specifying list of hostnames. */ @CommandLine.Command -public class HostNameParameters { +public class HostNameParameters extends ItemsFromStdin { - @CommandLine.Parameters(description = "One or more host names separated by spaces. " + - "To read from stdin, specify '-' and supply the host names " + - "separated by newlines.", + @CommandLine.Parameters(description = "Host names" + FORMAT_DESCRIPTION, arity = "1..*", paramLabel = "") - private List parameters = new ArrayList<>(); + public void setHostNames(List arguments) { + setItems(arguments); + } public List getHostNames() { - List hosts; - // Whether to read from stdin - if (parameters.get(0).equals("-")) { - hosts = new ArrayList<>(); - Scanner scanner = new Scanner(System.in, StandardCharsets.UTF_8.name()); - while (scanner.hasNextLine()) { - hosts.add(scanner.nextLine().trim()); - } - } else { - hosts = parameters; - } - return hosts; + return getItems(); } } diff --git a/hadoop-ozone/cli-shell/src/main/java/org/apache/hadoop/ozone/shell/Shell.java b/hadoop-ozone/cli-shell/src/main/java/org/apache/hadoop/ozone/shell/Shell.java index 5b899606e713..3aa280737c18 100644 --- a/hadoop-ozone/cli-shell/src/main/java/org/apache/hadoop/ozone/shell/Shell.java +++ b/hadoop-ozone/cli-shell/src/main/java/org/apache/hadoop/ozone/shell/Shell.java @@ -68,6 +68,7 @@ private static class ExecutionMode { public Shell() { super(new PicocliCommandsFactory()); + getCmd().setExecutionStrategy(this::execute); } public String name() { @@ -79,26 +80,19 @@ public String prompt() { return name(); } - @Override - public void run(String[] argv) { + private int execute(CommandLine.ParseResult parseResult) { name = spec.name(); - try { - // parse args to check if interactive mode is requested - getCmd().parseArgs(argv); - } catch (Exception ignored) { - // failure will be reported by regular, non-interactive run - } - - if (executionMode != null && (executionMode.interactive || !executionMode.command.isEmpty())) { + if (parseResult.hasMatchedOption("--interactive") || parseResult.hasMatchedOption("--execute")) { spec.name(""); // use short name (e.g. "token get" instead of "ozone sh token get") installBatchExceptionHandler(); new REPL(this, getCmd(), (PicocliCommandsFactory) getCmd().getFactory(), executionMode.command); - } else { - TracingUtil.initTracing("shell", getOzoneConf()); - String spanName = spec.name() + " " + String.join(" ", argv); - TracingUtil.executeInNewSpan(spanName, () -> super.run(argv)); + return 0; } + + TracingUtil.initTracing("shell", getOzoneConf()); + String spanName = spec.name() + " " + String.join(" ", parseResult.originalArgs()); + return TracingUtil.executeInNewSpan(spanName, () -> new CommandLine.RunLast().execute(parseResult)); } private void installBatchExceptionHandler() {