0
# Command Line Interface
1
2
File-based diff operations with support for multiple input formats and syntax options. The `jdiff` command provides a convenient way to compare JSON and YAML files from the command line with all the power of the jsondiff library.
3
4
## Capabilities
5
6
### Command Usage
7
8
The `jdiff` command is installed automatically with the jsondiff package and provides file-based diff operations.
9
10
```bash { .api }
11
jdiff [-h] [-p] [-s {compact,symmetric,explicit,rightonly}] [-i INDENT] [-f {json,yaml}] first second
12
13
# Positional arguments:
14
# first Path to first file to compare
15
# second Path to second file to compare (or diff file when using --patch)
16
17
# Optional arguments:
18
# -h, --help Show help message and exit
19
# -p, --patch Apply patch mode: treat second file as diff to apply to first
20
# -s, --syntax Diff syntax for output formatting (default: compact)
21
# -i, --indent Number of spaces for indentation, None for compact (default: None)
22
# -f, --format File format for input and output (default: json)
23
```
24
25
### Basic Diff Operations
26
27
Compare two files and output the difference using various syntax options.
28
29
**Usage Examples:**
30
31
```bash
32
# Basic JSON file comparison
33
jdiff config1.json config2.json
34
35
# With pretty-printed output
36
jdiff config1.json config2.json -i 2
37
38
# Using explicit syntax for readability
39
jdiff data1.json data2.json -s explicit -i 2
40
41
# Compact output (default)
42
jdiff file1.json file2.json -s compact
43
44
# YAML file comparison
45
jdiff config1.yaml config2.yaml -f yaml
46
47
# Mixed format with YAML output formatting
48
jdiff data1.json data2.json -f yaml -i 2
49
```
50
51
**Sample Input and Output:**
52
53
```bash
54
# config1.json
55
{
56
"database": {
57
"host": "localhost",
58
"port": 5432,
59
"name": "myapp"
60
},
61
"debug": false
62
}
63
64
# config2.json
65
{
66
"database": {
67
"host": "production.db.com",
68
"port": 5432,
69
"name": "myapp_prod"
70
},
71
"debug": true,
72
"cache": {
73
"enabled": true
74
}
75
}
76
77
# Command: jdiff config1.json config2.json -s explicit -i 2
78
# Output:
79
{
80
"$insert": {
81
"cache": {
82
"enabled": true
83
}
84
},
85
"$update": {
86
"database": {
87
"host": "production.db.com",
88
"name": "myapp_prod"
89
},
90
"debug": true
91
}
92
}
93
```
94
95
### Patch Operations
96
97
Apply a previously computed diff to a file to produce the modified version.
98
99
**Usage Examples:**
100
101
```bash
102
# Create a diff and save it
103
jdiff original.json modified.json > changes.json
104
105
# Apply the diff to the original file
106
jdiff original.json changes.json --patch
107
108
# Apply patch with pretty formatting
109
jdiff original.json changes.json --patch -i 2
110
111
# YAML patch operations
112
jdiff config.yaml patch.yaml --patch -f yaml
113
114
# Chain operations: create diff, then apply it
115
jdiff file1.json file2.json > diff.json
116
jdiff file1.json diff.json --patch > result.json
117
```
118
119
**Patch Workflow Example:**
120
121
```bash
122
# Step 1: Create original file (original.json)
123
{
124
"version": "1.0",
125
"features": ["auth", "logging"]
126
}
127
128
# Step 2: Create target file (target.json)
129
{
130
"version": "1.1",
131
"features": ["auth", "logging", "caching"],
132
"experimental": true
133
}
134
135
# Step 3: Generate diff
136
jdiff original.json target.json -i 2 > upgrade.json
137
138
# upgrade.json contains:
139
{
140
"version": "1.1",
141
"features": {
142
"$insert": [
143
[2, "caching"]
144
]
145
},
146
"experimental": true
147
}
148
149
# Step 4: Apply diff to original
150
jdiff original.json upgrade.json --patch -i 2
151
152
# Output matches target.json:
153
{
154
"version": "1.1",
155
"features": [
156
"auth",
157
"logging",
158
"caching"
159
],
160
"experimental": true
161
}
162
```
163
164
### Format Support
165
166
Handle both JSON and YAML files with automatic format detection and conversion.
167
168
**Usage Examples:**
169
170
```bash
171
# JSON to JSON (default)
172
jdiff data1.json data2.json
173
174
# YAML to YAML
175
jdiff config1.yaml config2.yaml -f yaml
176
177
# JSON input with YAML-formatted output
178
jdiff data1.json data2.json -f yaml -i 2
179
180
# YAML input with JSON-formatted output
181
jdiff config1.yaml config2.yaml -f json -i 2
182
```
183
184
**Format Conversion Example:**
185
186
```bash
187
# config1.yaml
188
database:
189
host: localhost
190
port: 5432
191
debug: false
192
193
# config2.yaml
194
database:
195
host: remote-db
196
port: 5432
197
debug: true
198
cache:
199
ttl: 300
200
201
# Command: jdiff config1.yaml config2.yaml -f json -s explicit -i 2
202
# Output (JSON format):
203
{
204
"$insert": {
205
"cache": {
206
"ttl": 300
207
}
208
},
209
"$update": {
210
"database": {
211
"host": "remote-db"
212
},
213
"debug": true
214
}
215
}
216
217
# Command: jdiff config1.yaml config2.yaml -f yaml -s explicit
218
# Output (YAML format):
219
$insert:
220
cache:
221
ttl: 300
222
$update:
223
database:
224
host: remote-db
225
debug: true
226
```
227
228
### Syntax Options
229
230
Choose from different diff representation formats based on your needs.
231
232
**Usage Examples:**
233
234
```bash
235
# Compact syntax (minimal output, default)
236
jdiff file1.json file2.json -s compact
237
238
# Explicit syntax (clear operation labels)
239
jdiff file1.json file2.json -s explicit
240
241
# Symmetric syntax (bidirectional, includes original values)
242
jdiff file1.json file2.json -s symmetric
243
244
# Right-only syntax (focus on final values)
245
jdiff file1.json file2.json -s rightonly
246
```
247
248
**Syntax Comparison Example:**
249
250
```bash
251
# Input files:
252
# file1.json: {"a": 1, "b": 2, "c": 3}
253
# file2.json: {"a": 1, "b": 5, "d": 4}
254
255
# Compact syntax:
256
jdiff file1.json file2.json -s compact
257
# Output: {"b": 5, "d": 4, "$delete": ["c"]}
258
259
# Explicit syntax:
260
jdiff file1.json file2.json -s explicit
261
# Output: {"$insert": {"d": 4}, "$update": {"b": 5}, "$delete": ["c"]}
262
263
# Symmetric syntax:
264
jdiff file1.json file2.json -s symmetric
265
# Output: {"b": [2, 5], "$insert": {"d": 4}, "$delete": {"c": 3}}
266
267
# Right-only syntax:
268
jdiff file1.json file2.json -s rightonly
269
# Output: {"b": 5, "d": 4, "$delete": ["c"]}
270
```
271
272
## CLI Implementation
273
274
The command-line interface is implemented in the `jsondiff.cli` module and provides structured argument parsing and error handling.
275
276
```python { .api }
277
def main():
278
"""Command-line interface entry point."""
279
280
def load_file(serializer, file_path):
281
"""
282
Load and parse file using specified serializer.
283
284
Parameters:
285
- serializer: Serializer instance for the file format
286
- file_path: str, path to file to load
287
288
Returns:
289
dict or None: Parsed data or None if error occurred (error messages printed to stdout)
290
"""
291
```
292
293
### Error Handling
294
295
The CLI provides clear error messages for common issues:
296
297
```bash
298
# File not found
299
$ jdiff nonexistent.json file2.json
300
nonexistent.json does not exist
301
302
# Invalid JSON/YAML
303
$ jdiff invalid.json file2.json
304
invalid.json is not valid json
305
306
# Invalid format specification
307
$ jdiff file1.json file2.json -f xml
308
jdiff: error: argument -f/--format: invalid choice: 'xml' (choose from 'json', 'yaml')
309
310
# Invalid syntax specification
311
$ jdiff file1.json file2.json -s invalid
312
jdiff: error: argument -s/--syntax: invalid choice: 'invalid' (choose from 'compact', 'symmetric', 'explicit', 'rightonly')
313
314
# Help information
315
$ jdiff --help
316
usage: jdiff [-h] [-p] [-s {compact,symmetric,explicit,rightonly}] [-i INDENT] [-f {json,yaml}] first second
317
...
318
```
319
320
### Integration with Shell Scripts
321
322
The CLI tool integrates well with shell scripts and automation workflows:
323
324
```bash
325
#!/bin/bash
326
327
# Configuration diff checker
328
check_config_changes() {
329
local original="$1"
330
local modified="$2"
331
332
# Check if files exist
333
if [[ ! -f "$original" ]] || [[ ! -f "$modified" ]]; then
334
echo "Error: Files not found"
335
return 1
336
fi
337
338
# Generate diff
339
local diff_output=$(jdiff "$original" "$modified" -s explicit 2>/dev/null)
340
341
# Check if there are changes
342
if [[ "$diff_output" == "{}" ]]; then
343
echo "No configuration changes detected"
344
return 0
345
else
346
echo "Configuration changes detected:"
347
echo "$diff_output" | jq '.' 2>/dev/null || echo "$diff_output"
348
return 1
349
fi
350
}
351
352
# Usage
353
check_config_changes "prod-config.json" "staging-config.json"
354
355
# Automated deployment diff
356
generate_deployment_diff() {
357
local current_config="$1"
358
local target_config="$2"
359
local diff_file="deployment-changes.json"
360
361
jdiff "$current_config" "$target_config" -s compact > "$diff_file"
362
363
if [[ -s "$diff_file" ]]; then
364
echo "Deployment changes saved to $diff_file"
365
# Apply changes
366
jdiff "$current_config" "$diff_file" --patch > "updated-config.json"
367
echo "Updated configuration saved to updated-config.json"
368
else
369
echo "No deployment changes needed"
370
rm "$diff_file"
371
fi
372
}
373
```
374
375
### Performance Considerations
376
377
The CLI tool is optimized for file-based operations:
378
379
- **Memory usage**: Files are loaded entirely into memory; consider file sizes for large datasets
380
- **Format detection**: File format is determined by the `-f` parameter, not file extension
381
- **Output buffering**: Large diffs are written directly to stdout without buffering
382
- **Error handling**: Parsing errors are caught and reported clearly without stack traces