|
1 | 1 | """ Client for the SandboxStore.
|
2 | 2 | Will connect to the WorkloadManagement/SandboxStore service.
|
3 | 3 | """
|
| 4 | +from __future__ import annotations |
4 | 5 |
|
5 | 6 | import hashlib
|
6 | 7 | import os
|
7 | 8 | import re
|
8 | 9 | import tarfile
|
9 | 10 | import tempfile
|
| 11 | +from contextlib import contextmanager |
10 | 12 | from io import BytesIO, StringIO
|
| 13 | +from typing import Literal |
| 14 | + |
| 15 | +import zstandard |
11 | 16 |
|
12 | 17 | from DIRAC import S_ERROR, S_OK, gLogger
|
13 | 18 | from DIRAC.ConfigurationSystem.Client.Helpers.Registry import getVOForGroup
|
|
18 | 23 | from DIRAC.Resources.Storage.StorageElement import StorageElement
|
19 | 24 |
|
20 | 25 |
|
| 26 | +@contextmanager |
| 27 | +def ZstdCompatibleTarFile(tarFileName: os.PathLike, *, mode: Literal["r"] = "r"): |
| 28 | + """Context manager to extend tarfile.open to support zstd compressed files. |
| 29 | +
|
| 30 | + This is only needed for Python <=3.13. |
| 31 | + """ |
| 32 | + with open(tarFileName, "rb") as f: |
| 33 | + magic = f.read(4) |
| 34 | + # Read magic bytes to determine compression format |
| 35 | + if magic.startswith(b"\x28\xb5\x2f\xfd"): # zstd magic number |
| 36 | + dctx = zstandard.ZstdDecompressor() |
| 37 | + with dctx.stream_reader(f) as decompressor: |
| 38 | + with tarfile.open(fileobj=decompressor, mode=f"{mode}|") as tf: |
| 39 | + yield tf |
| 40 | + else: |
| 41 | + with tarfile.open(name=tarFileName, mode=mode) as tf: |
| 42 | + yield tf |
| 43 | + |
| 44 | + |
21 | 45 | class SandboxStoreClient:
|
22 | 46 | __validSandboxTypes = ("Input", "Output")
|
23 | 47 |
|
@@ -192,7 +216,7 @@ def downloadSandbox(self, sbLocation, destinationDir="", inMemory=False, unpack=
|
192 | 216 |
|
193 | 217 | try:
|
194 | 218 | sandboxSize = 0
|
195 |
| - with tarfile.open(name=tarFileName, mode="r") as tf: |
| 219 | + with ZstdCompatibleTarFile(tarFileName, mode="r") as tf: |
196 | 220 | for tarinfo in tf:
|
197 | 221 | tf.extract(tarinfo, path=destinationDir)
|
198 | 222 | sandboxSize += tarinfo.size
|
|
0 commit comments