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.
- py_wlcli-0.8.0.dist-info/METADATA +139 -0
- py_wlcli-0.8.0.dist-info/RECORD +320 -0
- py_wlcli-0.8.0.dist-info/WHEEL +4 -0
- py_wlcli-0.8.0.dist-info/entry_points.txt +2 -0
- py_wlcli-0.8.0.dist-info/licenses/LICENSE +21 -0
- wl_cli/__init__.py +27 -0
- wl_cli/__main__.py +130 -0
- wl_cli/capabilities.py +79 -0
- wl_cli/cc/__init__.py +5 -0
- wl_cli/cc/checks.py +1019 -0
- wl_cli/cc/cli.py +370 -0
- wl_cli/cc/mutate.py +1350 -0
- wl_cli/cli_click.py +156 -0
- wl_cli/commands/__init__.py +84 -0
- wl_cli/commands/base.py +80 -0
- wl_cli/commands/buildcommands/__init__.py +1 -0
- wl_cli/commands/buildcommands/build.py +71 -0
- wl_cli/commands/buildcommands/build_utils.py +47 -0
- wl_cli/commands/buildcommands/builders/__init__.py +18 -0
- wl_cli/commands/buildcommands/builders/cleanup.py +35 -0
- wl_cli/commands/buildcommands/builders/coordinator.py +122 -0
- wl_cli/commands/buildcommands/builders/environment.py +81 -0
- wl_cli/commands/buildcommands/builders/rust_builder.py +39 -0
- wl_cli/commands/buildcommands/builders/stubs.py +58 -0
- wl_cli/commands/buildcommands/dist.py +326 -0
- wl_cli/commands/buildcommands/test.py +89 -0
- wl_cli/commands/clean/__init__.py +1 -0
- wl_cli/commands/clean/build.py +151 -0
- wl_cli/commands/clean/clean.py +294 -0
- wl_cli/commands/clean/clean_utils.py +77 -0
- wl_cli/commands/clean/core.py +236 -0
- wl_cli/commands/clean/dead_code/__init__.py +0 -0
- wl_cli/commands/clean/dead_code/dead_code_command.py +70 -0
- wl_cli/commands/clean/dead_code/detector.py +161 -0
- wl_cli/commands/clean/dead_code/fixer.py +176 -0
- wl_cli/commands/clean/dead_code/reporter.py +295 -0
- wl_cli/commands/clean/dead_code/utils.py +0 -0
- wl_cli/commands/clean/lfs.py +215 -0
- wl_cli/commands/clean/python.py +81 -0
- wl_cli/commands/clean/rust.py +91 -0
- wl_cli/commands/clean/utils/__init__.py +34 -0
- wl_cli/commands/clean/venv.py +91 -0
- wl_cli/commands/cleanup.py +73 -0
- wl_cli/commands/click_base.py +79 -0
- wl_cli/commands/config/__init__.py +1 -0
- wl_cli/commands/config/config.py +291 -0
- wl_cli/commands/debug/__init__.py +6 -0
- wl_cli/commands/debug/debug.py +309 -0
- wl_cli/commands/debug/debug_cache.py +86 -0
- wl_cli/commands/debug/debug_subagent.py +156 -0
- wl_cli/commands/debug/output_formatter.py +165 -0
- wl_cli/commands/debug/source_hasher.py +92 -0
- wl_cli/commands/format/__init__.py +13 -0
- wl_cli/commands/format/format_cache_adapter.py +125 -0
- wl_cli/commands/format/format_command.py +197 -0
- wl_cli/commands/format/format_coordinator.py +191 -0
- wl_cli/commands/format/format_executor.py +470 -0
- wl_cli/commands/format/format_outcome.py +44 -0
- wl_cli/commands/format/format_path_handler.py +1016 -0
- wl_cli/commands/format/format_progress.py +62 -0
- wl_cli/commands/format/format_reporter.py +31 -0
- wl_cli/commands/format/python_formatter.py +506 -0
- wl_cli/commands/format/rust_formatter.py +106 -0
- wl_cli/commands/gate/__init__.py +1 -0
- wl_cli/commands/gate/gate_command.py +862 -0
- wl_cli/commands/gate/preflight.py +445 -0
- wl_cli/commands/git/__init__.py +1 -0
- wl_cli/commands/git/config.py +169 -0
- wl_cli/commands/git/git_facts.py +60 -0
- wl_cli/commands/git/git_flow.py +86 -0
- wl_cli/commands/git/hook.py +112 -0
- wl_cli/commands/git/policy.py +216 -0
- wl_cli/commands/git/push_update.py +82 -0
- wl_cli/commands/initenv/__init__.py +1 -0
- wl_cli/commands/initenv/common/__init__.py +23 -0
- wl_cli/commands/initenv/common/check_git_bash.py +78 -0
- wl_cli/commands/initenv/common/error_handler.py +68 -0
- wl_cli/commands/initenv/common/exceptions.py +52 -0
- wl_cli/commands/initenv/components/__init__.py +4 -0
- wl_cli/commands/initenv/components/cargo_sync.py +240 -0
- wl_cli/commands/initenv/components/config_manager.py +106 -0
- wl_cli/commands/initenv/components/directory_utils.py +71 -0
- wl_cli/commands/initenv/components/git/__init__.py +9 -0
- wl_cli/commands/initenv/components/git/branch_creator.py +143 -0
- wl_cli/commands/initenv/components/git/git_flow_interface.py +24 -0
- wl_cli/commands/initenv/components/git/git_flow_manager.py +159 -0
- wl_cli/commands/initenv/components/git/git_lfs_manager.py +272 -0
- wl_cli/commands/initenv/components/git/git_utility.py +254 -0
- wl_cli/commands/initenv/components/git/gitignore_manager.py +53 -0
- wl_cli/commands/initenv/components/git_initializer.py +212 -0
- wl_cli/commands/initenv/components/i18n_manager.py +104 -0
- wl_cli/commands/initenv/components/log_manager.py +241 -0
- wl_cli/commands/initenv/components/project_structure/__init__.py +23 -0
- wl_cli/commands/initenv/components/project_structure/config_generator.py +360 -0
- wl_cli/commands/initenv/components/project_structure/directory_creator.py +184 -0
- wl_cli/commands/initenv/components/project_structure/hook_source.py +110 -0
- wl_cli/commands/initenv/components/project_structure/hooks_manager.py +995 -0
- wl_cli/commands/initenv/components/project_structure/readme_handler.py +56 -0
- wl_cli/commands/initenv/components/project_structure/rust_files_handler.py +30 -0
- wl_cli/commands/initenv/components/project_structure/setup_handler.py +103 -0
- wl_cli/commands/initenv/components/project_structure/sop_generator.py +73 -0
- wl_cli/commands/initenv/components/project_structure/template_copier.py +104 -0
- wl_cli/commands/initenv/components/project_structure/template_manager.py +195 -0
- wl_cli/commands/initenv/components/pyproject_generator.py +194 -0
- wl_cli/commands/initenv/components/rust_initializer.py +145 -0
- wl_cli/commands/initenv/components/symlink_cleaner.py +99 -0
- wl_cli/commands/initenv/components/symlink_manager.py +52 -0
- wl_cli/commands/initenv/components/venv_manager.py +118 -0
- wl_cli/commands/initenv/initenv.py +169 -0
- wl_cli/commands/initenv/services/__init__.py +11 -0
- wl_cli/commands/initenv/services/environment_initializer.py +288 -0
- wl_cli/commands/initenv/services/git_lfs_initializer.py +26 -0
- wl_cli/commands/initenv/services/project_structure_initializer.py +52 -0
- wl_cli/commands/lfs/README.md +221 -0
- wl_cli/commands/lfs/__init__.py +5 -0
- wl_cli/commands/lfs/cli.py +106 -0
- wl_cli/commands/lfs/config.py +164 -0
- wl_cli/commands/lfs/hook.py +61 -0
- wl_cli/commands/lfs/initializer.py +531 -0
- wl_cli/commands/lfs/manager.py +95 -0
- wl_cli/commands/lfs/policy.py +165 -0
- wl_cli/commands/lfs/watcher.py +294 -0
- wl_cli/commands/lint/__init__.py +1 -0
- wl_cli/commands/lint/lint_command.py +297 -0
- wl_cli/commands/lint/lint_executor.py +409 -0
- wl_cli/commands/lint/lint_reporter.py +579 -0
- wl_cli/commands/lint/lint_run.py +258 -0
- wl_cli/commands/lint/mypy_config.py +90 -0
- wl_cli/commands/registry.py +103 -0
- wl_cli/commands/self/__init__.py +7 -0
- wl_cli/commands/self/common/__init__.py +8 -0
- wl_cli/commands/self/common/capabilities.py +30 -0
- wl_cli/commands/self/common/config.py +27 -0
- wl_cli/commands/self/common/version_cache.py +85 -0
- wl_cli/commands/self/handlers/__init__.py +19 -0
- wl_cli/commands/self/handlers/base_handler.py +28 -0
- wl_cli/commands/self/handlers/install_handler.py +85 -0
- wl_cli/commands/self/handlers/status_handler.py +66 -0
- wl_cli/commands/self/handlers/uninstall_handler.py +58 -0
- wl_cli/commands/self/handlers/update_handler.py +102 -0
- wl_cli/commands/self/handlers/version_handler.py +16 -0
- wl_cli/commands/self/self_command.py +237 -0
- wl_cli/commands/self/services/__init__.py +15 -0
- wl_cli/commands/self/services/installation_manager.py +187 -0
- wl_cli/commands/self/services/local_installer.py +165 -0
- wl_cli/commands/self/services/pypi_updater.py +278 -0
- wl_cli/commands/self/services/windows_update.py +174 -0
- wl_cli/commands/testcommands/__init__.py +8 -0
- wl_cli/commands/testcommands/base_dependency_analyzer.py +198 -0
- wl_cli/commands/testcommands/batch_processor.py +278 -0
- wl_cli/commands/testcommands/cache_manager.py +1156 -0
- wl_cli/commands/testcommands/coverage_analyzer.py +955 -0
- wl_cli/commands/testcommands/coverage_cache_manager.py +183 -0
- wl_cli/commands/testcommands/progress_manager.py +79 -0
- wl_cli/commands/testcommands/python_env_detector.py +207 -0
- wl_cli/commands/testcommands/report_generator.py +101 -0
- wl_cli/commands/testcommands/single_test_executor.py +250 -0
- wl_cli/commands/testcommands/speed_checker.py +118 -0
- wl_cli/commands/testcommands/test_command_builder.py +165 -0
- wl_cli/commands/testcommands/test_commands.py +786 -0
- wl_cli/commands/testcommands/test_reporter.py +181 -0
- wl_cli/commands/testcommands/test_result_handler.py +96 -0
- wl_cli/commands/testcommands/test_runner.py +1343 -0
- wl_cli/commands/testcommands/test_utils.py +197 -0
- wl_cli/commands/testcommands/utils/__init__.py +17 -0
- wl_cli/commands/testcommands/utils/coverage_parser.py +98 -0
- wl_cli/commands/testcommands/utils/env_info.py +36 -0
- wl_cli/commands/testcommands/utils/junit_parser.py +75 -0
- wl_cli/commands/testcommands/utils/markdown_utils.py +20 -0
- wl_cli/commands/testcommands/utils/project_root.py +61 -0
- wl_cli/commands/update/__init__.py +9 -0
- wl_cli/commands/update/services/__init__.py +21 -0
- wl_cli/commands/update/services/backup_manager.py +207 -0
- wl_cli/commands/update/services/component_manager.py +83 -0
- wl_cli/commands/update/services/conflict_resolver.py +189 -0
- wl_cli/commands/update/services/vendors_updater.py +85 -0
- wl_cli/commands/update/services/version_tracker.py +127 -0
- wl_cli/commands/update/update_command.py +270 -0
- wl_cli/commands/update/utils/__init__.py +3 -0
- wl_cli/commands/version/__init__.py +9 -0
- wl_cli/commands/version/version_command.py +155 -0
- wl_cli/commands/workflow.py +477 -0
- wl_cli/env/__init__.py +5 -0
- wl_cli/env/cli.py +167 -0
- wl_cli/env_status.py +157 -0
- wl_cli/envelope.py +91 -0
- wl_cli/exceptions.py +85 -0
- wl_cli/lib/__init__.py +3 -0
- wl_cli/lib/rust_utils.py +35 -0
- wl_cli/mcp/__init__.py +6 -0
- wl_cli/mcp/capabilities.py +19 -0
- wl_cli/mcp/cli.py +22 -0
- wl_cli/mcp/gitlab.py +553 -0
- wl_cli/mcp/k8s.py +344 -0
- wl_cli/mcp/protocol.py +159 -0
- wl_cli/platform.py +139 -0
- wl_cli/quality/__init__.py +18 -0
- wl_cli/utils/__init__.py +7 -0
- wl_cli/utils/cache.py +491 -0
- wl_cli/utils/cache_ledger.py +355 -0
- wl_cli/utils/cache_store.py +546 -0
- wl_cli/utils/config/__init__.py +27 -0
- wl_cli/utils/config/config_loader.py +163 -0
- wl_cli/utils/config/core.py +862 -0
- wl_cli/utils/config/defaults.py +142 -0
- wl_cli/utils/config/env_exporter.py +86 -0
- wl_cli/utils/config/env_parser.py +108 -0
- wl_cli/utils/config/validation.py +280 -0
- wl_cli/utils/error_handler.py +165 -0
- wl_cli/utils/file_copier.py +56 -0
- wl_cli/utils/file_operations.py +506 -0
- wl_cli/utils/language_utils.py +122 -0
- wl_cli/utils/lazy_import.py +240 -0
- wl_cli/utils/log_levels.py +35 -0
- wl_cli/utils/log_rotators.py +74 -0
- wl_cli/utils/logging.py +458 -0
- wl_cli/utils/output_context.py +142 -0
- wl_cli/utils/performance/__init__.py +1 -0
- wl_cli/utils/performance/decorators.py +111 -0
- wl_cli/utils/performance/exporter.py +38 -0
- wl_cli/utils/performance/models.py +16 -0
- wl_cli/utils/performance/monitor.py +161 -0
- wl_cli/utils/performance_monitor.py +32 -0
- wl_cli/utils/platform_adapter.py +131 -0
- wl_cli/utils/pre_commit.py +266 -0
- wl_cli/utils/pre_commit_config.py +72 -0
- wl_cli/utils/root.py +521 -0
- wl_cli/utils/root_fallback.py +256 -0
- wl_cli/utils/run_evidence.py +236 -0
- wl_cli/utils/structured_logger.py +18 -0
- wl_cli/utils/structured_logging/__init__.py +19 -0
- wl_cli/utils/structured_logging/config.py +337 -0
- wl_cli/utils/structured_logging/core.py +177 -0
- wl_cli/utils/structured_logging/env.py +56 -0
- wl_cli/utils/structured_logging/filtering.py +75 -0
- wl_cli/utils/structured_logging/filters.py +55 -0
- wl_cli/utils/structured_logging/formatters.py +251 -0
- wl_cli/utils/structured_logging/handlers.py +308 -0
- wl_cli/utils/structured_logging/logger.py +354 -0
- wl_cli/utils/subprocess.py +71 -0
- wl_cli/utils/subprocess_utils.py +260 -0
- wl_cli/utils/test_utils/__init__.py +5 -0
- wl_cli/utils/test_utils/test_filter.py +36 -0
- wl_cli/utils/uv_run.py +79 -0
- wl_cli/utils/uv_tool.py +117 -0
- wl_cli/utils/uv_tree.py +71 -0
- wl_cli/utils/uv_workspace.py +174 -0
- wl_cli/utils/version/__init__.py +15 -0
- wl_cli/utils/version/pypi_version_checker.py +95 -0
- wl_cli/utils/version/version_comparator.py +133 -0
- wl_cli/utils/version/version_detectors.py +312 -0
- wl_cli/utils/version/version_service.py +131 -0
- wl_cli/utils/version/version_updater.py +198 -0
- wl_cli/utils/wl_dir_updater.py +1440 -0
- wl_cli/utils/workspace_detector/__init__.py +28 -0
- wl_cli/utils/workspace_detector/core.py +161 -0
- wl_cli/utils/workspace_detector/detection_strategies.py +107 -0
- wl_cli/utils/workspace_detector/exceptions.py +5 -0
- wl_cli/utils/workspace_detector/types.py +17 -0
- wl_cli/utils/workspace_detector/venv_resolver.py +84 -0
- wl_cli/vendors/config/.codespellrc +2 -0
- wl_cli/vendors/config/dependencies.toml +10 -0
- wl_cli/vendors/config/mypy.ini +62 -0
- wl_cli/vendors/config/pyproject_defaults.toml +28 -0
- wl_cli/vendors/config/template_config.toml +24 -0
- wl_cli/vendors/config/tool_configs.toml +76 -0
- wl_cli/vendors/git/.gitignore +122 -0
- wl_cli/vendors/git/.pre-commit-config.yaml +37 -0
- wl_cli/vendors/hooks/applypatch-msg.sample +15 -0
- wl_cli/vendors/hooks/commit-msg.sample +24 -0
- wl_cli/vendors/hooks/fsmonitor-watchman.sample +174 -0
- wl_cli/vendors/hooks/post-update.sample +8 -0
- wl_cli/vendors/hooks/pre-applypatch.sample +14 -0
- wl_cli/vendors/hooks/pre-commit +45 -0
- wl_cli/vendors/hooks/pre-commit.legacy +31 -0
- wl_cli/vendors/hooks/pre-commit.sample +49 -0
- wl_cli/vendors/hooks/pre-merge-commit.sample +13 -0
- wl_cli/vendors/hooks/pre-push.sample +60 -0
- wl_cli/vendors/hooks/pre-rebase.sample +169 -0
- wl_cli/vendors/hooks/pre-receive.sample +24 -0
- wl_cli/vendors/hooks/prepare-commit-msg.sample +42 -0
- wl_cli/vendors/hooks/push-to-checkout.sample +78 -0
- wl_cli/vendors/hooks/sendemail-validate.sample +77 -0
- wl_cli/vendors/hooks/unix/applypatch-msg.sample +15 -0
- wl_cli/vendors/hooks/unix/check_lockfile.py +58 -0
- wl_cli/vendors/hooks/unix/check_lockfile.sh +36 -0
- wl_cli/vendors/hooks/unix/commit-msg.sample +24 -0
- wl_cli/vendors/hooks/unix/fsmonitor-watchman.sample +174 -0
- wl_cli/vendors/hooks/unix/post-update.sample +8 -0
- wl_cli/vendors/hooks/unix/pre-applypatch.sample +14 -0
- wl_cli/vendors/hooks/unix/pre-commit +190 -0
- wl_cli/vendors/hooks/unix/pre-commit.legacy +31 -0
- wl_cli/vendors/hooks/unix/pre-commit.py +81 -0
- wl_cli/vendors/hooks/unix/pre-commit.sample +49 -0
- wl_cli/vendors/hooks/unix/pre-merge-commit.sample +13 -0
- wl_cli/vendors/hooks/unix/pre-push +417 -0
- wl_cli/vendors/hooks/unix/pre-push.sample +53 -0
- wl_cli/vendors/hooks/unix/pre-rebase.sample +169 -0
- wl_cli/vendors/hooks/unix/pre-receive.sample +24 -0
- wl_cli/vendors/hooks/unix/prepare-commit-msg.sample +42 -0
- wl_cli/vendors/hooks/update.sample +128 -0
- wl_cli/vendors/hooks/win/work.bat +63 -0
- wl_cli/vendors/project/.gitignore +90 -0
- wl_cli/vendors/project/.python-version +1 -0
- wl_cli/vendors/project/LICENSE +21 -0
- wl_cli/vendors/project/README.md +0 -0
- wl_cli/vendors/project/pyproject.toml +27 -0
- wl_cli/vendors/project/pyproject_no_workspace.toml +16 -0
- wl_cli/vendors/project/pyproject_workspace.toml +14 -0
- wl_cli/vendors/readme/README.md +120 -0
- wl_cli/vendors/rust/Cargo.toml +14 -0
- wl_cli/vendors/rust/lib/__init__.py +3 -0
- wl_cli/vendors/rust/lib/rust_utils.py +31 -0
- wl_cli/vendors/rust/src/lib.rs +13 -0
- wl_cli/vendors/rust/src/main.rs +3 -0
- wl_cli/vendors/rust/tests/test_rust_fallback.py +40 -0
- wl_cli/vendors/sop_doc/git-dev-sop.md +220 -0
- wl_cli/vendors/sop_doc/industrial-standard-sop.md +145 -0
- wl_cli/vendors/sop_doc/python-sop.md +342 -0
- wl_cli/vendors/sop_doc/rust-readme.md +219 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"""README template handler."""
|
|
2
|
+
|
|
3
|
+
from .....utils.logging import log_debug_pair, log_info_pair
|
|
4
|
+
from ..config_manager import ConfigManager
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ReadmeHandler:
|
|
8
|
+
"""Handle README template processing."""
|
|
9
|
+
|
|
10
|
+
def __init__(self):
|
|
11
|
+
self.config_manager = ConfigManager()
|
|
12
|
+
|
|
13
|
+
def create_readme(self, project_name: str) -> None:
|
|
14
|
+
"""Copy README template and customize it for the project."""
|
|
15
|
+
try:
|
|
16
|
+
# Calculate path to vendors/readme/README.md relative to this file
|
|
17
|
+
template_path = self.config_manager.get_vendor_config_path(
|
|
18
|
+
"readme/README.md"
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
if template_path.exists():
|
|
22
|
+
# Read the template
|
|
23
|
+
with open(template_path, encoding="utf-8") as f:
|
|
24
|
+
template_content = f.read()
|
|
25
|
+
|
|
26
|
+
# Customize the template
|
|
27
|
+
customized_content = template_content.format(
|
|
28
|
+
project_name=project_name,
|
|
29
|
+
project_description=f"{project_name} - A Python project",
|
|
30
|
+
cli_command="wl", # Default CLI command
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
# Write to project README.md
|
|
34
|
+
with open("README.md", "w", encoding="utf-8") as f:
|
|
35
|
+
f.write(customized_content)
|
|
36
|
+
|
|
37
|
+
log_debug_pair(
|
|
38
|
+
f"✓ README.md template copied and customized for: {project_name}",
|
|
39
|
+
f"✓ README.md 模板复制并定制化完成: {project_name}",
|
|
40
|
+
)
|
|
41
|
+
else:
|
|
42
|
+
# Fallback to simple README if template doesn't exist
|
|
43
|
+
with open("README.md", "w", encoding="utf-8") as f:
|
|
44
|
+
f.write(f"# {project_name}\n")
|
|
45
|
+
log_debug_pair(
|
|
46
|
+
f"✓ Created simple README.md with project name: {project_name}",
|
|
47
|
+
f"✓ 创建简单 README.md,项目名: {project_name}",
|
|
48
|
+
)
|
|
49
|
+
except Exception as e:
|
|
50
|
+
# Fallback to simple README if customization fails
|
|
51
|
+
with open("README.md", "w", encoding="utf-8") as f:
|
|
52
|
+
f.write(f"# {project_name}\n")
|
|
53
|
+
log_info_pair(
|
|
54
|
+
f"Warning: Failed to customize README.md, created simple one: {e}",
|
|
55
|
+
f"警告: 定制 README.md 失败,创建简单版本: {e}",
|
|
56
|
+
)
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"""Rust example files handler."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from .template_copier import TemplateCopier
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class RustFilesHandler(TemplateCopier):
|
|
9
|
+
"""Copy Rust example files from vendors to project using config-driven approach."""
|
|
10
|
+
|
|
11
|
+
CONFIG_SECTION = "rust_templates"
|
|
12
|
+
|
|
13
|
+
def copy_rust_files(self, project_name: str, dest_base: Path | None = None) -> None:
|
|
14
|
+
"""Copy Rust example files from vendors to project.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
project_name: Normalized project/package name used in dest templates.
|
|
18
|
+
dest_base: Optional base directory (``packages/<normalized>`` in
|
|
19
|
+
workspace mode) prefixed to every configured destination.
|
|
20
|
+
"""
|
|
21
|
+
self._copy_from_section(
|
|
22
|
+
project_name,
|
|
23
|
+
action_name_en="copy Rust example files",
|
|
24
|
+
action_name_zh="复制 Rust 示例文件",
|
|
25
|
+
success_msg_en="✓ Copied {name} to {dest.parent}",
|
|
26
|
+
success_msg_zh="✓ 复制 {name} 到 {dest.parent}",
|
|
27
|
+
fail_msg="Warning: Failed to copy {name}: {message}",
|
|
28
|
+
fail_msg_zh="警告: 复制 {name} 失败: {message}",
|
|
29
|
+
dest_base=dest_base,
|
|
30
|
+
)
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"""Project structure setup handler.
|
|
2
|
+
|
|
3
|
+
This module serves as the entry point for the modularized project structure setup functionality.
|
|
4
|
+
主要功能委托给专门的模块以获得更好的组织结构。
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
from .....utils.root_fallback import current_context
|
|
10
|
+
from ..config_manager import ConfigManager
|
|
11
|
+
from .config_generator import ConfigGenerator
|
|
12
|
+
from .directory_creator import DirectoryCreator, normalize_project_name
|
|
13
|
+
from .hooks_manager import sync_hooks
|
|
14
|
+
from .readme_handler import ReadmeHandler
|
|
15
|
+
from .rust_files_handler import RustFilesHandler
|
|
16
|
+
from .sop_generator import SopGenerator
|
|
17
|
+
from .template_manager import TemplateManager
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class ProjectStructureSetup:
|
|
21
|
+
"""Project structure setup handler - now a coordinator for specialized modules."""
|
|
22
|
+
|
|
23
|
+
def __init__(self) -> None:
|
|
24
|
+
self.config_manager = ConfigManager()
|
|
25
|
+
self.directory_creator = DirectoryCreator()
|
|
26
|
+
self.readme_handler = ReadmeHandler()
|
|
27
|
+
self.config_generator = ConfigGenerator()
|
|
28
|
+
self.sop_generator = SopGenerator()
|
|
29
|
+
self.template_manager = TemplateManager()
|
|
30
|
+
self.rust_files_handler = RustFilesHandler()
|
|
31
|
+
|
|
32
|
+
def setup(
|
|
33
|
+
self,
|
|
34
|
+
project_name: str,
|
|
35
|
+
use_workspace: bool = True,
|
|
36
|
+
copy_pyproject: bool = True,
|
|
37
|
+
workspace_mode: bool = False,
|
|
38
|
+
) -> None:
|
|
39
|
+
"""Setup project structure by coordinating specialized modules.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
project_name: Name of the project
|
|
43
|
+
use_workspace: If True, use pyproject.toml with workspace config.
|
|
44
|
+
If False, use pyproject.toml without workspace config.
|
|
45
|
+
copy_pyproject: If True, copy pyproject.toml from template.
|
|
46
|
+
If False, skip pyproject.toml (will be generated by PyProjectGenerator).
|
|
47
|
+
workspace_mode: If True, create packages/{name}/ layout instead of src/{name}/.
|
|
48
|
+
"""
|
|
49
|
+
# The `wl init` entry resolves the roots **once** here and hands the
|
|
50
|
+
# deploy root to the two `.wl` steps below (#160/F5). Each of them is a
|
|
51
|
+
# public entry that can also be called directly (and then resolves the
|
|
52
|
+
# one root it needs itself), but on this path they must not each walk
|
|
53
|
+
# the CWD again -- that would resolve the same value twice. Resolving at
|
|
54
|
+
# entry rather than after the file creation below is safe: both roots
|
|
55
|
+
# are "git top, else marker, else start", and none of the steps can move
|
|
56
|
+
# the git top.
|
|
57
|
+
context = current_context()
|
|
58
|
+
|
|
59
|
+
# Normalize the project name exactly once (#175): the same value feeds
|
|
60
|
+
# directory creation, template rendering and both config-driven
|
|
61
|
+
# copiers, so a hyphenated name can never create a parallel
|
|
62
|
+
# ``src/my-project/`` tree next to ``src/my_project/``.
|
|
63
|
+
normalized_name = normalize_project_name(project_name)
|
|
64
|
+
package_base = Path("packages") / normalized_name if workspace_mode else None
|
|
65
|
+
|
|
66
|
+
# Create main project structure
|
|
67
|
+
self.directory_creator.create_structure(
|
|
68
|
+
normalized_name, workspace_mode=workspace_mode
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
# Copy project template files including .coveragerc
|
|
72
|
+
self.template_manager.copy_template_files(
|
|
73
|
+
use_workspace=use_workspace,
|
|
74
|
+
copy_pyproject=copy_pyproject,
|
|
75
|
+
workspace_mode=workspace_mode,
|
|
76
|
+
project_name=normalized_name,
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
# Create README.md if it doesn't exist or is empty
|
|
80
|
+
readme_file = Path("README.md")
|
|
81
|
+
should_create_readme = (
|
|
82
|
+
not readme_file.exists()
|
|
83
|
+
or readme_file.read_text(encoding="utf-8").strip() == ""
|
|
84
|
+
)
|
|
85
|
+
if should_create_readme:
|
|
86
|
+
self.readme_handler.create_readme(project_name)
|
|
87
|
+
|
|
88
|
+
# Generate SOP files for Rust-Python integration. In workspace mode the
|
|
89
|
+
# package-scoped templates share the single ``packages/<norm>`` base.
|
|
90
|
+
self.sop_generator.generate_sop_files(normalized_name, dest_base=package_base)
|
|
91
|
+
|
|
92
|
+
# Copy Rust example files
|
|
93
|
+
self.rust_files_handler.copy_rust_files(normalized_name, dest_base=package_base)
|
|
94
|
+
|
|
95
|
+
# Generate configuration files in .wl directory
|
|
96
|
+
self.config_generator.generate_configs(context.deploy)
|
|
97
|
+
|
|
98
|
+
# Sync git hooks explicitly (generate_configs is pure template migration)
|
|
99
|
+
sync_hooks(context.deploy)
|
|
100
|
+
|
|
101
|
+
from .....utils.logging import log_info_pair
|
|
102
|
+
|
|
103
|
+
log_info_pair("✓ Project structure created successfully", "✓ 项目结构创建成功")
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"""SOP file generator."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from .template_copier import TemplateCopier
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class SopGenerator(TemplateCopier):
|
|
9
|
+
"""Generate SOP files for Rust-Python integration using config-driven approach."""
|
|
10
|
+
|
|
11
|
+
CONFIG_SECTION = "sop_templates"
|
|
12
|
+
|
|
13
|
+
def generate_sop_files(
|
|
14
|
+
self, project_name: str, dest_base: Path | None = None
|
|
15
|
+
) -> None:
|
|
16
|
+
"""Generate SOP files for Rust-Python integration.
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
project_name: Normalized project/package name used in dest templates.
|
|
20
|
+
dest_base: Optional base directory (``packages/<normalized>`` in
|
|
21
|
+
workspace mode) prefixed to every configured destination.
|
|
22
|
+
"""
|
|
23
|
+
existed = self._existing_sop_dests(project_name, dest_base)
|
|
24
|
+
self._copy_from_section(
|
|
25
|
+
project_name,
|
|
26
|
+
action_name_en="generate SOP files",
|
|
27
|
+
action_name_zh="生成 SOP 文件",
|
|
28
|
+
success_msg_en="✓ Generated SOP file: {dest}",
|
|
29
|
+
success_msg_zh="✓ 生成 SOP 文件: {dest}",
|
|
30
|
+
fail_msg="Warning: Failed to generate SOP {name}: {message}",
|
|
31
|
+
fail_msg_zh="警告: 生成 SOP {name} 失败: {message}",
|
|
32
|
+
dest_base=dest_base,
|
|
33
|
+
)
|
|
34
|
+
self._rewrite_self_references(project_name, existed, dest_base)
|
|
35
|
+
|
|
36
|
+
def _sop_destinations(
|
|
37
|
+
self, project_name: str, dest_base: Path | None = None
|
|
38
|
+
) -> list[Path]:
|
|
39
|
+
"""Resolve the configured SOP destinations for this project name."""
|
|
40
|
+
base = dest_base if dest_base is not None else Path()
|
|
41
|
+
dests: list[Path] = []
|
|
42
|
+
for template in self.config.get(self.CONFIG_SECTION, {}).values():
|
|
43
|
+
dests.append(base / template["dest"].format(project_name=project_name))
|
|
44
|
+
return dests
|
|
45
|
+
|
|
46
|
+
def _existing_sop_dests(
|
|
47
|
+
self, project_name: str, dest_base: Path | None = None
|
|
48
|
+
) -> set[Path]:
|
|
49
|
+
return {
|
|
50
|
+
d for d in self._sop_destinations(project_name, dest_base) if d.exists()
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
def _rewrite_self_references(
|
|
54
|
+
self, project_name: str, existed: set[Path], dest_base: Path | None = None
|
|
55
|
+
) -> None:
|
|
56
|
+
"""Rewrite freshly generated SOP copies so they no longer self-reference
|
|
57
|
+
wl_cli (industrial-SOP D1 / map #49 #52).
|
|
58
|
+
|
|
59
|
+
The vendored SOP templates are repo-agnostic prose, but keep the
|
|
60
|
+
``wl_cli`` tokens as runnable examples. We copy them verbatim
|
|
61
|
+
(template=false, since the markdown's code fences contain literal
|
|
62
|
+
braces that ``.format`` would break on) and then replace the token with
|
|
63
|
+
the generated project's own name, so the SOP a new project receives
|
|
64
|
+
matches its real package/module (``{project_name}_native`` etc.).
|
|
65
|
+
"""
|
|
66
|
+
for dest in self._sop_destinations(project_name, dest_base):
|
|
67
|
+
if dest.exists() and dest not in existed:
|
|
68
|
+
text = dest.read_text(encoding="utf-8")
|
|
69
|
+
if "wl_cli" in text:
|
|
70
|
+
dest.write_text(
|
|
71
|
+
text.replace("wl_cli", project_name),
|
|
72
|
+
encoding="utf-8",
|
|
73
|
+
)
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"""Shared template copying implementation for config-driven project generators.
|
|
2
|
+
|
|
3
|
+
Both SopGenerator and RustFilesHandler copy vendored template files into the
|
|
4
|
+
project based on sections in template_config.toml. This base class factors out
|
|
5
|
+
their identical initialization, config loading, and copy loop so changes to
|
|
6
|
+
copying behaviour (error handling, template placeholder support, logging) are
|
|
7
|
+
made in one place.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
import tomllib
|
|
13
|
+
|
|
14
|
+
from .....utils.file_copier import FileCopier
|
|
15
|
+
from .....utils.logging import log_debug_pair, log_info_pair
|
|
16
|
+
from ..config_manager import ConfigManager
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class TemplateCopier:
|
|
20
|
+
"""Copy vendored template files based on a template_config.toml section."""
|
|
21
|
+
|
|
22
|
+
# Subclasses set the config section key, e.g. "sop_templates".
|
|
23
|
+
CONFIG_SECTION = ""
|
|
24
|
+
|
|
25
|
+
def __init__(self) -> None:
|
|
26
|
+
"""Initialize with a config manager, file copier, and loaded config."""
|
|
27
|
+
self.config_manager = ConfigManager()
|
|
28
|
+
self.file_copier = FileCopier()
|
|
29
|
+
self.config: dict = {}
|
|
30
|
+
self._load_config()
|
|
31
|
+
|
|
32
|
+
def _load_config(self) -> None:
|
|
33
|
+
"""Load template_config.toml, falling back to an empty dict on failure."""
|
|
34
|
+
config_path = self.config_manager.get_vendor_config_path(
|
|
35
|
+
"config/template_config.toml"
|
|
36
|
+
)
|
|
37
|
+
if config_path.exists():
|
|
38
|
+
try:
|
|
39
|
+
with open(config_path, "rb") as f:
|
|
40
|
+
self.config = tomllib.load(f)
|
|
41
|
+
except Exception as e:
|
|
42
|
+
log_info_pair(
|
|
43
|
+
f"Warning: Failed to load template config: {e}",
|
|
44
|
+
f"警告: 加载模板配置失败: {e}",
|
|
45
|
+
)
|
|
46
|
+
self.config = {}
|
|
47
|
+
else:
|
|
48
|
+
self.config = {}
|
|
49
|
+
|
|
50
|
+
def _copy_from_section(
|
|
51
|
+
self,
|
|
52
|
+
project_name: str,
|
|
53
|
+
*,
|
|
54
|
+
action_name_en: str,
|
|
55
|
+
action_name_zh: str,
|
|
56
|
+
success_msg_en: str,
|
|
57
|
+
success_msg_zh: str,
|
|
58
|
+
fail_msg: str,
|
|
59
|
+
fail_msg_zh: str,
|
|
60
|
+
dest_base: Path | None = None,
|
|
61
|
+
) -> None:
|
|
62
|
+
"""Copy files described by CONFIG_SECTION, skipping existing targets.
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
project_name: Name of the project, used for {project_name} placeholders.
|
|
66
|
+
action_name_en: English action label used in the top-level failure message.
|
|
67
|
+
action_name_zh: Chinese action label used in the top-level failure message.
|
|
68
|
+
success_msg_en: English success message template with {dest} or {name}.
|
|
69
|
+
success_msg_zh: Chinese success message template with {dest} or {name}.
|
|
70
|
+
fail_msg: English failure message template with {name} and {message}.
|
|
71
|
+
fail_msg_zh: Chinese failure message template with {name} and {message}.
|
|
72
|
+
dest_base: Optional base directory prefixed to every configured dest.
|
|
73
|
+
In workspace mode the caller passes ``packages/<normalized>`` so
|
|
74
|
+
package-scoped templates land inside the sub-package (#175).
|
|
75
|
+
"""
|
|
76
|
+
try:
|
|
77
|
+
section_config = self.config.get(self.CONFIG_SECTION, {})
|
|
78
|
+
context = {"project_name": project_name}
|
|
79
|
+
base = dest_base if dest_base is not None else Path()
|
|
80
|
+
|
|
81
|
+
for name, template in section_config.items():
|
|
82
|
+
src = self.config_manager.get_vendor_config_path(template["src"])
|
|
83
|
+
dest = base / template["dest"].format(**context)
|
|
84
|
+
is_template = template.get("template", False)
|
|
85
|
+
|
|
86
|
+
if not dest.exists():
|
|
87
|
+
result = self.file_copier.copy_file(
|
|
88
|
+
src, dest, template=is_template, context=context
|
|
89
|
+
)
|
|
90
|
+
if result.success:
|
|
91
|
+
log_debug_pair(
|
|
92
|
+
success_msg_en.format(dest=dest, name=name),
|
|
93
|
+
success_msg_zh.format(dest=dest, name=name),
|
|
94
|
+
)
|
|
95
|
+
else:
|
|
96
|
+
log_info_pair(
|
|
97
|
+
fail_msg.format(name=name, message=result.message),
|
|
98
|
+
fail_msg_zh.format(name=name, message=result.message),
|
|
99
|
+
)
|
|
100
|
+
except Exception as e:
|
|
101
|
+
log_info_pair(
|
|
102
|
+
f"Warning: Failed to {action_name_en}: {e}",
|
|
103
|
+
f"警告: {action_name_zh}失败: {e}",
|
|
104
|
+
)
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
"""Project template manager."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
import tomllib
|
|
6
|
+
|
|
7
|
+
from .....utils.file_copier import FileCopier
|
|
8
|
+
from .....utils.logging import log_debug, log_debug_pair, log_info, log_info_pair
|
|
9
|
+
from .....utils.root import RootKind
|
|
10
|
+
from .....utils.root_fallback import current_root
|
|
11
|
+
from ..config_manager import ConfigManager
|
|
12
|
+
from .directory_creator import normalize_project_name
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class TemplateManager:
|
|
16
|
+
"""Copy project template files using config-driven approach."""
|
|
17
|
+
|
|
18
|
+
def __init__(self):
|
|
19
|
+
self.config_manager = ConfigManager()
|
|
20
|
+
self.file_copier = FileCopier()
|
|
21
|
+
self.config = {}
|
|
22
|
+
self._load_config()
|
|
23
|
+
|
|
24
|
+
def _load_config(self):
|
|
25
|
+
config_path = self.config_manager.get_vendor_config_path(
|
|
26
|
+
"config/template_config.toml"
|
|
27
|
+
)
|
|
28
|
+
if config_path.exists():
|
|
29
|
+
try:
|
|
30
|
+
with open(config_path, "rb") as f:
|
|
31
|
+
self.config = tomllib.load(f)
|
|
32
|
+
except Exception as e:
|
|
33
|
+
log_info_pair(
|
|
34
|
+
f"Warning: Failed to load template config: {e}",
|
|
35
|
+
f"警告: 加载模板配置失败: {e}",
|
|
36
|
+
)
|
|
37
|
+
self.config = {}
|
|
38
|
+
else:
|
|
39
|
+
self.config = {}
|
|
40
|
+
|
|
41
|
+
def _validate_template_files(self) -> list[str]:
|
|
42
|
+
missing_files = []
|
|
43
|
+
all_templates = {}
|
|
44
|
+
all_templates.update(self.config.get("core_templates", {}))
|
|
45
|
+
all_templates.update(self.config.get("rust_templates", {}))
|
|
46
|
+
all_templates.update(self.config.get("sop_templates", {}))
|
|
47
|
+
all_templates.update(self.config.get("config_templates", {}))
|
|
48
|
+
|
|
49
|
+
for name, template in all_templates.items():
|
|
50
|
+
src = self.config_manager.get_vendor_config_path(template["src"])
|
|
51
|
+
if not src.exists():
|
|
52
|
+
missing_files.append(f"{name}: {template['src']}")
|
|
53
|
+
|
|
54
|
+
return missing_files
|
|
55
|
+
|
|
56
|
+
def copy_template_files(
|
|
57
|
+
self,
|
|
58
|
+
use_workspace: bool = True,
|
|
59
|
+
copy_pyproject: bool = True,
|
|
60
|
+
workspace_mode: bool = False,
|
|
61
|
+
project_name: str | None = None,
|
|
62
|
+
) -> None:
|
|
63
|
+
"""Copy project template files (core + config templates).
|
|
64
|
+
|
|
65
|
+
Args:
|
|
66
|
+
use_workspace: If True, use pyproject.toml with workspace config.
|
|
67
|
+
If False, use pyproject.toml without workspace config.
|
|
68
|
+
copy_pyproject: If True, copy pyproject.toml from template.
|
|
69
|
+
If False, skip pyproject.toml (will be generated by PyProjectGenerator).
|
|
70
|
+
workspace_mode: If True, copy workspace layout templates.
|
|
71
|
+
project_name: Normalized project name resolved once by the caller
|
|
72
|
+
(#175). Falls back to the CWD basename for direct calls.
|
|
73
|
+
"""
|
|
74
|
+
missing = self._validate_template_files()
|
|
75
|
+
if missing:
|
|
76
|
+
log_info_pair(
|
|
77
|
+
f"Warning: Missing template files: {missing}",
|
|
78
|
+
f"警告: 缺失模板文件: {missing}",
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
try:
|
|
82
|
+
self._copy_core_templates()
|
|
83
|
+
self._copy_config_templates()
|
|
84
|
+
|
|
85
|
+
if copy_pyproject:
|
|
86
|
+
if workspace_mode:
|
|
87
|
+
self._copy_workspace_templates(project_name)
|
|
88
|
+
else:
|
|
89
|
+
self._copy_pyproject(use_workspace)
|
|
90
|
+
|
|
91
|
+
except Exception as e:
|
|
92
|
+
log_info_pair(
|
|
93
|
+
f"Warning: Failed to copy project template files: {e}",
|
|
94
|
+
f"警告: 复制项目模板文件失败: {e}",
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
def _copy_core_templates(self):
|
|
98
|
+
core_config = self.config.get("core_templates", {})
|
|
99
|
+
for name, template in core_config.items():
|
|
100
|
+
src = self.config_manager.get_vendor_config_path(template["src"])
|
|
101
|
+
dest = Path(template["dest"])
|
|
102
|
+
|
|
103
|
+
if not dest.exists():
|
|
104
|
+
result = self.file_copier.copy_file(src, dest)
|
|
105
|
+
if result.success:
|
|
106
|
+
log_debug_pair(
|
|
107
|
+
f"✓ Copied {name} from template", f"✓ 从模板复制 {name}"
|
|
108
|
+
)
|
|
109
|
+
else:
|
|
110
|
+
log_info(f"Warning: Failed to copy {name}: {result.message}")
|
|
111
|
+
|
|
112
|
+
def _copy_config_templates(self):
|
|
113
|
+
"""Copy the ``.wl`` config templates, anchored at the deploy root.
|
|
114
|
+
|
|
115
|
+
These destinations all live under ``.wl`` (``.wl/mypy.ini`` and friends),
|
|
116
|
+
which since #95 / #96 belongs inside the git work tree -- the same base
|
|
117
|
+
:class:`ConfigGenerator` uses. Resolving them against the CWD instead
|
|
118
|
+
dropped a second, partial ``.wl`` into an ``wl init project`` run from a
|
|
119
|
+
subdirectory (issue #95 / #96 fix-up, F1).
|
|
120
|
+
"""
|
|
121
|
+
# The same deploy root :class:`ConfigGenerator` uses (#160): the one
|
|
122
|
+
# fallback policy, taken as a bare Path to join the template paths onto.
|
|
123
|
+
deploy_root = current_root(RootKind.DEPLOY).path
|
|
124
|
+
config_config = self.config.get("config_templates", {})
|
|
125
|
+
for name, template in config_config.items():
|
|
126
|
+
src = self.config_manager.get_vendor_config_path(template["src"])
|
|
127
|
+
dest = deploy_root / template["dest"]
|
|
128
|
+
|
|
129
|
+
if not dest.exists():
|
|
130
|
+
dest.parent.mkdir(parents=True, exist_ok=True)
|
|
131
|
+
result = self.file_copier.copy_file(src, dest)
|
|
132
|
+
if result.success:
|
|
133
|
+
log_debug_pair(
|
|
134
|
+
f"✓ Copied {name} from template", f"✓ 从模板复制 {name}"
|
|
135
|
+
)
|
|
136
|
+
else:
|
|
137
|
+
log_info(f"Warning: Failed to copy {name}: {result.message}")
|
|
138
|
+
|
|
139
|
+
def _copy_workspace_templates(self, project_name: str | None = None) -> None:
|
|
140
|
+
"""Copy workspace layout templates (root pyproject + package pyproject)."""
|
|
141
|
+
pyproject_config = self.config.get("pyproject_templates", {})
|
|
142
|
+
normalized_name = normalize_project_name(project_name or Path.cwd().name)
|
|
143
|
+
|
|
144
|
+
# Copy workspace root pyproject.toml
|
|
145
|
+
root_key = "workspace_root"
|
|
146
|
+
if root_key in pyproject_config:
|
|
147
|
+
template = pyproject_config[root_key]
|
|
148
|
+
src = self.config_manager.get_vendor_config_path(template["src"])
|
|
149
|
+
dest = Path(template["dest"])
|
|
150
|
+
if not dest.exists() and src.exists():
|
|
151
|
+
result = self.file_copier.copy_file(src, dest)
|
|
152
|
+
if result.success:
|
|
153
|
+
log_debug("✓ Copied workspace root pyproject.toml")
|
|
154
|
+
else:
|
|
155
|
+
log_info(
|
|
156
|
+
f"Warning: Failed to copy workspace pyproject.toml: {result.message}"
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
# Copy package pyproject.toml
|
|
160
|
+
pkg_key = "workspace_package"
|
|
161
|
+
if pkg_key in pyproject_config:
|
|
162
|
+
template = pyproject_config[pkg_key]
|
|
163
|
+
src = self.config_manager.get_vendor_config_path(template["src"])
|
|
164
|
+
dest_str = template["dest"].replace("{project_name}", normalized_name)
|
|
165
|
+
dest = Path(dest_str)
|
|
166
|
+
dest.parent.mkdir(parents=True, exist_ok=True)
|
|
167
|
+
if not dest.exists() and src.exists():
|
|
168
|
+
result = self.file_copier.copy_file(src, dest)
|
|
169
|
+
if result.success:
|
|
170
|
+
log_debug(f"✓ Copied package pyproject.toml to {dest}")
|
|
171
|
+
else:
|
|
172
|
+
log_info(
|
|
173
|
+
f"Warning: Failed to copy package pyproject.toml: {result.message}"
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
def _copy_pyproject(self, use_workspace: bool):
|
|
177
|
+
pyproject_config = self.config.get("pyproject_templates", {})
|
|
178
|
+
key = "workspace" if use_workspace else "no_workspace"
|
|
179
|
+
|
|
180
|
+
if key in pyproject_config:
|
|
181
|
+
template = pyproject_config[key]
|
|
182
|
+
src = self.config_manager.get_vendor_config_path(template["src"])
|
|
183
|
+
dest = Path(template["dest"])
|
|
184
|
+
|
|
185
|
+
if not dest.exists() and src.exists():
|
|
186
|
+
result = self.file_copier.copy_file(src, dest)
|
|
187
|
+
if result.success:
|
|
188
|
+
log_debug_pair(
|
|
189
|
+
"✓ Copied pyproject.toml from template",
|
|
190
|
+
"✓ 从模板复制 pyproject.toml",
|
|
191
|
+
)
|
|
192
|
+
else:
|
|
193
|
+
log_info(
|
|
194
|
+
f"Warning: Failed to copy pyproject.toml: {result.message}"
|
|
195
|
+
)
|