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,169 @@
|
|
|
1
|
+
"""初始化项目命令"""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
import click
|
|
6
|
+
|
|
7
|
+
from ...exceptions import CommandError
|
|
8
|
+
from ..lfs.initializer import LfsLockInitializer, lfs_lock_init_failure_message
|
|
9
|
+
from .components.git.git_flow_manager import GitFlowManager
|
|
10
|
+
from .components.git_initializer import GitInitializer
|
|
11
|
+
from .services.environment_initializer import EnvironmentInitializer
|
|
12
|
+
from .services.git_lfs_initializer import GitLfsInitializer
|
|
13
|
+
from .services.project_structure_initializer import ProjectStructureInitializer
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@click.group(
|
|
17
|
+
invoke_without_command=True,
|
|
18
|
+
context_settings={"help_option_names": ["-h", "--help"]},
|
|
19
|
+
)
|
|
20
|
+
@click.option(
|
|
21
|
+
"-v",
|
|
22
|
+
"--verbose",
|
|
23
|
+
is_flag=True,
|
|
24
|
+
help="Enable verbose output showing detailed progress information",
|
|
25
|
+
)
|
|
26
|
+
@click.option(
|
|
27
|
+
"--log-level",
|
|
28
|
+
type=click.Choice(["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]),
|
|
29
|
+
help="Set the log level for the project",
|
|
30
|
+
)
|
|
31
|
+
@click.option(
|
|
32
|
+
"--log-console",
|
|
33
|
+
is_flag=True,
|
|
34
|
+
help="Enable console logging",
|
|
35
|
+
)
|
|
36
|
+
@click.option(
|
|
37
|
+
"--log-file",
|
|
38
|
+
help="Set the log file path",
|
|
39
|
+
)
|
|
40
|
+
def initenv_group(
|
|
41
|
+
verbose: bool, log_level: str | None, log_console: bool, log_file: str | None
|
|
42
|
+
) -> None:
|
|
43
|
+
"""Initialize project environment or project structure.
|
|
44
|
+
|
|
45
|
+
Use one of the subcommands: env, project, git, lfs, work
|
|
46
|
+
|
|
47
|
+
If no subcommand is specified, defaults to 'env'.
|
|
48
|
+
"""
|
|
49
|
+
ctx = click.get_current_context()
|
|
50
|
+
if ctx.invoked_subcommand is None:
|
|
51
|
+
_execute_env_command(verbose, log_level, log_console, log_file)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _execute_env_command(
|
|
55
|
+
verbose: bool, log_level: str | None, log_console: bool, log_file: str | None
|
|
56
|
+
) -> None:
|
|
57
|
+
"""Execute the env command logic."""
|
|
58
|
+
env_initializer = EnvironmentInitializer(env=os.environ.copy())
|
|
59
|
+
kwargs: dict = {"verbose": verbose}
|
|
60
|
+
if log_level:
|
|
61
|
+
kwargs["log_level"] = log_level
|
|
62
|
+
if log_console:
|
|
63
|
+
kwargs["log_console"] = True
|
|
64
|
+
if log_file:
|
|
65
|
+
kwargs["log_file"] = log_file
|
|
66
|
+
try:
|
|
67
|
+
env_initializer.initialize(**kwargs)
|
|
68
|
+
except CommandError as exc:
|
|
69
|
+
# Surface the failure as a Click error so ``wl init env`` / bare
|
|
70
|
+
# ``wl init`` exit non-zero instead of reporting success.
|
|
71
|
+
raise click.ClickException(str(exc)) from exc
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@initenv_group.command()
|
|
75
|
+
@click.option(
|
|
76
|
+
"-v",
|
|
77
|
+
"--verbose",
|
|
78
|
+
is_flag=True,
|
|
79
|
+
help="Enable verbose output showing detailed progress information",
|
|
80
|
+
)
|
|
81
|
+
@click.option(
|
|
82
|
+
"--log-level",
|
|
83
|
+
type=click.Choice(["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]),
|
|
84
|
+
help="Set the log level for the project",
|
|
85
|
+
)
|
|
86
|
+
@click.option(
|
|
87
|
+
"--log-console",
|
|
88
|
+
is_flag=True,
|
|
89
|
+
help="Enable console logging",
|
|
90
|
+
)
|
|
91
|
+
@click.option(
|
|
92
|
+
"--log-file",
|
|
93
|
+
help="Set the log file path",
|
|
94
|
+
)
|
|
95
|
+
def env(
|
|
96
|
+
verbose: bool, log_level: str | None, log_console: bool, log_file: str | None
|
|
97
|
+
) -> None:
|
|
98
|
+
"""Initialize project environment."""
|
|
99
|
+
_execute_env_command(verbose, log_level, log_console, log_file)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
@initenv_group.command()
|
|
103
|
+
@click.option(
|
|
104
|
+
"--workspace/--no-workspace",
|
|
105
|
+
default=True,
|
|
106
|
+
help="Initialize project as uv workspace (packages/* layout) or flat layout (default: workspace)",
|
|
107
|
+
)
|
|
108
|
+
def project(workspace: bool) -> None:
|
|
109
|
+
"""Initialize project structure."""
|
|
110
|
+
project_initializer = ProjectStructureInitializer()
|
|
111
|
+
project_initializer.initialize(workspace=workspace)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
@initenv_group.command()
|
|
115
|
+
@click.argument(
|
|
116
|
+
"work_type",
|
|
117
|
+
type=click.Choice(["feature", "fix", "hotfix", "release"]),
|
|
118
|
+
)
|
|
119
|
+
def work(work_type: str) -> None:
|
|
120
|
+
"""Initialize Git Flow work environment."""
|
|
121
|
+
env = dict(os.environ)
|
|
122
|
+
skip_remote_ops = os.environ.get("PYTEST_CURRENT_TEST") is not None
|
|
123
|
+
manager = GitFlowManager(env, skip_remote_ops=skip_remote_ops)
|
|
124
|
+
manager.setup_git_flow_branches_by_work_type(work_type)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
@initenv_group.command()
|
|
128
|
+
def git() -> None:
|
|
129
|
+
"""Initialize Git repository."""
|
|
130
|
+
env = dict(os.environ)
|
|
131
|
+
skip_remote_ops = os.environ.get("PYTEST_CURRENT_TEST") is not None
|
|
132
|
+
initializer = GitInitializer(env, skip_remote_ops=skip_remote_ops)
|
|
133
|
+
initializer.initialize()
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
@initenv_group.command()
|
|
137
|
+
@click.option(
|
|
138
|
+
"--fix",
|
|
139
|
+
is_flag=True,
|
|
140
|
+
help="Automatically fix issues like nested .git directories when initializing LFS",
|
|
141
|
+
)
|
|
142
|
+
@click.option(
|
|
143
|
+
"--with-locks",
|
|
144
|
+
is_flag=True,
|
|
145
|
+
help="Initialize LFS lock workflow configuration",
|
|
146
|
+
)
|
|
147
|
+
def lfs(fix: bool, with_locks: bool) -> None:
|
|
148
|
+
"""Initialize Git LFS."""
|
|
149
|
+
lock_initializer = LfsLockInitializer() if with_locks else None
|
|
150
|
+
# Probe the lock workflow's precondition before the Git LFS step mutates
|
|
151
|
+
# the repository (filters, hooks, config): failing afterwards would leave
|
|
152
|
+
# the project half-initialized (#198).
|
|
153
|
+
if lock_initializer is not None and not lock_initializer.wl_dir_ready():
|
|
154
|
+
raise click.ClickException(
|
|
155
|
+
lfs_lock_init_failure_message(lock_initializer.project_root)
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
lfs_initializer = GitLfsInitializer()
|
|
159
|
+
lfs_initializer.initialize(auto_fix=fix)
|
|
160
|
+
|
|
161
|
+
if lock_initializer is not None and lock_initializer.initialize() is False:
|
|
162
|
+
raise click.ClickException(
|
|
163
|
+
lfs_lock_init_failure_message(lock_initializer.project_root)
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def initenv() -> click.Group:
|
|
168
|
+
"""Return the initenv Click group for registration."""
|
|
169
|
+
return initenv_group
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"""Business services for initenv module."""
|
|
2
|
+
|
|
3
|
+
from .environment_initializer import EnvironmentInitializer
|
|
4
|
+
from .git_lfs_initializer import GitLfsInitializer
|
|
5
|
+
from .project_structure_initializer import ProjectStructureInitializer
|
|
6
|
+
|
|
7
|
+
__all__ = [
|
|
8
|
+
"EnvironmentInitializer",
|
|
9
|
+
"ProjectStructureInitializer",
|
|
10
|
+
"GitLfsInitializer",
|
|
11
|
+
]
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
"""Environment initialization coordinator."""
|
|
2
|
+
|
|
3
|
+
import subprocess
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
from ....exceptions import CommandError
|
|
7
|
+
from ....utils.logging import (
|
|
8
|
+
log_debug,
|
|
9
|
+
log_debug_pair,
|
|
10
|
+
log_error_pair,
|
|
11
|
+
log_info_pair,
|
|
12
|
+
)
|
|
13
|
+
from ....utils.platform_adapter import PlatformAdapter
|
|
14
|
+
from ....utils.workspace_detector import WorkspaceDetector
|
|
15
|
+
from ..common import error_handler
|
|
16
|
+
from ..components import (
|
|
17
|
+
cargo_sync,
|
|
18
|
+
config_manager,
|
|
19
|
+
i18n_manager,
|
|
20
|
+
log_manager,
|
|
21
|
+
pyproject_generator,
|
|
22
|
+
rust_initializer,
|
|
23
|
+
venv_manager,
|
|
24
|
+
)
|
|
25
|
+
from ..components.project_structure.setup_handler import ProjectStructureSetup
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class EnvironmentInitializer:
|
|
29
|
+
"""Coordinator for project initialization."""
|
|
30
|
+
|
|
31
|
+
def __init__(self, env: dict[str, str]) -> None:
|
|
32
|
+
self.env = env
|
|
33
|
+
self.project_name = Path.cwd().name
|
|
34
|
+
self.config_manager = config_manager.ConfigManager()
|
|
35
|
+
self.i18n_manager = i18n_manager.I18nManager()
|
|
36
|
+
self.log_manager = log_manager.LogManager()
|
|
37
|
+
self.workspace_detector = WorkspaceDetector()
|
|
38
|
+
|
|
39
|
+
# Initialize sub-components
|
|
40
|
+
self.project_structure_setup = ProjectStructureSetup()
|
|
41
|
+
self.rust_initializer = rust_initializer.RustInitializer()
|
|
42
|
+
self.venv_manager = venv_manager.VenvManager(env)
|
|
43
|
+
|
|
44
|
+
@error_handler("Failed to initialize project environment")
|
|
45
|
+
def initialize(self, **kwargs) -> None:
|
|
46
|
+
"""
|
|
47
|
+
Initialize complete project environment.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
**kwargs: Command line arguments including log configuration parameters
|
|
51
|
+
"""
|
|
52
|
+
log_info_pair(
|
|
53
|
+
"=== Starting initialization of project environment ===",
|
|
54
|
+
"=== 开始初始化项目环境 ===",
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
# Check uv installation
|
|
58
|
+
self.check_uv_installed()
|
|
59
|
+
|
|
60
|
+
# Apply logging configuration
|
|
61
|
+
log_manager.LogManager.configure_logging(**kwargs)
|
|
62
|
+
|
|
63
|
+
# Check if project is already initialized
|
|
64
|
+
is_initialized = self.is_project_initialized()
|
|
65
|
+
|
|
66
|
+
if is_initialized:
|
|
67
|
+
log_info_pair(
|
|
68
|
+
"=== Project already initialized, performing daily update ===",
|
|
69
|
+
"=== 项目已初始化,执行每日更新 ===",
|
|
70
|
+
)
|
|
71
|
+
# Execute update process
|
|
72
|
+
self.update_project()
|
|
73
|
+
else:
|
|
74
|
+
# Execute full initialization process
|
|
75
|
+
# Setup project structure (don't use workspace config, don't copy template pyproject.toml)
|
|
76
|
+
# pyproject.toml will be generated by PyProjectGenerator with complete configuration
|
|
77
|
+
self.setup_project_structure(use_workspace=False, copy_pyproject=False)
|
|
78
|
+
|
|
79
|
+
# Initialize Rust if needed
|
|
80
|
+
self.init_rust()
|
|
81
|
+
|
|
82
|
+
# Generate pyproject.toml if needed
|
|
83
|
+
# Run after init_rust to correctly detect Rust environment
|
|
84
|
+
self.generate_pyproject()
|
|
85
|
+
|
|
86
|
+
# Sync Cargo.toml with pyproject.toml
|
|
87
|
+
self.sync_cargo_toml()
|
|
88
|
+
|
|
89
|
+
# Create virtual environment
|
|
90
|
+
self.create_venv()
|
|
91
|
+
|
|
92
|
+
# Platform-specific finalization
|
|
93
|
+
self._finalize()
|
|
94
|
+
|
|
95
|
+
log_info_pair(
|
|
96
|
+
"Project environment initialization completed!",
|
|
97
|
+
"项目环境初始化完成!",
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
@staticmethod
|
|
101
|
+
def _finalize() -> None:
|
|
102
|
+
"""Run the platform-specific finalization step.
|
|
103
|
+
|
|
104
|
+
The former ``_finalize_windows`` and ``_finalize_unix`` differed only
|
|
105
|
+
in the label they logged, so the platform is read from
|
|
106
|
+
:class:`PlatformAdapter` here rather than branched on by the caller.
|
|
107
|
+
"""
|
|
108
|
+
if PlatformAdapter.is_windows():
|
|
109
|
+
log_info_pair(
|
|
110
|
+
"✓ Windows-specific finalization completed",
|
|
111
|
+
"✓ Windows特定的最终化完成",
|
|
112
|
+
)
|
|
113
|
+
else:
|
|
114
|
+
log_info_pair(
|
|
115
|
+
"✓ Unix-specific finalization completed",
|
|
116
|
+
"✓ Unix特定的最终化完成",
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
@error_handler("Failed to check uv installation")
|
|
120
|
+
def check_uv_installed(self) -> None:
|
|
121
|
+
"""Check if uv is installed."""
|
|
122
|
+
subprocess.run(
|
|
123
|
+
["uv", "--version"], check=True, capture_output=True, env=self.env
|
|
124
|
+
)
|
|
125
|
+
log_info_pair(
|
|
126
|
+
"✓ uv command found.",
|
|
127
|
+
"✓ 找到 uv 命令。",
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
@error_handler("Failed to setup project structure")
|
|
131
|
+
def setup_project_structure(
|
|
132
|
+
self, use_workspace: bool | None = None, copy_pyproject: bool = True
|
|
133
|
+
) -> None:
|
|
134
|
+
"""Setup project structure.
|
|
135
|
+
|
|
136
|
+
Args:
|
|
137
|
+
use_workspace: If True, use pyproject.toml with workspace config.
|
|
138
|
+
If False, use pyproject.toml without workspace config.
|
|
139
|
+
If None, auto-detect based on current environment.
|
|
140
|
+
copy_pyproject: If True, copy pyproject.toml from template.
|
|
141
|
+
If False, skip pyproject.toml (will be generated by PyProjectGenerator).
|
|
142
|
+
"""
|
|
143
|
+
log_debug_pair(
|
|
144
|
+
"Setting up project structure...",
|
|
145
|
+
"设置项目结构...",
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
# Determine workspace mode
|
|
149
|
+
if use_workspace is None:
|
|
150
|
+
# Auto-detect if we're in a uv workspace environment
|
|
151
|
+
is_workspace = self.workspace_detector.detect(Path.cwd())
|
|
152
|
+
else:
|
|
153
|
+
is_workspace = use_workspace
|
|
154
|
+
|
|
155
|
+
self.project_structure_setup.setup(
|
|
156
|
+
self.project_name,
|
|
157
|
+
use_workspace=is_workspace,
|
|
158
|
+
copy_pyproject=copy_pyproject,
|
|
159
|
+
)
|
|
160
|
+
log_debug_pair(
|
|
161
|
+
"✓ Project structure setup completed",
|
|
162
|
+
"✓ 项目结构设置完成",
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
@error_handler("Failed to initialize Rust")
|
|
166
|
+
def init_rust(self) -> None:
|
|
167
|
+
"""Initialize Rust environment."""
|
|
168
|
+
log_debug_pair(
|
|
169
|
+
"Initializing Rust environment...",
|
|
170
|
+
"初始化Rust环境...",
|
|
171
|
+
)
|
|
172
|
+
self.rust_initializer.initialize()
|
|
173
|
+
log_debug_pair(
|
|
174
|
+
"✓ Rust environment initialized",
|
|
175
|
+
"✓ Rust环境初始化完成",
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
@error_handler("Failed to generate pyproject.toml")
|
|
179
|
+
def generate_pyproject(self) -> None:
|
|
180
|
+
"""Generate pyproject.toml if it doesn't exist."""
|
|
181
|
+
if not Path("pyproject.toml").exists():
|
|
182
|
+
log_debug_pair(
|
|
183
|
+
"pyproject.toml not found, generating...",
|
|
184
|
+
"未找到 pyproject.toml,正在生成...",
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
# Create PyProjectGenerator instance and generate pyproject.toml
|
|
188
|
+
generator = pyproject_generator.PyProjectGenerator(self.project_name)
|
|
189
|
+
generator.set_project_info()
|
|
190
|
+
generator.set_build_system(is_rust=Path("rust").exists())
|
|
191
|
+
generator.set_development_tools()
|
|
192
|
+
generator.generate()
|
|
193
|
+
|
|
194
|
+
log_info_pair(
|
|
195
|
+
"✓ pyproject.toml generated successfully",
|
|
196
|
+
"✓ pyproject.toml 生成成功",
|
|
197
|
+
)
|
|
198
|
+
else:
|
|
199
|
+
log_debug_pair(
|
|
200
|
+
"✓ pyproject.toml already exists, skipping generation",
|
|
201
|
+
"✓ pyproject.toml 已存在,跳过生成",
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
@error_handler("Failed to sync Cargo.toml")
|
|
205
|
+
def sync_cargo_toml(self) -> None:
|
|
206
|
+
"""Sync Cargo.toml with pyproject.toml."""
|
|
207
|
+
cargo_sync.sync_toml_files(Path("pyproject.toml"), Path("rust/Cargo.toml"))
|
|
208
|
+
log_debug("✓ rust/Cargo.toml 已成功同步和更新。")
|
|
209
|
+
|
|
210
|
+
@error_handler("Failed to create virtual environment")
|
|
211
|
+
def create_venv(self) -> None:
|
|
212
|
+
"""Create the virtual environment unless a uv workspace provides one.
|
|
213
|
+
|
|
214
|
+
The former ``_create_venv_windows`` and ``_create_venv_unix`` differed
|
|
215
|
+
only in which ``VenvManager`` entry point they reached for the same
|
|
216
|
+
destination and version; that split now lives inside
|
|
217
|
+
:meth:`VenvManager.create_venv`, which takes the environment
|
|
218
|
+
explicitly.
|
|
219
|
+
"""
|
|
220
|
+
log_debug_pair(
|
|
221
|
+
"Checking uv workspace status to determine if virtual environment should be created...",
|
|
222
|
+
"检查uv workspace状态以决定是否创建虚拟环境...",
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
if self._detect_uv_workspace():
|
|
226
|
+
log_debug_pair(
|
|
227
|
+
"✓ uv workspace environment detected, skipping local .venv creation",
|
|
228
|
+
"✓ 检测到uv workspace环境,跳过创建本地.venv",
|
|
229
|
+
)
|
|
230
|
+
else:
|
|
231
|
+
log_debug_pair(
|
|
232
|
+
"Ensuring virtual environment exists...",
|
|
233
|
+
"确保虚拟环境存在...",
|
|
234
|
+
)
|
|
235
|
+
venv_path = self.config_manager.get("venv_path", ".venv")
|
|
236
|
+
python_version = self.config_manager.get("python_version", "3.10")
|
|
237
|
+
if not self.venv_manager.create_venv(venv_path, python_version, self.env):
|
|
238
|
+
log_error_pair(
|
|
239
|
+
"✗ Failed to create the virtual environment; "
|
|
240
|
+
"see the warning above for details",
|
|
241
|
+
"✗ 虚拟环境创建失败;详情见上方警告",
|
|
242
|
+
)
|
|
243
|
+
raise CommandError("uv could not create the virtual environment")
|
|
244
|
+
log_info_pair(
|
|
245
|
+
"✓ Virtual environment created successfully",
|
|
246
|
+
"✓ 虚拟环境创建成功",
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
def _detect_uv_workspace(self) -> bool:
|
|
250
|
+
return self.workspace_detector.detect(Path.cwd())
|
|
251
|
+
|
|
252
|
+
def is_project_initialized(self) -> bool:
|
|
253
|
+
"""Check if the project is already initialized."""
|
|
254
|
+
# 检测项目是否已经初始化
|
|
255
|
+
# 检查是否存在pyproject.toml文件
|
|
256
|
+
is_pyproject_exists = Path("pyproject.toml").exists()
|
|
257
|
+
|
|
258
|
+
return is_pyproject_exists
|
|
259
|
+
|
|
260
|
+
@error_handler("Failed to update project")
|
|
261
|
+
def update_project(self) -> None:
|
|
262
|
+
"""Update the project by syncing environment."""
|
|
263
|
+
# 确保项目结构(包括.wl目录)存在
|
|
264
|
+
log_debug_pair(
|
|
265
|
+
"Ensuring project structure exists...",
|
|
266
|
+
"确保项目结构存在...",
|
|
267
|
+
)
|
|
268
|
+
self.setup_project_structure()
|
|
269
|
+
|
|
270
|
+
# 确保pyproject.toml是最新的
|
|
271
|
+
self.generate_pyproject()
|
|
272
|
+
|
|
273
|
+
# 同步Cargo.toml与pyproject.toml
|
|
274
|
+
self.sync_cargo_toml()
|
|
275
|
+
|
|
276
|
+
# 同步uv环境
|
|
277
|
+
if not self.venv_manager.sync_environment():
|
|
278
|
+
log_error_pair(
|
|
279
|
+
"✗ Failed to sync environment dependencies; "
|
|
280
|
+
"see the warning above for details",
|
|
281
|
+
"✗ 环境依赖同步失败;详情见上方警告",
|
|
282
|
+
)
|
|
283
|
+
raise CommandError("uv could not sync the environment dependencies")
|
|
284
|
+
|
|
285
|
+
log_info_pair(
|
|
286
|
+
"✓ Project update completed",
|
|
287
|
+
"✓ 项目更新完成",
|
|
288
|
+
)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""Git LFS initialization coordinator."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
from ....utils.logging import log_info_pair
|
|
6
|
+
from ..common import error_handler
|
|
7
|
+
from ..components.git.git_lfs_manager import GitLFSManager
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class GitLfsInitializer:
|
|
11
|
+
"""Coordinator for Git LFS initialization."""
|
|
12
|
+
|
|
13
|
+
@staticmethod
|
|
14
|
+
@error_handler("Failed to initialize Git LFS")
|
|
15
|
+
def initialize(*, auto_fix: bool = False) -> None:
|
|
16
|
+
"""Initialize Git LFS."""
|
|
17
|
+
log_info_pair(
|
|
18
|
+
"=== Starting initialization of Git LFS ===", "=== 开始初始化Git LFS ==="
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
# Get environment
|
|
22
|
+
env = dict(os.environ)
|
|
23
|
+
initializer = GitLFSManager(env)
|
|
24
|
+
initializer.initialize(auto_fix=auto_fix)
|
|
25
|
+
|
|
26
|
+
log_info_pair("Git LFS initialization completed!", "Git LFS初始化完成!")
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""Project structure initialization coordinator."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from ....utils.logging import log_info, log_info_pair
|
|
6
|
+
from ..common import error_handler
|
|
7
|
+
from ..components.project_structure.directory_creator import normalize_project_name
|
|
8
|
+
from ..components.project_structure.setup_handler import ProjectStructureSetup
|
|
9
|
+
from ..components.pyproject_generator import PyProjectGenerator
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class ProjectStructureInitializer:
|
|
13
|
+
"""Coordinator for project structure initialization."""
|
|
14
|
+
|
|
15
|
+
@staticmethod
|
|
16
|
+
@error_handler("Failed to initialize project structure")
|
|
17
|
+
def initialize(workspace: bool = True) -> None:
|
|
18
|
+
"""Initialize project structure.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
workspace: If True, create workspace layout (packages/{name}/).
|
|
22
|
+
If False, create flat layout (src/{name}/).
|
|
23
|
+
"""
|
|
24
|
+
log_info_pair(
|
|
25
|
+
"=== Starting initialization of project structure ===",
|
|
26
|
+
"=== 开始初始化项目结构 ===",
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
project_name = Path.cwd().name
|
|
30
|
+
project_structure_setup = ProjectStructureSetup()
|
|
31
|
+
project_structure_setup.setup(
|
|
32
|
+
project_name=project_name,
|
|
33
|
+
use_workspace=workspace,
|
|
34
|
+
copy_pyproject=workspace,
|
|
35
|
+
workspace_mode=workspace,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
if workspace:
|
|
39
|
+
normalized = normalize_project_name(project_name)
|
|
40
|
+
pkg_root = Path(f"packages/{normalized}")
|
|
41
|
+
pkg_pyproject = pkg_root / "pyproject.toml"
|
|
42
|
+
if not pkg_pyproject.exists():
|
|
43
|
+
has_rust = (pkg_root / "rust").exists()
|
|
44
|
+
generator = PyProjectGenerator(project_name)
|
|
45
|
+
generator.generate_package_pyproject(
|
|
46
|
+
str(pkg_pyproject), is_rust=has_rust
|
|
47
|
+
)
|
|
48
|
+
log_info("✓ Generated package pyproject.toml")
|
|
49
|
+
|
|
50
|
+
log_info_pair(
|
|
51
|
+
"Project structure initialization completed!", "项目结构初始化完成!"
|
|
52
|
+
)
|