From 47c2e14b6e736c5c34cd041f18fb867ee65bedb6 Mon Sep 17 00:00:00 2001 From: Aoran Zeng Date: Wed, 19 Aug 2026 18:28:37 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84:=20`yield=20source`=20?= =?UTF-8?q?=E6=97=B6=E5=85=88=E8=80=83=E8=99=91=20`combo`=20=E7=9A=84=20`u?= =?UTF-8?q?ser=20define`=20=E8=83=BD=E5=8A=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chsrc-main.c | 4 +- src/framework/chef.c | 6 +- src/framework/dish.c | 33 +++++- src/framework/helper.c | 2 + src/framework/source.c | 122 ++++++++++---------- src/framework/struct.h | 4 +- src/recipe/lang/Python/uv/uv-pypi-index.c | 2 +- src/recipe/lang/Python/uv/uv-python-build.c | 7 +- src/recipe/lang/Python/uv/uv.c | 3 +- 9 files changed, 109 insertions(+), 74 deletions(-) diff --git a/src/chsrc-main.c b/src/chsrc-main.c index 67461b99..d03d162d 100644 --- a/src/chsrc-main.c +++ b/src/chsrc-main.c @@ -819,7 +819,7 @@ chefs_handle_Set_Source (Dish_t *dish, const char *input, char *option) { if (dish_has_sub_dishes(dish)) { - chsrc_begin_combo_source_resolution (dish); + push_combo_stack (dish); for (size_t i=0; isub_dishes); i++) { @@ -830,7 +830,7 @@ chefs_handle_Set_Source (Dish_t *dish, const char *input, char *option) br(); } - chsrc_end_combo_source_resolution (); + pop_combo_stack (); return; } diff --git a/src/framework/chef.c b/src/framework/chef.c index fab7fe7f..98d3e49e 100644 --- a/src/framework/chef.c +++ b/src/framework/chef.c @@ -414,7 +414,7 @@ chef_allow_user_define (Dish_t *dish) xy_cant_be_null (dish); dish->can_user_define = true; - dish->can_user_define_explain = NULL; + dish->user_define_cap_explain = NULL; } void @@ -424,9 +424,7 @@ chef_deny_user_define (Dish_t *dish) dish->can_user_define = false; - char *reason = CHINESE ? "URL将会根据内部实现重写,因此不能自定义" - : "The URL will be rewritten based on internal implementation, so it cannot be customized"; - dish->can_user_define_explain = reason; + dish->user_define_cap_explain = NULL; } diff --git a/src/framework/dish.c b/src/framework/dish.c index 388fd9aa..c3d83e51 100644 --- a/src/framework/dish.c +++ b/src/framework/dish.c @@ -47,7 +47,7 @@ dish_has_sub_dishes (Dish_t *dish) bool dish_has_source_from_mirror (Dish_t *dish, const char *mirror_code) { - if (!dish || !dish->sources || !code) + if (!dish || !dish->sources || !mirror_code) return false; if (xy_streql (mirror_code, "upstream")) @@ -102,3 +102,34 @@ subdish_sibling_has_source_from_mirror (Dish_t *dish, const char *mirror_code) return false; } + +void +push_combo_stack (Dish_t *combo_dish) +{ + if (ProgStatus.ComboStackDepth >= MaxComboStackDepth) + chsrc_breakdown ("combo dish 嵌套层级过深"); + + int depth = ProgStatus.ComboStackDepth; + ProgStatus.ComboStack[depth] = combo_dish; + ProgStatus.ComboBackedUpPaths[depth] = xy_seq_new (); + ProgStatus.ComboStackDepth++; +} + +void +pop_combo_stack (void) +{ + if (ProgStatus.ComboStackDepth <= 0) + chsrc_breakdown ("combo dish 栈已为空"); + + ProgStatus.ComboStackDepth--; +} + + +Dish_t * +current_combo_dish () +{ + if (ProgStatus.ComboStackDepth <= 0) + return NULL; + + return ProgStatus.ComboStack[ProgStatus.ComboStackDepth - 1]; +} diff --git a/src/framework/helper.c b/src/framework/helper.c index a65d6a8f..1f6ab780 100644 --- a/src/framework/helper.c +++ b/src/framework/helper.c @@ -14,6 +14,8 @@ bool hp_is_url (const char *str) { + if (!str) + return false; return (xy_str_start_with (str, "http://") || xy_str_start_with (str, "https://")); } diff --git a/src/framework/source.c b/src/framework/source.c index f0cf595a..69805aa1 100644 --- a/src/framework/source.c +++ b/src/framework/source.c @@ -14,35 +14,13 @@ * 源的确定 * ------------------------------------------------------------*/ -void -chsrc_begin_combo_source_resolution (Dish_t *dish) -{ - if (ProgStatus.ComboStackDepth >= MaxComboStackDepth) - chsrc_breakdown ("combo dish 嵌套层级过深"); - - int depth = ProgStatus.ComboStackDepth; - ProgStatus.ComboStack[depth] = dish; - ProgStatus.ComboBackedUpPaths[depth] = xy_seq_new (); - ProgStatus.ComboStackDepth++; -} - -void -chsrc_end_combo_source_resolution (void) -{ - if (ProgStatus.ComboStackDepth <= 0) - chsrc_breakdown ("combo dish 栈已为空"); - - ProgStatus.ComboStackDepth--; -} - - /** * 用于 _setsrc() 函数,检测用户输入的镜像站 code,是否存在于该 dish 可用源中 * * @note 一个源Source必定来自于一个Provider,所以该函数名叫 query_mirror_exist * * @param dish_name 菜品名 - * @param input 如果用户输入 default 或者 def,则选择第一个源 + * @param input 如果用户输入 `first`,则选择第一个源 */ int query_mirror_exist (Source_t *sources, size_t size, char *dish_name, char *input) @@ -149,25 +127,28 @@ query_mirror_exist (Source_t *sources, size_t size, char *dish_name, char *input * * @param speed 单位为Byte/s */ -char * +static char * to_human_readable_speed (double speed) { char *scale[] = {"Byte/s", "KByte/s", "MByte/s", "GByte/s", "TByte/s"}; int i = 0; while (speed > 1024.0) - { - i += 1; - speed /= 1024.0; - } + { + i += 1; + speed /= 1024.0; + } char *buf = xy_malloc0 (64); sprintf (buf, "%.2f %s", speed, scale[i]); char *new = NULL; - if (i <= 1 ) new = red (buf); + if (i <= 1 ) + { + new = red(buf); + } else { - if (i == 2 && speed < 2.00) new = yellow (buf); - else new = green (buf); + if (i == 2 && speed < 2.00) new = yellow(buf); + else new = green(buf); } return new; } @@ -181,7 +162,7 @@ to_human_readable_speed (double speed) * * 该函数实际原型为 char * (*)(const char*) */ -void * +static void * measure_speed_for_url (void *url) { char *time_sec = NULL; @@ -224,7 +205,7 @@ measure_speed_for_url (void *url) /** * @return 返回速度speed,单位为 Byte/s */ -double +static double parse_and_say_curl_result (char *curl_buf) { /* 分隔两部分数据 */ @@ -278,7 +259,7 @@ get_max_ele_idx_in_dbl_ary (double *array, int size) * @param size 待测源的数量 * @param[out] speed_records 速度值记录,单位为Byte/s */ -void +static void measure_speed_for_every_source (Source_t sources[], int size, double speed_records[]) { // bool get_measured[size]; /* 是否真正执行了测速 */ @@ -559,19 +540,19 @@ use_specific_mirror_or_auto_select (char *input, Dish_t *dish) } -bool +static bool source_is_upstream (Source_t *source) { return xy_streql (source->mirror->code, "upstream"); } -bool +static bool source_is_userdefine (Source_t *source) { return xy_streql (source->mirror->code, "user"); } -bool +static bool source_has_empty_url (Source_t *source) { return source->url == NULL; @@ -581,22 +562,30 @@ source_has_empty_url (Source_t *source) /** * @brief 在 combo dish 中为当前 sub dish 解析源 * - * 用户只提供一个 code。若当前 sub dish 拥有该 code,直接使用它;否则, - * 若某个兄弟 sub dish 拥有该 code,说明该 code 仅属于另一类源,当前 sub - * dish 应自动测速选择其最快镜像。都不存在时走普通查询路径并报错。 + * 用户只提供一个 mirror code, + * + * 1. 若当前 sub dish 拥有该 code,直接使用它 + * 2. 若1不成立,而某个兄弟 sub dish 拥有该 code,说明该 code 仅属于另一类源, + * 当前 sub dish 应自动测速选择其最快镜像 + * 3. 若1和2都不成立,则直接报错 */ int -chsrc_resolve_combo_subdish_source (Dish_t *dish, char *option) +resolve_combo_subdish_source (Dish_t *dish, char *mirror_code) { - if (dish_has_source_from_mirror (dish, option)) - return query_mirror_exist (dish->sources, dish->sources_n, dish->aliases, option); + if (dish_has_source_from_mirror (dish, mirror_code)) + return query_mirror_exist (dish->sources, dish->sources_n, dish->aliases, mirror_code); - if (subdish_sibling_has_source_from_mirror (dish, option)) - return auto_select_mirror (dish->sources, dish->sources_n, dish->aliases); + if (subdish_sibling_has_source_from_mirror (dish, mirror_code)) + { + chsrc_alert2 (CHINESE ? "当前子菜品没有来自所请求镜像站的源,尝试测速选择最快源" + : "Current sub dish has no source from the requested mirror, try to auto select the fastest source"); + return auto_select_mirror (dish->sources, dish->sources_n, dish->aliases); + } - chsrc_breakdown (ENGLISH - ? "This combo sub dish has no source from the requested mirror" - : "该 combo sub dish 没有所请求镜像站的源"); + + chsrc_error (CHINESE ? "所有的子菜品均没有来自所请求镜像站的源" + : "All sub dishes have no source from the requested mirror"); + exit (Exit_UserCause); return 0; } @@ -629,27 +618,44 @@ chsrc_yield_source (Dish_t *dish, char *option) if (!dish->prepared) dish->preparefn(); Source_t source; + char *user_defined_url = NULL; + char *mirror_code = NULL; + + if (hp_is_url (option)) + { + user_defined_url = option; + } + else if (option) + { + mirror_code = option; + } + + /** + * @note + * 这里的逻辑需要厘清: 这个函数本身,只会被 _setsrc() 调用,而 + * combo dish 自身是没有 _setsrc() 的!所以进入到这里来的,必 + * 定是 combo dish 的 sub dish 的 _setsrc() + */ if (chsrc_in_dish_group_mode() && option) { - if (hp_is_url (option)) + Dish_t *combo_dish = current_combo_dish(); + if (user_defined_url) { - /* combo dish 传入 URL 时,支持该 sub dish 自定义 URL 的则直接使用; - * 不支持则自动选择该 sub dish 的最快源。这样 uv 可只把 URL 当作 - * PyPI index,而 python-install-mirror 仍自动选择。 */ - if (dish->can_user_define) + if (combo_dish->can_user_define) { - Source_t tmp = { &UserDefinedProvider, option }; + Source_t tmp = { &UserDefinedProvider, option, NULL }; source = tmp; } else { - int index = auto_select_mirror (dish->sources, dish->sources_n, dish->aliases); - source = dish->sources[index]; + char *default_msg = "该 combo dish 不支持用户自定义源,可能原因是:该 combo dish 的多个 sub dish 所需要的源不同,无法确定你提供的源到底适用于哪个 sub dish,因此请尝试单独为每个 sub dish 指定源 (使用 chsrc ls 查看其 sub dish 列表)"; + chsrc_error (default_msg); + exit (Exit_Unsupported); } } else { - int index = chsrc_resolve_combo_subdish_source (dish, option); + int index = resolve_combo_subdish_source (dish, mirror_code); source = dish->sources[index]; } } @@ -658,7 +664,7 @@ chsrc_yield_source (Dish_t *dish, char *option) if (!(dish->can_user_define)) { char *en_msg = "Using user-defined sources for this dish is not supported."; - char *zh_msg = dish->can_user_define_explain ? xy_2strcat ("暂不支持对该菜品使用用户自定义源,", dish->can_user_define_explain) : "暂不支持对该菜品使用用户自定义源"; + char *zh_msg = dish->user_define_cap_explain ? xy_2strcat ("暂不支持对该菜品使用用户自定义源,", dish->user_define_cap_explain) : "暂不支持对该菜品使用用户自定义源"; chsrc_error (ENGLISH ? en_msg : zh_msg); exit (Exit_Unsupported); } diff --git a/src/framework/struct.h b/src/framework/struct.h index c35a7c4b..bb576f50 100644 --- a/src/framework/struct.h +++ b/src/framework/struct.h @@ -197,8 +197,8 @@ typedef struct Dish_t /* Features */ bool can_english; /* 是否支持英文输出 */ - bool can_user_define; /* 是否支持用户自定义URL来换源 */ - char *can_user_define_explain; /* 用户自定义URL的说明 */ + bool can_user_define; /* 是否支持用户自定义URL来换源 */ + char *user_define_cap_explain; /* 用户不能自定义URL的原因解释 */ /** * 各作用域的支持情况 diff --git a/src/recipe/lang/Python/uv/uv-pypi-index.c b/src/recipe/lang/Python/uv/uv-pypi-index.c index cd184900..46748502 100644 --- a/src/recipe/lang/Python/uv/uv-pypi-index.c +++ b/src/recipe/lang/Python/uv/uv-pypi-index.c @@ -10,7 +10,7 @@ pl_uv_pypi_index_prepare (void) chef_prep_this_dish (pl_uv_pypi_index, gsr); chef_set_recipe_created_on (this, "2024-12-11"); - chef_set_recipe_last_updated (this, "2026-08-12"); + chef_set_recipe_last_updated (this, "2026-08-19"); chef_set_chefs (this, 3, "@happy-game", "@MingriLingran", "@Mikachu2333"); chef_set_sauciers (this, 2, "@ccmywish", "@Kattos"); diff --git a/src/recipe/lang/Python/uv/uv-python-build.c b/src/recipe/lang/Python/uv/uv-python-build.c index 11742fad..adfbd295 100644 --- a/src/recipe/lang/Python/uv/uv-python-build.c +++ b/src/recipe/lang/Python/uv/uv-python-build.c @@ -26,7 +26,7 @@ pl_uv_python_build_prepare (void) chef_prep_this_dish (pl_uv_python_build, gsr); chef_set_recipe_created_on (this, "2026-08-02"); - chef_set_recipe_last_updated (this, "2026-08-13"); + chef_set_recipe_last_updated (this, "2026-08-19"); chef_set_chefs (this, 2, "@Mikachu2333", "@ccmywish"); chef_set_sauciers (this, 0); @@ -37,10 +37,7 @@ pl_uv_python_build_prepare (void) chef_set_default_scope (this, UserScope); chef_deny_english (this); - chef_deny_user_define (this); - this->can_user_define_explain = - CHINESE ? "python-install-mirror 不支持手动指定,chsrc 会自动选择" - : "python-install-mirror cannot be specified manually; chsrc selects it automatically"; + chef_allow_user_define (this); def_sources_begin () {&UpstreamProvider, "https://github.com/astral-sh/python-build-standalone/releases/download", DelegateToUpstream}, diff --git a/src/recipe/lang/Python/uv/uv.c b/src/recipe/lang/Python/uv/uv.c index 2f6eddbf..34beb577 100644 --- a/src/recipe/lang/Python/uv/uv.c +++ b/src/recipe/lang/Python/uv/uv.c @@ -10,9 +10,10 @@ pl_uv_prepare (void) chef_prep_this_dish (pl_uv, NOOP); chef_set_recipe_created_on (this, "2026-08-12"); - chef_set_recipe_last_updated (this, "2026-08-13"); + chef_set_recipe_last_updated (this, "2026-08-19"); chef_set_sub_dishes (this, 2, &pl_uv_pypi_index_dish, &pl_uv_python_build_dish); + chef_deny_user_define (this); chef_use_other_dish_sources (this, &pl_pypi_dish); }