You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hugegraph.apache.org by ji...@apache.org on 2026/10/12 02:16:57 UTC
(hugegraph-toolchain) branch master updated: fix(loader): accept response file arguments (#808)
This is an automated email from the ASF dual-hosted git repository.
imbajin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/hugegraph-toolchain.git
The following commit(s) were added to refs/heads/master by this push:
new 2692b6bf9 fix(loader): accept response file arguments (#808)
2692b6bf9 is described below
commit 2692b6bf9dbf41111a6e5bc04241f1d5236a245e
Author: imbajin <ji...@apache.org>
AuthorDate: Mon Oct 12 10:16:52 2026 +0800
fix(loader): accept response file arguments (#808)
- rely on required options and validators after expansion
- cover response files, defaults, and invalid parser input
- document private argument files and writable mappings
---
hugegraph-loader/README.md | 21 +++++++
.../hugegraph/loader/executor/LoadOptions.java | 4 --
.../loader/test/unit/LoadOptionsTest.java | 68 +++++++++++++++++++++-
3 files changed, 86 insertions(+), 7 deletions(-)
diff --git a/hugegraph-loader/README.md b/hugegraph-loader/README.md
index 9b6342b06..e3254db3e 100644
--- a/hugegraph-loader/README.md
+++ b/hugegraph-loader/README.md
@@ -109,6 +109,27 @@ sh bin/hugegraph-loader.sh -g hugegraph -f example/file/struct.json -s example/f
More details is in the [doc](https://hugegraph.apache.org/docs/quickstart/hugegraph-loader/)
+#### Arguments from a file
+
+The launcher accepts JCommander's `@file` syntax. Put each option and its value on separate lines:
+
+```text
+--graph
+hugegraph
+--file
+example/file/struct.json
+--schema
+example/file/schema.groovy
+```
+
+```bash
+bash bin/hugegraph-loader.sh @loader.args
+```
+
+Paths in the argument file resolve from the working directory. Protect files containing credentials with mode `0600`;
+the credentials can then stay out of the process arguments. The mapping directory must be writable for progress output,
+so copy a mapping mounted from a read-only Kubernetes ConfigMap to a writable volume before running Loader.
+
### 3.2 Load data with docker
> If the `loader` and `server` is in the same docker network (for example, you deploy `loader` and `server` with `docker-compose`), we can set `-h {server_container_name}`. In our example, the container name of `server` is `graph`
diff --git a/hugegraph-loader/src/main/java/org/apache/hugegraph/loader/executor/LoadOptions.java b/hugegraph-loader/src/main/java/org/apache/hugegraph/loader/executor/LoadOptions.java
index eb0ed5efb..7c0042f9d 100644
--- a/hugegraph-loader/src/main/java/org/apache/hugegraph/loader/executor/LoadOptions.java
+++ b/hugegraph-loader/src/main/java/org/apache/hugegraph/loader/executor/LoadOptions.java
@@ -48,7 +48,6 @@ public final class LoadOptions implements Cloneable {
private static final int CPUS = Runtime.getRuntime().availableProcessors();
private static final int DEFAULT_MAX_CONNECTIONS = CPUS * 4;
private static final int DEFAULT_MAX_CONNECTIONS_PER_ROUTE = CPUS * 2;
- private static final int MINIMUM_REQUIRED_ARGS = 3;
private static final Set<String> SENSITIVE_PARAMETER_FIELDS =
ImmutableSet.of("password", "trustStoreToken", "token", "pdToken");
@@ -388,9 +387,6 @@ public final class LoadOptions implements Cloneable {
if (options.help) {
LoadUtil.exitWithUsage(commander, Constants.EXIT_CODE_NORM);
}
- if (args.length < MINIMUM_REQUIRED_ARGS) {
- LoadUtil.exitWithUsage(commander, Constants.EXIT_CODE_ERROR);
- }
// Check options
// Check option "-f"
E.checkArgument(!StringUtils.isEmpty(options.file),
diff --git a/hugegraph-loader/src/test/java/org/apache/hugegraph/loader/test/unit/LoadOptionsTest.java b/hugegraph-loader/src/test/java/org/apache/hugegraph/loader/test/unit/LoadOptionsTest.java
index 82bc8d13a..aa16276e8 100644
--- a/hugegraph-loader/src/test/java/org/apache/hugegraph/loader/test/unit/LoadOptionsTest.java
+++ b/hugegraph-loader/src/test/java/org/apache/hugegraph/loader/test/unit/LoadOptionsTest.java
@@ -48,7 +48,7 @@ public class LoadOptionsTest {
"--port", "not-an-integer");
assertParserExit(false, "--unknown-option");
assertParserExit(false);
- assertParserExit(false, "--file", mapping.getPath());
+ assertParserExit(false, "--file");
assertParserExit(true, "--help");
assertParserExit(true, "-help");
} finally {
@@ -57,6 +57,64 @@ public class LoadOptionsTest {
}
private static void assertParserExit(boolean help, String... args) throws Exception {
+ assertParserExit(help, true, args);
+ }
+
+ @Test
+ public void testRequiredMappingOptionUsesDefaults() throws Exception {
+ File mapping = createTempMapping();
+ try {
+ assertParserExit(true, false, "--file", mapping.getPath());
+ LoadOptions options = LoadOptions.parseOptions(new String[]{"--file", mapping.getPath()});
+ Assert.assertEquals(mapping.getPath(), options.file);
+ Assert.assertEquals("hugegraph", options.graph);
+ Assert.assertEquals("http://localhost", options.host);
+ } finally {
+ mapping.delete();
+ }
+ }
+
+ @Test
+ public void testResponseFileOptions() throws Exception {
+ File mapping = createTempMapping();
+ File arguments = File.createTempFile("loader arguments-", ".args", new File("."));
+ try {
+ Files.write(arguments.toPath(), Arrays.asList("--file", mapping.getPath(),
+ "--graph", "response-file-graph",
+ "--parser-threads", "2"),
+ StandardCharsets.UTF_8);
+ String[] args = new String[]{"@" + arguments.getPath()};
+ assertParserExit(true, false, args);
+ LoadOptions options = LoadOptions.parseOptions(args);
+ Assert.assertEquals(mapping.getPath(), options.file);
+ Assert.assertEquals("response-file-graph", options.graph);
+ Assert.assertEquals(2, options.parseThreads);
+ } finally {
+ arguments.delete();
+ mapping.delete();
+ }
+ }
+
+ @Test
+ public void testInvalidResponseFileOptionsExitNonzero() throws Exception {
+ File mapping = createTempMapping();
+ File arguments = File.createTempFile("loader-invalid-", ".args", new File("."));
+ try {
+ Files.write(arguments.toPath(), Arrays.asList("--graph", "missing-mapping"),
+ StandardCharsets.UTF_8);
+ assertParserExit(false, "@" + arguments.getPath());
+ Files.write(arguments.toPath(), Arrays.asList("--file", mapping.getPath(),
+ "--port", "not-an-integer"),
+ StandardCharsets.UTF_8);
+ assertParserExit(false, "@" + arguments.getPath());
+ } finally {
+ arguments.delete();
+ mapping.delete();
+ }
+ }
+
+ private static void assertParserExit(boolean success, boolean expectUsage,
+ String... args) throws Exception {
List<String> command = new ArrayList<>();
command.add(new File(System.getProperty("java.home"), "bin/java").getPath());
command.add("-Xmx128m");
@@ -71,8 +129,12 @@ public class LoadOptionsTest {
try {
Assert.assertTrue("Parser process timed out", process.waitFor(20, TimeUnit.SECONDS));
String usage = new String(Files.readAllBytes(output.toPath()), StandardCharsets.UTF_8);
- Assert.assertTrue(usage, usage.contains("Usage:") && usage.contains("--file"));
- if (help) {
+ if (expectUsage) {
+ Assert.assertTrue(usage, usage.contains("Usage:") && usage.contains("--file"));
+ } else {
+ Assert.assertFalse(usage, usage.contains("Usage:"));
+ }
+ if (success) {
Assert.assertEquals(0, process.exitValue());
} else {
Assert.assertTrue(usage, process.exitValue() != 0);