cafs-cache-cdn-client 1.0.6__tar.gz → 1.0.8__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.
- {cafs_cache_cdn_client-1.0.6 → cafs_cache_cdn_client-1.0.8}/PKG-INFO +7 -6
- {cafs_cache_cdn_client-1.0.6 → cafs_cache_cdn_client-1.0.8}/README.md +5 -4
- {cafs_cache_cdn_client-1.0.6 → cafs_cache_cdn_client-1.0.8}/cafs_cache_cdn_client/__init__.py +1 -0
- {cafs_cache_cdn_client-1.0.6 → cafs_cache_cdn_client-1.0.8}/cafs_cache_cdn_client/cafs/blob/utils.py +3 -0
- {cafs_cache_cdn_client-1.0.6 → cafs_cache_cdn_client-1.0.8}/cafs_cache_cdn_client/cafs/client.py +22 -11
- {cafs_cache_cdn_client-1.0.6 → cafs_cache_cdn_client-1.0.8}/cafs_cache_cdn_client/client.py +4 -2
- {cafs_cache_cdn_client-1.0.6 → cafs_cache_cdn_client-1.0.8}/cafs_cache_cdn_client/file_utils.py +3 -2
- {cafs_cache_cdn_client-1.0.6 → cafs_cache_cdn_client-1.0.8}/pyproject.toml +2 -2
- {cafs_cache_cdn_client-1.0.6 → cafs_cache_cdn_client-1.0.8}/cafs_cache_cdn_client/cafs/README.md +0 -0
- {cafs_cache_cdn_client-1.0.6 → cafs_cache_cdn_client-1.0.8}/cafs_cache_cdn_client/cafs/__init__.py +0 -0
- {cafs_cache_cdn_client-1.0.6 → cafs_cache_cdn_client-1.0.8}/cafs_cache_cdn_client/cafs/blob/__init__.py +0 -0
- {cafs_cache_cdn_client-1.0.6 → cafs_cache_cdn_client-1.0.8}/cafs_cache_cdn_client/cafs/blob/hash_.py +0 -0
- {cafs_cache_cdn_client-1.0.6 → cafs_cache_cdn_client-1.0.8}/cafs_cache_cdn_client/cafs/blob/package.py +0 -0
- {cafs_cache_cdn_client-1.0.6 → cafs_cache_cdn_client-1.0.8}/cafs_cache_cdn_client/cafs/exceptions.py +0 -0
- {cafs_cache_cdn_client-1.0.6 → cafs_cache_cdn_client-1.0.8}/cafs_cache_cdn_client/cafs/types.py +0 -0
- {cafs_cache_cdn_client-1.0.6 → cafs_cache_cdn_client-1.0.8}/cafs_cache_cdn_client/repo/__init__.py +0 -0
- {cafs_cache_cdn_client-1.0.6 → cafs_cache_cdn_client-1.0.8}/cafs_cache_cdn_client/repo/client.py +0 -0
- {cafs_cache_cdn_client-1.0.6 → cafs_cache_cdn_client-1.0.8}/cafs_cache_cdn_client/repo/datatypes.py +0 -0
@@ -1,13 +1,13 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: cafs-cache-cdn-client
|
3
|
-
Version: 1.0.
|
3
|
+
Version: 1.0.8
|
4
4
|
Summary: Async Cache CDN client implementation
|
5
5
|
Keywords: cafs,cache
|
6
6
|
Author: Konstantin Belov
|
7
7
|
Author-email: k.belov@gaijin.team
|
8
8
|
Requires-Python: >=3.11,<4.0
|
9
9
|
Classifier: License :: OSI Approved :: MIT License
|
10
|
-
Classifier: Development Status ::
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
11
11
|
Classifier: Programming Language :: Python :: 3.11
|
12
12
|
Classifier: Programming Language :: Python :: 3.12
|
13
13
|
Classifier: Programming Language :: Python :: 3.13
|
@@ -38,7 +38,7 @@ pip install cafs-cache-cdn-client
|
|
38
38
|
import asyncio
|
39
39
|
import logging
|
40
40
|
from pathlib import Path
|
41
|
-
from cafs_cache_cdn_client import CacheCdnClient
|
41
|
+
from cafs_cache_cdn_client import CacheCdnClient, CompressionT
|
42
42
|
|
43
43
|
# Configure logging to see detailed operation information
|
44
44
|
logging.basicConfig(level=logging.DEBUG)
|
@@ -54,10 +54,11 @@ async def main():
|
|
54
54
|
|
55
55
|
# Use as an async context manager to ensure proper resource cleanup
|
56
56
|
async with client:
|
57
|
-
# Push a local directory to cache with a 2-hour TTL
|
57
|
+
# Push a local directory to cache with a 2-hour TTL and preferred ZSTD compression
|
58
58
|
await client.push('project_name', 'build_artifacts',
|
59
59
|
'/path/to/build/output', ttl_hours=2,
|
60
|
-
comment='Build artifacts from CI run #123'
|
60
|
+
comment='Build artifacts from CI run #123',
|
61
|
+
compression=CompressionT.ZSTD)
|
61
62
|
|
62
63
|
# Check if a reference exists
|
63
64
|
exists = await client.check('project_name', 'build_artifacts')
|
@@ -90,7 +91,7 @@ if __name__ == '__main__':
|
|
90
91
|
- `connection_per_cafs_server`: Number of concurrent connections per CAFS server
|
91
92
|
|
92
93
|
- **Methods**:
|
93
|
-
- `push(repo: str, ref: str, directory: Path | str, ttl_hours: int = 0, comment: str | None = None)` - Push a local directory to cache
|
94
|
+
- `push(repo: str, ref: str, directory: Path | str, ttl_hours: int = 0, comment: str | None = None, compression: CompressionT = CompressionT.NONE)` - Push a local directory to cache
|
94
95
|
- `pull(repo: str, ref: str, directory: Path | str)` - Pull cached content to a local directory
|
95
96
|
- `check(repo: str, ref: str) -> bool` - Check if a reference exists
|
96
97
|
- `tag(repo: str, ref: str, tag: str)` - Create a tag for a reference
|
@@ -18,7 +18,7 @@ pip install cafs-cache-cdn-client
|
|
18
18
|
import asyncio
|
19
19
|
import logging
|
20
20
|
from pathlib import Path
|
21
|
-
from cafs_cache_cdn_client import CacheCdnClient
|
21
|
+
from cafs_cache_cdn_client import CacheCdnClient, CompressionT
|
22
22
|
|
23
23
|
# Configure logging to see detailed operation information
|
24
24
|
logging.basicConfig(level=logging.DEBUG)
|
@@ -34,10 +34,11 @@ async def main():
|
|
34
34
|
|
35
35
|
# Use as an async context manager to ensure proper resource cleanup
|
36
36
|
async with client:
|
37
|
-
# Push a local directory to cache with a 2-hour TTL
|
37
|
+
# Push a local directory to cache with a 2-hour TTL and preferred ZSTD compression
|
38
38
|
await client.push('project_name', 'build_artifacts',
|
39
39
|
'/path/to/build/output', ttl_hours=2,
|
40
|
-
comment='Build artifacts from CI run #123'
|
40
|
+
comment='Build artifacts from CI run #123',
|
41
|
+
compression=CompressionT.ZSTD)
|
41
42
|
|
42
43
|
# Check if a reference exists
|
43
44
|
exists = await client.check('project_name', 'build_artifacts')
|
@@ -70,7 +71,7 @@ if __name__ == '__main__':
|
|
70
71
|
- `connection_per_cafs_server`: Number of concurrent connections per CAFS server
|
71
72
|
|
72
73
|
- **Methods**:
|
73
|
-
- `push(repo: str, ref: str, directory: Path | str, ttl_hours: int = 0, comment: str | None = None)` - Push a local directory to cache
|
74
|
+
- `push(repo: str, ref: str, directory: Path | str, ttl_hours: int = 0, comment: str | None = None, compression: CompressionT = CompressionT.NONE)` - Push a local directory to cache
|
74
75
|
- `pull(repo: str, ref: str, directory: Path | str)` - Pull cached content to a local directory
|
75
76
|
- `check(repo: str, ref: str) -> bool` - Check if a reference exists
|
76
77
|
- `tag(repo: str, ref: str, tag: str)` - Create a tag for a reference
|
{cafs_cache_cdn_client-1.0.6 → cafs_cache_cdn_client-1.0.8}/cafs_cache_cdn_client/cafs/blob/utils.py
RENAMED
@@ -28,6 +28,9 @@ def is_file_already_compressed(file_path: Path) -> bool:
|
|
28
28
|
def choose_compression(
|
29
29
|
file_path: Path, preferred_compression: CompressionT = CompressionT.NONE
|
30
30
|
) -> CompressionT:
|
31
|
+
if preferred_compression == CompressionT.NONE:
|
32
|
+
return preferred_compression
|
33
|
+
|
31
34
|
if file_path.stat().st_size < MINIMAL_COMPRESSION_SIZE:
|
32
35
|
return CompressionT.NONE
|
33
36
|
|
{cafs_cache_cdn_client-1.0.6 → cafs_cache_cdn_client-1.0.8}/cafs_cache_cdn_client/cafs/client.py
RENAMED
@@ -1,5 +1,4 @@
|
|
1
1
|
import asyncio
|
2
|
-
from asyncio import Queue, QueueShutDown
|
3
2
|
from collections.abc import (
|
4
3
|
AsyncIterator,
|
5
4
|
Callable,
|
@@ -282,7 +281,8 @@ class ConnectionPool:
|
|
282
281
|
|
283
282
|
_lock: asyncio.Lock
|
284
283
|
_connections: set[CAFSConnection]
|
285
|
-
_connection_queue: Queue[CAFSConnection]
|
284
|
+
_connection_queue: asyncio.Queue[CAFSConnection]
|
285
|
+
_close_event: asyncio.Event
|
286
286
|
|
287
287
|
def __init__(
|
288
288
|
self,
|
@@ -297,8 +297,9 @@ class ConnectionPool:
|
|
297
297
|
self.connection_per_server = connection_per_server
|
298
298
|
|
299
299
|
self._connections = set()
|
300
|
-
self._connection_queue = Queue()
|
300
|
+
self._connection_queue = asyncio.Queue()
|
301
301
|
self._lock = asyncio.Lock()
|
302
|
+
self._close_event = asyncio.Event()
|
302
303
|
|
303
304
|
async def get_connection_count(self) -> int:
|
304
305
|
async with self._lock:
|
@@ -315,10 +316,21 @@ class ConnectionPool:
|
|
315
316
|
await self._connection_queue.put(conn)
|
316
317
|
|
317
318
|
async def _get_connection(self) -> CAFSConnection:
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
319
|
+
if self._close_event.is_set():
|
320
|
+
raise EmptyConnectionPoolError()
|
321
|
+
get_task = asyncio.create_task(self._connection_queue.get())
|
322
|
+
close_task = asyncio.create_task(self._close_event.wait())
|
323
|
+
_, pending = await asyncio.wait(
|
324
|
+
[get_task, close_task], return_when=asyncio.FIRST_COMPLETED
|
325
|
+
)
|
326
|
+
|
327
|
+
for task in pending:
|
328
|
+
task.cancel()
|
329
|
+
|
330
|
+
if get_task in pending:
|
331
|
+
raise EmptyConnectionPoolError()
|
332
|
+
|
333
|
+
return get_task.result()
|
322
334
|
|
323
335
|
async def _release_connection(self, conn: CAFSConnection) -> None:
|
324
336
|
await self._connection_queue.put(conn)
|
@@ -328,14 +340,15 @@ class ConnectionPool:
|
|
328
340
|
async with self._lock:
|
329
341
|
self._connections.remove(conn)
|
330
342
|
if not self._connections:
|
331
|
-
self.
|
343
|
+
self._close_event.set()
|
332
344
|
|
333
345
|
async def close(self) -> None:
|
334
346
|
async with self._lock:
|
335
|
-
self.
|
347
|
+
self._close_event.set()
|
336
348
|
for conn in self._connections:
|
337
349
|
if conn.is_connected:
|
338
350
|
await conn.disconnect()
|
351
|
+
self._connections.clear()
|
339
352
|
|
340
353
|
@asynccontextmanager
|
341
354
|
async def connection(self) -> AsyncIterator[CAFSConnection]:
|
@@ -428,7 +441,6 @@ class CAFSClient:
|
|
428
441
|
stop_event = asyncio.Event()
|
429
442
|
workers = [asyncio.create_task(worker(stop_event)) for _ in range(len(blobs))]
|
430
443
|
errors = await asyncio.gather(*workers, return_exceptions=True)
|
431
|
-
files_queue.shutdown(immediate=True)
|
432
444
|
|
433
445
|
for err in errors:
|
434
446
|
if isinstance(err, Exception):
|
@@ -508,7 +520,6 @@ class CAFSClient:
|
|
508
520
|
asyncio.create_task(worker(stop_event)) for _ in range(max_concurrent)
|
509
521
|
]
|
510
522
|
errors = await asyncio.gather(*workers, return_exceptions=True)
|
511
|
-
files_queue.shutdown(immediate=True)
|
512
523
|
|
513
524
|
for err in errors:
|
514
525
|
if isinstance(err, Exception):
|
@@ -7,7 +7,7 @@ from typing import Any, Self, TypeVar
|
|
7
7
|
|
8
8
|
import aiofiles.os as aio_os
|
9
9
|
|
10
|
-
from cafs_cache_cdn_client.cafs import CAFSClient
|
10
|
+
from cafs_cache_cdn_client.cafs import CAFSClient, CompressionT
|
11
11
|
from cafs_cache_cdn_client.file_utils import (
|
12
12
|
LocalFile,
|
13
13
|
compare_file_lists,
|
@@ -64,6 +64,7 @@ class CacheCdnClient:
|
|
64
64
|
directory: Path | str,
|
65
65
|
ttl_hours: int = 0,
|
66
66
|
comment: str | None = None,
|
67
|
+
compression: CompressionT = CompressionT.NONE,
|
67
68
|
) -> None:
|
68
69
|
if isinstance(directory, str):
|
69
70
|
directory = Path(directory)
|
@@ -71,7 +72,8 @@ class CacheCdnClient:
|
|
71
72
|
raise ValueError(f'{directory} is not a directory')
|
72
73
|
files = walk(directory)
|
73
74
|
hashes = await self._cafs_client.stream_batch(
|
74
|
-
[directory / file.path for file in files]
|
75
|
+
[directory / file.path for file in files],
|
76
|
+
compression=compression,
|
75
77
|
)
|
76
78
|
await self._repo_client.post_ref_info(
|
77
79
|
repo,
|
{cafs_cache_cdn_client-1.0.6 → cafs_cache_cdn_client-1.0.8}/cafs_cache_cdn_client/file_utils.py
RENAMED
@@ -40,9 +40,10 @@ class LocalFile:
|
|
40
40
|
|
41
41
|
def walk(directory: Path) -> list[LocalFile]:
|
42
42
|
results = []
|
43
|
-
for root, _, files in
|
43
|
+
for root, _, files in os.walk(str(directory)):
|
44
|
+
root_ = Path(root)
|
44
45
|
for file in files:
|
45
|
-
file_ =
|
46
|
+
file_ = root_ / file
|
46
47
|
file_stat = file_.stat()
|
47
48
|
results.append(
|
48
49
|
LocalFile(
|
@@ -1,6 +1,6 @@
|
|
1
1
|
[project]
|
2
2
|
name = "cafs-cache-cdn-client"
|
3
|
-
version = "1.0.
|
3
|
+
version = "1.0.8"
|
4
4
|
description = "Async Cache CDN client implementation"
|
5
5
|
authors = [
|
6
6
|
{ name = "Konstantin Belov", "email" = "k.belov@gaijin.team" },
|
@@ -9,7 +9,7 @@ readme = "README.md"
|
|
9
9
|
keywords = ["cafs", "cache"]
|
10
10
|
classifiers = [
|
11
11
|
"License :: OSI Approved :: MIT License",
|
12
|
-
"Development Status ::
|
12
|
+
"Development Status :: 4 - Beta",
|
13
13
|
"Programming Language :: Python :: 3.11",
|
14
14
|
"Programming Language :: Python :: 3.12",
|
15
15
|
"Programming Language :: Python :: 3.13",
|
{cafs_cache_cdn_client-1.0.6 → cafs_cache_cdn_client-1.0.8}/cafs_cache_cdn_client/cafs/README.md
RENAMED
File without changes
|
{cafs_cache_cdn_client-1.0.6 → cafs_cache_cdn_client-1.0.8}/cafs_cache_cdn_client/cafs/__init__.py
RENAMED
File without changes
|
File without changes
|
{cafs_cache_cdn_client-1.0.6 → cafs_cache_cdn_client-1.0.8}/cafs_cache_cdn_client/cafs/blob/hash_.py
RENAMED
File without changes
|
File without changes
|
{cafs_cache_cdn_client-1.0.6 → cafs_cache_cdn_client-1.0.8}/cafs_cache_cdn_client/cafs/exceptions.py
RENAMED
File without changes
|
{cafs_cache_cdn_client-1.0.6 → cafs_cache_cdn_client-1.0.8}/cafs_cache_cdn_client/cafs/types.py
RENAMED
File without changes
|
{cafs_cache_cdn_client-1.0.6 → cafs_cache_cdn_client-1.0.8}/cafs_cache_cdn_client/repo/__init__.py
RENAMED
File without changes
|
{cafs_cache_cdn_client-1.0.6 → cafs_cache_cdn_client-1.0.8}/cafs_cache_cdn_client/repo/client.py
RENAMED
File without changes
|
{cafs_cache_cdn_client-1.0.6 → cafs_cache_cdn_client-1.0.8}/cafs_cache_cdn_client/repo/datatypes.py
RENAMED
File without changes
|