This is an automated email from the ASF dual-hosted git repository.
dlmarion pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/accumulo.git
The following commit(s) were added to refs/heads/main by this push:
new 66f568d90e Modified accumulo script to use group name in command
syntax (#6109)
66f568d90e is described below
commit 66f568d90e15f2e3fa46a7fe6b658327e0e2e8a6
Author: Dave Marion <[email protected]>
AuthorDate: Wed Feb 4 15:18:52 2026 -0500
Modified accumulo script to use group name in command syntax (#6109)
Modified command syntax from `accumulo <command>` to
`accumulo <group> <command>`. This work will be leveraged
in a future change to decompose the `admin` command into
seperate KeywordExecutable instances in an `admin` group.
Related to #6086
---
assemble/bin/accumulo-service | 6 +-
.../miniclusterImpl/MiniAccumuloClusterImpl.java | 1 -
.../main/java/org/apache/accumulo/start/Main.java | 101 +++++++++------
.../apache/accumulo/test/start/KeywordStartIT.java | 142 +++++++++++++--------
4 files changed, 153 insertions(+), 97 deletions(-)
diff --git a/assemble/bin/accumulo-service b/assemble/bin/accumulo-service
index b887160ecf..af4aa83dea 100755
--- a/assemble/bin/accumulo-service
+++ b/assemble/bin/accumulo-service
@@ -27,8 +27,8 @@ Services:
monitor Accumulo monitor
manager Accumulo manager
tserver Accumulo tserver
- compactor Accumulo compactor (experimental)
- sserver Accumulo scan server (experimental)
+ compactor Accumulo compactor
+ sserver Accumulo scan server
Commands:
start Starts service(s)
@@ -111,7 +111,7 @@ function start_service() {
rotate_log "$outfile"
rotate_log "$errfile"
- nohup "${bin}/accumulo" "$service_type" "$@" >"$outfile" 2>"$errfile"
</dev/null &
+ nohup "${bin}/accumulo" "process" "$service_type" "$@" >"$outfile"
2>"$errfile" </dev/null &
echo "$!" >"${pid_file}"
done
diff --git
a/minicluster/src/main/java/org/apache/accumulo/miniclusterImpl/MiniAccumuloClusterImpl.java
b/minicluster/src/main/java/org/apache/accumulo/miniclusterImpl/MiniAccumuloClusterImpl.java
index d1977799a7..f9703f721b 100644
---
a/minicluster/src/main/java/org/apache/accumulo/miniclusterImpl/MiniAccumuloClusterImpl.java
+++
b/minicluster/src/main/java/org/apache/accumulo/miniclusterImpl/MiniAccumuloClusterImpl.java
@@ -431,7 +431,6 @@ public class MiniAccumuloClusterImpl implements
AccumuloCluster {
File stdErr = logDir.resolve(clazz.getSimpleName() + "_" + hashcode +
".err").toFile();
Process process =
builder.redirectError(stdErr).redirectOutput(stdOut).start();
-
cleanup.add(process);
return new ProcessInfo(process, stdOut);
diff --git a/start/src/main/java/org/apache/accumulo/start/Main.java
b/start/src/main/java/org/apache/accumulo/start/Main.java
index 3f6eea7992..d45efd5e57 100644
--- a/start/src/main/java/org/apache/accumulo/start/Main.java
+++ b/start/src/main/java/org/apache/accumulo/start/Main.java
@@ -21,8 +21,10 @@ package org.apache.accumulo.start;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
+import java.util.Arrays;
import java.util.Collections;
-import java.util.Comparator;
+import java.util.EnumMap;
+import java.util.List;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.TreeMap;
@@ -37,7 +39,7 @@ public class Main {
private static final Logger log = LoggerFactory.getLogger(Main.class);
private static ClassLoader classLoader;
- private static Map<String,KeywordExecutable> servicesMap;
+ private static Map<UsageGroup,Map<String,KeywordExecutable>> servicesMap;
public static void main(final String[] args) throws Exception {
final ClassLoader loader = getClassLoader();
@@ -51,14 +53,21 @@ public class Main {
return;
}
- // determine whether a keyword was used or a class name, and execute it
with the remaining
- // args
- String keywordOrClassName = args[0];
- KeywordExecutable keywordExec =
getExecutables(loader).get(keywordOrClassName);
- if (keywordExec != null) {
- execKeyword(keywordExec, stripArgs(args, 1));
+ if (args.length == 1) {
+ execMainClassName(args[0], new String[] {});
} else {
- execMainClassName(keywordOrClassName, stripArgs(args, 1));
+ String arg1 = args[0];
+ String arg2 = args[1];
+ KeywordExecutable keywordExec = null;
+ try {
+ UsageGroup group = UsageGroup.valueOf(arg1.toUpperCase());
+ keywordExec = getExecutables(loader).get(group).get(arg2);
+ } catch (IllegalArgumentException e) {}
+ if (keywordExec != null) {
+ execKeyword(keywordExec, stripArgs(args, 2));
+ } else {
+ execMainClassName(arg1, stripArgs(args, 1));
+ }
}
}
@@ -157,61 +166,71 @@ public class Main {
System.exit(1);
}
- public static void printCommands(TreeSet<KeywordExecutable> set, UsageGroup
group) {
- set.stream().filter(e -> e.usageGroup() == group)
- .forEach(ke -> System.out.printf(" %-30s %s\n", ke.usage(),
ke.description()));
- }
-
public static void printUsage() {
- TreeSet<KeywordExecutable> executables =
- new TreeSet<>(Comparator.comparing(KeywordExecutable::keyword));
- executables.addAll(getExecutables(getClassLoader()).values());
-
- System.out.println("\nUsage: accumulo <command> [--help] (<argument>
...)\n\n"
- + " --help Prints usage for specified command");
- System.out.println("\nCore Commands:");
- printCommands(executables, UsageGroup.CORE);
- System.out.println(" jshell Runs JShell for
Accumulo\n"
- + " classpath Prints Accumulo classpath\n"
- + " <main class> args Runs Java <main class> located on
Accumulo classpath");
-
- System.out.println("\nProcess Commands:");
- printCommands(executables, UsageGroup.PROCESS);
-
- System.out.println("\nOther Commands:");
- printCommands(executables, UsageGroup.OTHER);
+ System.out.println("\nUsage one of:");
+ System.out.println(" accumulo --help");
+ System.out.println(" accumulo classpath");
+ System.out.println(" accumulo jshell (<argument> ...)");
+ System.out.println(" accumulo className (<argument> ...)");
+ System.out.println(" accumulo <group> <command> [--help] (<argument>
...)\n\n");
+
+ Map<UsageGroup,Map<String,KeywordExecutable>> exectuables =
getExecutables(getClassLoader());
+ List<UsageGroup> groups = Arrays.asList(UsageGroup.values());
+ Collections.sort(groups);
+ groups.forEach(g -> {
+ System.out.println("\n" + g.name() + " Group Commands:");
+ exectuables.get(g).values()
+ .forEach(ke -> System.out.printf(" %-30s %s\n", ke.usage(),
ke.description()));
+ });
System.out.println();
}
- public static synchronized Map<String,KeywordExecutable>
getExecutables(final ClassLoader cl) {
+ public static synchronized Map<UsageGroup,Map<String,KeywordExecutable>>
+ getExecutables(final ClassLoader cl) {
if (servicesMap == null) {
servicesMap =
checkDuplicates(ServiceLoader.load(KeywordExecutable.class, cl));
}
return servicesMap;
}
- public static Map<String,KeywordExecutable>
+ private record BanKey(UsageGroup group, String keyword) implements
Comparable<BanKey> {
+ @Override
+ public int compareTo(BanKey o) {
+ int result = this.group.compareTo(o.group);
+ if (result == 0) {
+ result = this.keyword.compareTo(o.keyword);
+ }
+ return result;
+ }
+ };
+
+ public static Map<UsageGroup,Map<String,KeywordExecutable>>
checkDuplicates(final Iterable<? extends KeywordExecutable> services) {
- TreeSet<String> banList = new TreeSet<>();
- TreeMap<String,KeywordExecutable> results = new TreeMap<>();
+ TreeSet<BanKey> banList = new TreeSet<>();
+ EnumMap<UsageGroup,Map<String,KeywordExecutable>> results = new
EnumMap<>(UsageGroup.class);
+ for (UsageGroup ug : UsageGroup.values()) {
+ results.put(ug, new TreeMap<>());
+ }
for (KeywordExecutable service : services) {
+ UsageGroup group = service.usageGroup();
String keyword = service.keyword();
- if (banList.contains(keyword)) {
+ BanKey bk = new BanKey(group, keyword);
+ if (banList.contains(bk)) {
// subsequent times a duplicate is found, just warn and exclude it
warnDuplicate(service);
- } else if (results.containsKey(keyword)) {
+ } else if (results.get(group).containsKey(keyword)) {
// the first time a duplicate is found, banList it and warn
- banList.add(keyword);
- warnDuplicate(results.remove(keyword));
+ banList.add(bk);
+ warnDuplicate(results.get(group).remove(keyword));
warnDuplicate(service);
} else {
// first observance of this keyword, so just add it to the list
- results.put(service.keyword(), service);
+ results.get(group).put(service.keyword(), service);
}
}
- return Collections.unmodifiableSortedMap(results);
+ return Collections.unmodifiableMap(results);
}
private static void warnDuplicate(final KeywordExecutable service) {
diff --git
a/test/src/main/java/org/apache/accumulo/test/start/KeywordStartIT.java
b/test/src/main/java/org/apache/accumulo/test/start/KeywordStartIT.java
index f3798a2a90..40b7d02e99 100644
--- a/test/src/main/java/org/apache/accumulo/test/start/KeywordStartIT.java
+++ b/test/src/main/java/org/apache/accumulo/test/start/KeywordStartIT.java
@@ -18,7 +18,6 @@
*/
package org.apache.accumulo.test.start;
-import static java.util.stream.Collectors.toSet;
import static org.apache.accumulo.harness.AccumuloITBase.SUNNY_DAY;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
@@ -35,8 +34,10 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
-import java.util.Map.Entry;
+import java.util.Set;
+import java.util.SortedSet;
import java.util.TreeMap;
+import java.util.TreeSet;
import org.apache.accumulo.compactor.CompactorExecutable;
import org.apache.accumulo.core.file.rfile.GenerateSplits;
@@ -68,6 +69,7 @@ import org.apache.accumulo.server.util.ZooZap;
import org.apache.accumulo.shell.Shell;
import org.apache.accumulo.start.Main;
import org.apache.accumulo.start.spi.KeywordExecutable;
+import org.apache.accumulo.start.spi.KeywordExecutable.UsageGroup;
import org.apache.accumulo.tserver.ScanServerExecutable;
import org.apache.accumulo.tserver.TServerExecutable;
import org.apache.accumulo.tserver.TabletServer;
@@ -91,7 +93,7 @@ public class KeywordStartIT {
* There may be other ways to run annotation processors in your IDE, so this
may not be necessary,
* depending on your IDE and its configuration.
*/
- private Map<String,KeywordExecutable> getKeywordExecutables() {
+ private Map<UsageGroup,Map<String,KeywordExecutable>>
getKeywordExecutables() {
var all = Main.getExecutables(ClassLoader.getSystemClassLoader());
assumeTrue(!all.isEmpty());
return all;
@@ -99,7 +101,9 @@ public class KeywordStartIT {
@Test
public void testKeywordsMatch() {
- getKeywordExecutables().forEach((k, v) -> assertEquals(k, v.keyword()));
+ getKeywordExecutables().forEach((k, v) -> {
+ v.forEach((k2, v2) -> assertEquals(k2, v2.keyword()));
+ });
}
@Test
@@ -110,14 +114,30 @@ public class KeywordStartIT {
NoOp three = new NoOp("three");
List<NoOp> services = Arrays.asList(one, three, two, two, three, three,
anotherOne);
assertEquals(7, services.size());
- Map<String,KeywordExecutable> results = Main.checkDuplicates(services);
- assertTrue(results.containsKey(one.keyword()));
- assertTrue(results.containsKey(anotherOne.keyword()));
- assertFalse(results.containsKey(two.keyword()));
- assertFalse(results.containsKey(three.keyword()));
- assertEquals(2, results.size());
+ Map<UsageGroup,Map<String,KeywordExecutable>> results =
Main.checkDuplicates(services);
+ assertTrue(results.get(UsageGroup.OTHER).containsKey(one.keyword()));
+
assertTrue(results.get(UsageGroup.OTHER).containsKey(anotherOne.keyword()));
+ assertFalse(results.get(UsageGroup.OTHER).containsKey(two.keyword()));
+ assertFalse(results.get(UsageGroup.OTHER).containsKey(three.keyword()));
+ assertEquals(2, results.get(UsageGroup.OTHER).size());
}
+ private record CommandInfo(UsageGroup group, String keyword,
+ Class<? extends KeywordExecutable> clazz) implements
Comparable<CommandInfo> {
+
+ @Override
+ public int compareTo(CommandInfo o) {
+ int result = this.group.compareTo(o.group);
+ if (result == 0) {
+ result = this.keyword.compareTo(o.keyword);
+ if (result == 0) {
+ result = this.clazz.getName().compareTo(o.clazz.getName());
+ }
+ }
+ return result;
+ }
+ };
+
/**
* This test guards against accidental renaming or incorrect naming of the
keyword used to
* identify the service. The keyword is used to access the commands via the
command line, so
@@ -126,48 +146,59 @@ public class KeywordStartIT {
@Test
public void testExpectedClasses() {
assumeTrue(Files.exists(Path.of(System.getProperty("user.dir")).resolve("src")));
- TreeMap<String,Class<? extends KeywordExecutable>> expectSet = new
TreeMap<>();
- expectSet.put("admin", Admin.class);
- expectSet.put("check-compaction-config", CheckCompactionConfig.class);
- expectSet.put("check-accumulo-properties", CheckAccumuloProperties.class);
- expectSet.put("compactor", CompactorExecutable.class);
- expectSet.put("create-empty", CreateEmpty.class);
- expectSet.put("create-token", CreateToken.class);
- expectSet.put("dump-zoo", DumpZookeeper.class);
- expectSet.put("ec-admin", ECAdmin.class);
- expectSet.put("gc", GCExecutable.class);
- expectSet.put("generate-splits", GenerateSplits.class);
- expectSet.put("help", Help.class);
- expectSet.put("info", Info.class);
- expectSet.put("init", Initialize.class);
- expectSet.put("login-info", LoginProperties.class);
- expectSet.put("manager", ManagerExecutable.class);
- expectSet.put("minicluster", MiniClusterExecutable.class);
- expectSet.put("monitor", MonitorExecutable.class);
- expectSet.put("rfile-info", PrintInfo.class);
- expectSet.put("shell", Shell.class);
- expectSet.put("split-large", SplitLarge.class);
- expectSet.put("sserver", ScanServerExecutable.class);
- expectSet.put("tserver", TServerExecutable.class);
- expectSet.put("upgrade", UpgradeUtil.class);
- expectSet.put("version", Version.class);
- expectSet.put("wal-info", LogReader.class);
- expectSet.put("zoo-info-viewer", ZooInfoViewer.class);
- expectSet.put("zoo-prop-editor", ZooPropEditor.class);
- expectSet.put("zoo-zap", ZooZap.class);
- expectSet.put("zookeeper", ZooKeeperMain.class);
+ SortedSet<CommandInfo> expectSet = new TreeSet<>();
+ expectSet.add(new CommandInfo(UsageGroup.CORE, "admin", Admin.class));
+ expectSet.add(
+ new CommandInfo(UsageGroup.OTHER, "check-compaction-config",
CheckCompactionConfig.class));
+ expectSet.add(new CommandInfo(UsageGroup.OTHER,
"check-accumulo-properties",
+ CheckAccumuloProperties.class));
+ expectSet.add(new CommandInfo(UsageGroup.PROCESS, "compactor",
CompactorExecutable.class));
+ expectSet.add(new CommandInfo(UsageGroup.OTHER, "create-empty",
CreateEmpty.class));
+ expectSet.add(new CommandInfo(UsageGroup.OTHER, "create-token",
CreateToken.class));
+ expectSet.add(new CommandInfo(UsageGroup.OTHER, "dump-zoo",
DumpZookeeper.class));
+ expectSet.add(new CommandInfo(UsageGroup.CORE, "ec-admin", ECAdmin.class));
+ expectSet.add(new CommandInfo(UsageGroup.PROCESS, "gc",
GCExecutable.class));
+ expectSet.add(new CommandInfo(UsageGroup.OTHER, "generate-splits",
GenerateSplits.class));
+ expectSet.add(new CommandInfo(UsageGroup.CORE, "help", Help.class));
+ expectSet.add(new CommandInfo(UsageGroup.CORE, "info", Info.class));
+ expectSet.add(new CommandInfo(UsageGroup.CORE, "init", Initialize.class));
+ expectSet.add(new CommandInfo(UsageGroup.OTHER, "login-info",
LoginProperties.class));
+ expectSet.add(new CommandInfo(UsageGroup.PROCESS, "manager",
ManagerExecutable.class));
+ expectSet.add(new CommandInfo(UsageGroup.PROCESS, "minicluster",
MiniClusterExecutable.class));
+ expectSet.add(new CommandInfo(UsageGroup.PROCESS, "monitor",
MonitorExecutable.class));
+ expectSet.add(new CommandInfo(UsageGroup.OTHER, "rfile-info",
PrintInfo.class));
+ expectSet.add(new CommandInfo(UsageGroup.CORE, "shell", Shell.class));
+ expectSet.add(new CommandInfo(UsageGroup.OTHER, "split-large",
SplitLarge.class));
+ expectSet.add(new CommandInfo(UsageGroup.PROCESS, "sserver",
ScanServerExecutable.class));
+ expectSet.add(new CommandInfo(UsageGroup.PROCESS, "tserver",
TServerExecutable.class));
+ expectSet.add(new CommandInfo(UsageGroup.OTHER, "upgrade",
UpgradeUtil.class));
+ expectSet.add(new CommandInfo(UsageGroup.CORE, "version", Version.class));
+ expectSet.add(new CommandInfo(UsageGroup.OTHER, "wal-info",
LogReader.class));
+ expectSet.add(new CommandInfo(UsageGroup.OTHER, "zoo-info-viewer",
ZooInfoViewer.class));
+ expectSet.add(new CommandInfo(UsageGroup.OTHER, "zoo-prop-editor",
ZooPropEditor.class));
+ expectSet.add(new CommandInfo(UsageGroup.OTHER, "zoo-zap", ZooZap.class));
+ expectSet.add(new CommandInfo(UsageGroup.PROCESS, "zookeeper",
ZooKeeperMain.class));
+
+ Map<UsageGroup,Map<String,KeywordExecutable>> actualExecutables =
+ new TreeMap<>(getKeywordExecutables());
+ SortedSet<CommandInfo> actualSet = new TreeSet<>();
+ actualExecutables.entrySet().forEach((e) -> {
+ e.getValue().entrySet().forEach((e2) -> {
+ actualSet.add(new CommandInfo(e.getKey(), e2.getKey(),
e2.getValue().getClass()));
+ });
+ });
+
+ Iterator<CommandInfo> expectIter = expectSet.iterator();
+ Iterator<CommandInfo> actualIter = actualSet.iterator();
- Iterator<Entry<String,Class<? extends KeywordExecutable>>> expectIter =
- expectSet.entrySet().iterator();
- TreeMap<String,KeywordExecutable> actualSet = new
TreeMap<>(getKeywordExecutables());
- Iterator<Entry<String,KeywordExecutable>> actualIter =
actualSet.entrySet().iterator();
- Entry<String,Class<? extends KeywordExecutable>> expected;
- Entry<String,KeywordExecutable> actual;
+ CommandInfo expected;
+ CommandInfo actual;
while (expectIter.hasNext() && actualIter.hasNext()) {
expected = expectIter.next();
actual = actualIter.next();
- assertEquals(expected.getKey(), actual.getKey());
- assertEquals(expected.getValue(), actual.getValue().getClass());
+ assertEquals(expected.group(), actual.group());
+ assertEquals(expected.keyword(), actual.keyword());
+ assertEquals(expected.clazz(), actual.clazz());
}
boolean moreExpected = expectIter.hasNext();
if (moreExpected) {
@@ -223,16 +254,23 @@ public class KeywordStartIT {
c -> assertTrue(hasMain(c), "Class " + c.getName() + " is missing a
main method!"));
// build a list of all classed that implement KeywordExecutable
- var all =
getKeywordExecutables().values().stream().map(Object::getClass).collect(toSet());
+ Map<UsageGroup,Map<String,KeywordExecutable>> actualExecutables =
+ new TreeMap<>(getKeywordExecutables());
+ Set<Class<? extends KeywordExecutable>> actualSet = new HashSet<>();
+ actualExecutables.entrySet().forEach((e) -> {
+ e.getValue().entrySet().forEach((e2) -> {
+ actualSet.add(e2.getValue().getClass());
+ });
+ });
// remove the ones we already verified have a main method
- assertTrue(all.removeAll(expectSet));
+ assertTrue(actualSet.removeAll(expectSet));
// ensure there's still some left (there should be some that don't have a
main method)
- assertNotEquals(0, all.size());
+ assertNotEquals(0, actualSet.size());
// for those remaining, make sure they *don't* have an unexpected main
method
- all.forEach(
+ actualSet.forEach(
c -> assertFalse(hasMain(c), "Class " + c.getName() + " has an
unexpected main method!"));
}