omdev 0.0.0.dev226__py3-none-any.whl → 0.0.0.dev228__py3-none-any.whl
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.
- omdev/__about__.py +2 -2
- omdev/ci/cache.py +60 -4
- omdev/ci/cli.py +23 -2
- omdev/ci/github/cache.py +5 -8
- omdev/ci/github/inject.py +5 -14
- omdev/ci/inject.py +10 -15
- omdev/scripts/ci.py +120 -47
- omdev/scripts/interp.py +1 -1
- omdev/scripts/pyproject.py +1 -1
- omdev/tagstrings.py +19 -5
- {omdev-0.0.0.dev226.dist-info → omdev-0.0.0.dev228.dist-info}/METADATA +6 -6
- {omdev-0.0.0.dev226.dist-info → omdev-0.0.0.dev228.dist-info}/RECORD +16 -16
- {omdev-0.0.0.dev226.dist-info → omdev-0.0.0.dev228.dist-info}/LICENSE +0 -0
- {omdev-0.0.0.dev226.dist-info → omdev-0.0.0.dev228.dist-info}/WHEEL +0 -0
- {omdev-0.0.0.dev226.dist-info → omdev-0.0.0.dev228.dist-info}/entry_points.txt +0 -0
- {omdev-0.0.0.dev226.dist-info → omdev-0.0.0.dev228.dist-info}/top_level.txt +0 -0
omdev/__about__.py
CHANGED
@@ -13,7 +13,7 @@ class Project(ProjectBase):
|
|
13
13
|
|
14
14
|
optional_dependencies = {
|
15
15
|
'black': [
|
16
|
-
'black ~=
|
16
|
+
'black ~= 25.1',
|
17
17
|
],
|
18
18
|
|
19
19
|
'c': [
|
@@ -46,7 +46,7 @@ class Project(ProjectBase):
|
|
46
46
|
],
|
47
47
|
|
48
48
|
'wheel': [
|
49
|
-
'wheel ~= 0.
|
49
|
+
'wheel ~= 0.45',
|
50
50
|
],
|
51
51
|
}
|
52
52
|
|
omdev/ci/cache.py
CHANGED
@@ -1,10 +1,17 @@
|
|
1
1
|
# ruff: noqa: UP006 UP007
|
2
|
+
"""
|
3
|
+
TODO:
|
4
|
+
- os.mtime, Config.purge_after_days
|
5
|
+
- nice to have: get a total set of might-need keys ahead of time and keep those
|
6
|
+
- okay: just purge after running
|
7
|
+
"""
|
2
8
|
import abc
|
3
9
|
import asyncio
|
4
10
|
import dataclasses as dc
|
5
11
|
import functools
|
6
12
|
import os.path
|
7
13
|
import shutil
|
14
|
+
import time
|
8
15
|
import typing as ta
|
9
16
|
import urllib.request
|
10
17
|
|
@@ -70,6 +77,11 @@ class DirectoryFileCache(FileCache):
|
|
70
77
|
no_create: bool = False
|
71
78
|
no_purge: bool = False
|
72
79
|
|
80
|
+
no_update_mtime: bool = False
|
81
|
+
|
82
|
+
purge_max_age_s: ta.Optional[float] = None
|
83
|
+
purge_max_size_b: ta.Optional[int] = None
|
84
|
+
|
73
85
|
def __init__(
|
74
86
|
self,
|
75
87
|
config: Config,
|
@@ -90,6 +102,12 @@ class DirectoryFileCache(FileCache):
|
|
90
102
|
|
91
103
|
VERSION_FILE_NAME = '.ci-cache-version'
|
92
104
|
|
105
|
+
def _iter_dir_contents(self) -> ta.Iterator[str]:
|
106
|
+
for n in sorted(os.listdir(self.dir)):
|
107
|
+
if n.startswith('.'):
|
108
|
+
continue
|
109
|
+
yield os.path.join(self.dir, n)
|
110
|
+
|
93
111
|
@cached_nullary
|
94
112
|
def setup_dir(self) -> None:
|
95
113
|
version_file = os.path.join(self.dir, self.VERSION_FILE_NAME)
|
@@ -120,10 +138,7 @@ class DirectoryFileCache(FileCache):
|
|
120
138
|
f'due to present directories: {", ".join(dirs)}',
|
121
139
|
)
|
122
140
|
|
123
|
-
for
|
124
|
-
if n.startswith('.'):
|
125
|
-
continue
|
126
|
-
fp = os.path.join(self.dir, n)
|
141
|
+
for fp in self._iter_dir_contents():
|
127
142
|
check.state(os.path.isfile(fp))
|
128
143
|
log.debug('Purging stale cache file: %s', fp)
|
129
144
|
os.unlink(fp)
|
@@ -135,6 +150,42 @@ class DirectoryFileCache(FileCache):
|
|
135
150
|
|
136
151
|
#
|
137
152
|
|
153
|
+
def purge(self, *, dry_run: bool = False) -> None:
|
154
|
+
purge_max_age_s = self._config.purge_max_age_s
|
155
|
+
purge_max_size_b = self._config.purge_max_size_b
|
156
|
+
if self._config.no_purge or (purge_max_age_s is None and purge_max_size_b is None):
|
157
|
+
return
|
158
|
+
|
159
|
+
self.setup_dir()
|
160
|
+
|
161
|
+
purge_min_mtime: ta.Optional[float] = None
|
162
|
+
if purge_max_age_s is not None:
|
163
|
+
purge_min_mtime = time.time() - purge_max_age_s
|
164
|
+
|
165
|
+
dct: ta.Dict[str, os.stat_result] = {}
|
166
|
+
for fp in self._iter_dir_contents():
|
167
|
+
check.state(os.path.isfile(fp))
|
168
|
+
dct[fp] = os.stat(fp)
|
169
|
+
|
170
|
+
total_size_b = 0
|
171
|
+
for fp, st in sorted(dct.items(), key=lambda t: -t[1].st_mtime):
|
172
|
+
total_size_b += st.st_size
|
173
|
+
|
174
|
+
purge = False
|
175
|
+
if purge_min_mtime is not None and st.st_mtime < purge_min_mtime:
|
176
|
+
purge = True
|
177
|
+
if purge_max_size_b is not None and total_size_b >= purge_max_size_b:
|
178
|
+
purge = True
|
179
|
+
|
180
|
+
if not purge:
|
181
|
+
continue
|
182
|
+
|
183
|
+
log.debug('Purging cache file: %s', fp)
|
184
|
+
if not dry_run:
|
185
|
+
os.unlink(fp)
|
186
|
+
|
187
|
+
#
|
188
|
+
|
138
189
|
def get_cache_file_path(
|
139
190
|
self,
|
140
191
|
key: str,
|
@@ -151,6 +202,11 @@ class DirectoryFileCache(FileCache):
|
|
151
202
|
cache_file_path = self.get_cache_file_path(key)
|
152
203
|
if not os.path.exists(cache_file_path):
|
153
204
|
return None
|
205
|
+
|
206
|
+
if not self._config.no_update_mtime:
|
207
|
+
stat_info = os.stat(cache_file_path)
|
208
|
+
os.utime(cache_file_path, (stat_info.st_atime, time.time()))
|
209
|
+
|
154
210
|
return cache_file_path
|
155
211
|
|
156
212
|
async def put_file(
|
omdev/ci/cli.py
CHANGED
@@ -25,6 +25,7 @@ from omlish.lite.inject import inj
|
|
25
25
|
from omlish.lite.logs import log
|
26
26
|
from omlish.logs.standard import configure_standard_logging
|
27
27
|
|
28
|
+
from .cache import DirectoryFileCache
|
28
29
|
from .ci import Ci
|
29
30
|
from .compose import get_compose_service_dependencies
|
30
31
|
from .github.bootstrap import is_in_github_actions
|
@@ -70,6 +71,9 @@ class CiCli(ArgparseCli):
|
|
70
71
|
|
71
72
|
#
|
72
73
|
|
74
|
+
DEFAULT_PURGE_MAX_AGE_S = 60 * 60 * 24 * 30
|
75
|
+
DEFAULT_PURGE_MAX_SIZE_B = 1024 * 1024 * 1024 * 4
|
76
|
+
|
73
77
|
@argparse_cmd(
|
74
78
|
argparse_arg('project-dir'),
|
75
79
|
argparse_arg('service'),
|
@@ -79,6 +83,8 @@ class CiCli(ArgparseCli):
|
|
79
83
|
|
80
84
|
argparse_arg('--cache-dir'),
|
81
85
|
|
86
|
+
argparse_arg('--no-purge', action='store_true'),
|
87
|
+
|
82
88
|
argparse_arg('--github', action='store_true'),
|
83
89
|
argparse_arg('--github-detect', action='store_true'),
|
84
90
|
|
@@ -202,17 +208,32 @@ class CiCli(ArgparseCli):
|
|
202
208
|
run_options=run_options,
|
203
209
|
)
|
204
210
|
|
211
|
+
directory_file_cache_config: ta.Optional[DirectoryFileCache.Config] = None
|
212
|
+
if cache_dir is not None:
|
213
|
+
directory_file_cache_config = DirectoryFileCache.Config(
|
214
|
+
dir=cache_dir,
|
215
|
+
|
216
|
+
no_purge=bool(self.args.no_purge),
|
217
|
+
|
218
|
+
purge_max_age_s=self.DEFAULT_PURGE_MAX_AGE_S,
|
219
|
+
purge_max_size_b=self.DEFAULT_PURGE_MAX_SIZE_B,
|
220
|
+
)
|
221
|
+
|
205
222
|
injector = inj.create_injector(bind_ci(
|
206
223
|
config=config,
|
207
224
|
|
208
|
-
|
225
|
+
directory_file_cache_config=directory_file_cache_config,
|
209
226
|
|
210
|
-
|
227
|
+
github=github,
|
211
228
|
))
|
212
229
|
|
213
230
|
async with injector[Ci] as ci:
|
214
231
|
await ci.run()
|
215
232
|
|
233
|
+
if directory_file_cache_config is not None and not directory_file_cache_config.no_purge:
|
234
|
+
dfc = injector[DirectoryFileCache]
|
235
|
+
dfc.purge()
|
236
|
+
|
216
237
|
|
217
238
|
async def _async_main() -> ta.Optional[int]:
|
218
239
|
return await CiCli().async_cli_run()
|
omdev/ci/github/cache.py
CHANGED
@@ -21,14 +21,16 @@ from .client import GithubCacheServiceV1Client
|
|
21
21
|
class GithubCache(FileCache, DataCache):
|
22
22
|
@dc.dataclass(frozen=True)
|
23
23
|
class Config:
|
24
|
-
|
24
|
+
pass
|
25
25
|
|
26
26
|
def __init__(
|
27
27
|
self,
|
28
|
-
config: Config,
|
28
|
+
config: Config = Config(),
|
29
29
|
*,
|
30
30
|
client: ta.Optional[GithubCacheClient] = None,
|
31
31
|
version: ta.Optional[CacheVersion] = None,
|
32
|
+
|
33
|
+
local: DirectoryFileCache,
|
32
34
|
) -> None:
|
33
35
|
super().__init__(
|
34
36
|
version=version,
|
@@ -42,12 +44,7 @@ class GithubCache(FileCache, DataCache):
|
|
42
44
|
)
|
43
45
|
self._client: GithubCacheClient = client
|
44
46
|
|
45
|
-
self._local =
|
46
|
-
DirectoryFileCache.Config(
|
47
|
-
dir=check.non_empty_str(config.dir),
|
48
|
-
),
|
49
|
-
version=self._version,
|
50
|
-
)
|
47
|
+
self._local = local
|
51
48
|
|
52
49
|
#
|
53
50
|
|
omdev/ci/github/inject.py
CHANGED
@@ -12,19 +12,10 @@ from .cache import GithubCache
|
|
12
12
|
##
|
13
13
|
|
14
14
|
|
15
|
-
def bind_github(
|
16
|
-
|
17
|
-
|
18
|
-
)
|
19
|
-
|
20
|
-
|
21
|
-
if cache_dir is not None:
|
22
|
-
lst.extend([
|
23
|
-
inj.bind(GithubCache.Config(
|
24
|
-
dir=cache_dir,
|
25
|
-
)),
|
26
|
-
inj.bind(GithubCache, singleton=True),
|
27
|
-
inj.bind(FileCache, to_key=GithubCache),
|
28
|
-
])
|
15
|
+
def bind_github() -> InjectorBindings:
|
16
|
+
lst: ta.List[InjectorBindingOrBindings] = [
|
17
|
+
inj.bind(GithubCache, singleton=True),
|
18
|
+
inj.bind(FileCache, to_key=GithubCache),
|
19
|
+
]
|
29
20
|
|
30
21
|
return inj.as_bindings(*lst)
|
omdev/ci/inject.py
CHANGED
@@ -21,9 +21,9 @@ def bind_ci(
|
|
21
21
|
*,
|
22
22
|
config: Ci.Config,
|
23
23
|
|
24
|
-
|
24
|
+
directory_file_cache_config: ta.Optional[DirectoryFileCache.Config] = None,
|
25
25
|
|
26
|
-
|
26
|
+
github: bool = False,
|
27
27
|
) -> InjectorBindings:
|
28
28
|
lst: ta.List[InjectorBindingOrBindings] = [ # noqa
|
29
29
|
inj.bind(config),
|
@@ -42,20 +42,15 @@ def bind_ci(
|
|
42
42
|
),
|
43
43
|
))
|
44
44
|
|
45
|
-
if
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
45
|
+
if directory_file_cache_config is not None:
|
46
|
+
lst.extend([
|
47
|
+
inj.bind(directory_file_cache_config),
|
48
|
+
inj.bind(DirectoryFileCache, singleton=True),
|
49
|
+
])
|
50
50
|
|
51
|
+
if github:
|
52
|
+
lst.append(bind_github())
|
51
53
|
else:
|
52
|
-
lst.
|
53
|
-
inj.bind(DirectoryFileCache.Config(
|
54
|
-
dir=cache_dir,
|
55
|
-
)),
|
56
|
-
inj.bind(DirectoryFileCache, singleton=True),
|
57
|
-
inj.bind(FileCache, to_key=DirectoryFileCache),
|
58
|
-
|
59
|
-
])
|
54
|
+
lst.append(inj.bind(FileCache, to_key=DirectoryFileCache))
|
60
55
|
|
61
56
|
return inj.as_bindings(*lst)
|
omdev/scripts/ci.py
CHANGED
@@ -24,6 +24,8 @@ import contextlib
|
|
24
24
|
import contextvars
|
25
25
|
import dataclasses as dc
|
26
26
|
import datetime
|
27
|
+
import errno
|
28
|
+
import fcntl
|
27
29
|
import functools
|
28
30
|
import hashlib
|
29
31
|
import http.client
|
@@ -1094,7 +1096,7 @@ class Timeout(abc.ABC):
|
|
1094
1096
|
|
1095
1097
|
@classmethod
|
1096
1098
|
def _now(cls) -> float:
|
1097
|
-
return time.
|
1099
|
+
return time.monotonic()
|
1098
1100
|
|
1099
1101
|
#
|
1100
1102
|
|
@@ -1417,20 +1419,33 @@ log_timing_context = LogTimingContext
|
|
1417
1419
|
# ../../../omlish/os/files.py
|
1418
1420
|
|
1419
1421
|
|
1420
|
-
def
|
1422
|
+
def is_fd_open(fd: int) -> bool:
|
1423
|
+
try:
|
1424
|
+
fcntl.fcntl(fd, fcntl.F_GETFD)
|
1425
|
+
except OSError as e:
|
1426
|
+
if e.errno == errno.EBADF:
|
1427
|
+
return False
|
1428
|
+
raise
|
1429
|
+
else:
|
1430
|
+
return True
|
1431
|
+
|
1432
|
+
|
1433
|
+
def touch(path: str, mode: int = 0o666, exist_ok: bool = True) -> None:
|
1421
1434
|
if exist_ok:
|
1422
1435
|
# First try to bump modification time
|
1423
1436
|
# Implementation note: GNU touch uses the UTIME_NOW option of the utimensat() / futimens() functions.
|
1424
1437
|
try:
|
1425
|
-
os.utime(
|
1438
|
+
os.utime(path, None)
|
1426
1439
|
except OSError:
|
1427
1440
|
pass
|
1428
1441
|
else:
|
1429
1442
|
return
|
1443
|
+
|
1430
1444
|
flags = os.O_CREAT | os.O_WRONLY
|
1431
1445
|
if not exist_ok:
|
1432
1446
|
flags |= os.O_EXCL
|
1433
|
-
|
1447
|
+
|
1448
|
+
fd = os.open(path, flags, mode)
|
1434
1449
|
os.close(fd)
|
1435
1450
|
|
1436
1451
|
|
@@ -3458,6 +3473,12 @@ class SubprocessRunnable(abc.ABC, ta.Generic[T]):
|
|
3458
3473
|
|
3459
3474
|
########################################
|
3460
3475
|
# ../cache.py
|
3476
|
+
"""
|
3477
|
+
TODO:
|
3478
|
+
- os.mtime, Config.purge_after_days
|
3479
|
+
- nice to have: get a total set of might-need keys ahead of time and keep those
|
3480
|
+
- okay: just purge after running
|
3481
|
+
"""
|
3461
3482
|
|
3462
3483
|
|
3463
3484
|
CacheVersion = ta.NewType('CacheVersion', int)
|
@@ -3514,6 +3535,11 @@ class DirectoryFileCache(FileCache):
|
|
3514
3535
|
no_create: bool = False
|
3515
3536
|
no_purge: bool = False
|
3516
3537
|
|
3538
|
+
no_update_mtime: bool = False
|
3539
|
+
|
3540
|
+
purge_max_age_s: ta.Optional[float] = None
|
3541
|
+
purge_max_size_b: ta.Optional[int] = None
|
3542
|
+
|
3517
3543
|
def __init__(
|
3518
3544
|
self,
|
3519
3545
|
config: Config,
|
@@ -3534,6 +3560,12 @@ class DirectoryFileCache(FileCache):
|
|
3534
3560
|
|
3535
3561
|
VERSION_FILE_NAME = '.ci-cache-version'
|
3536
3562
|
|
3563
|
+
def _iter_dir_contents(self) -> ta.Iterator[str]:
|
3564
|
+
for n in sorted(os.listdir(self.dir)):
|
3565
|
+
if n.startswith('.'):
|
3566
|
+
continue
|
3567
|
+
yield os.path.join(self.dir, n)
|
3568
|
+
|
3537
3569
|
@cached_nullary
|
3538
3570
|
def setup_dir(self) -> None:
|
3539
3571
|
version_file = os.path.join(self.dir, self.VERSION_FILE_NAME)
|
@@ -3564,10 +3596,7 @@ class DirectoryFileCache(FileCache):
|
|
3564
3596
|
f'due to present directories: {", ".join(dirs)}',
|
3565
3597
|
)
|
3566
3598
|
|
3567
|
-
for
|
3568
|
-
if n.startswith('.'):
|
3569
|
-
continue
|
3570
|
-
fp = os.path.join(self.dir, n)
|
3599
|
+
for fp in self._iter_dir_contents():
|
3571
3600
|
check.state(os.path.isfile(fp))
|
3572
3601
|
log.debug('Purging stale cache file: %s', fp)
|
3573
3602
|
os.unlink(fp)
|
@@ -3579,6 +3608,42 @@ class DirectoryFileCache(FileCache):
|
|
3579
3608
|
|
3580
3609
|
#
|
3581
3610
|
|
3611
|
+
def purge(self, *, dry_run: bool = False) -> None:
|
3612
|
+
purge_max_age_s = self._config.purge_max_age_s
|
3613
|
+
purge_max_size_b = self._config.purge_max_size_b
|
3614
|
+
if self._config.no_purge or (purge_max_age_s is None and purge_max_size_b is None):
|
3615
|
+
return
|
3616
|
+
|
3617
|
+
self.setup_dir()
|
3618
|
+
|
3619
|
+
purge_min_mtime: ta.Optional[float] = None
|
3620
|
+
if purge_max_age_s is not None:
|
3621
|
+
purge_min_mtime = time.time() - purge_max_age_s
|
3622
|
+
|
3623
|
+
dct: ta.Dict[str, os.stat_result] = {}
|
3624
|
+
for fp in self._iter_dir_contents():
|
3625
|
+
check.state(os.path.isfile(fp))
|
3626
|
+
dct[fp] = os.stat(fp)
|
3627
|
+
|
3628
|
+
total_size_b = 0
|
3629
|
+
for fp, st in sorted(dct.items(), key=lambda t: -t[1].st_mtime):
|
3630
|
+
total_size_b += st.st_size
|
3631
|
+
|
3632
|
+
purge = False
|
3633
|
+
if purge_min_mtime is not None and st.st_mtime < purge_min_mtime:
|
3634
|
+
purge = True
|
3635
|
+
if purge_max_size_b is not None and total_size_b >= purge_max_size_b:
|
3636
|
+
purge = True
|
3637
|
+
|
3638
|
+
if not purge:
|
3639
|
+
continue
|
3640
|
+
|
3641
|
+
log.debug('Purging cache file: %s', fp)
|
3642
|
+
if not dry_run:
|
3643
|
+
os.unlink(fp)
|
3644
|
+
|
3645
|
+
#
|
3646
|
+
|
3582
3647
|
def get_cache_file_path(
|
3583
3648
|
self,
|
3584
3649
|
key: str,
|
@@ -3595,6 +3660,11 @@ class DirectoryFileCache(FileCache):
|
|
3595
3660
|
cache_file_path = self.get_cache_file_path(key)
|
3596
3661
|
if not os.path.exists(cache_file_path):
|
3597
3662
|
return None
|
3663
|
+
|
3664
|
+
if not self._config.no_update_mtime:
|
3665
|
+
stat_info = os.stat(cache_file_path)
|
3666
|
+
os.utime(cache_file_path, (stat_info.st_atime, time.time()))
|
3667
|
+
|
3598
3668
|
return cache_file_path
|
3599
3669
|
|
3600
3670
|
async def put_file(
|
@@ -4352,14 +4422,16 @@ def subprocess_maybe_shell_wrap_exec(*cmd: str) -> ta.Tuple[str, ...]:
|
|
4352
4422
|
class GithubCache(FileCache, DataCache):
|
4353
4423
|
@dc.dataclass(frozen=True)
|
4354
4424
|
class Config:
|
4355
|
-
|
4425
|
+
pass
|
4356
4426
|
|
4357
4427
|
def __init__(
|
4358
4428
|
self,
|
4359
|
-
config: Config,
|
4429
|
+
config: Config = Config(),
|
4360
4430
|
*,
|
4361
4431
|
client: ta.Optional[GithubCacheClient] = None,
|
4362
4432
|
version: ta.Optional[CacheVersion] = None,
|
4433
|
+
|
4434
|
+
local: DirectoryFileCache,
|
4363
4435
|
) -> None:
|
4364
4436
|
super().__init__(
|
4365
4437
|
version=version,
|
@@ -4373,12 +4445,7 @@ class GithubCache(FileCache, DataCache):
|
|
4373
4445
|
)
|
4374
4446
|
self._client: GithubCacheClient = client
|
4375
4447
|
|
4376
|
-
self._local =
|
4377
|
-
DirectoryFileCache.Config(
|
4378
|
-
dir=check.non_empty_str(config.dir),
|
4379
|
-
),
|
4380
|
-
version=self._version,
|
4381
|
-
)
|
4448
|
+
self._local = local
|
4382
4449
|
|
4383
4450
|
#
|
4384
4451
|
|
@@ -4677,20 +4744,11 @@ class BaseSubprocesses(abc.ABC): # noqa
|
|
4677
4744
|
##
|
4678
4745
|
|
4679
4746
|
|
4680
|
-
def bind_github(
|
4681
|
-
|
4682
|
-
|
4683
|
-
)
|
4684
|
-
|
4685
|
-
|
4686
|
-
if cache_dir is not None:
|
4687
|
-
lst.extend([
|
4688
|
-
inj.bind(GithubCache.Config(
|
4689
|
-
dir=cache_dir,
|
4690
|
-
)),
|
4691
|
-
inj.bind(GithubCache, singleton=True),
|
4692
|
-
inj.bind(FileCache, to_key=GithubCache),
|
4693
|
-
])
|
4747
|
+
def bind_github() -> InjectorBindings:
|
4748
|
+
lst: ta.List[InjectorBindingOrBindings] = [
|
4749
|
+
inj.bind(GithubCache, singleton=True),
|
4750
|
+
inj.bind(FileCache, to_key=GithubCache),
|
4751
|
+
]
|
4694
4752
|
|
4695
4753
|
return inj.as_bindings(*lst)
|
4696
4754
|
|
@@ -5912,9 +5970,9 @@ def bind_ci(
|
|
5912
5970
|
*,
|
5913
5971
|
config: Ci.Config,
|
5914
5972
|
|
5915
|
-
|
5973
|
+
directory_file_cache_config: ta.Optional[DirectoryFileCache.Config] = None,
|
5916
5974
|
|
5917
|
-
|
5975
|
+
github: bool = False,
|
5918
5976
|
) -> InjectorBindings:
|
5919
5977
|
lst: ta.List[InjectorBindingOrBindings] = [ # noqa
|
5920
5978
|
inj.bind(config),
|
@@ -5933,21 +5991,16 @@ def bind_ci(
|
|
5933
5991
|
),
|
5934
5992
|
))
|
5935
5993
|
|
5936
|
-
if
|
5937
|
-
|
5938
|
-
|
5939
|
-
|
5940
|
-
|
5994
|
+
if directory_file_cache_config is not None:
|
5995
|
+
lst.extend([
|
5996
|
+
inj.bind(directory_file_cache_config),
|
5997
|
+
inj.bind(DirectoryFileCache, singleton=True),
|
5998
|
+
])
|
5941
5999
|
|
6000
|
+
if github:
|
6001
|
+
lst.append(bind_github())
|
5942
6002
|
else:
|
5943
|
-
lst.
|
5944
|
-
inj.bind(DirectoryFileCache.Config(
|
5945
|
-
dir=cache_dir,
|
5946
|
-
)),
|
5947
|
-
inj.bind(DirectoryFileCache, singleton=True),
|
5948
|
-
inj.bind(FileCache, to_key=DirectoryFileCache),
|
5949
|
-
|
5950
|
-
])
|
6003
|
+
lst.append(inj.bind(FileCache, to_key=DirectoryFileCache))
|
5951
6004
|
|
5952
6005
|
return inj.as_bindings(*lst)
|
5953
6006
|
|
@@ -5992,6 +6045,9 @@ class CiCli(ArgparseCli):
|
|
5992
6045
|
|
5993
6046
|
#
|
5994
6047
|
|
6048
|
+
DEFAULT_PURGE_MAX_AGE_S = 60 * 60 * 24 * 30
|
6049
|
+
DEFAULT_PURGE_MAX_SIZE_B = 1024 * 1024 * 1024 * 4
|
6050
|
+
|
5995
6051
|
@argparse_cmd(
|
5996
6052
|
argparse_arg('project-dir'),
|
5997
6053
|
argparse_arg('service'),
|
@@ -6001,6 +6057,8 @@ class CiCli(ArgparseCli):
|
|
6001
6057
|
|
6002
6058
|
argparse_arg('--cache-dir'),
|
6003
6059
|
|
6060
|
+
argparse_arg('--no-purge', action='store_true'),
|
6061
|
+
|
6004
6062
|
argparse_arg('--github', action='store_true'),
|
6005
6063
|
argparse_arg('--github-detect', action='store_true'),
|
6006
6064
|
|
@@ -6124,17 +6182,32 @@ class CiCli(ArgparseCli):
|
|
6124
6182
|
run_options=run_options,
|
6125
6183
|
)
|
6126
6184
|
|
6185
|
+
directory_file_cache_config: ta.Optional[DirectoryFileCache.Config] = None
|
6186
|
+
if cache_dir is not None:
|
6187
|
+
directory_file_cache_config = DirectoryFileCache.Config(
|
6188
|
+
dir=cache_dir,
|
6189
|
+
|
6190
|
+
no_purge=bool(self.args.no_purge),
|
6191
|
+
|
6192
|
+
purge_max_age_s=self.DEFAULT_PURGE_MAX_AGE_S,
|
6193
|
+
purge_max_size_b=self.DEFAULT_PURGE_MAX_SIZE_B,
|
6194
|
+
)
|
6195
|
+
|
6127
6196
|
injector = inj.create_injector(bind_ci(
|
6128
6197
|
config=config,
|
6129
6198
|
|
6130
|
-
|
6199
|
+
directory_file_cache_config=directory_file_cache_config,
|
6131
6200
|
|
6132
|
-
|
6201
|
+
github=github,
|
6133
6202
|
))
|
6134
6203
|
|
6135
6204
|
async with injector[Ci] as ci:
|
6136
6205
|
await ci.run()
|
6137
6206
|
|
6207
|
+
if directory_file_cache_config is not None and not directory_file_cache_config.no_purge:
|
6208
|
+
dfc = injector[DirectoryFileCache]
|
6209
|
+
dfc.purge()
|
6210
|
+
|
6138
6211
|
|
6139
6212
|
async def _async_main() -> ta.Optional[int]:
|
6140
6213
|
return await CiCli().async_cli_run()
|
omdev/scripts/interp.py
CHANGED
omdev/scripts/pyproject.py
CHANGED
omdev/tagstrings.py
CHANGED
@@ -21,7 +21,10 @@ TAG_STRING_VALUE_TYPES: ta.Tuple = (
|
|
21
21
|
)
|
22
22
|
|
23
23
|
|
24
|
-
TAG_STRING_BOOL_STR_MAP: ta.Mapping[str, bool] = {
|
24
|
+
TAG_STRING_BOOL_STR_MAP: ta.Mapping[str, bool] = {
|
25
|
+
'true': True,
|
26
|
+
'false': False,
|
27
|
+
}
|
25
28
|
|
26
29
|
|
27
30
|
def check_tag_string_string(s: str) -> str:
|
@@ -31,7 +34,9 @@ def check_tag_string_string(s: str) -> str:
|
|
31
34
|
return s
|
32
35
|
|
33
36
|
|
34
|
-
def build_hierarchy_tag_string_values(
|
37
|
+
def build_hierarchy_tag_string_values(
|
38
|
+
m: ta.Mapping[str, ta.Any],
|
39
|
+
) -> ta.FrozenSet[HierarchyTagStringValue]:
|
35
40
|
def rec(c):
|
36
41
|
if isinstance(c, str):
|
37
42
|
yield (c,)
|
@@ -98,7 +103,10 @@ class TagString(ta.Generic[TagStringValueT]):
|
|
98
103
|
return cls(
|
99
104
|
name=name,
|
100
105
|
type=bool, # type: ignore
|
101
|
-
valid_values=
|
106
|
+
valid_values=(
|
107
|
+
frozenset(valid_values) # type: ignore
|
108
|
+
if valid_values is not None else None
|
109
|
+
),
|
102
110
|
**kwargs,
|
103
111
|
)
|
104
112
|
|
@@ -112,7 +120,10 @@ class TagString(ta.Generic[TagStringValueT]):
|
|
112
120
|
return cls(
|
113
121
|
name=name,
|
114
122
|
type=str, # type: ignore
|
115
|
-
valid_values=
|
123
|
+
valid_values=(
|
124
|
+
frozenset(check.not_isinstance(valid_values, str)) # type: ignore
|
125
|
+
if valid_values is not None else None
|
126
|
+
),
|
116
127
|
**kwargs,
|
117
128
|
)
|
118
129
|
|
@@ -126,7 +137,10 @@ class TagString(ta.Generic[TagStringValueT]):
|
|
126
137
|
return cls(
|
127
138
|
name=name,
|
128
139
|
type=HierarchyTagStringValue, # type: ignore
|
129
|
-
valid_values=
|
140
|
+
valid_values=(
|
141
|
+
build_hierarchy_tag_string_values(valid_values) # type: ignore
|
142
|
+
if valid_values is not None else None
|
143
|
+
),
|
130
144
|
**kwargs,
|
131
145
|
)
|
132
146
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: omdev
|
3
|
-
Version: 0.0.0.
|
3
|
+
Version: 0.0.0.dev228
|
4
4
|
Summary: omdev
|
5
5
|
Author: wrmsr
|
6
6
|
License: BSD-3-Clause
|
@@ -12,9 +12,9 @@ Classifier: Operating System :: OS Independent
|
|
12
12
|
Classifier: Operating System :: POSIX
|
13
13
|
Requires-Python: >=3.12
|
14
14
|
License-File: LICENSE
|
15
|
-
Requires-Dist: omlish==0.0.0.
|
15
|
+
Requires-Dist: omlish==0.0.0.dev228
|
16
16
|
Provides-Extra: all
|
17
|
-
Requires-Dist: black~=
|
17
|
+
Requires-Dist: black~=25.1; extra == "all"
|
18
18
|
Requires-Dist: pycparser~=2.22; extra == "all"
|
19
19
|
Requires-Dist: pcpp~=1.30; extra == "all"
|
20
20
|
Requires-Dist: cffi~=1.17; extra == "all"
|
@@ -24,9 +24,9 @@ Requires-Dist: mypy~=1.11; extra == "all"
|
|
24
24
|
Requires-Dist: gprof2dot~=2024.6; extra == "all"
|
25
25
|
Requires-Dist: prompt-toolkit~=3.0; extra == "all"
|
26
26
|
Requires-Dist: segno~=1.6; extra == "all"
|
27
|
-
Requires-Dist: wheel~=0.
|
27
|
+
Requires-Dist: wheel~=0.45; extra == "all"
|
28
28
|
Provides-Extra: black
|
29
|
-
Requires-Dist: black~=
|
29
|
+
Requires-Dist: black~=25.1; extra == "black"
|
30
30
|
Provides-Extra: c
|
31
31
|
Requires-Dist: pycparser~=2.22; extra == "c"
|
32
32
|
Requires-Dist: pcpp~=1.30; extra == "c"
|
@@ -43,4 +43,4 @@ Requires-Dist: prompt-toolkit~=3.0; extra == "ptk"
|
|
43
43
|
Provides-Extra: qr
|
44
44
|
Requires-Dist: segno~=1.6; extra == "qr"
|
45
45
|
Provides-Extra: wheel
|
46
|
-
Requires-Dist: wheel~=0.
|
46
|
+
Requires-Dist: wheel~=0.45; extra == "wheel"
|
@@ -1,5 +1,5 @@
|
|
1
1
|
omdev/.manifests.json,sha256=02pFpcoefn9JQr0AIqt_6-BnWi49KF0baoGEKv8bjn0,9093
|
2
|
-
omdev/__about__.py,sha256=
|
2
|
+
omdev/__about__.py,sha256=Iect_SBD2EXgx7QcFGiOqTHkOWD-bWOyvzgReDOY4Es,1214
|
3
3
|
omdev/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
4
4
|
omdev/bracepy.py,sha256=I8EdqtDvxzAi3I8TuMEW-RBfwXfqKbwp06CfOdj3L1o,2743
|
5
5
|
omdev/classdot.py,sha256=YOvgy6x295I_8NKBbBlRVd3AN7Osirm_Lqt4Wj0j9rY,1631
|
@@ -9,7 +9,7 @@ omdev/imgur.py,sha256=h38w1a1hFYAysfmD4uYXZo1yMj0NKzWgdQmedVSHnTc,3000
|
|
9
9
|
omdev/pip.py,sha256=7cZ_IOpekQvgPm_gKnX3Pr8xjqUid50PPScTlZCYVlM,2118
|
10
10
|
omdev/revisions.py,sha256=0feRWC0Uttd6K9cCImAHEXoo6-Nuso3tpaHUuhzBlRQ,4985
|
11
11
|
omdev/secrets.py,sha256=aC1o2vJtdLpa_MJoO2P2wty1pfqgAPytj54CamLLFWw,544
|
12
|
-
omdev/tagstrings.py,sha256=
|
12
|
+
omdev/tagstrings.py,sha256=zIP7nzcsZf5te0lphu6k36ND_cOvNFRg00neoTcoCs8,5484
|
13
13
|
omdev/wheelfile.py,sha256=yfupGcGkbFlmzGzKU64k_vmOKpaKnUlDWxeGn2KdekU,10005
|
14
14
|
omdev/amalg/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
15
15
|
omdev/amalg/__main__.py,sha256=1sZH8SLAueWxMxK9ngvndUW3L_rw7f-s_jK3ZP1yAH8,170
|
@@ -71,12 +71,12 @@ omdev/cexts/_distutils/compilers/options.py,sha256=H7r5IcLvga5Fs3jjXWIT-6ap3JBdu
|
|
71
71
|
omdev/cexts/_distutils/compilers/unixccompiler.py,sha256=o1h8QuyupLntv4F21_XjzAZmCiwwxJuTmOirvBSL-Qw,15419
|
72
72
|
omdev/ci/__init__.py,sha256=Y3l4WY4JRi2uLG6kgbGp93fuGfkxkKwZDvhsa0Rwgtk,15
|
73
73
|
omdev/ci/__main__.py,sha256=Jsrv3P7LX2Cg08W7ByZfZ1JQT4lgLDPW1qNAmShFuMk,75
|
74
|
-
omdev/ci/cache.py,sha256=
|
74
|
+
omdev/ci/cache.py,sha256=K3SirapVPEGcdq2_G1DeLc0hxweTPeer9DH3LlZZK8w,8350
|
75
75
|
omdev/ci/ci.py,sha256=JNFDs3sYCs93NOrnQxKiZNVnOotOwOL1CIEB4TL--Fg,6342
|
76
|
-
omdev/ci/cli.py,sha256=
|
76
|
+
omdev/ci/cli.py,sha256=CgFxNllLCn-hgVsq3w_RCBb3j3jjacZVtkFNQXxgBmE,6828
|
77
77
|
omdev/ci/compose.py,sha256=vHLuXO5e2paafBC0Kf-OUGoamtIJmQ19r2U3_oikk_g,4541
|
78
78
|
omdev/ci/consts.py,sha256=1puYfksvGOaVWEnbARM_sdMqs8oTn_VvsevsOtLsFno,21
|
79
|
-
omdev/ci/inject.py,sha256=
|
79
|
+
omdev/ci/inject.py,sha256=xo3AkobJKLLE7ZTa084NeGZm8pCABh4Wmh-RLRHFjTs,1460
|
80
80
|
omdev/ci/requirements.py,sha256=UKN6avU5V96YmmJL8XYvMPxzzOagrKpGTYadaxI2z9U,2105
|
81
81
|
omdev/ci/shell.py,sha256=cBPLMKiAJuNpPGj3ou6hpl88Xw7r99xpL91KJBQ0rqw,835
|
82
82
|
omdev/ci/utils.py,sha256=YxOT4S-YLDOAv27K0Q0SKzxncZrWFA_wNXlFOaJmQuI,304
|
@@ -94,11 +94,11 @@ omdev/ci/docker/utils.py,sha256=URioGRzqyqdJBZyOfzsrUwv5hSJ3WM23_sLHES9vamc,1129
|
|
94
94
|
omdev/ci/github/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
95
95
|
omdev/ci/github/api.py,sha256=Vqza7Hm1OCSfZYgdXF4exkjneqNjFcdO1pl8qmODskU,5198
|
96
96
|
omdev/ci/github/bootstrap.py,sha256=9OuftAz7CUd7uf2Or3sJFVozQQiwu0RGAlTOQNpLQIY,430
|
97
|
-
omdev/ci/github/cache.py,sha256=
|
97
|
+
omdev/ci/github/cache.py,sha256=n0nuEaGidvXBfB1ZU1G2Khp5Wuztoh_uNjPkny8KDdQ,2553
|
98
98
|
omdev/ci/github/cli.py,sha256=6mG0CllwrOoC7MDzKfKDqBHAjfF0gEI6aT5UAGMmuss,1114
|
99
99
|
omdev/ci/github/client.py,sha256=fT8rQ5RO5MXyjpIt6UEFR7escofkBau73m8KYMzcZFo,14614
|
100
100
|
omdev/ci/github/env.py,sha256=FQFjP_m7JWM7es9I51U-6UgJTwAt_UCVHFIYKTd9NKM,394
|
101
|
-
omdev/ci/github/inject.py,sha256=
|
101
|
+
omdev/ci/github/inject.py,sha256=Dwm2-qujyIqKYpBhiuebV3Lg5Gzf_cqk13NFVbf-8PQ,479
|
102
102
|
omdev/cli/__init__.py,sha256=V_l6VP1SZMlJbO-8CJwSuO9TThOy2S_oaPepNYgIrbE,37
|
103
103
|
omdev/cli/__main__.py,sha256=mOJpgc07o0r5luQ1DlX4tk2PqZkgmbwPbdzJ3KmtjgQ,138
|
104
104
|
omdev/cli/_pathhack.py,sha256=kxqb2kHap68Lkh8b211rDbcgj06hidBiAKA3f9posyc,2119
|
@@ -206,12 +206,12 @@ omdev/pyproject/resources/docker-dev.sh,sha256=DHkz5D18jok_oDolfg2mqrvGRWFoCe9GQ
|
|
206
206
|
omdev/pyproject/resources/python.sh,sha256=rFaN4SiJ9hdLDXXsDTwugI6zsw6EPkgYMmtacZeTbvw,749
|
207
207
|
omdev/scripts/__init__.py,sha256=MKCvUAEQwsIvwLixwtPlpBqmkMXLCnjjXyAXvVpDwVk,91
|
208
208
|
omdev/scripts/bumpversion.py,sha256=Kn7fo73Hs8uJh3Hi3EIyLOlzLPWAC6dwuD_lZ3cIzuY,1064
|
209
|
-
omdev/scripts/ci.py,sha256=
|
209
|
+
omdev/scripts/ci.py,sha256=sZeKGLX3XsmhL7n02npohUpE3Z3MWe03AkhZAh5mU94,162353
|
210
210
|
omdev/scripts/execrss.py,sha256=mR0G0wERBYtQmVIn63lCIIFb5zkCM6X_XOENDFYDBKc,651
|
211
211
|
omdev/scripts/exectime.py,sha256=S2O4MgtzTsFOY2IUJxsrnOIame9tEFc6aOlKP-F1JSg,1541
|
212
212
|
omdev/scripts/importtrace.py,sha256=oa7CtcWJVMNDbyIEiRHej6ICfABfErMeo4_haIqe18Q,14041
|
213
|
-
omdev/scripts/interp.py,sha256=
|
214
|
-
omdev/scripts/pyproject.py,sha256=
|
213
|
+
omdev/scripts/interp.py,sha256=hKBiphk6k9g2QVkPbEYDmdAeCQCDmhv98u5qfvAFlcA,150410
|
214
|
+
omdev/scripts/pyproject.py,sha256=qC1HifBvYyDOj_Caw6B7AvklgYcdtLhejVtA6V2yDYk,258083
|
215
215
|
omdev/scripts/slowcat.py,sha256=lssv4yrgJHiWfOiHkUut2p8E8Tq32zB-ujXESQxFFHY,2728
|
216
216
|
omdev/scripts/tmpexec.py,sha256=WTYcf56Tj2qjYV14AWmV8SfT0u6Y8eIU6cKgQRvEK3c,1442
|
217
217
|
omdev/tokens/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -243,9 +243,9 @@ omdev/tools/json/rendering.py,sha256=tMcjOW5edfozcMSTxxvF7WVTsbYLoe9bCKFh50qyaGw
|
|
243
243
|
omdev/tools/pawk/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
244
244
|
omdev/tools/pawk/__main__.py,sha256=VCqeRVnqT1RPEoIrqHFSu4PXVMg4YEgF4qCQm90-eRI,66
|
245
245
|
omdev/tools/pawk/pawk.py,sha256=zsEkfQX0jF5bn712uqPAyBSdJt2dno1LH2oeSMNfXQI,11424
|
246
|
-
omdev-0.0.0.
|
247
|
-
omdev-0.0.0.
|
248
|
-
omdev-0.0.0.
|
249
|
-
omdev-0.0.0.
|
250
|
-
omdev-0.0.0.
|
251
|
-
omdev-0.0.0.
|
246
|
+
omdev-0.0.0.dev228.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
|
247
|
+
omdev-0.0.0.dev228.dist-info/METADATA,sha256=F21kNK_t2VCTGzAd_c0dW2mXJ1zKvOPizv8l2cwnV4s,1636
|
248
|
+
omdev-0.0.0.dev228.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
249
|
+
omdev-0.0.0.dev228.dist-info/entry_points.txt,sha256=dHLXFmq5D9B8qUyhRtFqTGWGxlbx3t5ejedjrnXNYLU,33
|
250
|
+
omdev-0.0.0.dev228.dist-info/top_level.txt,sha256=1nr7j30fEWgLYHW3lGR9pkdHkb7knv1U1ES1XRNVQ6k,6
|
251
|
+
omdev-0.0.0.dev228.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|