omdev 0.0.0.dev227__tar.gz → 0.0.0.dev228__tar.gz
Sign up to get free protection for your applications and to get access to all the features.
- {omdev-0.0.0.dev227/omdev.egg-info → omdev-0.0.0.dev228}/PKG-INFO +6 -6
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/__about__.py +2 -2
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/ci/cache.py +60 -4
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/ci/cli.py +23 -2
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/ci/github/cache.py +5 -8
- omdev-0.0.0.dev228/omdev/ci/github/inject.py +21 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/ci/inject.py +10 -15
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/scripts/ci.py +120 -47
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/scripts/interp.py +1 -1
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/scripts/pyproject.py +1 -1
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/tagstrings.py +19 -5
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228/omdev.egg-info}/PKG-INFO +6 -6
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev.egg-info/requires.txt +5 -5
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/pyproject.toml +6 -6
- omdev-0.0.0.dev227/omdev/ci/github/inject.py +0 -30
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/LICENSE +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/MANIFEST.in +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/README.rst +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/.manifests.json +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/__init__.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/amalg/__init__.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/amalg/__main__.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/amalg/gen.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/amalg/imports.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/amalg/main.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/amalg/manifests.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/amalg/resources.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/amalg/srcfiles.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/amalg/strip.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/amalg/types.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/amalg/typing.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/antlr/__init__.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/antlr/consts.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/antlr/gen.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/bracepy.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/cache/__init__.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/cache/compute/__init__.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/cache/compute/cache.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/cache/compute/contexts.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/cache/compute/currents.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/cache/compute/fns.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/cache/compute/resolvers.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/cache/compute/storage.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/cache/compute/types.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/cache/data/__init__.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/cache/data/actions.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/cache/data/cache.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/cache/data/consts.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/cache/data/defaults.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/cache/data/manifests.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/cache/data/specs.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/cc/__init__.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/cc/__main__.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/cc/cdeps.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/cc/cdeps.toml +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/cc/cli.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/cexts/__init__.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/cexts/_boilerplate.cc +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/cexts/_distutils/LICENSE +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/cexts/_distutils/__init__.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/cexts/_distutils/build_ext.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/cexts/_distutils/compilers/__init__.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/cexts/_distutils/compilers/ccompiler.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/cexts/_distutils/compilers/options.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/cexts/_distutils/compilers/unixccompiler.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/cexts/_distutils/dir_util.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/cexts/_distutils/errors.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/cexts/_distutils/extension.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/cexts/_distutils/file_util.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/cexts/_distutils/modified.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/cexts/_distutils/spawn.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/cexts/_distutils/sysconfig.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/cexts/_distutils/util.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/cexts/_distutils/version.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/cexts/build.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/cexts/cmake.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/cexts/importhook.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/cexts/magic.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/cexts/scan.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/ci/__init__.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/ci/__main__.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/ci/ci.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/ci/compose.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/ci/consts.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/ci/docker/__init__.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/ci/docker/buildcaching.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/ci/docker/cache.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/ci/docker/cacheserved.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/ci/docker/cmds.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/ci/docker/dataserver.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/ci/docker/imagepulling.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/ci/docker/inject.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/ci/docker/packing.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/ci/docker/repositories.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/ci/docker/utils.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/ci/github/__init__.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/ci/github/api.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/ci/github/bootstrap.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/ci/github/cli.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/ci/github/client.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/ci/github/env.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/ci/requirements.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/ci/shell.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/ci/utils.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/classdot.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/cli/__init__.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/cli/__main__.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/cli/_pathhack.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/cli/clicli.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/cli/install.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/cli/main.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/cli/managers.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/cli/types.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/clipboard/__init__.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/clipboard/clipboard.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/clipboard/darwin_cf.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/clipboard/linux_x11.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/cmake.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/dataserver/__init__.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/dataserver/handlers.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/dataserver/http.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/dataserver/routes.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/dataserver/server.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/dataserver/targets.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/findimports.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/git/__init__.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/git/revisions.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/git/shallow.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/git/status.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/imgur.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/interp/__init__.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/interp/__main__.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/interp/cli.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/interp/default.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/interp/inject.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/interp/inspect.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/interp/providers/__init__.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/interp/providers/base.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/interp/providers/inject.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/interp/providers/running.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/interp/providers/standalone.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/interp/providers/system.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/interp/pyenv/__init__.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/interp/pyenv/inject.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/interp/pyenv/install.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/interp/pyenv/provider.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/interp/pyenv/pyenv.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/interp/resolvers.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/interp/types.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/interp/uv/__init__.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/interp/uv/inject.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/interp/uv/provider.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/interp/uv/uv.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/interp/venvs.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/magic/__init__.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/magic/__main__.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/magic/cli.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/magic/find.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/magic/magic.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/magic/prepare.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/magic/styles.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/manifests/__init__.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/manifests/__main__.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/manifests/build.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/manifests/main.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/mypy/__init__.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/mypy/debug.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/oci/__init__.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/oci/building.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/oci/compression.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/oci/data.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/oci/datarefs.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/oci/dataserver.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/oci/loading.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/oci/media.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/oci/pack/__init__.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/oci/pack/packing.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/oci/pack/repositories.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/oci/pack/unpacking.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/oci/repositories.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/oci/tars.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/packaging/__init__.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/packaging/marshal.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/packaging/names.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/packaging/requires.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/packaging/specifiers.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/packaging/versions.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/pip.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/precheck/__init__.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/precheck/__main__.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/precheck/base.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/precheck/git.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/precheck/lite.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/precheck/main.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/precheck/manifests.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/precheck/scripts.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/ptk/__init__.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/ptk/apps/__init__.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/ptk/apps/ncdu.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/pycharm/__init__.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/pycharm/__main__.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/pycharm/cli.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/pyproject/__init__.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/pyproject/__main__.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/pyproject/cexts.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/pyproject/cli.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/pyproject/configs.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/pyproject/inject.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/pyproject/pkg.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/pyproject/reqs.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/pyproject/resources/__init__.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/pyproject/resources/docker-dev.sh +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/pyproject/resources/python.sh +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/pyproject/venvs.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/revisions.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/scripts/__init__.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/scripts/bumpversion.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/scripts/execrss.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/scripts/exectime.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/scripts/importtrace.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/scripts/slowcat.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/scripts/tmpexec.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/secrets.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/tokens/__init__.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/tokens/all.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/tokens/tokenizert.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/tokens/utils.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/tools/__init__.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/tools/cloc.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/tools/doc.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/tools/docker.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/tools/git.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/tools/importscan.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/tools/json/__init__.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/tools/json/__main__.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/tools/json/cli.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/tools/json/formats.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/tools/json/io.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/tools/json/parsing.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/tools/json/processing.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/tools/json/rendering.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/tools/linehisto.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/tools/mkenv.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/tools/mkrelimp.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/tools/notebook.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/tools/pawk/__init__.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/tools/pawk/__main__.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/tools/pawk/pawk.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/tools/pip.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/tools/prof.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/tools/qr.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/tools/sqlrepl.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev/wheelfile.py +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev.egg-info/SOURCES.txt +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev.egg-info/dependency_links.txt +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev.egg-info/entry_points.txt +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/omdev.egg-info/top_level.txt +0 -0
- {omdev-0.0.0.dev227 → omdev-0.0.0.dev228}/setup.cfg +0 -0
@@ -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"
|
@@ -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
|
|
@@ -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(
|
@@ -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()
|
@@ -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
|
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# ruff: noqa: UP006 UP007
|
2
|
+
import typing as ta
|
3
|
+
|
4
|
+
from omlish.lite.inject import InjectorBindingOrBindings
|
5
|
+
from omlish.lite.inject import InjectorBindings
|
6
|
+
from omlish.lite.inject import inj
|
7
|
+
|
8
|
+
from ..cache import FileCache
|
9
|
+
from .cache import GithubCache
|
10
|
+
|
11
|
+
|
12
|
+
##
|
13
|
+
|
14
|
+
|
15
|
+
def bind_github() -> InjectorBindings:
|
16
|
+
lst: ta.List[InjectorBindingOrBindings] = [
|
17
|
+
inj.bind(GithubCache, singleton=True),
|
18
|
+
inj.bind(FileCache, to_key=GithubCache),
|
19
|
+
]
|
20
|
+
|
21
|
+
return inj.as_bindings(*lst)
|
@@ -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)
|
@@ -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()
|