omdev 0.0.0.dev223__tar.gz → 0.0.0.dev225__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
Files changed (258) hide show
  1. {omdev-0.0.0.dev223/omdev.egg-info → omdev-0.0.0.dev225}/PKG-INFO +2 -2
  2. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/amalg/typing.py +7 -1
  3. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/ci/cache.py +108 -0
  4. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/ci/ci.py +1 -1
  5. omdev-0.0.0.dev225/omdev/ci/docker/cacheserved.py +262 -0
  6. omdev-0.0.0.dev225/omdev/ci/docker/dataserver.py +204 -0
  7. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/ci/docker/imagepulling.py +2 -1
  8. omdev-0.0.0.dev225/omdev/ci/docker/packing.py +72 -0
  9. omdev-0.0.0.dev225/omdev/ci/docker/repositories.py +40 -0
  10. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/ci/github/cache.py +20 -1
  11. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/ci/github/client.py +9 -2
  12. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/ci/github/inject.py +4 -4
  13. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/ci/requirements.py +1 -1
  14. omdev-0.0.0.dev225/omdev/ci/utils.py +20 -0
  15. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/dataserver/targets.py +32 -0
  16. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/git/revisions.py +2 -2
  17. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/git/shallow.py +1 -1
  18. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/git/status.py +1 -1
  19. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/oci/data.py +19 -0
  20. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/oci/dataserver.py +4 -1
  21. omdev-0.0.0.dev225/omdev/oci/pack/packing.py +185 -0
  22. omdev-0.0.0.dev225/omdev/oci/pack/repositories.py +162 -0
  23. omdev-0.0.0.dev223/omdev/oci/packing.py → omdev-0.0.0.dev225/omdev/oci/pack/unpacking.py +0 -177
  24. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/oci/repositories.py +6 -0
  25. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/precheck/lite.py +1 -1
  26. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/pyproject/pkg.py +1 -1
  27. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/scripts/ci.py +773 -552
  28. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/scripts/interp.py +230 -299
  29. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/scripts/pyproject.py +328 -256
  30. omdev-0.0.0.dev225/omdev/tools/pawk/__init__.py +0 -0
  31. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225/omdev.egg-info}/PKG-INFO +2 -2
  32. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev.egg-info/SOURCES.txt +8 -1
  33. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev.egg-info/requires.txt +1 -1
  34. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/pyproject.toml +2 -2
  35. omdev-0.0.0.dev223/omdev/ci/utils.py +0 -69
  36. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/LICENSE +0 -0
  37. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/MANIFEST.in +0 -0
  38. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/README.rst +0 -0
  39. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/.manifests.json +0 -0
  40. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/__about__.py +0 -0
  41. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/__init__.py +0 -0
  42. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/amalg/__init__.py +0 -0
  43. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/amalg/__main__.py +0 -0
  44. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/amalg/gen.py +0 -0
  45. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/amalg/imports.py +0 -0
  46. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/amalg/main.py +0 -0
  47. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/amalg/manifests.py +0 -0
  48. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/amalg/resources.py +0 -0
  49. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/amalg/srcfiles.py +0 -0
  50. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/amalg/strip.py +0 -0
  51. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/amalg/types.py +0 -0
  52. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/antlr/__init__.py +0 -0
  53. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/antlr/consts.py +0 -0
  54. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/antlr/gen.py +0 -0
  55. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/bracepy.py +0 -0
  56. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/cache/__init__.py +0 -0
  57. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/cache/compute/__init__.py +0 -0
  58. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/cache/compute/cache.py +0 -0
  59. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/cache/compute/contexts.py +0 -0
  60. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/cache/compute/currents.py +0 -0
  61. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/cache/compute/fns.py +0 -0
  62. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/cache/compute/resolvers.py +0 -0
  63. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/cache/compute/storage.py +0 -0
  64. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/cache/compute/types.py +0 -0
  65. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/cache/data/__init__.py +0 -0
  66. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/cache/data/actions.py +0 -0
  67. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/cache/data/cache.py +0 -0
  68. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/cache/data/consts.py +0 -0
  69. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/cache/data/defaults.py +0 -0
  70. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/cache/data/manifests.py +0 -0
  71. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/cache/data/specs.py +0 -0
  72. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/cc/__init__.py +0 -0
  73. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/cc/__main__.py +0 -0
  74. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/cc/cdeps.py +0 -0
  75. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/cc/cdeps.toml +0 -0
  76. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/cc/cli.py +0 -0
  77. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/cexts/__init__.py +0 -0
  78. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/cexts/_boilerplate.cc +0 -0
  79. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/cexts/_distutils/LICENSE +0 -0
  80. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/cexts/_distutils/__init__.py +0 -0
  81. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/cexts/_distutils/build_ext.py +0 -0
  82. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/cexts/_distutils/compilers/__init__.py +0 -0
  83. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/cexts/_distutils/compilers/ccompiler.py +0 -0
  84. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/cexts/_distutils/compilers/options.py +0 -0
  85. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/cexts/_distutils/compilers/unixccompiler.py +0 -0
  86. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/cexts/_distutils/dir_util.py +0 -0
  87. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/cexts/_distutils/errors.py +0 -0
  88. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/cexts/_distutils/extension.py +0 -0
  89. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/cexts/_distutils/file_util.py +0 -0
  90. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/cexts/_distutils/modified.py +0 -0
  91. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/cexts/_distutils/spawn.py +0 -0
  92. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/cexts/_distutils/sysconfig.py +0 -0
  93. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/cexts/_distutils/util.py +0 -0
  94. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/cexts/_distutils/version.py +0 -0
  95. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/cexts/build.py +0 -0
  96. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/cexts/cmake.py +0 -0
  97. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/cexts/importhook.py +0 -0
  98. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/cexts/magic.py +0 -0
  99. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/cexts/scan.py +0 -0
  100. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/ci/__init__.py +0 -0
  101. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/ci/__main__.py +0 -0
  102. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/ci/cli.py +0 -0
  103. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/ci/compose.py +0 -0
  104. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/ci/consts.py +0 -0
  105. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/ci/docker/__init__.py +0 -0
  106. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/ci/docker/buildcaching.py +0 -0
  107. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/ci/docker/cache.py +0 -0
  108. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/ci/docker/cmds.py +0 -0
  109. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/ci/docker/inject.py +0 -0
  110. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/ci/docker/utils.py +0 -0
  111. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/ci/github/__init__.py +0 -0
  112. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/ci/github/api.py +0 -0
  113. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/ci/github/bootstrap.py +0 -0
  114. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/ci/github/cli.py +0 -0
  115. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/ci/github/env.py +0 -0
  116. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/ci/inject.py +0 -0
  117. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/ci/shell.py +0 -0
  118. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/classdot.py +0 -0
  119. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/cli/__init__.py +0 -0
  120. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/cli/__main__.py +0 -0
  121. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/cli/_pathhack.py +0 -0
  122. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/cli/clicli.py +0 -0
  123. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/cli/install.py +0 -0
  124. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/cli/main.py +0 -0
  125. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/cli/managers.py +0 -0
  126. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/cli/types.py +0 -0
  127. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/clipboard/__init__.py +0 -0
  128. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/clipboard/clipboard.py +0 -0
  129. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/clipboard/darwin_cf.py +0 -0
  130. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/clipboard/linux_x11.py +0 -0
  131. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/cmake.py +0 -0
  132. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/dataserver/__init__.py +0 -0
  133. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/dataserver/handlers.py +0 -0
  134. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/dataserver/http.py +0 -0
  135. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/dataserver/routes.py +0 -0
  136. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/dataserver/server.py +0 -0
  137. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/findimports.py +0 -0
  138. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/git/__init__.py +0 -0
  139. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/imgur.py +0 -0
  140. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/interp/__init__.py +0 -0
  141. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/interp/__main__.py +0 -0
  142. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/interp/cli.py +0 -0
  143. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/interp/default.py +0 -0
  144. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/interp/inject.py +0 -0
  145. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/interp/inspect.py +0 -0
  146. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/interp/providers/__init__.py +0 -0
  147. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/interp/providers/base.py +0 -0
  148. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/interp/providers/inject.py +0 -0
  149. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/interp/providers/running.py +0 -0
  150. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/interp/providers/standalone.py +0 -0
  151. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/interp/providers/system.py +0 -0
  152. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/interp/pyenv/__init__.py +0 -0
  153. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/interp/pyenv/inject.py +0 -0
  154. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/interp/pyenv/install.py +0 -0
  155. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/interp/pyenv/provider.py +0 -0
  156. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/interp/pyenv/pyenv.py +0 -0
  157. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/interp/resolvers.py +0 -0
  158. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/interp/types.py +0 -0
  159. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/interp/uv/__init__.py +0 -0
  160. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/interp/uv/inject.py +0 -0
  161. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/interp/uv/provider.py +0 -0
  162. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/interp/uv/uv.py +0 -0
  163. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/interp/venvs.py +0 -0
  164. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/magic/__init__.py +0 -0
  165. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/magic/__main__.py +0 -0
  166. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/magic/cli.py +0 -0
  167. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/magic/find.py +0 -0
  168. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/magic/magic.py +0 -0
  169. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/magic/prepare.py +0 -0
  170. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/magic/styles.py +0 -0
  171. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/manifests/__init__.py +0 -0
  172. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/manifests/__main__.py +0 -0
  173. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/manifests/build.py +0 -0
  174. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/manifests/main.py +0 -0
  175. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/mypy/__init__.py +0 -0
  176. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/mypy/debug.py +0 -0
  177. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/oci/__init__.py +0 -0
  178. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/oci/building.py +0 -0
  179. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/oci/compression.py +0 -0
  180. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/oci/datarefs.py +0 -0
  181. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/oci/loading.py +0 -0
  182. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/oci/media.py +0 -0
  183. {omdev-0.0.0.dev223/omdev/packaging → omdev-0.0.0.dev225/omdev/oci/pack}/__init__.py +0 -0
  184. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/oci/tars.py +0 -0
  185. {omdev-0.0.0.dev223/omdev/precheck → omdev-0.0.0.dev225/omdev/packaging}/__init__.py +0 -0
  186. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/packaging/marshal.py +0 -0
  187. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/packaging/names.py +0 -0
  188. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/packaging/requires.py +0 -0
  189. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/packaging/specifiers.py +0 -0
  190. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/packaging/versions.py +0 -0
  191. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/pip.py +0 -0
  192. {omdev-0.0.0.dev223/omdev/ptk/apps → omdev-0.0.0.dev225/omdev/precheck}/__init__.py +0 -0
  193. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/precheck/__main__.py +0 -0
  194. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/precheck/base.py +0 -0
  195. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/precheck/git.py +0 -0
  196. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/precheck/main.py +0 -0
  197. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/precheck/manifests.py +0 -0
  198. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/precheck/scripts.py +0 -0
  199. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/ptk/__init__.py +0 -0
  200. {omdev-0.0.0.dev223/omdev/pycharm → omdev-0.0.0.dev225/omdev/ptk/apps}/__init__.py +0 -0
  201. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/ptk/apps/ncdu.py +0 -0
  202. {omdev-0.0.0.dev223/omdev/pyproject/resources → omdev-0.0.0.dev225/omdev/pycharm}/__init__.py +0 -0
  203. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/pycharm/__main__.py +0 -0
  204. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/pycharm/cli.py +0 -0
  205. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/pyproject/__init__.py +0 -0
  206. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/pyproject/__main__.py +0 -0
  207. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/pyproject/cexts.py +0 -0
  208. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/pyproject/cli.py +0 -0
  209. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/pyproject/configs.py +0 -0
  210. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/pyproject/inject.py +0 -0
  211. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/pyproject/reqs.py +0 -0
  212. {omdev-0.0.0.dev223/omdev/tokens → omdev-0.0.0.dev225/omdev/pyproject/resources}/__init__.py +0 -0
  213. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/pyproject/resources/docker-dev.sh +0 -0
  214. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/pyproject/resources/python.sh +0 -0
  215. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/pyproject/venvs.py +0 -0
  216. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/revisions.py +0 -0
  217. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/scripts/__init__.py +0 -0
  218. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/scripts/bumpversion.py +0 -0
  219. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/scripts/execrss.py +0 -0
  220. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/scripts/exectime.py +0 -0
  221. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/scripts/importtrace.py +0 -0
  222. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/scripts/slowcat.py +0 -0
  223. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/scripts/tmpexec.py +0 -0
  224. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/secrets.py +0 -0
  225. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/tagstrings.py +0 -0
  226. {omdev-0.0.0.dev223/omdev/tools/json → omdev-0.0.0.dev225/omdev/tokens}/__init__.py +0 -0
  227. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/tokens/all.py +0 -0
  228. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/tokens/tokenizert.py +0 -0
  229. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/tokens/utils.py +0 -0
  230. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/tools/__init__.py +0 -0
  231. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/tools/cloc.py +0 -0
  232. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/tools/doc.py +0 -0
  233. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/tools/docker.py +0 -0
  234. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/tools/git.py +0 -0
  235. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/tools/importscan.py +0 -0
  236. {omdev-0.0.0.dev223/omdev/tools/pawk → omdev-0.0.0.dev225/omdev/tools/json}/__init__.py +0 -0
  237. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/tools/json/__main__.py +0 -0
  238. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/tools/json/cli.py +0 -0
  239. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/tools/json/formats.py +0 -0
  240. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/tools/json/io.py +0 -0
  241. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/tools/json/parsing.py +0 -0
  242. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/tools/json/processing.py +0 -0
  243. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/tools/json/rendering.py +0 -0
  244. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/tools/linehisto.py +0 -0
  245. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/tools/mkenv.py +0 -0
  246. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/tools/mkrelimp.py +0 -0
  247. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/tools/notebook.py +0 -0
  248. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/tools/pawk/__main__.py +0 -0
  249. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/tools/pawk/pawk.py +0 -0
  250. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/tools/pip.py +0 -0
  251. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/tools/prof.py +0 -0
  252. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/tools/qr.py +0 -0
  253. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/tools/sqlrepl.py +0 -0
  254. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev/wheelfile.py +0 -0
  255. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev.egg-info/dependency_links.txt +0 -0
  256. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev.egg-info/entry_points.txt +0 -0
  257. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/omdev.egg-info/top_level.txt +0 -0
  258. {omdev-0.0.0.dev223 → omdev-0.0.0.dev225}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: omdev
