omdev 0.0.0.dev227__py3-none-any.whl → 0.0.0.dev228__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- 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.dev227.dist-info → omdev-0.0.0.dev228.dist-info}/METADATA +6 -6
- {omdev-0.0.0.dev227.dist-info → omdev-0.0.0.dev228.dist-info}/RECORD +16 -16
- {omdev-0.0.0.dev227.dist-info → omdev-0.0.0.dev228.dist-info}/LICENSE +0 -0
- {omdev-0.0.0.dev227.dist-info → omdev-0.0.0.dev228.dist-info}/WHEEL +0 -0
- {omdev-0.0.0.dev227.dist-info → omdev-0.0.0.dev228.dist-info}/entry_points.txt +0 -0
- {omdev-0.0.0.dev227.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
|