omdev 0.0.53__tar.gz → 0.0.54__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.
Files changed (575) hide show
  1. {omdev-0.0.53/omdev.egg-info → omdev-0.0.54}/PKG-INFO +12 -12
  2. omdev-0.0.54/omdev/home/secretinject.py +330 -0
  3. {omdev-0.0.53 → omdev-0.0.54}/omdev/home/secrets.py +22 -12
  4. omdev-0.0.54/omdev/qr/LICENSE +27 -0
  5. omdev-0.0.54/omdev/qr/__init__.py +1 -0
  6. omdev-0.0.54/omdev/qr/consts.py +610 -0
  7. omdev-0.0.54/omdev/qr/encoding.py +849 -0
  8. omdev-0.0.54/omdev/qr/segments.py +235 -0
  9. omdev-0.0.54/omdev/qr/utils.py +129 -0
  10. omdev-0.0.54/omdev/qr/writers.py +100 -0
  11. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/controls/cards.py +3 -2
  12. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/vim/__init__.py +2 -0
  13. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/vim/engine.py +17 -2
  14. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/vim/options.py +44 -1
  15. {omdev-0.0.53 → omdev-0.0.54/omdev.egg-info}/PKG-INFO +12 -12
  16. {omdev-0.0.53 → omdev-0.0.54}/omdev.egg-info/SOURCES.txt +8 -0
  17. {omdev-0.0.53 → omdev-0.0.54}/omdev.egg-info/requires.txt +11 -11
  18. {omdev-0.0.53 → omdev-0.0.54}/pyproject.toml +12 -12
  19. {omdev-0.0.53 → omdev-0.0.54}/LICENSE +0 -0
  20. {omdev-0.0.53 → omdev-0.0.54}/MANIFEST.in +0 -0
  21. {omdev-0.0.53 → omdev-0.0.54}/README.md +0 -0
  22. {omdev-0.0.53 → omdev-0.0.54}/omdev/.om-manifests.json +0 -0
  23. {omdev-0.0.53 → omdev-0.0.54}/omdev/README.md +0 -0
  24. {omdev-0.0.53 → omdev-0.0.54}/omdev/__about__.py +0 -0
  25. {omdev-0.0.53 → omdev-0.0.54}/omdev/__init__.py +0 -0
  26. {omdev-0.0.53 → omdev-0.0.54}/omdev/amalg/__init__.py +0 -0
  27. {omdev-0.0.53 → omdev-0.0.54}/omdev/amalg/__main__.py +0 -0
  28. {omdev-0.0.53 → omdev-0.0.54}/omdev/amalg/cli/__init__.py +0 -0
  29. {omdev-0.0.53 → omdev-0.0.54}/omdev/amalg/cli/main.py +0 -0
  30. {omdev-0.0.53 → omdev-0.0.54}/omdev/amalg/gen/__init__.py +0 -0
  31. {omdev-0.0.53 → omdev-0.0.54}/omdev/amalg/gen/gen.py +0 -0
  32. {omdev-0.0.53 → omdev-0.0.54}/omdev/amalg/gen/imports.py +0 -0
  33. {omdev-0.0.53 → omdev-0.0.54}/omdev/amalg/gen/manifests.py +0 -0
  34. {omdev-0.0.53 → omdev-0.0.54}/omdev/amalg/gen/resources.py +0 -0
  35. {omdev-0.0.53 → omdev-0.0.54}/omdev/amalg/gen/srcfiles.py +0 -0
  36. {omdev-0.0.53 → omdev-0.0.54}/omdev/amalg/gen/strip.py +0 -0
  37. {omdev-0.0.53 → omdev-0.0.54}/omdev/amalg/gen/types.py +0 -0
  38. {omdev-0.0.53 → omdev-0.0.54}/omdev/amalg/gen/typing.py +0 -0
  39. {omdev-0.0.53 → omdev-0.0.54}/omdev/amalg/info.py +0 -0
  40. {omdev-0.0.53 → omdev-0.0.54}/omdev/amalg/sources.py +0 -0
  41. {omdev-0.0.53 → omdev-0.0.54}/omdev/cache/__init__.py +0 -0
  42. {omdev-0.0.53 → omdev-0.0.54}/omdev/cache/compute/__init__.py +0 -0
  43. {omdev-0.0.53 → omdev-0.0.54}/omdev/cache/compute/cache.py +0 -0
  44. {omdev-0.0.53 → omdev-0.0.54}/omdev/cache/compute/contexts.py +0 -0
  45. {omdev-0.0.53 → omdev-0.0.54}/omdev/cache/compute/currents.py +0 -0
  46. {omdev-0.0.53 → omdev-0.0.54}/omdev/cache/compute/fns.py +0 -0
  47. {omdev-0.0.53 → omdev-0.0.54}/omdev/cache/compute/resolvers.py +0 -0
  48. {omdev-0.0.53 → omdev-0.0.54}/omdev/cache/compute/storage.py +0 -0
  49. {omdev-0.0.53 → omdev-0.0.54}/omdev/cache/compute/types.py +0 -0
  50. {omdev-0.0.53 → omdev-0.0.54}/omdev/cache/data/__init__.py +0 -0
  51. {omdev-0.0.53 → omdev-0.0.54}/omdev/cache/data/actions.py +0 -0
  52. {omdev-0.0.53 → omdev-0.0.54}/omdev/cache/data/cache.py +0 -0
  53. {omdev-0.0.53 → omdev-0.0.54}/omdev/cache/data/consts.py +0 -0
  54. {omdev-0.0.53 → omdev-0.0.54}/omdev/cache/data/defaults.py +0 -0
  55. {omdev-0.0.53 → omdev-0.0.54}/omdev/cache/data/manifests.py +0 -0
  56. {omdev-0.0.53 → omdev-0.0.54}/omdev/cache/data/specs.py +0 -0
  57. {omdev-0.0.53 → omdev-0.0.54}/omdev/capi/__init__.py +0 -0
  58. {omdev-0.0.53 → omdev-0.0.54}/omdev/capi/darwin/__init__.py +0 -0
  59. {omdev-0.0.53 → omdev-0.0.54}/omdev/capi/darwin/aps.py +0 -0
  60. {omdev-0.0.53 → omdev-0.0.54}/omdev/capi/darwin/ax.py +0 -0
  61. {omdev-0.0.53 → omdev-0.0.54}/omdev/capi/darwin/cf.py +0 -0
  62. {omdev-0.0.53 → omdev-0.0.54}/omdev/capi/darwin/cg.py +0 -0
  63. {omdev-0.0.53 → omdev-0.0.54}/omdev/capi/linux/__init__.py +0 -0
  64. {omdev-0.0.53 → omdev-0.0.54}/omdev/capi/linux/x11.py +0 -0
  65. {omdev-0.0.53 → omdev-0.0.54}/omdev/cc/__init__.py +0 -0
  66. {omdev-0.0.53 → omdev-0.0.54}/omdev/cc/__main__.py +0 -0
  67. {omdev-0.0.53 → omdev-0.0.54}/omdev/cc/cdeps.py +0 -0
  68. {omdev-0.0.53 → omdev-0.0.54}/omdev/cc/cdeps.toml +0 -0
  69. {omdev-0.0.53 → omdev-0.0.54}/omdev/cc/cli.py +0 -0
  70. {omdev-0.0.53 → omdev-0.0.54}/omdev/cc/srclangs.py +0 -0
  71. {omdev-0.0.53 → omdev-0.0.54}/omdev/cexts/__init__.py +0 -0
  72. {omdev-0.0.53 → omdev-0.0.54}/omdev/cexts/_boilerplate.cc +0 -0
  73. {omdev-0.0.53 → omdev-0.0.54}/omdev/cexts/_distutils/LICENSE +0 -0
  74. {omdev-0.0.53 → omdev-0.0.54}/omdev/cexts/_distutils/__init__.py +0 -0
  75. {omdev-0.0.53 → omdev-0.0.54}/omdev/cexts/_distutils/build_ext.py +0 -0
  76. {omdev-0.0.53 → omdev-0.0.54}/omdev/cexts/_distutils/compilers/__init__.py +0 -0
  77. {omdev-0.0.53 → omdev-0.0.54}/omdev/cexts/_distutils/compilers/ccompiler.py +0 -0
  78. {omdev-0.0.53 → omdev-0.0.54}/omdev/cexts/_distutils/compilers/options.py +0 -0
  79. {omdev-0.0.53 → omdev-0.0.54}/omdev/cexts/_distutils/compilers/unixccompiler.py +0 -0
  80. {omdev-0.0.53 → omdev-0.0.54}/omdev/cexts/_distutils/dir_util.py +0 -0
  81. {omdev-0.0.53 → omdev-0.0.54}/omdev/cexts/_distutils/errors.py +0 -0
  82. {omdev-0.0.53 → omdev-0.0.54}/omdev/cexts/_distutils/extension.py +0 -0
  83. {omdev-0.0.53 → omdev-0.0.54}/omdev/cexts/_distutils/file_util.py +0 -0
  84. {omdev-0.0.53 → omdev-0.0.54}/omdev/cexts/_distutils/modified.py +0 -0
  85. {omdev-0.0.53 → omdev-0.0.54}/omdev/cexts/_distutils/spawn.py +0 -0
  86. {omdev-0.0.53 → omdev-0.0.54}/omdev/cexts/_distutils/sysconfig.py +0 -0
  87. {omdev-0.0.53 → omdev-0.0.54}/omdev/cexts/_distutils/util.py +0 -0
  88. {omdev-0.0.53 → omdev-0.0.54}/omdev/cexts/_distutils/version.py +0 -0
  89. {omdev-0.0.53 → omdev-0.0.54}/omdev/cexts/build.py +0 -0
  90. {omdev-0.0.53 → omdev-0.0.54}/omdev/cexts/cmake.py +0 -0
  91. {omdev-0.0.53 → omdev-0.0.54}/omdev/cexts/configs.py +0 -0
  92. {omdev-0.0.53 → omdev-0.0.54}/omdev/cexts/importhook.py +0 -0
  93. {omdev-0.0.53 → omdev-0.0.54}/omdev/cexts/magic.py +0 -0
  94. {omdev-0.0.53 → omdev-0.0.54}/omdev/cexts/scan.py +0 -0
  95. {omdev-0.0.53 → omdev-0.0.54}/omdev/ci/__init__.py +0 -0
  96. {omdev-0.0.53 → omdev-0.0.54}/omdev/ci/__main__.py +0 -0
  97. {omdev-0.0.53 → omdev-0.0.54}/omdev/ci/cache.py +0 -0
  98. {omdev-0.0.53 → omdev-0.0.54}/omdev/ci/ci.py +0 -0
  99. {omdev-0.0.53 → omdev-0.0.54}/omdev/ci/cli.py +0 -0
  100. {omdev-0.0.53 → omdev-0.0.54}/omdev/ci/compose.py +0 -0
  101. {omdev-0.0.53 → omdev-0.0.54}/omdev/ci/consts.py +0 -0
  102. {omdev-0.0.53 → omdev-0.0.54}/omdev/ci/docker/__init__.py +0 -0
  103. {omdev-0.0.53 → omdev-0.0.54}/omdev/ci/docker/buildcaching.py +0 -0
  104. {omdev-0.0.53 → omdev-0.0.54}/omdev/ci/docker/cache.py +0 -0
  105. {omdev-0.0.53 → omdev-0.0.54}/omdev/ci/docker/cacheserved/__init__.py +0 -0
  106. {omdev-0.0.53 → omdev-0.0.54}/omdev/ci/docker/cacheserved/cache.py +0 -0
  107. {omdev-0.0.53 → omdev-0.0.54}/omdev/ci/docker/cacheserved/manifests.py +0 -0
  108. {omdev-0.0.53 → omdev-0.0.54}/omdev/ci/docker/cmds.py +0 -0
  109. {omdev-0.0.53 → omdev-0.0.54}/omdev/ci/docker/dataserver.py +0 -0
  110. {omdev-0.0.53 → omdev-0.0.54}/omdev/ci/docker/imagepulling.py +0 -0
  111. {omdev-0.0.53 → omdev-0.0.54}/omdev/ci/docker/inject.py +0 -0
  112. {omdev-0.0.53 → omdev-0.0.54}/omdev/ci/docker/packing.py +0 -0
  113. {omdev-0.0.53 → omdev-0.0.54}/omdev/ci/docker/repositories.py +0 -0
  114. {omdev-0.0.53 → omdev-0.0.54}/omdev/ci/docker/utils.py +0 -0
  115. {omdev-0.0.53 → omdev-0.0.54}/omdev/ci/github/__init__.py +0 -0
  116. {omdev-0.0.53 → omdev-0.0.54}/omdev/ci/github/api/__init__.py +0 -0
  117. {omdev-0.0.53 → omdev-0.0.54}/omdev/ci/github/api/clients.py +0 -0
  118. {omdev-0.0.53 → omdev-0.0.54}/omdev/ci/github/api/v1/__init__.py +0 -0
  119. {omdev-0.0.53 → omdev-0.0.54}/omdev/ci/github/api/v1/api.py +0 -0
  120. {omdev-0.0.53 → omdev-0.0.54}/omdev/ci/github/api/v1/client.py +0 -0
  121. {omdev-0.0.53 → omdev-0.0.54}/omdev/ci/github/api/v2/__init__.py +0 -0
  122. {omdev-0.0.53 → omdev-0.0.54}/omdev/ci/github/api/v2/api.py +0 -0
  123. {omdev-0.0.53 → omdev-0.0.54}/omdev/ci/github/api/v2/azure.py +0 -0
  124. {omdev-0.0.53 → omdev-0.0.54}/omdev/ci/github/api/v2/client.py +0 -0
  125. {omdev-0.0.53 → omdev-0.0.54}/omdev/ci/github/bootstrap.py +0 -0
  126. {omdev-0.0.53 → omdev-0.0.54}/omdev/ci/github/cache.py +0 -0
  127. {omdev-0.0.53 → omdev-0.0.54}/omdev/ci/github/cli.py +0 -0
  128. {omdev-0.0.53 → omdev-0.0.54}/omdev/ci/github/env.py +0 -0
  129. {omdev-0.0.53 → omdev-0.0.54}/omdev/ci/github/inject.py +0 -0
  130. {omdev-0.0.53 → omdev-0.0.54}/omdev/ci/inject.py +0 -0
  131. {omdev-0.0.53 → omdev-0.0.54}/omdev/ci/requirements.py +0 -0
  132. {omdev-0.0.53 → omdev-0.0.54}/omdev/ci/shell.py +0 -0
  133. {omdev-0.0.53 → omdev-0.0.54}/omdev/ci/utils.py +0 -0
  134. {omdev-0.0.53 → omdev-0.0.54}/omdev/cli/__init__.py +0 -0
  135. {omdev-0.0.53 → omdev-0.0.54}/omdev/cli/__main__.py +0 -0
  136. {omdev-0.0.53 → omdev-0.0.54}/omdev/cli/_pathhack.py +0 -0
  137. {omdev-0.0.53 → omdev-0.0.54}/omdev/cli/clicli.py +0 -0
  138. {omdev-0.0.53 → omdev-0.0.54}/omdev/cli/install.py +0 -0
  139. {omdev-0.0.53 → omdev-0.0.54}/omdev/cli/main.py +0 -0
  140. {omdev-0.0.53 → omdev-0.0.54}/omdev/cli/managers.py +0 -0
  141. {omdev-0.0.53 → omdev-0.0.54}/omdev/cli/types.py +0 -0
  142. {omdev-0.0.53 → omdev-0.0.54}/omdev/clipboard/__init__.py +0 -0
  143. {omdev-0.0.53 → omdev-0.0.54}/omdev/clipboard/capi/__init__.py +0 -0
  144. {omdev-0.0.53 → omdev-0.0.54}/omdev/clipboard/capi/darwin_cf.py +0 -0
  145. {omdev-0.0.53 → omdev-0.0.54}/omdev/clipboard/capi/linux_x11.py +0 -0
  146. {omdev-0.0.53 → omdev-0.0.54}/omdev/clipboard/commands.py +0 -0
  147. {omdev-0.0.53 → omdev-0.0.54}/omdev/clipboard/platform.py +0 -0
  148. {omdev-0.0.53 → omdev-0.0.54}/omdev/clipboard/types.py +0 -0
  149. {omdev-0.0.53 → omdev-0.0.54}/omdev/cmake.py +0 -0
  150. {omdev-0.0.53 → omdev-0.0.54}/omdev/cmdlog/__init__.py +0 -0
  151. {omdev-0.0.53 → omdev-0.0.54}/omdev/cmdlog/__main__.py +0 -0
  152. {omdev-0.0.53 → omdev-0.0.54}/omdev/cmdlog/_cmdlog.py +0 -0
  153. {omdev-0.0.53 → omdev-0.0.54}/omdev/cmdlog/cli.py +0 -0
  154. {omdev-0.0.53 → omdev-0.0.54}/omdev/cmdlog/cmdlog.py +0 -0
  155. {omdev-0.0.53 → omdev-0.0.54}/omdev/dataclasses/__init__.py +0 -0
  156. {omdev-0.0.53 → omdev-0.0.54}/omdev/dataclasses/__main__.py +0 -0
  157. {omdev-0.0.53 → omdev-0.0.54}/omdev/dataclasses/_dumping.py +0 -0
  158. {omdev-0.0.53 → omdev-0.0.54}/omdev/dataclasses/_template.py +0 -0
  159. {omdev-0.0.53 → omdev-0.0.54}/omdev/dataclasses/cli.py +0 -0
  160. {omdev-0.0.53 → omdev-0.0.54}/omdev/dataclasses/codegen.py +0 -0
  161. {omdev-0.0.53 → omdev-0.0.54}/omdev/dataclasses/dumping.py +0 -0
  162. {omdev-0.0.53 → omdev-0.0.54}/omdev/dataserver/__init__.py +0 -0
  163. {omdev-0.0.53 → omdev-0.0.54}/omdev/dataserver/handlers.py +0 -0
  164. {omdev-0.0.53 → omdev-0.0.54}/omdev/dataserver/http.py +0 -0
  165. {omdev-0.0.53 → omdev-0.0.54}/omdev/dataserver/routes.py +0 -0
  166. {omdev-0.0.53 → omdev-0.0.54}/omdev/dataserver/server.py +0 -0
  167. {omdev-0.0.53 → omdev-0.0.54}/omdev/dataserver/targets.py +0 -0
  168. {omdev-0.0.53 → omdev-0.0.54}/omdev/dockerdev/__init__.py +0 -0
  169. {omdev-0.0.53 → omdev-0.0.54}/omdev/dockerdev/__main__.py +0 -0
  170. {omdev-0.0.53 → omdev-0.0.54}/omdev/dockerdev/build.py +0 -0
  171. {omdev-0.0.53 → omdev-0.0.54}/omdev/dockerdev/cli.py +0 -0
  172. {omdev-0.0.53 → omdev-0.0.54}/omdev/dockerdev/config.py +0 -0
  173. {omdev-0.0.53 → omdev-0.0.54}/omdev/dockerdev/config.toml +0 -0
  174. {omdev-0.0.53 → omdev-0.0.54}/omdev/dockerdev/content.py +0 -0
  175. {omdev-0.0.53 → omdev-0.0.54}/omdev/dockerdev/discovery.py +0 -0
  176. {omdev-0.0.53 → omdev-0.0.54}/omdev/dockerdev/gen.py +0 -0
  177. {omdev-0.0.53 → omdev-0.0.54}/omdev/dockerdev/helpers.py +0 -0
  178. {omdev-0.0.53 → omdev-0.0.54}/omdev/dockerdev/ops.py +0 -0
  179. {omdev-0.0.53 → omdev-0.0.54}/omdev/dockerdev/rendering.py +0 -0
  180. {omdev-0.0.53 → omdev-0.0.54}/omdev/dockerdev/resources/.python-versions.json +0 -0
  181. {omdev-0.0.53 → omdev-0.0.54}/omdev/dockerdev/resources/configs/.gdbinit +0 -0
  182. {omdev-0.0.53 → omdev-0.0.54}/omdev/dockerdev/resources/configs/.sqliterc +0 -0
  183. {omdev-0.0.53 → omdev-0.0.54}/omdev/dockerdev/resources/configs/.tmux.conf +0 -0
  184. {omdev-0.0.53 → omdev-0.0.54}/omdev/dockerdev/resources/configs/.vimrc +0 -0
  185. {omdev-0.0.53 → omdev-0.0.54}/omdev/dockerdev/resources/depsets/python.toml +0 -0
  186. {omdev-0.0.53 → omdev-0.0.54}/omdev/dockerdev/resources/depsets/system.toml +0 -0
  187. {omdev-0.0.53 → omdev-0.0.54}/omdev/dockerdev/resources/depsets/x11.toml +0 -0
  188. {omdev-0.0.53 → omdev-0.0.54}/omdev/dockerdev/resources/fragments/apt.sh +0 -0
  189. {omdev-0.0.53 → omdev-0.0.54}/omdev/dockerdev/resources/fragments/chgrp.sh +0 -0
  190. {omdev-0.0.53 → omdev-0.0.54}/omdev/dockerdev/resources/fragments/docker.sh +0 -0
  191. {omdev-0.0.53 → omdev-0.0.54}/omdev/dockerdev/resources/fragments/firefox.sh +0 -0
  192. {omdev-0.0.53 → omdev-0.0.54}/omdev/dockerdev/resources/fragments/go.sh +0 -0
  193. {omdev-0.0.53 → omdev-0.0.54}/omdev/dockerdev/resources/fragments/jdk.sh +0 -0
  194. {omdev-0.0.53 → omdev-0.0.54}/omdev/dockerdev/resources/fragments/man.sh +0 -0
  195. {omdev-0.0.53 → omdev-0.0.54}/omdev/dockerdev/resources/fragments/nvm.sh +0 -0
  196. {omdev-0.0.53 → omdev-0.0.54}/omdev/dockerdev/resources/fragments/om.sh +0 -0
  197. {omdev-0.0.53 → omdev-0.0.54}/omdev/dockerdev/resources/fragments/pyenv.sh +0 -0
  198. {omdev-0.0.53 → omdev-0.0.54}/omdev/dockerdev/resources/fragments/rbenv.sh +0 -0
  199. {omdev-0.0.53 → omdev-0.0.54}/omdev/dockerdev/resources/fragments/rust.sh +0 -0
  200. {omdev-0.0.53 → omdev-0.0.54}/omdev/dockerdev/resources/fragments/sshd.sh +0 -0
  201. {omdev-0.0.53 → omdev-0.0.54}/omdev/dockerdev/resources/fragments/user.sh +0 -0
  202. {omdev-0.0.53 → omdev-0.0.54}/omdev/dockerdev/resources/fragments/uv.sh +0 -0
  203. {omdev-0.0.53 → omdev-0.0.54}/omdev/dockerdev/resources/fragments/vcpkg.sh +0 -0
  204. {omdev-0.0.53 → omdev-0.0.54}/omdev/dockerdev/resources/fragments/workdir.sh +0 -0
  205. {omdev-0.0.53 → omdev-0.0.54}/omdev/dockerdev/resources/fragments/zig.sh +0 -0
  206. {omdev-0.0.53 → omdev-0.0.54}/omdev/dockerdev/resources/scripts/install-claude +0 -0
  207. {omdev-0.0.53 → omdev-0.0.54}/omdev/dockerdev/resources/scripts/install-codex +0 -0
  208. {omdev-0.0.53 → omdev-0.0.54}/omdev/dockerdev/resources/scripts/install-pi +0 -0
  209. {omdev-0.0.53 → omdev-0.0.54}/omdev/dockerdev/resources/scripts/run-dbus +0 -0
  210. {omdev-0.0.53 → omdev-0.0.54}/omdev/dockerdev/resources/scripts/run-mysql +0 -0
  211. {omdev-0.0.53 → omdev-0.0.54}/omdev/dockerdev/resources/scripts/run-postgres +0 -0
  212. {omdev-0.0.53 → omdev-0.0.54}/omdev/dockerdev/resources/shift-uid.sh +0 -0
  213. {omdev-0.0.53 → omdev-0.0.54}/omdev/dockerdev/run.py +0 -0
  214. {omdev-0.0.53 → omdev-0.0.54}/omdev/dockerdev/utils.py +0 -0
  215. {omdev-0.0.53 → omdev-0.0.54}/omdev/git/__init__.py +0 -0
  216. {omdev-0.0.53 → omdev-0.0.54}/omdev/git/magic.py +0 -0
  217. {omdev-0.0.53 → omdev-0.0.54}/omdev/git/revisions.py +0 -0
  218. {omdev-0.0.53 → omdev-0.0.54}/omdev/git/shallow.py +0 -0
  219. {omdev-0.0.53 → omdev-0.0.54}/omdev/git/status.py +0 -0
  220. {omdev-0.0.53 → omdev-0.0.54}/omdev/git/vendor/__init__.py +0 -0
  221. {omdev-0.0.53 → omdev-0.0.54}/omdev/git/vendor/aborting.py +0 -0
  222. {omdev-0.0.53 → omdev-0.0.54}/omdev/git/vendor/diffing.py +0 -0
  223. {omdev-0.0.53 → omdev-0.0.54}/omdev/git/vendor/errors.py +0 -0
  224. {omdev-0.0.53 → omdev-0.0.54}/omdev/git/vendor/journals.py +0 -0
  225. {omdev-0.0.53 → omdev-0.0.54}/omdev/git/vendor/merging.py +0 -0
  226. {omdev-0.0.53 → omdev-0.0.54}/omdev/git/vendor/paths.py +0 -0
  227. {omdev-0.0.53 → omdev-0.0.54}/omdev/git/vendor/pulling.py +0 -0
  228. {omdev-0.0.53 → omdev-0.0.54}/omdev/git/vendor/runners.py +0 -0
  229. {omdev-0.0.53 → omdev-0.0.54}/omdev/git/vendor/specs.py +0 -0
  230. {omdev-0.0.53 → omdev-0.0.54}/omdev/git/vendor/upstreams.py +0 -0
  231. {omdev-0.0.53 → omdev-0.0.54}/omdev/home/__init__.py +0 -0
  232. {omdev-0.0.53 → omdev-0.0.54}/omdev/home/__main__.py +0 -0
  233. {omdev-0.0.53 → omdev-0.0.54}/omdev/home/cli.py +0 -0
  234. {omdev-0.0.53 → omdev-0.0.54}/omdev/home/paths.py +0 -0
  235. {omdev-0.0.53 → omdev-0.0.54}/omdev/home/shadow.py +0 -0
  236. {omdev-0.0.53 → omdev-0.0.54}/omdev/imgur.py +0 -0
  237. {omdev-0.0.53 → omdev-0.0.54}/omdev/intellij/__init__.py +0 -0
  238. {omdev-0.0.53 → omdev-0.0.54}/omdev/intellij/cli.py +0 -0
  239. {omdev-0.0.53 → omdev-0.0.54}/omdev/intellij/ides.py +0 -0
  240. {omdev-0.0.53 → omdev-0.0.54}/omdev/intellij/open.py +0 -0
  241. {omdev-0.0.53 → omdev-0.0.54}/omdev/interp/__init__.py +0 -0
  242. {omdev-0.0.53 → omdev-0.0.54}/omdev/interp/__main__.py +0 -0
  243. {omdev-0.0.53 → omdev-0.0.54}/omdev/interp/cli.py +0 -0
  244. {omdev-0.0.53 → omdev-0.0.54}/omdev/interp/default.py +0 -0
  245. {omdev-0.0.53 → omdev-0.0.54}/omdev/interp/inject.py +0 -0
  246. {omdev-0.0.53 → omdev-0.0.54}/omdev/interp/inspect.py +0 -0
  247. {omdev-0.0.53 → omdev-0.0.54}/omdev/interp/providers/__init__.py +0 -0
  248. {omdev-0.0.53 → omdev-0.0.54}/omdev/interp/providers/base.py +0 -0
  249. {omdev-0.0.53 → omdev-0.0.54}/omdev/interp/providers/inject.py +0 -0
  250. {omdev-0.0.53 → omdev-0.0.54}/omdev/interp/providers/running.py +0 -0
  251. {omdev-0.0.53 → omdev-0.0.54}/omdev/interp/providers/standalone.py +0 -0
  252. {omdev-0.0.53 → omdev-0.0.54}/omdev/interp/providers/system.py +0 -0
  253. {omdev-0.0.53 → omdev-0.0.54}/omdev/interp/pyenv/__init__.py +0 -0
  254. {omdev-0.0.53 → omdev-0.0.54}/omdev/interp/pyenv/inject.py +0 -0
  255. {omdev-0.0.53 → omdev-0.0.54}/omdev/interp/pyenv/install.py +0 -0
  256. {omdev-0.0.53 → omdev-0.0.54}/omdev/interp/pyenv/provider.py +0 -0
  257. {omdev-0.0.53 → omdev-0.0.54}/omdev/interp/pyenv/pyenv.py +0 -0
  258. {omdev-0.0.53 → omdev-0.0.54}/omdev/interp/resolvers.py +0 -0
  259. {omdev-0.0.53 → omdev-0.0.54}/omdev/interp/types.py +0 -0
  260. {omdev-0.0.53 → omdev-0.0.54}/omdev/interp/uv/__init__.py +0 -0
  261. {omdev-0.0.53 → omdev-0.0.54}/omdev/interp/uv/inject.py +0 -0
  262. {omdev-0.0.53 → omdev-0.0.54}/omdev/interp/uv/provider.py +0 -0
  263. {omdev-0.0.53 → omdev-0.0.54}/omdev/interp/uv/uv.py +0 -0
  264. {omdev-0.0.53 → omdev-0.0.54}/omdev/interp/venvs.py +0 -0
  265. {omdev-0.0.53 → omdev-0.0.54}/omdev/java/__init__.py +0 -0
  266. {omdev-0.0.53 → omdev-0.0.54}/omdev/java/__main__.py +0 -0
  267. {omdev-0.0.53 → omdev-0.0.54}/omdev/java/cli.py +0 -0
  268. {omdev-0.0.53 → omdev-0.0.54}/omdev/java/pomgen.py +0 -0
  269. {omdev-0.0.53 → omdev-0.0.54}/omdev/java/utils.py +0 -0
  270. {omdev-0.0.53 → omdev-0.0.54}/omdev/java/xml.py +0 -0
  271. {omdev-0.0.53 → omdev-0.0.54}/omdev/js/__init__.py +0 -0
  272. {omdev-0.0.53 → omdev-0.0.54}/omdev/js/quickjs/LICENSE +0 -0
  273. {omdev-0.0.53 → omdev-0.0.54}/omdev/js/quickjs/TODO.md +0 -0
  274. {omdev-0.0.53 → omdev-0.0.54}/omdev/js/quickjs/__init__.py +0 -0
  275. {omdev-0.0.53 → omdev-0.0.54}/omdev/js/quickjs/_pyqjsng.c +0 -0
  276. {omdev-0.0.53 → omdev-0.0.54}/omdev/js/quickjs/_pyqjsng.pyi +0 -0
  277. {omdev-0.0.53 → omdev-0.0.54}/omdev/js/quickjs/_quickjs/LICENSE +0 -0
  278. {omdev-0.0.53 → omdev-0.0.54}/omdev/js/quickjs/_quickjs/builtin-array-fromasync.h +0 -0
  279. {omdev-0.0.53 → omdev-0.0.54}/omdev/js/quickjs/_quickjs/builtin-iterator-zip-keyed.h +0 -0
  280. {omdev-0.0.53 → omdev-0.0.54}/omdev/js/quickjs/_quickjs/builtin-iterator-zip.h +0 -0
  281. {omdev-0.0.53 → omdev-0.0.54}/omdev/js/quickjs/_quickjs/cutils.h +0 -0
  282. {omdev-0.0.53 → omdev-0.0.54}/omdev/js/quickjs/_quickjs/dtoa.c +0 -0
  283. {omdev-0.0.53 → omdev-0.0.54}/omdev/js/quickjs/_quickjs/dtoa.h +0 -0
  284. {omdev-0.0.53 → omdev-0.0.54}/omdev/js/quickjs/_quickjs/libregexp-opcode.h +0 -0
  285. {omdev-0.0.53 → omdev-0.0.54}/omdev/js/quickjs/_quickjs/libregexp.c +0 -0
  286. {omdev-0.0.53 → omdev-0.0.54}/omdev/js/quickjs/_quickjs/libregexp.h +0 -0
  287. {omdev-0.0.53 → omdev-0.0.54}/omdev/js/quickjs/_quickjs/libunicode-table.h +0 -0
  288. {omdev-0.0.53 → omdev-0.0.54}/omdev/js/quickjs/_quickjs/libunicode.c +0 -0
  289. {omdev-0.0.53 → omdev-0.0.54}/omdev/js/quickjs/_quickjs/libunicode.h +0 -0
  290. {omdev-0.0.53 → omdev-0.0.54}/omdev/js/quickjs/_quickjs/list.h +0 -0
  291. {omdev-0.0.53 → omdev-0.0.54}/omdev/js/quickjs/_quickjs/quickjs-atom.h +0 -0
  292. {omdev-0.0.53 → omdev-0.0.54}/omdev/js/quickjs/_quickjs/quickjs-c-atomics.h +0 -0
  293. {omdev-0.0.53 → omdev-0.0.54}/omdev/js/quickjs/_quickjs/quickjs-libc.c +0 -0
  294. {omdev-0.0.53 → omdev-0.0.54}/omdev/js/quickjs/_quickjs/quickjs-libc.h +0 -0
  295. {omdev-0.0.53 → omdev-0.0.54}/omdev/js/quickjs/_quickjs/quickjs-opcode.h +0 -0
  296. {omdev-0.0.53 → omdev-0.0.54}/omdev/js/quickjs/_quickjs/quickjs.c +0 -0
  297. {omdev-0.0.53 → omdev-0.0.54}/omdev/js/quickjs/_quickjs/quickjs.h +0 -0
  298. {omdev-0.0.53 → omdev-0.0.54}/omdev/js/quickjs/snapshots.py +0 -0
  299. {omdev-0.0.53 → omdev-0.0.54}/omdev/magic/__init__.py +0 -0
  300. {omdev-0.0.53 → omdev-0.0.54}/omdev/magic/__main__.py +0 -0
  301. {omdev-0.0.53 → omdev-0.0.54}/omdev/magic/cli.py +0 -0
  302. {omdev-0.0.53 → omdev-0.0.54}/omdev/magic/find.py +0 -0
  303. {omdev-0.0.53 → omdev-0.0.54}/omdev/magic/magic.py +0 -0
  304. {omdev-0.0.53 → omdev-0.0.54}/omdev/magic/prepare.py +0 -0
  305. {omdev-0.0.53 → omdev-0.0.54}/omdev/magic/styles.py +0 -0
  306. {omdev-0.0.53 → omdev-0.0.54}/omdev/manifests/__init__.py +0 -0
  307. {omdev-0.0.53 → omdev-0.0.54}/omdev/manifests/__main__.py +0 -0
  308. {omdev-0.0.53 → omdev-0.0.54}/omdev/manifests/_dumping.py +0 -0
  309. {omdev-0.0.53 → omdev-0.0.54}/omdev/manifests/building.py +0 -0
  310. {omdev-0.0.53 → omdev-0.0.54}/omdev/manifests/dumping.py +0 -0
  311. {omdev-0.0.53 → omdev-0.0.54}/omdev/manifests/main.py +0 -0
  312. {omdev-0.0.53 → omdev-0.0.54}/omdev/mypy/__init__.py +0 -0
  313. {omdev-0.0.53 → omdev-0.0.54}/omdev/mypy/debug.py +0 -0
  314. {omdev-0.0.53 → omdev-0.0.54}/omdev/mypy/report.py +0 -0
  315. {omdev-0.0.53 → omdev-0.0.54}/omdev/packaging/__init__.py +0 -0
  316. {omdev-0.0.53 → omdev-0.0.54}/omdev/packaging/marshal.py +0 -0
  317. {omdev-0.0.53 → omdev-0.0.54}/omdev/packaging/names.py +0 -0
  318. {omdev-0.0.53 → omdev-0.0.54}/omdev/packaging/requirements.py +0 -0
  319. {omdev-0.0.53 → omdev-0.0.54}/omdev/packaging/revisions.py +0 -0
  320. {omdev-0.0.53 → omdev-0.0.54}/omdev/packaging/specifiers.py +0 -0
  321. {omdev-0.0.53 → omdev-0.0.54}/omdev/packaging/versions.py +0 -0
  322. {omdev-0.0.53 → omdev-0.0.54}/omdev/packaging/wheelfile.py +0 -0
  323. {omdev-0.0.53 → omdev-0.0.54}/omdev/pip.py +0 -0
  324. {omdev-0.0.53 → omdev-0.0.54}/omdev/precheck/__init__.py +0 -0
  325. {omdev-0.0.53 → omdev-0.0.54}/omdev/precheck/__main__.py +0 -0
  326. {omdev-0.0.53 → omdev-0.0.54}/omdev/precheck/base.py +0 -0
  327. {omdev-0.0.53 → omdev-0.0.54}/omdev/precheck/blanklines.py +0 -0
  328. {omdev-0.0.53 → omdev-0.0.54}/omdev/precheck/caches.py +0 -0
  329. {omdev-0.0.53 → omdev-0.0.54}/omdev/precheck/git.py +0 -0
  330. {omdev-0.0.53 → omdev-0.0.54}/omdev/precheck/imports.py +0 -0
  331. {omdev-0.0.53 → omdev-0.0.54}/omdev/precheck/lite.py +0 -0
  332. {omdev-0.0.53 → omdev-0.0.54}/omdev/precheck/main.py +0 -0
  333. {omdev-0.0.53 → omdev-0.0.54}/omdev/precheck/manifests.py +0 -0
  334. {omdev-0.0.53 → omdev-0.0.54}/omdev/precheck/scripts.py +0 -0
  335. {omdev-0.0.53 → omdev-0.0.54}/omdev/precheck/unicode.py +0 -0
  336. {omdev-0.0.53 → omdev-0.0.54}/omdev/py/__init__.py +0 -0
  337. {omdev-0.0.53 → omdev-0.0.54}/omdev/py/asts/__init__.py +0 -0
  338. {omdev-0.0.53 → omdev-0.0.54}/omdev/py/asts/parents.py +0 -0
  339. {omdev-0.0.53 → omdev-0.0.54}/omdev/py/asts/toplevel.py +0 -0
  340. {omdev-0.0.53 → omdev-0.0.54}/omdev/py/asts/visitors.py +0 -0
  341. {omdev-0.0.53 → omdev-0.0.54}/omdev/py/attrdocs.py +0 -0
  342. {omdev-0.0.53 → omdev-0.0.54}/omdev/py/bracepy.py +0 -0
  343. {omdev-0.0.53 → omdev-0.0.54}/omdev/py/classdot.py +0 -0
  344. {omdev-0.0.53 → omdev-0.0.54}/omdev/py/docstrings/LICENSE +0 -0
  345. {omdev-0.0.53 → omdev-0.0.54}/omdev/py/docstrings/__init__.py +0 -0
  346. {omdev-0.0.53 → omdev-0.0.54}/omdev/py/docstrings/attrdoc.py +0 -0
  347. {omdev-0.0.53 → omdev-0.0.54}/omdev/py/docstrings/common.py +0 -0
  348. {omdev-0.0.53 → omdev-0.0.54}/omdev/py/docstrings/epydoc.py +0 -0
  349. {omdev-0.0.53 → omdev-0.0.54}/omdev/py/docstrings/google.py +0 -0
  350. {omdev-0.0.53 → omdev-0.0.54}/omdev/py/docstrings/numpydoc.py +0 -0
  351. {omdev-0.0.53 → omdev-0.0.54}/omdev/py/docstrings/parser.py +0 -0
  352. {omdev-0.0.53 → omdev-0.0.54}/omdev/py/docstrings/rest.py +0 -0
  353. {omdev-0.0.53 → omdev-0.0.54}/omdev/py/findimports.py +0 -0
  354. {omdev-0.0.53 → omdev-0.0.54}/omdev/py/reprs.py +0 -0
  355. {omdev-0.0.53 → omdev-0.0.54}/omdev/py/scripts/__init__.py +0 -0
  356. {omdev-0.0.53 → omdev-0.0.54}/omdev/py/scripts/bumpversion.py +0 -0
  357. {omdev-0.0.53 → omdev-0.0.54}/omdev/py/scripts/importtrace.py +0 -0
  358. {omdev-0.0.53 → omdev-0.0.54}/omdev/py/srcheaders.py +0 -0
  359. {omdev-0.0.53 → omdev-0.0.54}/omdev/py/tokens/__init__.py +0 -0
  360. {omdev-0.0.53 → omdev-0.0.54}/omdev/py/tokens/all.py +0 -0
  361. {omdev-0.0.53 → omdev-0.0.54}/omdev/py/tokens/tokenizert.py +0 -0
  362. {omdev-0.0.53 → omdev-0.0.54}/omdev/py/tokens/utils.py +0 -0
  363. {omdev-0.0.53 → omdev-0.0.54}/omdev/py/tools/__init__.py +0 -0
  364. {omdev-0.0.53 → omdev-0.0.54}/omdev/py/tools/fixdocstrings.py +0 -0
  365. {omdev-0.0.53 → omdev-0.0.54}/omdev/py/tools/importscan.py +0 -0
  366. {omdev-0.0.53 → omdev-0.0.54}/omdev/py/tools/mkrelimp.py +0 -0
  367. {omdev-0.0.53 → omdev-0.0.54}/omdev/py/tools/pipdepup.py +0 -0
  368. {omdev-0.0.53 → omdev-0.0.54}/omdev/py.typed +0 -0
  369. {omdev-0.0.53 → omdev-0.0.54}/omdev/pyproject/__init__.py +0 -0
  370. {omdev-0.0.53 → omdev-0.0.54}/omdev/pyproject/__main__.py +0 -0
  371. {omdev-0.0.53 → omdev-0.0.54}/omdev/pyproject/cli.py +0 -0
  372. {omdev-0.0.53 → omdev-0.0.54}/omdev/pyproject/configs.py +0 -0
  373. {omdev-0.0.53 → omdev-0.0.54}/omdev/pyproject/inject.py +0 -0
  374. {omdev-0.0.53 → omdev-0.0.54}/omdev/pyproject/pkg.py +0 -0
  375. {omdev-0.0.53 → omdev-0.0.54}/omdev/pyproject/reqs.py +0 -0
  376. {omdev-0.0.53 → omdev-0.0.54}/omdev/pyproject/resources/dockerdev.sh +0 -0
  377. {omdev-0.0.53 → omdev-0.0.54}/omdev/pyproject/resources/python.sh +0 -0
  378. {omdev-0.0.53 → omdev-0.0.54}/omdev/pyproject/tools/__init__.py +0 -0
  379. {omdev-0.0.53 → omdev-0.0.54}/omdev/pyproject/tools/aboutdeps.py +0 -0
  380. {omdev-0.0.53 → omdev-0.0.54}/omdev/pyproject/tools/buildrs.py +0 -0
  381. {omdev-0.0.53 → omdev-0.0.54}/omdev/pyproject/tools/pyversions.py +0 -0
  382. {omdev-0.0.53 → omdev-0.0.54}/omdev/pyproject/venvs.py +0 -0
  383. {omdev-0.0.53 → omdev-0.0.54}/omdev/pyproject/versions.py +0 -0
  384. {omdev-0.0.53 → omdev-0.0.54}/omdev/pyright/__init__.py +0 -0
  385. {omdev-0.0.53 → omdev-0.0.54}/omdev/pyright/report.py +0 -0
  386. {omdev-0.0.53 → omdev-0.0.54}/omdev/rs/__init__.py +0 -0
  387. {omdev-0.0.53 → omdev-0.0.54}/omdev/scripts/__init__.py +0 -0
  388. {omdev-0.0.53 → omdev-0.0.54}/omdev/scripts/ci.py +0 -0
  389. {omdev-0.0.53 → omdev-0.0.54}/omdev/scripts/ghajunit.py +0 -0
  390. {omdev-0.0.53 → omdev-0.0.54}/omdev/scripts/interp.py +0 -0
  391. {omdev-0.0.53 → omdev-0.0.54}/omdev/scripts/lib/__init__.py +0 -0
  392. {omdev-0.0.53 → omdev-0.0.54}/omdev/scripts/lib/formats/__init__.py +0 -0
  393. {omdev-0.0.53 → omdev-0.0.54}/omdev/scripts/lib/formats/goyaml.py +0 -0
  394. {omdev-0.0.53 → omdev-0.0.54}/omdev/scripts/lib/inject.py +0 -0
  395. {omdev-0.0.53 → omdev-0.0.54}/omdev/scripts/lib/io/__init__.py +0 -0
  396. {omdev-0.0.53 → omdev-0.0.54}/omdev/scripts/lib/io/pipelines.py +0 -0
  397. {omdev-0.0.53 → omdev-0.0.54}/omdev/scripts/lib/io/streambufs.py +0 -0
  398. {omdev-0.0.53 → omdev-0.0.54}/omdev/scripts/lib/logs.py +0 -0
  399. {omdev-0.0.53 → omdev-0.0.54}/omdev/scripts/lib/marshal.py +0 -0
  400. {omdev-0.0.53 → omdev-0.0.54}/omdev/scripts/pidfiles.py +0 -0
  401. {omdev-0.0.53 → omdev-0.0.54}/omdev/scripts/pyproject.py +0 -0
  402. {omdev-0.0.53 → omdev-0.0.54}/omdev/scripts/slowcat.py +0 -0
  403. {omdev-0.0.53 → omdev-0.0.54}/omdev/scripts/tmpexec.py +0 -0
  404. {omdev-0.0.53 → omdev-0.0.54}/omdev/specs/__init__.py +0 -0
  405. {omdev-0.0.53 → omdev-0.0.54}/omdev/specs/irc/__init__.py +0 -0
  406. {omdev-0.0.53 → omdev-0.0.54}/omdev/specs/irc/messages/__init__.py +0 -0
  407. {omdev-0.0.53 → omdev-0.0.54}/omdev/specs/irc/messages/base.py +0 -0
  408. {omdev-0.0.53 → omdev-0.0.54}/omdev/specs/irc/messages/formats.py +0 -0
  409. {omdev-0.0.53 → omdev-0.0.54}/omdev/specs/irc/messages/messages.py +0 -0
  410. {omdev-0.0.53 → omdev-0.0.54}/omdev/specs/irc/messages/parsing.py +0 -0
  411. {omdev-0.0.53 → omdev-0.0.54}/omdev/specs/irc/numerics/__init__.py +0 -0
  412. {omdev-0.0.53 → omdev-0.0.54}/omdev/specs/irc/numerics/formats.py +0 -0
  413. {omdev-0.0.53 → omdev-0.0.54}/omdev/specs/irc/numerics/numerics.py +0 -0
  414. {omdev-0.0.53 → omdev-0.0.54}/omdev/specs/irc/numerics/types.py +0 -0
  415. {omdev-0.0.53 → omdev-0.0.54}/omdev/specs/irc/protocol/LICENSE +0 -0
  416. {omdev-0.0.53 → omdev-0.0.54}/omdev/specs/irc/protocol/__init__.py +0 -0
  417. {omdev-0.0.53 → omdev-0.0.54}/omdev/specs/irc/protocol/consts.py +0 -0
  418. {omdev-0.0.53 → omdev-0.0.54}/omdev/specs/irc/protocol/errors.py +0 -0
  419. {omdev-0.0.53 → omdev-0.0.54}/omdev/specs/irc/protocol/message.py +0 -0
  420. {omdev-0.0.53 → omdev-0.0.54}/omdev/specs/irc/protocol/nuh.py +0 -0
  421. {omdev-0.0.53 → omdev-0.0.54}/omdev/specs/irc/protocol/parsing.py +0 -0
  422. {omdev-0.0.53 → omdev-0.0.54}/omdev/specs/irc/protocol/rendering.py +0 -0
  423. {omdev-0.0.53 → omdev-0.0.54}/omdev/specs/irc/protocol/tags.py +0 -0
  424. {omdev-0.0.53 → omdev-0.0.54}/omdev/specs/irc/protocol/utils.py +0 -0
  425. {omdev-0.0.53 → omdev-0.0.54}/omdev/specs/jsonschema/__init__.py +0 -0
  426. {omdev-0.0.53 → omdev-0.0.54}/omdev/specs/jsonschema/codegen/__init__.py +0 -0
  427. {omdev-0.0.53 → omdev-0.0.54}/omdev/specs/jsonschema/codegen/__main__.py +0 -0
  428. {omdev-0.0.53 → omdev-0.0.54}/omdev/specs/jsonschema/codegen/analysis.py +0 -0
  429. {omdev-0.0.53 → omdev-0.0.54}/omdev/specs/jsonschema/codegen/cli.py +0 -0
  430. {omdev-0.0.53 → omdev-0.0.54}/omdev/specs/jsonschema/codegen/config.py +0 -0
  431. {omdev-0.0.53 → omdev-0.0.54}/omdev/specs/jsonschema/codegen/errors.py +0 -0
  432. {omdev-0.0.53 → omdev-0.0.54}/omdev/specs/jsonschema/codegen/generator.py +0 -0
  433. {omdev-0.0.53 → omdev-0.0.54}/omdev/specs/jsonschema/codegen/ir.py +0 -0
  434. {omdev-0.0.53 → omdev-0.0.54}/omdev/specs/jsonschema/codegen/names.py +0 -0
  435. {omdev-0.0.53 → omdev-0.0.54}/omdev/specs/jsonschema/codegen/rendering.py +0 -0
  436. {omdev-0.0.53 → omdev-0.0.54}/omdev/specs/jsonschema/codegen/transforms.py +0 -0
  437. {omdev-0.0.53 → omdev-0.0.54}/omdev/specs/jsonschema/codegen/typing.py +0 -0
  438. {omdev-0.0.53 → omdev-0.0.54}/omdev/specs/oci/__init__.py +0 -0
  439. {omdev-0.0.53 → omdev-0.0.54}/omdev/specs/oci/building.py +0 -0
  440. {omdev-0.0.53 → omdev-0.0.54}/omdev/specs/oci/compression.py +0 -0
  441. {omdev-0.0.53 → omdev-0.0.54}/omdev/specs/oci/data.py +0 -0
  442. {omdev-0.0.53 → omdev-0.0.54}/omdev/specs/oci/datarefs.py +0 -0
  443. {omdev-0.0.53 → omdev-0.0.54}/omdev/specs/oci/dataserver.py +0 -0
  444. {omdev-0.0.53 → omdev-0.0.54}/omdev/specs/oci/loading.py +0 -0
  445. {omdev-0.0.53 → omdev-0.0.54}/omdev/specs/oci/media.py +0 -0
  446. {omdev-0.0.53 → omdev-0.0.54}/omdev/specs/oci/pack/__init__.py +0 -0
  447. {omdev-0.0.53 → omdev-0.0.54}/omdev/specs/oci/pack/packing.py +0 -0
  448. {omdev-0.0.53 → omdev-0.0.54}/omdev/specs/oci/pack/repositories.py +0 -0
  449. {omdev-0.0.53 → omdev-0.0.54}/omdev/specs/oci/pack/unpacking.py +0 -0
  450. {omdev-0.0.53 → omdev-0.0.54}/omdev/specs/oci/repositories.py +0 -0
  451. {omdev-0.0.53 → omdev-0.0.54}/omdev/specs/oci/tars.py +0 -0
  452. {omdev-0.0.53 → omdev-0.0.54}/omdev/tagstrings.py +0 -0
  453. {omdev-0.0.53 → omdev-0.0.54}/omdev/tools/__init__.py +0 -0
  454. {omdev-0.0.53 → omdev-0.0.54}/omdev/tools/cloc.py +0 -0
  455. {omdev-0.0.53 → omdev-0.0.54}/omdev/tools/diff.py +0 -0
  456. {omdev-0.0.53 → omdev-0.0.54}/omdev/tools/doc.py +0 -0
  457. {omdev-0.0.53 → omdev-0.0.54}/omdev/tools/docker.py +0 -0
  458. {omdev-0.0.53 → omdev-0.0.54}/omdev/tools/git/__init__.py +0 -0
  459. {omdev-0.0.53 → omdev-0.0.54}/omdev/tools/git/__main__.py +0 -0
  460. {omdev-0.0.53 → omdev-0.0.54}/omdev/tools/git/cli.py +0 -0
  461. {omdev-0.0.53 → omdev-0.0.54}/omdev/tools/git/cloning.py +0 -0
  462. {omdev-0.0.53 → omdev-0.0.54}/omdev/tools/git/consts.py +0 -0
  463. {omdev-0.0.53 → omdev-0.0.54}/omdev/tools/git/messages.py +0 -0
  464. {omdev-0.0.53 → omdev-0.0.54}/omdev/tools/json/__init__.py +0 -0
  465. {omdev-0.0.53 → omdev-0.0.54}/omdev/tools/json/__main__.py +0 -0
  466. {omdev-0.0.53 → omdev-0.0.54}/omdev/tools/json/cli.py +0 -0
  467. {omdev-0.0.53 → omdev-0.0.54}/omdev/tools/json/formats.py +0 -0
  468. {omdev-0.0.53 → omdev-0.0.54}/omdev/tools/json/io.py +0 -0
  469. {omdev-0.0.53 → omdev-0.0.54}/omdev/tools/json/parsing.py +0 -0
  470. {omdev-0.0.53 → omdev-0.0.54}/omdev/tools/json/processing.py +0 -0
  471. {omdev-0.0.53 → omdev-0.0.54}/omdev/tools/json/rendering.py +0 -0
  472. {omdev-0.0.53 → omdev-0.0.54}/omdev/tools/jsonview/__init__.py +0 -0
  473. {omdev-0.0.53 → omdev-0.0.54}/omdev/tools/jsonview/__main__.py +0 -0
  474. {omdev-0.0.53 → omdev-0.0.54}/omdev/tools/jsonview/cli.py +0 -0
  475. {omdev-0.0.53 → omdev-0.0.54}/omdev/tools/jsonview/resources/jsonview.css +0 -0
  476. {omdev-0.0.53 → omdev-0.0.54}/omdev/tools/jsonview/resources/jsonview.html.j2 +0 -0
  477. {omdev-0.0.53 → omdev-0.0.54}/omdev/tools/jsonview/resources/jsonview.js +0 -0
  478. {omdev-0.0.53 → omdev-0.0.54}/omdev/tools/linehisto.py +0 -0
  479. {omdev-0.0.53 → omdev-0.0.54}/omdev/tools/mkenv.py +0 -0
  480. {omdev-0.0.53 → omdev-0.0.54}/omdev/tools/notebook.py +0 -0
  481. {omdev-0.0.53 → omdev-0.0.54}/omdev/tools/ocr.py +0 -0
  482. {omdev-0.0.53 → omdev-0.0.54}/omdev/tools/pawk/README.md +0 -0
  483. {omdev-0.0.53 → omdev-0.0.54}/omdev/tools/pawk/__init__.py +0 -0
  484. {omdev-0.0.53 → omdev-0.0.54}/omdev/tools/pawk/__main__.py +0 -0
  485. {omdev-0.0.53 → omdev-0.0.54}/omdev/tools/pawk/pawk.py +0 -0
  486. {omdev-0.0.53 → omdev-0.0.54}/omdev/tools/pip.py +0 -0
  487. {omdev-0.0.53 → omdev-0.0.54}/omdev/tools/prof.py +0 -0
  488. {omdev-0.0.53 → omdev-0.0.54}/omdev/tools/qr.py +0 -0
  489. {omdev-0.0.53 → omdev-0.0.54}/omdev/tools/shadow.py +0 -0
  490. {omdev-0.0.53 → omdev-0.0.54}/omdev/tools/shell.py +0 -0
  491. {omdev-0.0.53 → omdev-0.0.54}/omdev/tools/sqlrepl.py +0 -0
  492. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/__init__.py +0 -0
  493. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/diff/LICENSE +0 -0
  494. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/diff/README.md +0 -0
  495. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/diff/__init__.py +0 -0
  496. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/diff/__main__.py +0 -0
  497. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/diff/cli.py +0 -0
  498. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/diff/rendering.py +0 -0
  499. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/diff/terminal.py +0 -0
  500. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/diff/themes.py +0 -0
  501. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/README.md +0 -0
  502. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/__init__.py +0 -0
  503. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/_dataclasses.py +0 -0
  504. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/_devdocs/design.md +0 -0
  505. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/_devdocs/dev_00_initial.md +0 -0
  506. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/_devdocs/dev_01_parity_push.md +0 -0
  507. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/_devdocs/intro.md +0 -0
  508. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/_devdocs/requirements.md +0 -0
  509. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/_devdocs/research.md +0 -0
  510. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/controls/__init__.py +0 -0
  511. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/controls/base.py +0 -0
  512. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/controls/history.py +0 -0
  513. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/controls/markdown.py +0 -0
  514. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/controls/spinners.py +0 -0
  515. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/controls/stacks.py +0 -0
  516. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/controls/static.py +0 -0
  517. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/controls/status.py +0 -0
  518. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/controls/suggestions.py +0 -0
  519. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/controls/textarea.py +0 -0
  520. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/docs/__init__.py +0 -0
  521. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/docs/cursors.py +0 -0
  522. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/docs/documents.py +0 -0
  523. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/docs/edits.py +0 -0
  524. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/docs/highlighting.py +0 -0
  525. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/docs/positions.py +0 -0
  526. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/docs/searching.py +0 -0
  527. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/docs/treesitter.py +0 -0
  528. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/events/__init__.py +0 -0
  529. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/events/keymaps.py +0 -0
  530. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/events/keys.py +0 -0
  531. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/events/parsing.py +0 -0
  532. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/events/types.py +0 -0
  533. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/events/xterm.py +0 -0
  534. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/runtime/__init__.py +0 -0
  535. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/runtime/asyncio.py +0 -0
  536. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/runtime/base.py +0 -0
  537. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/runtime/jobcontrol.py +0 -0
  538. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/runtime/sync.py +0 -0
  539. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/runtime/timers.py +0 -0
  540. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/screens/__init__.py +0 -0
  541. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/screens/cells.py +0 -0
  542. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/screens/diffs.py +0 -0
  543. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/surfaces/__init__.py +0 -0
  544. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/surfaces/alts.py +0 -0
  545. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/surfaces/base.py +0 -0
  546. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/surfaces/inlines.py +0 -0
  547. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/surfaces/writers.py +0 -0
  548. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/text/__init__.py +0 -0
  549. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/text/markdown/__init__.py +0 -0
  550. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/text/markdown/backends.py +0 -0
  551. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/text/markdown/base.py +0 -0
  552. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/text/markdown/flattening.py +0 -0
  553. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/text/markdown/markdownit.py +0 -0
  554. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/text/markdown/pdcmark.py +0 -0
  555. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/text/parts.py +0 -0
  556. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/text/rendering.py +0 -0
  557. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/text/segments.py +0 -0
  558. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/text/styles.py +0 -0
  559. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/text/themes.py +0 -0
  560. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/text/wrap.py +0 -0
  561. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/tty/__init__.py +0 -0
  562. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/tty/terminals.py +0 -0
  563. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/vim/_dataclasses.py +0 -0
  564. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/vim/modes.py +0 -0
  565. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/vim/motions.py +0 -0
  566. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/vim/parsing.py +0 -0
  567. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/vim/registers.py +0 -0
  568. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/vim/scans.py +0 -0
  569. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/vim/status.py +0 -0
  570. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/vim/substitutes.py +0 -0
  571. {omdev-0.0.53 → omdev-0.0.54}/omdev/tui/minitui/vim/textobjs.py +0 -0
  572. {omdev-0.0.53 → omdev-0.0.54}/omdev.egg-info/dependency_links.txt +0 -0
  573. {omdev-0.0.53 → omdev-0.0.54}/omdev.egg-info/entry_points.txt +0 -0
  574. {omdev-0.0.53 → omdev-0.0.54}/omdev.egg-info/top_level.txt +0 -0
  575. {omdev-0.0.53 → omdev-0.0.54}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: omdev