3
- Version: 0.0.0.dev223
3
+ Version: 0.0.0.dev225
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.dev223
15
+ Requires-Dist: omlish==0.0.0.dev225
16
16
  Provides-Extra: all
17
17
  Requires-Dist: black~=24.10; extra == "all"
18
18
  Requires-Dist: pycparser~=2.22; extra == "all"
@@ -89,9 +89,15 @@ def skip_root_level_if_type_checking_block(
89
89
  ) -> int:
90
90
  def skip_block():
91
91
  nonlocal i
92
+
93
+ nl = cls[i]
94
+ if nl[0].name != 'INDENT':
95
+ raise RuntimeError
96
+ i += 1
97
+
92
98
  while True:
93
99
  nl = cls[i]
94
- if nl and nl[0].name != 'INDENT':
100
+ if nl and nl[0].name == 'DEDENT':
95
101
  return nl
96
102
  i += 1
97
103
 
@@ -1,13 +1,17 @@
1
1
  # ruff: noqa: UP006 UP007
2
2
  import abc
3
+ import asyncio
3
4
  import dataclasses as dc
5
+ import functools
4
6
  import os.path
5
7
  import shutil
6
8
  import typing as ta
9
+ import urllib.request
7
10
 
8
11
  from omlish.lite.cached import cached_nullary
