This is an automated email from the ASF dual-hosted git repository.
shaofengshi pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/gravitino.git
The following commit(s) were added to refs/heads/main by this push:
new 7a42199a5 [#5379] Add basic Fileset commands to Gravitno CLI (#5380)
7a42199a5 is described below
commit 7a42199a5fcaa02eaa8053cfec5b6f7b3dab3850
Author: Justin Mclean <[email protected]>
AuthorDate: Fri Nov 29 13:20:46 2024 +1100
[#5379] Add basic Fileset commands to Gravitno CLI (#5380)
### What changes were proposed in this pull request?
Added basic Fileset commands to Gravitno CLI
### Why are the changes needed?
To expand Gravitino CLI support.
Fix: #5379
### Does this PR introduce _any_ user-facing change?
No, but it adds extra commands to the Gravitino CLI.
### How was this patch tested?
Compiled and tested locally.
---
.../org/apache/gravitino/cli/CommandEntities.java | 2 +
.../org/apache/gravitino/cli/ErrorMessages.java | 2 +
.../java/org/apache/gravitino/cli/FullName.java | 15 +-
.../apache/gravitino/cli/GravitinoCommandLine.java | 29 ++++
.../org/apache/gravitino/cli/GravitinoOptions.java | 6 +-
.../java/org/apache/gravitino/cli/Properties.java | 18 ++-
.../apache/gravitino/cli/TestableCommandLine.java | 37 +++++
.../gravitino/cli/commands/CreateFileset.java | 103 ++++++++++++
.../gravitino/cli/commands/DeleteFileset.java | 102 ++++++++++++
.../gravitino/cli/commands/FilesetDetails.java | 101 ++++++++++++
.../gravitino/cli/commands/ListFilesets.java | 82 ++++++++++
.../apache/gravitino/cli/TestCommandEntities.java | 2 +
.../apache/gravitino/cli/TestFilesetCommands.java | 175 +++++++++++++++++++++
docs/cli.md | 32 +++-
14 files changed, 691 insertions(+), 15 deletions(-)
diff --git
a/clients/cli/src/main/java/org/apache/gravitino/cli/CommandEntities.java
b/clients/cli/src/main/java/org/apache/gravitino/cli/CommandEntities.java
index a68703a13..aaf10e8e1 100644
--- a/clients/cli/src/main/java/org/apache/gravitino/cli/CommandEntities.java
+++ b/clients/cli/src/main/java/org/apache/gravitino/cli/CommandEntities.java
@@ -34,6 +34,7 @@ public class CommandEntities {
public static final String USER = "user";
public static final String GROUP = "group";
public static final String TAG = "tag";
+ public static final String FILESET = "fileset";
public static final String ROLE = "role";
private static final HashSet<String> VALID_ENTITIES = new HashSet<>();
@@ -47,6 +48,7 @@ public class CommandEntities {
VALID_ENTITIES.add(USER);
VALID_ENTITIES.add(GROUP);
VALID_ENTITIES.add(TAG);
+ VALID_ENTITIES.add(FILESET);
VALID_ENTITIES.add(ROLE);
}
diff --git
a/clients/cli/src/main/java/org/apache/gravitino/cli/ErrorMessages.java
b/clients/cli/src/main/java/org/apache/gravitino/cli/ErrorMessages.java
index 3c7870968..873ded785 100644
--- a/clients/cli/src/main/java/org/apache/gravitino/cli/ErrorMessages.java
+++ b/clients/cli/src/main/java/org/apache/gravitino/cli/ErrorMessages.java
@@ -41,6 +41,8 @@ public class ErrorMessages {
public static final String MULTIPLE_TAG_COMMAND_ERROR =
"Error: The current command only supports one --tag option.";
public static final String TAG_EXISTS = "Tag already exists.";
+ public static final String UNKNOWN_FILESET = "Unknown fileset.";
+ public static final String FILESET_EXISTS = "Fileset already exists.";
public static final String TAG_EMPTY = "Error: Must configure --tag option.";
public static final String UNKNOWN_ROLE = "Unknown role.";
public static final String ROLE_EXISTS = "Role already exists.";
diff --git a/clients/cli/src/main/java/org/apache/gravitino/cli/FullName.java
b/clients/cli/src/main/java/org/apache/gravitino/cli/FullName.java
index 48b68bb44..3c53401ca 100644
--- a/clients/cli/src/main/java/org/apache/gravitino/cli/FullName.java
+++ b/clients/cli/src/main/java/org/apache/gravitino/cli/FullName.java
@@ -80,7 +80,7 @@ public class FullName {
}
/**
- * Retrieves the catalog name from the second part of the full name option.
+ * Retrieves the catalog name from the first part of the full name option.
*
* @return The catalog name, or null if not found.
*/
@@ -89,7 +89,7 @@ public class FullName {
}
/**
- * Retrieves the schema name from the third part of the full name option.
+ * Retrieves the schema name from the second part of the full name option.
*
* @return The schema name, or null if not found.
*/
@@ -98,7 +98,7 @@ public class FullName {
}
/**
- * Retrieves the table name from the fourth part of the full name option.
+ * Retrieves the table name from the third part of the full name option.
*
* @return The table name, or null if not found.
*/
@@ -106,6 +106,15 @@ public class FullName {
return getNamePart(2);
}
+ /**
+ * Retrieves the fileset name from the third part of the full name option.
+ *
+ * @return The table name, or null if not found.
+ */
+ public String getFilesetName() {
+ return getNamePart(2);
+ }
+
/**
* Helper method to retrieve a specific part of the full name based on the
position of the part.
*
diff --git
a/clients/cli/src/main/java/org/apache/gravitino/cli/GravitinoCommandLine.java
b/clients/cli/src/main/java/org/apache/gravitino/cli/GravitinoCommandLine.java
index a4b41b12e..cc2147c02 100644
---
a/clients/cli/src/main/java/org/apache/gravitino/cli/GravitinoCommandLine.java
+++
b/clients/cli/src/main/java/org/apache/gravitino/cli/GravitinoCommandLine.java
@@ -124,6 +124,8 @@ public class GravitinoCommandLine extends
TestableCommandLine {
handleCatalogCommand();
} else if (entity.equals(CommandEntities.METALAKE)) {
handleMetalakeCommand();
+ } else if (entity.equals(CommandEntities.FILESET)) {
+ handleFilesetCommand();
} else if (entity.equals(CommandEntities.USER)) {
handleUserCommand();
} else if (entity.equals(CommandEntities.GROUP)) {
@@ -489,6 +491,33 @@ public class GravitinoCommandLine extends
TestableCommandLine {
}
}
+ /**
+ * Handles the command execution for filesets based on command type and the
command line options.
+ */
+ private void handleFilesetCommand() {
+ String url = getUrl();
+ FullName name = new FullName(line);
+ String metalake = name.getMetalakeName();
+ String catalog = name.getCatalogName();
+ String schema = name.getSchemaName();
+ String fileset = name.getFilesetName();
+
+ if (CommandActions.DETAILS.equals(command)) {
+ newFilesetDetails(url, ignore, metalake, catalog, schema,
fileset).handle();
+ } else if (CommandActions.LIST.equals(command)) {
+ newListFilesets(url, ignore, metalake, catalog, schema).handle();
+ } else if (CommandActions.CREATE.equals(command)) {
+ String comment = line.getOptionValue(GravitinoOptions.COMMENT);
+ String[] properties = line.getOptionValues(GravitinoOptions.PROPERTIES);
+ Map<String, String> propertyMap = new Properties().parse(properties);
+ newCreateFileset(url, ignore, metalake, catalog, schema, fileset,
comment, propertyMap)
+ .handle();
+ } else if (CommandActions.DELETE.equals(command)) {
+ boolean force = line.hasOption(GravitinoOptions.FORCE);
+ newDeleteFileset(url, ignore, force, metalake, catalog, schema,
fileset).handle();
+ }
+ }
+
/**
* Retrieves the Gravitinno URL from the command line options or the
GRAVITINO_URL environment
* variable or the Gravitio config file.
diff --git
a/clients/cli/src/main/java/org/apache/gravitino/cli/GravitinoOptions.java
b/clients/cli/src/main/java/org/apache/gravitino/cli/GravitinoOptions.java
index dd9fedd7a..ee3e09472 100644
--- a/clients/cli/src/main/java/org/apache/gravitino/cli/GravitinoOptions.java
+++ b/clients/cli/src/main/java/org/apache/gravitino/cli/GravitinoOptions.java
@@ -65,9 +65,9 @@ public class GravitinoOptions {
options.addOption(createArgOption("m", METALAKE, "metalake name"));
options.addOption(createSimpleOption("i", IGNORE, "ignore client/sever
version check"));
options.addOption(createSimpleOption("a", AUDIT, "display audit
information"));
- options.addOption(createSimpleOption("x", INDEX, "Display index
infromation"));
- options.addOption(createSimpleOption("d", DISTRIBUTION, "Display
distribution information"));
- options.addOption(createSimpleOption(null, PARTITION, "Display partition
information"));
+ options.addOption(createSimpleOption("x", INDEX, "display index
information"));
+ options.addOption(createSimpleOption("d", DISTRIBUTION, "display
distribution information"));
+ options.addOption(createSimpleOption(null, PARTITION, "display partition
information"));
// Create/update options
options.addOption(createArgOption(null, RENAME, "new entity name"));
diff --git a/clients/cli/src/main/java/org/apache/gravitino/cli/Properties.java
b/clients/cli/src/main/java/org/apache/gravitino/cli/Properties.java
index 1c166102f..16213976c 100644
--- a/clients/cli/src/main/java/org/apache/gravitino/cli/Properties.java
+++ b/clients/cli/src/main/java/org/apache/gravitino/cli/Properties.java
@@ -61,14 +61,16 @@ public class Properties {
public Map<String, String> parse(String[] inputs) {
HashMap<String, String> map = new HashMap<>();
- for (String input : inputs) {
- // Split the input by the delimiter into key-value pairs
- String[] pairs = input.split(delimiter);
- for (String pair : pairs) {
- // Split each key-value pair by the separator
- String[] keyValue = pair.split(keyValueSeparator, 2);
- if (keyValue.length == 2) {
- map.put(keyValue[0].trim(), keyValue[1].trim());
+ if (inputs != null) {
+ for (String input : inputs) {
+ // Split the input by the delimiter into key-value pairs
+ String[] pairs = input.split(delimiter);
+ for (String pair : pairs) {
+ // Split each key-value pair by the separator
+ String[] keyValue = pair.split(keyValueSeparator, 2);
+ if (keyValue.length == 2) {
+ map.put(keyValue[0].trim(), keyValue[1].trim());
+ }
}
}
}
diff --git
a/clients/cli/src/main/java/org/apache/gravitino/cli/TestableCommandLine.java
b/clients/cli/src/main/java/org/apache/gravitino/cli/TestableCommandLine.java
index 94435160d..1df28658b 100644
---
a/clients/cli/src/main/java/org/apache/gravitino/cli/TestableCommandLine.java
+++
b/clients/cli/src/main/java/org/apache/gravitino/cli/TestableCommandLine.java
@@ -27,6 +27,7 @@ import org.apache.gravitino.cli.commands.CatalogAudit;
import org.apache.gravitino.cli.commands.CatalogDetails;
import org.apache.gravitino.cli.commands.ClientVersion;
import org.apache.gravitino.cli.commands.CreateCatalog;
+import org.apache.gravitino.cli.commands.CreateFileset;
import org.apache.gravitino.cli.commands.CreateGroup;
import org.apache.gravitino.cli.commands.CreateMetalake;
import org.apache.gravitino.cli.commands.CreateRole;
@@ -34,6 +35,7 @@ import org.apache.gravitino.cli.commands.CreateSchema;
import org.apache.gravitino.cli.commands.CreateTag;
import org.apache.gravitino.cli.commands.CreateUser;
import org.apache.gravitino.cli.commands.DeleteCatalog;
+import org.apache.gravitino.cli.commands.DeleteFileset;
import org.apache.gravitino.cli.commands.DeleteGroup;
import org.apache.gravitino.cli.commands.DeleteMetalake;
import org.apache.gravitino.cli.commands.DeleteRole;
@@ -41,12 +43,14 @@ import org.apache.gravitino.cli.commands.DeleteSchema;
import org.apache.gravitino.cli.commands.DeleteTable;
import org.apache.gravitino.cli.commands.DeleteTag;
import org.apache.gravitino.cli.commands.DeleteUser;
+import org.apache.gravitino.cli.commands.FilesetDetails;
import org.apache.gravitino.cli.commands.GroupDetails;
import org.apache.gravitino.cli.commands.ListAllTags;
import org.apache.gravitino.cli.commands.ListCatalogProperties;
import org.apache.gravitino.cli.commands.ListCatalogs;
import org.apache.gravitino.cli.commands.ListColumns;
import org.apache.gravitino.cli.commands.ListEntityTags;
+import org.apache.gravitino.cli.commands.ListFilesets;
import org.apache.gravitino.cli.commands.ListGroups;
import org.apache.gravitino.cli.commands.ListIndexes;
import org.apache.gravitino.cli.commands.ListMetalakeProperties;
@@ -442,4 +446,37 @@ public class TestableCommandLine {
String url, boolean ignore, String metalake, String entity, String
entityType) {
return new OwnerDetails(url, ignore, metalake, entity, entityType);
}
+
+ protected FilesetDetails newFilesetDetails(
+ String url, boolean ignore, String metalake, String catalog, String
schema, String fileset) {
+ return new FilesetDetails(url, ignore, metalake, catalog, schema, fileset);
+ }
+
+ protected ListFilesets newListFilesets(
+ String url, boolean ignore, String metalake, String catalog, String
schema) {
+ return new ListFilesets(url, ignore, metalake, catalog, schema);
+ }
+
+ protected CreateFileset newCreateFileset(
+ String url,
+ boolean ignore,
+ String metalake,
+ String catalog,
+ String schema,
+ String fileset,
+ String comment,
+ Map<String, String> propertyMap) {
+ return new CreateFileset(url, ignore, metalake, catalog, schema, fileset,
comment, propertyMap);
+ }
+
+ protected DeleteFileset newDeleteFileset(
+ String url,
+ boolean ignore,
+ boolean force,
+ String metalake,
+ String catalog,
+ String schema,
+ String fileset) {
+ return new DeleteFileset(url, ignore, force, metalake, catalog, schema,
fileset);
+ }
}
diff --git
a/clients/cli/src/main/java/org/apache/gravitino/cli/commands/CreateFileset.java
b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/CreateFileset.java
new file mode 100644
index 000000000..bc109fcc5
--- /dev/null
+++
b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/CreateFileset.java
@@ -0,0 +1,103 @@
+/*
+ * 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.gravitino.cli.commands;
+
+import java.util.Map;
+import org.apache.gravitino.NameIdentifier;
+import org.apache.gravitino.cli.ErrorMessages;
+import org.apache.gravitino.client.GravitinoClient;
+import org.apache.gravitino.exceptions.FilesetAlreadyExistsException;
+import org.apache.gravitino.exceptions.NoSuchCatalogException;
+import org.apache.gravitino.exceptions.NoSuchMetalakeException;
+import org.apache.gravitino.exceptions.NoSuchSchemaException;
+import org.apache.gravitino.file.Fileset;
+
+public class CreateFileset extends Command {
+ protected final String metalake;
+ protected final String catalog;
+ protected final String schema;
+ protected final String fileset;
+ protected final String comment;
+ protected final Map<String, String> properties;
+
+ /**
+ * Create a new fileset.
+ *
+ * @param url The URL of the Gravitino server.
+ * @param ignoreVersions If true don't check the client/server versions
match.
+ * @param metalake The name of the metalake.
+ * @param catalog The name of the catalog.
+ * @param schema The name of the schema.
+ * @param fileset The name of the fileset.
+ * @param comment The fileset's comment.
+ * @param properties The catalog's properties.
+ */
+ public CreateFileset(
+ String url,
+ boolean ignoreVersions,
+ String metalake,
+ String catalog,
+ String schema,
+ String fileset,
+ String comment,
+ Map<String, String> properties) {
+ super(url, ignoreVersions);
+ this.metalake = metalake;
+ this.catalog = catalog;
+ this.schema = schema;
+ this.fileset = fileset;
+ this.comment = comment;
+ this.properties = properties;
+ }
+
+ /** Create a new fileset. */
+ @Override
+ public void handle() {
+ NameIdentifier name = NameIdentifier.of(schema, fileset);
+ boolean managed = properties.get("managed").equals("true");
+ String location = properties.get("location");
+ Fileset.Type filesetType = managed ? Fileset.Type.MANAGED :
Fileset.Type.EXTERNAL;
+
+ try {
+ GravitinoClient client = buildClient(metalake);
+ client
+ .loadCatalog(catalog)
+ .asFilesetCatalog()
+ .createFileset(name, comment, filesetType, location, null);
+ } catch (NoSuchMetalakeException err) {
+ System.err.println(ErrorMessages.UNKNOWN_METALAKE);
+ return;
+ } catch (NoSuchCatalogException err) {
+ System.err.println(ErrorMessages.UNKNOWN_CATALOG);
+ return;
+ } catch (NoSuchSchemaException err) {
+ System.err.println(ErrorMessages.UNKNOWN_SCHEMA);
+ return;
+ } catch (FilesetAlreadyExistsException err) {
+ System.err.println(ErrorMessages.FILESET_EXISTS);
+ return;
+ } catch (Exception exp) {
+ System.err.println(exp.getMessage());
+ return;
+ }
+
+ System.out.println(fileset + " created");
+ }
+}
diff --git
a/clients/cli/src/main/java/org/apache/gravitino/cli/commands/DeleteFileset.java
b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/DeleteFileset.java
new file mode 100644
index 000000000..bc76dcb26
--- /dev/null
+++
b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/DeleteFileset.java
@@ -0,0 +1,102 @@
+/*
+ * 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.gravitino.cli.commands;
+
+import org.apache.gravitino.NameIdentifier;
+import org.apache.gravitino.cli.AreYouSure;
+import org.apache.gravitino.cli.ErrorMessages;
+import org.apache.gravitino.client.GravitinoClient;
+import org.apache.gravitino.exceptions.NoSuchCatalogException;
+import org.apache.gravitino.exceptions.NoSuchFilesetException;
+import org.apache.gravitino.exceptions.NoSuchMetalakeException;
+import org.apache.gravitino.exceptions.NoSuchSchemaException;
+
+public class DeleteFileset extends Command {
+
+ protected final String metalake;
+ protected final String catalog;
+ protected final String schema;
+ protected final String fileset;
+ protected final boolean force;
+
+ /**
+ * Delete a fileset.
+ *
+ * @param url The URL of the Gravitino server.
+ * @param ignoreVersions If true don't check the client/server versions
match.
+ * @param force Force operation.
+ * @param metalake The name of the metalake.
+ * @param catalog The name of the catalog.
+ * @param schema The name of the schema.
+ * @param fileset The name of the fileset.
+ */
+ public DeleteFileset(
+ String url,
+ boolean ignoreVersions,
+ boolean force,
+ String metalake,
+ String catalog,
+ String schema,
+ String fileset) {
+ super(url, ignoreVersions);
+ this.force = force;
+ this.metalake = metalake;
+ this.catalog = catalog;
+ this.schema = schema;
+ this.fileset = fileset;
+ }
+
+ /** Delete a fileset. */
+ @Override
+ public void handle() {
+ NameIdentifier name = NameIdentifier.of(schema, fileset);
+ boolean deleted = false;
+
+ if (!AreYouSure.really(force)) {
+ return;
+ }
+
+ try {
+ GravitinoClient client = buildClient(metalake);
+ deleted =
client.loadCatalog(catalog).asFilesetCatalog().dropFileset(name);
+ } catch (NoSuchMetalakeException err) {
+ System.err.println(ErrorMessages.UNKNOWN_METALAKE);
+ return;
+ } catch (NoSuchCatalogException err) {
+ System.err.println(ErrorMessages.UNKNOWN_CATALOG);
+ return;
+ } catch (NoSuchSchemaException err) {
+ System.err.println(ErrorMessages.UNKNOWN_SCHEMA);
+ return;
+ } catch (NoSuchFilesetException err) {
+ System.err.println(ErrorMessages.UNKNOWN_FILESET);
+ return;
+ } catch (Exception exp) {
+ System.err.println(exp.getMessage());
+ return;
+ }
+
+ if (deleted) {
+ System.out.println(fileset + " deleted.");
+ } else {
+ System.out.println(fileset + " not deleted.");
+ }
+ }
+}
diff --git
a/clients/cli/src/main/java/org/apache/gravitino/cli/commands/FilesetDetails.java
b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/FilesetDetails.java
new file mode 100644
index 000000000..8d7a5d2f3
--- /dev/null
+++
b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/FilesetDetails.java
@@ -0,0 +1,101 @@
+/*
+ * 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.gravitino.cli.commands;
+
+import org.apache.gravitino.NameIdentifier;
+import org.apache.gravitino.cli.ErrorMessages;
+import org.apache.gravitino.client.GravitinoClient;
+import org.apache.gravitino.exceptions.NoSuchCatalogException;
+import org.apache.gravitino.exceptions.NoSuchFilesetException;
+import org.apache.gravitino.exceptions.NoSuchMetalakeException;
+import org.apache.gravitino.exceptions.NoSuchSchemaException;
+import org.apache.gravitino.file.Fileset;
+
+/** Displays the details of fileset. */
+public class FilesetDetails extends Command {
+
+ protected final String metalake;
+ protected final String catalog;
+ protected final String schema;
+ protected final String fileset;
+
+ /**
+ * Displays the details of a fileset.
+ *
+ * @param url The URL of the Gravitino server.
+ * @param ignoreVersions If true don't check the client/server versions
match.
+ * @param metalake The name of the metalake.
+ * @param catalog The name of the catalog.
+ * @param schema The name of the schenma.
+ * @param fileset The name of the fileset.
+ */
+ public FilesetDetails(
+ String url,
+ boolean ignoreVersions,
+ String metalake,
+ String catalog,
+ String schema,
+ String fileset) {
+ super(url, ignoreVersions);
+ this.metalake = metalake;
+ this.catalog = catalog;
+ this.schema = schema;
+ this.fileset = fileset;
+ }
+
+ /** Displays the name and comments of fileset. */
+ @Override
+ public void handle() {
+ NameIdentifier name = NameIdentifier.of(schema, fileset);
+ Fileset result = null;
+
+ try {
+ GravitinoClient client = buildClient(metalake);
+ result =
client.loadCatalog(catalog).asFilesetCatalog().loadFileset(name);
+ } catch (NoSuchMetalakeException err) {
+ System.err.println(ErrorMessages.UNKNOWN_METALAKE);
+ return;
+ } catch (NoSuchCatalogException err) {
+ System.err.println(ErrorMessages.UNKNOWN_CATALOG);
+ return;
+ } catch (NoSuchSchemaException err) {
+ System.err.println(ErrorMessages.UNKNOWN_SCHEMA);
+ return;
+ } catch (NoSuchFilesetException err) {
+ System.err.println(ErrorMessages.UNKNOWN_FILESET);
+ return;
+ } catch (Exception exp) {
+ System.err.println(exp.getMessage());
+ return;
+ }
+
+ if (result != null) {
+ String filesetType = (result.type() == Fileset.Type.MANAGED) ? "managed"
: "external";
+ System.out.println(
+ result.name()
+ + ","
+ + filesetType
+ + ","
+ + result.comment()
+ + ","
+ + result.storageLocation());
+ }
+ }
+}
diff --git
a/clients/cli/src/main/java/org/apache/gravitino/cli/commands/ListFilesets.java
b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/ListFilesets.java
new file mode 100644
index 000000000..428fe9bb1
--- /dev/null
+++
b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/ListFilesets.java
@@ -0,0 +1,82 @@
+/*
+ * 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.gravitino.cli.commands;
+
+import com.google.common.base.Joiner;
+import org.apache.gravitino.NameIdentifier;
+import org.apache.gravitino.Namespace;
+import org.apache.gravitino.cli.ErrorMessages;
+import org.apache.gravitino.client.GravitinoClient;
+import org.apache.gravitino.exceptions.NoSuchCatalogException;
+import org.apache.gravitino.exceptions.NoSuchMetalakeException;
+import org.apache.gravitino.exceptions.NoSuchSchemaException;
+
+/** List all fileset names in a schema. */
+public class ListFilesets extends Command {
+
+ protected final String metalake;
+ protected final String catalog;
+ protected final String schema;
+
+ /**
+ * Lists all filesets in a schema.
+ *
+ * @param url The URL of the Gravitino server.
+ * @param ignoreVersions If true don't check the client/server versions
match.
+ * @param metalake The name of the metalake.
+ * @param catalog The name of the catalog.
+ * @param schema The name of the schema.
+ */
+ public ListFilesets(
+ String url, boolean ignoreVersions, String metalake, String catalog,
String schema) {
+ super(url, ignoreVersions);
+ this.metalake = metalake;
+ this.catalog = catalog;
+ this.schema = schema;
+ }
+
+ /** List all filesets names in a schema. */
+ @Override
+ public void handle() {
+ Namespace name = Namespace.of(schema);
+ NameIdentifier[] filesets = new NameIdentifier[0];
+
+ try {
+ GravitinoClient client = buildClient(metalake);
+ filesets =
client.loadCatalog(catalog).asFilesetCatalog().listFilesets(name);
+ } catch (NoSuchMetalakeException err) {
+ System.err.println(ErrorMessages.UNKNOWN_METALAKE);
+ return;
+ } catch (NoSuchCatalogException err) {
+ System.err.println(ErrorMessages.UNKNOWN_CATALOG);
+ return;
+ } catch (NoSuchSchemaException err) {
+ System.err.println(ErrorMessages.UNKNOWN_SCHEMA);
+ return;
+ } catch (Exception exp) {
+ System.err.println(exp.getMessage());
+ return;
+ }
+
+ String all = Joiner.on(",").join(filesets);
+
+ System.out.println(all.toString());
+ }
+}
diff --git
a/clients/cli/src/test/java/org/apache/gravitino/cli/TestCommandEntities.java
b/clients/cli/src/test/java/org/apache/gravitino/cli/TestCommandEntities.java
index 50743c1f3..5f60d3e7e 100644
---
a/clients/cli/src/test/java/org/apache/gravitino/cli/TestCommandEntities.java
+++
b/clients/cli/src/test/java/org/apache/gravitino/cli/TestCommandEntities.java
@@ -38,6 +38,8 @@ public class TestCommandEntities {
assertTrue(
CommandEntities.isValidEntity(CommandEntities.TABLE), "TABLE should be
a valid entity");
assertTrue(CommandEntities.isValidEntity(CommandEntities.TAG), "TAG should
be a valid entity");
+ assertTrue(
+ CommandEntities.isValidEntity(CommandEntities.FILESET), "FILESET
should be a valid entity");
assertTrue(
CommandEntities.isValidEntity(CommandEntities.ROLE), "ROLE should be a
valid entity");
}
diff --git
a/clients/cli/src/test/java/org/apache/gravitino/cli/TestFilesetCommands.java
b/clients/cli/src/test/java/org/apache/gravitino/cli/TestFilesetCommands.java
new file mode 100644
index 000000000..d7932bde8
--- /dev/null
+++
b/clients/cli/src/test/java/org/apache/gravitino/cli/TestFilesetCommands.java
@@ -0,0 +1,175 @@
+/*
+ * 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.gravitino.cli;
+
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Options;
+import org.apache.gravitino.cli.commands.CreateFileset;
+import org.apache.gravitino.cli.commands.DeleteFileset;
+import org.apache.gravitino.cli.commands.FilesetDetails;
+import org.apache.gravitino.cli.commands.ListFilesets;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+class TestFilesetCommands {
+ private CommandLine mockCommandLine;
+ private Options mockOptions;
+
+ @BeforeEach
+ void setUp() {
+ mockCommandLine = mock(CommandLine.class);
+ mockOptions = mock(Options.class);
+ }
+
+ @Test
+ void testListFilesetsCommand() {
+ ListFilesets mockList = mock(ListFilesets.class);
+
when(mockCommandLine.hasOption(GravitinoOptions.METALAKE)).thenReturn(true);
+
when(mockCommandLine.getOptionValue(CommandEntities.METALAKE)).thenReturn("metalake_demo");
+ when(mockCommandLine.hasOption(GravitinoOptions.NAME)).thenReturn(true);
+
when(mockCommandLine.getOptionValue(GravitinoOptions.NAME)).thenReturn("catalog.schema");
+ GravitinoCommandLine commandLine =
+ spy(
+ new GravitinoCommandLine(
+ mockCommandLine, mockOptions, CommandEntities.FILESET,
CommandActions.LIST));
+ doReturn(mockList)
+ .when(commandLine)
+ .newListFilesets(
+ GravitinoCommandLine.DEFAULT_URL, false, "metalake_demo",
"catalog", "schema");
+ commandLine.handleCommandLine();
+ verify(mockList).handle();
+ }
+
+ @Test
+ void testFilesetDetailsCommand() {
+ FilesetDetails mockDetails = mock(FilesetDetails.class);
+
when(mockCommandLine.hasOption(GravitinoOptions.METALAKE)).thenReturn(true);
+
when(mockCommandLine.getOptionValue(GravitinoOptions.METALAKE)).thenReturn("metalake_demo");
+ when(mockCommandLine.hasOption(GravitinoOptions.NAME)).thenReturn(true);
+ when(mockCommandLine.getOptionValue(GravitinoOptions.NAME))
+ .thenReturn("catalog.schema.fileset");
+ GravitinoCommandLine commandLine =
+ spy(
+ new GravitinoCommandLine(
+ mockCommandLine, mockOptions, CommandEntities.FILESET,
CommandActions.DETAILS));
+ doReturn(mockDetails)
+ .when(commandLine)
+ .newFilesetDetails(
+ GravitinoCommandLine.DEFAULT_URL,
+ false,
+ "metalake_demo",
+ "catalog",
+ "schema",
+ "fileset");
+ commandLine.handleCommandLine();
+ verify(mockDetails).handle();
+ }
+
+ @Test
+ void testCreateFilesetCommand() {
+ CreateFileset mockCreate = mock(CreateFileset.class);
+
when(mockCommandLine.hasOption(GravitinoOptions.METALAKE)).thenReturn(true);
+
when(mockCommandLine.getOptionValue(GravitinoOptions.METALAKE)).thenReturn("metalake_demo");
+ when(mockCommandLine.hasOption(GravitinoOptions.NAME)).thenReturn(true);
+ when(mockCommandLine.getOptionValue(GravitinoOptions.NAME))
+ .thenReturn("catalog.schema.fileset");
+ when(mockCommandLine.hasOption(GravitinoOptions.COMMENT)).thenReturn(true);
+
when(mockCommandLine.getOptionValue(GravitinoOptions.COMMENT)).thenReturn("comment");
+
+ GravitinoCommandLine commandLine =
+ spy(
+ new GravitinoCommandLine(
+ mockCommandLine, mockOptions, CommandEntities.FILESET,
CommandActions.CREATE));
+ doReturn(mockCreate)
+ .when(commandLine)
+ .newCreateFileset(
+ eq(GravitinoCommandLine.DEFAULT_URL),
+ eq(false),
+ eq("metalake_demo"),
+ eq("catalog"),
+ eq("schema"),
+ eq("fileset"),
+ eq("comment"),
+ any());
+ commandLine.handleCommandLine();
+ verify(mockCreate).handle();
+ }
+
+ @Test
+ void testDeleteFilesetCommand() {
+ DeleteFileset mockDelete = mock(DeleteFileset.class);
+
when(mockCommandLine.hasOption(GravitinoOptions.METALAKE)).thenReturn(true);
+
when(mockCommandLine.getOptionValue(GravitinoOptions.METALAKE)).thenReturn("metalake_demo");
+ when(mockCommandLine.hasOption(GravitinoOptions.NAME)).thenReturn(true);
+ when(mockCommandLine.getOptionValue(GravitinoOptions.NAME))
+ .thenReturn("catalog.schema.fileset");
+ GravitinoCommandLine commandLine =
+ spy(
+ new GravitinoCommandLine(
+ mockCommandLine, mockOptions, CommandEntities.FILESET,
CommandActions.DELETE));
+ doReturn(mockDelete)
+ .when(commandLine)
+ .newDeleteFileset(
+ GravitinoCommandLine.DEFAULT_URL,
+ false,
+ false,
+ "metalake_demo",
+ "catalog",
+ "schema",
+ "fileset");
+ commandLine.handleCommandLine();
+ verify(mockDelete).handle();
+ }
+
+ @Test
+ void testDeleteFilesetForceCommand() {
+ DeleteFileset mockDelete = mock(DeleteFileset.class);
+
when(mockCommandLine.hasOption(GravitinoOptions.METALAKE)).thenReturn(true);
+
when(mockCommandLine.getOptionValue(GravitinoOptions.METALAKE)).thenReturn("metalake_demo");
+ when(mockCommandLine.hasOption(GravitinoOptions.NAME)).thenReturn(true);
+ when(mockCommandLine.getOptionValue(GravitinoOptions.NAME))
+ .thenReturn("catalog.schema.fileset");
+ when(mockCommandLine.hasOption(GravitinoOptions.FORCE)).thenReturn(true);
+ GravitinoCommandLine commandLine =
+ spy(
+ new GravitinoCommandLine(
+ mockCommandLine, mockOptions, CommandEntities.FILESET,
CommandActions.DELETE));
+ doReturn(mockDelete)
+ .when(commandLine)
+ .newDeleteFileset(
+ GravitinoCommandLine.DEFAULT_URL,
+ false,
+ true,
+ "metalake_demo",
+ "catalog",
+ "schema",
+ "fileset");
+ commandLine.handleCommandLine();
+ verify(mockDelete).handle();
+ }
+}
diff --git a/docs/cli.md b/docs/cli.md
index dbbbca7cb..856e591a4 100644
--- a/docs/cli.md
+++ b/docs/cli.md
@@ -28,10 +28,11 @@ The general structure for running commands with the
Gravitino CLI is `gcli entit
```bash
[options]
- usage: gcli [metalake|catalog|schema|table|column|user|group|tag]
[list|details|create|delete|update|set|remove|properties|revoke|grant] [options]
+ usage: gcli [metalake|catalog|schema|table|column|user|group|tag|fileset]
[list|details|create|delete|update|set|remove|properties|revoke|grant] [options]
Options
-a,--audit display audit information
-c,--comment <arg> entity comment
+ -d,--distribution display distribution information
-f,--force force operation
-g,--group <arg> group name
-h,--help command help information
@@ -39,8 +40,10 @@ The general structure for running commands with the
Gravitino CLI is `gcli entit
-l,--user <arg> user name
-m,--metalake <arg> metalake name
-n,--name <arg> full entity name (dot separated)
+ -o,--owner entity owner
-P,--property <arg> property name
-p,--properties <arg> property name/value pairs
+ --partition display partition information
-r,--role <arg> role name
--rename <arg> new entity name
-s,--server Gravitino server version
@@ -48,6 +51,7 @@ The general structure for running commands with the Gravitino
CLI is `gcli entit
-u,--url <arg> Gravitino URL (default: http://localhost:8090)
-v,--version Gravitino client version
-V,--value <arg> property value
+ -x,--index display index information
-z,--provider <arg> provider one of hadoop, hive, mysql, postgres,
iceberg, kafka
```
@@ -591,3 +595,29 @@ gcli group grant --group groupA --role admin
```bash
gcli group revoke --group groupA --role admin
```
+
+### Fileset commands
+
+#### Create a fileset
+
+```bash
+gcli fileset create --name hadoop.schema.fileset --properties
managed=true,location=file:/tmp/root/schema/example
+```
+
+#### List filesets
+
+```bash
+gcli fileset list --name hadoop.schema
+```
+
+#### Display a fileset's details
+
+```bash
+gcli fileset details --name hadoop.schema.fileset
+```
+
+#### Delete a fileset
+
+```bash
+gcli fileset delete --name hadoop.schema.fileset
+```