mirror of
https://github.com/RubyMetric/chsrc
synced 2026-10-25 17:36:32 +08:00
拆分 core.c
This commit is contained in:
7 files changed
+2251
-2207
No files matched your search
@@ -35,7 +35,6 @@
|
||||
|
||||
#include "framework/version.h"
|
||||
#include "framework/foundation.c"
|
||||
#include "framework/helper.c"
|
||||
#include "framework/OS.c"
|
||||
#include "framework/chef.c"
|
||||
#include "framework/dish.c"
|
||||
|
||||
+1023
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
+50
-6
@@ -3,9 +3,10 @@
|
||||
* -------------------------------------------------------------
|
||||
* File Name : dish.c
|
||||
* File Authors : @ccmywish
|
||||
* Contributors : Nil Null <nil@null.org>
|
||||
* Contributors : @Mikachu2333
|
||||
* |
|
||||
* Created On : <2026-08-13>
|
||||
* Last Modified : <2026-08-14>
|
||||
* Last Modified : <2026-08-19>
|
||||
*
|
||||
* dish 为主体的一些函数
|
||||
* ------------------------------------------------------------*/
|
||||
@@ -38,21 +39,64 @@ dish_has_sub_dishes (Dish_t *dish)
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief 判断 dish 是否拥有来自指定镜像站的源
|
||||
*
|
||||
* @note 支持两个 "伪 mirror code": `upstream` 与 `first`
|
||||
*/
|
||||
bool
|
||||
dish_has_source_from_mirror (Dish_t *dish, const char *code)
|
||||
dish_has_source_from_mirror (Dish_t *dish, const char *mirror_code)
|
||||
{
|
||||
if (!dish || !dish->sources || !code)
|
||||
return false;
|
||||
|
||||
if (xy_streql (code, "upstream"))
|
||||
if (xy_streql (mirror_code, "upstream"))
|
||||
return dish->sources_n > 0;
|
||||
|
||||
if (xy_streql (code, "first"))
|
||||
if (xy_streql (mirror_code, "first"))
|
||||
return dish->sources_n > 1;
|
||||
|
||||
for (int i=0; i < dish->sources_n; i++)
|
||||
{
|
||||
if (xy_streql (dish->sources[i].mirror->code, code))
|
||||
if (xy_streql (dish->sources[i].mirror->code, mirror_code))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 判断 dish 的兄弟 sub dish 是否拥有来自指定镜像站的源
|
||||
*
|
||||
* @example
|
||||
*
|
||||
* / `dish` current dish as a sub dish
|
||||
* combo - sibling 1 sub dish
|
||||
* \ sibling 2 sub dish
|
||||
*/
|
||||
static bool
|
||||
subdish_sibling_has_source_from_mirror (Dish_t *dish, const char *mirror_code)
|
||||
{
|
||||
Dish_t *current = dish;
|
||||
|
||||
if (ProgStatus.ComboStackDepth <= 0)
|
||||
return false;
|
||||
|
||||
Dish_t *combo = ProgStatus.ComboStack[ProgStatus.ComboStackDepth - 1];
|
||||
if (!combo || !combo->sub_dishes)
|
||||
return false;
|
||||
|
||||
for (size_t i=0; i < xy_seq_len(combo->sub_dishes); i++)
|
||||
{
|
||||
Dish_t *sub_dish = xy_seq_at (combo->sub_dishes, i);
|
||||
if (sub_dish == current)
|
||||
continue;
|
||||
|
||||
if (!sub_dish->inited)
|
||||
sub_dish->preparefn ();
|
||||
|
||||
if (dish_has_source_from_mirror (sub_dish, mirror_code))
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,242 @@
|
||||
/** ------------------------------------------------------------
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* -------------------------------------------------------------
|
||||
* File Name : foundation.c
|
||||
* File Authors : @ccmywish
|
||||
* | @G_I_Y
|
||||
* Contributors : @happy-game
|
||||
* | @BingChunMoLi
|
||||
* | @Mikachu2333
|
||||
* |
|
||||
* Created On : <2023-08-29>
|
||||
* Last Modified : <2026-08-19>
|
||||
*
|
||||
* framework foundation
|
||||
* ------------------------------------------------------------*/
|
||||
|
||||
#if defined(__STDC__) && __STDC_VERSION__ < 201112L
|
||||
# error "chsrc requires C11 or later, please use a new compiler which at least supports C11"
|
||||
#endif
|
||||
|
||||
#if defined(__STDC__) && __STDC_VERSION__ < 201710L
|
||||
# warning "chsrc recommends a C17 or later compiler"
|
||||
#endif
|
||||
|
||||
#include "xy.h"
|
||||
#include "struct.h"
|
||||
#include "mirror.c"
|
||||
#include "helper.c"
|
||||
|
||||
#define App_Name "chsrc"
|
||||
|
||||
/* Global Program Mode */
|
||||
struct
|
||||
{
|
||||
// 用户命令
|
||||
bool MeasureMode;
|
||||
bool ResetMode;
|
||||
|
||||
// 用户命令选项
|
||||
bool Ipv6Mode;
|
||||
Scope_t Scope;
|
||||
bool EnglishMode;
|
||||
bool DryRunMode;
|
||||
bool NoColorMode;
|
||||
}
|
||||
ProgMode =
|
||||
{
|
||||
.MeasureMode = false,
|
||||
.ResetMode = false,
|
||||
.Ipv6Mode = false,
|
||||
.Scope = ImplementationDefinedScope,
|
||||
.EnglishMode = false,
|
||||
.DryRunMode = false,
|
||||
.NoColorMode = false
|
||||
};
|
||||
|
||||
/* recipe 相关 mode */
|
||||
bool chsrc_in_reset_mode(){return ProgMode.ResetMode;}
|
||||
/* 默认换源作用域就是 ImplementationDefinedScope */
|
||||
bool chsrc_in_default_scope_mode(){return ProgMode.Scope == ImplementationDefinedScope;}
|
||||
bool chsrc_in_user_scope_mode(){return ProgMode.Scope == UserScope;}
|
||||
bool chsrc_in_project_scope_mode(){return ProgMode.Scope == ProjectScope;}
|
||||
bool chsrc_in_system_scope_mode(){return ProgMode.Scope == SystemScope;}
|
||||
|
||||
bool chsrc_in_english_mode(){return ProgMode.EnglishMode;}
|
||||
bool chsrc_in_no_color_mode(){return ProgMode.NoColorMode;}
|
||||
|
||||
/* 仅 framework 相关 mode */
|
||||
static bool in_measure_mode(){return ProgMode.MeasureMode;}
|
||||
static bool in_ipv6_mode(){return ProgMode.Ipv6Mode;}
|
||||
static bool in_dry_run_mode(){return ProgMode.DryRunMode;}
|
||||
|
||||
|
||||
|
||||
typedef enum ChgType_t
|
||||
{
|
||||
ChgType_Auto,
|
||||
ChgType_Reset,
|
||||
ChgType_SemiAuto,
|
||||
ChgType_Manual,
|
||||
ChgType_Untested
|
||||
} ChgType_t;
|
||||
|
||||
#define MaxComboStackDepth 16
|
||||
|
||||
/* Global Program Status */
|
||||
struct
|
||||
{
|
||||
ChgType_t chgtype; /* 换源实现的类型 */
|
||||
|
||||
/* 此时 chsrc_run() 不再是recipe中指定要运行的一个外部命令,而是作为一个功能实现的支撑 */
|
||||
bool chsrc_run_faas;
|
||||
char *user_agent;
|
||||
|
||||
/**
|
||||
* combo dish 嵌套解析栈,该栈记录当前正在处理的 combo dish
|
||||
*
|
||||
* 用户只给一个 code/URL,但不同 sub dish 可能使用不同的源列表
|
||||
*/
|
||||
Dish_t *ComboStack[MaxComboStackDepth];
|
||||
XySeq_t *ComboBackedUpPaths[MaxComboStackDepth];
|
||||
int ComboStackDepth;
|
||||
}
|
||||
ProgStatus =
|
||||
{
|
||||
.chgtype = ChgType_Auto,
|
||||
.chsrc_run_faas = false,
|
||||
.user_agent = "chsrc/" Chsrc_Version,
|
||||
.ComboStackDepth = 0,
|
||||
};
|
||||
|
||||
|
||||
/* Global Program Store */
|
||||
struct
|
||||
{
|
||||
XySeq_t *mirror_sites;
|
||||
XySeq_t *pl;
|
||||
XySeq_t *os;
|
||||
XySeq_t *wr;
|
||||
XyMap_t *contributors; /* 所有贡献者 */
|
||||
}
|
||||
ProgStore =
|
||||
{
|
||||
.mirror_sites = NULL,
|
||||
.pl = NULL,
|
||||
.os = NULL,
|
||||
.wr = NULL,
|
||||
.contributors = NULL,
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Dish Group mode (相反则称为 standalone mode)
|
||||
*
|
||||
* 1. 一个 dish group 包含了多个 dish
|
||||
* 2. 触发该运行模式的 dish 被称为 combo dish,其只是一个 virtual dish,
|
||||
* 类似 APT 中的 virtual package,而这个 combo dish 包含了多个 sub dish
|
||||
*
|
||||
* 目前使用该模式的有3个:
|
||||
* - Python, JavaScript,因为二者的包管理器存在多个
|
||||
* - uv,因为其需要换不止一个源
|
||||
*/
|
||||
bool
|
||||
chsrc_in_dish_group_mode (void)
|
||||
{
|
||||
return ProgStatus.ComboStackDepth > 0;
|
||||
}
|
||||
|
||||
bool
|
||||
chsrc_in_standalone_mode()
|
||||
{
|
||||
return !chsrc_in_dish_group_mode();
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define Exit_OK 0
|
||||
#define Exit_Fatal 1
|
||||
#define Exit_Unknown 2
|
||||
#define Exit_Unsupported 3
|
||||
#define Exit_UserCause 4
|
||||
#define Exit_MaintainerCause 5
|
||||
#define Exit_ExternalError 6
|
||||
|
||||
/* Convenience */
|
||||
#define ENGLISH chsrc_in_english_mode()
|
||||
#define CHINESE !chsrc_in_english_mode()
|
||||
|
||||
#define faint(str) xy_str2faint(str)
|
||||
#define red(str) xy_str2red(str)
|
||||
#define blue(str) xy_str2blue(str)
|
||||
#define green(str) xy_str2green(str)
|
||||
#define yellow(str) xy_str2yellow(str)
|
||||
#define purple(str) xy_str2purple(str)
|
||||
#define bold(str) xy_str2bold(str)
|
||||
#define bdred(str) xy_str2bold(xy_str2red(str))
|
||||
#define bdblue(str) xy_str2bold(xy_str2blue(str))
|
||||
#define bdgreen(str) xy_str2bold(xy_str2green(str))
|
||||
#define bdyellow(str) xy_str2bold(xy_str2yellow(str))
|
||||
#define bdpurple(str) xy_str2bold(xy_str2purple(str))
|
||||
|
||||
#define chsrc_log(str) xy_log(App_Name,str)
|
||||
#define chsrc_succ(str) xy_succ(App_Name,str)
|
||||
#define chsrc_info(str) xy_info(App_Name,str)
|
||||
#define chsrc_warn(str) xy_warn(App_Name,str)
|
||||
#define chsrc_error(str) xy_error(App_Name,str)
|
||||
#ifdef XY_DEBUG
|
||||
#define chsrc_debug(dom,str) xy_warn(App_Name "(DEBUG " dom ")",str)
|
||||
#else
|
||||
#define chsrc_debug(dom,str)
|
||||
#endif
|
||||
#define chsrc_verbose(str) xy_info(App_Name "(VERBOSE)",str)
|
||||
/* 多语句必须括起来,否则在不带 { } 的 if else 等语句中会出错 */
|
||||
#define chsrc_breakdown(reason) { xy_error(App_Name "(BREAKDOWN)",reason); exit(Exit_MaintainerCause); }
|
||||
|
||||
|
||||
/* 2系列都是带有括号的 */
|
||||
#define chsrc_succ2(str) xy_succ_brkt(App_Name,ENGLISH?"SUCCEED":"成功",str)
|
||||
#define chsrc_log2(str) xy_info_brkt(App_Name,"LOG",str)
|
||||
#define chsrc_warn2(str) xy_warn_brkt(App_Name,ENGLISH?"WARN":"警告",str)
|
||||
#define chsrc_error2(str) xy_error_brkt(App_Name,ENGLISH?"ERROR":"错误",str)
|
||||
#ifdef XY_DEBUG
|
||||
#define chsrc_debug2(dom,str) xy_warn_brkt(App_Name,"DEBUG " dom,str)
|
||||
#else
|
||||
#define chsrc_debug2(dom,str)
|
||||
#endif
|
||||
#define chsrc_verbose2(str) xy_info_brkt(App_Name,"VERBOSE",str)
|
||||
|
||||
/**
|
||||
* @note 输出在 stdout 中
|
||||
*/
|
||||
void
|
||||
chsrc_note2 (const char *str)
|
||||
{
|
||||
char *msg = ENGLISH ? "NOTE" : "提示";
|
||||
xy_log_brkt (blue(App_Name), bdblue(msg), blue(str));
|
||||
}
|
||||
|
||||
/**
|
||||
* @note 输出在 stdout 中
|
||||
*/
|
||||
void
|
||||
chsrc_alert2 (const char *str)
|
||||
{
|
||||
char *msg = ENGLISH ? "ALERT" : "提醒";
|
||||
xy_log_brkt (yellow(App_Name), bdyellow(msg), yellow(str));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
chsrc_init_framework ()
|
||||
{
|
||||
xy_init ();
|
||||
|
||||
ProgStore.contributors = xy_map_new ();
|
||||
|
||||
ProgStore.mirror_sites = xy_seq_new ();
|
||||
ProgStore.pl = xy_seq_new ();
|
||||
ProgStore.os = xy_seq_new ();
|
||||
ProgStore.wr = xy_seq_new ();
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* -------------------------------------------------------------
|
||||
* File Name : helper.c
|
||||
* File Authors : 曾奥然 <ccmywish@qq.com>
|
||||
* File Authors : @ccmywish
|
||||
* Contributors : Nul None <nul@none.org>
|
||||
* Created On : <2025-07-14>
|
||||
* Last Modified : <2025-10-28>
|
||||
|
||||
@@ -0,0 +1,935 @@
|
||||
/** ------------------------------------------------------------
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* -------------------------------------------------------------
|
||||
* File Name : source.c
|
||||
* File Authors : @ccmywish
|
||||
* | @G_I_Y
|
||||
* Contributors : @Yangmoooo
|
||||
* | @BingChunMoLi
|
||||
* | @Mikachu2333
|
||||
* |
|
||||
* Created On : <2023-08-29>
|
||||
* Last Modified : <2026-08-19>
|
||||
*
|
||||
* 源的确定
|
||||
* ------------------------------------------------------------*/
|
||||
|
||||
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,则选择第一个源
|
||||
*/
|
||||
int
|
||||
query_mirror_exist (Source_t *sources, size_t size, char *dish_name, char *input)
|
||||
{
|
||||
if (hp_is_url (input))
|
||||
{
|
||||
char *msg = ENGLISH ? "Using user-defined sources for this software is not supported at this time, please contact the developers to ask why or request support" : "暂不支持对该软件使用用户自定义源,请联系开发者询问原因或请求支持";
|
||||
chsrc_error (msg);
|
||||
exit (Exit_Unsupported);
|
||||
}
|
||||
|
||||
if (0==size)
|
||||
{
|
||||
char *msg1 = ENGLISH ? "Currently " : "当前 ";
|
||||
char *msg2 = ENGLISH ? " doesn't have any source available. Please contact the maintainers" : " 无任何可用源,请联系维护者";
|
||||
chsrc_error (xy_strcat (3, msg1, dish_name, msg2));
|
||||
exit (Exit_MaintainerCause);
|
||||
}
|
||||
|
||||
if (1==size)
|
||||
{
|
||||
char *msg1 = ENGLISH ? "Currently " : "当前 ";
|
||||
char *msg2 = ENGLISH ? " only the upstream source exists. Please contact the maintainers" : " 仅存在上游默认源,请联系维护者";
|
||||
chsrc_error (xy_strcat (3, msg1, dish_name, msg2));
|
||||
exit (Exit_MaintainerCause);
|
||||
}
|
||||
|
||||
/* if (xy_streql ("reset", input)) 不再使用这种方式 */
|
||||
if (chsrc_in_reset_mode())
|
||||
{
|
||||
char *msg = ENGLISH ? "Will reset to the upstream's default source" : "将重置为上游默认源";
|
||||
say (msg);
|
||||
return 0; /* 返回第1个,因为第1个是上游默认源 */
|
||||
}
|
||||
|
||||
if (2==size)
|
||||
{
|
||||
char *msg1 = ENGLISH ? " is " : " 是 ";
|
||||
char *msg2 = ENGLISH ? "'s ONLY mirror available currently, thanks for their generous support"
|
||||
: " 目前唯一可用镜像站,感谢他们的慷慨支持";
|
||||
const char *name = ENGLISH ? sources[1].mirror->abbr
|
||||
: sources[1].mirror->name;
|
||||
chsrc_succ (xy_strcat (4, name, msg1, dish_name, msg2));
|
||||
}
|
||||
|
||||
if (xy_streql ("first", input))
|
||||
{
|
||||
char *msg = ENGLISH ? "Will use the first speedy source measured by maintainers" : "将使用维护团队测速第一的源";
|
||||
say (msg);
|
||||
return 1; /* 返回第2个,因为第1个是上游默认源 */
|
||||
}
|
||||
|
||||
int idx = 0;
|
||||
Source_t src = sources[0];
|
||||
|
||||
bool exist = false;
|
||||
for (int i=0; i<size; i++)
|
||||
{
|
||||
src = sources[i];
|
||||
if (xy_streql (src.mirror->code, input))
|
||||
{
|
||||
idx = i;
|
||||
exist = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!exist)
|
||||
{
|
||||
bool mirror_site_exist = false;
|
||||
for (int i=0; i<xy_seq_len(ProgStore.mirror_sites); i++)
|
||||
{
|
||||
MirrorSite_t *mir = xy_seq_at (ProgStore.mirror_sites, i);
|
||||
if (xy_streql_ic (mir->code, input))
|
||||
{
|
||||
mirror_site_exist = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (mirror_site_exist)
|
||||
{
|
||||
char *msg1 = ENGLISH ? "Mirror site " : "镜像站 ";
|
||||
char *msg2 = ENGLISH ? " exists, but is not available for this software" : " 存在,但未提供该软件源";
|
||||
chsrc_error (xy_strcat (3, msg1, input, msg2));
|
||||
exit (Exit_UserCause);
|
||||
}
|
||||
else
|
||||
{
|
||||
char *msg1 = ENGLISH ? "Mirror site " : "镜像站 ";
|
||||
char *msg2 = ENGLISH ? " doesn't exist" : " 不存在";
|
||||
chsrc_error (xy_strcat (3, msg1, input, msg2));
|
||||
}
|
||||
|
||||
char *msg = ENGLISH ? "To see available sources, use chsrc list " : "查看可使用源,请使用 chsrc list ";
|
||||
chsrc_error (xy_2strcat (msg, dish_name));
|
||||
exit (Exit_UserCause);
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 该函数来自 oh-my-mirrorz.py,由 @ccmywish 翻译为C语言,但功劳和版权属于原作者
|
||||
*
|
||||
* @param speed 单位为Byte/s
|
||||
*/
|
||||
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;
|
||||
}
|
||||
char *buf = xy_malloc0 (64);
|
||||
sprintf (buf, "%.2f %s", speed, scale[i]);
|
||||
|
||||
char *new = NULL;
|
||||
if (i <= 1 ) new = red (buf);
|
||||
else
|
||||
{
|
||||
if (i == 2 && speed < 2.00) new = yellow (buf);
|
||||
else new = green (buf);
|
||||
}
|
||||
return new;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 测速代码参考自 https://github.com/mirrorz-org/oh-my-mirrorz/blob/master/oh-my-mirrorz.py
|
||||
* 功劳和版权属于原作者,由 @ccmywish 修改为C语言,并做了额外调整
|
||||
*
|
||||
* @return 返回测得的速度,若出错,返回-1
|
||||
*
|
||||
* 该函数实际原型为 char * (*)(const char*)
|
||||
*/
|
||||
void *
|
||||
measure_speed_for_url (void *url)
|
||||
{
|
||||
char *time_sec = NULL;
|
||||
|
||||
time_sec = "8";
|
||||
|
||||
/**
|
||||
* 现在我们切换至跳转后的链接来测速,不再使用下述判断
|
||||
*
|
||||
* if (xy_str_start_with(url, "https://registry.npmmirror"))
|
||||
* {
|
||||
* // 这里 npmmirror 跳转非常慢,需要1~3秒,所以我们给它留够至少8秒测速时间,否则非常不准
|
||||
* time_sec = "10";
|
||||
* }
|
||||
*/
|
||||
|
||||
char *ipv6 = ""; // 默认不启用
|
||||
|
||||
if (in_ipv6_mode())
|
||||
{
|
||||
ipv6 = "--ipv6";
|
||||
}
|
||||
|
||||
char *os_devnull = xy.os_devnull;
|
||||
|
||||
/**
|
||||
* @note 我们用 —L,因为部分链接会跳转到其他地方,比如: RubyChina, npmmirror
|
||||
*/
|
||||
char *curl_cmd = xy_strcat (10, "curl -qsL ", ipv6,
|
||||
" -o ", os_devnull,
|
||||
" -w \"%{http_code} %{speed_download}\" -m", time_sec,
|
||||
" -A ", ProgStatus.user_agent, " ", url);
|
||||
|
||||
// chsrc_note2 (xy_2strcat ("测速命令 ", curl_cmd));
|
||||
char *curl_buf = xy_run (curl_cmd, 0);
|
||||
return curl_buf;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return 返回速度speed,单位为 Byte/s
|
||||
*/
|
||||
double
|
||||
parse_and_say_curl_result (char *curl_buf)
|
||||
{
|
||||
/* 分隔两部分数据 */
|
||||
char *split = strchr (curl_buf, ' ');
|
||||
if (split) *split = '\0';
|
||||
|
||||
// say(curl_buf); say(split+1);
|
||||
int http_code = xy_str2int (curl_buf);
|
||||
double speed = xy_str2float (split+1);
|
||||
char *speedstr = to_human_readable_speed (speed);
|
||||
|
||||
/* xy_str2int() 可能会返回0,表示转换失败 */
|
||||
if (0==http_code)
|
||||
{
|
||||
char *msg = ENGLISH ? "ERROR curl output: " : "错误 curl 输出: ";
|
||||
println (red (xy_strcat (3, msg, curl_buf)));
|
||||
}
|
||||
else if (200!=http_code)
|
||||
{
|
||||
char *http_code_str = yellow (xy_2strcat ("HTTP码 ", curl_buf));
|
||||
println (xy_strcat (3, speedstr, " | ", http_code_str));
|
||||
}
|
||||
else
|
||||
{
|
||||
println (speedstr);
|
||||
}
|
||||
return speed;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
get_max_ele_idx_in_dbl_ary (double *array, int size)
|
||||
{
|
||||
double maxval = array[0];
|
||||
int maxidx = 0;
|
||||
|
||||
for (int i=1; i<size; i++)
|
||||
{
|
||||
if (array[i]>maxval)
|
||||
{
|
||||
maxval = array[i];
|
||||
maxidx = i;
|
||||
}
|
||||
}
|
||||
return maxidx;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param sources 所有待测源
|
||||
* @param size 待测源的数量
|
||||
* @param[out] speed_records 速度值记录,单位为Byte/s
|
||||
*/
|
||||
void
|
||||
measure_speed_for_every_source (Source_t sources[], int size, double speed_records[])
|
||||
{
|
||||
// bool get_measured[size]; /* 是否真正执行了测速 */
|
||||
int get_measured_n = 0; /* 测速了几个 */
|
||||
char *measure_msgs[size];
|
||||
|
||||
double speed = 0.0;
|
||||
|
||||
for (int i=0; i<size; i++)
|
||||
{
|
||||
Source_t src = sources[i];
|
||||
|
||||
SourceProvider_t *provider = src.provider;
|
||||
ProviderSpeedMeasureInfo_t psmi = provider->psmi;
|
||||
|
||||
bool provider_skip = psmi.skip;
|
||||
|
||||
bool has_dedicated_speed_url = false;
|
||||
|
||||
/**
|
||||
* 存在两类测速链接
|
||||
* 1. 有*专用测速链接*时,我们选专用,这是精准测速
|
||||
* 2. 若无,我们用*镜像站整体测速链接*来进行代替,
|
||||
* 若是专用镜像站,则是精准测速
|
||||
* 若是通用镜像站,则是模糊测速
|
||||
*/
|
||||
const char *provider_speed_url = psmi.url;
|
||||
const char *dedicated_speed_url = src.speed_measure_url;
|
||||
|
||||
/* 最终用来测速的 URL */
|
||||
char *url = NULL;
|
||||
|
||||
if (!provider_skip && !provider_speed_url)
|
||||
/* 没有声明跳过,但是却没有提供 URL,这是维护者维护时出了纰漏,我们软处理 */
|
||||
{
|
||||
char *msg1 = ENGLISH ? "Maintainers don't offer " : "维护者未提供 ";
|
||||
char *msg2 = ENGLISH ? " mirror site's speed measure link, so skip it" : " 镜像站测速链接,跳过该站点(需修复)";
|
||||
chsrc_warn (xy_strcat (3, msg1, provider->code, msg2));
|
||||
speed = 0;
|
||||
|
||||
speed_records[i] = speed;
|
||||
// get_measured[i] = false;
|
||||
measure_msgs[i] = NULL;
|
||||
}
|
||||
else if (!provider_skip && provider_speed_url)
|
||||
{
|
||||
if (hp_is_url (provider_speed_url))
|
||||
{
|
||||
url = xy_strdup (provider_speed_url);
|
||||
chsrc_debug ("m", xy_2strcat ("使用镜像站整体测速链接: ", url));
|
||||
}
|
||||
}
|
||||
else if (provider_skip)
|
||||
{
|
||||
/* Provider 被声明为跳过测速,下方判断精准测速链接有无提供,若也没有提供,将会输出跳过原因 */
|
||||
}
|
||||
|
||||
if (dedicated_speed_url)
|
||||
{
|
||||
if (hp_is_url (dedicated_speed_url))
|
||||
{
|
||||
url = xy_strdup (dedicated_speed_url);
|
||||
has_dedicated_speed_url = true;
|
||||
chsrc_debug ("m", xy_2strcat ("使用专用测速链接: ", url));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 防止维护者没填,这里有一些脏数据,我们软处理:假装该链接URL不存在 */
|
||||
has_dedicated_speed_url = false;
|
||||
chsrc_debug ("m", xy_2strcat ("专用测速链接为脏数据,请修复: ", provider->name));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (provider_skip && !has_dedicated_speed_url)
|
||||
{
|
||||
if (xy_streql ("upstream", provider->code))
|
||||
{
|
||||
/* 上游源不测速,但不置0,因为要避免这么一种情况: 可能其他镜像站测速都为0,最后反而选择了该 upstream */
|
||||
speed = -1024*1024*1024;
|
||||
if (!src.url)
|
||||
{
|
||||
psmi.skip_reason_ZH = "缺乏对上游默认源进行测速的URL,请帮助补充";
|
||||
psmi.skip_reason_EN = "Lack of URL to measure upstream default source provider, please help to add";
|
||||
}
|
||||
}
|
||||
else if (xy_streql ("user", provider->code))
|
||||
{
|
||||
/* 代码不会执行至此 */
|
||||
speed = 1024*1024*1024;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 不测速的 Provider */
|
||||
speed = 0;
|
||||
}
|
||||
// get_measured[i] = false;
|
||||
speed_records[i] = speed;
|
||||
|
||||
const char *msg = ENGLISH ? provider->abbr : provider->name;
|
||||
const char *skip_reason = ENGLISH ? psmi.skip_reason_EN : psmi.skip_reason_ZH;
|
||||
if (NULL==skip_reason)
|
||||
{
|
||||
skip_reason = ENGLISH ? "SKIP for no reason" : "无理由跳过";
|
||||
}
|
||||
measure_msgs[i] = xy_strcat (4, faint(" x "), msg, " ", yellow(faint(skip_reason)));
|
||||
println (measure_msgs[i]);
|
||||
|
||||
/* 下一位 */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* 此时,一定获得了一个用于测速的链接 */
|
||||
if (url)
|
||||
{
|
||||
const char *msg = ENGLISH ? provider->abbr : provider->name;
|
||||
|
||||
bool is_accurate = false;
|
||||
if (has_dedicated_speed_url)
|
||||
{
|
||||
is_accurate = true;
|
||||
}
|
||||
else if (provider->psmi.accurate)
|
||||
{
|
||||
is_accurate = true;
|
||||
}
|
||||
|
||||
char *accurate_msg = CHINESE ? (is_accurate ? bdblue(faint("[精准测速]")) : faint("[模糊测速]"))
|
||||
: (is_accurate ? bdblue(faint("[accurate]")) : faint("[rough]"));
|
||||
|
||||
if (xy_streql ("upstream", provider->code))
|
||||
{
|
||||
measure_msgs[i] = xy_strcat (7, faint(" ^ "), msg, " (", src.url, ") ", accurate_msg, faint(" ... "));
|
||||
}
|
||||
else
|
||||
{
|
||||
measure_msgs[i] = xy_strcat (5, faint(" - "), msg, " ", accurate_msg, faint(" ... "));
|
||||
}
|
||||
|
||||
print (measure_msgs[i]);
|
||||
fflush (stdout);
|
||||
|
||||
char *curl_result = measure_speed_for_url (url);
|
||||
double speed = parse_and_say_curl_result (curl_result);
|
||||
speed_records[i] = speed;
|
||||
|
||||
/* 释放 url 内存 */
|
||||
if (url) free (url);
|
||||
}
|
||||
else
|
||||
{
|
||||
xy_unreached();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 自动测速选择镜像站和源
|
||||
*/
|
||||
int
|
||||
auto_select_mirror (Source_t *sources, size_t size, const char *dish_name)
|
||||
{
|
||||
/* reset 时选择默认源 */
|
||||
if (chsrc_in_reset_mode())
|
||||
return 0;
|
||||
|
||||
if (!in_dry_run_mode())
|
||||
{
|
||||
char *msg = ENGLISH ? "Measuring speed in sequence" : "测速中";
|
||||
xy_log_brkt (App_Name, bdpurple (ENGLISH ? "MEASURE" : "测速"), msg);
|
||||
br();
|
||||
}
|
||||
|
||||
if (0==size || 1==size)
|
||||
{
|
||||
char *msg1 = ENGLISH ? "Currently " : "当前 ";
|
||||
char *msg2 = ENGLISH ? "No any source, please contact maintainers: chsrc issue" : " 无任何可用源,请联系维护者: chsrc issue";
|
||||
chsrc_error (xy_strcat (3, msg1, dish_name, msg2));
|
||||
exit (Exit_MaintainerCause);
|
||||
}
|
||||
|
||||
if (in_dry_run_mode())
|
||||
/* Dry Run 时,跳过测速 */
|
||||
{
|
||||
return 1; /* 原则第一个源 */
|
||||
}
|
||||
|
||||
bool only_one = false;
|
||||
if (2==size) only_one = true;
|
||||
|
||||
/** --------------------------------------------- */
|
||||
bool exist_curl = chsrc_check_program_quietly_when_exist ("curl");
|
||||
if (!exist_curl)
|
||||
{
|
||||
char *msg = ENGLISH ? "No curl, unable to measure speed" : "没有curl命令,无法测速";
|
||||
chsrc_error (msg);
|
||||
exit (Exit_UserCause);
|
||||
}
|
||||
|
||||
if (xy.on_windows)
|
||||
{
|
||||
char *curl_version = xy_run ("curl --version", 1);
|
||||
/**
|
||||
* https://github.com/RubyMetric/chsrc/issues/144
|
||||
*
|
||||
* Cygwin上,curl 的版本信息为:
|
||||
*
|
||||
* curl 8.9.1 (x86_64-pc-cygwin)
|
||||
*
|
||||
*/
|
||||
if (strstr (curl_version, "pc-cygwin"))
|
||||
{
|
||||
char *msg = ENGLISH ? "You're using curl built by Cygwin which has a bug! Please use another curl!" : "你使用的是Cygwin构建的curl,该版本的curl存在bug,请改用其他版本的curl";
|
||||
chsrc_error (msg);
|
||||
exit (Exit_UserCause);
|
||||
}
|
||||
}
|
||||
/** --------------------------------------------- */
|
||||
|
||||
/* 总测速记录值 */
|
||||
double speed_records[size];
|
||||
measure_speed_for_every_source (sources, size, speed_records);
|
||||
br();
|
||||
|
||||
/* DEBUG */
|
||||
/*
|
||||
for (int i=0; i<size; i++)
|
||||
{
|
||||
printf ("speed_records[%d] = %f\n", i, speed_records[i]);
|
||||
}
|
||||
*/
|
||||
|
||||
int fast_idx = get_max_ele_idx_in_dbl_ary (speed_records, size);
|
||||
|
||||
if (only_one)
|
||||
{
|
||||
char *msg1 = ENGLISH ? "NOTICE mirror site: " : "镜像站提示: ";
|
||||
char *is = ENGLISH ? " is " : " 是 ";
|
||||
char *msg2 = ENGLISH ? "'s ONLY mirror available currently, thanks for their generous support"
|
||||
: " 目前唯一可用镜像站,感谢他们的慷慨支持";
|
||||
const char *name = ENGLISH ? sources[fast_idx].mirror->abbr
|
||||
: sources[fast_idx].mirror->name;
|
||||
say (xy_strcat (5, msg1, bdgreen(name), green(is), green(dish_name), green(msg2)));
|
||||
}
|
||||
else
|
||||
{
|
||||
char *msg = ENGLISH ? "FASTEST mirror site: " : "最快镜像站: ";
|
||||
const char *name = ENGLISH ? sources[fast_idx].mirror->abbr
|
||||
: sources[fast_idx].mirror->name;
|
||||
say (xy_2strcat (msg, green(name)));
|
||||
}
|
||||
|
||||
// https://github.com/RubyMetric/chsrc/pull/71
|
||||
if (in_measure_mode())
|
||||
{
|
||||
char *msg = ENGLISH ? "URL of above source: " : "镜像源地址: ";
|
||||
say (xy_2strcat (msg, green(sources[fast_idx].url)));
|
||||
}
|
||||
|
||||
return fast_idx;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
use_specific_mirror_or_auto_select (char *input, Dish_t *dish)
|
||||
{
|
||||
if (input)
|
||||
{
|
||||
return query_mirror_exist (dish->sources, dish->sources_n, dish->aliases, input);
|
||||
}
|
||||
else
|
||||
{
|
||||
return auto_select_mirror (dish->sources, dish->sources_n, dish->aliases);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
source_is_upstream (Source_t *source)
|
||||
{
|
||||
return xy_streql (source->mirror->code, "upstream");
|
||||
}
|
||||
|
||||
bool
|
||||
source_is_userdefine (Source_t *source)
|
||||
{
|
||||
return xy_streql (source->mirror->code, "user");
|
||||
}
|
||||
|
||||
bool
|
||||
source_has_empty_url (Source_t *source)
|
||||
{
|
||||
return source->url == NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 在 combo dish 中为当前 sub dish 解析源
|
||||
*
|
||||
* 用户只提供一个 code。若当前 sub dish 拥有该 code,直接使用它;否则,
|
||||
* 若某个兄弟 sub dish 拥有该 code,说明该 code 仅属于另一类源,当前 sub
|
||||
* dish 应自动测速选择其最快镜像。都不存在时走普通查询路径并报错。
|
||||
*/
|
||||
int
|
||||
chsrc_resolve_combo_subdish_source (Dish_t *dish, char *option)
|
||||
{
|
||||
if (dish_has_source_from_mirror (dish, option))
|
||||
return query_mirror_exist (dish->sources, dish->sources_n, dish->aliases, option);
|
||||
|
||||
if (subdish_sibling_has_source_from_mirror (dish, option))
|
||||
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 没有所请求镜像站的源");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief 为该 dish 确定最终将使用的源
|
||||
*
|
||||
* 用户*只可能*通过下面5种方式来换源,无论哪一种都会返回一个 Source_t 出来
|
||||
*
|
||||
* 1. 用户指定了一个 Mirror Code,即 chsrc set <dish> <code>
|
||||
* 2. 用户指定了一个 URL, 即 chsrc set <dish> https://ur
|
||||
* 3. 用户什么都没指定, 即 chsrc set <dish>
|
||||
* 4. 用户正在重置源, 即 chsrc reset <dish>
|
||||
*
|
||||
* 如果处于 combo source resolution 上下文中,则按 sub dish 与 sibling
|
||||
* 的源列表集中决定:code 命中本 dish 则直接使用;命中 sibling 则本 dish
|
||||
* 自动测速;传入 URL 时,支持自定义 URL 的 sub dish 使用 URL,其余自动测速。
|
||||
*
|
||||
*/
|
||||
Source_t
|
||||
chsrc_yield_source (Dish_t *dish, char *option)
|
||||
{
|
||||
/**
|
||||
* 防止某些意外时刻 _setsrc() 等函数会被直接调,但此时 _prepare() 还没有执行过
|
||||
* 我们在这里卡一道,确保 _prepare() 被调用
|
||||
*
|
||||
* 目前可能出现这种情况的时候:组换源的时候,sub dishes 的 _setsrc() 被直接调用
|
||||
*/
|
||||
if (!dish->inited) dish->preparefn();
|
||||
|
||||
Source_t source;
|
||||
if (chsrc_in_dish_group_mode() && option)
|
||||
{
|
||||
if (hp_is_url (option))
|
||||
{
|
||||
/* combo dish 传入 URL 时,支持该 sub dish 自定义 URL 的则直接使用;
|
||||
* 不支持则自动选择该 sub dish 的最快源。这样 uv 可只把 URL 当作
|
||||
* PyPI index,而 python-install-mirror 仍自动选择。 */
|
||||
if (dish->can_user_define)
|
||||
{
|
||||
Source_t tmp = { &UserDefinedProvider, option };
|
||||
source = tmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
int index = auto_select_mirror (dish->sources, dish->sources_n, dish->aliases);
|
||||
source = dish->sources[index];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int index = chsrc_resolve_combo_subdish_source (dish, option);
|
||||
source = dish->sources[index];
|
||||
}
|
||||
}
|
||||
else if (hp_is_url (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) : "暂不支持对该菜品使用用户自定义源";
|
||||
chsrc_error (ENGLISH ? en_msg : zh_msg);
|
||||
exit (Exit_Unsupported);
|
||||
}
|
||||
Source_t tmp = { &UserDefinedProvider, option };
|
||||
source = tmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
int index = use_specific_mirror_or_auto_select (option, dish);
|
||||
source = dish->sources[index];
|
||||
}
|
||||
return source;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#define hr() say ("--------------------------------");
|
||||
|
||||
|
||||
/**
|
||||
* 用于 _setsrc 函数
|
||||
*
|
||||
* 1. 告知用户选择了什么源和镜像
|
||||
* 2. 对选择的源和镜像站进行一定的校验
|
||||
*/
|
||||
void
|
||||
chsrc_confirm_source (Source_t *source)
|
||||
{
|
||||
// 由于实现问题,我们把本应该独立出去的上游默认源,也放在了可以换源的数组中,而且放在第一个
|
||||
// chsrc 已经规避用户使用未实现的 `chsrc reset`
|
||||
// 但是某些用户可能摸索着强行使用 chsrc set dish upstream,从而执行起该禁用的功能,
|
||||
// 之所以禁用,是因为有的 reset 我们并没有实现,我们在这里阻止这些邪恶的用户
|
||||
if (source_is_upstream (source) && source_has_empty_url (source))
|
||||
{
|
||||
char *msg = ENGLISH ? "Not implement `reset` for the dish yet" : "暂未对该菜品实现重置";
|
||||
chsrc_error (msg);
|
||||
exit (Exit_Unsupported);
|
||||
}
|
||||
else if (source_has_empty_url (source))
|
||||
{
|
||||
char *msg = ENGLISH ? "URL of the source doesn't exist, please report a bug to the dev team" : \
|
||||
"该源URL不存在,请向维护团队提交bug";
|
||||
chsrc_error (msg);
|
||||
exit (Exit_MaintainerCause);
|
||||
}
|
||||
else
|
||||
{
|
||||
char *msg = ENGLISH ? "SELECT mirror site: " : "选中镜像站: ";
|
||||
say (xy_strcat (5, msg, green (source->mirror->abbr), " (", green (source->mirror->code), ")"));
|
||||
}
|
||||
|
||||
hr();
|
||||
}
|
||||
|
||||
|
||||
Source_t
|
||||
chsrc_yield_source_and_confirm (Dish_t *dish, char *option)
|
||||
{
|
||||
Source_t source = chsrc_yield_source(dish, option);
|
||||
chsrc_confirm_source(&source);
|
||||
return source;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
chsrc_determine_chgtype (ChgType_t type)
|
||||
{
|
||||
ProgStatus.chgtype = chsrc_in_reset_mode() ? ChgType_Reset : type;
|
||||
}
|
||||
|
||||
|
||||
#define MSG_EN_PUBLIC_URL "If the URL you specify is a public service, you are invited to contribute: chsrc issue"
|
||||
#define MSG_ZH_PUBLIC_URL "若您指定的URL为公有服务,邀您参与贡献: chsrc issue"
|
||||
|
||||
#define MSG_EN_FULLY_AUTO "Fully-Auto changed source. "
|
||||
#define MSG_ZH_FULLY_AUTO "全自动换源完成"
|
||||
|
||||
#define MSG_EN_SEMI_AUTO "Semi-Auto changed source. "
|
||||
#define MSG_ZH_SEMI_AUTO "半自动换源完成"
|
||||
|
||||
#define MSG_EN_THANKS "Thanks to the mirror site: "
|
||||
#define MSG_ZH_THANKS "感谢镜像提供方: "
|
||||
|
||||
#define MSG_EN_BETTER "If you have a better source changing method , please help: chsrc issue"
|
||||
#define MSG_ZH_BETTER "若您有更好的换源方案,邀您帮助: chsrc issue"
|
||||
|
||||
#define MSG_EN_CONSTRAINT "Implementation constraints require manual operation according to the above prompts. "
|
||||
#define MSG_ZH_CONSTRAINT "因实现约束需按上述提示手工操作"
|
||||
|
||||
#define MSG_EN_STILL "Still need to operate manually according to the above prompts. "
|
||||
#define MSG_ZH_STILL "仍需按上述提示手工操作"
|
||||
|
||||
#define thank_mirror(msg) say(xy_2strcat(msg,purple(ENGLISH?source->mirror->abbr:source->mirror->name)))
|
||||
|
||||
/**
|
||||
* @param source 可为NULL
|
||||
*
|
||||
* @dependency @gvar:ProgStatus.chgtype
|
||||
*/
|
||||
void
|
||||
chsrc_conclude (Source_t *source)
|
||||
{
|
||||
hr();
|
||||
|
||||
// fprintf (stderr, "chsrc: now change type: %d\n", ProgStatus.chgtype);
|
||||
if (chsrc_in_reset_mode())
|
||||
{
|
||||
// source_is_upstream (source)
|
||||
char *msg = CHINESE ? "已重置为上游默认源"
|
||||
: "Has been reset to the upstream default source";
|
||||
chsrc_log (purple (msg));
|
||||
}
|
||||
else if (ChgType_Auto == ProgStatus.chgtype)
|
||||
{
|
||||
if (source)
|
||||
{
|
||||
if (source_is_userdefine (source))
|
||||
{
|
||||
char *msg = ENGLISH ? MSG_EN_FULLY_AUTO MSG_EN_PUBLIC_URL \
|
||||
: MSG_ZH_FULLY_AUTO ", " MSG_ZH_PUBLIC_URL;
|
||||
chsrc_log (msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
char *msg = ENGLISH ? MSG_EN_FULLY_AUTO MSG_EN_THANKS \
|
||||
: MSG_ZH_FULLY_AUTO ", " MSG_ZH_THANKS;
|
||||
thank_mirror (msg);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
char *msg = ENGLISH ? MSG_EN_FULLY_AUTO : MSG_ZH_FULLY_AUTO;
|
||||
chsrc_log (msg);
|
||||
}
|
||||
}
|
||||
else if (ChgType_SemiAuto == ProgStatus.chgtype)
|
||||
{
|
||||
if (source)
|
||||
{
|
||||
if (source_is_userdefine (source))
|
||||
{
|
||||
char *msg = ENGLISH ? MSG_EN_SEMI_AUTO MSG_EN_STILL MSG_EN_PUBLIC_URL \
|
||||
: MSG_ZH_SEMI_AUTO ", " MSG_ZH_STILL "。" MSG_ZH_PUBLIC_URL;
|
||||
chsrc_log (msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
char *msg = ENGLISH ? MSG_EN_SEMI_AUTO MSG_EN_STILL MSG_EN_THANKS \
|
||||
: MSG_ZH_SEMI_AUTO ", " MSG_ZH_STILL "。" MSG_ZH_THANKS;
|
||||
thank_mirror (msg);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
char *msg = ENGLISH ? MSG_EN_SEMI_AUTO MSG_EN_STILL \
|
||||
: MSG_ZH_SEMI_AUTO ", " MSG_ZH_STILL;
|
||||
chsrc_log (msg);
|
||||
}
|
||||
|
||||
char *msg = ENGLISH ? MSG_EN_BETTER : MSG_ZH_BETTER;
|
||||
chsrc_warn (msg);
|
||||
}
|
||||
else if (ChgType_Manual == ProgStatus.chgtype)
|
||||
{
|
||||
if (source)
|
||||
{
|
||||
if (source_is_userdefine (source))
|
||||
{
|
||||
char *msg = ENGLISH ? MSG_EN_CONSTRAINT MSG_EN_PUBLIC_URL \
|
||||
: MSG_ZH_CONSTRAINT "; " MSG_ZH_PUBLIC_URL;
|
||||
chsrc_log (msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
char *msg = ENGLISH ? MSG_EN_CONSTRAINT MSG_EN_THANKS \
|
||||
: MSG_ZH_CONSTRAINT ", " MSG_ZH_THANKS;
|
||||
thank_mirror (msg);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
char *msg = ENGLISH ? MSG_EN_CONSTRAINT : MSG_ZH_CONSTRAINT;
|
||||
chsrc_log (msg);
|
||||
}
|
||||
char *msg = ENGLISH ? MSG_EN_BETTER : MSG_ZH_BETTER;
|
||||
chsrc_warn (msg);
|
||||
}
|
||||
else if (ChgType_Untested == ProgStatus.chgtype)
|
||||
{
|
||||
if (source)
|
||||
{
|
||||
if (source_is_userdefine (source))
|
||||
{
|
||||
char *msg = ENGLISH ? MSG_EN_PUBLIC_URL : MSG_ZH_PUBLIC_URL;
|
||||
chsrc_log (msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
char *msg = ENGLISH ? MSG_EN_THANKS : MSG_ZH_THANKS;
|
||||
thank_mirror (msg);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
char *msg = ENGLISH ? "Auto changed source" : "自动换源完成";
|
||||
chsrc_log (msg);
|
||||
}
|
||||
|
||||
char *msg = ENGLISH ? "The method hasn't been tested or has any feedback, please report usage: chsrc issue" : "该换源步骤已实现但未经测试或存在任何反馈,请报告使用情况: chsrc issue";
|
||||
chsrc_warn (msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (stderr, "chsrc: Wrong change type: %d\n", ProgStatus.chgtype);
|
||||
xy_unreached();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 检测该 dish 是否实现了用户所指定的 scope 能力
|
||||
*
|
||||
* @note 此函数目前只支持中文
|
||||
*/
|
||||
void
|
||||
chsrc_check_scope_capability (Dish_t *dish)
|
||||
{
|
||||
ScopeCapability_t cap = ScopeCap_Unknown;
|
||||
|
||||
char *msg1 = "不支持";
|
||||
char *msg2 = "换源,请使用 chsrc ls ";
|
||||
char *msg3 = " 查看支持的作用域以及默认作用域";
|
||||
|
||||
char *aliases = dish->aliases;
|
||||
char *scope_name = NULL;
|
||||
|
||||
if (chsrc_in_project_scope_mode())
|
||||
{
|
||||
cap = dish->scope_caps[ScopeCap_Slot_Project];
|
||||
|
||||
if (cap != ScopeCap_Able_And_Implemented)
|
||||
{
|
||||
scope_name = "项目级";
|
||||
char* msg = xy_strcat (5, msg1, scope_name, msg2, aliases, msg3);
|
||||
chsrc_error (msg);
|
||||
exit (Exit_UserCause);
|
||||
}
|
||||
}
|
||||
if (chsrc_in_user_scope_mode())
|
||||
{
|
||||
cap = dish->scope_caps[ScopeCap_Slot_User];
|
||||
|
||||
if (cap != ScopeCap_Able_And_Implemented)
|
||||
{
|
||||
scope_name = "用户级";
|
||||
char* msg = xy_strcat (5, msg1, scope_name, msg2, aliases, msg3);
|
||||
chsrc_error (msg);
|
||||
exit (Exit_UserCause);
|
||||
}
|
||||
}
|
||||
if (chsrc_in_system_scope_mode())
|
||||
{
|
||||
cap = dish->scope_caps[ScopeCap_Slot_System];
|
||||
|
||||
if (cap != ScopeCap_Able_And_Implemented)
|
||||
{
|
||||
scope_name = "系统级";
|
||||
char* msg = xy_strcat (5, msg1, scope_name, msg2, aliases, msg3);
|
||||
chsrc_error (msg);
|
||||
exit (Exit_UserCause);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user