9
12
  from omlish.lite.check import check
10
13
  from omlish.lite.logs import log
14
+ from omlish.os.temp import make_temp_file
11
15
 
12
16
  from .consts import CI_CACHE_VERSION
13
17
 
@@ -162,3 +166,107 @@ class DirectoryFileCache(FileCache):
162
166
  else:
163
167
  shutil.copyfile(file_path, cache_file_path)
164
168
  return cache_file_path
169
+
170
+
171
+ ##
172
+
173
+
174
+ class DataCache:
175
+ @dc.dataclass(frozen=True)
176
+ class Data(abc.ABC): # noqa
177
+ pass
178
+
179
+ @dc.dataclass(frozen=True)
180
+ class BytesData(Data):
181
+ data: bytes
182
+
183
+ @dc.dataclass(frozen=True)
184
+ class FileData(Data):
185
+ file_path: str
186
+
187
+ @dc.dataclass(frozen=True)
188
+ class UrlData(Data):
189
+ url: str
190
+
191
+ #
192
+
193
+ @abc.abstractmethod
194
+ def get_data(self, key: str) -> ta.Awaitable[ta.Optional[Data]]:
195
+ raise NotImplementedError
196
+
197
+ @abc.abstractmethod
198
+ def put_data(self, key: str, data: Data) -> ta.Awaitable[None]:
199
+ raise NotImplementedError
200
+
201
+
202
+ #
203
+
204
+
205
+ @functools.singledispatch
206
+ async def read_data_cache_data(data: DataCache.Data) -> bytes:
207
+ raise TypeError(data)
208
+
209
+
210
+ @read_data_cache_data.register
211
+ async def _(data: DataCache.BytesData) -> bytes:
212
+ return data.data
213
+
214
+
215
+ @read_data_cache_data.register
216
+ async def _(data: DataCache.FileData) -> bytes:
217
+ with open(data.file_path, 'rb') as f: # noqa
218
+ return f.read()
219
+
220
+
221
+ @read_data_cache_data.register
222
+ async def _(data: DataCache.UrlData) -> bytes:
223
+ def inner() -> bytes:
224
+ with urllib.request.urlopen(urllib.request.Request( # noqa
225
+ data.url,
226
+ )) as resp:
227
+ return resp.read()
228
+
229
+ return await asyncio.get_running_loop().run_in_executor(None, inner)
230
+
231
+
232
+ #
233
+
234
+
235
+ class FileCacheDataCache(DataCache):
236
+ def __init__(
237
+ self,
238
+ file_cache: FileCache,
239
+ ) -> None:
240
+ super().__init__()
241
+
242
+ self._file_cache = file_cache
243
+
244
+ async def get_data(self, key: str) -> ta.Optional[DataCache.Data]:
245
+ if (file_path := await self._file_cache.get_file(key)) is None:
246
+ return None
247
+
248
+ return DataCache.FileData(file_path)
249
+
250
+ async def put_data(self, key: str, data: DataCache.Data) -> None:
251
+ steal = False
252
+
253
+ if isinstance(data, DataCache.BytesData):
254
+ file_path = make_temp_file()
255
+ with open(file_path, 'wb') as f: # noqa
256
+ f.write(data.data)
257
+ steal = True
258
+
259
+ elif isinstance(data, DataCache.FileData):
260
+ file_path = data.file_path
261
+
262
+ elif isinstance(data, DataCache.UrlData):
263
+ raise NotImplementedError
264
+
265
+ else:
266
+ raise TypeError(data)
267
+
268
+ await self._file_cache.put_file(
269
+ key,
270
+ file_path,
271
+ steal=steal,
272
+ )
@@ -7,6 +7,7 @@ from omlish.lite.cached import async_cached_nullary
7
7
  from omlish.lite.cached import cached_nullary
