py-wlcli 0.8.0__py3-none-any.whl

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 (320) hide show
  1. py_wlcli-0.8.0.dist-info/METADATA +139 -0
  2. py_wlcli-0.8.0.dist-info/RECORD +320 -0
  3. py_wlcli-0.8.0.dist-info/WHEEL +4 -0
  4. py_wlcli-0.8.0.dist-info/entry_points.txt +2 -0
  5. py_wlcli-0.8.0.dist-info/licenses/LICENSE +21 -0
  6. wl_cli/__init__.py +27 -0
  7. wl_cli/__main__.py +130 -0
  8. wl_cli/capabilities.py +79 -0
  9. wl_cli/cc/__init__.py +5 -0
  10. wl_cli/cc/checks.py +1019 -0
  11. wl_cli/cc/cli.py +370 -0
  12. wl_cli/cc/mutate.py +1350 -0
  13. wl_cli/cli_click.py +156 -0
  14. wl_cli/commands/__init__.py +84 -0
  15. wl_cli/commands/base.py +80 -0
  16. wl_cli/commands/buildcommands/__init__.py +1 -0
  17. wl_cli/commands/buildcommands/build.py +71 -0
  18. wl_cli/commands/buildcommands/build_utils.py +47 -0
  19. wl_cli/commands/buildcommands/builders/__init__.py +18 -0
  20. wl_cli/commands/buildcommands/builders/cleanup.py +35 -0
  21. wl_cli/commands/buildcommands/builders/coordinator.py +122 -0
  22. wl_cli/commands/buildcommands/builders/environment.py +81 -0
  23. wl_cli/commands/buildcommands/builders/rust_builder.py +39 -0
  24. wl_cli/commands/buildcommands/builders/stubs.py +58 -0
  25. wl_cli/commands/buildcommands/dist.py +326 -0
  26. wl_cli/commands/buildcommands/test.py +89 -0
  27. wl_cli/commands/clean/__init__.py +1 -0
  28. wl_cli/commands/clean/build.py +151 -0
  29. wl_cli/commands/clean/clean.py +294 -0
  30. wl_cli/commands/clean/clean_utils.py +77 -0
  31. wl_cli/commands/clean/core.py +236 -0
  32. wl_cli/commands/clean/dead_code/__init__.py +0 -0
  33. wl_cli/commands/clean/dead_code/dead_code_command.py +70 -0
  34. wl_cli/commands/clean/dead_code/detector.py +161 -0
  35. wl_cli/commands/clean/dead_code/fixer.py +176 -0
  36. wl_cli/commands/clean/dead_code/reporter.py +295 -0
  37. wl_cli/commands/clean/dead_code/utils.py +0 -0
  38. wl_cli/commands/clean/lfs.py +215 -0
  39. wl_cli/commands/clean/python.py +81 -0
  40. wl_cli/commands/clean/rust.py +91 -0
  41. wl_cli/commands/clean/utils/__init__.py +34 -0
  42. wl_cli/commands/clean/venv.py +91 -0
  43. wl_cli/commands/cleanup.py +73 -0
  44. wl_cli/commands/click_base.py +79 -0
  45. wl_cli/commands/config/__init__.py +1 -0
  46. wl_cli/commands/config/config.py +291 -0
  47. wl_cli/commands/debug/__init__.py +6 -0
  48. wl_cli/commands/debug/debug.py +309 -0
  49. wl_cli/commands/debug/debug_cache.py +86 -0
  50. wl_cli/commands/debug/debug_subagent.py +156 -0
  51. wl_cli/commands/debug/output_formatter.py +165 -0
  52. wl_cli/commands/debug/source_hasher.py +92 -0
  53. wl_cli/commands/format/__init__.py +13 -0
  54. wl_cli/commands/format/format_cache_adapter.py +125 -0
  55. wl_cli/commands/format/format_command.py +197 -0
  56. wl_cli/commands/format/format_coordinator.py +191 -0
  57. wl_cli/commands/format/format_executor.py +470 -0
  58. wl_cli/commands/format/format_outcome.py +44 -0
  59. wl_cli/commands/format/format_path_handler.py +1016 -0
  60. wl_cli/commands/format/format_progress.py +62 -0
  61. wl_cli/commands/format/format_reporter.py +31 -0
  62. wl_cli/commands/format/python_formatter.py +506 -0
  63. wl_cli/commands/format/rust_formatter.py +106 -0
  64. wl_cli/commands/gate/__init__.py +1 -0
  65. wl_cli/commands/gate/gate_command.py +862 -0
  66. wl_cli/commands/gate/preflight.py +445 -0
  67. wl_cli/commands/git/__init__.py +1 -0
  68. wl_cli/commands/git/config.py +169 -0
  69. wl_cli/commands/git/git_facts.py +60 -0
  70. wl_cli/commands/git/git_flow.py +86 -0
  71. wl_cli/commands/git/hook.py +112 -0
  72. wl_cli/commands/git/policy.py +216 -0
  73. wl_cli/commands/git/push_update.py +82 -0
  74. wl_cli/commands/initenv/__init__.py +1 -0
  75. wl_cli/commands/initenv/common/__init__.py +23 -0
  76. wl_cli/commands/initenv/common/check_git_bash.py +78 -0
  77. wl_cli/commands/initenv/common/error_handler.py +68 -0
  78. wl_cli/commands/initenv/common/exceptions.py +52 -0
  79. wl_cli/commands/initenv/components/__init__.py +4 -0
  80. wl_cli/commands/initenv/components/cargo_sync.py +240 -0
  81. wl_cli/commands/initenv/components/config_manager.py +106 -0
  82. wl_cli/commands/initenv/components/directory_utils.py +71 -0
  83. wl_cli/commands/initenv/components/git/__init__.py +9 -0
  84. wl_cli/commands/initenv/components/git/branch_creator.py +143 -0
  85. wl_cli/commands/initenv/components/git/git_flow_interface.py +24 -0
  86. wl_cli/commands/initenv/components/git/git_flow_manager.py +159 -0
  87. wl_cli/commands/initenv/components/git/git_lfs_manager.py +272 -0
  88. wl_cli/commands/initenv/components/git/git_utility.py +254 -0
  89. wl_cli/commands/initenv/components/git/gitignore_manager.py +53 -0
  90. wl_cli/commands/initenv/components/git_initializer.py +212 -0
  91. wl_cli/commands/initenv/components/i18n_manager.py +104 -0
  92. wl_cli/commands/initenv/components/log_manager.py +241 -0
  93. wl_cli/commands/initenv/components/project_structure/__init__.py +23 -0
  94. wl_cli/commands/initenv/components/project_structure/config_generator.py +360 -0
  95. wl_cli/commands/initenv/components/project_structure/directory_creator.py +184 -0
  96. wl_cli/commands/initenv/components/project_structure/hook_source.py +110 -0
  97. wl_cli/commands/initenv/components/project_structure/hooks_manager.py +995 -0
  98. wl_cli/commands/initenv/components/project_structure/readme_handler.py +56 -0
  99. wl_cli/commands/initenv/components/project_structure/rust_files_handler.py +30 -0
  100. wl_cli/commands/initenv/components/project_structure/setup_handler.py +103 -0
  101. wl_cli/commands/initenv/components/project_structure/sop_generator.py +73 -0
  102. wl_cli/commands/initenv/components/project_structure/template_copier.py +104 -0
  103. wl_cli/commands/initenv/components/project_structure/template_manager.py +195 -0
  104. wl_cli/commands/initenv/components/pyproject_generator.py +194 -0
  105. wl_cli/commands/initenv/components/rust_initializer.py +145 -0
  106. wl_cli/commands/initenv/components/symlink_cleaner.py +99 -0
  107. wl_cli/commands/initenv/components/symlink_manager.py +52 -0
  108. wl_cli/commands/initenv/components/venv_manager.py +118 -0
  109. wl_cli/commands/initenv/initenv.py +169 -0
  110. wl_cli/commands/initenv/services/__init__.py +11 -0
  111. wl_cli/commands/initenv/services/environment_initializer.py +288 -0
  112. wl_cli/commands/initenv/services/git_lfs_initializer.py +26 -0
  113. wl_cli/commands/initenv/services/project_structure_initializer.py +52 -0
  114. wl_cli/commands/lfs/README.md +221 -0
  115. wl_cli/commands/lfs/__init__.py +5 -0
  116. wl_cli/commands/lfs/cli.py +106 -0
  117. wl_cli/commands/lfs/config.py +164 -0
  118. wl_cli/commands/lfs/hook.py +61 -0
  119. wl_cli/commands/lfs/initializer.py +531 -0
  120. wl_cli/commands/lfs/manager.py +95 -0
  121. wl_cli/commands/lfs/policy.py +165 -0
  122. wl_cli/commands/lfs/watcher.py +294 -0
  123. wl_cli/commands/lint/__init__.py +1 -0
  124. wl_cli/commands/lint/lint_command.py +297 -0
  125. wl_cli/commands/lint/lint_executor.py +409 -0
  126. wl_cli/commands/lint/lint_reporter.py +579 -0
  127. wl_cli/commands/lint/lint_run.py +258 -0
  128. wl_cli/commands/lint/mypy_config.py +90 -0
  129. wl_cli/commands/registry.py +103 -0
  130. wl_cli/commands/self/__init__.py +7 -0
  131. wl_cli/commands/self/common/__init__.py +8 -0
  132. wl_cli/commands/self/common/capabilities.py +30 -0
  133. wl_cli/commands/self/common/config.py +27 -0
  134. wl_cli/commands/self/common/version_cache.py +85 -0
  135. wl_cli/commands/self/handlers/__init__.py +19 -0
  136. wl_cli/commands/self/handlers/base_handler.py +28 -0
  137. wl_cli/commands/self/handlers/install_handler.py +85 -0
  138. wl_cli/commands/self/handlers/status_handler.py +66 -0
  139. wl_cli/commands/self/handlers/uninstall_handler.py +58 -0
  140. wl_cli/commands/self/handlers/update_handler.py +102 -0
  141. wl_cli/commands/self/handlers/version_handler.py +16 -0
  142. wl_cli/commands/self/self_command.py +237 -0
  143. wl_cli/commands/self/services/__init__.py +15 -0
  144. wl_cli/commands/self/services/installation_manager.py +187 -0
  145. wl_cli/commands/self/services/local_installer.py +165 -0
  146. wl_cli/commands/self/services/pypi_updater.py +278 -0
  147. wl_cli/commands/self/services/windows_update.py +174 -0
  148. wl_cli/commands/testcommands/__init__.py +8 -0
  149. wl_cli/commands/testcommands/base_dependency_analyzer.py +198 -0
  150. wl_cli/commands/testcommands/batch_processor.py +278 -0
  151. wl_cli/commands/testcommands/cache_manager.py +1156 -0
  152. wl_cli/commands/testcommands/coverage_analyzer.py +955 -0
  153. wl_cli/commands/testcommands/coverage_cache_manager.py +183 -0
  154. wl_cli/commands/testcommands/progress_manager.py +79 -0
  155. wl_cli/commands/testcommands/python_env_detector.py +207 -0
  156. wl_cli/commands/testcommands/report_generator.py +101 -0
  157. wl_cli/commands/testcommands/single_test_executor.py +250 -0
  158. wl_cli/commands/testcommands/speed_checker.py +118 -0
  159. wl_cli/commands/testcommands/test_command_builder.py +165 -0
  160. wl_cli/commands/testcommands/test_commands.py +786 -0
  161. wl_cli/commands/testcommands/test_reporter.py +181 -0
  162. wl_cli/commands/testcommands/test_result_handler.py +96 -0
  163. wl_cli/commands/testcommands/test_runner.py +1343 -0
  164. wl_cli/commands/testcommands/test_utils.py +197 -0
  165. wl_cli/commands/testcommands/utils/__init__.py +17 -0
  166. wl_cli/commands/testcommands/utils/coverage_parser.py +98 -0
  167. wl_cli/commands/testcommands/utils/env_info.py +36 -0
  168. wl_cli/commands/testcommands/utils/junit_parser.py +75 -0
  169. wl_cli/commands/testcommands/utils/markdown_utils.py +20 -0
  170. wl_cli/commands/testcommands/utils/project_root.py +61 -0
  171. wl_cli/commands/update/__init__.py +9 -0
  172. wl_cli/commands/update/services/__init__.py +21 -0
  173. wl_cli/commands/update/services/backup_manager.py +207 -0
  174. wl_cli/commands/update/services/component_manager.py +83 -0
  175. wl_cli/commands/update/services/conflict_resolver.py +189 -0
  176. wl_cli/commands/update/services/vendors_updater.py +85 -0
  177. wl_cli/commands/update/services/version_tracker.py +127 -0
  178. wl_cli/commands/update/update_command.py +270 -0
  179. wl_cli/commands/update/utils/__init__.py +3 -0
  180. wl_cli/commands/version/__init__.py +9 -0
  181. wl_cli/commands/version/version_command.py +155 -0
  182. wl_cli/commands/workflow.py +477 -0
  183. wl_cli/env/__init__.py +5 -0
  184. wl_cli/env/cli.py +167 -0
  185. wl_cli/env_status.py +157 -0
  186. wl_cli/envelope.py +91 -0
  187. wl_cli/exceptions.py +85 -0
  188. wl_cli/lib/__init__.py +3 -0
  189. wl_cli/lib/rust_utils.py +35 -0
  190. wl_cli/mcp/__init__.py +6 -0
  191. wl_cli/mcp/capabilities.py +19 -0
  192. wl_cli/mcp/cli.py +22 -0
  193. wl_cli/mcp/gitlab.py +553 -0
  194. wl_cli/mcp/k8s.py +344 -0
  195. wl_cli/mcp/protocol.py +159 -0
  196. wl_cli/platform.py +139 -0
  197. wl_cli/quality/__init__.py +18 -0
  198. wl_cli/utils/__init__.py +7 -0
  199. wl_cli/utils/cache.py +491 -0
  200. wl_cli/utils/cache_ledger.py +355 -0
  201. wl_cli/utils/cache_store.py +546 -0
  202. wl_cli/utils/config/__init__.py +27 -0
  203. wl_cli/utils/config/config_loader.py +163 -0
  204. wl_cli/utils/config/core.py +862 -0
  205. wl_cli/utils/config/defaults.py +142 -0
  206. wl_cli/utils/config/env_exporter.py +86 -0
  207. wl_cli/utils/config/env_parser.py +108 -0
  208. wl_cli/utils/config/validation.py +280 -0
  209. wl_cli/utils/error_handler.py +165 -0
  210. wl_cli/utils/file_copier.py +56 -0
  211. wl_cli/utils/file_operations.py +506 -0
  212. wl_cli/utils/language_utils.py +122 -0
  213. wl_cli/utils/lazy_import.py +240 -0
  214. wl_cli/utils/log_levels.py +35 -0
  215. wl_cli/utils/log_rotators.py +74 -0
  216. wl_cli/utils/logging.py +458 -0
  217. wl_cli/utils/output_context.py +142 -0
  218. wl_cli/utils/performance/__init__.py +1 -0
  219. wl_cli/utils/performance/decorators.py +111 -0
  220. wl_cli/utils/performance/exporter.py +38 -0
  221. wl_cli/utils/performance/models.py +16 -0
  222. wl_cli/utils/performance/monitor.py +161 -0
  223. wl_cli/utils/performance_monitor.py +32 -0
  224. wl_cli/utils/platform_adapter.py +131 -0
  225. wl_cli/utils/pre_commit.py +266 -0
  226. wl_cli/utils/pre_commit_config.py +72 -0
  227. wl_cli/utils/root.py +521 -0
  228. wl_cli/utils/root_fallback.py +256 -0
  229. wl_cli/utils/run_evidence.py +236 -0
  230. wl_cli/utils/structured_logger.py +18 -0
  231. wl_cli/utils/structured_logging/__init__.py +19 -0
  232. wl_cli/utils/structured_logging/config.py +337 -0
  233. wl_cli/utils/structured_logging/core.py +177 -0
  234. wl_cli/utils/structured_logging/env.py +56 -0
  235. wl_cli/utils/structured_logging/filtering.py +75 -0
  236. wl_cli/utils/structured_logging/filters.py +55 -0
  237. wl_cli/utils/structured_logging/formatters.py +251 -0
  238. wl_cli/utils/structured_logging/handlers.py +308 -0
  239. wl_cli/utils/structured_logging/logger.py +354 -0
  240. wl_cli/utils/subprocess.py +71 -0
  241. wl_cli/utils/subprocess_utils.py +260 -0
  242. wl_cli/utils/test_utils/__init__.py +5 -0
  243. wl_cli/utils/test_utils/test_filter.py +36 -0
  244. wl_cli/utils/uv_run.py +79 -0
  245. wl_cli/utils/uv_tool.py +117 -0
  246. wl_cli/utils/uv_tree.py +71 -0
  247. wl_cli/utils/uv_workspace.py +174 -0
  248. wl_cli/utils/version/__init__.py +15 -0
  249. wl_cli/utils/version/pypi_version_checker.py +95 -0
  250. wl_cli/utils/version/version_comparator.py +133 -0
  251. wl_cli/utils/version/version_detectors.py +312 -0
  252. wl_cli/utils/version/version_service.py +131 -0
  253. wl_cli/utils/version/version_updater.py +198 -0
  254. wl_cli/utils/wl_dir_updater.py +1440 -0
  255. wl_cli/utils/workspace_detector/__init__.py +28 -0
  256. wl_cli/utils/workspace_detector/core.py +161 -0
  257. wl_cli/utils/workspace_detector/detection_strategies.py +107 -0
  258. wl_cli/utils/workspace_detector/exceptions.py +5 -0
  259. wl_cli/utils/workspace_detector/types.py +17 -0
  260. wl_cli/utils/workspace_detector/venv_resolver.py +84 -0
  261. wl_cli/vendors/config/.codespellrc +2 -0
  262. wl_cli/vendors/config/dependencies.toml +10 -0
  263. wl_cli/vendors/config/mypy.ini +62 -0
  264. wl_cli/vendors/config/pyproject_defaults.toml +28 -0
  265. wl_cli/vendors/config/template_config.toml +24 -0
  266. wl_cli/vendors/config/tool_configs.toml +76 -0
  267. wl_cli/vendors/git/.gitignore +122 -0
  268. wl_cli/vendors/git/.pre-commit-config.yaml +37 -0
  269. wl_cli/vendors/hooks/applypatch-msg.sample +15 -0
  270. wl_cli/vendors/hooks/commit-msg.sample +24 -0
  271. wl_cli/vendors/hooks/fsmonitor-watchman.sample +174 -0
  272. wl_cli/vendors/hooks/post-update.sample +8 -0
  273. wl_cli/vendors/hooks/pre-applypatch.sample +14 -0
  274. wl_cli/vendors/hooks/pre-commit +45 -0
  275. wl_cli/vendors/hooks/pre-commit.legacy +31 -0
  276. wl_cli/vendors/hooks/pre-commit.sample +49 -0
  277. wl_cli/vendors/hooks/pre-merge-commit.sample +13 -0
  278. wl_cli/vendors/hooks/pre-push.sample +60 -0
  279. wl_cli/vendors/hooks/pre-rebase.sample +169 -0
  280. wl_cli/vendors/hooks/pre-receive.sample +24 -0
  281. wl_cli/vendors/hooks/prepare-commit-msg.sample +42 -0
  282. wl_cli/vendors/hooks/push-to-checkout.sample +78 -0
  283. wl_cli/vendors/hooks/sendemail-validate.sample +77 -0
  284. wl_cli/vendors/hooks/unix/applypatch-msg.sample +15 -0
  285. wl_cli/vendors/hooks/unix/check_lockfile.py +58 -0
  286. wl_cli/vendors/hooks/unix/check_lockfile.sh +36 -0
  287. wl_cli/vendors/hooks/unix/commit-msg.sample +24 -0
  288. wl_cli/vendors/hooks/unix/fsmonitor-watchman.sample +174 -0
  289. wl_cli/vendors/hooks/unix/post-update.sample +8 -0
  290. wl_cli/vendors/hooks/unix/pre-applypatch.sample +14 -0
  291. wl_cli/vendors/hooks/unix/pre-commit +190 -0
  292. wl_cli/vendors/hooks/unix/pre-commit.legacy +31 -0
  293. wl_cli/vendors/hooks/unix/pre-commit.py +81 -0
  294. wl_cli/vendors/hooks/unix/pre-commit.sample +49 -0
  295. wl_cli/vendors/hooks/unix/pre-merge-commit.sample +13 -0
  296. wl_cli/vendors/hooks/unix/pre-push +417 -0
  297. wl_cli/vendors/hooks/unix/pre-push.sample +53 -0
  298. wl_cli/vendors/hooks/unix/pre-rebase.sample +169 -0
  299. wl_cli/vendors/hooks/unix/pre-receive.sample +24 -0
  300. wl_cli/vendors/hooks/unix/prepare-commit-msg.sample +42 -0
  301. wl_cli/vendors/hooks/update.sample +128 -0
  302. wl_cli/vendors/hooks/win/work.bat +63 -0
  303. wl_cli/vendors/project/.gitignore +90 -0
  304. wl_cli/vendors/project/.python-version +1 -0
  305. wl_cli/vendors/project/LICENSE +21 -0
  306. wl_cli/vendors/project/README.md +0 -0
  307. wl_cli/vendors/project/pyproject.toml +27 -0
  308. wl_cli/vendors/project/pyproject_no_workspace.toml +16 -0
  309. wl_cli/vendors/project/pyproject_workspace.toml +14 -0
  310. wl_cli/vendors/readme/README.md +120 -0
  311. wl_cli/vendors/rust/Cargo.toml +14 -0
  312. wl_cli/vendors/rust/lib/__init__.py +3 -0
  313. wl_cli/vendors/rust/lib/rust_utils.py +31 -0
  314. wl_cli/vendors/rust/src/lib.rs +13 -0
  315. wl_cli/vendors/rust/src/main.rs +3 -0
  316. wl_cli/vendors/rust/tests/test_rust_fallback.py +40 -0
  317. wl_cli/vendors/sop_doc/git-dev-sop.md +220 -0
  318. wl_cli/vendors/sop_doc/industrial-standard-sop.md +145 -0
  319. wl_cli/vendors/sop_doc/python-sop.md +342 -0
  320. wl_cli/vendors/sop_doc/rust-readme.md +219 -0