3
- Version: 0.0.53
3
+ Version: 0.0.54
4
4
  Summary: omdev
5
5
  Author: wrmsr
6
6
  License-Expression: BSD-3-Clause
@@ -14,11 +14,11 @@ Classifier: Programming Language :: Python :: 3.15
14
14
  Requires-Python: >=3.14
15
15
  Description-Content-Type: text/markdown
16
16
  License-File: LICENSE
17
- Requires-Dist: omcore==0.0.53
17
+ Requires-Dist: omcore==0.0.54
18
18
  Provides-Extra: ominfra
19
- Requires-Dist: ominfra==0.0.53; extra == "ominfra"
19
+ Requires-Dist: ominfra==0.0.54; extra == "ominfra"
20
20
  Provides-Extra: omllm
21
- Requires-Dist: omllm==0.0.53; extra == "omllm"
21
+ Requires-Dist: omllm==0.0.54; extra == "omllm"
22
22
  Provides-Extra: black
23
23
  Requires-Dist: black~=26.5; extra == "black"
24
24
  Provides-Extra: c
@@ -59,14 +59,14 @@ Requires-Dist: tree-sitter-toml~=0.7; extra == "tui-syntax"
59
59
  Requires-Dist: tree-sitter-xml~=0.7; extra == "tui-syntax"