8
8
  from omlish.lite.check import check
9
9
  from omlish.lite.contextmanagers import AsyncExitStacked
10
+ from omlish.lite.timing import log_timing_context
10
11
  from omlish.os.temp import temp_file_context
11
12
 
12
13
  from .compose import DockerComposeRun
@@ -17,7 +18,6 @@ from .docker.imagepulling import DockerImagePulling
17
18
  from .docker.utils import build_docker_file_hash
18
19
  from .requirements import build_requirements_hash
19
20
  from .shell import ShellCmd
20
- from .utils import log_timing_context
21
21
 
22
22
 
23
23
  ##
@@ -0,0 +1,262 @@
1
+ # ruff: noqa: UP006 UP007
2
+ import abc
3
+ import asyncio
4
+ import contextlib
5
+ import dataclasses as dc
6
+ import json
7
+ import os.path
8
+ import typing as ta
9
+
10
+ from omlish.asyncs.asyncio.subprocesses import asyncio_subprocesses
11
+ from omlish.lite.check import check
12
+ from omlish.lite.json import json_dumps_compact
13
+ from omlish.lite.logs import log
14
+ from omlish.lite.marshal import marshal_obj
15
+ from omlish.lite.marshal import unmarshal_obj
16
+
17
+ from ...dataserver.routes import DataServerRoute
18
+ from ...dataserver.server import DataServer
19
+ from ...dataserver.targets import BytesDataServerTarget
20
+ from ...dataserver.targets import DataServerTarget
21
+ from ...dataserver.targets import FileDataServerTarget
22
+ from ...oci.building import build_oci_index_repository
23
+ from ...oci.data import get_single_leaf_oci_image_index
24
+ from ...oci.dataserver import build_oci_repository_data_server_routes
25
+ from ...oci.loading import read_oci_repository_root_index
26
+ from ...oci.pack.repositories import OciPackedRepositoryBuilder
27
+ from ...oci.repositories import OciRepository
28
+ from ..cache import DataCache
29
+ from ..cache import read_data_cache_data
30
+ from .cache import DockerCache
31
+ from .dataserver import DockerDataServer
32
+ from .repositories import DockerImageRepositoryOpener
33
+
34
+
35
+ ##
36
+
37
+
38
+ @dc.dataclass(frozen=True)
39
+ class CacheServedDockerImageManifest:
40
+ @dc.dataclass(frozen=True)
41
+ class Route:
42
+ paths: ta.Sequence[str]
43
+
44
+ content_type: str
45
+ content_length: int
46
+
47
+ @dc.dataclass(frozen=True)
48
+ class Target(abc.ABC): # noqa
49
+ pass
50
+
51
+ @dc.dataclass(frozen=True)
52
+ class BytesTarget(Target):
53
+ data: bytes
54
+
55
+ @dc.dataclass(frozen=True)
56
+ class CacheKeyTarget(Target):
57
+ key: str
58
+
59
+ target: Target
60
+
61
+ def __post_init__(self) -> None:
62
+ check.not_isinstance(self.paths, str)
63
+
64
+ routes: ta.Sequence[Route]
65
+
66
+
67
+ #
68
+
69
+
70
+ async def build_cache_served_docker_image_manifest(
71
+ data_server_routes: ta.Iterable[DataServerRoute],
72
+ make_file_cache_key: ta.Callable[[str], ta.Awaitable[str]],
73
+ ) -> CacheServedDockerImageManifest:
74
+ routes: ta.List[CacheServedDockerImageManifest.Route] = []
75
+
76
+ for data_server_route in data_server_routes:
77
+ content_length: int
78
+
79
+ data_server_target = data_server_route.target
80
+ target: CacheServedDockerImageManifest.Route.Target
81
+ if isinstance(data_server_target, BytesDataServerTarget):
82
+ bytes_data = check.isinstance(data_server_target.data, bytes)
83
+ content_length = len(bytes_data)
84
+ target = CacheServedDockerImageManifest.Route.BytesTarget(bytes_data)
85
+
86
+ elif isinstance(data_server_target, FileDataServerTarget):
87
+ file_path = check.non_empty_str(data_server_target.file_path)
88
+ content_length = os.path.getsize(file_path)
89
+ cache_key = await make_file_cache_key(file_path)
90
+ target = CacheServedDockerImageManifest.Route.CacheKeyTarget(cache_key)
91
+
92
+ else:
93
+ raise TypeError(data_server_target)
94
+
95
+ routes.append(CacheServedDockerImageManifest.Route(
96
+ paths=data_server_route.paths,
97
+
98
+ content_type=check.non_empty_str(data_server_target.content_type),
99
+ content_length=content_length,
100
+
101
+ target=target,
102
+ ))
103
+
104
+ return CacheServedDockerImageManifest(
105
+ routes=routes,
106
+ )
107
+
108
+
109
+ #
110
+
111
+
112
+ async def build_cache_served_docker_image_data_server_routes(
113
+ manifest: CacheServedDockerImageManifest,
114
+ make_cache_key_target: ta.Callable[..., ta.Awaitable[DataServerTarget]],
115
+ ) -> ta.List[DataServerRoute]:
116
+ routes: ta.List[DataServerRoute] = []
117
+
118
+ for manifest_route in manifest.routes:
119
+ manifest_target = manifest_route.target
120
+
121
+ target_kwargs: dict = dict(
122
+ content_type=manifest_route.content_type,
123
+ content_length=manifest_route.content_length,
124
+ )
125
+
126
+ target: DataServerTarget
127
+
128
+ if isinstance(manifest_target, CacheServedDockerImageManifest.Route.BytesTarget):
129
+ target = DataServerTarget.of(manifest_target.data, **target_kwargs)
130
+
131
+ elif isinstance(manifest_target, CacheServedDockerImageManifest.Route.CacheKeyTarget):
132
+ target = await make_cache_key_target(manifest_target.key, **target_kwargs)
133
+
134
+ else:
135
+ raise TypeError(manifest_target)
136
+
137
+ routes.append(DataServerRoute(
138
+ paths=manifest_route.paths,
139
+ target=target,
140
+ ))
141
+
142
+ return routes
143
+
144
+
145
+ ##
146
+
147
+
148
+ class CacheServedDockerCache(DockerCache):
149
+ @dc.dataclass(frozen=True)
150
+ class Config:
151
+ port: int = 5021
152
+
153
+ repack: bool = True
154
+
155
+ def __init__(
156
+ self,
157
+ *,
158
+ config: Config = Config(),
159
+
160
+ image_repo_opener: DockerImageRepositoryOpener,
161
+ data_cache: DataCache,
162
+ ) -> None:
163
+ super().__init__()
164
+
165
+ self._config = config
166
+
167
+ self._image_repo_opener = image_repo_opener
168
+ self._data_cache = data_cache
169
+
170
+ async def load_cache_docker_image(self, key: str) -> ta.Optional[str]:
171
+ if (manifest_data := await self._data_cache.get_data(key)) is None:
172
+ return None
173
+
174
+ manifest_bytes = await read_data_cache_data(manifest_data)
175
+
176
+ manifest: CacheServedDockerImageManifest = unmarshal_obj(
177
+ json.loads(manifest_bytes.decode('utf-8')),
178
+ CacheServedDockerImageManifest,
179
+ )
180
+
181
+ async def make_cache_key_target(target_cache_key: str, **target_kwargs: ta.Any) -> DataServerTarget: # noqa
182
+ # FIXME: url
183
+ cache_data = check.not_none(await self._data_cache.get_data(target_cache_key))
184
+ file_path = check.isinstance(cache_data, DataCache.FileData).file_path
185
+ return DataServerTarget.of(
186
+ file_path=file_path,
187
+ **target_kwargs,
188
+ )
189
+
190
+ data_server_routes = await build_cache_served_docker_image_data_server_routes(
191
+ manifest,
192
+ make_cache_key_target,
193
+ )
194
+
195
+ data_server = DataServer(DataServer.HandlerRoute.of_(*data_server_routes))
196
+
197
+ image_url = f'localhost:{self._config.port}/{key}'
198
+
199
+ async with DockerDataServer(
200
+ self._config.port,
201
+ data_server,
202
+ handler_log=log,
203
+ ) as dds:
204
+ dds_run_task = asyncio.create_task(dds.run())
205
+ try:
206
+ # FIXME: lol
207
+ await asyncio.sleep(3.)
208
+
209
+ await asyncio_subprocesses.check_call(
210
+ 'docker',
211
+ 'pull',
212
+ image_url,
213
+ )
214
+
215
+ finally:
216
+ dds.stop_event.set()
217
+ await dds_run_task
218
+
219
+ return image_url
220
+
221
+ async def save_cache_docker_image(self, key: str, image: str) -> None:
222
+ async with contextlib.AsyncExitStack() as es:
223
+ image_repo: OciRepository = await es.enter_async_context(
224
+ self._image_repo_opener.open_docker_image_repository(image),
225
+ )
226
+
227
+ root_image_index = read_oci_repository_root_index(image_repo)
228
+ image_index = get_single_leaf_oci_image_index(root_image_index)
229
+
230
+ if self._config.repack:
231
+ prb: OciPackedRepositoryBuilder = es.enter_context(OciPackedRepositoryBuilder(
232
+ image_repo,
233
+ ))
234
+ built_repo = await asyncio.get_running_loop().run_in_executor(None, prb.build)
235
+
236
+ else:
237
+ built_repo = build_oci_index_repository(image_index)
238
+
239
+ data_server_routes = build_oci_repository_data_server_routes(
240
+ key,
241
+ built_repo,
242
+ )
243
+
244
+ async def make_file_cache_key(file_path: str) -> str:
245
+ target_cache_key = f'{key}--{os.path.basename(file_path).split(".")[0]}'
246
+ await self._data_cache.put_data(
247
+ target_cache_key,
248
+ DataCache.FileData(file_path),
249
+ )
250
+ return target_cache_key
251
+
252
+ cache_served_manifest = await build_cache_served_docker_image_manifest(
253
+ data_server_routes,
254
+ make_file_cache_key,
255
+ )
256
+
257
+ manifest_data = json_dumps_compact(marshal_obj(cache_served_manifest)).encode('utf-8')
258
+
259
+ await self._data_cache.put_data(
260
+ key,
261
+ DataCache.BytesData(manifest_data),
262
+ )
@@ -0,0 +1,204 @@
1
+ # ruff: noqa: UP006 UP007
2
+ import asyncio
3
+ import contextlib
4
+ import logging
5
+ import ssl
6
+ import sys
7
+ import threading
8
+ import typing as ta
9
+
10
+ from omlish.docker.portrelay import DockerPortRelay
11
+ from omlish.http.coro.simple import make_simple_http_server
12
+ from omlish.http.handlers import HttpHandler
13
+ from omlish.http.handlers import LoggingHttpHandler
14
+ from omlish.lite.cached import cached_nullary
15
+ from omlish.lite.check import check
16
+ from omlish.lite.contextmanagers import AsyncExitStacked
17
+ from omlish.secrets.tempssl import generate_temp_localhost_ssl_cert
18
+ from omlish.sockets.server.server import SocketServer
19
+
20
+ from ...dataserver.http import DataServerHttpHandler
21
+ from ...dataserver.server import DataServer
22
+
23
+
24
+ ##
25
+
26
+
27
+ @contextlib.asynccontextmanager
28
+ async def start_docker_port_relay(
29
+ docker_port: int,
30
+ host_port: int,
31
+ **kwargs: ta.Any,
32
+ ) -> ta.AsyncGenerator[None, None]:
33
+ proc = await asyncio.create_subprocess_exec(*DockerPortRelay(
34
+ docker_port,
35
+ host_port,
36
+ **kwargs,
37
+ ).run_cmd())
38
+
39
+ try:
40
+ yield
41
+
42
+ finally:
43
+ try:
44
+ proc.kill()
45
+ except ProcessLookupError:
46
+ pass
47
+ await proc.wait()
48
+
49
+
50
+ ##
51
+
52
+
53
+ class AsyncioManagedSimpleHttpServer(AsyncExitStacked):
54
+ def __init__(
55
+ self,
56
+ port: int,
57
+ handler: HttpHandler,
58
+ *,
59
+ temp_ssl: bool = False,
60
+ ) -> None:
61
+ super().__init__()
62
+
63
+ self._port = port
64
+ self._handler = handler
65
+
66
+ self._temp_ssl = temp_ssl
67
+
68
+ self._lock = threading.RLock()
69
+
70
+ self._loop: ta.Optional[asyncio.AbstractEventLoop] = None
71
+ self._thread: ta.Optional[threading.Thread] = None
72
+ self._thread_exit_event = asyncio.Event()
73
+ self._server: ta.Optional[SocketServer] = None
74
+
75
+ @cached_nullary
76
+ def _ssl_context(self) -> ta.Optional['ssl.SSLContext']:
77
+ if not self._temp_ssl:
78
+ return None
79
+
80
+ ssl_cert = generate_temp_localhost_ssl_cert().cert # FIXME: async blocking
81
+
82
+ ssl_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
83
+ ssl_context.load_cert_chain(
84
+ keyfile=ssl_cert.key_file,
85
+ certfile=ssl_cert.cert_file,
86
+ )
87
+
88
+ return ssl_context
89
+
90
+ @contextlib.contextmanager
91
+ def _make_server(self) -> ta.Iterator[SocketServer]:
92
+ with make_simple_http_server(
93
+ self._port,
94
+ self._handler,
95
+ ssl_context=self._ssl_context(),
96
+ use_threads=True,
97
+ ) as server:
98
+ yield server
99
+
100
+ def _thread_main(self) -> None:
101
+ try:
102
+ check.none(self._server)
103
+ with self._make_server() as server:
104
+ self._server = server
105
+
106
+ server.run()
107
+
108
+ finally:
109
+ check.not_none(self._loop).call_soon_threadsafe(self._thread_exit_event.set)
110
+
111
+ def is_running(self) -> bool:
112
+ return self._server is not None
113
+
114
+ def shutdown(self) -> None:
115
+ if (server := self._server) is not None:
116
+ server.shutdown(block=False)
117
+
118
+ async def run(self) -> None:
119
+ with self._lock:
120
+ check.none(self._loop)
121
+ check.none(self._thread)
122
+ check.state(not self._thread_exit_event.is_set())
123
+
124
+ if self._temp_ssl:
125
+ # Hit the ExitStack from this thread
126
+ self._ssl_context()
127
+
128
+ self._loop = check.not_none(asyncio.get_running_loop())
129
+ self._thread = threading.Thread(
130
+ target=self._thread_main,
131
+ daemon=True,
132
+ )
133
+ self._thread.start()
134
+
135
+ await self._thread_exit_event.wait()
136
+
137
+
138
+ ##
139
+
140
+
141
+ class DockerDataServer(AsyncExitStacked):
142
+ def __init__(
143
+ self,
144
+ port: int,
145
+ data_server: DataServer,
146
+ *,
147
+ handler_log: ta.Optional[logging.Logger] = None,
148
+ stop_event: ta.Optional[asyncio.Event] = None,
149
+ ) -> None:
150
+ super().__init__()
151
+
152
+ self._port = port
153
+ self._data_server = data_server
154
+
155
+ self._handler_log = handler_log
156
+
157
+ if stop_event is None:
158
+ stop_event = asyncio.Event()
159
+ self._stop_event = stop_event
160
+
161
+ @property
162
+ def stop_event(self) -> asyncio.Event:
163
+ return self._stop_event
164
+
165
+ async def run(self) -> None:
166
+ relay_port: ta.Optional[int] = None
167
+ if sys.platform == 'darwin':
168
+ relay_port = self._port
169
+ server_port = self._port + 1
170
+ else:
171
+ server_port = self._port
172
+
173
+ #
174
+
175
+ handler: HttpHandler = DataServerHttpHandler(self._data_server)
176
+
177
+ if self._handler_log is not None:
178
+ handler = LoggingHttpHandler(
179
+ handler,
180
+ self._handler_log,
181
+ )
182
+
183
+ #
184
+
185
+ async with contextlib.AsyncExitStack() as es:
186
+ if relay_port is not None:
187
+ await es.enter_async_context(start_docker_port_relay( # noqa
188
+ relay_port,
189
+ server_port,
190
+ intermediate_port=server_port + 1,
191
+ ))
192
+
193
+ async with AsyncioManagedSimpleHttpServer(
194
+ server_port,
195
+ handler,
196
+ temp_ssl=True,
197
+ ) as server:
198
+ server_run_task = asyncio.create_task(server.run())
199
+ try:
200
+ await self._stop_event.wait()
201
+
202
+ finally:
203
+ server.shutdown()
204
+ await server_run_task
@@ -3,8 +3,9 @@ import abc
3
3
  import dataclasses as dc
4
4
  import typing as ta
5
5
 
6
+ from omlish.lite.timing import log_timing_context
7
+
6
8
  from ..cache import FileCache
7
- from ..utils import log_timing_context
8
9
  from .cache import DockerCache
9
10
  from .cmds import is_docker_image_present
10
11
  from .cmds import pull_docker_image