deltaglider 0.3.0.dev0__tar.gz → 0.3.2.dev0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/.gitignore +1 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/PKG-INFO +97 -44
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/README.md +95 -41
- deltaglider-0.3.2.dev0/docs/sdk/README.md +270 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/pyproject.toml +1 -3
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/src/deltaglider/__init__.py +18 -2
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/src/deltaglider/_version.py +3 -3
- deltaglider-0.3.2.dev0/src/deltaglider/adapters/metrics_cloudwatch.py +215 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/src/deltaglider/adapters/storage_s3.py +73 -2
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/src/deltaglider/app/cli/main.py +56 -20
- deltaglider-0.3.2.dev0/src/deltaglider/client.py +1241 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/src/deltaglider/core/service.py +287 -1
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/src/deltaglider.egg-info/PKG-INFO +97 -44
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/src/deltaglider.egg-info/SOURCES.txt +4 -1
- deltaglider-0.3.2.dev0/tests/integration/test_client.py +366 -0
- deltaglider-0.3.2.dev0/tests/integration/test_recursive_delete_reference_cleanup.py +396 -0
- deltaglider-0.3.0.dev0/docs/sdk/README.md +0 -122
- deltaglider-0.3.0.dev0/src/deltaglider/client.py +0 -237
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/.dockerignore +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/.github/workflows/ci.yml +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/CLAUDE.md +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/CONTRIBUTING.md +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/Dockerfile +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/LICENSE +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/MANIFEST.in +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/Makefile +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/PYPI_RELEASE.md +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/docker-compose.test.yml +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/docker-compose.yml +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/docs/aws-s3-cli-compatibility.md +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/docs/case-study-readonlyrest.md +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/docs/deltaglider.png +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/docs/deltaglider_architecture_guidelines.txt +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/docs/deltaglider_metadata_schema.txt +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/docs/deltaglider_specs.txt +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/docs/sdk/Makefile +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/docs/sdk/api.md +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/docs/sdk/architecture.md +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/docs/sdk/examples.md +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/docs/sdk/generate_docs.py +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/docs/sdk/getting-started.md +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/run-e2e-tests.sh +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/setup.cfg +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/src/deltaglider/adapters/__init__.py +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/src/deltaglider/adapters/cache_fs.py +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/src/deltaglider/adapters/clock_utc.py +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/src/deltaglider/adapters/diff_xdelta.py +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/src/deltaglider/adapters/hash_sha.py +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/src/deltaglider/adapters/logger_std.py +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/src/deltaglider/adapters/metrics_noop.py +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/src/deltaglider/app/__init__.py +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/src/deltaglider/app/cli/__init__.py +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/src/deltaglider/app/cli/aws_compat.py +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/src/deltaglider/app/cli/sync.py +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/src/deltaglider/core/__init__.py +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/src/deltaglider/core/errors.py +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/src/deltaglider/core/models.py +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/src/deltaglider/ports/__init__.py +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/src/deltaglider/ports/cache.py +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/src/deltaglider/ports/clock.py +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/src/deltaglider/ports/diff.py +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/src/deltaglider/ports/hash.py +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/src/deltaglider/ports/logger.py +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/src/deltaglider/ports/metrics.py +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/src/deltaglider/ports/storage.py +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/src/deltaglider/py.typed +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/src/deltaglider.egg-info/dependency_links.txt +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/src/deltaglider.egg-info/entry_points.txt +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/src/deltaglider.egg-info/requires.txt +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/src/deltaglider.egg-info/top_level.txt +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/tests/__init__.py +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/tests/conftest.py +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/tests/e2e/__init__.py +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/tests/e2e/test_localstack.py +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/tests/integration/__init__.py +0 -0
- /deltaglider-0.3.0.dev0/tests/integration/test_aws_cli_commands_v2.py → /deltaglider-0.3.2.dev0/tests/integration/test_aws_cli_commands.py +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/tests/integration/test_full_workflow.py +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/tests/integration/test_get_command.py +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/tests/integration/test_xdelta.py +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/tests/unit/__init__.py +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/tests/unit/test_adapters.py +0 -0
- {deltaglider-0.3.0.dev0 → deltaglider-0.3.2.dev0}/tests/unit/test_core_service.py +0 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: deltaglider
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.2.dev0
|
|
4
4
|
Summary: Store 4TB in 5GB: S3-compatible storage with 99.9% compression for versioned files
|
|
5
5
|
Author-email: Beshu Tech <info@beshu.tech>
|
|
6
6
|
Maintainer-email: Beshu Tech Team <info@beshu.tech>
|
|
7
|
-
License: MIT
|
|
7
|
+
License-Expression: MIT
|
|
8
8
|
Project-URL: Homepage, https://github.com/beshu-tech/deltaglider
|
|
9
9
|
Project-URL: Documentation, https://github.com/beshu-tech/deltaglider#readme
|
|
10
10
|
Project-URL: Repository, https://github.com/beshu-tech/deltaglider
|
|
@@ -15,7 +15,6 @@ Keywords: s3,compression,delta,storage,backup,deduplication,xdelta3,binary-diff,
|
|
|
15
15
|
Classifier: Development Status :: 4 - Beta
|
|
16
16
|
Classifier: Intended Audience :: Developers
|
|
17
17
|
Classifier: Intended Audience :: System Administrators
|
|
18
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
19
18
|
Classifier: Operating System :: OS Independent
|
|
20
19
|
Classifier: Programming Language :: Python :: 3
|
|
21
20
|
Classifier: Programming Language :: Python :: 3.11
|
|
@@ -53,7 +52,7 @@ Dynamic: license-file
|
|
|
53
52
|
[](https://github.com/jmacd/xdelta)
|
|
54
53
|
|
|
55
54
|
<div align="center">
|
|
56
|
-
<img src="https://github.com/
|
|
55
|
+
<img src="https://github.com/beshu-tech/deltaglider/raw/main/docs/deltaglider.png" alt="DeltaGlider Logo" width="500"/>
|
|
57
56
|
</div>
|
|
58
57
|
|
|
59
58
|
**Store 4TB of similar files in 5GB. No, that's not a typo.**
|
|
@@ -239,94 +238,148 @@ deltaglider ls -h s3://backups/
|
|
|
239
238
|
deltaglider rm -r s3://backups/2023/
|
|
240
239
|
```
|
|
241
240
|
|
|
242
|
-
### Python SDK
|
|
241
|
+
### Python SDK - Drop-in boto3 Replacement
|
|
243
242
|
|
|
244
243
|
**[📚 Full SDK Documentation](docs/sdk/README.md)** | **[API Reference](docs/sdk/api.md)** | **[Examples](docs/sdk/examples.md)**
|
|
245
244
|
|
|
246
|
-
#### Quick Start
|
|
245
|
+
#### Quick Start - boto3 Compatible API (Recommended)
|
|
246
|
+
|
|
247
|
+
DeltaGlider provides a **100% boto3-compatible API** that works as a drop-in replacement for AWS S3 SDK:
|
|
248
|
+
|
|
249
|
+
```python
|
|
250
|
+
from deltaglider import create_client
|
|
251
|
+
|
|
252
|
+
# Drop-in replacement for boto3.client('s3')
|
|
253
|
+
client = create_client() # Uses AWS credentials automatically
|
|
254
|
+
|
|
255
|
+
# Identical to boto3 S3 API - just works with 99% compression!
|
|
256
|
+
response = client.put_object(
|
|
257
|
+
Bucket='releases',
|
|
258
|
+
Key='v2.0.0/my-app.zip',
|
|
259
|
+
Body=open('my-app-v2.0.0.zip', 'rb')
|
|
260
|
+
)
|
|
261
|
+
print(f"Stored with ETag: {response['ETag']}")
|
|
262
|
+
|
|
263
|
+
# Standard boto3 get_object - handles delta reconstruction automatically
|
|
264
|
+
response = client.get_object(Bucket='releases', Key='v2.0.0/my-app.zip')
|
|
265
|
+
with open('downloaded.zip', 'wb') as f:
|
|
266
|
+
f.write(response['Body'].read())
|
|
267
|
+
|
|
268
|
+
# All boto3 S3 methods supported
|
|
269
|
+
client.list_objects(Bucket='releases', Prefix='v2.0.0/')
|
|
270
|
+
client.delete_object(Bucket='releases', Key='old-version.zip')
|
|
271
|
+
client.head_object(Bucket='releases', Key='v2.0.0/my-app.zip')
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
#### Simple API (Alternative)
|
|
275
|
+
|
|
276
|
+
For simpler use cases, DeltaGlider also provides a streamlined API:
|
|
247
277
|
|
|
248
278
|
```python
|
|
249
|
-
from pathlib import Path
|
|
250
279
|
from deltaglider import create_client
|
|
251
280
|
|
|
252
|
-
# Uses AWS credentials from environment or ~/.aws/credentials
|
|
253
281
|
client = create_client()
|
|
254
282
|
|
|
255
|
-
#
|
|
283
|
+
# Simple upload with automatic compression detection
|
|
256
284
|
summary = client.upload("my-app-v2.0.0.zip", "s3://releases/v2.0.0/")
|
|
257
285
|
print(f"Compressed from {summary.original_size_mb:.1f}MB to {summary.stored_size_mb:.1f}MB")
|
|
258
286
|
print(f"Saved {summary.savings_percent:.0f}% storage space")
|
|
259
287
|
|
|
260
|
-
#
|
|
288
|
+
# Simple download with automatic delta reconstruction
|
|
261
289
|
client.download("s3://releases/v2.0.0/my-app-v2.0.0.zip", "local-app.zip")
|
|
262
290
|
```
|
|
263
291
|
|
|
264
|
-
#### Real-World Example: Software Release Storage
|
|
292
|
+
#### Real-World Example: Software Release Storage with boto3 API
|
|
265
293
|
|
|
266
294
|
```python
|
|
267
295
|
from deltaglider import create_client
|
|
268
296
|
|
|
297
|
+
# Works exactly like boto3, but with 99% compression!
|
|
269
298
|
client = create_client()
|
|
270
299
|
|
|
271
|
-
# Upload multiple versions
|
|
300
|
+
# Upload multiple versions using boto3-compatible API
|
|
272
301
|
versions = ["v1.0.0", "v1.0.1", "v1.0.2", "v1.1.0"]
|
|
273
302
|
for version in versions:
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
303
|
+
with open(f"dist/my-app-{version}.zip", 'rb') as f:
|
|
304
|
+
response = client.put_object(
|
|
305
|
+
Bucket='releases',
|
|
306
|
+
Key=f'{version}/my-app-{version}.zip',
|
|
307
|
+
Body=f,
|
|
308
|
+
Metadata={'version': version, 'build': 'production'}
|
|
309
|
+
)
|
|
310
|
+
|
|
311
|
+
# Check compression stats (DeltaGlider extension)
|
|
312
|
+
if 'DeltaGliderInfo' in response:
|
|
313
|
+
info = response['DeltaGliderInfo']
|
|
314
|
+
if info.get('IsDelta'):
|
|
315
|
+
print(f"{version}: Stored as {info['StoredSizeMB']:.1f}MB delta "
|
|
316
|
+
f"(saved {info['SavingsPercent']:.0f}%)")
|
|
317
|
+
else:
|
|
318
|
+
print(f"{version}: Stored as reference ({info['OriginalSizeMB']:.1f}MB)")
|
|
282
319
|
|
|
283
320
|
# Result:
|
|
284
321
|
# v1.0.0: Stored as reference (100.0MB)
|
|
285
322
|
# v1.0.1: Stored as 0.2MB delta (saved 99.8%)
|
|
286
323
|
# v1.0.2: Stored as 0.3MB delta (saved 99.7%)
|
|
287
324
|
# v1.1.0: Stored as 5.2MB delta (saved 94.8%)
|
|
325
|
+
|
|
326
|
+
# Download using standard boto3 API
|
|
327
|
+
response = client.get_object(Bucket='releases', Key='v1.1.0/my-app-v1.1.0.zip')
|
|
328
|
+
with open('my-app-latest.zip', 'wb') as f:
|
|
329
|
+
f.write(response['Body'].read())
|
|
288
330
|
```
|
|
289
331
|
|
|
290
|
-
#### Advanced Example: Automated Backup
|
|
332
|
+
#### Advanced Example: Automated Backup with boto3 API
|
|
291
333
|
|
|
292
334
|
```python
|
|
293
335
|
from datetime import datetime
|
|
294
336
|
from deltaglider import create_client
|
|
295
337
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
log_level="INFO"
|
|
299
|
-
)
|
|
338
|
+
# Works with any S3-compatible storage
|
|
339
|
+
client = create_client(endpoint_url="http://minio.internal:9000")
|
|
300
340
|
|
|
301
341
|
def backup_database():
|
|
302
|
-
"""Daily database backup with automatic deduplication."""
|
|
342
|
+
"""Daily database backup with automatic deduplication using boto3 API."""
|
|
303
343
|
date = datetime.now().strftime("%Y%m%d")
|
|
304
344
|
|
|
305
345
|
# Create database dump
|
|
306
346
|
dump_file = f"backup-{date}.sql.gz"
|
|
307
347
|
|
|
308
|
-
# Upload
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
348
|
+
# Upload using boto3-compatible API
|
|
349
|
+
with open(dump_file, 'rb') as f:
|
|
350
|
+
response = client.put_object(
|
|
351
|
+
Bucket='backups',
|
|
352
|
+
Key=f'postgres/{date}/{dump_file}',
|
|
353
|
+
Body=f,
|
|
354
|
+
Tagging='type=daily&database=production',
|
|
355
|
+
Metadata={'date': date, 'source': 'production'}
|
|
356
|
+
)
|
|
357
|
+
|
|
358
|
+
# Check compression effectiveness (DeltaGlider extension)
|
|
359
|
+
if 'DeltaGliderInfo' in response:
|
|
360
|
+
info = response['DeltaGliderInfo']
|
|
361
|
+
if info['DeltaRatio'] > 0.1: # If delta is >10% of original
|
|
362
|
+
print(f"Warning: Low compression ({info['SavingsPercent']:.0f}%), "
|
|
363
|
+
"database might have significant changes")
|
|
364
|
+
print(f"Backup stored: {info['StoredSizeMB']:.1f}MB "
|
|
365
|
+
f"(compressed from {info['OriginalSizeMB']:.1f}MB)")
|
|
366
|
+
|
|
367
|
+
# List recent backups using boto3 API
|
|
368
|
+
response = client.list_objects(
|
|
369
|
+
Bucket='backups',
|
|
370
|
+
Prefix='postgres/',
|
|
371
|
+
MaxKeys=30
|
|
313
372
|
)
|
|
314
373
|
|
|
315
|
-
#
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
client.lifecycle_policy("s3://backups/postgres/",
|
|
322
|
-
days_before_archive=30,
|
|
323
|
-
days_before_delete=90)
|
|
324
|
-
|
|
325
|
-
return summary
|
|
374
|
+
# Clean up old backups
|
|
375
|
+
for obj in response.get('Contents', []):
|
|
376
|
+
# Parse date from key
|
|
377
|
+
obj_date = obj['Key'].split('/')[1]
|
|
378
|
+
if days_old(obj_date) > 30:
|
|
379
|
+
client.delete_object(Bucket='backups', Key=obj['Key'])
|
|
326
380
|
|
|
327
381
|
# Run backup
|
|
328
|
-
|
|
329
|
-
print(f"Backup complete: {result.stored_size_mb:.1f}MB stored")
|
|
382
|
+
backup_database()
|
|
330
383
|
```
|
|
331
384
|
|
|
332
385
|
For more examples and detailed API documentation, see the [SDK Documentation](docs/sdk/README.md).
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
[](https://github.com/jmacd/xdelta)
|
|
8
8
|
|
|
9
9
|
<div align="center">
|
|
10
|
-
<img src="https://github.com/
|
|
10
|
+
<img src="https://github.com/beshu-tech/deltaglider/raw/main/docs/deltaglider.png" alt="DeltaGlider Logo" width="500"/>
|
|
11
11
|
</div>
|
|
12
12
|
|
|
13
13
|
**Store 4TB of similar files in 5GB. No, that's not a typo.**
|
|
@@ -193,94 +193,148 @@ deltaglider ls -h s3://backups/
|
|
|
193
193
|
deltaglider rm -r s3://backups/2023/
|
|
194
194
|
```
|
|
195
195
|
|
|
196
|
-
### Python SDK
|
|
196
|
+
### Python SDK - Drop-in boto3 Replacement
|
|
197
197
|
|
|
198
198
|
**[📚 Full SDK Documentation](docs/sdk/README.md)** | **[API Reference](docs/sdk/api.md)** | **[Examples](docs/sdk/examples.md)**
|
|
199
199
|
|
|
200
|
-
#### Quick Start
|
|
200
|
+
#### Quick Start - boto3 Compatible API (Recommended)
|
|
201
|
+
|
|
202
|
+
DeltaGlider provides a **100% boto3-compatible API** that works as a drop-in replacement for AWS S3 SDK:
|
|
203
|
+
|
|
204
|
+
```python
|
|
205
|
+
from deltaglider import create_client
|
|
206
|
+
|
|
207
|
+
# Drop-in replacement for boto3.client('s3')
|
|
208
|
+
client = create_client() # Uses AWS credentials automatically
|
|
209
|
+
|
|
210
|
+
# Identical to boto3 S3 API - just works with 99% compression!
|
|
211
|
+
response = client.put_object(
|
|
212
|
+
Bucket='releases',
|
|
213
|
+
Key='v2.0.0/my-app.zip',
|
|
214
|
+
Body=open('my-app-v2.0.0.zip', 'rb')
|
|
215
|
+
)
|
|
216
|
+
print(f"Stored with ETag: {response['ETag']}")
|
|
217
|
+
|
|
218
|
+
# Standard boto3 get_object - handles delta reconstruction automatically
|
|
219
|
+
response = client.get_object(Bucket='releases', Key='v2.0.0/my-app.zip')
|
|
220
|
+
with open('downloaded.zip', 'wb') as f:
|
|
221
|
+
f.write(response['Body'].read())
|
|
222
|
+
|
|
223
|
+
# All boto3 S3 methods supported
|
|
224
|
+
client.list_objects(Bucket='releases', Prefix='v2.0.0/')
|
|
225
|
+
client.delete_object(Bucket='releases', Key='old-version.zip')
|
|
226
|
+
client.head_object(Bucket='releases', Key='v2.0.0/my-app.zip')
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
#### Simple API (Alternative)
|
|
230
|
+
|
|
231
|
+
For simpler use cases, DeltaGlider also provides a streamlined API:
|
|
201
232
|
|
|
202
233
|
```python
|
|
203
|
-
from pathlib import Path
|
|
204
234
|
from deltaglider import create_client
|
|
205
235
|
|
|
206
|
-
# Uses AWS credentials from environment or ~/.aws/credentials
|
|
207
236
|
client = create_client()
|
|
208
237
|
|
|
209
|
-
#
|
|
238
|
+
# Simple upload with automatic compression detection
|
|
210
239
|
summary = client.upload("my-app-v2.0.0.zip", "s3://releases/v2.0.0/")
|
|
211
240
|
print(f"Compressed from {summary.original_size_mb:.1f}MB to {summary.stored_size_mb:.1f}MB")
|
|
212
241
|
print(f"Saved {summary.savings_percent:.0f}% storage space")
|
|
213
242
|
|
|
214
|
-
#
|
|
243
|
+
# Simple download with automatic delta reconstruction
|
|
215
244
|
client.download("s3://releases/v2.0.0/my-app-v2.0.0.zip", "local-app.zip")
|
|
216
245
|
```
|
|
217
246
|
|
|
218
|
-
#### Real-World Example: Software Release Storage
|
|
247
|
+
#### Real-World Example: Software Release Storage with boto3 API
|
|
219
248
|
|
|
220
249
|
```python
|
|
221
250
|
from deltaglider import create_client
|
|
222
251
|
|
|
252
|
+
# Works exactly like boto3, but with 99% compression!
|
|
223
253
|
client = create_client()
|
|
224
254
|
|
|
225
|
-
# Upload multiple versions
|
|
255
|
+
# Upload multiple versions using boto3-compatible API
|
|
226
256
|
versions = ["v1.0.0", "v1.0.1", "v1.0.2", "v1.1.0"]
|
|
227
257
|
for version in versions:
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
258
|
+
with open(f"dist/my-app-{version}.zip", 'rb') as f:
|
|
259
|
+
response = client.put_object(
|
|
260
|
+
Bucket='releases',
|
|
261
|
+
Key=f'{version}/my-app-{version}.zip',
|
|
262
|
+
Body=f,
|
|
263
|
+
Metadata={'version': version, 'build': 'production'}
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
# Check compression stats (DeltaGlider extension)
|
|
267
|
+
if 'DeltaGliderInfo' in response:
|
|
268
|
+
info = response['DeltaGliderInfo']
|
|
269
|
+
if info.get('IsDelta'):
|
|
270
|
+
print(f"{version}: Stored as {info['StoredSizeMB']:.1f}MB delta "
|
|
271
|
+
f"(saved {info['SavingsPercent']:.0f}%)")
|
|
272
|
+
else:
|
|
273
|
+
print(f"{version}: Stored as reference ({info['OriginalSizeMB']:.1f}MB)")
|
|
236
274
|
|
|
237
275
|
# Result:
|
|
238
276
|
# v1.0.0: Stored as reference (100.0MB)
|
|
239
277
|
# v1.0.1: Stored as 0.2MB delta (saved 99.8%)
|
|
240
278
|
# v1.0.2: Stored as 0.3MB delta (saved 99.7%)
|
|
241
279
|
# v1.1.0: Stored as 5.2MB delta (saved 94.8%)
|
|
280
|
+
|
|
281
|
+
# Download using standard boto3 API
|
|
282
|
+
response = client.get_object(Bucket='releases', Key='v1.1.0/my-app-v1.1.0.zip')
|
|
283
|
+
with open('my-app-latest.zip', 'wb') as f:
|
|
284
|
+
f.write(response['Body'].read())
|
|
242
285
|
```
|
|
243
286
|
|
|
244
|
-
#### Advanced Example: Automated Backup
|
|
287
|
+
#### Advanced Example: Automated Backup with boto3 API
|
|
245
288
|
|
|
246
289
|
```python
|
|
247
290
|
from datetime import datetime
|
|
248
291
|
from deltaglider import create_client
|
|
249
292
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
log_level="INFO"
|
|
253
|
-
)
|
|
293
|
+
# Works with any S3-compatible storage
|
|
294
|
+
client = create_client(endpoint_url="http://minio.internal:9000")
|
|
254
295
|
|
|
255
296
|
def backup_database():
|
|
256
|
-
"""Daily database backup with automatic deduplication."""
|
|
297
|
+
"""Daily database backup with automatic deduplication using boto3 API."""
|
|
257
298
|
date = datetime.now().strftime("%Y%m%d")
|
|
258
299
|
|
|
259
300
|
# Create database dump
|
|
260
301
|
dump_file = f"backup-{date}.sql.gz"
|
|
261
302
|
|
|
262
|
-
# Upload
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
303
|
+
# Upload using boto3-compatible API
|
|
304
|
+
with open(dump_file, 'rb') as f:
|
|
305
|
+
response = client.put_object(
|
|
306
|
+
Bucket='backups',
|
|
307
|
+
Key=f'postgres/{date}/{dump_file}',
|
|
308
|
+
Body=f,
|
|
309
|
+
Tagging='type=daily&database=production',
|
|
310
|
+
Metadata={'date': date, 'source': 'production'}
|
|
311
|
+
)
|
|
312
|
+
|
|
313
|
+
# Check compression effectiveness (DeltaGlider extension)
|
|
314
|
+
if 'DeltaGliderInfo' in response:
|
|
315
|
+
info = response['DeltaGliderInfo']
|
|
316
|
+
if info['DeltaRatio'] > 0.1: # If delta is >10% of original
|
|
317
|
+
print(f"Warning: Low compression ({info['SavingsPercent']:.0f}%), "
|
|
318
|
+
"database might have significant changes")
|
|
319
|
+
print(f"Backup stored: {info['StoredSizeMB']:.1f}MB "
|
|
320
|
+
f"(compressed from {info['OriginalSizeMB']:.1f}MB)")
|
|
321
|
+
|
|
322
|
+
# List recent backups using boto3 API
|
|
323
|
+
response = client.list_objects(
|
|
324
|
+
Bucket='backups',
|
|
325
|
+
Prefix='postgres/',
|
|
326
|
+
MaxKeys=30
|
|
267
327
|
)
|
|
268
328
|
|
|
269
|
-
#
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
client.lifecycle_policy("s3://backups/postgres/",
|
|
276
|
-
days_before_archive=30,
|
|
277
|
-
days_before_delete=90)
|
|
278
|
-
|
|
279
|
-
return summary
|
|
329
|
+
# Clean up old backups
|
|
330
|
+
for obj in response.get('Contents', []):
|
|
331
|
+
# Parse date from key
|
|
332
|
+
obj_date = obj['Key'].split('/')[1]
|
|
333
|
+
if days_old(obj_date) > 30:
|
|
334
|
+
client.delete_object(Bucket='backups', Key=obj['Key'])
|
|
280
335
|
|
|
281
336
|
# Run backup
|
|
282
|
-
|
|
283
|
-
print(f"Backup complete: {result.stored_size_mb:.1f}MB stored")
|
|
337
|
+
backup_database()
|
|
284
338
|
```
|
|
285
339
|
|
|
286
340
|
For more examples and detailed API documentation, see the [SDK Documentation](docs/sdk/README.md).
|