redeploy 0.2.18__tar.gz → 0.2.19__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 (113) hide show
  1. {redeploy-0.2.18 → redeploy-0.2.19}/PKG-INFO +6 -6
  2. {redeploy-0.2.18 → redeploy-0.2.19}/README.md +5 -5
  3. {redeploy-0.2.18 → redeploy-0.2.19}/pyproject.toml +1 -1
  4. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/__init__.py +1 -1
  5. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/apply/executor.py +49 -0
  6. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/cli.py +565 -413
  7. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/models.py +1 -0
  8. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy.egg-info/PKG-INFO +6 -6
  9. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/apply/__init__.py +0 -0
  10. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/apply/state.py +0 -0
  11. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/audit.py +0 -0
  12. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/data_sync.py +0 -0
  13. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/detect/__init__.py +0 -0
  14. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/detect/detector.py +0 -0
  15. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/detect/probes.py +0 -0
  16. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/detect/remote.py +0 -0
  17. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/detect/templates.py +0 -0
  18. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/detect/workflow.py +0 -0
  19. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/discovery.py +0 -0
  20. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/dsl/__init__.py +0 -0
  21. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/dsl/loader.py +0 -0
  22. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/dsl/parser.py +0 -0
  23. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/dsl_python/__init__.py +0 -0
  24. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/dsl_python/context.py +0 -0
  25. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/dsl_python/decorators.py +0 -0
  26. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/dsl_python/docker_steps.py +0 -0
  27. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/dsl_python/exceptions.py +0 -0
  28. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/dsl_python/runner.py +0 -0
  29. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/dsl_python/steps.py +0 -0
  30. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/fleet.py +0 -0
  31. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/iac/__init__.py +0 -0
  32. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/iac/base.py +0 -0
  33. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/iac/docker_compose.py +0 -0
  34. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/iac/parsers/__init__.py +0 -0
  35. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/iac/parsers/compose.py +0 -0
  36. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/iac/registry.py +0 -0
  37. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/markpact/__init__.py +0 -0
  38. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/markpact/compiler.py +0 -0
  39. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/markpact/models.py +0 -0
  40. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/markpact/parser.py +0 -0
  41. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/observe.py +0 -0
  42. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/parse.py +0 -0
  43. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/patterns.py +0 -0
  44. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/plan/__init__.py +0 -0
  45. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/plan/planner.py +0 -0
  46. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/plugins/__init__.py +0 -0
  47. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/plugins/builtin/__init__.py +0 -0
  48. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/plugins/builtin/browser_reload.py +0 -0
  49. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/plugins/builtin/notify.py +0 -0
  50. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/plugins/builtin/systemd_reload.py +0 -0
  51. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/spec_loader.py +0 -0
  52. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/ssh.py +0 -0
  53. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/steps.py +0 -0
  54. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/tests/__init__.py +0 -0
  55. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/tests/test_audit.py +0 -0
  56. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/tests/test_cli.py +0 -0
  57. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/tests/test_data_sync.py +0 -0
  58. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/tests/test_discovery.py +0 -0
  59. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/tests/test_dsl.py +0 -0
  60. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/tests/test_examples.py +0 -0
  61. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/tests/test_executor.py +0 -0
  62. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/tests/test_fleet.py +0 -0
  63. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/tests/test_git_integration.py +0 -0
  64. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/tests/test_iac.py +0 -0
  65. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/tests/test_manifest.py +0 -0
  66. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/tests/test_markpact_compiler.py +0 -0
  67. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/tests/test_markpact_parser.py +0 -0
  68. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/tests/test_models.py +0 -0
  69. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/tests/test_observe.py +0 -0
  70. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/tests/test_parse.py +0 -0
  71. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/tests/test_patterns.py +0 -0
  72. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/tests/test_planner_edge.py +0 -0
  73. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/tests/test_plugins.py +0 -0
  74. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/tests/test_probes.py +0 -0
  75. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/tests/test_public_api.py +0 -0
  76. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/tests/test_resume.py +0 -0
  77. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/tests/test_spec_loader.py +0 -0
  78. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/tests/test_ssh.py +0 -0
  79. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/tests/test_templates.py +0 -0
  80. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/tests/test_verify.py +0 -0
  81. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/tests/test_version.py +0 -0
  82. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/tests/test_version_changelog.py +0 -0
  83. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/tests/test_version_cli.py +0 -0
  84. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/tests/test_version_manifest.py +0 -0
  85. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/tests/test_version_sources.py +0 -0
  86. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/tests/test_workflow.py +0 -0
  87. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/verify.py +0 -0
  88. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/version/__init__.py +0 -0
  89. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/version/bump.py +0 -0
  90. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/version/changelog.py +0 -0
  91. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/version/commits.py +0 -0
  92. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/version/diff.py +0 -0
  93. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/version/git_integration.py +0 -0
  94. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/version/git_transaction.py +0 -0
  95. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/version/manifest.py +0 -0
  96. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/version/sources/__init__.py +0 -0
  97. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/version/sources/base.py +0 -0
  98. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/version/sources/json_.py +0 -0
  99. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/version/sources/plain.py +0 -0
  100. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/version/sources/regex.py +0 -0
  101. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/version/sources/toml_.py +0 -0
  102. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/version/sources/yaml_.py +0 -0
  103. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/version/transaction.py +0 -0
  104. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy/version.py +0 -0
  105. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy.egg-info/SOURCES.txt +0 -0
  106. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy.egg-info/dependency_links.txt +0 -0
  107. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy.egg-info/entry_points.txt +0 -0
  108. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy.egg-info/requires.txt +0 -0
  109. {redeploy-0.2.18 → redeploy-0.2.19}/redeploy.egg-info/top_level.txt +0 -0
  110. {redeploy-0.2.18 → redeploy-0.2.19}/setup.cfg +0 -0
  111. {redeploy-0.2.18 → redeploy-0.2.19}/tests/test_iac.py +0 -0
  112. {redeploy-0.2.18 → redeploy-0.2.19}/tests/test_parse.py +0 -0
  113. {redeploy-0.2.18 → redeploy-0.2.19}/tests/test_redeploy.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: redeploy
