refactor(system): add setenv_group and write_file task helpers

1. 为setenv和which函数添加正确的返回类型注解
2. 新增setenv_group批量设置环境变量的任务组
3. 新增write_file写入文件的任务工具函数
4. 更新__all__导出所有新增的工具函数

feat(cli/envdev): rewrite envdev cli with proper config and args
1. 重构环境开发CLI脚本,使用argparse替换原有TypedDict配置
2. 新增Python和Conda镜像源选择参数
3. 自动生成并写入Python pip和Conda配置文件
4. 优化任务依赖和命名,统一使用系统工具函数
This commit is contained in:
2026-06-27 17:12:53 +08:00
parent 336f7b7292
commit 9d033e1c0b
2 changed files with 147 additions and 29 deletions
+126 -26
View File
@@ -1,54 +1,101 @@
from typing import TypedDict from __future__ import annotations
import argparse
from pathlib import Path
from typing import Literal, get_args
import pyflowx as px import pyflowx as px
from pyflowx.tasks.system import Constants, setenv_group, write_file
class EnvConfig(TypedDict):
"""环境配置项."""
name: str
value: str
description: str
PIP_INDEX_URL_CONFIG: EnvConfig = {
"name": "PIP_INDEX_URL",
"value": "https://pypi.tuna.tsinghua.edu.cn/simple",
"description": "PIP索引URL",
}
# ============================================================================ # ============================================================================
# 配置 # Mirror 配置
# ============================================================================ # ============================================================================
DOWNLOAD_MIRROR_SCRIPT: str = "curl -sSL https://linuxmirrors.cn/main.sh -o /tmp/linuxmirrors.sh"
INSTALL_MIRROR_SCRIPT: str = "sudo bash /tmp/linuxmirrors.sh"
PIP_INDEX_URLS: dict[str, str] = { # ============================================================================
# Python 配置
# ============================================================================
PyMirrorType = Literal["tsinghua", "aliyun"]
PIP_INDEX_URLS: dict[PyMirrorType, str] = {
"tsinghua": "https://pypi.tuna.tsinghua.edu.cn/simple", "tsinghua": "https://pypi.tuna.tsinghua.edu.cn/simple",
"aliyun": "https://mirrors.aliyun.com/pypi/simple/", "aliyun": "https://mirrors.aliyun.com/pypi/simple/",
} }
PIP_TRUSTED_HOSTS: dict[str, str] = { PIP_TRUSTED_HOSTS: dict[PyMirrorType, str] = {
"tsinghua": "pypi.tuna.tsinghua.edu.cn", "tsinghua": "pypi.tuna.tsinghua.edu.cn",
"aliyun": "mirrors.aliyun.com", "aliyun": "mirrors.aliyun.com",
} }
PIP_CONFIG_PATH = Path.home() / ".pip" / "pip.conf" if not Constants.IS_WINDOWS else Path.home() / "pip" / "pip.ini"
UV_INDEX_URL: str = "https://mirrors.aliyun.com/pypi/simple/" UV_INDEX_URLS: dict[PyMirrorType, str] = {
"tsinghua": "https://pypi.tuna.tsinghua.edu.cn/simple",
"aliyun": "https://mirrors.aliyun.com/pypi/simple/",
}
UV_PYTHON_INSTALL_MIRROR: str = "https://registry.npmmirror.com/-/binary/python-build-standalone" UV_PYTHON_INSTALL_MIRROR: str = "https://registry.npmmirror.com/-/binary/python-build-standalone"
CONDA_MIRROR_URLS: dict[str, list[str]] = { # ============================================================================
# Conda 配置
# ============================================================================
CondaMirrorType = Literal["tsinghua", "ustc", "bsfu", "aliyun"]
CONDA_MIRROR_URLS: dict[CondaMirrorType, list[str]] = {
"tsinghua": [ "tsinghua": [
"https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/", "https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/",
"https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/", "https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/",
"https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/r/",
"https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/msys2/",
"https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/pro/",
"https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/", "https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/",
"https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/bioconda/",
"https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/menpo/",
"https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/pytorch/",
],
"ustc": [
"https://mirrors.ustc.edu.cn/anaconda/pkgs/main/",
"https://mirrors.ustc.edu.cn/anaconda/pkgs/free/",
"https://mirrors.ustc.edu.cn/anaconda/pkgs/r/",
"https://mirrors.ustc.edu.cn/anaconda/pkgs/msys2/",
"https://mirrors.ustc.edu.cn/anaconda/pkgs/pro/",
"https://mirrors.ustc.edu.cn/anaconda/pkgs/dev/",
"https://mirrors.ustc.edu.cn/anaconda/cloud/conda-forge/",
"https://mirrors.ustc.edu.cn/anaconda/cloud/bioconda/",
"https://mirrors.ustc.edu.cn/anaconda/cloud/menpo/",
"https://mirrors.ustc.edu.cn/anaconda/cloud/pytorch/",
],
"bsfu": [
"https://mirrors.bsfu.edu.cn/anaconda/pkgs/main/",
"https://mirrors.bsfu.edu.cn/anaconda/pkgs/free/",
"https://mirrors.bsfu.edu.cn/anaconda/pkgs/r/",
"https://mirrors.bsfu.edu.cn/anaconda/pkgs/msys2/",
"https://mirrors.bsfu.edu.cn/anaconda/pkgs/pro/",
"https://mirrors.bsfu.edu.cn/anaconda/pkgs/dev/",
"https://mirrors.bsfu.edu.cn/anaconda/cloud/conda-forge/",
"https://mirrors.bsfu.edu.cn/anaconda/cloud/bioconda/",
"https://mirrors.bsfu.edu.cn/anaconda/cloud/menpo/",
"https://mirrors.bsfu.edu.cn/anaconda/cloud/pytorch/",
], ],
"aliyun": [ "aliyun": [
"https://mirrors.aliyun.com/anaconda/pkgs/main/", "https://mirrors.aliyun.com/anaconda/pkgs/main/",
"https://mirrors.aliyun.com/anaconda/pkgs/free/", "https://mirrors.aliyun.com/anaconda/pkgs/free/",
"https://mirrors.aliyun.com/anaconda/pkgs/r/",
"https://mirrors.aliyun.com/anaconda/pkgs/msys2/",
"https://mirrors.aliyun.com/anaconda/pkgs/pro/",
"https://mirrors.aliyun.com/anaconda/pkgs/dev/",
"https://mirrors.aliyun.com/anaconda/cloud/conda-forge/", "https://mirrors.aliyun.com/anaconda/cloud/conda-forge/",
"https://mirrors.aliyun.com/anaconda/cloud/bioconda/",
"https://mirrors.aliyun.com/anaconda/cloud/menpo/",
"https://mirrors.aliyun.com/anaconda/cloud/pytorch/",
], ],
} }
CONDA_CONFIG_PATH = Path.home() / ".condarc"
# ============================================================================
# Qt 配置
# ============================================================================
QT_LIBS: list[str] = [ QT_LIBS: list[str] = [
"build-essential", "build-essential",
"libgl1", "libgl1",
@@ -79,19 +126,72 @@ CHINESE_FONTS: list[str] = [
def main() -> None: def main() -> None:
"""主函数.""" """主函数."""
parser = argparse.ArgumentParser(description="环境开发工具")
parser.add_argument(
"--python-mirror",
nargs="?",
type=str,
default="tsinghua",
choices=get_args(PyMirrorType),
help="Python 镜像源",
)
parser.add_argument(
"--conda-mirror",
nargs="?",
type=str,
default="tsinghua",
choices=get_args(CondaMirrorType),
help="Conda 镜镜像源",
)
args = parser.parse_args()
python_mirror = args.python_mirror
python_envs: dict[str, str] = {
"PIP_INDEX_URL": PIP_INDEX_URLS[python_mirror],
"PIP_TRUSTED_HOSTS": PIP_TRUSTED_HOSTS[python_mirror],
"UV_INDEX_URL": UV_INDEX_URLS[python_mirror],
"UV_PYTHON_INSTALL_MIRROR": UV_PYTHON_INSTALL_MIRROR,
"UV_HTTP_TIMEOUT": "600",
"UV_LINK_MODE": "copy",
}
conda_mirror_urls = CONDA_MIRROR_URLS[args.conda_mirror]
# 确保配置文件目录存在
PIP_CONFIG_PATH.parent.mkdir(parents=True, exist_ok=True)
CONDA_CONFIG_PATH.parent.mkdir(parents=True, exist_ok=True)
# 使用更安全的分步执行方式,便于调试和捕获错误 # 使用更安全的分步执行方式,便于调试和捕获错误
graph = px.Graph.from_specs([ graph = px.Graph.from_specs([
# 下载镜像 # 下载镜像
px.TaskSpec("download", cmd="curl -sSL https://linuxmirrors.cn/main.sh -o /tmp/linuxmirrors.sh", verbose=True), px.TaskSpec("download_mirror", cmd=DOWNLOAD_MIRROR_SCRIPT, verbose=True),
# 安装镜像 # 安装镜像
px.TaskSpec("install", cmd="sudo bash /tmp/linuxmirrors.sh", verbose=True, depends_on=("download",)), px.TaskSpec("install_mirror", cmd=INSTALL_MIRROR_SCRIPT, verbose=True, depends_on=("download_mirror",)),
# 安装 PyQt 相关依赖 # 安装 PyQt 相关依赖
px.TaskSpec( px.TaskSpec(
"envqt_install", cmd=["sudo", "apt", "install", "-y", *QT_LIBS], verbose=True, depends_on=("install",) "install_qt_libs",
cmd=["sudo", "apt", "install", "-y", *QT_LIBS],
verbose=True,
depends_on=("install_mirror",),
), ),
# 安装中文字体 # 安装中文字体
px.TaskSpec( px.TaskSpec(
"envqt_fonts", cmd=["sudo", "apt", "install", "-y", *CHINESE_FONTS], verbose=True, depends_on=("install",) "install_fonts",
cmd=["sudo", "apt", "install", "-y", *CHINESE_FONTS],
verbose=True,
depends_on=("install_mirror",),
),
# 设置 Python 环境变量
*setenv_group(python_envs),
# 写入 Python 配置
write_file(
str(PIP_CONFIG_PATH),
f"[global]\nindex-url = {PIP_INDEX_URLS[python_mirror]}\ntrusted-host = {PIP_TRUSTED_HOSTS[python_mirror]}",
),
# 写入 Conda 配置
write_file(
str(CONDA_CONFIG_PATH),
"show_channel_urls: true\nchannels:" + "\n".join(conda_mirror_urls) + "\n - defaults",
), ),
]) ])
px.run(graph, strategy="thread", verbose=True) px.run(graph, strategy="thread", verbose=True)
+21 -3
View File
@@ -66,7 +66,7 @@ def reset_icon_cache() -> list[px.TaskSpec]:
] ]
def setenv(name: str, value: str, default: bool = False): def setenv(name: str, value: str, default: bool = False) -> px.TaskSpec:
"""设置环境变量任务.""" """设置环境变量任务."""
def set_env(): def set_env():
@@ -78,7 +78,12 @@ def setenv(name: str, value: str, default: bool = False):
return px.TaskSpec(f"setenv_{name.lower()}", fn=set_env, verbose=True) return px.TaskSpec(f"setenv_{name.lower()}", fn=set_env, verbose=True)
def which(cmd: str): def setenv_group(envs: dict[str, str], default: bool = False) -> list[px.TaskSpec]:
"""设置环境变量组任务."""
return [setenv(name, value, default) for name, value in envs.items()]
def which(cmd: str) -> px.TaskSpec:
"""查找命令路径任务.""" """查找命令路径任务."""
which_cmd = "where" if Constants.IS_WINDOWS else "which" which_cmd = "where" if Constants.IS_WINDOWS else "which"
@@ -95,4 +100,17 @@ def which(cmd: str):
return px.TaskSpec(f"which_{cmd}", fn=find_command) return px.TaskSpec(f"which_{cmd}", fn=find_command)
__all__ = ["clr", "setenv", "which"] def write_file(path: str, content: str, encoding: str = "utf-8") -> px.TaskSpec:
"""写入文件任务."""
def write():
try:
with open(path, "w", encoding=encoding) as f:
f.write(content)
except Exception as e:
print(f"写入文件 {path} 失败: {e}")
return px.TaskSpec(f"write_file_{path}", fn=write, verbose=True)
__all__ = ["clr", "reset_icon_cache", "setenv", "setenv_group", "which", "write_file"]