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
         
     |