This is an automated email from the ASF dual-hosted git repository.
SpriCoder pushed a commit to branch fs/inner-view
in repository https://gitbox.apache.org/repos/asf/iotdb.git
The following commit(s) were added to refs/heads/fs/inner-view by this push:
new 600b516f8ae add head
600b516f8ae is described below
commit 600b516f8aee83624b622378ff8b235be0540f8f
Author: spricoder <[email protected]>
AuthorDate: Wed Apr 29 20:09:11 2026 +0800
add head
---
.../org/apache/iotdb/cli/fs/FilesystemShell.java | 17 ++++-
.../iotdb/cli/fs/command/FilesystemCommand.java | 27 ++++++--
.../cli/fs/command/FilesystemCommandParser.java | 73 +++++++++++++++++++++-
.../org/apache/iotdb/cli/utils/JlineUtils.java | 2 +-
.../apache/iotdb/cli/fs/FilesystemShellTest.java | 40 ++++++++++++
.../fs/command/FilesystemCommandParserTest.java | 28 +++++++++
6 files changed, 175 insertions(+), 12 deletions(-)
diff --git
a/iotdb-client/cli/src/main/java/org/apache/iotdb/cli/fs/FilesystemShell.java
b/iotdb-client/cli/src/main/java/org/apache/iotdb/cli/fs/FilesystemShell.java
index 4c8372bb8ad..6a3cf9e976d 100644
---
a/iotdb-client/cli/src/main/java/org/apache/iotdb/cli/fs/FilesystemShell.java
+++
b/iotdb-client/cli/src/main/java/org/apache/iotdb/cli/fs/FilesystemShell.java
@@ -44,7 +44,7 @@ public class FilesystemShell {
private static final int DEFAULT_READ_LIMIT = 20;
private static final List<String> COMMANDS =
Arrays.asList(
- "pwd", "ls", "ll", "cd", "stat", "cat", "paste", "tree", "help",
"exit", "quit");
+ "pwd", "ls", "ll", "cd", "stat", "cat", "head", "paste", "tree",
"help", "exit", "quit");
private final CliContext ctx;
private final FilesystemSchemaProvider provider;
@@ -74,7 +74,10 @@ public class FilesystemShell {
printNode(provider.describe(resolve(command.getPath())));
return true;
case CAT:
- printRows(provider.read(resolve(command.getPath()),
DEFAULT_READ_LIMIT));
+ printSequentialReads(command.getPaths(), DEFAULT_READ_LIMIT);
+ return true;
+ case HEAD:
+ printRows(provider.read(resolve(command.getPath()),
command.getLimit()));
return true;
case PASTE:
printRows(provider.read(resolve(command.getPaths()),
DEFAULT_READ_LIMIT));
@@ -172,6 +175,12 @@ public class FilesystemShell {
}
}
+ private void printSequentialReads(List<String> paths, int limit) throws
SQLException {
+ for (String path : paths) {
+ printRows(provider.read(resolve(path), limit));
+ }
+ }
+
private static String joinValues(SqlRow row) {
StringBuilder builder = new StringBuilder();
for (String value : row.asMap().values()) {
@@ -191,8 +200,10 @@ public class FilesystemShell {
ctx.getPrinter().println("ll [path]");
ctx.getPrinter().println("cd <path>");
ctx.getPrinter().println("stat [path]");
- ctx.getPrinter().println("cat <path>");
+ ctx.getPrinter().println("cat <path>...");
+ ctx.getPrinter().println("head [-n lines] <path>");
ctx.getPrinter().println("paste <path>...");
+ ctx.getPrinter().println("tree [-L depth] [path]");
ctx.getPrinter().println("exit");
}
diff --git
a/iotdb-client/cli/src/main/java/org/apache/iotdb/cli/fs/command/FilesystemCommand.java
b/iotdb-client/cli/src/main/java/org/apache/iotdb/cli/fs/command/FilesystemCommand.java
index f375d008669..2cdd492fdc5 100644
---
a/iotdb-client/cli/src/main/java/org/apache/iotdb/cli/fs/command/FilesystemCommand.java
+++
b/iotdb-client/cli/src/main/java/org/apache/iotdb/cli/fs/command/FilesystemCommand.java
@@ -31,6 +31,7 @@ public class FilesystemCommand {
CD,
STAT,
CAT,
+ HEAD,
PASTE,
TREE,
SQL,
@@ -43,6 +44,7 @@ public class FilesystemCommand {
private final String path;
private final List<String> paths;
private final int depth;
+ private final int limit;
private final String statement;
private final String errorMessage;
@@ -51,39 +53,48 @@ public class FilesystemCommand {
String path,
List<String> paths,
int depth,
+ int limit,
String statement,
String errorMessage) {
this.type = type;
this.path = path;
this.paths = paths;
this.depth = depth;
+ this.limit = limit;
this.statement = statement;
this.errorMessage = errorMessage;
}
public static FilesystemCommand simple(Type type) {
- return new FilesystemCommand(type, "", Collections.emptyList(), -1, "",
"");
+ return new FilesystemCommand(type, "", Collections.emptyList(), -1, -1,
"", "");
}
public static FilesystemCommand path(Type type, String path) {
- return new FilesystemCommand(type, path, Collections.singletonList(path),
-1, "", "");
+ return new FilesystemCommand(type, path, Collections.singletonList(path),
-1, -1, "", "");
}
public static FilesystemCommand paths(Type type, List<String> paths) {
String path = paths.isEmpty() ? "" : paths.get(0);
- return new FilesystemCommand(type, path,
Collections.unmodifiableList(paths), -1, "", "");
+ return new FilesystemCommand(type, path,
Collections.unmodifiableList(paths), -1, -1, "", "");
+ }
+
+ public static FilesystemCommand head(String path, int limit) {
+ return new FilesystemCommand(
+ Type.HEAD, path, Collections.singletonList(path), -1, limit, "", "");
}
public static FilesystemCommand tree(String path, int depth) {
- return new FilesystemCommand(Type.TREE, path,
Collections.singletonList(path), depth, "", "");
+ return new FilesystemCommand(
+ Type.TREE, path, Collections.singletonList(path), depth, -1, "", "");
}
public static FilesystemCommand sql(String statement) {
- return new FilesystemCommand(Type.SQL, "", Collections.emptyList(), -1,
statement, "");
+ return new FilesystemCommand(Type.SQL, "", Collections.emptyList(), -1,
-1, statement, "");
}
public static FilesystemCommand invalid(String errorMessage) {
- return new FilesystemCommand(Type.INVALID, "", Collections.emptyList(),
-1, "", errorMessage);
+ return new FilesystemCommand(
+ Type.INVALID, "", Collections.emptyList(), -1, -1, "", errorMessage);
}
public Type getType() {
@@ -102,6 +113,10 @@ public class FilesystemCommand {
return depth;
}
+ public int getLimit() {
+ return limit;
+ }
+
public String getStatement() {
return statement;
}
diff --git
a/iotdb-client/cli/src/main/java/org/apache/iotdb/cli/fs/command/FilesystemCommandParser.java
b/iotdb-client/cli/src/main/java/org/apache/iotdb/cli/fs/command/FilesystemCommandParser.java
index 5fc2021edcd..7bdab81d178 100644
---
a/iotdb-client/cli/src/main/java/org/apache/iotdb/cli/fs/command/FilesystemCommandParser.java
+++
b/iotdb-client/cli/src/main/java/org/apache/iotdb/cli/fs/command/FilesystemCommandParser.java
@@ -27,6 +27,7 @@ public class FilesystemCommandParser {
private static final String DEFAULT_PATH = ".";
private static final int DEFAULT_TREE_DEPTH = Integer.MAX_VALUE;
+ private static final int DEFAULT_HEAD_LIMIT = 10;
private FilesystemCommandParser() {}
@@ -53,7 +54,7 @@ public class FilesystemCommandParser {
String[] tokens = line.split("\\s+");
String command = tokens[0].toLowerCase(Locale.ROOT);
if ("ls".equals(command)) {
- return FilesystemCommand.path(FilesystemCommand.Type.LS,
pathArgument(tokens));
+ return parseLs(tokens);
}
if ("ll".equals(command)) {
return FilesystemCommand.path(FilesystemCommand.Type.LL,
pathArgument(tokens));
@@ -65,7 +66,10 @@ public class FilesystemCommandParser {
return FilesystemCommand.path(FilesystemCommand.Type.STAT,
pathArgument(tokens));
}
if ("cat".equals(command)) {
- return FilesystemCommand.path(FilesystemCommand.Type.CAT,
pathArgument(tokens));
+ return parseCat(tokens);
+ }
+ if ("head".equals(command)) {
+ return parseHead(tokens);
}
if ("paste".equals(command)) {
return parsePaste(tokens);
@@ -95,6 +99,71 @@ public class FilesystemCommandParser {
return FilesystemCommand.paths(FilesystemCommand.Type.PASTE, paths);
}
+ private static FilesystemCommand parseLs(String[] tokens) {
+ FilesystemCommand.Type type = FilesystemCommand.Type.LS;
+ String path = DEFAULT_PATH;
+
+ for (int i = 1; i < tokens.length; i++) {
+ String token = tokens[i];
+ if (token.startsWith("-")) {
+ for (int j = 1; j < token.length(); j++) {
+ char option = token.charAt(j);
+ if (option == 'l') {
+ type = FilesystemCommand.Type.LL;
+ } else if (option != 'a') {
+ return FilesystemCommand.invalid("Unsupported ls option: -" +
option);
+ }
+ }
+ } else {
+ path = token;
+ }
+ }
+ return FilesystemCommand.path(type, path);
+ }
+
+ private static FilesystemCommand parseCat(String[] tokens) {
+ if (tokens.length < 2) {
+ return FilesystemCommand.path(FilesystemCommand.Type.CAT, DEFAULT_PATH);
+ }
+ List<String> paths = new ArrayList<>();
+ for (int i = 1; i < tokens.length; i++) {
+ paths.add(tokens[i]);
+ }
+ return FilesystemCommand.paths(FilesystemCommand.Type.CAT, paths);
+ }
+
+ private static FilesystemCommand parseHead(String[] tokens) {
+ String path = DEFAULT_PATH;
+ int limit = DEFAULT_HEAD_LIMIT;
+
+ for (int i = 1; i < tokens.length; i++) {
+ String token = tokens[i];
+ if ("-n".equals(token)) {
+ if (i + 1 >= tokens.length) {
+ return FilesystemCommand.invalid("Missing head line count");
+ }
+ try {
+ limit = Integer.parseInt(tokens[++i]);
+ } catch (NumberFormatException e) {
+ return FilesystemCommand.invalid("Invalid head line count: " +
tokens[i]);
+ }
+ } else if (token.startsWith("-") && token.length() > 1) {
+ try {
+ limit = Integer.parseInt(token.substring(1));
+ } catch (NumberFormatException e) {
+ return FilesystemCommand.invalid("Unsupported head option: " +
token);
+ }
+ } else {
+ path = token;
+ }
+ }
+
+ if (limit < 0) {
+ return FilesystemCommand.invalid("Invalid head line count: " + limit);
+ }
+ return FilesystemCommand.head(path, limit);
+ }
+
private static FilesystemCommand parseTree(String[] tokens) {
String path = DEFAULT_PATH;
int depth = DEFAULT_TREE_DEPTH;
diff --git
a/iotdb-client/cli/src/main/java/org/apache/iotdb/cli/utils/JlineUtils.java
b/iotdb-client/cli/src/main/java/org/apache/iotdb/cli/utils/JlineUtils.java
index b244b00ebf4..0a98529f6af 100644
--- a/iotdb-client/cli/src/main/java/org/apache/iotdb/cli/utils/JlineUtils.java
+++ b/iotdb-client/cli/src/main/java/org/apache/iotdb/cli/utils/JlineUtils.java
@@ -152,7 +152,7 @@ public class JlineUtils {
static Completer createCompleter(String accessMode) {
if ("filesystem".equalsIgnoreCase(accessMode)) {
return new StringsCompleter(
- "pwd", "ls", "ll", "cd", "stat", "cat", "paste", "tree", "help",
"exit", "quit");
+ "pwd", "ls", "ll", "cd", "stat", "cat", "head", "paste", "tree",
"help", "exit", "quit");
}
return new StringsCompleter(SQL_KEYWORDS);
}
diff --git
a/iotdb-client/cli/src/test/java/org/apache/iotdb/cli/fs/FilesystemShellTest.java
b/iotdb-client/cli/src/test/java/org/apache/iotdb/cli/fs/FilesystemShellTest.java
index e49ee0daf8a..e4ea9161a85 100644
---
a/iotdb-client/cli/src/test/java/org/apache/iotdb/cli/fs/FilesystemShellTest.java
+++
b/iotdb-client/cli/src/test/java/org/apache/iotdb/cli/fs/FilesystemShellTest.java
@@ -106,6 +106,20 @@ public class FilesystemShellTest {
verify(provider).list(FsPath.absolute("/"));
}
+ @Test
+ public void executeLsLongOptionPrintsLongListing() throws SQLException {
+ when(provider.list(FsPath.absolute("/")))
+ .thenReturn(
+ Arrays.asList(
+ new FsNode("testtest", FsPath.absolute("/testtest"),
FsNodeType.TABLE_DATABASE)));
+
+ assertTrue(shell.execute("ls -l /"));
+
+ assertTrue(out.toString().contains("dr-xr-xr-x"));
+ assertTrue(out.toString().contains("testtest"));
+ verify(provider).list(FsPath.absolute("/"));
+ }
+
@Test
public void executeCdUpdatesCurrentPath() throws SQLException {
when(provider.describe(FsPath.absolute("/root")))
@@ -153,6 +167,32 @@ public class FilesystemShellTest {
verify(provider).read(FsPath.absolute("/db1/table1"), 20);
}
+ @Test
+ public void executeCatReadsMultiplePathsSequentially() throws SQLException {
+ when(provider.read(FsPath.absolute("/db1/table1/tag1"), 20))
+ .thenReturn(Arrays.asList(SqlRow.of("Time", "1", "tag1", "a")));
+ when(provider.read(FsPath.absolute("/db1/table1/s1"), 20))
+ .thenReturn(Arrays.asList(SqlRow.of("Time", "1", "s1", "42")));
+
+ assertTrue(shell.execute("cat /db1/table1/tag1 /db1/table1/s1"));
+
+ assertTrue(out.toString().contains("1\ta"));
+ assertTrue(out.toString().contains("1\t42"));
+ verify(provider).read(FsPath.absolute("/db1/table1/tag1"), 20);
+ verify(provider).read(FsPath.absolute("/db1/table1/s1"), 20);
+ }
+
+ @Test
+ public void executeHeadReadsPathWithLimit() throws SQLException {
+ when(provider.read(FsPath.absolute("/db1/table1"), 5))
+ .thenReturn(Arrays.asList(SqlRow.of("Time", "1", "tag1", "a", "s1",
"42")));
+
+ assertTrue(shell.execute("head -n 5 /db1/table1"));
+
+ assertTrue(out.toString().contains("1\ta\t42"));
+ verify(provider).read(FsPath.absolute("/db1/table1"), 5);
+ }
+
@Test
public void executePasteReadsMultiplePaths() throws SQLException {
when(provider.read(
diff --git
a/iotdb-client/cli/src/test/java/org/apache/iotdb/cli/fs/command/FilesystemCommandParserTest.java
b/iotdb-client/cli/src/test/java/org/apache/iotdb/cli/fs/command/FilesystemCommandParserTest.java
index 360e5cbe593..2816912ab0b 100644
---
a/iotdb-client/cli/src/test/java/org/apache/iotdb/cli/fs/command/FilesystemCommandParserTest.java
+++
b/iotdb-client/cli/src/test/java/org/apache/iotdb/cli/fs/command/FilesystemCommandParserTest.java
@@ -43,6 +43,14 @@ public class FilesystemCommandParserTest {
assertEquals("/db1", command.getPath());
}
+ @Test
+ public void parseLsLongOptionAsLongListCommand() {
+ FilesystemCommand command = FilesystemCommandParser.parse("ls -la /db1");
+
+ assertEquals(FilesystemCommand.Type.LL, command.getType());
+ assertEquals("/db1", command.getPath());
+ }
+
@Test
public void parsePathCommand() {
FilesystemCommand command = FilesystemCommandParser.parse(" ls /root/sg
");
@@ -59,6 +67,26 @@ public class FilesystemCommandParserTest {
assertEquals("/db1/table1", command.getPath());
}
+ @Test
+ public void parseCatMultiplePaths() {
+ FilesystemCommand command =
+ FilesystemCommandParser.parse("cat /db1/table1/tag1 /db1/table1/s1");
+
+ assertEquals(FilesystemCommand.Type.CAT, command.getType());
+ assertEquals(2, command.getPaths().size());
+ assertEquals("/db1/table1/tag1", command.getPaths().get(0));
+ assertEquals("/db1/table1/s1", command.getPaths().get(1));
+ }
+
+ @Test
+ public void parseHeadLimitAndPath() {
+ FilesystemCommand command = FilesystemCommandParser.parse("head -n 5
/db1/table1");
+
+ assertEquals(FilesystemCommand.Type.HEAD, command.getType());
+ assertEquals("/db1/table1", command.getPath());
+ assertEquals(5, command.getLimit());
+ }
+
@Test
public void parsePastePaths() {
FilesystemCommand command =