From 2b24591fb79c718611ebae4f5463f37396e6bfbd Mon Sep 17 00:00:00 2001 From: Mikachu2333 Date: Wed, 27 May 2026 16:41:21 +0800 Subject: [PATCH 1/7] =?UTF-8?q?=E5=A2=9E=E5=8A=A0uv=E7=9A=84python?= =?UTF-8?q?=E4=B8=8B=E8=BD=BD=E9=95=9C=E5=83=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 增加uv的python下载镜像 2. 现在uv会同时对pypi和python进行换源 --- src/recipe/lang/Python/uv.c | 248 +++++++++++++++++++++++++++--------- 1 file changed, 186 insertions(+), 62 deletions(-) diff --git a/src/recipe/lang/Python/uv.c b/src/recipe/lang/Python/uv.c index 5277bb58..c554159f 100644 --- a/src/recipe/lang/Python/uv.c +++ b/src/recipe/lang/Python/uv.c @@ -10,12 +10,12 @@ pl_python_uv_prelude (void) chef_prep_this (pl_python_uv, gsr); chef_set_recipe_created_on (this, "2024-12-11"); - chef_set_recipe_last_updated (this, "2025-12-29"); - chef_set_sources_last_updated (this, "2025-08-09"); + chef_set_recipe_last_updated (this, "2026-05-27"); + chef_set_sources_last_updated (this, "2026-05-27"); chef_set_chef (this, NULL); chef_set_cooks (this, 2, "@happy-game", "@MingriLingran"); - chef_set_sauciers (this, 2, "@Kattos", "@ccmywish"); + chef_set_sauciers (this, 3, "@Kattos", "@ccmywish", "@Mikachu2333"); chef_set_scope_cap (this, ProjectScope, ScopeCap_Able_And_Implemented); chef_set_scope_cap (this, UserScope, ScopeCap_Able_And_Implemented); @@ -32,11 +32,11 @@ pl_python_uv_prelude (void) /** * chsrc get uv * - * uv的配置优先级顺序如下(高到低): - * 1. $workspaces/uv.toml - * 2. $workspaces/pyproject.toml - * 3. ~/.config/uv/uv.toml - * 4. /etc/uv/uv.toml + * uv 配置文件查找优先级 (代码仅涵盖 ①②,③④为 uv 自身支持): + * ① ./uv.toml (项目级) + * ② ~/.config/uv/uv.toml (用户级, Windows: %APPDATA%\uv\uv.toml) + * ③ $workspace/pyproject.toml (项目级, 未实现) + * ④ /etc/uv/uv.toml (系统级, 未实现) */ #define PL_Python_uv_ConfigFile "uv.toml" @@ -55,7 +55,6 @@ pl_python_find_uv_config (bool mkdir) { if (xy.on_windows) { - /* config path on Windows */ char *appdata = getenv ("APPDATA"); if (!appdata) @@ -73,7 +72,6 @@ pl_python_find_uv_config (bool mkdir) } else { - /* config path on Linux or macOS */ if (mkdir) { chsrc_ensure_dir (PL_Python_uv_User_ConfigPath); @@ -83,106 +81,232 @@ pl_python_find_uv_config (bool mkdir) } } + void pl_python_uv_getsrc (char *option) { char *uv_config = pl_python_find_uv_config (false); - if (!chsrc_check_file (uv_config)) + if (!uv_config || !chsrc_check_file (uv_config)) { - chsrc_error2 ("未找到 uv 配置文件"); + if (!uv_config) + chsrc_error2 ("无法获取 uv 配置文件路径"); + else + chsrc_error2 ("未找到 uv 配置文件"); return; } /* 获取 [[index]] 配置项的 url */ if (xy.on_windows) { - /* 在 Windows 上使用 PowerShell 替代 grep */ char *script = xy_str_gsub (RAWSTR_pl_python_get_uv_config_on_windows, "@f@", uv_config); chsrc_run_as_powershell_file (script); } else { - /* 在类 Unix 系统上使用 grep */ char *cmd = xy_str_gsub (RAWSTR_pl_python_get_uv_config, "@f@", uv_config); chsrc_run (cmd, RunOpt_Default); } + + /* 检查 Python 下载镜像 */ + char *content = xy_file_read (uv_config); + if (content) + { + char *line = strstr (content, "python-install-mirror"); + if (line && (line == content || line[-1] == '\n')) + { + char *end = strchr (line, '\n'); + if (!end) end = line + strlen (line); + printf ("%.*s\n", (int)(end - line), line); + } + free (content); + } } -/** - * @consult https://docs.astral.sh/uv/configuration/files/ - * https://github.com/RubyMetric/chsrc/issues/139 - */ -void -pl_python_uv_setsrc (char *option) +/* + * Python下载镜像 (python-install-mirror) +*/ + +static MirrorSite_t +Py_GHRelease_NJU = { - chsrc_ensure_program ("uv"); + IS_DedicatedMirrorSite, + "nju", "NJU GitHub Release", "南京大学 GitHub 发布镜像", + "https://mirrors.nju.edu.cn/github-release/astral-sh/python-build-standalone", + {NotSkip, NA, NA, + "https://mirror.nju.edu.cn/github-release/astral-sh/python-build-standalone/20260510/cpython-3.14.5+20260510-i686-pc-windows-msvc-install_only_stripped.tar.gz", + ACCURATE} +}; - Source_t source = chsrc_yield_source (&pl_python_group_target, option); - if (chsrc_in_standalone_mode()) - chsrc_confirm_source(&source); +// 中科大的镜像由于仅保留最新的Latest且文件链接内含动态版本号导致无法测速 +static MirrorSite_t +Py_GHRelease_USTC = +{ + IS_DedicatedMirrorSite, + "ustc", "USTC GitHub Release", "中科大 GitHub 发布镜像", + "https://mirrors.ustc.edu.cn/github-release/astral-sh/python-build-standalone", + {NotSkip, NA, NA, + "https://mirrors.ustc.edu.cn/github-release/astral-sh/python-build-standalone/LatestRelease/SHA256SUMS", + ROUGH} +}; - char *uv_config = pl_python_find_uv_config (true); - if (NULL==uv_config) - { - chsrc_error2 ("无法获取 uv 配置文件路径"); - return; - } - chsrc_backup (uv_config); +static MirrorSite_t +Py_GHRelease_LZU = +{ + IS_DedicatedMirrorSite, + "lzu", "LZUOSS GitHub Release", "兰州大学 GitHub 发布镜像", + "https://mirror.lzu.edu.cn/github-release/astral-sh/python-build-standalone", + {NotSkip, NA, NA, + "https://mirror.lzu.edu.cn/github-release/astral-sh/python-build-standalone/20260510/cpython-3.14.5+20260510-i686-pc-windows-msvc-install_only_stripped.tar.gz", + ACCURATE} +}; + +static MirrorSite_t +Py_GHRelease_Aliyun = +{ + IS_DedicatedMirrorSite, + "ali", "Aliyun GitHub Release", "阿里云 GitHub 发布镜像", + "https://mirrors.aliyun.com/github/releases/astral-sh/python-build-standalone", + {NotSkip, NA, NA, + "https://mirrors.aliyun.com/github/releases/astral-sh/python-build-standalone/20260510/cpython-3.14.5+20260510-i686-pc-windows-msvc-install_only_stripped.tar.gz", + ACCURATE} +}; + +/* 内部 target,不注册到 menu,仅用于 chsrc_yield_source 自动测速选取 */ +static Source_t gh_release_sources[] = { + {&UpstreamProvider, "https://github.com/astral-sh/python-build-standalone/releases/download", DelegateToUpstream}, + {&Py_GHRelease_NJU, "https://mirrors.nju.edu.cn/github-release/astral-sh/python-build-standalone", DelegateToMirror}, + {&Py_GHRelease_USTC, "https://mirrors.ustc.edu.cn/github-release/astral-sh/python-build-standalone", DelegateToMirror}, + {&Py_GHRelease_LZU, "https://mirror.lzu.edu.cn/github-release/astral-sh/python-build-standalone", DelegateToMirror}, + {&Py_GHRelease_Aliyun, "https://mirrors.aliyun.com/github/releases/astral-sh/python-build-standalone", DelegateToMirror} +}; - const char *source_content = xy_str_gsub (RAWSTR_pl_python_uv_config_source_content, "@url@", source.url); +static Target_t gh_release_target = { + .sources_n = xy_c_array_len (gh_release_sources), + .sources = gh_release_sources, + .inited = true +}; + + +static void +pl_python_uv_write_pypi_index (const char *uv_config, const char *url) +{ + char *source_content = xy_str_gsub (RAWSTR_pl_python_uv_config_source_content, "@url@", url); if (!xy_file_exist (uv_config)) { - /* 当 uv_config 不存在,直接写入文件 */ chsrc_append_to_file (source_content, uv_config); + return; } + + char *cmd = NULL; + if (xy.on_windows) + cmd = xy_str_gsub (RAWSTR_pl_python_test_uv_if_set_source_on_windows, "@f@", uv_config); else + cmd = xy_str_gsub (RAWSTR_pl_python_test_uv_if_set_source, "@f@", uv_config); + + int status = xy_run_get_status (cmd); + if (0 == status) { - /* 当 uv_config 存在,如果存在 [[index]] 则更新,否则追加到文件末尾 */ - char *cmd = NULL; if (xy.on_windows) { - /* 在 Windows 上使用 PowerShell 替代 grep */ - cmd = xy_str_gsub (RAWSTR_pl_python_test_uv_if_set_source_on_windows, "@f@", uv_config); + char *ps_cmd = xy_str_gsub (RAWSTR_pl_python_set_uv_config_on_windows, "@f@", uv_config); + char *tmp = xy_str_gsub (ps_cmd, "@url@", url); + free (ps_cmd); + chsrc_run (tmp, RunOpt_Default); } else { - cmd = xy_str_gsub (RAWSTR_pl_python_test_uv_if_set_source, "@f@", uv_config); - } - - int status = xy_run_get_status (cmd); - if (0==status) - { - if (xy.on_windows) - { - /* 在 Windows 上使用 PowerShell 替代 sed */ - char *powershell_cmd_with_file = xy_str_gsub(RAWSTR_pl_python_set_uv_config_on_windows, "@f@", uv_config); - char *powershell_cmd = xy_str_gsub(powershell_cmd_with_file, "@url@", source.url); - chsrc_run (powershell_cmd, RunOpt_Default); - } - else - { - /* 非 Windows 系统使用 sed */ - char *sed_cmd = NULL; #if defined(XY_Build_On_macOS) || defined(XY_Build_On_BSD) - sed_cmd = "sed -i '' "; + char *sed_prefix = "sed -i '' "; #else - sed_cmd = "sed -i "; + char *sed_prefix = "sed -i "; #endif - char *update_config_cmd = xy_str_gsub (RAWSTR_pl_python_set_uv_config, "@sed@", sed_cmd); - update_config_cmd = xy_str_gsub (update_config_cmd, "@f@", uv_config); - update_config_cmd = xy_str_gsub (update_config_cmd, "@url@", source.url); - chsrc_run (update_config_cmd, RunOpt_Default); - } + char *cmd2 = xy_str_gsub (RAWSTR_pl_python_set_uv_config, "@sed@", sed_prefix); + char *tmp = xy_str_gsub (cmd2, "@f@", uv_config); + free (cmd2); + cmd2 = xy_str_gsub (tmp, "@url@", url); + free (tmp); + chsrc_run (cmd2, RunOpt_Default); + } + } + else + { + chsrc_append_to_file (source_content, uv_config); + } +} + + +static void +pl_python_uv_write_python_download_mirror (const char *uv_config, Source_t gh_source) +{ + char *content = xy_file_read (uv_config); + if (!content) content = xy_strdup (""); + + size_t estimate = strlen (content) + strlen (gh_source.url) + 128; + char *new_content = xy_malloc0 (estimate); + size_t pos = 0; + + const char *p = content; + while (*p) + { + if (xy_str_start_with (p, "python-install-mirror")) + { + while (*p && *p != '\n') p++; + if (*p == '\n') p++; } else { - chsrc_append_to_file (source_content, uv_config); + while (*p && *p != '\n') new_content[pos++] = *p++; + if (*p == '\n') new_content[pos++] = *p++; } } + pos += snprintf (new_content + pos, estimate - pos, + "python-install-mirror = \"%s\"\n", gh_source.url); + new_content[pos] = '\0'; + + chsrc_overwrite_file (new_content, uv_config); + + free (content); + free (new_content); +} + + +/** + * chsrc set uv + * + * 同时更换两部分: + * 1. PyPI 索引源 ([[index]] 表) + * 2. Python 解释器下载源 (python-install-mirror) + * + * @consult https://docs.astral.sh/uv/reference/settings/#python-install-mirror + */ +void +pl_python_uv_setsrc (char *option) +{ + chsrc_ensure_program ("uv"); + + /* ---- 1. 先获取配置路径,再选取源 ---- */ + char *uv_config = pl_python_find_uv_config (true); + if (NULL == uv_config) + { + chsrc_error2 ("无法获取 uv 配置文件路径"); + return; + } + + Source_t source = chsrc_yield_source (&pl_python_group_target, option); + Source_t gh_source = chsrc_yield_source (&gh_release_target, NULL); + + if (chsrc_in_standalone_mode()) + chsrc_confirm_source (&source); + + /* ---- 2. 写入文件 ---- */ + chsrc_backup (uv_config); + pl_python_uv_write_pypi_index (uv_config, source.url); + pl_python_uv_write_python_download_mirror (uv_config, gh_source); + if (chsrc_in_standalone_mode()) { chsrc_determine_chgtype (ChgType_Auto); From 824e3e7e6480d769c28bf41c6def88a59daa90d5 Mon Sep 17 00:00:00 2001 From: Mikachu2333 Date: Wed, 27 May 2026 18:34:49 +0800 Subject: [PATCH 2/7] =?UTF-8?q?=E4=BF=AE=E5=A4=8Duv=E4=B8=AD=E7=9A=84?= =?UTF-8?q?=E5=BE=AE=E5=B0=8F=E5=86=85=E5=AD=98=E6=B3=84=E6=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/recipe/lang/Python/uv.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/recipe/lang/Python/uv.c b/src/recipe/lang/Python/uv.c index c554159f..235b872e 100644 --- a/src/recipe/lang/Python/uv.c +++ b/src/recipe/lang/Python/uv.c @@ -68,7 +68,9 @@ pl_python_find_uv_config (bool mkdir) { chsrc_ensure_dir (config_dir); } - return xy_2strcat (config_dir, PL_Python_uv_ConfigFile); + char *result = xy_2strcat (config_dir, PL_Python_uv_ConfigFile); + free (config_dir); + return result; } else { @@ -93,6 +95,7 @@ pl_python_uv_getsrc (char *option) chsrc_error2 ("无法获取 uv 配置文件路径"); else chsrc_error2 ("未找到 uv 配置文件"); + free (uv_config); return; } @@ -101,11 +104,13 @@ pl_python_uv_getsrc (char *option) { char *script = xy_str_gsub (RAWSTR_pl_python_get_uv_config_on_windows, "@f@", uv_config); chsrc_run_as_powershell_file (script); + free (script); } else { char *cmd = xy_str_gsub (RAWSTR_pl_python_get_uv_config, "@f@", uv_config); chsrc_run (cmd, RunOpt_Default); + free (cmd); } /* 检查 Python 下载镜像 */ @@ -121,6 +126,8 @@ pl_python_uv_getsrc (char *option) } free (content); } + + free (uv_config); } @@ -139,7 +146,7 @@ Py_GHRelease_NJU = ACCURATE} }; -// 中科大的镜像由于仅保留最新的Latest且文件链接内含动态版本号导致无法测速 +/* 中科大的镜像由于仅保留最新的 Latest 且文件链接内含动态版本号导致无法精准测速 */ static MirrorSite_t Py_GHRelease_USTC = { @@ -197,6 +204,7 @@ pl_python_uv_write_pypi_index (const char *uv_config, const char *url) if (!xy_file_exist (uv_config)) { chsrc_append_to_file (source_content, uv_config); + free (source_content); return; } @@ -207,6 +215,8 @@ pl_python_uv_write_pypi_index (const char *uv_config, const char *url) cmd = xy_str_gsub (RAWSTR_pl_python_test_uv_if_set_source, "@f@", uv_config); int status = xy_run_get_status (cmd); + free (cmd); + if (0 == status) { if (xy.on_windows) @@ -215,6 +225,7 @@ pl_python_uv_write_pypi_index (const char *uv_config, const char *url) char *tmp = xy_str_gsub (ps_cmd, "@url@", url); free (ps_cmd); chsrc_run (tmp, RunOpt_Default); + free (tmp); } else { @@ -229,12 +240,15 @@ pl_python_uv_write_pypi_index (const char *uv_config, const char *url) cmd2 = xy_str_gsub (tmp, "@url@", url); free (tmp); chsrc_run (cmd2, RunOpt_Default); + free (cmd2); } } else { chsrc_append_to_file (source_content, uv_config); } + + free (source_content); } @@ -307,6 +321,8 @@ pl_python_uv_setsrc (char *option) pl_python_uv_write_pypi_index (uv_config, source.url); pl_python_uv_write_python_download_mirror (uv_config, gh_source); + free (uv_config); + if (chsrc_in_standalone_mode()) { chsrc_determine_chgtype (ChgType_Auto); From 29d3dadb564bdb44938f77c99e7a93db2697b415 Mon Sep 17 00:00:00 2001 From: Mikachu2333 Date: Wed, 27 May 2026 19:05:50 +0800 Subject: [PATCH 3/7] =?UTF-8?q?=E9=87=8D=E6=9E=84uv=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E5=86=99=E5=85=A5=E9=80=BB=E8=BE=91=EF=BC=8C?= =?UTF-8?q?=E5=93=8D=E5=BA=94=E9=A1=B9=E7=9B=AE=E7=BA=A7=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/recipe/lang/Python/uv.c | 145 +++++++++++++++++++++++------------- 1 file changed, 94 insertions(+), 51 deletions(-) diff --git a/src/recipe/lang/Python/uv.c b/src/recipe/lang/Python/uv.c index 235b872e..19bea0f8 100644 --- a/src/recipe/lang/Python/uv.c +++ b/src/recipe/lang/Python/uv.c @@ -196,69 +196,97 @@ static Target_t gh_release_target = { }; -static void -pl_python_uv_write_pypi_index (const char *uv_config, const char *url) +/** + * 在 content 中找到 [[index]] 段并替换其 url = "..." 行。 + * 找不到 [[index]] 则追加整个段到末尾。 + * + * @return 新内容 (caller-free) + */ +static char * +replace_pypi_index_url (const char *content, const char *url) { - char *source_content = xy_str_gsub (RAWSTR_pl_python_uv_config_source_content, "@url@", url); + const char *index_tag = "[[index]]"; - if (!xy_file_exist (uv_config)) + char *index_pos = strstr (content, index_tag); + if (!index_pos || (index_pos != content && index_pos[-1] != '\n')) { - chsrc_append_to_file (source_content, uv_config); - free (source_content); - return; + /* 文件中尚无 [[index]] 段,追加到末尾 */ + bool need_sep = (content[0] != '\0'); + size_t len = strlen (content) + strlen (url) + 80; + char *ret = xy_malloc0 (len); + if (need_sep) + snprintf (ret, len, "%s\n[[index]]\nurl = \"%s\"\ndefault = true\n", content, url); + else + snprintf (ret, len, "[[index]]\nurl = \"%s\"\ndefault = true\n", url); + return ret; } - char *cmd = NULL; - if (xy.on_windows) - cmd = xy_str_gsub (RAWSTR_pl_python_test_uv_if_set_source_on_windows, "@f@", uv_config); - else - cmd = xy_str_gsub (RAWSTR_pl_python_test_uv_if_set_source, "@f@", uv_config); + /* 找到 [[index]] 后紧跟的 url = "..." 行 (允许被 default = true 行隔开) */ + const char *search_start = index_pos + strlen (index_tag); + const char *url_key = "url = \""; + char *url_line = NULL; - int status = xy_run_get_status (cmd); - free (cmd); + /* 只在当前 [[index]] 段内搜索: 遇到下一个 [[ 开头的行或文件结尾就停止 */ + const char *next_section = strstr (search_start, "\n[["); + const char *limit = next_section ? next_section + 1 : content + strlen (content); - if (0 == status) + for (const char *p = search_start; p < limit; p++) { - if (xy.on_windows) + if (*p == 'u' && xy_str_start_with (p, url_key) && (p == content || p[-1] == '\n')) { - char *ps_cmd = xy_str_gsub (RAWSTR_pl_python_set_uv_config_on_windows, "@f@", uv_config); - char *tmp = xy_str_gsub (ps_cmd, "@url@", url); - free (ps_cmd); - chsrc_run (tmp, RunOpt_Default); - free (tmp); - } - else - { -#if defined(XY_Build_On_macOS) || defined(XY_Build_On_BSD) - char *sed_prefix = "sed -i '' "; -#else - char *sed_prefix = "sed -i "; -#endif - char *cmd2 = xy_str_gsub (RAWSTR_pl_python_set_uv_config, "@sed@", sed_prefix); - char *tmp = xy_str_gsub (cmd2, "@f@", uv_config); - free (cmd2); - cmd2 = xy_str_gsub (tmp, "@url@", url); - free (tmp); - chsrc_run (cmd2, RunOpt_Default); - free (cmd2); + url_line = (char *)p; + break; } } - else + + if (!url_line) { - chsrc_append_to_file (source_content, uv_config); + /* 有 [[index]] 段但没有 url = "..." 行,追加 url 行 */ + size_t len = strlen (content) + strlen (url) + 32; + char *ret = xy_malloc0 (len); + size_t pos = 0; + + /* 在 [[index]] 行的下一行插入 url */ + const char *insert_at = search_start; + while (*insert_at == '\n') insert_at++; + + pos += snprintf (ret + pos, len - pos, "%.*s", + (int)(insert_at - content), content); + pos += snprintf (ret + pos, len - pos, "url = \"%s\"\n", url); + strcpy (ret + pos, insert_at); + return ret; } - free (source_content); + /* 替换 url = "..." 行 */ + /* 找到该行结尾 */ + char *url_end = strchr (url_line, '\n'); + if (!url_end) url_end = (char *)content + strlen (content); + + size_t est = strlen (content) + strlen (url) + 32; + char *ret = xy_malloc0 (est); + size_t pos = 0; + + /* 拷贝 url_line 之前的内容 */ + pos += snprintf (ret + pos, est - pos, "%.*s", + (int)(url_line - content), content); + /* 写入新的 url 行 */ + pos += snprintf (ret + pos, est - pos, "url = \"%s\"", url); + /* 拷贝 url_line 之后的内容 (从该行原换行符开始, 保留 \n) */ + strcpy (ret + pos, url_end); + + return ret; } -static void -pl_python_uv_write_python_download_mirror (const char *uv_config, Source_t gh_source) +/** + * 过滤 content 中的 python-install-mirror 行,追加新值。 + * + * @return 新内容 (caller-free) + */ +static char * +replace_python_install_mirror (const char *content, const char *url) { - char *content = xy_file_read (uv_config); - if (!content) content = xy_strdup (""); - - size_t estimate = strlen (content) + strlen (gh_source.url) + 128; + size_t estimate = strlen (content) + strlen (url) + 128; char *new_content = xy_malloc0 (estimate); size_t pos = 0; @@ -278,13 +306,29 @@ pl_python_uv_write_python_download_mirror (const char *uv_config, Source_t gh_so } pos += snprintf (new_content + pos, estimate - pos, - "python-install-mirror = \"%s\"\n", gh_source.url); + "python-install-mirror = \"%s\"\n", url); new_content[pos] = '\0'; + return new_content; +} - chsrc_overwrite_file (new_content, uv_config); +/** + * 一次性完成uv配置文件的全部文件操作 + */ +static void +pl_python_uv_write_all (const char *uv_config, const char *pypi_url, const char *py_dl_url) +{ + char *content = xy_file_read (uv_config); + if (!content) content = xy_strdup (""); + + char *updated = replace_pypi_index_url (content, pypi_url); free (content); - free (new_content); + + char *final = replace_python_install_mirror (updated, py_dl_url); + free (updated); + + chsrc_overwrite_file (final, uv_config); + free (final); } @@ -316,10 +360,9 @@ pl_python_uv_setsrc (char *option) if (chsrc_in_standalone_mode()) chsrc_confirm_source (&source); - /* ---- 2. 写入文件 ---- */ + /* ---- 2. 写入文件 (纯C, 无 shell 依赖) ---- */ chsrc_backup (uv_config); - pl_python_uv_write_pypi_index (uv_config, source.url); - pl_python_uv_write_python_download_mirror (uv_config, gh_source); + pl_python_uv_write_all (uv_config, source.url, gh_source.url); free (uv_config); From 928ce52223094764577083da099af361c6b99853 Mon Sep 17 00:00:00 2001 From: Mikachu2333 Date: Wed, 27 May 2026 19:23:14 +0800 Subject: [PATCH 4/7] =?UTF-8?q?uv=E5=93=8D=E5=BA=94reset?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/recipe/lang/Python/uv.c | 116 +++++++++++++++++++++++++++++++++++- 1 file changed, 113 insertions(+), 3 deletions(-) diff --git a/src/recipe/lang/Python/uv.c b/src/recipe/lang/Python/uv.c index 19bea0f8..23d5a417 100644 --- a/src/recipe/lang/Python/uv.c +++ b/src/recipe/lang/Python/uv.c @@ -313,7 +313,84 @@ replace_python_install_mirror (const char *content, const char *url) /** - * 一次性完成uv配置文件的全部文件操作 + * reset 专用: 删除所有 [[index]] 段内的 url 行 (连带 [[index]] 头与 + * default 行一起删除), 删除 python-install-mirror 行, 其余内容原样保留。 + * + * @return 新内容 (caller-free) + */ +static char * +cleanup_config_for_reset (const char *content) +{ + size_t est = strlen (content) + 128; + char *ret = xy_malloc0 (est); + size_t pos = 0; + + const char *p = content; + while (*p) + { + if (xy_str_start_with (p, "[[index]]")) + { + /* 扫描这个 [[index]] 段, 查找是否包含 url = "..." 行 */ + const char *scan = p; + while (*scan && *scan != '\n') scan++; + if (*scan == '\n') scan++; + + bool has_url = false; + const char *scan2 = scan; + while (*scan2 && !xy_str_start_with (scan2, "[[") && !xy_str_start_with (scan2, "[")) + { + if (*scan2 != '\n' && xy_str_start_with (scan2, "url = \"")) + { + has_url = true; + break; + } + while (*scan2 && *scan2 != '\n') scan2++; + if (*scan2 == '\n') scan2++; + } + + if (has_url) + { + /* 跳过整个 [[index]] 段 (包括 [[index]] 头 + url/default 行) */ + p = scan; + while (*p && !xy_str_start_with (p, "[[") && !xy_str_start_with (p, "[")) + { + if (xy_str_start_with (p, "url = \"") || + xy_str_start_with (p, "default = ")) + { + while (*p && *p != '\n') p++; + if (*p == '\n') p++; + } + else + { + /* 遇到非 url/default 行, 段结束 */ + break; + } + } + continue; + } + /* [[index]] 段没有 url, 保留不动, 继续正常拷贝 */ + } + + /* 跳过 python-install-mirror 行 */ + if (xy_str_start_with (p, "python-install-mirror")) + { + while (*p && *p != '\n') p++; + if (*p == '\n') p++; + continue; + } + + /* 拷贝当前行 */ + while (*p && *p != '\n') ret[pos++] = *p++; + if (*p == '\n') ret[pos++] = *p++; + } + + ret[pos] = '\0'; + return ret; +} + + +/** + * 一次性完成uv配置文件的全部文件操作 (set 路径) */ static void pl_python_uv_write_all (const char *uv_config, const char *pypi_url, const char *py_dl_url) @@ -346,7 +423,6 @@ pl_python_uv_setsrc (char *option) { chsrc_ensure_program ("uv"); - /* ---- 1. 先获取配置路径,再选取源 ---- */ char *uv_config = pl_python_find_uv_config (true); if (NULL == uv_config) { @@ -354,13 +430,47 @@ pl_python_uv_setsrc (char *option) return; } + /* reset: 清理 [[index]] 段 url 与 python-install-mirror 行 */ + if (chsrc_in_reset_mode ()) + { + if (!chsrc_check_file (uv_config)) + { + chsrc_info ("没有 uv 配置文件, 无需重置"); + free (uv_config); + return; + } + + /* 读内容, 清理, 直接写回 */ + char *content = xy_file_read (uv_config); + if (!content) + { + chsrc_error2 ("无法读取 uv 配置文件"); + free (uv_config); + return; + } + + char *cleaned = cleanup_config_for_reset (content); + free (content); + + FILE *f = fopen (uv_config, "w"); + if (f) + { + fwrite (cleaned, 1, strlen (cleaned), f); + fclose (f); + } + free (cleaned); + + free (uv_config); + return; + } + + /* set: 选取源并写入 */ Source_t source = chsrc_yield_source (&pl_python_group_target, option); Source_t gh_source = chsrc_yield_source (&gh_release_target, NULL); if (chsrc_in_standalone_mode()) chsrc_confirm_source (&source); - /* ---- 2. 写入文件 (纯C, 无 shell 依赖) ---- */ chsrc_backup (uv_config); pl_python_uv_write_all (uv_config, source.url, gh_source.url); From 1c64b9f08176823ee11012732fd71b05e56fe15d Mon Sep 17 00:00:00 2001 From: Mikachu2333 Date: Wed, 27 May 2026 19:32:37 +0800 Subject: [PATCH 5/7] =?UTF-8?q?=E4=BF=AE=E5=A4=8Duv=E9=87=8D=E7=BD=AE?= =?UTF-8?q?=E6=97=B6=E5=8F=AF=E8=83=BD=E7=9A=84=E6=A0=BC=E5=BC=8F=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/recipe/lang/Python/uv.c | 66 ++++++++++--------------------------- 1 file changed, 17 insertions(+), 49 deletions(-) diff --git a/src/recipe/lang/Python/uv.c b/src/recipe/lang/Python/uv.c index 23d5a417..847d3631 100644 --- a/src/recipe/lang/Python/uv.c +++ b/src/recipe/lang/Python/uv.c @@ -313,8 +313,8 @@ replace_python_install_mirror (const char *content, const char *url) /** - * reset 专用: 删除所有 [[index]] 段内的 url 行 (连带 [[index]] 头与 - * default 行一起删除), 删除 python-install-mirror 行, 其余内容原样保留。 + * reset 专用: 删除所有 [[index]] 段内的 url/default 行 (保留 [[index]] 头 + * 与 name 等其余字段), 删除 python-install-mirror 行, 其余内容原样保留。 * * @return 新内容 (caller-free) */ @@ -328,60 +328,28 @@ cleanup_config_for_reset (const char *content) const char *p = content; while (*p) { - if (xy_str_start_with (p, "[[index]]")) - { - /* 扫描这个 [[index]] 段, 查找是否包含 url = "..." 行 */ - const char *scan = p; - while (*scan && *scan != '\n') scan++; - if (*scan == '\n') scan++; - - bool has_url = false; - const char *scan2 = scan; - while (*scan2 && !xy_str_start_with (scan2, "[[") && !xy_str_start_with (scan2, "[")) - { - if (*scan2 != '\n' && xy_str_start_with (scan2, "url = \"")) - { - has_url = true; - break; - } - while (*scan2 && *scan2 != '\n') scan2++; - if (*scan2 == '\n') scan2++; - } + bool skip = false; - if (has_url) - { - /* 跳过整个 [[index]] 段 (包括 [[index]] 头 + url/default 行) */ - p = scan; - while (*p && !xy_str_start_with (p, "[[") && !xy_str_start_with (p, "[")) - { - if (xy_str_start_with (p, "url = \"") || - xy_str_start_with (p, "default = ")) - { - while (*p && *p != '\n') p++; - if (*p == '\n') p++; - } - else - { - /* 遇到非 url/default 行, 段结束 */ - break; - } - } - continue; - } - /* [[index]] 段没有 url, 保留不动, 继续正常拷贝 */ + if (xy_str_start_with (p, "url = \"") || + xy_str_start_with (p, "default = ")) + { + skip = true; + } + else if (xy_str_start_with (p, "python-install-mirror")) + { + skip = true; } - /* 跳过 python-install-mirror 行 */ - if (xy_str_start_with (p, "python-install-mirror")) + if (skip) { while (*p && *p != '\n') p++; if (*p == '\n') p++; - continue; } - - /* 拷贝当前行 */ - while (*p && *p != '\n') ret[pos++] = *p++; - if (*p == '\n') ret[pos++] = *p++; + else + { + while (*p && *p != '\n') ret[pos++] = *p++; + if (*p == '\n') ret[pos++] = *p++; + } } ret[pos] = '\0'; From 7795ed0b8432b1a2545a493e389b3763771ee8d1 Mon Sep 17 00:00:00 2001 From: Mikachu2333 Date: Wed, 27 May 2026 19:33:42 +0800 Subject: [PATCH 6/7] =?UTF-8?q?=E4=BF=AE=E6=94=B9uv=E7=9A=84=E6=B3=A8?= =?UTF-8?q?=E9=87=8A=E4=B8=AD=E5=8F=AF=E8=83=BD=E4=BA=A7=E7=94=9F=E8=AF=AF?= =?UTF-8?q?=E8=A7=A3=E7=9A=84=E5=9C=B0=E6=96=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/recipe/lang/Python/uv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/recipe/lang/Python/uv.c b/src/recipe/lang/Python/uv.c index 847d3631..d9245cb1 100644 --- a/src/recipe/lang/Python/uv.c +++ b/src/recipe/lang/Python/uv.c @@ -32,7 +32,7 @@ pl_python_uv_prelude (void) /** * chsrc get uv * - * uv 配置文件查找优先级 (代码仅涵盖 ①②,③④为 uv 自身支持): + * uv 配置文件查找优先级: * ① ./uv.toml (项目级) * ② ~/.config/uv/uv.toml (用户级, Windows: %APPDATA%\uv\uv.toml) * ③ $workspace/pyproject.toml (项目级, 未实现) From 9e79f8a4d6926950648dbb3a871ffb2f075f3a48 Mon Sep 17 00:00:00 2001 From: Mikachu2333 Date: Wed, 27 May 2026 19:37:17 +0800 Subject: [PATCH 7/7] =?UTF-8?q?uv=E8=B0=83=E7=94=A8chsrc=5Foverwrite=5Ffil?= =?UTF-8?q?e=E9=81=BF=E5=85=8D=E6=89=8B=E5=8A=A8=E5=A4=84=E7=90=86?= =?UTF-8?q?=E5=86=99=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/recipe/lang/Python/uv.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/recipe/lang/Python/uv.c b/src/recipe/lang/Python/uv.c index d9245cb1..0e0063ea 100644 --- a/src/recipe/lang/Python/uv.c +++ b/src/recipe/lang/Python/uv.c @@ -408,7 +408,7 @@ pl_python_uv_setsrc (char *option) return; } - /* 读内容, 清理, 直接写回 */ + /* 读内容, 清理, 写回 */ char *content = xy_file_read (uv_config); if (!content) { @@ -419,13 +419,7 @@ pl_python_uv_setsrc (char *option) char *cleaned = cleanup_config_for_reset (content); free (content); - - FILE *f = fopen (uv_config, "w"); - if (f) - { - fwrite (cleaned, 1, strlen (cleaned), f); - fclose (f); - } + chsrc_overwrite_file (cleaned, uv_config); free (cleaned); free (uv_config);