or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

archives.mdindex.mdmaintenance.mdmount.mdrepository.mdutilities.md

archives.mddocs/

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

```