wl_cli/cli_click.py ADDED
@@ -0,0 +1,156 @@
1
+ #!/usr/bin/env python3
2
+ """Command line interface entry point based on Click."""
3
+
4
+ import importlib
5
+ import sys
6
+
7
+ import click
8
+
9
+ from . import __version__
10
+ from .commands.registry import COMMAND_TABLE
11
+ from .utils.logging import log_error
12
+ from .utils.wl_dir_updater import check_and_update_wl_dir
13
+
14
+ #: Command prefixes that own their stdout stream (JSON / JSON-RPC).
15
+ #: The startup ``.wl`` self-sync logs INFO lines on stdout, which would corrupt
16
+ #: those payloads, so the dispatcher skips the sync for these commands (#220).
17
+ #: The ``cc`` write commands are listed individually: ``cc init --json`` and
18
+ #: friends emit one envelope line just like ``cc check`` (#223).
19
+ _SYNC_SKIP_PREFIXES: tuple[tuple[str, ...], ...] = (
20
+ ("env", "check"),
21
+ ("cc", "check"),
22
+ ("cc", "init"),
23
+ ("cc", "repair"),
24
+ ("cc", "upgrade"),
25
+ ("cc", "plugins"),
26
+ ("cc", "mcp"),
27
+ ("cc", "settings"),
28
+ ("cc", "statusline"),
29
+ ("cc", "hooks"),
30
+ ("cc", "stamps"),
31
+ ("self", "capabilities"),
32
+ ("mcp", "serve"),
33
+ )
34
+
35
+ #: Raw argv of the current :func:`main` invocation. Click resolves and consumes
36
+ #: the subcommand tokens before the group callback runs (``ctx.args`` is empty),
37
+ #: so ``main`` records them here for :func:`should_skip_wl_sync`. Direct ``wl``
38
+ #: invocations (tests) leave this empty, which means "run the sync".
39
+ _INVOCATION_ARGV: list[str] = []
40
+
41
+
42
+ def should_skip_wl_sync(argv: list[str]) -> bool:
43
+ """Return True when the startup ``.wl`` self-sync must be skipped.
44
+
45
+ Read-only commands that emit machine-readable output on stdout
46
+ (``wl env check --json``, ``wl self capabilities``, ``wl mcp serve``)
47
+ cannot tolerate the sync's INFO logging on the same stream. This is a
48
+ pure argv predicate: no command business logic belongs here.
49
+
50
+ Args:
51
+ argv: Raw argv handed to ``wl``, without the program name.
52
+
53
+ Returns:
54
+ True if ``argv`` starts with one of the read-only command prefixes.
55
+ """
56
+ return any(tuple(argv[: len(prefix)]) == prefix for prefix in _SYNC_SKIP_PREFIXES)
57
+
58
+
59
+ @click.group(
60
+ invoke_without_command=True,
61
+ context_settings={"help_option_names": ["-h", "--help"]},
62
+ )
63
+ @click.option("--version", "-v", is_flag=True, help="Show version information")
64
+ def wl(version):
65
+ """WL Commands - A command-line tool for project management."""
66
+ ctx = click.get_current_context()
67
+
68
+ if version:
69
+ click.echo(f"wl {__version__}")
70
+ ctx.exit(0)
71
+
72
+ if not should_skip_wl_sync(_INVOCATION_ARGV):
73
+ check_and_update_wl_dir()
74
+
75
+ if ctx.invoked_subcommand is None:
76
+ click.echo(ctx.get_help())
77
+
78
+
79
+ def _register_click_command(
80
+ name: str, click_func, aliases: list[str] | None = None
81
+ ) -> None:
82
+ """Register a Click command function with the wl group.
83
+
84
+ Aliases register the *same* Click object under a second name (Click keeps
85
+ the object's own ``name`` untouched), so an alias accepts exactly the
86
+ canonical command's options, arguments and subcommands. A zero-option
87
+ wrapper shell would reject every parameter an alias was given (#194).
88
+
89
+ Args:
90
+ name: Command name
91
+ click_func: Click command function
92
+ aliases: List of command aliases
93
+ """
94
+ wl.add_command(click_func, name=name)
95
+ for alias in aliases or ():
96
+ wl.add_command(click_func, name=alias)
97
+
98
+
99
+ def setup_commands():
100
+ """Register every command on the ``wl`` group from COMMAND_TABLE.
101
+
102
+ Each module in the table is imported exactly once; the symbol named by the
103
+ spec is fetched and, when the spec asks for it, instantiated. The command is
104
+ then registered under its canonical name plus any live aliases.
105
+ """
106
+ try:
107
+ if not hasattr(wl, "_commands_setup") or not wl._commands_setup:
108
+ for name, spec in COMMAND_TABLE.items():
109
+ module = importlib.import_module(f"{spec.package}.{spec.module_path}")
110
+ click_func = getattr(module, spec.symbol)
111
+ if spec.instantiate:
112
+ click_func = click_func()
113
+ _register_click_command(name, click_func, aliases=list(spec.aliases))
114
+
115
+ wl._commands_setup = True
116
+ except Exception as e:
117
+ log_error(f"Error setting up commands: {e}")
118
+ raise
119
+
120
+
121
+ def main(argv: list[str] | None = None) -> int:
122
+ """Main entry point for the CLI.
123
+
124
+ Args:
125
+ argv: Command line arguments
126
+
127
+ Returns:
128
+ int: Exit code, 0 for success, 1 for failure
129
+ """
130
+ global _INVOCATION_ARGV
131
+
132
+ if argv is None:
133
+ argv = sys.argv[1:]
134
+
135
+ if argv and (argv[0] == "--version" or argv[0] == "-v"):
136
+ click.echo(f"wl {__version__}")
137
+ raise SystemExit(0)
138
+
139
+ _INVOCATION_ARGV = list(argv)
140
+ try:
141
+ setup_commands()
142
+ wl.main(args=argv, standalone_mode=True)
143
+ return 0
144
+ except click.ClickException as e:
145
+ log_error(str(e))
146
+ return 1
147
+ except Exception as e:
148
+ log_error(str(e))
149
+ return 1
150
+ finally:
151
+ # Never leak one invocation's argv into a later in-process invocation.
152
+ _INVOCATION_ARGV = []
153
+
154
+
155
+ if __name__ == "__main__":
156
+ sys.exit(main())
@@ -0,0 +1,84 @@
1
+ """Command registration and management module."""
2
+
3
+ import functools
4
+ from collections.abc import Callable
5
+ from typing import Any
6
+
7
+ from ..exceptions import ErrorCode
8
+ from .base import CommandBase
9
+ from .registry import get_command, list_commands
10
+
11
+
12
+ class Command(CommandBase):
13
+ """
14
+ Base class for all commands.
15
+ """
16
+
17
+ def __init__(self, **dependencies: Any) -> None:
18
+ super().__init__(**dependencies)
19
+
20
+ @property
21
+ def name(self) -> str:
22
+ """
23
+ Get the command name.
24
+
25
+ Returns:
26
+ str: The command name
27
+ """
28
+ raise NotImplementedError("Command subclasses must implement name property")
29
+
30
+ @property
31
+ def help(self) -> str:
32
+ """
33
+ Get the command help text.
34
+
35
+ Returns:
36
+ str: The command help text
37
+ """
38
+ raise NotImplementedError("Command subclasses must implement help property")
39
+
40
+ def execute(self, *_: Any, **kwargs: Any) -> Any:
41
+ """
42
+ Execute the command.
43
+
44
+ Args:
45
+ *args: Positional arguments
46
+ **kwargs: Keyword arguments
47
+ """
48
+ raise NotImplementedError("Command subclasses must implement execute method")
49
+
50
+
51
+ def validate_command_args(**validators: Callable[[Any], bool]) -> Callable:
52
+ """
53
+ Decorator to validate command arguments.
54
+
55
+ Args:
56
+ **validators: A dictionary of argument names and validation functions
57
+
58
+ Returns:
59
+ Callable: The decorator function
60
+ """
61
+
62
+ def decorator(func: Callable) -> Callable:
63
+ @functools.wraps(func)
64
+ def wrapper(*args: Any, **kwargs: Any) -> Any:
65
+ for arg_name, validator in validators.items():
66
+ if arg_name in kwargs:
67
+ if not validator(kwargs[arg_name]):
68
+ raise ValueError(f"Invalid value for {arg_name}")
69
+
70
+ return func(*args, **kwargs)
71
+
72
+ return wrapper
73
+
74
+ return decorator
75
+
76
+
77
+ __all__ = [
78
+ "Command",
79
+ "CommandBase",
80
+ "ErrorCode",
81
+ "get_command",
82
+ "list_commands",
83
+ "validate_command_args",
84
+ ]
@@ -0,0 +1,80 @@
1
+ """Unified command base class for WL Commands."""
2
+
3
+ from abc import ABC, abstractmethod
4
+ from typing import Any
5
+
6
+
7
+ class CommandBase(ABC):
8
+ """
9
+ Abstract base class for all commands, providing lifecycle and logging utilities.
10
+ """
11
+
12
+ def __init__(self, **dependencies: Any) -> None:
13
+ """Initialize the command with dependencies.
14
+
15
+ Args:
16
+ **dependencies: Dependencies for the command
17
+ """
18
+ self._dependencies = dependencies
19
+
20
+ @property
21
+ @abstractmethod
22
+ def name(self) -> str:
23
+ """Get the command name."""
24
+ pass
25
+
26
+ @property
27
+ @abstractmethod
28
+ def help(self) -> str:
29
+ """Get the command help text."""
30
+ pass
31
+
32
+ @abstractmethod
33
+ def execute(self, *_: Any, **kwargs: Any) -> Any:
34
+ """Execute the command."""
35
+ pass
36
+
37
+ def before_execute(self, *args: Any, **kwargs: Any) -> None:
38
+ """Lifecycle hook called before execution."""
39
+ return None
40
+
41
+ def after_execute(self, result: Any = None) -> None:
42
+ """Lifecycle hook called after execution."""
43
+ return None
44
+
45
+ def run(self, *args: Any, **kwargs: Any) -> Any:
46
+ """Run with lifecycle and error handling around execute."""
47
+ try:
48
+ # Validate arguments and use the validated kwargs
49
+ validated_kwargs = self.validate_args(**kwargs)
50
+ self.before_execute(*args, **validated_kwargs)
51
+ result = self.execute(*args, **validated_kwargs)
52
+ self.after_execute(result)
53
+ return result
54
+ except Exception as error:
55
+ self.handle_error(error)
56
+ raise
57
+
58
+ def validate_args(self, **kwargs: Any) -> dict[str, Any]:
59
+ """Validate command arguments."""
60
+ return kwargs
61
+
62
+ def handle_error(self, error: Exception) -> None:
63
+ """Default error handler; override for custom behavior."""
64
+ raise error
65
+
66
+ def log_info(self, en_msg: str, zh_msg: str | None = None) -> None:
67
+ """Log messages in English and optionally Chinese."""
68
+ try:
69
+ from wl_cli.utils.logging import log_info
70
+
71
+ log_info(en_msg, lang="en")
72
+ if zh_msg is not None:
73
+ log_info(zh_msg, lang="zh")
74
+ except Exception:
75
+ # Logging utility may not be available in certain contexts; ignore
76
+ pass
77
+
78
+
79
+ # Backward compatibility alias
80
+ BaseCommand = CommandBase
@@ -0,0 +1 @@
1
+ """Build commands package (registered lazily via COMMAND_TABLE)."""
@@ -0,0 +1,71 @@
1
+ """Build command for WL Commands."""
2
+
3
+ from typing import Any
4
+
5
+ import click
6
+
7
+ from .. import Command
8
+ from .build_utils import build_project, build_project_full
9
+
10
+
11
+ class BuildCommand(Command):
12
+ """Command to build the project"""
13
+
14
+ @property
15
+ def name(self) -> str:
16
+ """Return command name"""
17
+ return "build"
18
+
19
+ @property
20
+ def help(self) -> str:
21
+ """Get command help text"""
22
+ return "Build the project"
23
+
24
+ def execute(self, *_: Any, **kwargs: Any) -> None:
25
+ """Execute the build command."""
26
+ unknown_args = kwargs.get("unknown_args", [])
27
+ if unknown_args and unknown_args[0] == "dist":
28
+ build_project_full()
29
+ else:
30
+ build_project()
31
+
32
+
33
+ class BuildCommandImpl:
34
+ """Implementation of the build command."""
35
+
36
+ @property
37
+ def name(self) -> str:
38
+ return "build"
39
+
40
+ @property
41
+ def help(self) -> str:
42
+ return "Build the project"
43
+
44
+ @property
45
+ def aliases(self) -> list[str]:
46
+ return []
47
+
48
+ def execute(self, dist: bool = False) -> None:
49
+ """Execute the build command.
50
+
51
+ Args:
52
+ dist: If True, perform full compilation (build_project_full).
53
+ If False, perform regular build (build_project).
54
+ """
55
+ if dist:
56
+ build_project_full()
57
+ else:
58
+ build_project()
59
+
60
+
61
+ @click.command()
62
+ @click.option(
63
+ "-d",
64
+ "--dist",
65
+ is_flag=True,
66
+ help="Perform full compilation including all outputs",
67
+ )
68
+ def build_command(dist: bool) -> None:
69
+ """Build command Click wrapper."""
70
+ cmd = BuildCommandImpl()
71
+ cmd.execute(dist=dist)
@@ -0,0 +1,47 @@
1
+ """Build utilities for WL Commands.
2
+
3
+ This module serves as the entry point for the modularized build functionality.
4
+ 主要功能委托给专门的模块以获得更好的组织结构。
5
+ """
6
+
7
+ from .builders.cleanup import CleanupManager
8
+ from .builders.coordinator import BuildCoordinator
9
+ from .builders.environment import EnvironmentDetector
10
+ from .builders.rust_builder import RustBuilder
11
+ from .builders.stubs import StubsManager
12
+
13
+
14
+ # Backward compatibility: re-export all the main functions
15
+ def is_rust_enabled() -> bool:
16
+ """Check if Rust is enabled for this project."""
17
+ return EnvironmentDetector.is_rust_enabled()
18
+
19
+
20
+ def build_project_full() -> None:
21
+ """Perform a full project build."""
22
+ coordinator = BuildCoordinator()
23
+ coordinator.build_project_full()
24
+
25
+
26
+ def build_project() -> None:
27
+ """Build the project based on the current platform."""
28
+ try:
29
+ coordinator = BuildCoordinator()
30
+ coordinator.build_project()
31
+ except Exception as e:
32
+ from wl_cli.exceptions import CommandError
33
+
34
+ raise CommandError(f"Build failed: {e}")
35
+
36
+
37
+ # Re-export classes for advanced usage
38
+ __all__ = [
39
+ "is_rust_enabled",
40
+ "build_project_full",
41
+ "build_project",
42
+ "EnvironmentDetector",
43
+ "StubsManager",
44
+ "RustBuilder",
45
+ "CleanupManager",
46
+ "BuildCoordinator",
47
+ ]
@@ -0,0 +1,18 @@
1
+ """Build command modules for specialized functionality.
2
+
3
+ This package contains modularized build utilities for better code organization.
4
+ """
5
+
6
+ from .cleanup import CleanupManager
7
+ from .coordinator import BuildCoordinator
8
+ from .environment import EnvironmentDetector
9
+ from .rust_builder import RustBuilder
10
+ from .stubs import StubsManager
11
+
12
+ __all__ = [
13
+ "EnvironmentDetector",
14
+ "StubsManager",
15
+ "RustBuilder",
16
+ "CleanupManager",
17
+ "BuildCoordinator",
18
+ ]
@@ -0,0 +1,35 @@
1
+ """Build cleanup utilities."""
2
+
3
+ import shutil
4
+ from pathlib import Path
5
+
6
+ from ....utils.logging import log_error, log_info
7
+
8
+
9
+ class CleanupManager:
10
+ """Handle post-build cleanup operations."""
11
+
12
+ @staticmethod
13
+ def cleanup_after_build(is_workspace: bool) -> None:
14
+ """Clean up temporary files and directories after build."""
15
+ try:
16
+ root = Path.cwd()
17
+ typings_path = root / "typings"
18
+ if typings_path.exists():
19
+ shutil.rmtree(typings_path, ignore_errors=True)
20
+ log_info("✓ typings directory removed")
21
+
22
+ src_path = root / "src"
23
+ if src_path.exists():
24
+ removed = 0
25
+ for p in src_path.rglob("*.pyi"):
26
+ try:
27
+ p.unlink()
28
+ removed += 1
29
+ except Exception:
30
+ pass
31
+ if removed:
32
+ log_info(f"✓ Removed {removed} .pyi files from src")
33
+
34
+ except Exception as e:
35
+ log_error(f"Failed to cleanup stubs: {e}")
@@ -0,0 +1,122 @@
1
+ """Build coordination logic for different platforms and scenarios."""
2
+
3
+ from ....exceptions import CommandError
4
+ from ....utils.logging import (
5
+ log_error_pair,
6
+ log_info,
7
+ log_info_pair,
8
+ )
9
+ from ....utils.subprocess import run_command
10
+ from .cleanup import CleanupManager
11
+ from .environment import EnvironmentDetector
12
+ from .rust_builder import RustBuilder
13
+ from .stubs import StubsManager
14
+
15
+
16
+ class BuildCoordinator:
17
+ """Coordinate build operations across different platforms and scenarios."""
18
+
19
+ def __init__(self):
20
+ self.environment_detector = EnvironmentDetector()
21
+ self.stubs_manager = StubsManager()
22
+ self.rust_builder = RustBuilder()
23
+ self.cleanup_manager = CleanupManager()
24
+
25
+ def build_project_full(self) -> None:
26
+ """Perform a full project build."""
27
+ rust_enabled = self.environment_detector.is_rust_enabled()
28
+
29
+ try:
30
+ if rust_enabled:
31
+ log_info_pair(
32
+ "Using maturin build for full compilation...",
33
+ "使用 maturin build 进行完整编译...",
34
+ )
35
+
36
+ python_executable, is_workspace = (
37
+ self.environment_detector.resolve_python_executable()
38
+ )
39
+ self.stubs_manager.generate_and_copy_stubs()
40
+ self.rust_builder.build_full(python_executable)
41
+ self.cleanup_manager.cleanup_after_build(is_workspace)
42
+ else:
43
+ log_info_pair(
44
+ "Pure Python project, using uv build to generate distribution packages...",
45
+ "纯 Python 项目,使用 uv build 生成分发包...",
46
+ )
47
+ run_command(
48
+ ["uv", "build"],
49
+ capture_output=False,
50
+ )
51
+
52
+ log_info_pair(
53
+ "✓ Full build completed successfully",
54
+ "✓ 完整构建成功完成",
55
+ )
56
+
57
+ # List files in dist directory for verification
58
+ from pathlib import Path
59
+
60
+ dist_dir = Path("dist")
61
+ if dist_dir.exists():
62
+ dist_files = list(dist_dir.iterdir())
63
+ if dist_files:
64
+ log_info_pair(
65
+ "Generated distribution packages in dist directory:",
66
+ "在 dist 目录中生成的分发包:",
67
+ )
68
+ for f in dist_files:
69
+ log_info(f" - {f.name}")
70
+ else:
71
+ log_info_pair(
72
+ "No distribution packages generated in dist directory",
73
+ "在 dist 目录中没有生成分发包",
74
+ )
75
+ except Exception as e:
76
+ log_error_pair(
77
+ f"Full build failed: {e}",
78
+ f"完整构建失败: {e}",
79
+ )
80
+ raise CommandError(f"Full build failed: {e}")
81
+
82
+ def build(self) -> None:
83
+ """Build the project in place, on any platform.
84
+
85
+ The former ``build_windows`` and ``build_unix`` bodies were
86
+ byte-identical, so the platform branch collapsed away.
87
+ """
88
+ rust_enabled = self.environment_detector.is_rust_enabled()
89
+
90
+ try:
91
+ if rust_enabled:
92
+ self.rust_builder.build_incremental()
93
+ else:
94
+ log_info_pair(
95
+ "Pure Python project, using uv pip install -e . for installation...",
96
+ "纯 Python 项目,使用 uv pip install -e . 进行安装...",
97
+ )
98
+ run_command(
99
+ ["uv", "pip", "install", "--link-mode=copy", "-e", "."],
100
+ capture_output=False,
101
+ )
102
+
103
+ log_info_pair(
104
+ "✓ Build completed successfully",
105
+ "✓ 构建成功完成",
106
+ )
107
+ except CommandError as e:
108
+ log_error_pair(
109
+ f"Build failed: {e}",
110
+ f"构建失败: {e}",
111
+ )
112
+ raise
113
+ except Exception as e:
114
+ log_error_pair(
115
+ f"Unexpected error during build: {e}",
116
+ f"构建过程中出现意外错误: {e}",
117
+ )
118
+ raise CommandError(f"Build failed: {e}")
119
+
120
+ def build_project(self) -> None:
121
+ """Build the project."""
122
+ self.build()