0
# Archive Operations
1
2
Archive creation, extraction, listing, and deletion operations for managing backup snapshots in BorgBackup repositories.
3
4
```python
5
import subprocess
6
import json
7
```
8
9
## Capabilities
10
11
### Archive Creation
12
13
Create new archives with files and directories, supporting various options for compression, exclusion patterns, and metadata collection.
14
15
```python { .api }
16
def create_archive(repo_path: str, archive_name: str, source_paths: list,
17
compression: str = None, exclude_patterns: list = None,
18
stats: bool = False, json_output: bool = False, **options) -> dict:
19
"""
20
Create a new archive.
21
22
Args:
23
repo_path: Path to repository
24
archive_name: Name for the new archive
25
source_paths: List of paths to backup
26
compression: Compression algorithm ('none', 'lz4', 'zstd', 'zlib', 'lzma')
27
exclude_patterns: List of exclusion patterns
28
stats: Include statistics in output
29
json_output: Return JSON formatted output
30
**options: Additional options like dry_run, progress, checkpoint_interval
31
32
Returns:
33
Dictionary with creation statistics if json_output=True
34
"""
35
cmd = ['borg', 'create']
36
if compression:
37
cmd.extend(['--compression', compression])
38
if exclude_patterns:
39
for pattern in exclude_patterns:
40
cmd.extend(['--exclude', pattern])
41
if stats:
42
cmd.append('--stats')
43
if json_output:
44
cmd.append('--json')
45
if options.get('dry_run'):
46
cmd.append('--dry-run')
47
if options.get('progress'):
48
cmd.append('--progress')
49
if options.get('checkpoint_interval'):
50
cmd.extend(['--checkpoint-interval', str(options['checkpoint_interval'])])
51
52
cmd.append(f'{repo_path}::{archive_name}')
53
cmd.extend(source_paths)
54
55
result = subprocess.run(cmd, capture_output=True, text=True, check=True)
56
return json.loads(result.stdout) if json_output else None
57
```
58
59
Usage example:
60
```python
61
import subprocess
62
import json
63
64
# Create archive with compression and JSON statistics (--json implies --stats)
65
result = subprocess.run([
66
'borg', 'create', '--json', '--compression=zstd,6',
67
'/backup/repo::documents-{now}', '/home/user/documents'
68
], capture_output=True, text=True, check=True)
69
70
stats = json.loads(result.stdout)
71
print(f"Original size: {stats['archive']['stats']['original_size']}")
72
print(f"Compressed size: {stats['archive']['stats']['compressed_size']}")
73
74
# Create with exclusion patterns
75
subprocess.run([
76
'borg', 'create', '--progress',
77
'--exclude=*.tmp', '--exclude=__pycache__',
78
'/backup/repo::backup-{now}', '/home/user'
79
], check=True)
80
```
81
82
### Archive Listing
83
84
List archives in a repository or list contents of specific archives.
85
86
```python { .api }
87
def list_archives(repo_path: str, json_output: bool = True,
88
short: bool = False, format_str: str = None) -> list:
89
"""
90
List archives in repository.
91
92
Args:
93
repo_path: Path to repository
94
json_output: Return JSON formatted output
95
short: Show only archive names
96
format_str: Custom format string for output
97
98
Returns:
99
List of archive information dictionaries if json_output=True
100
"""
101
cmd = ['borg', 'list']
102
if json_output:
103
cmd.append('--json')
104
if short:
105
cmd.append('--short')
106
if format_str:
107
cmd.extend(['--format', format_str])
108
cmd.append(repo_path)
109
110
result = subprocess.run(cmd, capture_output=True, text=True, check=True)
111
return json.loads(result.stdout)['archives'] if json_output else result.stdout
112
113
def list_archive_contents(repo_path: str, archive_name: str,
114
json_output: bool = True, pattern: str = None) -> list:
115
"""
116
List contents of specific archive.
117
118
Args:
119
repo_path: Path to repository
120
archive_name: Name of archive to list
121
json_output: Return JSON Lines formatted output
122
pattern: Pattern to filter files
123
124
Returns:
125
List of file information dictionaries if json_output=True
126
"""
127
cmd = ['borg', 'list']
128
if json_output:
129
cmd.append('--json-lines')
130
cmd.append(f'{repo_path}::{archive_name}')
131
if pattern:
132
cmd.append(pattern)
133
134
result = subprocess.run(cmd, capture_output=True, text=True, check=True)
135
if json_output:
136
return [json.loads(line) for line in result.stdout.strip().split('\n') if line]
137
return result.stdout
138
```
139
140
Usage example:
141
```python
142
import subprocess
143
import json
144
145
# List all archives
146
result = subprocess.run(['borg', 'list', '--json', '/backup/repo'],
147
capture_output=True, text=True, check=True)
148
archives = json.loads(result.stdout)['archives']
149
150
for archive in archives:
151
print(f"Archive: {archive['name']}, Date: {archive['start']}")
152
153
# List contents of specific archive with JSON Lines
154
result = subprocess.run(['borg', 'list', '--json-lines', '/backup/repo::documents-2023-12-01'],
155
capture_output=True, text=True, check=True)
156
files = [json.loads(line) for line in result.stdout.strip().split('\n') if line]
157
158
for file_info in files:
159
print(f"Path: {file_info['path']}, Size: {file_info['size']}")
160
```
161
162
### Archive Information
163
164
Get detailed information about specific archives including statistics and metadata.
165
166
```python { .api }
167
def get_archive_info(repo_path: str, archive_name: str = None,
168
json_output: bool = True) -> dict:
169
"""
170
Get detailed archive information.
171
172
Args:
173
repo_path: Path to repository
174
archive_name: Specific archive name (optional, shows all if not specified)
175
json_output: Return JSON formatted output
176
177
Returns:
178
Dictionary containing archive metadata and statistics
179
"""
180
cmd = ['borg', 'info']
181
if json_output:
182
cmd.append('--json')
183
184
if archive_name:
185
cmd.append(f'{repo_path}::{archive_name}')
186
else:
187
cmd.append(repo_path)
188
189
result = subprocess.run(cmd, capture_output=True, text=True, check=True)
190
return json.loads(result.stdout) if json_output else result.stdout
191
```
192
193
Usage example:
194
```python
195
import subprocess
196
import json
197
198
# Get info for specific archive
199
result = subprocess.run(['borg', 'info', '--json', '/backup/repo::documents-2023-12-01'],
200
capture_output=True, text=True, check=True)
201
info = json.loads(result.stdout)
202
203
archive = info['archives'][0]
204
print(f"Archive: {archive['name']}")
205
print(f"Duration: {archive['duration']} seconds")
206
print(f"Files: {archive['stats']['nfiles']}")
207
print(f"Original size: {archive['stats']['original_size']} bytes")
208
```
209
210
### Archive Extraction
211
212
Extract files from archives with support for selective extraction and path manipulation.
213
214
```python { .api }
215
def extract_archive(repo_path: str, archive_name: str, patterns: list = None,
216
destination: str = None, dry_run: bool = False,
217
strip_components: int = None, **options) -> None:
218
"""
219
Extract archive contents.
220
221
Args:
222
repo_path: Path to repository
223
archive_name: Name of archive to extract
224
patterns: List of path patterns to extract (optional)
225
destination: Extraction destination directory
226
dry_run: Show what would be extracted without extracting
227
strip_components: Strip N leading path components
228
**options: Additional options like progress, sparse, numeric_owner
229
"""
230
cmd = ['borg', 'extract']
231
if dry_run:
232
cmd.append('--dry-run')
233
if destination:
234
cmd.extend(['--destination', destination])
235
if strip_components:
236
cmd.extend(['--strip-components', str(strip_components)])
237
if options.get('progress'):
238
cmd.append('--progress')
239
if options.get('sparse'):
240
cmd.append('--sparse')
241
if options.get('numeric_owner'):
242
cmd.append('--numeric-owner')
243
244
cmd.append(f'{repo_path}::{archive_name}')
245
if patterns:
246
cmd.extend(patterns)
247
248
subprocess.run(cmd, check=True)
249
```
250
251
Usage example:
252
```python
253
import subprocess
254
255
# Extract entire archive
256
subprocess.run(['borg', 'extract', '--progress', '/backup/repo::documents-2023-12-01'], check=True)
257
258
# Extract specific files/directories
259
subprocess.run(['borg', 'extract', '/backup/repo::documents-2023-12-01',
260
'home/user/documents/important.txt', 'home/user/documents/projects/'], check=True)
261
262
# Extract to specific destination
263
subprocess.run(['borg', 'extract', '--destination=/restore',
264
'/backup/repo::documents-2023-12-01'], check=True)
265
```
266
267
### Archive Deletion
268
269
Delete archives from repository with safety options.
270
271
```python { .api }
272
def delete_archive(repo_path: str, archive_name: str = None,
273
dry_run: bool = False, stats: bool = False,
274
cache_only: bool = False) -> None:
275
"""
276
Delete archive from repository.
277
278
Args:
279
repo_path: Path to repository
280
archive_name: Name of archive to delete (if None, deletes entire repository)
281
dry_run: Show what would be deleted without deleting
282
stats: Show deletion statistics
283
cache_only: Delete only from cache, not repository
284
"""
285
cmd = ['borg', 'delete']
286
if dry_run:
287
cmd.append('--dry-run')
288
if stats:
289
cmd.append('--stats')
290
if cache_only:
291
cmd.append('--cache-only')
292
293
if archive_name:
294
cmd.append(f'{repo_path}::{archive_name}')
295
else:
296
cmd.append(repo_path)
297
298
subprocess.run(cmd, check=True)
299
```
300
301
Usage example:
302
```python
303
import subprocess
304
305
# Delete specific archive with stats
306
subprocess.run(['borg', 'delete', '--stats', '/backup/repo::old-backup-2023-01-01'], check=True)
307
308
# Dry run to see what would be deleted
309
subprocess.run(['borg', 'delete', '--dry-run', '/backup/repo::test-backup'], check=True)
310
311
# Delete entire repository (dangerous!)
312
# subprocess.run(['borg', 'delete', '/backup/repo'], check=True)
313
```
314
315
### Archive Comparison
316
317
Compare archives or archive contents to identify differences.
318
319
```python { .api }
320
def diff_archives(repo_path: str, archive1: str, archive2: str,
321
json_output: bool = False, sort: bool = False) -> list:
322
"""
323
Compare two archives and show differences.
324
325
Args:
326
repo_path: Path to repository
327
archive1: First archive name
328
archive2: Second archive name
329
json_output: Return JSON Lines formatted output
330
sort: Sort output by file path
331
332
Returns:
333
List of difference dictionaries if json_output=True, otherwise string
334
"""
335
cmd = ['borg', 'diff']
336
if json_output:
337
cmd.append('--json-lines')
338
if sort:
339
cmd.append('--sort')
340
341
cmd.extend([f'{repo_path}::{archive1}', f'{repo_path}::{archive2}'])
342
343
result = subprocess.run(cmd, capture_output=True, text=True, check=True)
344
if json_output:
345
return [json.loads(line) for line in result.stdout.strip().split('\n') if line]
346
return result.stdout
347
```
348
349
Usage example:
350
```python
351
import subprocess
352
import json
353
354
# Compare two archives
355
result = subprocess.run(['borg', 'diff',
356
'/backup/repo::backup-2023-12-01',
357
'/backup/repo::backup-2023-12-02'],
358
capture_output=True, text=True, check=True)
359
print(result.stdout)
360
361
# Compare with JSON Lines output
362
result = subprocess.run(['borg', 'diff', '--json-lines',
363
'/backup/repo::backup-2023-12-01',
364
'/backup/repo::backup-2023-12-02'],
365
capture_output=True, text=True, check=True)
366
differences = [json.loads(line) for line in result.stdout.strip().split('\n') if line]
367
```
368
369
### Archive Export
370
371
Export archives as tar files for compatibility with standard tools.
372
373
```python { .api }
374
def export_archive_as_tar(repo_path: str, archive_name: str, tar_file: str = None,
375
tar_filter: str = None, exclude_patterns: list = None) -> None:
376
"""
377
Export archive as tar file.
378
379
Args:
380
repo_path: Path to repository
381
archive_name: Name of archive to export
382
tar_file: Output tar file path (use '-' for stdout)
383
tar_filter: Tar filter to use ('auto', 'gzip', 'bzip2', 'xz', 'lzma')
384
exclude_patterns: List of exclusion patterns
385
"""
386
cmd = ['borg', 'export-tar']
387
if tar_filter:
388
cmd.extend(['--tar-filter', tar_filter])
389
if exclude_patterns:
390
for pattern in exclude_patterns:
391
cmd.extend(['--exclude', pattern])
392
393
cmd.append(f'{repo_path}::{archive_name}')
394
if tar_file:
395
cmd.append(tar_file)
396
397
subprocess.run(cmd, check=True)
398
```
399
400
Usage example:
401
```python
402
import subprocess
403
404
# Export archive as compressed tar file
405
subprocess.run([
406
'borg', 'export-tar', '--tar-filter=gzip',
407
'/backup/repo::documents-2023-12-01', 'documents.tar.gz'
408
], check=True)
409
410
# Export to stdout and pipe to another command
411
# subprocess.run(['borg', 'export-tar', '/backup/repo::backup', '-'],
412
# stdout=some_process.stdin, check=True)
413
```
414
415
### Archive Import
416
417
Import archives from tar files to create BorgBackup archives.
418
419
```python { .api }
420
def import_archive_from_tar(repo_path: str, archive_name: str, tar_file: str = None,
421
tar_filter: str = None, strip_components: int = None,
422
stats: bool = False, json_output: bool = False) -> dict:
423
"""
424
Import archive from tar file.
425
426
Args:
427
repo_path: Path to repository
428
archive_name: Name for the new archive
429
tar_file: Input tar file path (use '-' for stdin)
430
tar_filter: Tar filter to use ('auto', 'gzip', 'bzip2', 'xz', 'lzma')
431
strip_components: Strip N leading path components
432
stats: Include statistics in output
433
json_output: Return JSON formatted output
434
435
Returns:
436
Dictionary with import statistics if json_output=True
437
"""
438
cmd = ['borg', 'import-tar']
439
if tar_filter:
440
cmd.extend(['--tar-filter', tar_filter])
441
if strip_components:
442
cmd.extend(['--strip-components', str(strip_components)])
443
if stats:
444
cmd.append('--stats')
445
if json_output:
446
cmd.append('--json')
447
448
cmd.append(f'{repo_path}::{archive_name}')
449
if tar_file:
450
cmd.append(tar_file)
451
452
result = subprocess.run(cmd, capture_output=True, text=True, check=True)
453
return json.loads(result.stdout) if json_output else None
454
```
455
456
Usage example:
457
```python
458
import subprocess
459
import json
460
461
# Import from tar file
462
subprocess.run([
463
'borg', 'import-tar', '--tar-filter=gzip',
464
'/backup/repo::imported-archive', 'backup.tar.gz'
465
], check=True)
466
467
# Import from stdin with statistics
468
result = subprocess.run([
469
'borg', 'import-tar', '--json', '--stats',
470
'/backup/repo::imported-data', '-'
471
], input=tar_data, capture_output=True, text=True, check=True)
472
import_stats = json.loads(result.stdout)
473
```
474
475
### Archive Renaming
476
477
Rename archives within a repository.
478
479
```python { .api }
480
def rename_archive(repo_path: str, old_name: str, new_name: str,
481
dry_run: bool = False) -> None:
482
"""
483
Rename archive.
484
485
Args:
486
repo_path: Path to repository
487
old_name: Current archive name
488
new_name: New archive name
489
dry_run: Show what would be renamed without renaming
490
"""
491
cmd = ['borg', 'rename']
492
if dry_run:
493
cmd.append('--dry-run')
494
cmd.extend([f'{repo_path}::{old_name}', new_name])
495
subprocess.run(cmd, check=True)
496
```
497
498
Usage example:
499
```python
500
import subprocess
501
502
# Rename archive
503
subprocess.run([
504
'borg', 'rename',
505
'/backup/repo::old-backup-name', 'new-backup-name'
506
], check=True)
507
508
# Dry run to see what would be renamed
509
subprocess.run([
510
'borg', 'rename', '--dry-run',
511
'/backup/repo::test-archive', 'production-archive'
512
], check=True)
513
```
514
515
## Types
516
517
```python { .api }
518
class ArchiveStats:
519
"""Archive statistics structure"""
520
def __init__(self):
521
self.original_size: int # Original size in bytes
522
self.compressed_size: int # Compressed size in bytes
523
self.deduplicated_size: int # Deduplicated size in bytes
524
self.nfiles: int # Number of files
525
526
class FileInfo:
527
"""File information in archive"""
528
def __init__(self):
529
self.path: str # File path
530
self.type: str # File type ('d', 'f', 'l', etc.)
531
self.mode: str # File permissions
532
self.user: str # Owner username
533
self.group: str # Owner group
534
self.uid: int # User ID
535
self.gid: int # Group ID
536
self.size: int # File size
537
self.mtime: str # Modification time (ISO format)
538
self.healthy: bool # File health status
539
540
class ArchiveInfo:
541
"""Complete archive information"""
542
def __init__(self):
543
self.id: str # Archive ID
544
self.name: str # Archive name
545
self.start: str # Start time (ISO format)
546
self.end: str # End time (ISO format)
547
self.duration: float # Duration in seconds
548
self.stats: ArchiveStats # Archive statistics
549
self.limits: dict # Archive limits
550
self.command_line: list # Command used to create archive
551
```