Skip to content
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
248 changes: 186 additions & 62 deletions src/recipe/lang/Python/uv.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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 (系统级, 未实现)
Comment thread
Mikachu2333 marked this conversation as resolved.
Outdated
Comment thread
Mikachu2333 marked this conversation as resolved.
Outdated
*/

#define PL_Python_uv_ConfigFile "uv.toml"
Expand All @@ -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)
Expand All @@ -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);
Expand All @@ -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 */
Comment thread
Mikachu2333 marked this conversation as resolved.
char *script = xy_str_gsub (RAWSTR_pl_python_get_uv_config_on_windows, "@f@", uv_config);
chsrc_run_as_powershell_file (script);
Comment thread
Mikachu2333 marked this conversation as resolved.
}
else
{
/* 在类 Unix 系统上使用 grep */
char *cmd = xy_str_gsub (RAWSTR_pl_python_get_uv_config, "@f@", uv_config);
chsrc_run (cmd, RunOpt_Default);
Comment thread
Mikachu2333 marked this conversation as resolved.
}

/* 检查 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
Comment thread
Mikachu2333 marked this conversation as resolved.
Outdated
Py_GHRelease_NJU =
Comment thread
Mikachu2333 marked this conversation as resolved.
Outdated
{
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",
Comment thread
Mikachu2333 marked this conversation as resolved.
Outdated
Comment thread
Mikachu2333 marked this conversation as resolved.
Outdated
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 =
Comment thread
Mikachu2333 marked this conversation as resolved.
Outdated
{
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 =
Comment thread
Mikachu2333 marked this conversation as resolved.
Outdated
{
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",
Comment thread
Mikachu2333 marked this conversation as resolved.
Outdated
Comment thread
Mikachu2333 marked this conversation as resolved.
Outdated
ACCURATE}
};

static MirrorSite_t
Py_GHRelease_Aliyun =
Comment thread
Mikachu2333 marked this conversation as resolved.
Outdated
{
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",
Comment thread
Mikachu2333 marked this conversation as resolved.
Outdated
Comment thread
Mikachu2333 marked this conversation as resolved.
Outdated
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);
Comment thread
Mikachu2333 marked this conversation as resolved.
Outdated
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);
Comment thread
Mikachu2333 marked this conversation as resolved.
Outdated
}
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);
Comment thread
Mikachu2333 marked this conversation as resolved.
Outdated
}
}
else
{
chsrc_append_to_file (source_content, uv_config);
Comment thread
Mikachu2333 marked this conversation as resolved.
Outdated
}
}


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"))
Comment thread
Mikachu2333 marked this conversation as resolved.
{
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);
Comment thread
Mikachu2333 marked this conversation as resolved.
Outdated
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);
Comment thread
Mikachu2333 marked this conversation as resolved.
Outdated

if (chsrc_in_standalone_mode())
{
chsrc_determine_chgtype (ChgType_Auto);
Expand Down
Loading