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
@@ -0,0 +1,194 @@
1
+ """PyProject.toml generator utility."""
2
+
3
+ import re
4
+ from pathlib import Path
5
+ from typing import Any
6
+
7
+ import toml
8
+
9
+ from ....utils.logging import log_debug
10
+ from .config_manager import ConfigManager
11
+ from .project_structure.directory_creator import normalize_project_name
12
+
13
+
14
+ def clean_cargo_name(name: str) -> str:
15
+ """Cleans a string to be a valid Cargo package name.
16
+ - Replaces invalid characters (anything not letter, number, _, -) with underscore.
17
+ - Ensures it doesn't start/end with invalid chars like _ or -.
18
+ """
19
+ # Replace sequences of invalid characters (anything not alphanumeric or _) with a single underscore
20
+ # Also replace hyphens with underscores as Cargo prefers underscores, though hyphens are technically allowed.
21
+ cleaned = re.sub(r"[^a-zA-Z0-9_]+", "_", name.replace("-", "_"))
22
+ # Remove leading/trailing underscores
23
+ cleaned = cleaned.strip("_")
24
+ # Handle potential empty string after cleaning
25
+ if not cleaned:
26
+ return "rust_package" # Default fallback name
27
+ # Ensure it doesn't start with a digit (invalid for Rust identifiers)
28
+ if cleaned[0].isdigit():
29
+ cleaned = "_" + cleaned
30
+ return cleaned
31
+
32
+
33
+ def dump_toml(data: dict[str, Any], file_path: str) -> None:
34
+ """将数据以 TOML 格式写入文件"""
35
+ with open(file_path, "w", encoding="utf-8") as f:
36
+ toml.dump(data, f)
37
+
38
+
39
+ class PyProjectGenerator:
40
+ """pyproject.toml 生成器类"""
41
+
42
+ def __init__(self, project_name: str) -> None:
43
+ self.cleaned_python_name = normalize_project_name(project_name)
44
+ self.cleaned_rust_name = clean_cargo_name(f"{project_name}_native")
45
+ self.config: dict[str, Any] = {}
46
+ self.config_manager = ConfigManager()
47
+
48
+ def _load_tool_configs(self) -> dict[str, Any]:
49
+ """加载工具配置"""
50
+ result = self.config_manager.load_vendor_config("config/tool_configs.toml")
51
+ return result or {}
52
+
53
+ def _load_dependencies(self) -> list[str]:
54
+ """加载依赖列表"""
55
+ dependencies_config = self.config_manager.load_vendor_config(
56
+ "config/dependencies.toml"
57
+ )
58
+ return dependencies_config.get("dependencies", {}).get("default", []) or []
59
+
60
+ def set_project_info(
61
+ self,
62
+ description: str | None = None,
63
+ authors: list[dict[str, str]] | None = None,
64
+ python_version: str = ">=3.12",
65
+ license_name: str = "MIT",
66
+ dependencies: list[str] | None = None,
67
+ ) -> None:
68
+ """设置项目基本信息"""
69
+ # Load dependencies from config if not provided
70
+ if not dependencies:
71
+ dependencies = self._load_dependencies()
72
+
73
+ # Use cleaned python name for URLs and description default
74
+ project_urls = {
75
+ "Homepage": f"https://github.com/example/{self.cleaned_python_name}",
76
+ "Issues": f"https://github.com/example/{self.cleaned_python_name}/issues",
77
+ }
78
+
79
+ self.config["project"] = {
80
+ "name": self.cleaned_python_name,
81
+ "dynamic": ["version"],
82
+ "description": description or f"{self.cleaned_python_name} - Python项目",
83
+ "requires-python": python_version,
84
+ "license": license_name,
85
+ "readme": "README.md",
86
+ "dependencies": dependencies,
87
+ "authors": authors or [{"name": "Admin", "email": "admin@example.com"}],
88
+ "urls": project_urls,
89
+ }
90
+
91
+ def set_build_system(self, is_rust: bool = False) -> None:
92
+ """设置构建系统配置"""
93
+ if not is_rust:
94
+ log_debug("Non-Rust build system not fully configured in generator.")
95
+ # Set a basic setuptools build system or similar if required
96
+ self.config["build-system"] = {
97
+ "requires": ["setuptools>=61.0"],
98
+ "build-backend": "setuptools.build_meta",
99
+ }
100
+ return # Exit early if not using Rust/Maturin
101
+
102
+ # --- Maturin Configuration ---
103
+ self.config["build-system"] = {
104
+ "requires": ["maturin>=1.0,<2.0"],
105
+ "build-backend": "maturin",
106
+ }
107
+
108
+ # Maturin 特定配置
109
+ maturin_config = {
110
+ "manifest-path": "rust/Cargo.toml",
111
+ # Use CLEANED Python and Rust names for module-name
112
+ "module-name": f"{self.cleaned_python_name}.lib.{self.cleaned_rust_name}",
113
+ "python-source": "src",
114
+ # Use cleaned python name for include path
115
+ "include": [f"src/{self.cleaned_python_name}/**/*"],
116
+ "bindings": "pyo3",
117
+ "features": ["pyo3/extension-module"],
118
+ "sdist-include": ["src/**/*"],
119
+ # Use cleaned python name for python-packages
120
+ "python-packages": [self.cleaned_python_name],
121
+ }
122
+
123
+ self.config["tool"] = self.config.get("tool", {})
124
+ self.config["tool"]["maturin"] = maturin_config
125
+
126
+ def set_development_tools(self) -> None:
127
+ """设置开发工具配置"""
128
+ tool_configs = self._load_tool_configs()
129
+
130
+ log_debug(f"Loaded tool_configs keys: {list(tool_configs.keys())}")
131
+ if "tool" in tool_configs:
132
+ log_debug(f"tool_configs['tool'] keys: {list(tool_configs['tool'].keys())}")
133
+
134
+ self.config["tool"] = self.config.get("tool", {})
135
+ self.config["tool"].update(tool_configs.get("tool", {}))
136
+
137
+ def set_entry_points(self, entry_points: dict[str, Any]) -> None:
138
+ """设置入口点"""
139
+ if "project" not in self.config:
140
+ self.config["project"] = {}
141
+
142
+ if "scripts" in entry_points:
143
+ self.config["project"]["scripts"] = entry_points["scripts"]
144
+ if "gui_scripts" in entry_points:
145
+ self.config["project"]["gui-scripts"] = entry_points["gui_scripts"]
146
+
147
+ def generate_package_pyproject(
148
+ self, output_path: str, is_rust: bool = False
149
+ ) -> None:
150
+ """Generate pyproject.toml for a workspace sub-package (e.g. packages/{name}/).
151
+
152
+ Args:
153
+ output_path: Path to write the pyproject.toml file.
154
+ is_rust: Whether to include Rust/maturin build configuration.
155
+ """
156
+ pkg_config: dict[str, Any] = {
157
+ "project": {
158
+ "name": self.cleaned_python_name,
159
+ "version": "0.1.0",
160
+ "description": f"{self.cleaned_python_name} - Python项目",
161
+ "requires-python": ">=3.12",
162
+ "readme": "README.md",
163
+ "dependencies": self._load_dependencies(),
164
+ },
165
+ }
166
+
167
+ if is_rust:
168
+ pkg_config["build-system"] = {
169
+ "requires": ["maturin>=1.0,<2.0"],
170
+ "build-backend": "maturin",
171
+ }
172
+ pkg_config["tool"] = {
173
+ "maturin": {
174
+ "manifest-path": "rust/Cargo.toml",
175
+ "module-name": f"{self.cleaned_python_name}.lib.{self.cleaned_rust_name}",
176
+ "python-source": "src",
177
+ "bindings": "pyo3",
178
+ "features": ["pyo3/extension-module"],
179
+ },
180
+ }
181
+
182
+ dump_toml(pkg_config, output_path)
183
+
184
+ def generate(self, output_path: str = "pyproject.toml") -> None:
185
+ """生成 pyproject.toml 文件"""
186
+ is_rust = Path("rust").exists()
187
+
188
+ if "project" not in self.config:
189
+ self.set_project_info()
190
+ self.set_development_tools()
191
+ if "build-system" not in self.config:
192
+ self.set_build_system(is_rust=is_rust)
193
+
194
+ dump_toml(self.config, output_path)
@@ -0,0 +1,145 @@
1
+ """Custom exceptions for initenv commands."""
2
+
3
+ import shutil
4
+ from pathlib import Path
5
+
6
+ from ....utils.logging import log_debug, log_debug_pair, log_info_pair
7
+ from ..common.exceptions import InitEnvError
8
+ from .log_manager import performance_monitor
9
+ from .pyproject_generator import clean_cargo_name # Import the cleaning function
10
+
11
+
12
+ class RustInitializer:
13
+ """Rust environment initializer."""
14
+
15
+ def __init__(self) -> None:
16
+ pass
17
+
18
+ @performance_monitor
19
+ def initialize(self) -> None:
20
+ """Initialize Rust environment."""
21
+ rust_dir = Path("rust")
22
+
23
+ # Create rust directory if it doesn't exist
24
+ if not rust_dir.exists():
25
+ log_debug_pair("Creating rust directory...", "创建rust目录...")
26
+ rust_dir.mkdir(exist_ok=True)
27
+
28
+ # Check if Cargo.toml exists
29
+ cargo_toml_path = rust_dir / "Cargo.toml"
30
+ if cargo_toml_path.exists():
31
+ log_debug_pair(
32
+ "Cargo.toml already exists, skipping creation",
33
+ "Cargo.toml 已存在,跳过创建",
34
+ )
35
+ return
36
+
37
+ # Use project template files instead of cargo init
38
+ log_debug_pair(
39
+ "Initializing Rust project with project template...",
40
+ "使用项目模板初始化Rust项目...",
41
+ )
42
+ try:
43
+ # Get the template directory path
44
+ # Calculate path to vendors/rust directory relative to this file
45
+ # File is in src/wl_cli/commands/initenv/utils/
46
+ # vendors dir is in src/wl_cli/
47
+ # So we need to go up 4 levels
48
+ template_dir = (
49
+ Path(__file__).parent.parent.parent.parent / "vendors" / "rust"
50
+ )
51
+
52
+ log_debug(f"Template directory: {template_dir}")
53
+
54
+ if not template_dir.exists():
55
+ raise InitEnvError(f"Rust template directory not found: {template_dir}")
56
+
57
+ # Get project name from current directory
58
+ project_name = Path.cwd().name
59
+
60
+ # Copy template files to rust directory
61
+ for item in template_dir.iterdir():
62
+ dest_path = rust_dir / item.name
63
+ if item.is_dir():
64
+ shutil.copytree(item, dest_path, dirs_exist_ok=True)
65
+ else:
66
+ # Special handling for Cargo.toml to replace project name
67
+ if item.name == "Cargo.toml":
68
+ self._copy_and_update_cargo_toml(item, dest_path, project_name)
69
+ else:
70
+ shutil.copy2(item, dest_path)
71
+
72
+ # Update lib.rs with the correct module name
73
+ lib_rs_path = rust_dir / "src" / "lib.rs"
74
+ if lib_rs_path.exists():
75
+ self._update_lib_rs(lib_rs_path, project_name)
76
+
77
+ log_info_pair(
78
+ "✓ Rust project initialized successfully with template",
79
+ "✓ 使用模板成功初始化Rust项目",
80
+ )
81
+ except Exception as e:
82
+ raise InitEnvError(f"Failed to initialize Rust project: {e}")
83
+
84
+ def _copy_and_update_cargo_toml(
85
+ self, source: Path, dest: Path, project_name: str
86
+ ) -> None:
87
+ """Copy Cargo.toml template and update project name."""
88
+ # Read the template file
89
+ with open(source, encoding="utf-8") as f:
90
+ content = f.read()
91
+
92
+ # Clean the project name to be a valid Cargo name
93
+ cleaned_project_name = clean_cargo_name(project_name)
94
+ # Ensure the library name uses underscores, not hyphens
95
+ lib_name = cleaned_project_name + "_native"
96
+
97
+ # Warn users if their project name contains hyphens
98
+ if "-" in project_name:
99
+ log_info_pair(
100
+ "Warning: Project name contains hyphens which are not allowed in Rust library names.",
101
+ "警告: 项目名称包含连字符,这在Rust库名称中是不允许的。",
102
+ )
103
+ log_info_pair(
104
+ " Converting to underscores for Rust compatibility.",
105
+ " 已转换为下划线以确保与Rust兼容。",
106
+ )
107
+
108
+ # Replace the template project name with actual project name
109
+ # Replace both the package name and the lib name
110
+ updated_content = content.replace("wl_cli_native", lib_name)
111
+ # Also replace in the [lib] section to ensure library name is correct
112
+ updated_content = updated_content.replace(
113
+ 'name = "wl_cli_native"', f'name = "{lib_name}"'
114
+ )
115
+
116
+ # Write the updated content to destination
117
+ with open(dest, "w", encoding="utf-8") as f:
118
+ f.write(updated_content)
119
+
120
+ def _update_lib_rs(self, lib_rs_path: Path, project_name: str) -> None:
121
+ """Update lib.rs with the correct module name."""
122
+ # Read the template file
123
+ with open(lib_rs_path, encoding="utf-8") as f:
124
+ content = f.read()
125
+
126
+ # Clean the project name to be a valid Cargo name
127
+ cleaned_project_name = clean_cargo_name(project_name)
128
+ # Ensure the library name uses underscores, not hyphens
129
+ lib_name = cleaned_project_name + "_native"
130
+
131
+ # Warn users if their project name contains hyphens
132
+ if "-" in project_name:
133
+ log_info_pair(
134
+ "Warning: Project name contains hyphens which are not allowed in Rust library names.",
135
+ "警告: 项目名称包含连字符,这在Rust库名称中是不允许的。",
136
+ )
137
+ log_info_pair(
138
+ " Converting to underscores for Rust compatibility.",
139
+ " 已转换为下划线以确保与Rust兼容。",
140
+ )
141
+
142
+ # Replace the template project name with actual project name in lib.rs
143
+ updated_content = content.replace("wl_cli_native", lib_name)
144
+ with open(lib_rs_path, "w", encoding="utf-8") as f:
145
+ f.write(updated_content)
@@ -0,0 +1,99 @@
1
+ """
2
+ Symlink cleaning utilities for deployment functionality.
3
+ """
4
+
5
+ import os
6
+
7
+
8
+ def _clean_file_symlinks(root: str, files: list[str], source_dir_basename: str) -> int:
9
+ """
10
+ 清理文件软链接
11
+
12
+ Args:
13
+ root: 根目录路径
14
+ files: 文件列表
15
+ source_dir_basename: 源目录基本名称
16
+
17
+ Returns:
18
+ int: 清理的链接数量
19
+ """
20
+ cleaned_count = 0
21
+ for file in files:
22
+ file_path = os.path.join(root, file)
23
+ if os.path.islink(file_path):
24
+ try:
25
+ link_target = os.readlink(file_path)
26
+ if source_dir_basename in link_target:
27
+ os.unlink(file_path)
28
+ cleaned_count += 1
29
+ except OSError:
30
+ pass
31
+ return cleaned_count
32
+
33
+
34
+ def _clean_directory_symlinks(
35
+ root: str, dirs: list[str], source_dir_basename: str
36
+ ) -> tuple[int, list[str]]:
37
+ """
38
+ 清理目录软链接
39
+
40
+ Args:
41
+ root: 根目录路径
42
+ dirs: 目录列表
43
+ source_dir_basename: 源目录基本名称
44
+
45
+ Returns:
46
+ tuple[int, list[str]]: (清理的链接数量, 需要从遍历中移除的目录列表)
47
+ """
48
+ cleaned_count = 0
49
+ removed_dirs = []
50
+ for dir_name in dirs[:]: # 使用副本进行迭代,因为我们可能会修改dirs
51
+ dir_path = os.path.join(root, dir_name)
52
+ if os.path.islink(dir_path):
53
+ try:
54
+ link_target = os.readlink(dir_path)
55
+ if source_dir_basename in link_target:
56
+ os.unlink(dir_path)
57
+ cleaned_count += 1
58
+ removed_dirs.append(dir_name) # 记录需要移除的目录
59
+ except OSError:
60
+ pass
61
+ return cleaned_count, removed_dirs
62
+
63
+
64
+ def clean_existing_symlinks(
65
+ py_dirs: list[str], source_dir_name: str = "shared-build-system"
66
+ ) -> int:
67
+ """
68
+ 清理目标文件夹中已有的软链接
69
+ """
70
+ cleaned_count = 0
71
+ source_dir_basename = os.path.basename(source_dir_name)
72
+
73
+ for py_dir in py_dirs:
74
+ if not os.path.exists(py_dir):
75
+ continue
76
+
77
+ # 递归清理子目录中的链接
78
+ try:
79
+ for root, dirs, files in os.walk(py_dir):
80
+ # 清理文件链接
81
+ cleaned_count += _clean_file_symlinks(root, files, source_dir_basename)
82
+
83
+ # 清理目录链接
84
+ dir_cleaned_count, removed_dirs = _clean_directory_symlinks(
85
+ root, dirs, source_dir_basename
86
+ )
87
+ cleaned_count += dir_cleaned_count
88
+
89
+ # 从遍历列表中移除已清理的目录
90
+ for removed_dir in removed_dirs:
91
+ try:
92
+ dirs.remove(removed_dir)
93
+ except ValueError:
94
+ pass # 目录不在列表中,忽略
95
+
96
+ except OSError:
97
+ pass
98
+
99
+ return cleaned_count
@@ -0,0 +1,52 @@
1
+ """
2
+ Symlink management utilities for deployment.
3
+ """
4
+
5
+ import os
6
+ import shutil
7
+
8
+ from ....utils.platform_adapter import PlatformAdapter
9
+
10
+
11
+ def create_symlink(source: str, target: str) -> bool:
12
+ """
13
+ 创建从源到目标的软链接,处理平台差异
14
+ """
15
+ source = os.path.abspath(source)
16
+ target = os.path.abspath(target)
17
+
18
+ # 如果目标文件已存在,先删除
19
+ if os.path.exists(target):
20
+ try:
21
+ if os.path.islink(target):
22
+ os.unlink(target)
23
+ elif os.path.isdir(target):
24
+ shutil.rmtree(target)
25
+ elif os.path.isfile(target):
26
+ os.remove(target)
27
+ except OSError:
28
+ return False
29
+
30
+ # 确保目标目录存在
31
+ target_dir = os.path.dirname(target)
32
+ try:
33
+ os.makedirs(target_dir, exist_ok=True)
34
+ except OSError:
35
+ return False
36
+
37
+ # 创建软链接(处理不同操作系统)
38
+ try:
39
+ if PlatformAdapter.is_windows():
40
+ # Windows 需要管理员权限并区分目录和文件链接
41
+ is_directory = os.path.isdir(source)
42
+ if is_directory:
43
+ # Windows 10以上版本支持目录符号链接,低版本需使用junction
44
+ os.symlink(source, target, target_is_directory=True)
45
+ else:
46
+ os.symlink(source, target)
47
+ else:
48
+ # Unix/Linux/macOS
49
+ os.symlink(source, target)
50
+ return True
51
+ except OSError:
52
+ return False
@@ -0,0 +1,118 @@
1
+ """Virtual environment manager utility."""
2
+
3
+ import subprocess
4
+
5
+ from ....utils.logging import log_info, log_info_pair
6
+ from ....utils.platform_adapter import PlatformAdapter
7
+ from .log_manager import performance_monitor
8
+
9
+
10
+ class VenvManager:
11
+ """Virtual environment manager."""
12
+
13
+ def __init__(self, env: dict[str, str]) -> None:
14
+ self.env = env
15
+
16
+ @performance_monitor
17
+ def create_venv(
18
+ self, venv_path: str, _: str, env: dict[str, str] | None = None
19
+ ) -> bool:
20
+ """Create a virtual environment, retrying on Windows when needed.
21
+
22
+ The platform differences live on :class:`PlatformAdapter`: it supplies
23
+ the primary argv (``python -m uv`` on Windows, ``uv`` elsewhere) and,
24
+ on Windows only, a retry argv for when the interpreter cannot find uv
25
+ as a module.
26
+
27
+ Args:
28
+ venv_path: Destination directory for the virtual environment.
29
+ _: Python version; currently informational only.
30
+ env: Environment for the subprocess. Defaults to this manager's
31
+ own environment; the Windows caller relies on that default.
32
+
33
+ Returns:
34
+ True if the environment was created, False otherwise.
35
+ """
36
+ process_env = self.env if env is None else env
37
+
38
+ try:
39
+ cmd = PlatformAdapter.get_venv_create_command(venv_path)
40
+ fallback_cmd = PlatformAdapter.get_venv_create_fallback_command(venv_path)
41
+
42
+ result = subprocess.run(
43
+ cmd, capture_output=True, text=True, env=process_env, encoding="utf-8"
44
+ )
45
+
46
+ # If the interpreter cannot find uv as a module, retry with the uv
47
+ # command directly (Windows only -- fallback_cmd is None elsewhere).
48
+ if (
49
+ result.returncode != 0
50
+ and fallback_cmd is not None
51
+ and "No module named uv" in result.stderr
52
+ ):
53
+ log_info("uv module not found, trying uv command directly...")
54
+ result = subprocess.run(
55
+ fallback_cmd,
56
+ capture_output=True,
57
+ text=True,
58
+ env=process_env,
59
+ encoding="utf-8",
60
+ )
61
+
62
+ if result.returncode == 0:
63
+ log_info_pair(
64
+ f"✓ Virtual environment created at {venv_path}",
65
+ f"✓ 虚拟环境已在 {venv_path} 创建",
66
+ )
67
+ return True
68
+ else:
69
+ log_info_pair(
70
+ f"Warning: Failed to create virtual environment: {result.stderr}",
71
+ f"警告: 创建虚拟环境失败: {result.stderr}",
72
+ )
73
+ return False
74
+ except Exception as e:
75
+ log_info_pair(
76
+ f"Warning: Failed to create virtual environment: {e}",
77
+ f"警告: 创建虚拟环境失败: {e}",
78
+ )
79
+ return False
80
+
81
+ @performance_monitor
82
+ def sync_environment(self, _venv_path: str = ".venv") -> bool:
83
+ """Sync the environment by updating dependencies."""
84
+ log_info_pair(
85
+ "Syncing environment dependencies...",
86
+ "同步环境依赖...",
87
+ )
88
+
89
+ try:
90
+ # 更新依赖
91
+ log_info_pair(
92
+ "Updating dependencies with uv...",
93
+ "使用uv更新依赖...",
94
+ )
95
+ cmd = ["uv", "sync"]
96
+
97
+ result = subprocess.run(
98
+ cmd, capture_output=True, text=True, env=self.env, encoding="utf-8"
99
+ )
100
+
101
+ if result.returncode == 0:
102
+ log_info_pair(
103
+ "✓ Dependencies updated successfully",
104
+ "✓ 依赖更新成功",
105
+ )
106
+ return True
107
+ else:
108
+ log_info_pair(
109
+ f"Warning: Failed to update dependencies: {result.stderr}",
110
+ f"警告: 更新依赖失败: {result.stderr}",
111
+ )
112
+ return False
113
+ except Exception as e:
114
+ log_info_pair(
115
+ f"Warning: Failed to sync environment: {e}",
116
+ f"警告: 同步环境失败: {e}",
117
+ )
118
+ return False