fcmd 0.2.0__tar.gz → 0.2.2__tar.gz
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.
- {fcmd-0.2.0 → fcmd-0.2.2}/.bumpversion.toml +1 -1
- {fcmd-0.2.0 → fcmd-0.2.2}/PKG-INFO +4 -5
- {fcmd-0.2.0 → fcmd-0.2.2}/README.md +2 -3
- {fcmd-0.2.0 → fcmd-0.2.2}/pyproject.toml +1 -2
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/__init__.py +1 -1
- fcmd-0.2.2/src/fcmd/__main__.py +6 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/_compat.py +1 -1
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/apis/dag.py +2 -3
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/apis/task.py +0 -1
- fcmd-0.2.2/src/fcmd/cli/_env_persist.py +101 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/_profiler_helpers.py +2 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/archivex.py +4 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/asciitool.py +4 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/autofmt.py +5 -1
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/bumpversion.py +4 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/casetool.py +4 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/clr.py +5 -1
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/codetool.py +4 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/colortool.py +4 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/convtool.py +4 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/cryptool.py +4 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/csvtool.py +4 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/dockercmd.py +5 -1
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/envdev.py +123 -40
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/filedate.py +4 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/filelevel.py +4 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/filerename.py +4 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/filesearch.py +4 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/folderback.py +4 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/folderzip.py +5 -1
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/gittool.py +4 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/hashfile.py +4 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/hashtool.py +4 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/idtool.py +4 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/imagetool.py +4 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/iptool.py +4 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/jsontool.py +4 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/lscalc.py +4 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/main.py +3 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/mathtool.py +4 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/nettool.py +4 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/packtool.py +4 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/padtool.py +4 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/pathtool.py +4 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/pdftool.py +4 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/piptool.py +4 -0
- fcmd-0.2.2/src/fcmd/cli/portcheck.py +295 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/pymake.py +5 -1
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/randtool.py +4 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/regextool.py +4 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/reseticoncache.py +5 -1
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/screenshot.py +4 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/setenv.py +5 -1
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/sshcopyid.py +5 -1
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/stattool.py +4 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/sysinfo.py +4 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/taskkill.py +4 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/textdiff.py +4 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/timetool.py +4 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/txttool.py +4 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/urltool.py +4 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/which.py +5 -1
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/writefile.py +5 -1
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/xmltool.py +4 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/yamtool.py +4 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/zipencrypt.py +4 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/command.py +1 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/console.py +17 -1
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/executors.py +2 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_cli.py +0 -1
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_cli_codetool.py +15 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_cli_envdev.py +131 -17
- fcmd-0.2.2/tests/test_cli_portcheck.py +443 -0
- fcmd-0.2.2/tests/test_env_persist.py +142 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/uv.lock +1 -1
- fcmd-0.2.0/.trae/.ignore +0 -15
- fcmd-0.2.0/.trae/docs/iter-46-p45-structure-refactor.md +0 -52
- fcmd-0.2.0/.trae/docs/iter-47-p46-main-split.md +0 -94
- fcmd-0.2.0/.trae/docs/iter-48-p47-win7-rich-width.md +0 -84
- fcmd-0.2.0/.trae/docs/iter-49-p48-win7-rich-ascii.md +0 -111
- fcmd-0.2.0/.trae/docs/iter-50-p49-remove-rich.md +0 -82
- fcmd-0.2.0/.trae/req/done/req-01-/345/212/237/350/203/275/351/234/200/346/261/202.md +0 -3
- fcmd-0.2.0/.trae/rules/git-commit-message.md +0 -56
- fcmd-0.2.0/.trae/rules/rule-01-/345/274/200/345/217/221/346/265/201/347/250/213.md +0 -69
- fcmd-0.2.0/.trae/rules/rule-02-/344/272/247/347/211/251/347/272/246/346/235/237.md +0 -30
- fcmd-0.2.0/.trae/rules/rule-03-/350/247/246/345/217/221/345/234/272/346/231/257.md +0 -29
- fcmd-0.2.0/.trae/skills/python-class-design/SKILL.md +0 -518
- fcmd-0.2.0/.trae/skills/python-cli/SKILL.md +0 -718
- fcmd-0.2.0/.trae/skills/python-concurrency/SKILL.md +0 -589
- fcmd-0.2.0/.trae/skills/python-config/SKILL.md +0 -500
- fcmd-0.2.0/.trae/skills/python-file-io/SKILL.md +0 -534
- fcmd-0.2.0/.trae/skills/python-gui-pyside/LAYOUT.md +0 -285
- fcmd-0.2.0/.trae/skills/python-gui-pyside/PATTERNS.md +0 -664
- fcmd-0.2.0/.trae/skills/python-gui-pyside/SKILL.md +0 -891
- fcmd-0.2.0/.trae/skills/python-gui-pyside/UI-DESIGN.md +0 -259
- fcmd-0.2.0/.trae/skills/python-logging/SKILL.md +0 -497
- fcmd-0.2.0/.trae/skills/python-performance/SKILL.md +0 -805
- fcmd-0.2.0/.trae/skills/python-project-structure/SKILL.md +0 -907
- fcmd-0.2.0/.trae/skills/python-standards/SKILL.md +0 -145
- fcmd-0.2.0/.trae/skills/python-subprocess/SKILL.md +0 -500
- fcmd-0.2.0/.trae/skills/python-testing/SKILL.md +0 -684
- fcmd-0.2.0/src/fcmd/__main__.py +0 -6
- fcmd-0.2.0/src/fcmd/cli/basetool.py +0 -260
- fcmd-0.2.0/src/fcmd/cli/portcheck.py +0 -128
- fcmd-0.2.0/tests/test_cli_basetool.py +0 -255
- fcmd-0.2.0/tests/test_cli_portcheck.py +0 -128
- {fcmd-0.2.0 → fcmd-0.2.2}/.copier-answers.yml +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/.coveragerc +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/.gitattributes +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/.github/workflows/ci.yml +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/.github/workflows/release.yml +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/.gitignore +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/.pre-commit-config.yaml +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/.python-version +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/.readthedocs.yaml +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/.vscode/settings.json +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/LICENSE +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/Makefile +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/docs/_static/.gitkeep +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/docs/api.rst +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/docs/changelog.rst +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/docs/conf.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/docs/index.rst +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/pyrefly.toml +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/pytest.ini +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/ruff.toml +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/apis/__init__.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/apis/context.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/apis/errors.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/apis/profiling.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/apis/report.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/apis/toolkit.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/__init__.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/_common.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/cli/_completion_scripts.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/conditions.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/models/__init__.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/models/command.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/models/filefilter.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/models/version.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/py.typed +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/src/fcmd/yaml_loader.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/__init__.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_cli_archivex.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_cli_asciitool.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_cli_autofmt.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_cli_bumpversion.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_cli_casetool.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_cli_clr.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_cli_colortool.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_cli_convtool.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_cli_cryptool.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_cli_csvtool.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_cli_dockercmd.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_cli_filedate.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_cli_filelevel.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_cli_filerename.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_cli_filesearch.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_cli_folderback.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_cli_folderzip.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_cli_gittool.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_cli_hashfile.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_cli_hashtool.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_cli_idtool.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_cli_imagetool.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_cli_iptool.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_cli_jsontool.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_cli_lscalc.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_cli_mathtool.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_cli_nettool.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_cli_packtool.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_cli_padtool.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_cli_pathtool.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_cli_pdftool.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_cli_piptool.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_cli_profiler.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_cli_pymake.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_cli_randtool.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_cli_regextool.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_cli_reseticoncache.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_cli_screenshot.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_cli_setenv.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_cli_sshcopyid.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_cli_stattool.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_cli_sysinfo.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_cli_taskkill.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_cli_textdiff.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_cli_timetool.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_cli_txttool.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_cli_urltool.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_cli_which.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_cli_writefile.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_cli_xmltool.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_cli_yamtool.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_cli_zipencrypt.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_command.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_conditions.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_console.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_context.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_executors.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_fcmd.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_graph.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_init.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_models.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_profiling.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_report.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_task.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_toolkit.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tests/test_yaml_loader.py +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/tox.ini +0 -0
- {fcmd-0.2.0 → fcmd-0.2.2}/uv.toml +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: fcmd
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: 极速 Python 工具集应用:DAG 任务调度 + 组合 CLI
|
|
5
5
|
Author: fcmd
|
|
6
6
|
License: MIT
|
|
@@ -182,7 +182,7 @@ fcmd completion --shell fish | source # fish
|
|
|
182
182
|
|------|------|------|
|
|
183
183
|
| `txttool` | - | 文本处理(大小写/去重/排序/统计/截断) |
|
|
184
184
|
| `asciitool` | - | ASCII 码表(char/code/table) |
|
|
185
|
-
| `
|
|
185
|
+
| `codetool` | - | 编解码(Base64/URL/HTML/Hex/ROT13) |
|
|
186
186
|
| `casetool` | - | 命名风格转换(camel/snake/kebab/pascal) |
|
|
187
187
|
| `colortool` | - | 颜色换算(RGB/HEX/HSL/HSV) |
|
|
188
188
|
| `convtool` | - | 单位换算(长度/重量/温度/面积等) |
|
|
@@ -218,7 +218,7 @@ fcmd completion --shell fish | source # fish
|
|
|
218
218
|
| 工具 | 别名 | 说明 |
|
|
219
219
|
|------|------|------|
|
|
220
220
|
| `sysinfo` | - | 系统信息收集(Python/平台/内存/磁盘/CPU) |
|
|
221
|
-
| `portcheck` | - |
|
|
221
|
+
| `portcheck` | - | 端口检查与扫描(socket 检测占用,lsof/netstat 查询占用进程,跨平台) |
|
|
222
222
|
| `taskkill` | - | 按名称终止进程(Windows taskkill / Unix pkill) |
|
|
223
223
|
| `which` | - | 查找可执行命令路径 |
|
|
224
224
|
| `clr` | - | 跨平台清屏 |
|
|
@@ -237,7 +237,6 @@ fcmd completion --shell fish | source # fish
|
|
|
237
237
|
| `envdev` | - | 开发环境镜像源配置(Python/Conda/Rust,Linux 专用操作跳过) |
|
|
238
238
|
| `setenv` | - | 设置当前进程环境变量(支持 `--default` 仅在未设置时写入) |
|
|
239
239
|
| `sshcopyid` | - | SSH 公钥部署到远程服务器(依赖 sshpass) |
|
|
240
|
-
| `codetool` | - | 代码统计(行数/字符数/空行/注释行) |
|
|
241
240
|
|
|
242
241
|
查看任意工具的子命令与字段详情:
|
|
243
242
|
|
|
@@ -119,7 +119,7 @@ fcmd completion --shell fish | source # fish
|
|
|
119
119
|
|------|------|------|
|
|
120
120
|
| `txttool` | - | 文本处理(大小写/去重/排序/统计/截断) |
|
|
121
121
|
| `asciitool` | - | ASCII 码表(char/code/table) |
|
|
122
|
-
| `
|
|
122
|
+
| `codetool` | - | 编解码(Base64/URL/HTML/Hex/ROT13) |
|
|
123
123
|
| `casetool` | - | 命名风格转换(camel/snake/kebab/pascal) |
|
|
124
124
|
| `colortool` | - | 颜色换算(RGB/HEX/HSL/HSV) |
|
|
125
125
|
| `convtool` | - | 单位换算(长度/重量/温度/面积等) |
|
|
@@ -155,7 +155,7 @@ fcmd completion --shell fish | source # fish
|
|
|
155
155
|
| 工具 | 别名 | 说明 |
|
|
156
156
|
|------|------|------|
|
|
157
157
|
| `sysinfo` | - | 系统信息收集(Python/平台/内存/磁盘/CPU) |
|
|
158
|
-
| `portcheck` | - |
|
|
158
|
+
| `portcheck` | - | 端口检查与扫描(socket 检测占用,lsof/netstat 查询占用进程,跨平台) |
|
|
159
159
|
| `taskkill` | - | 按名称终止进程(Windows taskkill / Unix pkill) |
|
|
160
160
|
| `which` | - | 查找可执行命令路径 |
|
|
161
161
|
| `clr` | - | 跨平台清屏 |
|
|
@@ -174,7 +174,6 @@ fcmd completion --shell fish | source # fish
|
|
|
174
174
|
| `envdev` | - | 开发环境镜像源配置(Python/Conda/Rust,Linux 专用操作跳过) |
|
|
175
175
|
| `setenv` | - | 设置当前进程环境变量(支持 `--default` 仅在未设置时写入) |
|
|
176
176
|
| `sshcopyid` | - | SSH 公钥部署到远程服务器(依赖 sshpass) |
|
|
177
|
-
| `codetool` | - | 代码统计(行数/字符数/空行/注释行) |
|
|
178
177
|
|
|
179
178
|
查看任意工具的子命令与字段详情:
|
|
180
179
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "fcmd"
|
|
3
|
-
version = "0.2.
|
|
3
|
+
version = "0.2.2"
|
|
4
4
|
description = "极速 Python 工具集应用:DAG 任务调度 + 组合 CLI"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.8"
|
|
@@ -27,7 +27,6 @@ fcmd = "fcmd.cli.main:main"
|
|
|
27
27
|
archivex = "fcmd.cli.archivex:main"
|
|
28
28
|
asciitool = "fcmd.cli.asciitool:main"
|
|
29
29
|
autofmt = "fcmd.cli.autofmt:main"
|
|
30
|
-
basetool = "fcmd.cli.basetool:main"
|
|
31
30
|
bumpversion = "fcmd.cli.bumpversion:main"
|
|
32
31
|
casetool = "fcmd.cli.casetool:main"
|
|
33
32
|
clr = "fcmd.cli.clr:main"
|
|
@@ -362,9 +362,8 @@ class Graph:
|
|
|
362
362
|
def subgraph_with_deps(self, names: Iterable[str]) -> Graph:
|
|
363
363
|
"""返回包含 ``names`` 及其所有传递依赖的新图。
|
|
364
364
|
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
使子图可独立执行。
|
|
365
|
+
沿 ``depends_on`` 和 ``soft_depends_on`` 向上遍历,确保被选中
|
|
366
|
+
任务所需的上游全部包含在内,使子图可独立执行。
|
|
368
367
|
|
|
369
368
|
参数
|
|
370
369
|
----
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"""_env_persist - 跨平台环境变量持久化辅助(私有,不参与工具发现)。
|
|
2
|
+
|
|
3
|
+
``os.environ[name] = value`` 仅修改当前进程的环境变量副本,进程退出即失效。
|
|
4
|
+
本模块提供 :func:`persist_env`,将环境变量实质写入用户层面:
|
|
5
|
+
|
|
6
|
+
- Windows:写入注册表 ``HKEY_CURRENT_USER\\Environment``(用户级环境变量),
|
|
7
|
+
并广播 ``WM_SETTINGCHANGE`` 通知已运行的进程刷新环境(如资源管理器、
|
|
8
|
+
新开的终端)。相比 ``setx`` 无 1024 字符长度截断限制,且不依赖外部命令。
|
|
9
|
+
- Linux/macOS:在 shell 启动文件(默认 ``~/.profile``)中追加或更新
|
|
10
|
+
``export NAME="value"`` 行,登录后新终端自动生效。
|
|
11
|
+
|
|
12
|
+
无论平台,同时更新当前进程的 ``os.environ``,使本次会话内立即可用。
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import os
|
|
18
|
+
import re
|
|
19
|
+
import sys
|
|
20
|
+
from pathlib import Path
|
|
21
|
+
|
|
22
|
+
__all__ = ["persist_env", "shell_profile_path"]
|
|
23
|
+
|
|
24
|
+
# Windows 注册表用户环境变量键路径(HKEY_CURRENT_USER 下)。
|
|
25
|
+
_WIN_ENV_KEY: str = "Environment"
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def shell_profile_path() -> Path:
|
|
29
|
+
"""返回 Linux/macOS 上用于持久化环境变量的 shell 启动文件路径。
|
|
30
|
+
|
|
31
|
+
优先使用 ``~/.profile``(登录 shell 通用,bash/sh/zsh 均会读取)。
|
|
32
|
+
"""
|
|
33
|
+
return Path.home() / ".profile"
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _persist_env_windows(name: str, value: str) -> None: # pragma: no cover - 仅 Windows 运行
|
|
37
|
+
"""在 Windows 上将环境变量写入注册表 ``HKCU\\Environment`` 并广播刷新通知。"""
|
|
38
|
+
import ctypes
|
|
39
|
+
import winreg
|
|
40
|
+
|
|
41
|
+
with winreg.OpenKey(winreg.HKEY_CURRENT_USER, _WIN_ENV_KEY, 0, winreg.KEY_SET_VALUE) as key:
|
|
42
|
+
winreg.SetValueEx(key, name, 0, winreg.REG_EXPAND_SZ, value)
|
|
43
|
+
|
|
44
|
+
# 广播 WM_SETTINGCHANGE,通知已运行进程刷新环境块(否则新终端才生效)。
|
|
45
|
+
hwnd_broadcast = 0xFFFF # HWND_BROADCAST
|
|
46
|
+
wm_settingchange = 0x001A
|
|
47
|
+
smto_abortifhung = 0x0002
|
|
48
|
+
ctypes.windll.user32.SendMessageTimeoutW(
|
|
49
|
+
hwnd_broadcast,
|
|
50
|
+
wm_settingchange,
|
|
51
|
+
0,
|
|
52
|
+
"Environment",
|
|
53
|
+
smto_abortifhung,
|
|
54
|
+
5000,
|
|
55
|
+
None,
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _persist_env_unix(name: str, value: str) -> None:
|
|
60
|
+
"""在 Linux/macOS 上将 ``export NAME="value"`` 追加或更新到 shell 启动文件。"""
|
|
61
|
+
profile = shell_profile_path()
|
|
62
|
+
profile.parent.mkdir(parents=True, exist_ok=True)
|
|
63
|
+
|
|
64
|
+
export_line = f'export {name}="{value}"'
|
|
65
|
+
try:
|
|
66
|
+
existing = profile.read_text(encoding="utf-8")
|
|
67
|
+
except (OSError, UnicodeDecodeError):
|
|
68
|
+
existing = ""
|
|
69
|
+
|
|
70
|
+
# 匹配同名变量的已有 export 行(行首可有空白),存在则替换,否则追加。
|
|
71
|
+
pattern = re.compile(rf"^\s*export\s+{re.escape(name)}=.*$", re.MULTILINE)
|
|
72
|
+
if pattern.search(existing):
|
|
73
|
+
updated = pattern.sub(export_line, existing)
|
|
74
|
+
else:
|
|
75
|
+
prefix = existing if existing.endswith("\n") or not existing else existing + "\n"
|
|
76
|
+
updated = f"{prefix}{export_line}\n"
|
|
77
|
+
|
|
78
|
+
profile.write_text(updated, encoding="utf-8")
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def persist_env(name: str, value: str) -> None:
|
|
82
|
+
"""持久化设置环境变量(跨平台),并同步更新当前进程。
|
|
83
|
+
|
|
84
|
+
Parameters
|
|
85
|
+
----------
|
|
86
|
+
name:
|
|
87
|
+
环境变量名。
|
|
88
|
+
value:
|
|
89
|
+
环境变量值。
|
|
90
|
+
|
|
91
|
+
Notes
|
|
92
|
+
-----
|
|
93
|
+
Windows 写入注册表用户环境变量并广播刷新;Linux/macOS 写入
|
|
94
|
+
``~/.profile``。两种平台均更新 ``os.environ`` 使本进程立即可用。
|
|
95
|
+
持久化写入通常需重开终端或重新登录后对新进程生效。
|
|
96
|
+
"""
|
|
97
|
+
os.environ[name] = value
|
|
98
|
+
if sys.platform == "win32":
|
|
99
|
+
_persist_env_windows(name, value)
|
|
100
|
+
else:
|
|
101
|
+
_persist_env_unix(name, value)
|
|
@@ -112,6 +112,7 @@ def output_profile(
|
|
|
112
112
|
if export == "text":
|
|
113
113
|
sys.stdout.write(profile.describe())
|
|
114
114
|
sys.stdout.write("\n")
|
|
115
|
+
sys.stdout.flush()
|
|
115
116
|
return
|
|
116
117
|
|
|
117
118
|
# HTML 格式
|
|
@@ -129,4 +130,5 @@ def output_profile(
|
|
|
129
130
|
try:
|
|
130
131
|
webbrowser.open(f"file:///{out_path.resolve().as_posix()}")
|
|
131
132
|
except Exception as e:
|
|
133
|
+
# webbrowser.open 可抛 OS 级或 webbrowser.Error,属非关键功能
|
|
132
134
|
get_console().print(f"[yellow]警告:[/yellow] 无法打开浏览器: {e}")
|
|
@@ -46,4 +46,8 @@ def docker_login(username: str = "", registry: str = _DEFAULT_REGISTRY) -> None:
|
|
|
46
46
|
|
|
47
47
|
@fcmd.main("dockercmd")
|
|
48
48
|
def main() -> None:
|
|
49
|
-
pass
|
|
49
|
+
pass # pragma: no cover - @fcmd.main 装饰器替换函数体,pass 永不执行
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
if __name__ == "__main__": # pragma: no cover
|
|
53
|
+
main()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""envdev - 开发环境镜像源配置工具。
|
|
2
2
|
|
|
3
|
-
配置 Python / Conda / Rust 镜像源(Linux 还会安装 Qt 库、中文字体、Docker)。
|
|
3
|
+
配置 Python / Conda / Rust / Bun 镜像源(Linux 还会安装 Qt 库、中文字体、Docker)。
|
|
4
4
|
所有镜像源参数互不影响,可单独使用。Linux 专用操作(系统镜像/Qt/字体/Docker)
|
|
5
5
|
在非 Linux 平台上由函数内部跳过。
|
|
6
6
|
|
|
@@ -9,32 +9,30 @@
|
|
|
9
9
|
fcmd envdev setup-python # 配置 Python 镜像源(默认清华)
|
|
10
10
|
fcmd envdev setup-python --mirror aliyun # 配置阿里云镜像源
|
|
11
11
|
fcmd envdev setup-conda --mirror ustc # 配置 Conda 镜像源
|
|
12
|
-
fcmd envdev
|
|
13
|
-
fcmd envdev
|
|
14
|
-
fcmd envdev install-rust --version stable # 安装 Rust 工具链
|
|
12
|
+
fcmd envdev rust --mirror tsinghua nightly # 配置 Rust 环境(镜像源 + 下载 + 安装)
|
|
13
|
+
fcmd envdev js-bun # 配置 Bun 环境(镜像源 + 安装)
|
|
15
14
|
"""
|
|
16
15
|
|
|
17
16
|
from __future__ import annotations
|
|
18
17
|
|
|
19
18
|
import getpass
|
|
20
|
-
import os
|
|
21
19
|
import shutil
|
|
22
20
|
import sys
|
|
23
21
|
from pathlib import Path
|
|
24
22
|
|
|
25
23
|
import fcmd
|
|
24
|
+
from fcmd.cli._env_persist import persist_env
|
|
26
25
|
from fcmd.models import run_command
|
|
27
26
|
|
|
28
27
|
__all__ = [
|
|
29
|
-
"download_rustup_script",
|
|
30
28
|
"install_linux_docker",
|
|
31
29
|
"install_linux_fonts",
|
|
32
30
|
"install_linux_qt_libs",
|
|
33
|
-
"
|
|
31
|
+
"setup_bun_env",
|
|
34
32
|
"setup_conda_mirror",
|
|
35
33
|
"setup_linux_system_mirror",
|
|
36
34
|
"setup_python_mirror",
|
|
37
|
-
"
|
|
35
|
+
"setup_rust_env",
|
|
38
36
|
]
|
|
39
37
|
|
|
40
38
|
# ============================================================================
|
|
@@ -163,6 +161,9 @@ _INSTALL_MIRROR_SCRIPT: str = "sudo bash /tmp/linuxmirrors.sh"
|
|
|
163
161
|
_RUSTUP_DOWNLOAD_URL_LINUX: str = "https://mirrors.aliyun.com/repo/rust/rustup-init.sh"
|
|
164
162
|
_RUSTUP_DOWNLOAD_URL_WINDOWS: str = "https://static.rust-lang.org/rustup/dist/x86_64-pc-windows-msvc/rustup-init.exe"
|
|
165
163
|
|
|
164
|
+
_BUN_NPM_REGISTRY: str = "https://registry.npmmirror.com"
|
|
165
|
+
_BUN_INSTALL_SCRIPT_URL: str = "https://bun.sh/install"
|
|
166
|
+
|
|
166
167
|
|
|
167
168
|
# ============================================================================
|
|
168
169
|
# 私有辅助
|
|
@@ -182,16 +183,17 @@ def _pip_config_path() -> Path:
|
|
|
182
183
|
|
|
183
184
|
|
|
184
185
|
@fcmd.tool("envdev", subcommand="setup-python", help="配置 Python 镜像源")
|
|
185
|
-
def setup_python_mirror(mirror: str = "
|
|
186
|
-
"""配置 Python
|
|
186
|
+
def setup_python_mirror(mirror: str = "aliyun") -> None:
|
|
187
|
+
"""配置 Python 镜像源(持久化环境变量 + 写入 pip 配置文件)。
|
|
187
188
|
|
|
188
|
-
|
|
189
|
-
``UV_PYTHON_INSTALL_MIRROR``
|
|
189
|
+
通过 :func:`persist_env` 持久化 ``PIP_INDEX_URL`` / ``PIP_TRUSTED_HOSTS`` /
|
|
190
|
+
``UV_INDEX_URL`` / ``UV_PYTHON_INSTALL_MIRROR`` 等环境变量(Windows 写注册表,
|
|
191
|
+
Linux/macOS 写 ``~/.profile``,同时更新当前进程),并写入 pip 配置文件。
|
|
190
192
|
|
|
191
193
|
Parameters
|
|
192
194
|
----------
|
|
193
195
|
mirror:
|
|
194
|
-
镜像源名称:tsinghua/aliyun/huaweicloud/ustc/zju(默认
|
|
196
|
+
镜像源名称:tsinghua/aliyun/huaweicloud/ustc/zju(默认 aliyun)
|
|
195
197
|
"""
|
|
196
198
|
if mirror not in _PIP_INDEX_URLS:
|
|
197
199
|
print(f"未知 Python 镜像源: {mirror}")
|
|
@@ -200,12 +202,13 @@ def setup_python_mirror(mirror: str = "tsinghua") -> None:
|
|
|
200
202
|
index_url = _PIP_INDEX_URLS[mirror]
|
|
201
203
|
trusted_host = _PIP_TRUSTED_HOSTS[mirror]
|
|
202
204
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
205
|
+
print(f"配置 Python 镜像源: {mirror}")
|
|
206
|
+
persist_env("PIP_INDEX_URL", index_url)
|
|
207
|
+
persist_env("PIP_TRUSTED_HOSTS", trusted_host)
|
|
208
|
+
persist_env("UV_INDEX_URL", index_url)
|
|
209
|
+
persist_env("UV_PYTHON_INSTALL_MIRROR", _UV_PYTHON_INSTALL_MIRROR)
|
|
210
|
+
persist_env("UV_HTTP_TIMEOUT", "600")
|
|
211
|
+
persist_env("UV_LINK_MODE", "copy")
|
|
209
212
|
|
|
210
213
|
config_path = _pip_config_path()
|
|
211
214
|
config_path.parent.mkdir(parents=True, exist_ok=True)
|
|
@@ -215,13 +218,13 @@ def setup_python_mirror(mirror: str = "tsinghua") -> None:
|
|
|
215
218
|
|
|
216
219
|
|
|
217
220
|
@fcmd.tool("envdev", subcommand="setup-conda", help="配置 Conda 镜像源")
|
|
218
|
-
def setup_conda_mirror(mirror: str = "
|
|
221
|
+
def setup_conda_mirror(mirror: str = "aliyun") -> None:
|
|
219
222
|
"""配置 Conda 镜像源(写入 ~/.condarc)。
|
|
220
223
|
|
|
221
224
|
Parameters
|
|
222
225
|
----------
|
|
223
226
|
mirror:
|
|
224
|
-
镜像源名称:tsinghua/ustc/bsfu/aliyun(默认
|
|
227
|
+
镜像源名称:tsinghua/ustc/bsfu/aliyun(默认 aliyun)
|
|
225
228
|
"""
|
|
226
229
|
if mirror not in _CONDA_MIRROR_URLS:
|
|
227
230
|
print(f"未知 Conda 镜像源: {mirror}")
|
|
@@ -235,27 +238,31 @@ def setup_conda_mirror(mirror: str = "tsinghua") -> None:
|
|
|
235
238
|
print(f"Conda 镜像源已配置: {mirror} -> {config_path}")
|
|
236
239
|
|
|
237
240
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
+
# ============================================================================
|
|
242
|
+
# Rust 工具链安装
|
|
243
|
+
# ============================================================================
|
|
244
|
+
@fcmd.tool("envdev", subcommand="setup-rust", help="配置 Rust 镜像源", hidden=True)
|
|
245
|
+
def _setup_rust_mirror(mirror: str = "aliyun") -> None:
|
|
246
|
+
"""配置 Rust 镜像源(持久化环境变量 + 写入 cargo config + 创建 sccache 目录)。
|
|
241
247
|
|
|
242
|
-
|
|
243
|
-
等环境变量,写入 ``~/.cargo/config.toml``,并创建
|
|
248
|
+
通过 :func:`persist_env` 持久化 ``RUSTUP_DIST_SERVER`` / ``RUSTUP_UPDATE_ROOT`` /
|
|
249
|
+
``RUST_SCCACHE_DIR`` 等环境变量,写入 ``~/.cargo/config.toml``,并创建
|
|
250
|
+
sccache 缓存目录。
|
|
244
251
|
|
|
245
252
|
Parameters
|
|
246
253
|
----------
|
|
247
254
|
mirror:
|
|
248
|
-
镜像源名称:tsinghua/ustc/aliyun(默认
|
|
255
|
+
镜像源名称:tsinghua/ustc/aliyun(默认 aliyun)
|
|
249
256
|
"""
|
|
250
257
|
if mirror not in _RUSTUP_MIRRORS:
|
|
251
258
|
print(f"未知 Rust 镜像源: {mirror}")
|
|
252
259
|
return
|
|
253
260
|
|
|
254
261
|
mirrors = _RUSTUP_MIRRORS[mirror]
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
262
|
+
persist_env("RUSTUP_DIST_SERVER", mirrors["RUSTUP_DIST_SERVER"])
|
|
263
|
+
persist_env("RUSTUP_UPDATE_ROOT", mirrors["RUSTUP_UPDATE_ROOT"])
|
|
264
|
+
persist_env("RUST_SCCACHE_DIR", str(_RUST_SCCACHE_DIR))
|
|
265
|
+
persist_env("RUST_SCCACHE_CACHE_SIZE", _RUST_SCCACHE_CACHE_SIZE)
|
|
259
266
|
|
|
260
267
|
_RUST_SCCACHE_DIR.mkdir(parents=True, exist_ok=True)
|
|
261
268
|
|
|
@@ -271,13 +278,8 @@ def setup_rust_mirror(mirror: str = "tsinghua") -> None:
|
|
|
271
278
|
print(f"Rust 镜像源已配置: {mirror} -> {config_path}")
|
|
272
279
|
|
|
273
280
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
# ============================================================================
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
@fcmd.tool("envdev", subcommand="download-rustup", help="下载 Rustup 安装脚本")
|
|
280
|
-
def download_rustup_script() -> None:
|
|
281
|
+
@fcmd.tool("envdev", subcommand="download-rustup", help="下载 Rustup 安装脚本", hidden=True)
|
|
282
|
+
def _download_rustup() -> None:
|
|
281
283
|
"""下载 Rustup 安装脚本(跨平台,已安装 rustup 时跳过)。
|
|
282
284
|
|
|
283
285
|
Linux 下载 ``rustup-init.sh``,Windows 下载 ``rustup-init.exe``。
|
|
@@ -304,8 +306,8 @@ def download_rustup_script() -> None:
|
|
|
304
306
|
run_command(["curl", "-fsSL", _RUSTUP_DOWNLOAD_URL_LINUX, "-o", "rustup-init.sh"])
|
|
305
307
|
|
|
306
308
|
|
|
307
|
-
@fcmd.tool("envdev", subcommand="install-rust", help="安装 Rust 工具链")
|
|
308
|
-
def
|
|
309
|
+
@fcmd.tool("envdev", subcommand="install-rust", help="安装 Rust 工具链", hidden=True)
|
|
310
|
+
def _install_rust_toolchain(version: str = "stable") -> None:
|
|
309
311
|
"""安装 Rust 工具链(rustup 未安装时跳过)。
|
|
310
312
|
|
|
311
313
|
Parameters
|
|
@@ -321,6 +323,83 @@ def install_rust_toolchain(version: str = "stable") -> None:
|
|
|
321
323
|
print(f"Rust 工具链 {version} 安装完成")
|
|
322
324
|
|
|
323
325
|
|
|
326
|
+
@fcmd.tool("envdev", subcommand="rust", help="配置 Rust 环境")
|
|
327
|
+
def setup_rust_env(mirror: str = "aliyun", rust_version: str = "stable") -> None:
|
|
328
|
+
"""配置 Rust 环境(镜像源 + 下载 rustup + 安装工具链)。
|
|
329
|
+
|
|
330
|
+
依次执行:配置 Rust 镜像源(环境变量 + ``~/.cargo/config.toml`` + sccache 目录)、
|
|
331
|
+
下载 Rustup 安装脚本(已安装 rustup 时跳过)、安装指定版本工具链
|
|
332
|
+
(rustup 未安装时跳过)。
|
|
333
|
+
|
|
334
|
+
Parameters
|
|
335
|
+
----------
|
|
336
|
+
mirror:
|
|
337
|
+
镜像源名称:tsinghua/ustc/aliyun(默认 aliyun)
|
|
338
|
+
rust_version:
|
|
339
|
+
Rust 版本:``stable`` / ``nightly`` / ``beta``(默认 ``stable``)
|
|
340
|
+
"""
|
|
341
|
+
_setup_rust_mirror(mirror)
|
|
342
|
+
_download_rustup()
|
|
343
|
+
_install_rust_toolchain(rust_version)
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
# ============================================================================
|
|
347
|
+
# JavaScript 工具链安装
|
|
348
|
+
# ============================================================================
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
@fcmd.tool("envdev", subcommand="setup-bun", help="配置 Bun 镜像源", hidden=True)
|
|
352
|
+
def _setup_bun_mirror() -> None:
|
|
353
|
+
"""配置 Bun npm 镜像源(持久化环境变量 + 写入 ``~/.bunfig.toml``)。
|
|
354
|
+
|
|
355
|
+
通过 :func:`persist_env` 持久化 ``BUN_CONFIG_REGISTRY`` 环境变量,
|
|
356
|
+
并写入 bunfig.toml 指向 npmmirror。
|
|
357
|
+
"""
|
|
358
|
+
persist_env("BUN_CONFIG_REGISTRY", _BUN_NPM_REGISTRY)
|
|
359
|
+
|
|
360
|
+
config_path = Path.home() / ".bunfig.toml"
|
|
361
|
+
config_path.parent.mkdir(parents=True, exist_ok=True)
|
|
362
|
+
content = f'[install]\nregistry = "{_BUN_NPM_REGISTRY}"\n'
|
|
363
|
+
config_path.write_text(content, encoding="utf-8")
|
|
364
|
+
print(f"Bun 镜像源已配置: {_BUN_NPM_REGISTRY} -> {config_path}")
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
@fcmd.tool("envdev", subcommand="install-bun", help="安装 Bun", hidden=True)
|
|
368
|
+
def _install_bun() -> None:
|
|
369
|
+
"""安装 Bun.js(已安装时跳过)。
|
|
370
|
+
|
|
371
|
+
Linux/macOS 通过官方脚本安装(Linux 先安装 curl/zip/unzip 依赖);
|
|
372
|
+
Windows 提示使用 PowerShell 安装命令。
|
|
373
|
+
"""
|
|
374
|
+
if shutil.which("bun") is not None:
|
|
375
|
+
print("bun 已安装,跳过安装")
|
|
376
|
+
return
|
|
377
|
+
|
|
378
|
+
if sys.platform == "win32":
|
|
379
|
+
print("Windows 请使用 PowerShell 执行: irm bun.sh/install.ps1 | iex")
|
|
380
|
+
return
|
|
381
|
+
|
|
382
|
+
if sys.platform.startswith("linux"):
|
|
383
|
+
print("更新系统包...")
|
|
384
|
+
run_command(["sudo", "apt", "update"])
|
|
385
|
+
run_command(["sudo", "apt", "install", "-y", "curl", "zip", "unzip"])
|
|
386
|
+
|
|
387
|
+
print("下载并安装 Bun.js...")
|
|
388
|
+
run_command(["bash", "-c", f"curl -fsSL {_BUN_INSTALL_SCRIPT_URL} | bash"])
|
|
389
|
+
print("Bun.js 安装完成")
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
@fcmd.tool("envdev", subcommand="js-bun", help="配置 Bun 环境")
|
|
393
|
+
def setup_bun_env() -> None:
|
|
394
|
+
"""配置 Bun 环境(配置 npm 镜像源 + 安装 Bun.js)。
|
|
395
|
+
|
|
396
|
+
依次执行:配置 Bun npm 镜像源(环境变量 + ``~/.bunfig.toml``)、
|
|
397
|
+
安装 Bun.js(已安装时跳过)。
|
|
398
|
+
"""
|
|
399
|
+
_setup_bun_mirror()
|
|
400
|
+
_install_bun()
|
|
401
|
+
|
|
402
|
+
|
|
324
403
|
# ============================================================================
|
|
325
404
|
# Linux 专用子命令
|
|
326
405
|
# ============================================================================
|
|
@@ -396,3 +475,7 @@ def install_linux_docker() -> None:
|
|
|
396
475
|
@fcmd.main("envdev")
|
|
397
476
|
def main() -> None:
|
|
398
477
|
pass
|
|
478
|
+
|
|
479
|
+
|
|
480
|
+
if __name__ == "__main__":
|
|
481
|
+
main()
|