omdev 0.0.0.dev221__tar.gz → 0.0.0.dev222__tar.gz
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-0.0.0.dev221/omdev.egg-info → omdev-0.0.0.dev222}/PKG-INFO +2 -2
- omdev-0.0.0.dev222/omdev/oci/building.py +123 -0
- omdev-0.0.0.dev222/omdev/oci/data.py +127 -0
- omdev-0.0.0.dev222/omdev/oci/datarefs.py +98 -0
- omdev-0.0.0.dev222/omdev/oci/loading.py +122 -0
- omdev-0.0.0.dev222/omdev/oci/media.py +159 -0
- omdev-0.0.0.dev222/omdev/oci/repositories.py +83 -0
- omdev-0.0.0.dev222/omdev/tools/pawk/__init__.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222/omdev.egg-info}/PKG-INFO +2 -2
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev.egg-info/SOURCES.txt +7 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev.egg-info/requires.txt +1 -1
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/pyproject.toml +2 -2
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/LICENSE +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/MANIFEST.in +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/README.rst +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/.manifests.json +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/__about__.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/__init__.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/amalg/__init__.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/amalg/__main__.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/amalg/gen.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/amalg/imports.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/amalg/main.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/amalg/manifests.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/amalg/resources.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/amalg/srcfiles.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/amalg/strip.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/amalg/types.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/amalg/typing.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/antlr/__init__.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/antlr/consts.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/antlr/gen.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/bracepy.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/cache/__init__.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/cache/compute/__init__.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/cache/compute/cache.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/cache/compute/contexts.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/cache/compute/currents.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/cache/compute/fns.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/cache/compute/resolvers.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/cache/compute/storage.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/cache/compute/types.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/cache/data/__init__.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/cache/data/actions.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/cache/data/cache.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/cache/data/consts.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/cache/data/defaults.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/cache/data/manifests.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/cache/data/specs.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/cc/__init__.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/cc/__main__.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/cc/cdeps.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/cc/cdeps.toml +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/cc/cli.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/cexts/__init__.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/cexts/_boilerplate.cc +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/cexts/_distutils/LICENSE +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/cexts/_distutils/__init__.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/cexts/_distutils/build_ext.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/cexts/_distutils/compilers/__init__.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/cexts/_distutils/compilers/ccompiler.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/cexts/_distutils/compilers/options.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/cexts/_distutils/compilers/unixccompiler.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/cexts/_distutils/dir_util.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/cexts/_distutils/errors.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/cexts/_distutils/extension.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/cexts/_distutils/file_util.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/cexts/_distutils/modified.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/cexts/_distutils/spawn.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/cexts/_distutils/sysconfig.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/cexts/_distutils/util.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/cexts/_distutils/version.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/cexts/build.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/cexts/cmake.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/cexts/importhook.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/cexts/magic.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/cexts/scan.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/ci/__init__.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/ci/__main__.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/ci/cache.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/ci/ci.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/ci/cli.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/ci/compose.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/ci/consts.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/ci/docker.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/ci/github/__init__.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/ci/github/api.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/ci/github/bootstrap.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/ci/github/cache.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/ci/github/cli.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/ci/github/client.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/ci/github/env.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/ci/requirements.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/ci/shell.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/ci/utils.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/classdot.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/cli/__init__.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/cli/__main__.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/cli/_pathhack.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/cli/clicli.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/cli/install.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/cli/main.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/cli/managers.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/cli/types.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/clipboard/__init__.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/clipboard/clipboard.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/clipboard/darwin_cf.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/clipboard/linux_x11.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/cmake.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/findimports.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/git/__init__.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/git/revisions.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/git/shallow.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/git/status.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/imgur.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/interp/__init__.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/interp/__main__.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/interp/cli.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/interp/default.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/interp/inject.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/interp/inspect.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/interp/providers/__init__.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/interp/providers/base.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/interp/providers/inject.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/interp/providers/running.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/interp/providers/standalone.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/interp/providers/system.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/interp/pyenv/__init__.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/interp/pyenv/inject.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/interp/pyenv/install.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/interp/pyenv/provider.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/interp/pyenv/pyenv.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/interp/resolvers.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/interp/types.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/interp/uv/__init__.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/interp/uv/inject.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/interp/uv/provider.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/interp/uv/uv.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/interp/venvs.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/magic/__init__.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/magic/__main__.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/magic/cli.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/magic/find.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/magic/magic.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/magic/prepare.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/magic/styles.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/manifests/__init__.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/manifests/__main__.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/manifests/build.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/manifests/main.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/mypy/__init__.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/mypy/debug.py +0 -0
- {omdev-0.0.0.dev221/omdev/packaging → omdev-0.0.0.dev222/omdev/oci}/__init__.py +0 -0
- {omdev-0.0.0.dev221/omdev/precheck → omdev-0.0.0.dev222/omdev/packaging}/__init__.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/packaging/marshal.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/packaging/names.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/packaging/requires.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/packaging/specifiers.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/packaging/versions.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/pip.py +0 -0
- {omdev-0.0.0.dev221/omdev/ptk/apps → omdev-0.0.0.dev222/omdev/precheck}/__init__.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/precheck/__main__.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/precheck/base.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/precheck/git.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/precheck/lite.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/precheck/main.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/precheck/manifests.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/precheck/scripts.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/ptk/__init__.py +0 -0
- {omdev-0.0.0.dev221/omdev/pycharm → omdev-0.0.0.dev222/omdev/ptk/apps}/__init__.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/ptk/apps/ncdu.py +0 -0
- {omdev-0.0.0.dev221/omdev/pyproject/resources → omdev-0.0.0.dev222/omdev/pycharm}/__init__.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/pycharm/__main__.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/pycharm/cli.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/pyproject/__init__.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/pyproject/__main__.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/pyproject/cexts.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/pyproject/cli.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/pyproject/configs.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/pyproject/inject.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/pyproject/pkg.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/pyproject/reqs.py +0 -0
- {omdev-0.0.0.dev221/omdev/tokens → omdev-0.0.0.dev222/omdev/pyproject/resources}/__init__.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/pyproject/resources/docker-dev.sh +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/pyproject/resources/python.sh +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/pyproject/venvs.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/revisions.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/scripts/__init__.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/scripts/bumpversion.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/scripts/ci.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/scripts/execrss.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/scripts/exectime.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/scripts/importtrace.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/scripts/interp.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/scripts/pyproject.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/scripts/slowcat.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/scripts/tmpexec.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/secrets.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/tagstrings.py +0 -0
- {omdev-0.0.0.dev221/omdev/tools/json → omdev-0.0.0.dev222/omdev/tokens}/__init__.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/tokens/all.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/tokens/tokenizert.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/tokens/utils.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/tools/__init__.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/tools/cloc.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/tools/doc.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/tools/docker.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/tools/git.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/tools/importscan.py +0 -0
- {omdev-0.0.0.dev221/omdev/tools/pawk → omdev-0.0.0.dev222/omdev/tools/json}/__init__.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/tools/json/__main__.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/tools/json/cli.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/tools/json/formats.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/tools/json/io.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/tools/json/parsing.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/tools/json/processing.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/tools/json/rendering.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/tools/linehisto.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/tools/mkenv.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/tools/mkrelimp.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/tools/notebook.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/tools/pawk/__main__.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/tools/pawk/pawk.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/tools/pip.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/tools/prof.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/tools/qr.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/tools/sqlrepl.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev/wheelfile.py +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev.egg-info/dependency_links.txt +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev.egg-info/entry_points.txt +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/omdev.egg-info/top_level.txt +0 -0
- {omdev-0.0.0.dev221 → omdev-0.0.0.dev222}/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.dev222
|
|
4
4
|
Summary: omdev
|
|
5
5
|
Author: wrmsr
|
|
6
6
|
License: BSD-3-Clause
|
|
@@ -12,7 +12,7 @@ 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.dev222
|
|
16
16
|
Provides-Extra: all
|
|
17
17
|
Requires-Dist: black~=24.10; extra == "all"
|
|
18
18
|
Requires-Dist: pycparser~=2.22; extra == "all"
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# ruff: noqa: UP006 UP007
|
|
2
|
+
# @omlish-lite
|
|
3
|
+
import dataclasses as dc
|
|
4
|
+
import typing as ta
|
|
5
|
+
|
|
6
|
+
from omlish.lite.check import check
|
|
7
|
+
from omlish.lite.json import json_dumps_compact
|
|
8
|
+
from omlish.lite.marshal import marshal_obj
|
|
9
|
+
|
|
10
|
+
from .data import OciDataclass
|
|
11
|
+
from .data import OciImageConfig
|
|
12
|
+
from .data import OciImageIndex
|
|
13
|
+
from .data import OciImageLayer
|
|
14
|
+
from .data import OciImageManifest
|
|
15
|
+
from .datarefs import BytesOciDataRef
|
|
16
|
+
from .datarefs import OciDataRef
|
|
17
|
+
from .datarefs import OciDataRefInfo
|
|
18
|
+
from .media import OCI_IMAGE_LAYER_KIND_MEDIA_TYPES
|
|
19
|
+
from .media import OciMediaDataclass
|
|
20
|
+
from .media import OciMediaDescriptor
|
|
21
|
+
from .media import OciMediaImageConfig
|
|
22
|
+
from .media import OciMediaImageIndex
|
|
23
|
+
from .media import OciMediaImageManifest
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
##
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class OciRepositoryBuilder:
|
|
30
|
+
def __init__(self) -> None:
|
|
31
|
+
super().__init__()
|
|
32
|
+
|
|
33
|
+
self._blobs: ta.Dict[str, OciDataRef] = {}
|
|
34
|
+
|
|
35
|
+
def get_blobs(self) -> ta.Dict[str, OciDataRef]:
|
|
36
|
+
return dict(self._blobs)
|
|
37
|
+
|
|
38
|
+
def add_blob(
|
|
39
|
+
self,
|
|
40
|
+
r: OciDataRef,
|
|
41
|
+
ri: ta.Optional[OciDataRefInfo] = None,
|
|
42
|
+
) -> None:
|
|
43
|
+
if ri is None:
|
|
44
|
+
ri = OciDataRefInfo(r)
|
|
45
|
+
if ri.digest() in self._blobs:
|
|
46
|
+
raise KeyError(ri.digest())
|
|
47
|
+
self._blobs[ri.digest()] = r
|
|
48
|
+
|
|
49
|
+
def marshal_media(self, obj: OciMediaDataclass) -> bytes:
|
|
50
|
+
check.isinstance(obj, OciMediaDataclass)
|
|
51
|
+
m = marshal_obj(obj)
|
|
52
|
+
j = json_dumps_compact(m)
|
|
53
|
+
b = j.encode('utf-8')
|
|
54
|
+
return b
|
|
55
|
+
|
|
56
|
+
def add_media(self, obj: OciMediaDataclass) -> OciMediaDescriptor:
|
|
57
|
+
b = self.marshal_media(obj)
|
|
58
|
+
|
|
59
|
+
r = BytesOciDataRef(b)
|
|
60
|
+
ri = OciDataRefInfo(r)
|
|
61
|
+
self.add_blob(r, ri)
|
|
62
|
+
|
|
63
|
+
return OciMediaDescriptor(
|
|
64
|
+
media_type=getattr(obj, 'media_type'),
|
|
65
|
+
digest=ri.digest(),
|
|
66
|
+
size=ri.size(),
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
def to_media(self, obj: OciDataclass) -> ta.Union[OciMediaDataclass, OciMediaDescriptor]:
|
|
70
|
+
def make_kw(*exclude):
|
|
71
|
+
return {
|
|
72
|
+
a: v
|
|
73
|
+
for f in dc.fields(obj)
|
|
74
|
+
if (a := f.name) not in exclude
|
|
75
|
+
for v in [getattr(obj, a)]
|
|
76
|
+
if v is not None
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if isinstance(obj, OciImageIndex):
|
|
80
|
+
return OciMediaImageIndex(
|
|
81
|
+
**make_kw('manifests'),
|
|
82
|
+
manifests=[
|
|
83
|
+
self.add_data(m)
|
|
84
|
+
for m in obj.manifests
|
|
85
|
+
],
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
elif isinstance(obj, OciImageManifest):
|
|
89
|
+
return OciMediaImageManifest(
|
|
90
|
+
**make_kw('config', 'layers'),
|
|
91
|
+
config=self.add_data(obj.config),
|
|
92
|
+
layers=[
|
|
93
|
+
self.add_data(l)
|
|
94
|
+
for l in obj.layers
|
|
95
|
+
],
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
elif isinstance(obj, OciImageLayer):
|
|
99
|
+
ri = OciDataRefInfo(obj.data)
|
|
100
|
+
self.add_blob(obj.data, ri)
|
|
101
|
+
return OciMediaDescriptor(
|
|
102
|
+
media_type=OCI_IMAGE_LAYER_KIND_MEDIA_TYPES[obj.kind],
|
|
103
|
+
digest=ri.digest(),
|
|
104
|
+
size=ri.size(),
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
elif isinstance(obj, OciImageConfig):
|
|
108
|
+
return OciMediaImageConfig(**make_kw())
|
|
109
|
+
|
|
110
|
+
else:
|
|
111
|
+
raise TypeError(obj)
|
|
112
|
+
|
|
113
|
+
def add_data(self, obj: OciDataclass) -> OciMediaDescriptor:
|
|
114
|
+
ret = self.to_media(obj)
|
|
115
|
+
|
|
116
|
+
if isinstance(ret, OciMediaDataclass):
|
|
117
|
+
return self.add_media(ret)
|
|
118
|
+
|
|
119
|
+
elif isinstance(ret, OciMediaDescriptor):
|
|
120
|
+
return ret
|
|
121
|
+
|
|
122
|
+
else:
|
|
123
|
+
raise TypeError(ret)
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# ruff: noqa: UP006 UP007
|
|
2
|
+
# @omlish-lite
|
|
3
|
+
import abc
|
|
4
|
+
import dataclasses as dc
|
|
5
|
+
import enum
|
|
6
|
+
import typing as ta
|
|
7
|
+
|
|
8
|
+
from omlish.lite.marshal import OBJ_MARSHALER_FIELD_KEY
|
|
9
|
+
from omlish.lite.marshal import OBJ_MARSHALER_OMIT_IF_NONE
|
|
10
|
+
|
|
11
|
+
from .datarefs import OciDataRef
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
##
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dc.dataclass()
|
|
18
|
+
class OciDataclass(abc.ABC): # noqa
|
|
19
|
+
pass
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
##
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@dc.dataclass()
|
|
26
|
+
class OciImageIndex(OciDataclass):
|
|
27
|
+
manifests: ta.List[ta.Union['OciImageIndex', 'OciImageManifest']]
|
|
28
|
+
|
|
29
|
+
annotations: ta.Optional[ta.Dict[str, str]] = None
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
#
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@dc.dataclass()
|
|
36
|
+
class OciImageManifest(OciDataclass):
|
|
37
|
+
config: 'OciImageConfig'
|
|
38
|
+
|
|
39
|
+
layers: ta.List['OciImageLayer']
|
|
40
|
+
|
|
41
|
+
annotations: ta.Optional[ta.Dict[str, str]] = None
|
|
42
|
+
|
|
43
|
+
#
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@dc.dataclass()
|
|
47
|
+
class OciImageLayer(OciDataclass):
|
|
48
|
+
class Kind(enum.Enum):
|
|
49
|
+
TAR = enum.auto()
|
|
50
|
+
TAR_GZIP = enum.auto()
|
|
51
|
+
TAR_ZSTD = enum.auto()
|
|
52
|
+
|
|
53
|
+
kind: Kind
|
|
54
|
+
|
|
55
|
+
data: OciDataRef
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
#
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
@dc.dataclass()
|
|
62
|
+
class OciImageConfig(OciDataclass):
|
|
63
|
+
"""https://github.com/opencontainers/image-spec/blob/92353b0bee778725c617e7d57317b568a7796bd0/config.md"""
|
|
64
|
+
|
|
65
|
+
architecture: str
|
|
66
|
+
os: str
|
|
67
|
+
|
|
68
|
+
@dc.dataclass()
|
|
69
|
+
class RootFs:
|
|
70
|
+
type: str
|
|
71
|
+
diff_ids: ta.List[str]
|
|
72
|
+
|
|
73
|
+
rootfs: RootFs
|
|
74
|
+
|
|
75
|
+
#
|
|
76
|
+
|
|
77
|
+
created: ta.Optional[str] = dc.field(default=None, metadata={OBJ_MARSHALER_OMIT_IF_NONE: True})
|
|
78
|
+
author: ta.Optional[str] = dc.field(default=None, metadata={OBJ_MARSHALER_OMIT_IF_NONE: True})
|
|
79
|
+
os_version: ta.Optional[str] = dc.field(default=None, metadata={OBJ_MARSHALER_FIELD_KEY: 'os.version', OBJ_MARSHALER_OMIT_IF_NONE: True}) # noqa
|
|
80
|
+
os_features: ta.Optional[ta.List[str]] = dc.field(default=None, metadata={OBJ_MARSHALER_FIELD_KEY: 'os.features', OBJ_MARSHALER_OMIT_IF_NONE: True}) # noqa
|
|
81
|
+
variant: ta.Optional[str] = dc.field(default=None, metadata={OBJ_MARSHALER_OMIT_IF_NONE: True})
|
|
82
|
+
|
|
83
|
+
"""
|
|
84
|
+
config object, OPTIONAL
|
|
85
|
+
User string, OPTIONAL
|
|
86
|
+
ExposedPorts object, OPTIONAL
|
|
87
|
+
Env array of strings, OPTIONAL
|
|
88
|
+
Entrypoint array of strings, OPTIONAL
|
|
89
|
+
Cmd array of strings, OPTIONAL
|
|
90
|
+
Volumes object, OPTIONAL
|
|
91
|
+
WorkingDir string, OPTIONAL
|
|
92
|
+
Labels object, OPTIONAL
|
|
93
|
+
StopSignal string, OPTIONAL
|
|
94
|
+
ArgsEscaped boolean, OPTIONAL
|
|
95
|
+
Memory integer, OPTIONAL
|
|
96
|
+
MemorySwap integer, OPTIONAL
|
|
97
|
+
CpuShares integer, OPTIONAL
|
|
98
|
+
Healthcheck object, OPTIONAL
|
|
99
|
+
"""
|
|
100
|
+
config: ta.Optional[ta.Dict[str, ta.Any]] = dc.field(default=None, metadata={OBJ_MARSHALER_OMIT_IF_NONE: True})
|
|
101
|
+
|
|
102
|
+
@dc.dataclass()
|
|
103
|
+
class History:
|
|
104
|
+
created: ta.Optional[str] = dc.field(default=None, metadata={OBJ_MARSHALER_OMIT_IF_NONE: True})
|
|
105
|
+
author: ta.Optional[str] = dc.field(default=None, metadata={OBJ_MARSHALER_OMIT_IF_NONE: True})
|
|
106
|
+
created_by: ta.Optional[str] = dc.field(default=None, metadata={OBJ_MARSHALER_OMIT_IF_NONE: True})
|
|
107
|
+
comment: ta.Optional[str] = dc.field(default=None, metadata={OBJ_MARSHALER_OMIT_IF_NONE: True})
|
|
108
|
+
empty_layer: ta.Optional[bool] = dc.field(default=None, metadata={OBJ_MARSHALER_OMIT_IF_NONE: True})
|
|
109
|
+
|
|
110
|
+
history: ta.Optional[ta.List[History]] = dc.field(default=None, metadata={OBJ_MARSHALER_OMIT_IF_NONE: True})
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
##
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def is_empty_oci_dataclass(obj: OciDataclass) -> bool:
|
|
117
|
+
if not isinstance(obj, OciDataclass):
|
|
118
|
+
raise TypeError(obj)
|
|
119
|
+
|
|
120
|
+
elif isinstance(obj, OciImageIndex):
|
|
121
|
+
return not obj.manifests
|
|
122
|
+
|
|
123
|
+
elif isinstance(obj, OciImageManifest):
|
|
124
|
+
return not obj.layers
|
|
125
|
+
|
|
126
|
+
else:
|
|
127
|
+
return False
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# ruff: noqa: UP006 UP007
|
|
2
|
+
# @omlish-lite
|
|
3
|
+
import abc
|
|
4
|
+
import dataclasses as dc
|
|
5
|
+
import hashlib
|
|
6
|
+
import io
|
|
7
|
+
import os.path
|
|
8
|
+
import shutil
|
|
9
|
+
import typing as ta
|
|
10
|
+
|
|
11
|
+
from omlish.lite.cached import cached_nullary
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
##
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dc.dataclass(frozen=True)
|
|
18
|
+
class OciDataRef(abc.ABC): # noqa
|
|
19
|
+
pass
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@dc.dataclass(frozen=True)
|
|
23
|
+
class BytesOciDataRef(OciDataRef):
|
|
24
|
+
data: bytes
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@dc.dataclass(frozen=True)
|
|
28
|
+
class FileOciDataRef(OciDataRef):
|
|
29
|
+
path: str
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
##
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@dc.dataclass(frozen=True)
|
|
36
|
+
class OciDataRefInfo:
|
|
37
|
+
data: OciDataRef
|
|
38
|
+
|
|
39
|
+
@cached_nullary
|
|
40
|
+
def sha256(self) -> str:
|
|
41
|
+
if isinstance(self.data, FileOciDataRef):
|
|
42
|
+
with open(self.data.path, 'rb') as f:
|
|
43
|
+
return hashlib.file_digest(f, 'sha256').hexdigest() # noqa
|
|
44
|
+
|
|
45
|
+
elif isinstance(self.data, BytesOciDataRef):
|
|
46
|
+
return hashlib.sha256(self.data.data).hexdigest()
|
|
47
|
+
|
|
48
|
+
else:
|
|
49
|
+
raise TypeError(self.data)
|
|
50
|
+
|
|
51
|
+
@cached_nullary
|
|
52
|
+
def digest(self) -> str:
|
|
53
|
+
return f'sha256:{self.sha256()}'
|
|
54
|
+
|
|
55
|
+
@cached_nullary
|
|
56
|
+
def size(self) -> int:
|
|
57
|
+
if isinstance(self.data, FileOciDataRef):
|
|
58
|
+
return os.path.getsize(self.data.path)
|
|
59
|
+
|
|
60
|
+
elif isinstance(self.data, BytesOciDataRef):
|
|
61
|
+
return len(self.data.data)
|
|
62
|
+
|
|
63
|
+
else:
|
|
64
|
+
raise TypeError(self.data)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def write_oci_data_ref_to_file(
|
|
68
|
+
data: OciDataRef,
|
|
69
|
+
dst: str,
|
|
70
|
+
*,
|
|
71
|
+
symlink: bool = False,
|
|
72
|
+
) -> None:
|
|
73
|
+
if isinstance(data, FileOciDataRef):
|
|
74
|
+
if symlink:
|
|
75
|
+
os.symlink(
|
|
76
|
+
os.path.relpath(data.path, os.path.dirname(dst)),
|
|
77
|
+
dst,
|
|
78
|
+
)
|
|
79
|
+
else:
|
|
80
|
+
shutil.copyfile(data.path, dst)
|
|
81
|
+
|
|
82
|
+
elif isinstance(data, BytesOciDataRef):
|
|
83
|
+
with open(dst, 'wb') as f:
|
|
84
|
+
f.write(data.data)
|
|
85
|
+
|
|
86
|
+
else:
|
|
87
|
+
raise TypeError(data)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def open_oci_data_ref(data: OciDataRef) -> ta.BinaryIO:
|
|
91
|
+
if isinstance(data, FileOciDataRef):
|
|
92
|
+
return open(data.path, 'rb')
|
|
93
|
+
|
|
94
|
+
elif isinstance(data, BytesOciDataRef):
|
|
95
|
+
return io.BytesIO(data.data)
|
|
96
|
+
|
|
97
|
+
else:
|
|
98
|
+
raise TypeError(data)
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# ruff: noqa: UP006 UP007
|
|
2
|
+
# @omlish-lite
|
|
3
|
+
import dataclasses as dc
|
|
4
|
+
import json
|
|
5
|
+
import typing as ta
|
|
6
|
+
|
|
7
|
+
from omlish.lite.check import check
|
|
8
|
+
|
|
9
|
+
from .data import OciImageConfig
|
|
10
|
+
from .data import OciImageIndex
|
|
11
|
+
from .data import OciImageLayer
|
|
12
|
+
from .data import OciImageManifest
|
|
13
|
+
from .data import is_empty_oci_dataclass
|
|
14
|
+
from .media import OCI_IMAGE_LAYER_KIND_MEDIA_TYPES_
|
|
15
|
+
from .media import OCI_MEDIA_FIELDS
|
|
16
|
+
from .media import OciMediaDescriptor
|
|
17
|
+
from .media import OciMediaImageConfig
|
|
18
|
+
from .media import OciMediaImageIndex
|
|
19
|
+
from .media import OciMediaImageManifest
|
|
20
|
+
from .media import unmarshal_oci_media_dataclass
|
|
21
|
+
from .repositories import OciRepository
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
T = ta.TypeVar('T')
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
##
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class OciRepositoryLoader:
|
|
31
|
+
def __init__(
|
|
32
|
+
self,
|
|
33
|
+
repo: OciRepository,
|
|
34
|
+
) -> None:
|
|
35
|
+
super().__init__()
|
|
36
|
+
|
|
37
|
+
self._repo = repo
|
|
38
|
+
|
|
39
|
+
#
|
|
40
|
+
|
|
41
|
+
def load_object(
|
|
42
|
+
self,
|
|
43
|
+
data: bytes,
|
|
44
|
+
cls: ta.Type[T] = object, # type: ignore[assignment]
|
|
45
|
+
*,
|
|
46
|
+
media_type: ta.Optional[str] = None,
|
|
47
|
+
) -> T:
|
|
48
|
+
text = data.decode('utf-8')
|
|
49
|
+
dct = json.loads(text)
|
|
50
|
+
obj = unmarshal_oci_media_dataclass(
|
|
51
|
+
dct,
|
|
52
|
+
media_type=media_type,
|
|
53
|
+
)
|
|
54
|
+
return check.isinstance(obj, cls)
|
|
55
|
+
|
|
56
|
+
def read_object(
|
|
57
|
+
self,
|
|
58
|
+
digest: str,
|
|
59
|
+
cls: ta.Type[T] = object, # type: ignore[assignment]
|
|
60
|
+
*,
|
|
61
|
+
media_type: ta.Optional[str] = None,
|
|
62
|
+
) -> T:
|
|
63
|
+
data = self._repo.read_blob(digest)
|
|
64
|
+
return self.load_object(
|
|
65
|
+
data,
|
|
66
|
+
cls,
|
|
67
|
+
media_type=media_type,
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
def read_descriptor(
|
|
71
|
+
self,
|
|
72
|
+
desc: OciMediaDescriptor,
|
|
73
|
+
cls: ta.Type[T] = object, # type: ignore[assignment]
|
|
74
|
+
) -> ta.Any:
|
|
75
|
+
return self.read_object(
|
|
76
|
+
desc.digest,
|
|
77
|
+
cls,
|
|
78
|
+
media_type=desc.media_type,
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
#
|
|
82
|
+
|
|
83
|
+
def from_media(self, obj: ta.Any) -> ta.Any:
|
|
84
|
+
def make_kw(*exclude):
|
|
85
|
+
return {
|
|
86
|
+
a: getattr(obj, a)
|
|
87
|
+
for f in dc.fields(obj)
|
|
88
|
+
if (a := f.name) not in OCI_MEDIA_FIELDS
|
|
89
|
+
and a not in exclude
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if isinstance(obj, OciMediaImageConfig):
|
|
93
|
+
return OciImageConfig(**make_kw())
|
|
94
|
+
|
|
95
|
+
elif isinstance(obj, OciMediaImageManifest):
|
|
96
|
+
return OciImageManifest(
|
|
97
|
+
**make_kw('config', 'layers'),
|
|
98
|
+
config=self.from_media(self.read_descriptor(obj.config)),
|
|
99
|
+
layers=[
|
|
100
|
+
OciImageLayer(
|
|
101
|
+
kind=lk,
|
|
102
|
+
data=self._repo.ref_blob(l.digest),
|
|
103
|
+
)
|
|
104
|
+
for l in obj.layers
|
|
105
|
+
if (lk := OCI_IMAGE_LAYER_KIND_MEDIA_TYPES_.get(l.media_type)) is not None
|
|
106
|
+
],
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
elif isinstance(obj, OciMediaImageIndex):
|
|
110
|
+
return OciImageIndex(
|
|
111
|
+
**make_kw('manifests'),
|
|
112
|
+
manifests=[
|
|
113
|
+
fm
|
|
114
|
+
for m in obj.manifests
|
|
115
|
+
if self._repo.contains_blob(m.digest)
|
|
116
|
+
for fm in [self.from_media(self.read_descriptor(m))]
|
|
117
|
+
if not is_empty_oci_dataclass(fm)
|
|
118
|
+
],
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
else:
|
|
122
|
+
raise TypeError(obj)
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# ruff: noqa: UP006 UP007
|
|
2
|
+
# @omlish-lite
|
|
3
|
+
import abc
|
|
4
|
+
import dataclasses as dc
|
|
5
|
+
import typing as ta
|
|
6
|
+
|
|
7
|
+
from omlish.lite.check import check
|
|
8
|
+
from omlish.lite.marshal import OBJ_MARSHALER_FIELD_KEY
|
|
9
|
+
from omlish.lite.marshal import OBJ_MARSHALER_OMIT_IF_NONE
|
|
10
|
+
from omlish.lite.marshal import unmarshal_obj
|
|
11
|
+
|
|
12
|
+
from .data import OciImageConfig
|
|
13
|
+
from .data import OciImageLayer
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
##
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
OCI_MEDIA_FIELDS: ta.Collection[str] = frozenset([
|
|
20
|
+
'schema_version',
|
|
21
|
+
'media_type',
|
|
22
|
+
])
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@dc.dataclass()
|
|
26
|
+
class OciMediaDataclass(abc.ABC): # noqa
|
|
27
|
+
SCHEMA_VERSION: ta.ClassVar[int]
|
|
28
|
+
MEDIA_TYPE: ta.ClassVar[str]
|
|
29
|
+
|
|
30
|
+
def __init_subclass__(cls, **kwargs: ta.Any) -> None:
|
|
31
|
+
super().__init_subclass__(**kwargs)
|
|
32
|
+
for a in OCI_MEDIA_FIELDS:
|
|
33
|
+
check.in_(a, cls.__dict__)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
_REGISTERED_OCI_MEDIA_DATACLASSES: ta.Dict[str, ta.Type[OciMediaDataclass]] = {}
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _register_oci_media_dataclass(cls):
|
|
40
|
+
check.issubclass(cls, OciMediaDataclass)
|
|
41
|
+
check.arg(dc.is_dataclass(cls))
|
|
42
|
+
mt = check.non_empty_str(cls.__dict__['MEDIA_TYPE'])
|
|
43
|
+
check.not_in(mt, _REGISTERED_OCI_MEDIA_DATACLASSES)
|
|
44
|
+
_REGISTERED_OCI_MEDIA_DATACLASSES[mt] = cls
|
|
45
|
+
return cls
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def get_registered_oci_media_dataclass(media_type: str) -> ta.Optional[ta.Type[OciMediaDataclass]]:
|
|
49
|
+
return _REGISTERED_OCI_MEDIA_DATACLASSES.get(media_type)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def unmarshal_oci_media_dataclass(
|
|
53
|
+
dct: ta.Mapping[str, ta.Any],
|
|
54
|
+
*,
|
|
55
|
+
media_type: ta.Optional[str] = None,
|
|
56
|
+
) -> ta.Any:
|
|
57
|
+
if media_type is None:
|
|
58
|
+
media_type = check.non_empty_str(dct['mediaType'])
|
|
59
|
+
cls = _REGISTERED_OCI_MEDIA_DATACLASSES[media_type]
|
|
60
|
+
return unmarshal_obj(dct, cls)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
##
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
@dc.dataclass()
|
|
67
|
+
class OciMediaDescriptor:
|
|
68
|
+
"""https://github.com/opencontainers/image-spec/blob/92353b0bee778725c617e7d57317b568a7796bd0/descriptor.md#properties""" # noqa
|
|
69
|
+
|
|
70
|
+
media_type: str = dc.field(metadata={OBJ_MARSHALER_FIELD_KEY: 'mediaType'})
|
|
71
|
+
digest: str
|
|
72
|
+
size: int
|
|
73
|
+
|
|
74
|
+
#
|
|
75
|
+
|
|
76
|
+
urls: ta.Optional[ta.Sequence[str]] = dc.field(default=None, metadata={OBJ_MARSHALER_OMIT_IF_NONE: True})
|
|
77
|
+
annotations: ta.Optional[ta.Mapping[str, str]] = dc.field(default=None, metadata={OBJ_MARSHALER_OMIT_IF_NONE: True}) # noqa
|
|
78
|
+
data: ta.Optional[str] = dc.field(default=None, metadata={OBJ_MARSHALER_OMIT_IF_NONE: True})
|
|
79
|
+
artifact_type: ta.Optional[str] = dc.field(default=None, metadata={OBJ_MARSHALER_FIELD_KEY: 'artifactType', OBJ_MARSHALER_OMIT_IF_NONE: True}) # noqa
|
|
80
|
+
|
|
81
|
+
#
|
|
82
|
+
|
|
83
|
+
platform: ta.Optional[ta.Mapping[str, ta.Any]] = dc.field(default=None, metadata={OBJ_MARSHALER_OMIT_IF_NONE: True}) # noqa
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
##
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
@_register_oci_media_dataclass
|
|
90
|
+
@dc.dataclass()
|
|
91
|
+
class OciMediaImageIndex(OciMediaDataclass):
|
|
92
|
+
"""https://github.com/opencontainers/image-spec/blob/92353b0bee778725c617e7d57317b568a7796bd0/image-index.md"""
|
|
93
|
+
|
|
94
|
+
manifests: ta.Sequence[OciMediaDescriptor] # -> OciMediaImageIndex | OciMediaImageManifest
|
|
95
|
+
|
|
96
|
+
#
|
|
97
|
+
|
|
98
|
+
annotations: ta.Optional[ta.Mapping[str, str]] = dc.field(default=None, metadata={OBJ_MARSHALER_OMIT_IF_NONE: True}) # noqa
|
|
99
|
+
|
|
100
|
+
#
|
|
101
|
+
|
|
102
|
+
SCHEMA_VERSION: ta.ClassVar[int] = 2
|
|
103
|
+
schema_version: int = dc.field(default=SCHEMA_VERSION, metadata={OBJ_MARSHALER_FIELD_KEY: 'schemaVersion'})
|
|
104
|
+
|
|
105
|
+
MEDIA_TYPE: ta.ClassVar[str] = 'application/vnd.oci.image.index.v1+json'
|
|
106
|
+
media_type: str = dc.field(default=MEDIA_TYPE, metadata={OBJ_MARSHALER_FIELD_KEY: 'mediaType'})
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
#
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
@_register_oci_media_dataclass
|
|
113
|
+
@dc.dataclass()
|
|
114
|
+
class OciMediaImageManifest(OciMediaDataclass):
|
|
115
|
+
"""https://github.com/opencontainers/image-spec/blob/92353b0bee778725c617e7d57317b568a7796bd0/manifest.md"""
|
|
116
|
+
|
|
117
|
+
config: OciMediaDescriptor # -> OciMediaImageConfig
|
|
118
|
+
|
|
119
|
+
layers: ta.Sequence[OciMediaDescriptor]
|
|
120
|
+
|
|
121
|
+
#
|
|
122
|
+
|
|
123
|
+
annotations: ta.Optional[ta.Mapping[str, str]] = dc.field(default=None, metadata={OBJ_MARSHALER_OMIT_IF_NONE: True}) # noqa
|
|
124
|
+
|
|
125
|
+
#
|
|
126
|
+
|
|
127
|
+
SCHEMA_VERSION: ta.ClassVar[int] = 2
|
|
128
|
+
schema_version: int = dc.field(default=SCHEMA_VERSION, metadata={OBJ_MARSHALER_FIELD_KEY: 'schemaVersion'})
|
|
129
|
+
|
|
130
|
+
MEDIA_TYPE: ta.ClassVar[str] = 'application/vnd.oci.image.manifest.v1+json'
|
|
131
|
+
media_type: str = dc.field(default=MEDIA_TYPE, metadata={OBJ_MARSHALER_FIELD_KEY: 'mediaType'})
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
#
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
OCI_IMAGE_LAYER_KIND_MEDIA_TYPES: ta.Mapping[OciImageLayer.Kind, str] = {
|
|
138
|
+
OciImageLayer.Kind.TAR: 'application/vnd.oci.image.layer.v1.tar',
|
|
139
|
+
OciImageLayer.Kind.TAR_GZIP: 'application/vnd.oci.image.layer.v1.tar+gzip',
|
|
140
|
+
OciImageLayer.Kind.TAR_ZSTD: 'application/vnd.oci.image.layer.v1.tar+zstd',
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
OCI_IMAGE_LAYER_KIND_MEDIA_TYPES_: ta.Mapping[str, OciImageLayer.Kind] = {
|
|
144
|
+
v: k
|
|
145
|
+
for k, v in OCI_IMAGE_LAYER_KIND_MEDIA_TYPES.items()
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
#
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
@_register_oci_media_dataclass
|
|
153
|
+
@dc.dataclass()
|
|
154
|
+
class OciMediaImageConfig(OciImageConfig, OciMediaDataclass):
|
|
155
|
+
SCHEMA_VERSION: ta.ClassVar[int] = 2
|
|
156
|
+
schema_version: int = dc.field(default=SCHEMA_VERSION, metadata={OBJ_MARSHALER_FIELD_KEY: 'schemaVersion'})
|
|
157
|
+
|
|
158
|
+
MEDIA_TYPE: ta.ClassVar[str] = 'application/vnd.oci.image.config.v1+json'
|
|
159
|
+
media_type: str = dc.field(default=MEDIA_TYPE, metadata={OBJ_MARSHALER_FIELD_KEY: 'mediaType'})
|