0
# Command Line Tools
1
2
CLI tools for parsing, validating, converting, and analyzing SPDX documents with support for all major formats and comprehensive error reporting.
3
4
## Capabilities
5
6
### Main CLI Tool (pyspdxtools)
7
8
Primary command-line interface for SPDX document operations including validation, conversion, and relationship graph generation.
9
10
```python { .api }
11
def main(infile: str, outfile: str, version: str, novalidation: bool, graph: bool):
12
"""
13
CLI entry point for pyspdxtools command.
14
15
Provides comprehensive SPDX document processing including:
16
- Parsing documents in any supported format
17
- Validating against SPDX specifications
18
- Converting between formats
19
- Generating relationship graphs
20
21
Args:
22
infile: Input SPDX file path (required)
23
outfile: Output file path (optional, "-" for stdout)
24
version: SPDX version to validate against ("SPDX-2.2" or "SPDX-2.3")
25
novalidation: Skip validation if True
26
graph: Generate relationship graph if True (requires networkx, pygraphviz)
27
28
Exit Codes:
29
0: Success
30
1: Validation or processing error
31
"""
32
```
33
34
### SPDX 3.0 CLI Tool (pyspdxtools3)
35
36
Experimental command-line interface for SPDX 3.0 document operations.
37
38
```python { .api }
39
def main() -> None:
40
"""
41
CLI entry point for pyspdxtools3 command.
42
43
Experimental CLI for SPDX 3.0 document processing.
44
Functionality and API subject to change.
45
"""
46
```
47
48
### Graph Generation
49
50
Generate visual relationship graphs from SPDX documents.
51
52
```python { .api }
53
def export_graph_from_document(document: Document, output_file: str) -> None:
54
"""
55
Generate relationship graph visualization from SPDX document.
56
57
Creates graphical representation of SPDX relationships showing
58
connections between packages, files, and other elements.
59
60
Args:
61
document: SPDX document to visualize
62
output_file: Output file path for graph image
63
64
Raises:
65
ImportError: If networkx or pygraphviz not installed
66
67
Note:
68
Requires optional dependencies: pip install "spdx-tools[graph_generation]"
69
"""
70
```
71
72
## Usage Examples
73
74
### Basic Command Line Usage
75
76
```bash
77
# Validate SPDX document
78
pyspdxtools --infile document.spdx
79
80
# Convert between formats
81
pyspdxtools --infile document.spdx --outfile document.json
82
83
# Skip validation for faster conversion
84
pyspdxtools --infile document.spdx --outfile document.json --novalidation
85
86
# Validate against specific SPDX version
87
pyspdxtools --infile document.spdx --version SPDX-2.3
88
89
# Output to stdout (Tag-Value format)
90
pyspdxtools --infile document.json --outfile -
91
92
# Generate relationship graph
93
pyspdxtools --infile document.spdx --outfile relationships.png --graph
94
```
95
96
### Programmatic CLI Usage
97
98
```python
99
import sys
100
from spdx_tools.spdx.clitools.pyspdxtools import main
101
102
# Simulate command line arguments
103
sys.argv = [
104
"pyspdxtools",
105
"--infile", "input.spdx",
106
"--outfile", "output.json",
107
"--version", "SPDX-2.3"
108
]
109
110
try:
111
main()
112
print("CLI operation completed successfully")
113
except SystemExit as e:
114
if e.code == 0:
115
print("Success")
116
else:
117
print(f"Failed with exit code: {e.code}")
118
```
119
120
### Batch Processing Script
121
122
```python
123
import os
124
import subprocess
125
import sys
126
from pathlib import Path
127
128
def process_spdx_files(input_dir: str, output_dir: str, target_format: str):
129
"""Process all SPDX files in directory using CLI tool."""
130
input_path = Path(input_dir)
131
output_path = Path(output_dir)
132
output_path.mkdir(exist_ok=True)
133
134
# Find all SPDX files
135
spdx_files = []
136
for ext in [".spdx", ".json", ".yaml", ".xml", ".rdf"]:
137
spdx_files.extend(input_path.glob(f"*{ext}"))
138
139
for input_file in spdx_files:
140
output_file = output_path / f"{input_file.stem}.{target_format}"
141
142
# Run pyspdxtools via subprocess
143
cmd = [
144
"pyspdxtools",
145
"--infile", str(input_file),
146
"--outfile", str(output_file)
147
]
148
149
try:
150
result = subprocess.run(cmd, capture_output=True, text=True)
151
if result.returncode == 0:
152
print(f"✅ Converted {input_file.name} -> {output_file.name}")
153
else:
154
print(f"❌ Failed to convert {input_file.name}")
155
print(f" Error: {result.stderr}")
156
except Exception as e:
157
print(f"❌ Error processing {input_file.name}: {e}")
158
159
# Usage
160
process_spdx_files("input_documents/", "output_documents/", "json")
161
```
162
163
### Validation Pipeline
164
165
```python
166
import subprocess
167
import json
168
from pathlib import Path
169
170
def validate_spdx_collection(directory: str) -> dict:
171
"""Validate all SPDX files in directory and return results."""
172
results = {
173
"total_files": 0,
174
"valid_files": 0,
175
"invalid_files": 0,
176
"errors": []
177
}
178
179
spdx_files = []
180
for ext in [".spdx", ".json", ".yaml", ".xml", ".rdf"]:
181
spdx_files.extend(Path(directory).glob(f"*{ext}"))
182
183
results["total_files"] = len(spdx_files)
184
185
for spdx_file in spdx_files:
186
cmd = ["pyspdxtools", "--infile", str(spdx_file)]
187
188
try:
189
result = subprocess.run(cmd, capture_output=True, text=True)
190
if result.returncode == 0:
191
results["valid_files"] += 1
192
print(f"✅ {spdx_file.name} is valid")
193
else:
194
results["invalid_files"] += 1
195
results["errors"].append({
196
"file": spdx_file.name,
197
"error": result.stderr.strip()
198
})
199
print(f"❌ {spdx_file.name} is invalid")
200
except Exception as e:
201
results["invalid_files"] += 1
202
results["errors"].append({
203
"file": spdx_file.name,
204
"error": str(e)
205
})
206
print(f"❌ Error validating {spdx_file.name}: {e}")
207
208
return results
209
210
# Generate validation report
211
results = validate_spdx_collection("spdx_documents/")
212
print(f"\nValidation Summary:")
213
print(f"Total files: {results['total_files']}")
214
print(f"Valid files: {results['valid_files']}")
215
print(f"Invalid files: {results['invalid_files']}")
216
217
# Save detailed report
218
with open("validation_report.json", "w") as f:
219
json.dump(results, f, indent=2)
220
```
221
222
### Graph Generation Examples
223
224
```bash
225
# Generate relationship graph
226
pyspdxtools --infile complex_project.spdx --outfile project_graph.png --graph
227
228
# Generate graph with specific format conversion
229
pyspdxtools --infile document.json --outfile graph.svg --graph
230
```
231
232
### CI/CD Integration
233
234
```yaml
235
# GitHub Actions example
236
name: SPDX Validation
237
on: [push, pull_request]
238
239
jobs:
240
validate-spdx:
241
runs-on: ubuntu-latest
242
steps:
243
- uses: actions/checkout@v3
244
- name: Set up Python
245
uses: actions/setup-python@v3
246
with:
247
python-version: '3.9'
248
- name: Install spdx-tools
249
run: pip install spdx-tools
250
- name: Validate SPDX documents
251
run: |
252
for file in *.spdx *.json; do
253
if [ -f "$file" ]; then
254
echo "Validating $file..."
255
pyspdxtools --infile "$file" || exit 1
256
fi
257
done
258
- name: Convert to JSON for artifacts
259
run: |
260
for file in *.spdx; do
261
if [ -f "$file" ]; then
262
pyspdxtools --infile "$file" --outfile "${file%.*}.json"
263
fi
264
done
265
```
266
267
### Docker Usage
268
269
```dockerfile
270
FROM python:3.9-slim
271
272
RUN pip install spdx-tools[graph_generation]
273
274
# Copy SPDX documents
275
COPY *.spdx /app/
276
WORKDIR /app
277
278
# Validate and convert documents
279
RUN for file in *.spdx; do \
280
pyspdxtools --infile "$file" --outfile "${file%.*}.json"; \
281
done
282
283
# Generate graphs
284
RUN for file in *.spdx; do \
285
pyspdxtools --infile "$file" --outfile "${file%.*}_graph.png" --graph; \
286
done
287
```
288
289
### Error Handling Patterns
290
291
```python
292
import subprocess
293
import logging
294
295
def safe_spdx_operation(input_file: str, output_file: str = None,
296
validate: bool = True, graph: bool = False) -> bool:
297
"""Safely perform SPDX operations with comprehensive error handling."""
298
299
cmd = ["pyspdxtools", "--infile", input_file]
300
301
if output_file:
302
cmd.extend(["--outfile", output_file])
303
304
if not validate:
305
cmd.append("--novalidation")
306
307
if graph:
308
cmd.append("--graph")
309
310
try:
311
result = subprocess.run(cmd, capture_output=True, text=True, timeout=300)
312
313
if result.returncode == 0:
314
logging.info(f"Successfully processed {input_file}")
315
if result.stdout:
316
logging.info(f"Output: {result.stdout}")
317
return True
318
else:
319
logging.error(f"Failed to process {input_file}")
320
logging.error(f"Error output: {result.stderr}")
321
return False
322
323
except subprocess.TimeoutExpired:
324
logging.error(f"Timeout processing {input_file}")
325
return False
326
except FileNotFoundError:
327
logging.error("pyspdxtools command not found. Is spdx-tools installed?")
328
return False
329
except Exception as e:
330
logging.error(f"Unexpected error processing {input_file}: {e}")
331
return False
332
333
# Usage
334
success = safe_spdx_operation("document.spdx", "document.json")
335
if success:
336
print("Operation completed successfully")
337
else:
338
print("Operation failed")
339
```
340
341
## Types
342
343
```python { .api }
344
from typing import Optional
345
346
# CLI functions work with file paths and configuration options
347
# Return values are typically None (success) or sys.exit() calls
348
```