60
60
  Requires-Dist: tree-sitter-yaml~=0.7; extra == "tui-syntax"
61
61
  Provides-Extra: cext
62
- Requires-Dist: omdev-cext==0.0.53; extra == "cext"
62
+ Requires-Dist: omdev-cext==0.0.54; extra == "cext"
63
63
  Provides-Extra: rs
64
- Requires-Dist: omdev-rs==0.0.53; extra == "rs"
64
+ Requires-Dist: omdev-rs==0.0.54; extra == "rs"
65
65
  Provides-Extra: cli
66
- Requires-Dist: omdev-cli==0.0.53; extra == "cli"
66
+ Requires-Dist: omdev-cli==0.0.54; extra == "cli"
67
67
  Provides-Extra: all
68
- Requires-Dist: ominfra==0.0.53; extra == "all"
69
- Requires-Dist: omllm==0.0.53; extra == "all"
68
+ Requires-Dist: ominfra==0.0.54; extra == "all"
69
+ Requires-Dist: omllm==0.0.54; extra == "all"
70
70
  Requires-Dist: black~=26.5; extra == "all"
71
71
  Requires-Dist: pycparser~=3.0; extra == "all"
72
72
  Requires-Dist: pcpp~=1.30; extra == "all"
@@ -95,9 +95,9 @@ Requires-Dist: tree-sitter-sql~=0.3; extra == "all"
95
95
  Requires-Dist: tree-sitter-toml~=0.7; extra == "all"