3
- Version: 0.2.18
3
+ Version: 0.2.19
4
4
  Summary: Infrastructure migration toolkit: detect → plan → apply
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
@@ -27,17 +27,17 @@ Requires-Dist: pfix>=0.1.60; extra == "dev"
27
27
 
28
28
  ## AI Cost Tracking
29
29
 
30
- ![PyPI](https://img.shields.io/badge/pypi-costs-blue) ![Version](https://img.shields.io/badge/version-0.2.18-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
31
- ![AI Cost](https://img.shields.io/badge/AI%20Cost-$5.55-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-12.6h-blue) ![Model](https://img.shields.io/badge/Model-openrouter%2Fqwen%2Fqwen3--coder--next-lightgrey)
30
+ ![PyPI](https://img.shields.io/badge/pypi-costs-blue) ![Version](https://img.shields.io/badge/version-0.2.19-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
31
+ ![AI Cost](https://img.shields.io/badge/AI%20Cost-$5.70-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-13.0h-blue) ![Model](https://img.shields.io/badge/Model-openrouter%2Fqwen%2Fqwen3--coder--next-lightgrey)
32
32
 
33
- - 🤖 **LLM usage:** $5.5500 (37 commits)
34
- - 👤 **Human dev:** ~$1255 (12.6h @ $100/h, 30min dedup)
33
+ - 🤖 **LLM usage:** $5.7000 (38 commits)
34
+ - 👤 **Human dev:** ~$1297 (13.0h @ $100/h, 30min dedup)
35
35
 
36
36
  Generated on 2026-04-21 using [openrouter/qwen/qwen3-coder-next](https://openrouter.ai/qwen/qwen3-coder-next)
37
37
 
38
38
  ---
39
39
 
40
- ![PyPI](https://img.shields.io/badge/pypi-redeploy-blue) ![Version](https://img.shields.io/badge/version-0.2.18-blue) ![Python](https://img.shields.io/badge/python-3.10+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
40
+ ![PyPI](https://img.shields.io/badge/pypi-redeploy-blue) ![Version](https://img.shields.io/badge/version-0.2.19-blue) ![Python](https://img.shields.io/badge/python-3.10+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
41
41
 
42
42
  Infrastructure migration and device deploy toolkit — VPS, Raspberry Pi kiosk, Podman Quadlet, k3s.
43
43
 
@@ -3,17 +3,17 @@
3
3
 
4
4
  ## AI Cost Tracking
5
5
 
6
- ![PyPI](https://img.shields.io/badge/pypi-costs-blue) ![Version](https://img.shields.io/badge/version-0.2.18-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
7
- ![AI Cost](https://img.shields.io/badge/AI%20Cost-$5.55-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-12.6h-blue) ![Model](https://img.shields.io/badge/Model-openrouter%2Fqwen%2Fqwen3--coder--next-lightgrey)
6
+ ![PyPI](https://img.shields.io/badge/pypi-costs-blue) ![Version](https://img.shields.io/badge/version-0.2.19-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
7
+ ![AI Cost](https://img.shields.io/badge/AI%20Cost-$5.70-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-13.0h-blue) ![Model](https://img.shields.io/badge/Model-openrouter%2Fqwen%2Fqwen3--coder--next-lightgrey)
8
8
 
9
- - 🤖 **LLM usage:** $5.5500 (37 commits)
10
- - 👤 **Human dev:** ~$1255 (12.6h @ $100/h, 30min dedup)
9
+ - 🤖 **LLM usage:** $5.7000 (38 commits)
10
+ - 👤 **Human dev:** ~$1297 (13.0h @ $100/h, 30min dedup)
11
11
 
12
12
  Generated on 2026-04-21 using [openrouter/qwen/qwen3-coder-next](https://openrouter.ai/qwen/qwen3-coder-next)
13
13
 
14
14
  ---
15
15
 
16
- ![PyPI](https://img.shields.io/badge/pypi-redeploy-blue) ![Version](https://img.shields.io/badge/version-0.2.18-blue) ![Python](https://img.shields.io/badge/python-3.10+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
16
+ ![PyPI](https://img.shields.io/badge/pypi-redeploy-blue) ![Version](https://img.shields.io/badge/version-0.2.19-blue) ![Python](https://img.shields.io/badge/python-3.10+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
17
17
 
18
18
  Infrastructure migration and device deploy toolkit — VPS, Raspberry Pi kiosk, Podman Quadlet, k3s.
19
19
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "redeploy"
7
- version = "0.2.18"
7
+ version = "0.2.19"
8
8
  description = "Infrastructure migration toolkit: detect → plan → apply"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -7,7 +7,7 @@ Public API (stable from 0.2.0, semver guaranteed)::
7
7
 
8
8
  Everything not listed in ``__all__`` is internal and may change without notice.
9
9
  """
10
- __version__ = "0.2.18"
10
+ __version__ = "0.2.19"
11
11
 
12
12
  # ── Core models ───────────────────────────────────────────────────────────────
13
13
  from .models import ( # noqa: F401
@@ -296,6 +296,7 @@ class Executor:
296
296
  StepAction.DOCKER_BUILD: self._run_docker_build,
297
297
  StepAction.DOCKER_HEALTH_WAIT: self._run_docker_health_wait,
298
298
  StepAction.CONTAINER_LOG_TAIL: self._run_container_log_tail,
299
+ StepAction.PODMAN_BUILD: self._run_podman_build,
299
300
  StepAction.SSH_CMD: self._run_ssh,
300
301
  StepAction.SCP: self._run_scp,
301
302
  StepAction.RSYNC: self._run_rsync,
@@ -403,6 +404,54 @@ class Executor:
403
404
  logger.debug(f" build completed in {elapsed + poll_interval}s")
404
405
  step.status = StepStatus.DONE
405
406
 
407
+ def _run_podman_build(self, step: MigrationStep) -> None:
408
+ """Run podman build on remote with periodic progress polling."""
409
+ cmd = step.command
410
+ if not cmd:
411
+ raise StepError(step, "No command specified")
412
+
413
+ timeout = step.timeout or 1800 # 30 min default for ARM64 builds
414
+ poll_interval = 15 # seconds between progress snapshots
415
+ done_event = threading.Event()
416
+ result_holder: list = []
417
+
418
+ def _ssh_build() -> None:
419
+ r = self.probe.run(cmd, timeout=timeout)
420
+ result_holder.append(r)
421
+ done_event.set()
422
+
423
+ thread = threading.Thread(target=_ssh_build, daemon=True)
424
+ thread.start()
425
+
426
+ elapsed = 0
427
+ while not done_event.wait(timeout=poll_interval):
428
+ elapsed += poll_interval
429
+ snap = self.probe.run(
430
+ "podman system df 2>/dev/null | grep -E 'Image|Cache' | "
431
+ "awk '{print $1, $3, $4}'",
432
+ timeout=10,
433
+ )
434
+ if snap.ok and snap.out.strip():
435
+ lines = " | ".join(snap.out.strip().splitlines())
436
+ msg = f"[{elapsed}s] podman cache: {lines}"
437
+ logger.debug(f" {msg}")
438
+ if self._emitter:
439
+ self._emitter.progress(step.id, msg)
440
+ else:
441
+ msg = f"[{elapsed}s] podman build in progress..."
442
+ logger.debug(f" {msg}")
443
+ if self._emitter:
444
+ self._emitter.progress(step.id, msg)
445
+
446
+ if not result_holder:
447
+ raise StepError(step, "Podman build thread did not return a result")
448
+ r = result_holder[0]
449
+ step.result = r.out[:500]
450
+ if not r.ok:
451
+ raise StepError(step, f"exit={r.exit_code}: {r.stderr[:300]}")
452
+ logger.debug(f" podman build completed in {elapsed + poll_interval}s")
453
+ step.status = StepStatus.DONE
454
+
406
455
  def _run_docker_health_wait(self, step: MigrationStep) -> None:
407
456
  """Wait until all containers reach 'healthy' or 'running' status.
408
457