diff --git a/src/main/java/org/spdx/tools/CompareSpdxDocs.java b/src/main/java/org/spdx/tools/CompareSpdxDocs.java
index fdc9629..984c1f8 100644
--- a/src/main/java/org/spdx/tools/CompareSpdxDocs.java
+++ b/src/main/java/org/spdx/tools/CompareSpdxDocs.java
@@ -44,37 +44,63 @@
* where output.xls is a file name for the output spreadsheet file
* and docX are SPDX document files to compare or directories containing SPDX documents.
* Document files can be either in RDF/XML or tag/value format
+ *
+ * Exit codes:
+ *
+ * - 0 - the documents were compared and the output spreadsheet was written
+ * - 1 - the comparison failed, or the output spreadsheet could not be written
+ * - 2 - the command was invoked incorrectly (missing/invalid arguments)
+ *
*
* @author Gary O'Neall
*/
public class CompareSpdxDocs {
static final int MIN_ARGS = 2;
static final int MAX_ARGS = MultiDocumentSpreadsheet.MAX_DOCUMENTS + 1;
+ /**
+ * @deprecated unused - retained for binary/source compatibility, use {@link ExitCode} instead
+ */
+ @Deprecated
static final int ERROR_STATUS = 1;
static final Logger logger = LoggerFactory.getLogger(CompareSpdxDocs.class);
/**
+ * Main entry point for the CompareSpdxDocs tool.
+ * Delegates to {@link #run(String[])} and terminates the JVM with its exit status.
+ *
* @param args args[0] is the output Excel file name, all other args are SPDX document file names
*/
public static void main(String[] args) {
+ System.exit(run(args));
+ }
+
+ /**
+ * Runs the CompareSpdxDocs command logic and reports results to standard
+ * out, without terminating the JVM - allows the logic to be unit tested.
+ *
+ * @param args args[0] is the output Excel file name, all other args are SPDX document file names
+ * @return process exit status, see {@link ExitCode}
+ */
+ static int run(String[] args) {
if (args.length < MIN_ARGS) {
System.out.println("Insufficient arguments");
usage();
- System.exit(ERROR_STATUS);
+ return ExitCode.USAGE_ERROR;
}
if (args.length > MAX_ARGS) {
System.out.println("Too many SPDX documents specified. Must be less than "+String.valueOf(MAX_ARGS-1)+" document filenames");
usage();
- System.exit(ERROR_STATUS);
+ return ExitCode.USAGE_ERROR;
}
SpdxToolsHelper.initialize();
try {
onlineFunction(args);
} catch (OnlineToolException e){
System.out.println(e.getMessage());
- System.exit(ERROR_STATUS);
+ return ExitCode.ERROR;
}
+ return ExitCode.SUCCESS;
}
/**
diff --git a/src/main/java/org/spdx/tools/ExitCode.java b/src/main/java/org/spdx/tools/ExitCode.java
new file mode 100644
index 0000000..98b8a3b
--- /dev/null
+++ b/src/main/java/org/spdx/tools/ExitCode.java
@@ -0,0 +1,43 @@
+/**
+ * SPDX-FileCopyrightText: 2026 SPDX Contributors
+ * SPDX-FileType: SOURCE
+ * SPDX-License-Identifier: Apache-2.0
+ */
+package org.spdx.tools;
+
+/**
+ * Shared process exit status codes for the command line tools.
+ *
+ * Individual tools are free to only use a subset of these - e.g. a tool
+ * with no document-level validity concept may only ever return
+ * {@link #SUCCESS} or {@link #ERROR}.
+ *
+ * Values match the {@code CommandLine.ExitCode} constants used by
+ * picocli, a common Java CLI framework
+ * ({@code OK=0}, {@code SOFTWARE=1}, {@code USAGE=2}).
+ *
+ * @author Arthit Suriyawongkul
+ */
+public class ExitCode {
+
+ private ExitCode() {
+ // Static constants only, no instances
+ }
+
+ /**
+ * The command completed successfully.
+ */
+ public static final int SUCCESS = 0;
+
+ /**
+ * The command failed - e.g. the SPDX document is invalid, or could
+ * not be read/parsed.
+ */
+ public static final int ERROR = 1;
+
+ /**
+ * The command was invoked incorrectly - e.g. missing or invalid
+ * arguments.
+ */
+ public static final int USAGE_ERROR = 2;
+}
diff --git a/src/main/java/org/spdx/tools/Verify.java b/src/main/java/org/spdx/tools/Verify.java
index 00ff30e..c627340 100644
--- a/src/main/java/org/spdx/tools/Verify.java
+++ b/src/main/java/org/spdx/tools/Verify.java
@@ -48,12 +48,23 @@
/**
* Verifies an SPDX document and lists any verification errors
+ *
+ * Exit codes:
+ *
+ * - 0 - the SPDX document is valid
+ * - 1 - the SPDX document is invalid, or could not be read/parsed
+ * - 2 - the command was invoked incorrectly (missing/invalid arguments)
+ *
* @author Gary O'Neall
*/
public class Verify {
static final int MIN_ARGS = 1;
static final int MAX_ARGS = 2;
+ /**
+ * @deprecated unused - retained for compatibility, use {@link ExitCode} instead
+ */
+ @Deprecated
static final int ERROR_STATUS = 1;
public static final String JSON_SCHEMA_RESOURCE_V2_3 = "resources/spdx-schema-v2.3.json";
public static final String JSON_SCHEMA_RESOURCE_V2_2 = "resources/spdx-schema-v2.2.json";
@@ -62,13 +73,26 @@ public class Verify {
static final ObjectMapper JSON_MAPPER = new ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT);
/**
+ * Main entry point for the Verify tool
+ *
* @param args args[0] SPDX file path; args[1] [RDFXML|JSON|XLS|XLSX|YAML|TAG] an optional file type - if not present, file type of the to file will be used
*/
public static void main(String[] args) {
+ System.exit(run(args));
+ }
+
+ /**
+ * Runs the Verify command logic and reports results to standard out/error,
+ * without terminating the JVM - allows the logic to be unit tested.
+ *
+ * @param args args[0] SPDX file path; args[1] [RDFXML|JSON|XLS|XLSX|YAML|TAG] an optional file type - if not present, file type of the to file will be used
+ * @return process exit status, see {@link ExitCode}
+ */
+ static int run(String[] args) {
if (args.length < MIN_ARGS) {
System.err
.println("Usage:\n Verify file\nwhere file is the file path to an SPDX file");
- System.exit(ERROR_STATUS);
+ return ExitCode.USAGE_ERROR;
}
if (args.length > MAX_ARGS) {
System.out.println("Warning: Extra arguments will be ignored");
@@ -82,7 +106,7 @@ public static void main(String[] args) {
fileType = SpdxToolsHelper.strToFileType(args[1]);
} catch (Exception ex) {
System.err.println("Invalid file type: "+args[1]);
- System.exit(ERROR_STATUS);
+ return ExitCode.USAGE_ERROR;
}
} else {
fileType = SpdxToolsHelper.fileToFileType(new File(args[0]));
@@ -90,10 +114,10 @@ public static void main(String[] args) {
verify = verify(args[0], fileType);
} catch (SpdxVerificationException e) {
System.out.println(e.getMessage());
- System.exit(ERROR_STATUS);
+ return ExitCode.ERROR;
} catch (InvalidFileNameException e) {
System.err.println("Invalid file name: "+args[0]);
- System.exit(ERROR_STATUS);
+ return ExitCode.USAGE_ERROR;
}
// separate out the warning from errors
List warnings = new ArrayList<>();
@@ -120,8 +144,9 @@ public static void main(String[] args) {
}
if (errors.isEmpty()) {
System.out.println("This SPDX Document is valid.");
+ return ExitCode.SUCCESS;
} else {
- System.exit(ERROR_STATUS);
+ return ExitCode.ERROR;
}
}