omdev 0.0.0.dev221__py3-none-any.whl → 0.0.0.dev223__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. omdev/ci/cache.py +40 -23
  2. omdev/ci/ci.py +49 -109
  3. omdev/ci/cli.py +24 -23
  4. omdev/ci/docker/__init__.py +0 -0
  5. omdev/ci/docker/buildcaching.py +69 -0
  6. omdev/ci/docker/cache.py +57 -0
  7. omdev/ci/{docker.py → docker/cmds.py} +1 -44
  8. omdev/ci/docker/imagepulling.py +64 -0
  9. omdev/ci/docker/inject.py +37 -0
  10. omdev/ci/docker/utils.py +48 -0
  11. omdev/ci/github/cache.py +15 -5
  12. omdev/ci/github/inject.py +30 -0
  13. omdev/ci/inject.py +61 -0
  14. omdev/dataserver/__init__.py +1 -0
  15. omdev/dataserver/handlers.py +198 -0
  16. omdev/dataserver/http.py +69 -0
  17. omdev/dataserver/routes.py +49 -0
  18. omdev/dataserver/server.py +90 -0
  19. omdev/dataserver/targets.py +89 -0
  20. omdev/oci/__init__.py +0 -0
  21. omdev/oci/building.py +221 -0
  22. omdev/oci/compression.py +8 -0
  23. omdev/oci/data.py +151 -0
  24. omdev/oci/datarefs.py +138 -0
  25. omdev/oci/dataserver.py +61 -0
  26. omdev/oci/loading.py +142 -0
  27. omdev/oci/media.py +179 -0
  28. omdev/oci/packing.py +381 -0
  29. omdev/oci/repositories.py +159 -0
  30. omdev/oci/tars.py +144 -0
  31. omdev/pyproject/resources/python.sh +1 -1
  32. omdev/scripts/ci.py +1841 -384
  33. omdev/scripts/interp.py +100 -22
  34. omdev/scripts/pyproject.py +122 -28
  35. {omdev-0.0.0.dev221.dist-info → omdev-0.0.0.dev223.dist-info}/METADATA +2 -2
  36. {omdev-0.0.0.dev221.dist-info → omdev-0.0.0.dev223.dist-info}/RECORD +40 -15
  37. {omdev-0.0.0.dev221.dist-info → omdev-0.0.0.dev223.dist-info}/LICENSE +0 -0
  38. {omdev-0.0.0.dev221.dist-info → omdev-0.0.0.dev223.dist-info}/WHEEL +0 -0
  39. {omdev-0.0.0.dev221.dist-info → omdev-0.0.0.dev223.dist-info}/entry_points.txt +0 -0
  40. {omdev-0.0.0.dev221.dist-info → omdev-0.0.0.dev223.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,159 @@
1
+ # ruff: noqa: UP006 UP007
2
+ # @omlish-lite
3
+ import abc
4
+ import os.path
5
+ import tarfile
6
+ import typing as ta
7
+
8
+ from omlish.lite.check import check
9
+ from omlish.os.paths import is_path_in_dir
10
+
11
+ from .datarefs import BytesOciDataRef
12
+ from .datarefs import FileOciDataRef
13
+ from .datarefs import OciDataRef
14
+ from .datarefs import TarFileOciDataRef
15
+
16
+
17
+ ##
18
+
19
+
20
+ class OciRepository(abc.ABC):
21
+ @abc.abstractmethod
22
+ def contains_blob(self, digest: str) -> bool:
23
+ raise NotImplementedError
24
+
25
+ @abc.abstractmethod
26
+ def read_blob(self, digest: str) -> bytes:
27
+ raise NotImplementedError
28
+
29
+ @abc.abstractmethod
30
+ def ref_blob(self, digest: str) -> OciDataRef:
31
+ raise NotImplementedError
32
+
33
+ @classmethod
34
+ def of(
35
+ cls,
36
+ obj: ta.Union[
37
+ 'OciRepository',
38
+ str,
39
+ tarfile.TarFile,
40
+ ta.Mapping[str, bytes],
41
+ ],
42
+ ) -> 'OciRepository':
43
+ if isinstance(obj, OciRepository):
44
+ return obj
45
+
46
+ elif isinstance(obj, str):
47
+ check.arg(os.path.isdir(obj))
48
+ return DirectoryOciRepository(obj)
49
+
50
+ elif isinstance(obj, tarfile.TarFile):
51
+ return TarFileOciRepository(obj)
52
+
53
+ elif isinstance(obj, ta.Mapping):
54
+ return DictOciRepository(obj)
55
+
56
+ else:
57
+ raise TypeError(obj)
58
+
59
+
60
+ class FileOciRepository(OciRepository, abc.ABC):
61
+ @abc.abstractmethod
62
+ def read_file(self, path: str) -> bytes:
63
+ raise NotImplementedError
64
+
65
+
66
+ #
67
+
68
+
69
+ class DirectoryOciRepository(FileOciRepository):
70
+ def __init__(self, data_dir: str) -> None:
71
+ super().__init__()
72
+
73
+ self._data_dir = check.non_empty_str(data_dir)
74
+
75
+ def read_file(self, path: str) -> bytes:
76
+ full_path = os.path.join(self._data_dir, path)
77
+ check.arg(is_path_in_dir(self._data_dir, full_path))
78
+ with open(full_path, 'rb') as f:
79
+ return f.read()
80
+
81
+ def blob_path(self, digest: str) -> str:
82
+ scheme, value = digest.split(':')
83
+ return os.path.join('blobs', scheme, value)
84
+
85
+ def blob_full_path(self, digest: str) -> str:
86
+ path = self.blob_path(digest)
87
+ full_path = os.path.join(self._data_dir, path)
88
+ check.arg(is_path_in_dir(self._data_dir, full_path))
89
+ return full_path
90
+
91
+ def contains_blob(self, digest: str) -> bool:
92
+ return os.path.isfile(self.blob_full_path(digest))
93
+
94
+ def read_blob(self, digest: str) -> bytes:
95
+ return self.read_file(self.blob_path(digest))
96
+
97
+ def ref_blob(self, digest: str) -> OciDataRef:
98
+ return FileOciDataRef(self.blob_full_path(digest))
99
+
100
+
101
+ #
102
+
103
+
104
+ class TarFileOciRepository(FileOciRepository):
105
+ def __init__(self, tar_file: tarfile.TarFile) -> None:
106
+ super().__init__()
107
+
108
+ check.arg('r' in tar_file.mode)
109
+
110
+ self._tar_file = tar_file
111
+
112
+ def read_file(self, path: str) -> bytes:
113
+ if (ti := self._tar_file.getmember(path)) is None:
114
+ raise FileNotFoundError(path)
115
+ with check.not_none(self._tar_file.extractfile(ti)) as f:
116
+ return f.read()
117
+
118
+ def blob_name(self, digest: str) -> str:
119
+ scheme, value = digest.split(':')
120
+ return os.path.join('blobs', scheme, value)
121
+
122
+ def contains_blob(self, digest: str) -> bool:
123
+ try:
124
+ self._tar_file.getmember(self.blob_name(digest))
125
+ except KeyError:
126
+ return False
127
+ else:
128
+ return True
129
+
130
+ def read_blob(self, digest: str) -> bytes:
131
+ if (ti := self._tar_file.getmember(self.blob_name(digest))) is None:
132
+ raise KeyError(digest)
133
+ with check.not_none(self._tar_file.extractfile(ti)) as f:
134
+ return f.read()
135
+
136
+ def ref_blob(self, digest: str) -> OciDataRef:
137
+ return TarFileOciDataRef(
138
+ tar_file=self._tar_file,
139
+ tar_info=self._tar_file.getmember(self.blob_name(digest)),
140
+ )
141
+
142
+
143
+ #
144
+
145
+
146
+ class DictOciRepository(OciRepository):
147
+ def __init__(self, blobs: ta.Mapping[str, bytes]) -> None:
148
+ super().__init__()
149
+
150
+ self._blobs = blobs
151
+
152
+ def contains_blob(self, digest: str) -> bool:
153
+ return digest in self._blobs
154
+
155
+ def read_blob(self, digest: str) -> bytes:
156
+ return self._blobs[digest]
157
+
158
+ def ref_blob(self, digest: str) -> OciDataRef:
159
+ return BytesOciDataRef(self._blobs[digest])
omdev/oci/tars.py ADDED
@@ -0,0 +1,144 @@
1
+ # ruff: noqa: UP006 UP007
2
+ # @omlish-lite
3
+ import gzip
4
+ import hashlib
5
+ import tarfile
6
+ import typing as ta
7
+
8
+ from omlish.lite.contextmanagers import ExitStacked
9
+
10
+ from .compression import OciCompression
11
+ from .datarefs import OciDataRef
12
+ from .datarefs import OciDataRefInfo
13
+ from .datarefs import open_oci_data_ref
14
+
15
+
16
+ ##
17
+
18
+
19
+ class WrittenOciDataTarFileInfo(ta.NamedTuple):
20
+ compressed_sz: int
21
+ compressed_sha256: str
22
+
23
+ tar_sz: int
24
+ tar_sha256: str
25
+
26
+
27
+ class OciDataTarWriter(ExitStacked):
28
+ def __init__(
29
+ self,
30
+ f: ta.BinaryIO,
31
+ compression: ta.Optional[OciCompression] = None,
32
+ *,
33
+ gzip_level: int = 1,
34
+ zstd_level: int = 10,
35
+ ) -> None:
36
+ super().__init__()
37
+
38
+ self._f = f
39
+ self._compression = compression
40
+
41
+ self._gzip_level = gzip_level
42
+ self._zstd_level = zstd_level
43
+
44
+ class _FileWrapper:
45
+ def __init__(self, f):
46
+ super().__init__()
47
+
48
+ self._f = f
49
+ self._c = 0
50
+ self._h = hashlib.sha256()
51
+
52
+ @property
53
+ def size(self) -> int:
54
+ return self._c
55
+
56
+ def sha256(self) -> str:
57
+ return self._h.hexdigest()
58
+
59
+ def write(self, d):
60
+ self._c += len(d)
61
+ self._h.update(d)
62
+ self._f.write(d)
63
+
64
+ def tell(self) -> int:
65
+ return self._f.tell()
66
+
67
+ _cw: _FileWrapper
68
+ _cf: ta.BinaryIO
69
+
70
+ _tw: _FileWrapper
71
+ _tf: tarfile.TarFile
72
+
73
+ def info(self) -> WrittenOciDataTarFileInfo:
74
+ return WrittenOciDataTarFileInfo(
75
+ compressed_sz=self._cw.size,
76
+ compressed_sha256=self._cw.sha256(),
77
+
78
+ tar_sz=self._tw.size,
79
+ tar_sha256=self._tw.sha256(),
80
+ )
81
+
82
+ def __enter__(self) -> 'OciDataTarWriter':
83
+ super().__enter__()
84
+
85
+ #
86
+
87
+ self._cw = self._FileWrapper(self._f)
88
+
89
+ if self._compression is OciCompression.GZIP:
90
+ self._cf = self._enter_context(
91
+ gzip.GzipFile( # type: ignore
92
+ fileobj=self._cw,
93
+ mode='wb',
94
+ compresslevel=self._gzip_level,
95
+ ),
96
+ )
97
+
98
+ elif self._compression is OciCompression.ZSTD:
99
+ zc = __import__('zstandard').ZstdCompressor(
100
+ level=self._zstd_level,
101
+ )
102
+ self._cf = self._enter_context(zc.stream_writer(self._cw))
103
+
104
+ elif self._compression is None:
105
+ self._cf = self._cw # type: ignore
106
+
107
+ else:
108
+ raise ValueError(self._compression)
109
+
110
+ #
111
+
112
+ self._tw = self._FileWrapper(self._cf)
113
+
114
+ self._tf = self._enter_context(
115
+ tarfile.open( # type: ignore
116
+ fileobj=self._tw,
117
+ mode='w',
118
+ ),
119
+ )
120
+
121
+ #
122
+
123
+ return self
124
+
125
+ def tar_file(self) -> tarfile.TarFile:
126
+ return self._tf
127
+
128
+ def add_file(self, ti: tarfile.TarInfo, f: ta.Optional[ta.BinaryIO] = None) -> None:
129
+ self._tf.addfile(ti, f)
130
+
131
+
132
+ def write_oci_data_tar_file(
133
+ f: ta.BinaryIO,
134
+ data: ta.Mapping[str, OciDataRef],
135
+ ) -> WrittenOciDataTarFileInfo:
136
+ with OciDataTarWriter(f) as tgw:
137
+ for n, dr in data.items():
138
+ ti = tarfile.TarInfo(name=n)
139
+ ri = OciDataRefInfo(dr)
140
+ ti.size = ri.size()
141
+ with open_oci_data_ref(dr) as df:
142
+ tgw.add_file(ti, df)
143
+
144
+ return tgw.info()
@@ -2,7 +2,7 @@
2
2
  set -e
3
3
 
4
4
  if [ -z "${VENV}" ] ; then
5
- if [ $(uname) = "Linux" ] && (cat /proc/mounts | grep -E '^overlay / .*/(docker|desktop-containerd)/' > /dev/null) ; then
5
+ if [ $(uname) = "Linux" ] && grep -E '^overlay / .*/(docker|desktop-containerd)/' /proc/mounts > /dev/null ; then
6
6
  VENV=docker
7
7
  else
8
8
  VENV=default