96
96
  Requires-Dist: tree-sitter-xml~=0.7; extra == "all"
97
97
  Requires-Dist: tree-sitter-yaml~=0.7; extra == "all"
98
- Requires-Dist: omdev-cext==0.0.53; extra == "all"
99
- Requires-Dist: omdev-rs==0.0.53; extra == "all"
100
- Requires-Dist: omdev-cli==0.0.53; extra == "all"
98
+ Requires-Dist: omdev-cext==0.0.54; extra == "all"
99
+ Requires-Dist: omdev-rs==0.0.54; extra == "all"
100
+ Requires-Dist: omdev-cli==0.0.54; extra == "all"
101
101
  Dynamic: license-file
102
102
 
103
103
  # Overview
@@ -0,0 +1,330 @@
1
+ #!/usr/bin/env python3
2
+ # @om-lite
3
+ # @om-script
4
+ # ruff: noqa: UP006 UP045
5
+ """
6
+ inject_secret.py -- atomically upsert keys into a JSON object file, safely in the presence of concurrent invocations of
7
+ itself.
8
+
9
+ printf '{"db_password": "%s", "legacy_token": null}' "$DB_PASSWORD" | inject_secret.py /etc/app/config.json
10
+
11
+ Stdin is a JSON object, shallowly merged into the file (which must hold a JSON object, or not exist yet): each key is
12
+ upserted wholesale -- values can be anything, but dicts and lists are replaced, never merged -- and a null value removes
13
+ the key.
14
+
15
+ Key order records modification order: keys not mentioned on stdin are written in the order they were read, followed by
16
+ every key set on stdin -- whether or not its value actually changed -- in the order they appear there. Removed keys are
17
+ simply dropped. If the result is identical to the current contents (same keys, values and order, compared by JSON
18
+ serialization, so 1, 1.0 and true are distinct) the file is not rewritten.
19
+
20
+ Output is pretty-printed with a two space indent, except that an empty object is written as exactly `{}`.
21
+
22
+ Guarantees (Linux only; needs nothing newer than flock(2), link(2), rename(2)):
23
+
24
+ * Nobody ever observes a partial, empty or invalid file at the path. The path is only ever populated by link(2)
25
+ (create) or rename(2) (replace) of a fully written and fsync'd temp file in the same directory.
26
+ * Concurrent invocations never lose each other's updates, whether or not the file exists beforehand.
27
+
28
+ How the lock and the atomic replace are combined:
29
+
30
+ flock(2) locks an *inode*, not a path, and rename(2) swaps the inode behind the path. A writer that holds the lock on
31
+ the old inode and renames a new file into place therefore leaves waiters holding a lock on a stale inode. The fix:
32
+ after acquiring the lock, compare fstat(fd) with stat(path); if they differ, release and start over against the
33
+ current file. Every replacement is performed by the holder of the lock on the inode currently at the path, so writers
34
+ are fully serialized.
35
+
36
+ Creation: rename(2) clobbers unconditionally, so bootstrapping via rename could overwrite a file a concurrent writer
37
+ just populated. link(2) fails with EEXIST if the target exists, so it is the atomic create-if-absent.
38
+
39
+ Exit status: 0 ok, 1 error, 2 usage, 3 lock timeout.
40
+ """
41
+ import argparse
42
+ import collections
43
+ import errno
44
+ import fcntl
45
+ import json
46
+ import os
47
+ import random
48
+ import stat
49
+ import sys
50
+ import tempfile
51
+ import time
52
+ import typing as ta
53
+
54
+
55
+ ##
56
+
57
+
58
+ # seconds; jittered so waiters don't wake in lockstep
59
+ POLL_MIN = 0.005
60
+ POLL_MAX = 0.05
61
+
62
+ # mode for a file we create; existing files keep theirs
63
+ NEW_FILE_MODE = 0o600
64
+
65
+ JsonObject = ta.OrderedDict[str, ta.Any] # ta.TypeAlias
66
+
67
+
68
+ def write_all(fd: int, data: bytes) -> None:
69
+ view = memoryview(data)
70
+ while view:
71
+ view = view[os.write(fd, view):]
72
+
73
+
74
+ def read_all(fd: int) -> bytes:
75
+ chunks: ta.List[bytes] = []
76
+ while True:
77
+ chunk = os.read(fd, 1 << 16)
78
+ if not chunk:
79
+ return b''.join(chunks)
80
+ chunks.append(chunk)
81
+
82
+
83
+ def fsync_dir(dirname: str) -> None:
84
+ """Persist the directory entry (the link/rename itself) after a crash."""
85
+
86
+ fd = os.open(dirname, os.O_RDONLY)
87
+ try:
88
+ os.fsync(fd)
89
+ except OSError:
90
+ pass # some filesystems refuse fsync on directories; not fatal
91
+ finally:
92
+ os.close(fd)
93
+
94
+
95
+ def write_temp(
96
+ dirname: str,
97
+ basename: str,
98
+ data: bytes,
99
+ mode: int,
100
+ *,
101
+ uid_gid: ta.Optional[ta.Tuple[int, int]] = None,
102
+ ) -> str:
103
+ """Write data to a fresh, fsync'd temp file next to the target. Returns its path."""
104
+
105
+ fd, tmp = tempfile.mkstemp(prefix='.' + basename + '.', suffix='.tmp', dir=dirname)
106
+
107
+ try:
108
+ if uid_gid is not None:
109
+ uid, gid = uid_gid
110
+ try:
111
+ os.fchown(fd, uid, gid)
112
+ except PermissionError:
113
+ pass # not root; the file keeps our ownership
114
+
115
+ os.fchmod(fd, mode)
116
+ write_all(fd, data)
117
+ os.fsync(fd)
118
+
119
+ except BaseException:
120
+ os.close(fd)
121
+ os.unlink(tmp)
122
+ raise
123
+
124
+ os.close(fd)
125
+ return tmp
126
+
127
+
128
+ def parse_object(text: str) -> JsonObject:
129
+ data = json.loads(text, object_pairs_hook=collections.OrderedDict)
130
+ if not isinstance(data, collections.OrderedDict):
131
+ raise ValueError('top-level JSON value is not an object') # noqa
132
+ return data
133
+
134
+
135
+ def load(raw: bytes) -> JsonObject:
136
+ text = raw.decode('utf-8')
137
+ if not text.strip():
138
+ return collections.OrderedDict() # tolerate an empty/whitespace-only file (e.g. `touch`ed)
139
+ return parse_object(text)
140
+
141
+
142
+ def dump(data: JsonObject) -> bytes:
143
+ if not data:
144
+ return b'{}'
145
+ return (json.dumps(data, indent=2, ensure_ascii=False) + '\n').encode('utf-8')
146
+
147
+
148
+ def values_equal(a: ta.Any, b: ta.Any) -> bool:
149
+ """Compare by JSON serialization: 1, 1.0 and true are all distinct, and key order within nested objects matters."""
150
+
151
+ return json.dumps(a) == json.dumps(b)
152
+
153
+
154
+ def merge(
155
+ existing: JsonObject,
156
+ update: JsonObject,
157
+ ) -> ta.Tuple[JsonObject, bool]:
158
+ """
159
+ Shallowly apply `update` to `existing`: a None value removes the key, any other value replaces it wholesale. Returns
160
+ the merged object -- keys not in `update` first, in their existing order, then every key set by `update` in `update`
161
+ order, even if its value is unchanged -- and whether the result differs from `existing` at all.
162
+ """
163
+
164
+ merged: JsonObject = collections.OrderedDict(
165
+ (k, v) for k, v in existing.items() if k not in update
166
+ )
167
+ merged.update((k, v) for k, v in update.items() if v is not None)
168
+ return merged, not values_equal(merged, existing)
169
+
170
+
171
+ def try_create(
172
+ path: str,
173
+ dirname: str,
174
+ basename: str,
175
+ data: JsonObject,
176
+ ) -> bool:
177
+ """Atomically create `path` with `data` iff it does not exist. True on success."""
178
+
179
+ tmp = write_temp(
180
+ dirname,
181
+ basename,
182
+ dump(data),
183
+ NEW_FILE_MODE,
184
+ )
185
+
186
+ try:
187
+ os.link(tmp, path)
188
+
189
+ except FileExistsError:
190
+ return False # someone beat us to it; caller will lock and update that file
191
+
192
+ except OSError as e:
193
+ if e.errno in (errno.EPERM, errno.EOPNOTSUPP, errno.EXDEV, errno.EMLINK):
194
+ raise OSError(
195
+ e.errno,
196
+ f'filesystem does not allow hard links, which are needed to create the file atomically: {e.strerror}',
197
+ path,
198
+ ) from None
199
+
200
+ raise
201
+
202
+ finally:
203
+ os.unlink(tmp)
204
+
205
+ fsync_dir(dirname)
206
+ return True
207
+
208
+
209
+ def inject(
210
+ path: str,
211
+ update: JsonObject,
212
+ timeout: float,
213
+ ) -> None:
214
+ path = os.path.realpath(path) # operate on the real file if `path` is a symlink
215
+ dirname, basename = os.path.split(path)
216
+ deadline = time.monotonic() + timeout
217
+
218
+ while True:
219
+ try:
220
+ fd = os.open(path, os.O_RDONLY)
221
+
222
+ except FileNotFoundError:
223
+ merged, _ = merge(collections.OrderedDict(), update)
224
+
225
+ if try_create(
226
+ path,
227
+ dirname,
228
+ basename,
229
+ merged,
230
+ ):
231
+ return
232
+
233
+ continue # lost the create race; lock whatever exists now
234
+
235
+ try:
236
+ try:
237
+ fcntl.flock(fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
238
+ except BlockingIOError:
239
+ if time.monotonic() >= deadline:
240
+ raise TimeoutError(f'timed out waiting for lock on {path}') from None
241
+ time.sleep(random.uniform(POLL_MIN, POLL_MAX))
242
+ continue
243
+
244
+ # We hold a lock on *an* inode. Make sure it is still the one at `path`: a concurrent writer may have
245
+ # rename()d a new file over it while we waited.
246
+ st = os.fstat(fd)
247
+
248
+ try:
249
+ cur = os.stat(path)
250
+ except FileNotFoundError:
251
+ continue # deleted underneath us; go recreate
252
+
253
+ if (st.st_dev, st.st_ino) != (cur.st_dev, cur.st_ino):
254
+ continue # stale inode; retry against the current file
255
+ if not stat.S_ISREG(st.st_mode):
256
+ raise OSError(errno.EINVAL, 'not a regular file', path)
257
+
258
+ try:
259
+ existing = load(read_all(fd))
260
+ except ValueError as e:
261
+ raise ValueError(f'{path}: {e}') from None
262
+
263
+ merged, changed = merge(existing, update)
264
+ if not changed:
265
+ return # nothing to do; don't churn the file
266
+
267
+ tmp = write_temp(
268
+ dirname,
269
+ basename,
270
+ dump(merged),
271
+ stat.S_IMODE(st.st_mode),
272
+ uid_gid=(st.st_uid, st.st_gid),
273
+ )
274
+
275
+ try:
276
+ os.rename(tmp, path) # atomic replace, done while holding the lock
277
+ except BaseException:
278
+ os.unlink(tmp)
279
+ raise
280
+
281
+ fsync_dir(dirname)
282
+ return
283
+
284
+ finally:
285
+ os.close(fd) # releases the flock
286
+
287
+
288
+ def main(argv: ta.Any = None) -> int:
289
+ ap = argparse.ArgumentParser(
290
+ description='Atomically upsert keys into a JSON object file; the update is a JSON object read from stdin.',
291
+ )
292
+
293
+ ap.add_argument(
294
+ 'file',
295
+ help='JSON file to update (created if missing)',
296
+ )
297
+ ap.add_argument(
298
+ '--timeout',
299
+ type=float,
300
+ default=30.0,
301
+ help='max seconds to wait for the lock (default: 30)',
302
+ )
303
+ ap.add_argument(
304
+ '--description',
305
+ help='ignored; only serves as a note in process listings and execution logs',
306
+ )
307
+
308
+ args = ap.parse_args(argv)
309
+
310
+ try:
311
+ update = parse_object(sys.stdin.buffer.read().decode('utf-8'))
312
+ except ValueError as e: # covers UnicodeDecodeError and json.JSONDecodeError
313
+ print(f'error: stdin is not a JSON object: {e}', file=sys.stderr)
314
+ return 1
315
+
316
+ try:
317
+ inject(args.file, update, args.timeout)
318
+ except TimeoutError as e:
319
+ print(f'error: {e}', file=sys.stderr)
320
+ return 3
321
+
322
+ except (OSError, ValueError) as e:
323
+ print(f'error: {e}', file=sys.stderr)
324
+ return 1
325
+
326
+ return 0
327
+
328
+
329
+ if __name__ == '__main__':
330
+ sys.exit(main())
@@ -1,7 +1,8 @@
1
1
  import os.path
2
2
  import typing as ta
3
3
 
4
- from omcore.formats.yaml import all as yaml
4
+ from omcore import lang
5
+ from omcore.configs.formats import DEFAULT_CONFIG_FILE_LOADER
5
6
  from omcore.os.environ import EnvVar
6
7
  from omcore.secrets import all as sec
7
8
 
@@ -11,25 +12,34 @@ from .paths import get_home_paths
11
12
  ##
12
13
 
13
14
 
14
- SECRETS_FILE_ENV_VAR = EnvVar('OM_SECRETS')
15
- DEFAULT_SECRETS_FILE_NAME = 'secrets.yml'
15
+ INJECTED_SECRETS_FILE_ENV_VAR = EnvVar('OM_SECRETS')
16
+ DEFAULT_INJECTED_SECRETS_FILE_NAME: ta.Final = 'secrets-injected.json'
16
17
 
18
+ USER_SECRETS_FILE_ENV_VAR = EnvVar('OM_SECRETS_INJECTED')
19
+ DEFAULT_USER_SECRETS_FILE_NAME: ta.Final = 'secrets.yml'
17
20
 
18
- def get_secrets_file() -> str:
19
- return os.path.expanduser(
20
- SECRETS_FILE_ENV_VAR.get(lambda: os.path.join(get_home_paths().config_dir, DEFAULT_SECRETS_FILE_NAME)),
21
- )
21
+
22
+ def _get_secrets_file_paths() -> lang.SequenceNotStr[str]:
23
+ return [
24
+ os.path.expanduser(p)
25
+ for ev, dfn in [
26
+ (INJECTED_SECRETS_FILE_ENV_VAR, DEFAULT_INJECTED_SECRETS_FILE_NAME),
27
+ (USER_SECRETS_FILE_ENV_VAR, DEFAULT_USER_SECRETS_FILE_NAME),
28
+ ]
29
+ for p_ in ev.get(lambda: os.path.join(get_home_paths().config_dir, dfn)).split(os.pathsep)
30
+ if (p := p_.strip())
31
+ ]
22
32
 
23
33
 
24
34
  def load_secrets() -> sec.Secrets:
25
35
  dct: dict[str, sec.Secret] = {}
26
- try:
27
- with open(get_secrets_file()) as f:
28
- for k, v in yaml.loads(f.read()).items():
36
+ for fp in _get_secrets_file_paths():
37
+ try:
38
+ for k, v in DEFAULT_CONFIG_FILE_LOADER.load_file(fp).as_map().items():
29
39
  if isinstance(v, str):
30
40
  dct[k] = sec.Secret(key=k, value=v)
31
- except FileNotFoundError:
32
- pass
41
+ except FileNotFoundError:
42
+ pass
33
43
  return sec.MappingSecrets(dct)
34
44
 
35
45
 
@@ -0,0 +1,27 @@
1
+ Copyright (c) 2016 - 2025, Lars Heuer
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without modification,
5
+ are permitted provided that the following conditions are met:
6
+
7
+ 1. Redistributions of source code must retain the above copyright notice,
8
+ this list of conditions and the following disclaimer.
9
+
10
+ 2. Redistributions in binary form must reproduce the above copyright notice,
11
+ this list of conditions and the following disclaimer in the documentation
12
+ and/or other materials provided with the distribution.
13
+
14
+ 3. Neither the name of the copyright holder nor the names of its contributors
15
+ may be used to endorse or promote products derived from this software
16
+ without specific prior written permission.
17
+
18
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1 @@
1
+ # https://github.com/heuer/segno/tree/1.6.6