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,53 @@
|
|
|
1
|
+
"""Gitignore template manager."""
|
|
2
|
+
|
|
3
|
+
import shutil
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
from wl_cli.utils.logging import log_info, log_info_pair
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class GitignoreManager:
|
|
10
|
+
"""Manager for .gitignore template operations."""
|
|
11
|
+
|
|
12
|
+
def __init__(self, skip_remote_ops: bool = False) -> None:
|
|
13
|
+
self.skip_remote_ops = skip_remote_ops
|
|
14
|
+
|
|
15
|
+
def copy_gitignore_template(self) -> None:
|
|
16
|
+
"""Copy .gitignore template from vendors to project root.
|
|
17
|
+
|
|
18
|
+
Copies the .gitignore template from the vendors directory to the
|
|
19
|
+
current working directory if no .gitignore file already exists.
|
|
20
|
+
"""
|
|
21
|
+
gitignore_path = Path(".gitignore")
|
|
22
|
+
|
|
23
|
+
# Only copy if .gitignore doesn't exist and not in test environment
|
|
24
|
+
if gitignore_path.exists() or self.skip_remote_ops:
|
|
25
|
+
return
|
|
26
|
+
|
|
27
|
+
try:
|
|
28
|
+
# Calculate path to vendors/git/.gitignore relative to this file
|
|
29
|
+
template_path = (
|
|
30
|
+
Path(__file__).parent.parent.parent.parent.parent
|
|
31
|
+
/ "vendors"
|
|
32
|
+
/ "git"
|
|
33
|
+
/ ".gitignore"
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
log_info(f"Looking for .gitignore template at: {template_path}")
|
|
37
|
+
|
|
38
|
+
if template_path.exists():
|
|
39
|
+
shutil.copy2(template_path, ".gitignore")
|
|
40
|
+
log_info_pair(
|
|
41
|
+
"✓ .gitignore template copied successfully",
|
|
42
|
+
"✓ .gitignore 模板复制成功",
|
|
43
|
+
)
|
|
44
|
+
else:
|
|
45
|
+
log_info_pair(
|
|
46
|
+
f"Warning: .gitignore template not found at {template_path}",
|
|
47
|
+
f"警告: 未找到 .gitignore 模板 {template_path}",
|
|
48
|
+
)
|
|
49
|
+
except Exception as e:
|
|
50
|
+
log_info_pair(
|
|
51
|
+
f"Warning: Failed to copy .gitignore template: {e}",
|
|
52
|
+
f"警告: 复制 .gitignore 模板失败: {e}",
|
|
53
|
+
)
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
"""Git initializer utility."""
|
|
2
|
+
|
|
3
|
+
import subprocess
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
from ....utils.logging import log_debug_pair, log_info, log_info_pair
|
|
7
|
+
from ....utils.root import _clear_root_cache
|
|
8
|
+
from ..common.check_git_bash import check_git_bash_installed
|
|
9
|
+
from ..common.exceptions import GitInitError
|
|
10
|
+
from .git.git_flow_manager import GitFlowManager
|
|
11
|
+
from .git.gitignore_manager import GitignoreManager
|
|
12
|
+
from .log_manager import performance_monitor
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class GitInitializer:
|
|
16
|
+
"""Git repository initializer."""
|
|
17
|
+
|
|
18
|
+
def __init__(
|
|
19
|
+
self,
|
|
20
|
+
env: dict[str, str],
|
|
21
|
+
project_root: Path | None = None,
|
|
22
|
+
skip_remote_ops: bool = False,
|
|
23
|
+
) -> None:
|
|
24
|
+
self.env = env
|
|
25
|
+
self.project_root = project_root or Path.cwd()
|
|
26
|
+
self.skip_remote_ops = skip_remote_ops
|
|
27
|
+
self.gitignore_manager = GitignoreManager(skip_remote_ops=skip_remote_ops)
|
|
28
|
+
self.git_flow_manager = GitFlowManager(env, skip_remote_ops=skip_remote_ops)
|
|
29
|
+
|
|
30
|
+
@performance_monitor
|
|
31
|
+
def initialize(self) -> None:
|
|
32
|
+
"""
|
|
33
|
+
Initialize Git repository if it doesn't exist.
|
|
34
|
+
"""
|
|
35
|
+
# Check for Git Bash (only runs on Windows)
|
|
36
|
+
check_git_bash_installed()
|
|
37
|
+
|
|
38
|
+
# Copy .gitignore template if it doesn't exist and we're not in a test environment
|
|
39
|
+
if not (self.project_root / ".gitignore").exists() and not self.skip_remote_ops:
|
|
40
|
+
self.gitignore_manager.copy_gitignore_template()
|
|
41
|
+
|
|
42
|
+
if not Path(".git").exists():
|
|
43
|
+
log_debug_pair("Initializing Git repository...", "初始化Git仓库...")
|
|
44
|
+
try:
|
|
45
|
+
if not self.git_flow_manager.git_utility.run_git_command(
|
|
46
|
+
["git", "init"], description="Initialize Git repository"
|
|
47
|
+
):
|
|
48
|
+
raise GitInitError(
|
|
49
|
+
"Failed to initialize Git repository after multiple attempts"
|
|
50
|
+
)
|
|
51
|
+
# The work tree did not exist a moment ago, so any DEPLOY root
|
|
52
|
+
# memoised for this directory came from the PROJECT fallback and
|
|
53
|
+
# is now wrong (it may point at a parent workspace or
|
|
54
|
+
# sub-package). Drop it so the rest of this run anchors the
|
|
55
|
+
# hooks leg at the root git just created (#103).
|
|
56
|
+
# The root module memoises every kind in one cache, including the
|
|
57
|
+
# negative answer (#113 User Story 17: "not found" is a cacheable
|
|
58
|
+
# answer, so a ``None`` asked for before this ``git init`` would
|
|
59
|
+
# otherwise stick for the whole process). This is the *only*
|
|
60
|
+
# invalidator now: the per-resolver clearers were deleted along
|
|
61
|
+
# with the resolvers themselves in #123.
|
|
62
|
+
_clear_root_cache()
|
|
63
|
+
log_info_pair("✓ Git repository initialized", "✓ Git仓库初始化完成")
|
|
64
|
+
except Exception as e:
|
|
65
|
+
log_info_pair(
|
|
66
|
+
"Warning: Failed to initialize Git repository",
|
|
67
|
+
"警告: 初始化Git仓库失败",
|
|
68
|
+
)
|
|
69
|
+
raise GitInitError(f"Failed to initialize Git repository: {e}")
|
|
70
|
+
else:
|
|
71
|
+
log_debug_pair(
|
|
72
|
+
"Git repository already exists, skipping initialization",
|
|
73
|
+
"Git仓库已存在,跳过初始化",
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
# Update repository if it already exists (skip during tests)
|
|
77
|
+
if not self.skip_remote_ops:
|
|
78
|
+
self.update_repository()
|
|
79
|
+
|
|
80
|
+
# Setup Git Flow branches (main, develop, features) and switch to features
|
|
81
|
+
if not self.skip_remote_ops:
|
|
82
|
+
try:
|
|
83
|
+
self.git_flow_manager.setup_git_flow_branches()
|
|
84
|
+
except Exception as e:
|
|
85
|
+
log_info_pair(
|
|
86
|
+
f"Warning: Failed to setup Git Flow branches: {e}",
|
|
87
|
+
f"警告: 设置Git Flow分支失败: {e}",
|
|
88
|
+
)
|
|
89
|
+
# Continue execution even if Git Flow setup fails
|
|
90
|
+
|
|
91
|
+
def setup_git_flow_branches(self, work_type: str) -> None:
|
|
92
|
+
"""Setup Git Flow branches based on work type."""
|
|
93
|
+
self.git_flow_manager.setup_git_flow_branches_by_work_type(work_type)
|
|
94
|
+
|
|
95
|
+
def update_repository(self) -> None:
|
|
96
|
+
"""Update the repository by pulling latest changes from all important branches.
|
|
97
|
+
|
|
98
|
+
This method:
|
|
99
|
+
1. Updates the main branch
|
|
100
|
+
2. Updates the develop branch
|
|
101
|
+
3. Updates all feature branches (skipped in test environments)
|
|
102
|
+
4. Switches back to the develop branch
|
|
103
|
+
"""
|
|
104
|
+
log_info_pair("Updating repository...", "更新仓库...")
|
|
105
|
+
|
|
106
|
+
# Update main branch
|
|
107
|
+
log_info_pair("Updating main branch...", "更新main分支...")
|
|
108
|
+
self._update_branch("main")
|
|
109
|
+
|
|
110
|
+
# Update develop branch
|
|
111
|
+
log_info_pair("Updating develop branch...", "更新develop分支...")
|
|
112
|
+
self._update_branch("develop")
|
|
113
|
+
|
|
114
|
+
# Update all feature branches - skip in test environment to speed up tests
|
|
115
|
+
if not self.skip_remote_ops:
|
|
116
|
+
self._update_feature_branches()
|
|
117
|
+
|
|
118
|
+
# Switch back to develop branch as a safe default
|
|
119
|
+
log_info("Switching back to develop branch...")
|
|
120
|
+
self.git_flow_manager.git_utility.run_git_command(
|
|
121
|
+
["git", "checkout", "develop"], description="Switch to develop branch"
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
def _update_branch(self, branch_name: str) -> bool:
|
|
125
|
+
"""
|
|
126
|
+
Update a specific git branch.
|
|
127
|
+
|
|
128
|
+
Args:
|
|
129
|
+
branch_name: Name of the branch to update
|
|
130
|
+
|
|
131
|
+
Returns:
|
|
132
|
+
bool: True if branch was updated successfully
|
|
133
|
+
"""
|
|
134
|
+
success = False
|
|
135
|
+
|
|
136
|
+
if self.git_flow_manager.git_utility.run_git_command(
|
|
137
|
+
["git", "fetch", "origin", branch_name],
|
|
138
|
+
description=f"Fetch {branch_name} branch",
|
|
139
|
+
):
|
|
140
|
+
if self.git_flow_manager.git_utility.run_git_command(
|
|
141
|
+
["git", "checkout", branch_name],
|
|
142
|
+
description=f"Checkout {branch_name} branch",
|
|
143
|
+
):
|
|
144
|
+
if self.git_flow_manager.git_utility.run_git_command(
|
|
145
|
+
["git", "pull", "origin", branch_name],
|
|
146
|
+
description=f"Pull {branch_name} branch",
|
|
147
|
+
):
|
|
148
|
+
log_info_pair(
|
|
149
|
+
f"✓ {branch_name} branch updated successfully",
|
|
150
|
+
f"✓ {branch_name}分支更新完成",
|
|
151
|
+
)
|
|
152
|
+
success = True
|
|
153
|
+
|
|
154
|
+
return success
|
|
155
|
+
|
|
156
|
+
def _update_feature_branches(self) -> None:
|
|
157
|
+
"""
|
|
158
|
+
Update all feature branches in the repository.
|
|
159
|
+
"""
|
|
160
|
+
log_info_pair(
|
|
161
|
+
"Updating all feature branches...", "拉取所有feature分支最新变更..."
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
try:
|
|
165
|
+
# Get all remote feature branches
|
|
166
|
+
result = subprocess.run(
|
|
167
|
+
["git", "branch", "-r"],
|
|
168
|
+
check=True,
|
|
169
|
+
capture_output=True,
|
|
170
|
+
env=self.env,
|
|
171
|
+
text=True,
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
# Parse feature branches
|
|
175
|
+
feature_branches = [
|
|
176
|
+
line.strip()
|
|
177
|
+
for line in result.stdout.split("\n")
|
|
178
|
+
if line.strip().startswith("origin/feature/")
|
|
179
|
+
]
|
|
180
|
+
|
|
181
|
+
# Update each feature branch
|
|
182
|
+
success_count = 0
|
|
183
|
+
for branch in feature_branches:
|
|
184
|
+
branch_name = branch.replace("origin/", "")
|
|
185
|
+
log_info_pair(f"Updating {branch_name}...", f"拉取{branch_name}...")
|
|
186
|
+
|
|
187
|
+
if self.git_flow_manager.git_utility.run_git_command(
|
|
188
|
+
["git", "fetch", "origin", branch_name],
|
|
189
|
+
description=f"Fetch {branch_name}",
|
|
190
|
+
):
|
|
191
|
+
success_count += 1
|
|
192
|
+
|
|
193
|
+
# Report results
|
|
194
|
+
if feature_branches:
|
|
195
|
+
total_count = len(feature_branches)
|
|
196
|
+
log_info_pair(
|
|
197
|
+
f"✓ Updated {success_count}/{total_count} feature branches",
|
|
198
|
+
f"✓ 已更新 {success_count}/{total_count} 个feature分支",
|
|
199
|
+
)
|
|
200
|
+
else:
|
|
201
|
+
log_info_pair("✓ No feature branches found", "✓ 未找到feature分支")
|
|
202
|
+
|
|
203
|
+
except subprocess.CalledProcessError as e:
|
|
204
|
+
log_info_pair(
|
|
205
|
+
f"Warning: Failed to list feature branches: {e.stderr}",
|
|
206
|
+
f"警告: 列出feature分支失败: {e.stderr}",
|
|
207
|
+
)
|
|
208
|
+
except Exception as e:
|
|
209
|
+
log_info_pair(
|
|
210
|
+
f"Warning: Failed to update feature branches: {e}",
|
|
211
|
+
f"警告: 更新feature分支失败: {e}",
|
|
212
|
+
)
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"""Internationalization manager utility."""
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class I18nManager:
|
|
5
|
+
"""Manager for internationalization support."""
|
|
6
|
+
|
|
7
|
+
def __init__(self, default_lang: str = "en") -> None:
|
|
8
|
+
self.default_lang = default_lang
|
|
9
|
+
self.current_lang = default_lang
|
|
10
|
+
self.translations: dict[str, dict[str, str]] = {}
|
|
11
|
+
self._load_default_translations()
|
|
12
|
+
|
|
13
|
+
def _load_default_translations(self) -> None:
|
|
14
|
+
"""Load default translations."""
|
|
15
|
+
# Default translations for initenv module
|
|
16
|
+
default_translations = {
|
|
17
|
+
"git_init_start": {
|
|
18
|
+
"en": "Initializing Git repository...",
|
|
19
|
+
"zh": "初始化Git仓库...",
|
|
20
|
+
},
|
|
21
|
+
"git_init_success": {
|
|
22
|
+
"en": "✓ Git repository initialized",
|
|
23
|
+
"zh": "✓ Git仓库初始化完成",
|
|
24
|
+
},
|
|
25
|
+
"git_init_skip": {
|
|
26
|
+
"en": "Git repository already exists, skipping initialization",
|
|
27
|
+
"zh": "Git仓库已存在,跳过初始化",
|
|
28
|
+
},
|
|
29
|
+
"git_init_fail": {
|
|
30
|
+
"en": "Warning: Failed to initialize Git repository",
|
|
31
|
+
"zh": "警告: 初始化Git仓库失败",
|
|
32
|
+
},
|
|
33
|
+
"project_structure_start": {
|
|
34
|
+
"en": "Setting up project structure...",
|
|
35
|
+
"zh": "设置项目结构...",
|
|
36
|
+
},
|
|
37
|
+
"project_structure_success": {
|
|
38
|
+
"en": "✓ Project structure created successfully",
|
|
39
|
+
"zh": "✓ 项目结构创建成功",
|
|
40
|
+
},
|
|
41
|
+
"project_structure_fail": {
|
|
42
|
+
"en": "Warning: Failed to setup project structure",
|
|
43
|
+
"zh": "警告: 设置项目结构失败",
|
|
44
|
+
},
|
|
45
|
+
"rust_init_start": {
|
|
46
|
+
"en": "Initializing Rust environment...",
|
|
47
|
+
"zh": "初始化Rust环境...",
|
|
48
|
+
},
|
|
49
|
+
"rust_init_success": {
|
|
50
|
+
"en": "✓ Rust project initialized successfully",
|
|
51
|
+
"zh": "✓ Rust项目初始化成功",
|
|
52
|
+
},
|
|
53
|
+
"rust_init_fail": {
|
|
54
|
+
"en": "Warning: Failed to initialize Rust environment",
|
|
55
|
+
"zh": "警告: 初始化Rust环境失败",
|
|
56
|
+
},
|
|
57
|
+
"venv_create_start": {
|
|
58
|
+
"en": "Creating virtual environment...",
|
|
59
|
+
"zh": "创建虚拟环境...",
|
|
60
|
+
},
|
|
61
|
+
"venv_create_success": {
|
|
62
|
+
"en": "✓ Virtual environment created successfully",
|
|
63
|
+
"zh": "✓ 虚拟环境创建成功",
|
|
64
|
+
},
|
|
65
|
+
"venv_create_fail": {
|
|
66
|
+
"en": "Warning: Failed to create virtual environment",
|
|
67
|
+
"zh": "警告: 创建虚拟环境失败",
|
|
68
|
+
},
|
|
69
|
+
"init_complete": {
|
|
70
|
+
"en": "Project environment initialization completed!",
|
|
71
|
+
"zh": "项目环境初始化完成!",
|
|
72
|
+
},
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
for key, translations in default_translations.items():
|
|
76
|
+
self.add_translation(key, translations)
|
|
77
|
+
|
|
78
|
+
def add_translation(self, key: str, translations: dict[str, str]) -> None:
|
|
79
|
+
"""Add translation for a key."""
|
|
80
|
+
self.translations[key] = translations
|
|
81
|
+
|
|
82
|
+
def get_text(self, key: str, lang: str | None = None) -> str:
|
|
83
|
+
"""Get translated text by key."""
|
|
84
|
+
if key not in self.translations:
|
|
85
|
+
return key
|
|
86
|
+
|
|
87
|
+
target_lang = lang or self.current_lang
|
|
88
|
+
translations = self.translations[key]
|
|
89
|
+
|
|
90
|
+
if target_lang in translations:
|
|
91
|
+
return translations[target_lang]
|
|
92
|
+
|
|
93
|
+
if self.default_lang in translations:
|
|
94
|
+
return translations[self.default_lang]
|
|
95
|
+
|
|
96
|
+
# Return first available translation
|
|
97
|
+
if translations:
|
|
98
|
+
return next(iter(translations.values()))
|
|
99
|
+
|
|
100
|
+
return key
|
|
101
|
+
|
|
102
|
+
def t(self, key: str, lang: str | None = None) -> str:
|
|
103
|
+
"""Shortcut for get_text."""
|
|
104
|
+
return self.get_text(key, lang)
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
"""Log manager utility for initenv module."""
|
|
2
|
+
|
|
3
|
+
import time
|
|
4
|
+
from collections.abc import Callable
|
|
5
|
+
from functools import wraps
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
from ....utils.log_levels import LogLevel
|
|
9
|
+
from ....utils.logging import (
|
|
10
|
+
StructuredLogger,
|
|
11
|
+
clear_log_context,
|
|
12
|
+
get_logger,
|
|
13
|
+
log_debug,
|
|
14
|
+
log_error,
|
|
15
|
+
log_exception,
|
|
16
|
+
log_info,
|
|
17
|
+
log_warning,
|
|
18
|
+
pop_log_context,
|
|
19
|
+
push_log_context,
|
|
20
|
+
)
|
|
21
|
+
from ....utils.logging import configure_logging as global_configure_logging
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class LogManager:
|
|
25
|
+
"""Manager for logging with levels - now using unified logging system."""
|
|
26
|
+
|
|
27
|
+
def __init__(self, name: str = "initenv") -> None:
|
|
28
|
+
self.logger: StructuredLogger = get_logger(name)
|
|
29
|
+
# Set default log level to INFO to match test expectations
|
|
30
|
+
self.logger.min_level = LogLevel.INFO
|
|
31
|
+
|
|
32
|
+
def info(self, message: str, lang: str = "en", **kwargs) -> None:
|
|
33
|
+
"""Log info message."""
|
|
34
|
+
log_info(message, lang=lang, **kwargs)
|
|
35
|
+
|
|
36
|
+
def warning(self, message: str, **kwargs) -> None:
|
|
37
|
+
"""Log warning message."""
|
|
38
|
+
log_warning(message, **kwargs)
|
|
39
|
+
|
|
40
|
+
def error(self, message: str, **kwargs) -> None:
|
|
41
|
+
"""Log error message."""
|
|
42
|
+
log_error(message, **kwargs)
|
|
43
|
+
|
|
44
|
+
def debug(self, message: str, **kwargs) -> None:
|
|
45
|
+
"""Log debug message."""
|
|
46
|
+
log_debug(message, **kwargs)
|
|
47
|
+
|
|
48
|
+
def push_context(self, **context) -> None:
|
|
49
|
+
"""Push context to the logger's context stack."""
|
|
50
|
+
if hasattr(self.logger, "push_context"):
|
|
51
|
+
self.logger.push_context(**context)
|
|
52
|
+
else:
|
|
53
|
+
push_log_context(**context)
|
|
54
|
+
|
|
55
|
+
def pop_context(self) -> dict[str, Any] | None:
|
|
56
|
+
"""Pop context from the logger's context stack."""
|
|
57
|
+
if hasattr(self.logger, "pop_context"):
|
|
58
|
+
return self.logger.pop_context()
|
|
59
|
+
else:
|
|
60
|
+
return pop_log_context()
|
|
61
|
+
|
|
62
|
+
def clear_context(self) -> None:
|
|
63
|
+
"""Clear all context from the logger's context stack."""
|
|
64
|
+
if hasattr(self.logger, "clear_context"):
|
|
65
|
+
self.logger.clear_context()
|
|
66
|
+
else:
|
|
67
|
+
clear_log_context()
|
|
68
|
+
|
|
69
|
+
@staticmethod
|
|
70
|
+
def configure_logging(**kwargs) -> None:
|
|
71
|
+
"""
|
|
72
|
+
Configure logging based on command-line arguments.
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
**kwargs: Command-line arguments including logging configuration
|
|
76
|
+
"""
|
|
77
|
+
from wl_cli.utils.config import get_config_manager
|
|
78
|
+
|
|
79
|
+
config_manager = get_config_manager()
|
|
80
|
+
|
|
81
|
+
# Get logging configuration from kwargs
|
|
82
|
+
log_level = kwargs.get("log_level")
|
|
83
|
+
log_console = kwargs.get("log_console")
|
|
84
|
+
log_file = kwargs.get("log_file")
|
|
85
|
+
log_format = kwargs.get("log_format")
|
|
86
|
+
log_rotation = kwargs.get("log_rotation")
|
|
87
|
+
|
|
88
|
+
# Update configuration
|
|
89
|
+
config_updates = {}
|
|
90
|
+
if log_level:
|
|
91
|
+
config_updates["log_level"] = log_level
|
|
92
|
+
if log_console is not None:
|
|
93
|
+
config_updates["log_console"] = log_console
|
|
94
|
+
if log_file:
|
|
95
|
+
config_updates["log_file"] = log_file
|
|
96
|
+
if log_format:
|
|
97
|
+
config_updates["log_file_format"] = log_format
|
|
98
|
+
if log_rotation:
|
|
99
|
+
config_updates["log_max_size"] = log_rotation
|
|
100
|
+
|
|
101
|
+
# Apply configuration updates
|
|
102
|
+
for key, value in config_updates.items():
|
|
103
|
+
config_manager.set(key, value)
|
|
104
|
+
|
|
105
|
+
# Configure the global logger
|
|
106
|
+
if config_updates:
|
|
107
|
+
global_configure_logging(config_updates)
|
|
108
|
+
|
|
109
|
+
@staticmethod
|
|
110
|
+
def get_logger(
|
|
111
|
+
name: str = "initenv", config: dict[str, Any] | None = None
|
|
112
|
+
) -> StructuredLogger:
|
|
113
|
+
"""
|
|
114
|
+
Get a logger instance with the specified name and configuration.
|
|
115
|
+
|
|
116
|
+
Args:
|
|
117
|
+
name (str): Logger name.
|
|
118
|
+
config (Optional[Dict[str, Any]]): Logger configuration.
|
|
119
|
+
|
|
120
|
+
Returns:
|
|
121
|
+
StructuredLogger: Logger instance.
|
|
122
|
+
"""
|
|
123
|
+
return get_logger(name, config)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def performance_monitor(func: Callable[..., Any]) -> Callable[..., Any]:
|
|
127
|
+
"""Decorator to monitor function execution time and add context."""
|
|
128
|
+
|
|
129
|
+
@wraps(func)
|
|
130
|
+
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
131
|
+
# Add function context
|
|
132
|
+
context = {"function": func.__name__, "module": func.__module__}
|
|
133
|
+
push_log_context(**context)
|
|
134
|
+
|
|
135
|
+
start_time = time.time()
|
|
136
|
+
log_info(f"Starting {func.__name__}...")
|
|
137
|
+
|
|
138
|
+
try:
|
|
139
|
+
result = func(*args, **kwargs)
|
|
140
|
+
end_time = time.time()
|
|
141
|
+
execution_time = end_time - start_time
|
|
142
|
+
log_info(
|
|
143
|
+
f"Finished {func.__name__} in {execution_time:.2f} seconds",
|
|
144
|
+
duration=execution_time,
|
|
145
|
+
result="success",
|
|
146
|
+
)
|
|
147
|
+
return result
|
|
148
|
+
except Exception as e:
|
|
149
|
+
end_time = time.time()
|
|
150
|
+
execution_time = end_time - start_time
|
|
151
|
+
log_exception(
|
|
152
|
+
f"Error in {func.__name__} after {execution_time:.2f} seconds",
|
|
153
|
+
exc_info=e,
|
|
154
|
+
duration=execution_time,
|
|
155
|
+
result="error",
|
|
156
|
+
)
|
|
157
|
+
raise
|
|
158
|
+
finally:
|
|
159
|
+
pop_log_context()
|
|
160
|
+
|
|
161
|
+
return wrapper
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def log_context(**context) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
|
|
165
|
+
"""Decorator to add context to log messages."""
|
|
166
|
+
|
|
167
|
+
def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
|
|
168
|
+
@wraps(func)
|
|
169
|
+
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
170
|
+
push_log_context(**context)
|
|
171
|
+
try:
|
|
172
|
+
return func(*args, **kwargs)
|
|
173
|
+
finally:
|
|
174
|
+
pop_log_context()
|
|
175
|
+
|
|
176
|
+
return wrapper
|
|
177
|
+
|
|
178
|
+
return decorator
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def error_handler(func: Callable[..., Any]) -> Callable[..., Any]:
|
|
182
|
+
"""Decorator to handle and log errors."""
|
|
183
|
+
|
|
184
|
+
@wraps(func)
|
|
185
|
+
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
186
|
+
try:
|
|
187
|
+
return func(*args, **kwargs)
|
|
188
|
+
except Exception as e:
|
|
189
|
+
log_exception(f"Error in {func.__name__}", exc_info=e)
|
|
190
|
+
raise
|
|
191
|
+
|
|
192
|
+
return wrapper
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def debug_only(func: Callable[..., Any]) -> Callable[..., Any]:
|
|
196
|
+
"""Decorator to only execute function in debug mode."""
|
|
197
|
+
|
|
198
|
+
@wraps(func)
|
|
199
|
+
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
200
|
+
logger = get_logger(func.__module__)
|
|
201
|
+
if logger.min_level <= LogLevel.DEBUG:
|
|
202
|
+
return func(*args, **kwargs)
|
|
203
|
+
return None
|
|
204
|
+
|
|
205
|
+
return wrapper
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def timed_operation(
|
|
209
|
+
description: str,
|
|
210
|
+
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
|
|
211
|
+
"""Decorator to time and log an operation with a description."""
|
|
212
|
+
|
|
213
|
+
def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
|
|
214
|
+
@wraps(func)
|
|
215
|
+
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
216
|
+
start_time = time.time()
|
|
217
|
+
log_info(f"Starting {description}...")
|
|
218
|
+
try:
|
|
219
|
+
result = func(*args, **kwargs)
|
|
220
|
+
end_time = time.time()
|
|
221
|
+
execution_time = end_time - start_time
|
|
222
|
+
log_info(
|
|
223
|
+
f"Finished {description} in {execution_time:.2f} seconds",
|
|
224
|
+
duration=execution_time,
|
|
225
|
+
operation=description,
|
|
226
|
+
)
|
|
227
|
+
return result
|
|
228
|
+
except Exception as e:
|
|
229
|
+
end_time = time.time()
|
|
230
|
+
execution_time = end_time - start_time
|
|
231
|
+
log_exception(
|
|
232
|
+
f"Error in {description} after {execution_time:.2f} seconds",
|
|
233
|
+
exc_info=e,
|
|
234
|
+
duration=execution_time,
|
|
235
|
+
operation=description,
|
|
236
|
+
)
|
|
237
|
+
raise
|
|
238
|
+
|
|
239
|
+
return wrapper
|
|
240
|
+
|
|
241
|
+
return decorator
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""Project structure utilities package."""
|
|
2
|
+
|
|
3
|
+
from .directory_creator import (
|
|
4
|
+
_create_init_files,
|
|
5
|
+
_create_readme,
|
|
6
|
+
_create_required_directories,
|
|
7
|
+
_normalize_project_name,
|
|
8
|
+
normalize_project_name,
|
|
9
|
+
setup_project_structure,
|
|
10
|
+
)
|
|
11
|
+
from .hooks_manager import sync_hooks
|
|
12
|
+
from .setup_handler import ProjectStructureSetup
|
|
13
|
+
|
|
14
|
+
__all__ = [
|
|
15
|
+
"ProjectStructureSetup",
|
|
16
|
+
"setup_project_structure",
|
|
17
|
+
"sync_hooks",
|
|
18
|
+
"_create_required_directories",
|
|
19
|
+
"_create_init_files",
|
|
20
|
+
"_create_readme",
|
|
21
|
+
"_normalize_project_name",
|
|
22
|
+
"normalize_project_name",
|
|
23
|
+
]
|