2023-09-09 16:49:06 +08:00
/** ------------------------------------------------------------
2024-06-11 20:18:02 +08:00
* SPDX - License - Identifier : GPL - 3.0 - or - later
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2024-08-16 19:06:16 +08:00
* File Name : chsrc . h
* File Authors : Aoran Zeng < ccmywish @ qq . com >
* | Heng Guo < 2085471348 @ qq . com >
* Contributors : Peng Gao < gn3po4g @ outlook . com >
2024-06-21 01:47:28 +08:00
* |
2024-09-05 18:29:28 +08:00
* Created On : < 2023 - 08 - 29 >
* Last Modified : < 2024 - 09 - 05 >
2023-09-09 16:49:06 +08:00
*
2024-06-11 20:18:02 +08:00
* chsrc 头 文 件
2023-09-09 16:49:06 +08:00
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2023-08-29 23:04:54 +08:00
2023-09-03 14:56:49 +08:00
# include "xy.h"
2024-05-24 20:43:48 +08:00
# include "source.h"
2024-09-01 23:27:49 +08:00
# include <pthread.h>
2023-09-03 14:48:53 +08:00
2024-06-08 08:34:53 +08:00
# define App_Name "chsrc"
2023-09-15 12:50:56 +08:00
2024-09-04 00:27:05 +08:00
static int chsrc_get_cpucore ( ) ;
2024-09-04 16:39:29 +08:00
bool ProgMode_CMD_Measure = false ;
2024-09-04 17:03:00 +08:00
bool ProgMode_CMD_Reset = false ;
2024-09-04 16:39:29 +08:00
2024-09-04 00:27:05 +08:00
2024-08-17 20:51:04 +08:00
/* 命令行选项 */
2024-08-23 08:09:39 +08:00
bool CliOpt_IPv6 = false ;
bool CliOpt_Locally = false ;
2024-08-17 20:51:04 +08:00
bool CliOpt_InEnglish = false ;
2024-08-23 08:09:39 +08:00
bool CliOpt_DryRun = false ;
bool CliOpt_NoColor = false ;
2024-09-04 01:03:53 +08:00
bool CliOpt_Parallel = false ;
2024-08-17 20:51:04 +08:00
/**
* - local 的 含 义 是 启 用 * 项 目 级 * 换 源
*
* 每 个 target 对 [ - local ] 的 支 持 情 况 可 使 用 | chsrc ls < target > | 来 查 看
*
*
* 1. 默 认 不 使 用 该 选 项 时 , 含 义 是 * 全 局 * 换 源 ,
*
* 全 局 分 为 ( 1 ) 系 统 级 ( 2 ) 用 户 级
*
* 大 多 数 第 三 方 配 置 软 件 往 往 默 认 进 行 的 是 * 用 户 级 * 的 配 置 。 所 以 chsrc 首 先 将 尝 试 使 用 * 用 户 级 * 配 置
*
* 2. 若 不 存 在 * 用 户 级 * 的 配 置 , chsrc 将 采 用 * 系 统 级 * 的 配 置
*
* 3. 最 终 效 果 本 质 由 第 三 方 软 件 决 定 , 如 poetry 默 认 实 现 的 就 是 项 目 级 的 换 源
*/
2024-06-14 15:01:52 +08:00
# define Exit_UserCause 1
# define Exit_Unsupported 2
# define Exit_MatinerIssue 3
2024-06-14 15:51:54 +08:00
# define Exit_FatalBug 4
# define Exit_FatalUnkownError 5
2024-06-14 15:01:52 +08:00
2024-06-08 12:38:41 +08:00
# define chsrc_log(str) xy_log(App_Name,str)
2024-06-08 08:34:53 +08:00
# 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)
2024-08-22 16:46:54 +08:00
# define red(str) xy_str_to_red(str)
# define blue(str) xy_str_to_blue(str)
# define green(str) xy_str_to_green(str)
# define yellow(str) xy_str_to_yellow(str)
# define purple(str) xy_str_to_purple(str)
# define bold(str) xy_str_to_bold(str)
# define bdred(str) xy_str_to_bold(xy_str_to_red(str))
# define bdblue(str) xy_str_to_bold(xy_str_to_blue(str))
# define bdgreen(str) xy_str_to_bold(xy_str_to_green(str))
# define bdyellow(str) xy_str_to_bold(xy_str_to_yellow(str))
# define bdpurple(str) xy_str_to_bold(xy_str_to_purple(str))
2024-08-08 16:30:38 +08:00
2024-08-22 20:43:49 +08:00
// 2系列都是带有括号的
# define chsrc_succ2(str) xy_succ_brkt(App_Name,CliOpt_InEnglish?"SUCCEED":"成功",str)
# define chsrc_log2(str) xy_info_brkt(App_Name,"LOG",str)
# define chsrc_warn2(str) xy_warn_brkt(App_Name,CliOpt_InEnglish?"WARN":"警告",str)
# define chsrc_error2(str) xy_error_brkt(App_Name,CliOpt_InEnglish?"ERROR":"错误",str)
2024-08-08 15:52:13 +08:00
void
chsrc_note2 ( const char * str )
{
2024-08-22 20:43:49 +08:00
char * msg = CliOpt_InEnglish ? " NOTE " : " 提示 " ;
xy_log_brkt ( yellow ( App_Name ) , bdyellow ( msg ) , yellow ( str ) ) ;
2024-08-08 15:52:13 +08:00
}
2024-08-17 06:50:20 +08:00
# define YesMark "✓"
# define NoMark "x"
# define SemiYesMark "⍻"
2023-09-27 15:20:44 +08:00
2024-08-17 20:51:04 +08:00
/**
* @ translation Done
*/
2024-06-11 18:03:02 +08:00
void
2024-08-19 11:42:31 +08:00
log_check_result ( const char * check_what , const char * check_type , bool exist )
2024-06-11 18:03:02 +08:00
{
2024-08-17 20:51:04 +08:00
char * chk_msg = NULL ;
char * not_exist_msg = NULL ;
char * exist_msg = NULL ;
if ( CliOpt_InEnglish )
{
chk_msg = " CHECK " ;
not_exist_msg = " doesn't exist " ;
exist_msg = " exists " ;
}
else
{
chk_msg = " 检查 " ;
not_exist_msg = " 不存在 " ;
exist_msg = " 存在 " ;
}
2024-06-11 18:03:02 +08:00
if ( ! exist )
{
2024-08-22 16:46:54 +08:00
xy_log_brkt ( App_Name , bdred ( chk_msg ) , xy_strjoin ( 5 ,
2024-08-19 11:53:10 +08:00
red ( NoMark " " ) , check_type , " " , red ( check_what ) , not_exist_msg ) ) ;
2024-06-11 18:03:02 +08:00
}
else
{
2024-08-22 16:46:54 +08:00
xy_log_brkt ( App_Name , bdgreen ( chk_msg ) , xy_strjoin ( 5 ,
2024-08-19 11:53:10 +08:00
green ( YesMark " " ) , check_type , " " , green ( check_what ) , exist_msg ) ) ;
2024-06-11 18:03:02 +08:00
}
}
2023-09-15 12:50:56 +08:00
2024-08-17 20:51:04 +08:00
/**
* @ translation Done
*/
2024-08-08 16:25:36 +08:00
void
2024-08-30 23:22:53 +08:00
log_cmd_result ( bool result , int exit_status )
2024-08-08 16:25:36 +08:00
{
2024-08-17 20:51:04 +08:00
char * run_msg = NULL ;
char * succ_msg = NULL ;
char * fail_msg = NULL ;
if ( CliOpt_InEnglish )
{
run_msg = " RUN " ;
succ_msg = YesMark " executed successfully " ;
2024-08-30 23:22:53 +08:00
fail_msg = NoMark " executed unsuccessfully, exit status: " ;
2024-08-17 20:51:04 +08:00
}
else
2024-08-08 16:25:36 +08:00
{
2024-08-17 20:51:04 +08:00
run_msg = " 运行 " ;
succ_msg = YesMark " 命令执行成功 " ;
2024-08-30 23:22:53 +08:00
fail_msg = NoMark " 命令执行失败,退出状态: " ;
2024-08-08 16:25:36 +08:00
}
2024-08-17 20:51:04 +08:00
if ( result )
2024-08-22 16:46:54 +08:00
xy_log_brkt ( green ( App_Name ) , bdgreen ( run_msg ) , green ( succ_msg ) ) ;
2024-08-08 16:25:36 +08:00
else
{
char buf [ 8 ] = { 0 } ;
2024-08-30 23:22:53 +08:00
sprintf ( buf , " %d " , exit_status ) ;
2024-08-22 16:46:54 +08:00
char * log = xy_2strjoin ( red ( fail_msg ) , bdred ( buf ) ) ;
xy_log_brkt ( red ( App_Name ) , bdred ( run_msg ) , log ) ;
2024-08-08 16:25:36 +08:00
}
}
2024-08-17 07:11:11 +08:00
2024-06-14 00:29:40 +08:00
bool
is_url ( const char * str )
{
return ( xy_str_start_with ( str , " http:// " ) | | xy_str_start_with ( str , " https:// " ) ) ;
}
2024-09-03 20:03:45 +08:00
# define Quiet_When_Exist 0x00
# define Noisy_When_Exist 0x01
# define Quiet_When_NonExist 0x00
# define Noisy_When_NonExist 0x10
2023-09-15 12:50:56 +08:00
/**
* 检 测 二 进 制 程 序 是 否 存 在
*
2024-06-05 10:15:58 +08:00
* @ param check_cmd 检 测 ` prog_name ` 是 否 存 在 的 一 段 命 令 , 一 般 来 说 , 填 ` prog_name ` 本 身 即 可 ,
2023-09-15 12:50:56 +08:00
* 但 是 某 些 情 况 下 , 需 要 使 用 其 他 命 令 绕 过 一 些 特 殊 情 况 , 比 如 python 这 个 命 令 在 Windows上
* 会 自 动 打 开 Microsoft Store , 需 避 免
*
2024-06-05 10:15:58 +08:00
* @ param prog_name 要 检 测 的 二 进 制 程 序 名
2024-08-17 20:51:04 +08:00
*
* @ translation Done
2023-09-15 12:50:56 +08:00
*/
bool
2024-09-03 20:03:45 +08:00
query_program_exist ( char * check_cmd , char * prog_name , int mode )
2023-09-15 12:50:56 +08:00
{
2024-06-05 10:15:58 +08:00
char * which = check_cmd ;
2023-09-15 12:50:56 +08:00
2024-09-03 20:03:45 +08:00
int status = system ( which ) ;
2023-09-15 12:50:56 +08:00
2024-09-03 20:03:45 +08:00
// char buf[32] = {0}; sprintf(buf, "错误码: %d", status);
2023-09-15 12:50:56 +08:00
2024-08-17 20:51:04 +08:00
char * msg = CliOpt_InEnglish ? " command " : " 命令 " ;
2024-09-03 20:03:45 +08:00
if ( 0 ! = status )
2024-06-05 10:15:58 +08:00
{
2024-09-03 20:03:45 +08:00
if ( mode & Noisy_When_NonExist )
{
// xy_warn (xy_strjoin(4, "× 命令 ", progname, " 不存在,", buf));
log_check_result ( prog_name , msg , false ) ;
return false ;
}
2024-06-05 10:15:58 +08:00
}
else
{
2024-09-03 20:03:45 +08:00
if ( mode & Noisy_When_Exist )
log_check_result ( prog_name , msg , true ) ;
2024-06-05 10:15:58 +08:00
return true ;
}
2023-09-15 12:50:56 +08:00
}
2024-06-14 01:02:23 +08:00
/**
2024-09-03 20:03:45 +08:00
* @ note
* 1. 一 般 只 在 Recipe 中 使 用 , 显 式 检 测 每 一 个 需 要 用 到 的 program
* 2. 无 论 存 在 与 否 , * * 均 输 出 * *
*
2024-06-14 01:02:23 +08:00
*/
bool
chsrc_check_program ( char * prog_name )
{
char * quiet_cmd = xy_str_to_quietcmd ( xy_2strjoin ( prog_name , " --version " ) ) ;
2024-09-03 20:03:45 +08:00
return query_program_exist ( quiet_cmd , prog_name , Noisy_When_Exist | Noisy_When_NonExist ) ;
2024-06-14 01:02:23 +08:00
}
2024-09-03 20:03:45 +08:00
/**
* @ note
* 1. 此 函 数 没 有 强 制 性 , 只 返 回 检 查 结 果
* 2. 无 论 存 在 与 否 , * * 均 不 输 出 * *
* 3. 此 函 数 只 能 对 接 受 - - version 选 项 的 命 令 行 程 序 有 效
*
*/
bool
chsrc_check_program_quietly ( char * prog_name )
{
char * quiet_cmd = xy_str_to_quietcmd ( xy_2strjoin ( prog_name , " --version " ) ) ;
return query_program_exist ( quiet_cmd , prog_name , Quiet_When_Exist | Quiet_When_NonExist ) ;
}
2024-06-14 01:02:23 +08:00
/**
2024-09-03 20:03:45 +08:00
* @ note 存 在 时 不 输 出 , 不 存 在 时 才 输 出
*
*/
bool
chsrc_check_program_quietly_when_exist ( char * prog_name )
{
char * quiet_cmd = xy_str_to_quietcmd ( xy_2strjoin ( prog_name , " --version " ) ) ;
return query_program_exist ( quiet_cmd , prog_name , Quiet_When_Exist | Noisy_When_NonExist ) ;
}
/**
* @ note
* 1. 此 函 数 具 有 强 制 性 , 检 测 不 到 就 直 接 退 出
* 2. 检 查 到 存 在 时 不 输 出 , 检 查 到 不 存 在 时 输 出
*
2024-06-14 01:02:23 +08:00
*/
void
chsrc_ensure_program ( char * prog_name )
{
char * quiet_cmd = xy_str_to_quietcmd ( xy_2strjoin ( prog_name , " --version " ) ) ;
2024-09-03 20:03:45 +08:00
bool exist = query_program_exist ( quiet_cmd , prog_name , Quiet_When_Exist | Noisy_When_NonExist ) ;
2024-06-14 01:02:23 +08:00
if ( exist )
{
// OK, nothing should be done
}
else
{
2024-08-22 23:14:06 +08:00
char * msg1 = CliOpt_InEnglish ? " not found " : " 未找到 " ;
char * msg2 = CliOpt_InEnglish ? " command, please check for existence " : " 命令,请检查是否存在 " ;
chsrc_error ( xy_strjoin ( 3 , msg1 , prog_name , msg2 ) ) ;
2024-06-14 15:01:52 +08:00
exit ( Exit_UserCause ) ;
2024-06-14 01:02:23 +08:00
}
}
2024-06-13 00:39:31 +08:00
bool
2024-06-14 15:15:59 +08:00
chsrc_check_file ( char * path )
2024-06-13 00:39:31 +08:00
{
2024-08-22 23:14:06 +08:00
char * msg = CliOpt_InEnglish ? " file " : " 文件 " ;
2024-06-13 00:39:31 +08:00
if ( xy_file_exist ( path ) )
{
2024-08-22 23:14:06 +08:00
log_check_result ( path , msg , true ) ;
2024-06-13 00:39:31 +08:00
return true ;
}
else
{
2024-08-22 23:14:06 +08:00
log_check_result ( path , msg , false ) ;
2024-06-13 00:39:31 +08:00
return false ;
}
}
2023-09-15 12:50:56 +08:00
/**
* 用 于 _setsrc 函 数 , 检 测 用 户 输 入 的 镜 像 站 code , 是 否 存 在 于 该 target可用源中
*
* @ param target 目 标 名
* @ param input 如 果 用 户 输 入 default 或 者 def , 则 选 择 第 一 个 源
*/
2023-10-05 09:40:10 +08:00
# define find_mirror(s, input) query_mirror_exist(s##_sources, s##_sources_n, (char*)#s+3, input)
2023-09-15 12:50:56 +08:00
int
2024-05-25 00:49:13 +08:00
query_mirror_exist ( SourceInfo * sources , size_t size , char * target , char * input )
2023-09-15 12:50:56 +08:00
{
2024-06-14 00:29:40 +08:00
if ( is_url ( input ) )
{
2024-08-22 23:14:06 +08:00
char * msg = CliOpt_InEnglish ? " Using user-defined sources for this software is not supported at this time, please contact the developer to ask why or request support " : " 暂不支持对该软件使用用户自定义源,请联系开发者询问原因或请求支持 " ;
chsrc_error ( msg ) ;
2024-06-14 15:01:52 +08:00
exit ( Exit_Unsupported ) ;
2024-06-14 00:29:40 +08:00
}
2024-06-07 23:51:11 +08:00
if ( 0 = = size | | 1 = = size )
2024-05-25 00:49:13 +08:00
{
2024-08-22 23:14:06 +08:00
char * msg1 = CliOpt_InEnglish ? " Currently " : " 当前 " ;
char * msg2 = CliOpt_InEnglish ? " doesn't have any source available, please contact the maintainer " : " 无任何可用源,请联系维护者 " ;
chsrc_error ( xy_strjoin ( 3 , msg1 , target , msg2 ) ) ;
2024-06-14 15:01:52 +08:00
exit ( Exit_MatinerIssue ) ;
2024-05-25 00:49:13 +08:00
}
2023-09-15 12:50:56 +08:00
2024-06-07 23:51:11 +08:00
if ( 2 = = size )
2024-05-25 00:49:13 +08:00
{
2024-08-22 23:14:06 +08:00
char * msg1 = CliOpt_InEnglish ? " is " : " 是 " ;
2024-09-04 16:39:29 +08:00
char * msg2 = CliOpt_InEnglish ? " 's ONLY mirror available currently, thanks for their generous support "
2024-08-23 14:24:31 +08:00
: " 目前唯一可用镜像站,感谢他们的慷慨支持 " ;
const char * name = CliOpt_InEnglish ? sources [ 1 ] . mirror - > abbr
: sources [ 1 ] . mirror - > name ;
chsrc_succ ( xy_strjoin ( 4 , name , msg1 , target , msg2 ) ) ;
2024-06-07 23:51:11 +08:00
}
if ( xy_streql ( " reset " , input ) )
{
2024-08-22 23:14:06 +08:00
char * msg = CliOpt_InEnglish ? " Will reset to the upstream's default source " : " 将重置为上游默认源 " ;
say ( msg ) ;
2024-06-07 23:51:11 +08:00
return 0 ; // 返回第1个, 因为第1个是上游默认源
2024-05-25 00:49:13 +08:00
}
2023-09-15 12:50:56 +08:00
2024-06-05 13:38:04 +08:00
if ( xy_streql ( " first " , input ) )
2024-05-25 00:49:13 +08:00
{
2024-08-22 23:14:06 +08:00
char * msg = CliOpt_InEnglish ? " Will use the first speed source measured by maintainers " : " 将使用维护团队测速第一的源 " ;
say ( msg ) ;
2024-06-07 23:51:11 +08:00
return 1 ; // 返回第2个, 因为第1个是上游默认源
2024-05-25 00:49:13 +08:00
}
2023-09-15 12:50:56 +08:00
int idx = 0 ;
2023-10-05 09:28:34 +08:00
SourceInfo source = sources [ 0 ] ;
2023-09-15 12:50:56 +08:00
bool exist = false ;
for ( int i = 0 ; i < size ; i + + )
2024-05-25 00:49:13 +08:00
{
source = sources [ i ] ;
2024-06-05 10:15:58 +08:00
if ( xy_streql ( source . mirror - > code , input ) )
2024-05-25 00:49:13 +08:00
{
idx = i ;
exist = true ;
break ;
}
}
if ( ! exist )
{
2024-08-22 23:14:06 +08:00
{
char * msg1 = CliOpt_InEnglish ? " Mirror site " : " 镜像站 " ;
char * msg2 = CliOpt_InEnglish ? " doesn't exist " : " 不存在 " ;
chsrc_error ( xy_strjoin ( 3 , msg1 , input , msg2 ) ) ;
}
char * msg = CliOpt_InEnglish ? " To see available sources, use chsrc list " : " 查看可使用源,请使用 chsrc list " ;
chsrc_error ( xy_2strjoin ( msg , target ) ) ;
2024-06-14 15:01:52 +08:00
exit ( Exit_UserCause ) ;
2023-09-15 12:50:56 +08:00
}
return idx ;
}
/**
2023-09-27 19:31:23 +08:00
* 该 函 数 来 自 oh - my - mirrorz . py , 由 @ ccmywish 翻 译 为 C语言 , 但 功 劳 和 版 权 属 于 原 作 者
2023-09-15 12:50:56 +08:00
*/
2024-05-25 00:49:13 +08:00
char *
2023-09-15 12:50:56 +08:00
to_human_readable_speed ( double speed )
{
2024-05-25 00:49:13 +08:00
char * scale [ ] = { " Byte/s " , " KByte/s " , " MByte/s " , " GByte/s " , " TByte/s " } ;
2023-09-15 12:50:56 +08:00
int i = 0 ;
while ( speed > 1024.0 )
{
i + = 1 ;
speed / = 1024.0 ;
}
2024-05-25 00:49:13 +08:00
char * buf = xy_malloc0 ( 64 ) ;
sprintf ( buf , " %.2f %s " , speed , scale [ i ] ) ;
2023-09-15 12:50:56 +08:00
2024-05-25 00:49:13 +08:00
char * new = NULL ;
2024-08-19 11:53:10 +08:00
if ( i < = 1 ) new = red ( buf ) ;
2023-09-15 12:50:56 +08:00
else
2024-05-25 00:49:13 +08:00
{
2024-08-19 11:53:10 +08:00
if ( i = = 2 & & speed < 2.00 ) new = yellow ( buf ) ;
else new = green ( buf ) ;
2024-05-25 00:49:13 +08:00
}
2023-09-15 12:50:56 +08:00
return new ;
}
/**
* 测 速 代 码 参 考 自 https : //github.com/mirrorz-org/oh-my-mirrorz/blob/master/oh-my-mirrorz.py
2023-09-27 19:31:23 +08:00
* 功 劳 和 版 权 属 于 原 作 者 , 由 @ ccmywish 修 改 为 C语言 , 并 做 了 额 外 调 整
2023-09-15 12:50:56 +08:00
*
* @ return 返 回 测 得 的 速 度 , 若 出 错 , 返 回 - 1
2024-09-01 23:27:49 +08:00
*
2024-09-03 17:52:03 +08:00
* 该 函 数 实 际 原 型 为 char * ( * ) ( const char * )
2023-09-15 12:50:56 +08:00
*/
2024-09-01 23:27:49 +08:00
void *
2024-09-04 01:03:53 +08:00
measure_speed_for_url ( void * url )
2023-09-15 12:50:56 +08:00
{
2024-09-04 01:03:53 +08:00
char * time_sec = NULL ;
if ( CliOpt_Parallel )
time_sec = " 9 " ;
else
time_sec = " 6 " ;
2023-09-15 12:50:56 +08:00
2024-06-05 10:15:58 +08:00
/* 现在我们切换至跳转后的链接来测速,不再使用下述判断
2023-09-15 12:50:56 +08:00
if ( xy_str_start_with ( url , " https://registry.npmmirror " ) )
2024-06-05 10:15:58 +08:00
{
// 这里 npmmirror 跳转非常慢, 需要1~3秒, 所以我们给它留够至少8秒测速时间, 否则非常不准
time_sec = " 10 " ;
}
*/
char * ipv6 = " " ; // 默认不启用
2024-08-09 01:49:14 +08:00
if ( CliOpt_IPv6 = = true )
2024-07-31 12:38:52 +08:00
{
ipv6 = " --ipv6 " ;
}
2023-09-15 12:50:56 +08:00
2024-09-05 18:29:28 +08:00
char * os_devnull = xy_os_devnull ;
bool on_cygwin = false ;
// https://github.com/RubyMetric/chsrc/issues/65
// curl (仅)在 Cygwin 上 -o nul 会把 nul 当做普通文件
// 为了践行 chsrc everywhere 的承诺,我们也考虑支持 Cygwin
if ( 0 = = system ( " cygcheck --version>nul " ) )
{
on_cygwin = true ;
os_devnull = " /tmp/chsrc-measure-downloaded " ;
}
2023-09-15 12:50:56 +08:00
// 我们用 —L, 因为Ruby China源会跳转到其他地方
// npmmirror 也会跳转
2024-09-05 18:29:28 +08:00
char * curl_cmd = xy_strjoin ( 8 , " curl -qsL " , ipv6 ,
" -o " , os_devnull ,
2024-07-31 12:38:52 +08:00
" -w \" %{http_code} %{speed_download} \" -m " , time_sec ,
2024-08-19 11:28:51 +08:00
" -A chsrc/ " Chsrc_Banner_Version " " , url ) ;
2023-09-15 12:50:56 +08:00
2024-06-08 08:34:53 +08:00
// chsrc_info (xy_2strjoin ("测速命令 ", curl_cmd));
2023-09-15 12:50:56 +08:00
2024-09-05 18:29:28 +08:00
char * curl_buf = NULL ;
if ( on_cygwin )
{
char * curl_script = " .chsrc_measure_tmp.sh " ;
FILE * f = fopen ( curl_script , " w " ) ;
if ( f = = NULL )
exit ( Exit_UserCause ) ;
fputs ( curl_cmd , f ) ;
fclose ( f ) ;
curl_buf = xy_run ( xy_2strjoin ( " bash . \\ " , curl_script ) , 0 , NULL ) ;
system ( xy_2strjoin ( " del " , curl_script ) ) ;
system ( xy_strjoin ( 3 , " bash -c \" rm " , os_devnull , " \" " ) ) ;
}
else
{
curl_buf = xy_run ( curl_cmd , 0 , NULL ) ;
}
2023-09-15 12:50:56 +08:00
// 如果尾部有换行,删除
2024-09-03 17:52:03 +08:00
curl_buf = xy_str_strip ( curl_buf ) ;
2023-09-15 12:50:56 +08:00
2024-09-03 17:52:03 +08:00
return curl_buf ;
}
/**
* @ return 返 回 速 度 speed
*/
double
parse_and_say_curl_result ( char * curl_buf )
{
2023-09-27 19:31:23 +08:00
// 分隔两部分数据
2024-09-03 17:52:03 +08:00
char * split = strchr ( curl_buf , ' ' ) ;
2023-09-15 12:50:56 +08:00
if ( split ) * split = ' \0 ' ;
2024-09-03 17:52:03 +08:00
// say(curl_buf); say(split+1);
int http_code = atoi ( curl_buf ) ;
double speed = atof ( split + 1 ) ;
char * speedstr = to_human_readable_speed ( speed ) ;
2024-05-25 00:49:13 +08:00
if ( 200 ! = http_code )
{
2024-09-03 17:52:03 +08:00
char * http_code_str = yellow ( xy_2strjoin ( " HTTP码 " , curl_buf ) ) ;
say ( xy_strjoin ( 3 , speedstr , " | " , http_code_str ) ) ;
2024-05-25 00:49:13 +08:00
}
else
{
2024-09-03 17:52:03 +08:00
say ( speedstr ) ;
2024-05-25 00:49:13 +08:00
}
2024-09-03 17:52:03 +08:00
return speed ;
2023-09-15 12:50:56 +08:00
}
2023-09-03 14:48:53 +08:00
int
2024-05-25 00:49:13 +08:00
get_max_ele_idx_in_dbl_ary ( double * array , int size )
2023-09-03 14:48:53 +08:00
{
double maxval = array [ 0 ] ;
2023-09-06 19:45:37 +08:00
int maxidx = 0 ;
2023-09-03 14:48:53 +08:00
2024-05-25 00:49:13 +08:00
for ( int i = 1 ; i < size ; i + + )
{
if ( array [ i ] > maxval )
{
maxval = array [ i ] ;
maxidx = i ;
}
2023-09-03 14:48:53 +08:00
}
return maxidx ;
}
2024-09-04 00:27:05 +08:00
2023-09-27 09:40:31 +08:00
/**
2024-09-04 08:22:39 +08:00
* @ param sources 所 有 待 测 源
* @ param size 待 测 源 的 数 量
* @ param [ out ] speed_records 速 度 值 记 录
2023-09-27 09:40:31 +08:00
*/
2024-09-04 00:27:05 +08:00
void
2024-09-04 08:22:39 +08:00
measure_speed_for_every_source ( SourceInfo sources [ ] , int size , double speed_records [ ] )
2023-09-15 12:50:56 +08:00
{
2024-09-03 17:52:03 +08:00
bool get_measured [ size ] ; /* 是否测速了 */
int get_measured_n = 0 ; /* 测速了几个 */
char * measure_msgs [ size ] ;
2023-09-15 12:50:56 +08:00
double speed = 0.0 ;
2024-09-01 23:27:49 +08:00
pthread_t * threads = xy_malloc0 ( sizeof ( pthread_t ) * size ) ;
2024-08-09 01:46:58 +08:00
for ( int i = 0 ; i < size ; i + + )
{
2024-09-04 08:22:39 +08:00
SourceInfo src = sources [ i ] ;
2024-09-01 23:27:49 +08:00
const char * url = src . mirror - > __bigfile_url ;
2024-08-09 01:46:58 +08:00
if ( NULL = = url )
{
if ( xy_streql ( " upstream " , src . mirror - > code ) )
{
2024-09-04 17:07:48 +08:00
// 上游源不测速, 但不置0, 因为要避免这种情况: 可能其他镜像站测速都为0, 最后反而选择了该 upstream
speed = - 999 ;
2024-08-09 01:46:58 +08:00
}
else
{
2024-08-17 20:51:04 +08:00
char * msg1 = CliOpt_InEnglish ? " Dev team doesn't offer " : " 开发者未提供 " ;
2024-09-04 17:07:48 +08:00
char * msg2 = CliOpt_InEnglish ? " mirror site's speed measure link, so skip it " : " 镜像站测速链接,跳过该站点 " ;
2024-08-17 20:51:04 +08:00
chsrc_warn ( xy_strjoin ( 3 , msg1 , src . mirror - > code , msg2 ) ) ;
2024-08-09 01:46:58 +08:00
speed = 0 ;
}
2024-09-04 08:22:39 +08:00
speed_records [ i ] = speed ;
2024-09-03 17:52:03 +08:00
get_measured [ i ] = false ;
measure_msgs [ i ] = NULL ;
2024-08-09 01:46:58 +08:00
}
else
{
2024-09-03 18:04:45 +08:00
const char * msg = CliOpt_InEnglish ? src . mirror - > abbr : src . mirror - > name ;
measure_msgs [ i ] = xy_strjoin ( 3 , " - " , msg , " ... " ) ;
2024-09-03 17:52:03 +08:00
printf ( " %s " , measure_msgs [ i ] ) ;
2024-09-04 01:03:53 +08:00
if ( CliOpt_Parallel )
say ( " " ) ; /* 并行时直接显示下一测速状态行 */
else
fflush ( stdout ) ;
2024-09-01 23:27:49 +08:00
char * url_ = xy_strdup ( url ) ;
2024-09-04 01:03:53 +08:00
if ( CliOpt_Parallel )
2024-09-01 23:27:49 +08:00
{
2024-09-04 01:03:53 +08:00
int ret = pthread_create ( & threads [ i ] , NULL , measure_speed_for_url , url_ ) ;
if ( ret ! = 0 )
{
chsrc_error ( " Unable to measure speed \n " ) ;
exit ( Exit_UserCause ) ;
}
else
{
get_measured [ i ] = true ;
get_measured_n + = 1 ;
}
2024-09-01 23:27:49 +08:00
}
else
{
2024-09-04 01:03:53 +08:00
char * curl_result = measure_speed_for_url ( url_ ) ;
double speed = parse_and_say_curl_result ( curl_result ) ;
2024-09-04 08:22:39 +08:00
speed_records [ i ] = speed ;
2024-09-01 23:27:49 +08:00
}
}
}
2024-09-03 17:52:03 +08:00
2024-09-04 01:03:53 +08:00
if ( CliOpt_Parallel )
2024-09-01 23:27:49 +08:00
{
2024-09-04 08:22:39 +08:00
/* 汇总 */
2024-09-04 01:03:53 +08:00
char * * curl_results = xy_malloc0 ( sizeof ( char * ) * size ) ;
for ( int i = 0 ; i < size ; i + + )
{
if ( get_measured [ i ] = = true )
pthread_join ( threads [ i ] , ( void * ) & curl_results [ i ] ) ;
}
2024-09-03 17:52:03 +08:00
2024-09-04 01:03:53 +08:00
for ( int i = 0 ; i < get_measured_n ; i + + )
printf ( " \033 [A \033 [2K " ) ;
2024-09-01 23:27:49 +08:00
2024-09-04 01:03:53 +08:00
for ( int i = 0 ; i < size ; i + + )
2024-09-01 23:27:49 +08:00
{
2024-09-04 01:03:53 +08:00
if ( get_measured [ i ] = = true )
{
printf ( " %s " , measure_msgs [ i ] ) ;
double speed = parse_and_say_curl_result ( curl_results [ i ] ) ;
2024-09-04 08:22:39 +08:00
speed_records [ i ] = speed ;
2024-09-04 01:03:53 +08:00
}
2024-08-09 01:46:58 +08:00
}
2024-09-04 01:03:53 +08:00
/* 汇总结束 */
} /* End of if Parallel*/
2024-09-04 00:27:05 +08:00
}
/**
* 自 动 测 速 选 择 镜 像 站 和 源
*
* @ translation Done
*/
2024-09-04 08:22:39 +08:00
# define auto_select_mirror(s) select_mirror_autoly(s##_sources, s##_sources_n, (char*)#s+3)
2024-09-04 00:27:05 +08:00
int
2024-09-04 08:22:39 +08:00
select_mirror_autoly ( SourceInfo * sources , size_t size , const char * target_name )
2024-09-04 00:27:05 +08:00
{
{
2024-09-04 01:03:53 +08:00
char * msg = NULL ;
if ( CliOpt_Parallel )
2024-09-04 17:07:48 +08:00
msg = CliOpt_InEnglish ? " Measuring speed in parallel. We recommend you use the default sequential measure for more referential results "
2024-09-04 01:03:53 +08:00
: " 即将并行测速,建议使用默认的顺序测速以获得更具参考意义的结果 " ;
else
msg = CliOpt_InEnglish ? " Measuring speed in sequence " : " 顺序测速中 " ;
2024-09-04 00:27:05 +08:00
xy_log_brkt ( App_Name , bdpurple ( CliOpt_InEnglish ? " MEASURE " : " 测速 " ) , msg ) ;
say ( " " ) ;
}
if ( 0 = = size | | 1 = = size )
{
char * msg1 = CliOpt_InEnglish ? " Currently " : " 当前 " ;
char * msg2 = CliOpt_InEnglish ? " No any source, please contact maintainers: chsrc issue " : " 无任何可用源,请联系维护者: chsrc issue " ;
chsrc_error ( xy_strjoin ( 3 , msg1 , target_name , msg2 ) ) ;
exit ( Exit_MatinerIssue ) ;
}
if ( CliOpt_DryRun )
{
return 1 ; // Dry Run 时,跳过测速
}
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 = CliOpt_InEnglish ? " No curl, unable to measure speed " : " 没有curl命令, 无法测速 " ;
chsrc_error ( msg ) ;
exit ( Exit_UserCause ) ;
}
/** --------------------------------------------- */
/* 总测速记录值 */
double speed_records [ size ] ;
2024-09-04 08:22:39 +08:00
measure_speed_for_every_source ( sources , size , speed_records ) ;
2024-09-03 20:03:45 +08:00
say ( " " ) ;
2024-09-03 17:52:03 +08:00
/* DEBUG */
2024-09-04 08:22:39 +08:00
/*
for ( int i = 0 ; i < size ; i + + )
{
printf ( " speed_records[%d] = %f \n " , i , speed_records [ i ] ) ;
}
*/
2024-08-09 01:46:58 +08:00
2024-09-04 00:27:05 +08:00
int fast_idx = get_max_ele_idx_in_dbl_ary ( speed_records , size ) ;
2023-09-15 12:50:56 +08:00
2024-08-09 01:46:58 +08:00
if ( only_one )
2024-08-17 20:51:04 +08:00
{
2024-09-04 16:39:29 +08:00
char * msg1 = CliOpt_InEnglish ? " NOTICE mirror site: " : " 镜像站提示: " ;
char * is = CliOpt_InEnglish ? " is " : " 是 " ;
char * msg2 = CliOpt_InEnglish ? " 's ONLY mirror available currently, thanks for their generous support "
: " 目前唯一可用镜像站,感谢他们的慷慨支持 " ;
2024-08-23 14:24:31 +08:00
const char * name = CliOpt_InEnglish ? sources [ fast_idx ] . mirror - > abbr
: sources [ fast_idx ] . mirror - > name ;
2024-09-04 16:39:29 +08:00
say ( xy_strjoin ( 5 , msg1 , bdgreen ( name ) , green ( is ) , green ( target_name ) , green ( msg2 ) ) ) ;
2024-08-17 20:51:04 +08:00
}
2023-09-15 12:50:56 +08:00
else
2024-08-17 20:51:04 +08:00
{
2024-08-22 23:14:06 +08:00
char * msg = CliOpt_InEnglish ? " FASTEST mirror site: " : " 最快镜像站: " ;
2024-08-23 14:24:31 +08:00
const char * name = CliOpt_InEnglish ? sources [ fast_idx ] . mirror - > abbr
: sources [ fast_idx ] . mirror - > name ;
say ( xy_2strjoin ( msg , green ( name ) ) ) ;
2024-08-17 20:51:04 +08:00
}
2024-09-04 16:39:29 +08:00
// https://github.com/RubyMetric/chsrc/pull/71
if ( ProgMode_CMD_Measure )
{
char * msg = CliOpt_InEnglish ? " URL of above source: " : " 镜像源地址: " ;
say ( xy_2strjoin ( msg , green ( sources [ fast_idx ] . url ) ) ) ;
}
2023-09-15 12:50:56 +08:00
2024-08-09 01:46:58 +08:00
return fast_idx ;
2023-09-15 12:50:56 +08:00
}
2023-09-27 09:40:31 +08:00
# define use_specific_mirror_or_auto_select(input, s) \
2024-09-04 08:22:39 +08:00
( NULL ! = ( input ) ) ? find_mirror ( s , input ) : auto_select_mirror ( s )
2023-09-27 09:40:31 +08:00
2024-06-07 23:51:11 +08:00
bool
2024-06-13 23:27:59 +08:00
source_is_upstream ( SourceInfo * source )
2024-06-07 23:51:11 +08:00
{
return xy_streql ( source - > mirror - > code , " upstream " ) ;
}
2024-06-13 23:27:59 +08:00
bool
source_is_userdefine ( SourceInfo * source )
{
return xy_streql ( source - > mirror - > code , " user " ) ;
}
2024-06-07 23:51:11 +08:00
bool
2024-06-08 14:45:05 +08:00
source_has_empty_url ( SourceInfo * source )
2024-06-07 23:51:11 +08:00
{
return source - > url = = NULL ;
}
2024-06-13 23:43:31 +08:00
/**
* 用 户 * 只 可 能 * 通 过 下 面 三 种 方 式 来 换 源 , 无 论 哪 一 种 都 会 返 回 一 个 SourceInfo 出 来
*
* 1. 用 户 指 定 MirrorCode
* 2. 用 户 什 么 都 没 指 定 ( 将 测 速 选 择 最 快 镜 像 )
* 3. 用 户 给 了 一 个 URL
*
* @ dependency 变 量 option
* @ dependency 变 量 source
*/
# define chsrc_yield_source(for_what) \
2024-08-18 09:27:22 +08:00
SourceInfo source ; \
2024-06-13 23:43:31 +08:00
if ( is_url ( option ) ) \
{ \
SourceInfo __tmp = { & UserDefine , option } ; \
source = __tmp ; \
} \
else \
{ \
int __index = use_specific_mirror_or_auto_select ( option , for_what ) ; \
2024-06-14 00:17:21 +08:00
source = for_what # # _sources [ __index ] ; \
2024-06-13 23:43:31 +08:00
}
2024-06-07 23:51:11 +08:00
2024-06-13 23:27:59 +08:00
2024-06-08 09:37:27 +08:00
# define split_between_source_changing_process puts ("--------------------------------")
2023-09-03 17:57:45 +08:00
/**
* 用 于 _setsrc 函 数
2024-06-07 23:51:11 +08:00
*
* 1. 告 知 用 户 选 择 了 什 么 源 和 镜 像
* 2. 对 选 择 的 源 和 镜 像 站 进 行 一 定 的 校 验
2024-08-17 20:51:04 +08:00
*
* @ translation Done
2023-09-03 17:57:45 +08:00
*/
2024-08-18 09:27:22 +08:00
# define chsrc_confirm_source confirm_source(&source)
2023-09-03 17:57:45 +08:00
void
2024-08-18 09:27:22 +08:00
confirm_source ( SourceInfo * source )
2023-09-03 17:57:45 +08:00
{
2024-06-07 23:51:11 +08:00
// 由于实现问题,我们把本应该独立出去的默认上游源,也放在了可以换源的数组中,而且放在第一个
// chsrc 已经规避用户使用未实现的 `chsrc reset`
// 但是某些用户可能摸索着强行使用 chsrc set target upstream, 从而执行起该禁用的功能,
// 之所以禁用,是因为有的 reset 我们并没有实现,我们在这里阻止这些邪恶的用户
2024-06-13 23:27:59 +08:00
if ( source_is_upstream ( source ) & & source_has_empty_url ( source ) )
2024-06-07 23:51:11 +08:00
{
2024-08-17 20:51:04 +08:00
char * msg = CliOpt_InEnglish ? " Not implement RESET for the target yet " : " 暂未对该目标实现重置 " ;
chsrc_error ( msg ) ;
2024-06-14 15:01:52 +08:00
exit ( Exit_Unsupported ) ;
2024-06-07 23:51:11 +08:00
}
2024-06-08 14:45:05 +08:00
else if ( source_has_empty_url ( source ) )
2024-06-07 23:51:11 +08:00
{
2024-08-17 20:51:04 +08:00
char * msg = CliOpt_InEnglish ? " URL of the source doesn't exist, please report a bug to the dev team " : \
" 该源URL不存在, 请向开发团队提交bug " ;
chsrc_error ( msg ) ;
2024-06-14 15:51:54 +08:00
exit ( Exit_FatalBug ) ;
2024-06-07 23:51:11 +08:00
}
else
{
2024-08-17 20:51:04 +08:00
char * msg = CliOpt_InEnglish ? " SELECT mirror site: " : " 选中镜像站: " ;
2024-08-19 11:53:10 +08:00
say ( xy_strjoin ( 5 , msg , green ( source - > mirror - > abbr ) , " ( " , green ( source - > mirror - > code ) , " ) " ) ) ;
2024-06-07 23:51:11 +08:00
}
2024-06-08 09:37:27 +08:00
split_between_source_changing_process ;
2023-09-03 17:57:45 +08:00
}
2024-08-18 09:27:22 +08:00
# define chsrc_yield_source_and_confirm(for_what) chsrc_yield_source(for_what);chsrc_confirm_source
2023-09-15 12:50:56 +08:00
2024-06-08 12:38:41 +08:00
# define ChsrcTypeAuto "auto"
# define ChsrcTypeReset "reset"
# define ChsrcTypeSemiAuto "semiauto"
# define ChsrcTypeManual "manual"
# define ChsrcTypeUntested "untested"
2024-08-18 09:04:25 +08:00
# define MSG_EN_PUBLIC_URL "If the URL you specify is a public service, you are invited to contribute: chsrc issue"
# define MSG_CN_PUBLIC_URL "若您指定的URL为公有服务, 邀您参与贡献: chsrc issue"
# define MSG_EN_FULLY_AUTO "Fully-Auto changed source. "
# define MSG_CN_FULLY_AUTO "全自动换源完成"
# define MSG_EN_SEMI_AUTO "Semi-Auto changed source. "
# define MSG_CN_SEMI_AUTO "半自动换源完成"
# define MSG_EN_THANKS "Thanks to the mirror site: "
# define MSG_CN_THANKS "感谢镜像提供方: "
# define MSG_EN_BETTER "If you have a better source changing method , please help: chsrc issue"
# define MSG_CN_BETTER "若您有更好的换源方案,邀您帮助: chsrc issue"
# define MSG_EN_CONSTRAINT "Implementation constraints require manual operation according to the above prompts. "
# define MSG_CN_CONSTRAINT "因实现约束需按上述提示手工操作"
# define MSG_EN_STILL "Still need to operate manually according to the above prompts. "
# define MSG_CN_STILL "仍需按上述提示手工操作"
2024-08-23 14:24:31 +08:00
# define thank_mirror(msg) chsrc_log(xy_2strjoin(msg,purple(CliOpt_InEnglish?source->mirror->abbr:source->mirror->name)))
2024-06-08 12:38:41 +08:00
/**
* @ param source 可 为 NULL
* @ param last_word 5 种 选 择 : ChsrcTypeAuto | ChsrcTypeReset | ChsrcTypeSemiAuto | ChsrcTypeManual | ChsrcTypeUntested
2024-08-18 09:04:25 +08:00
* @ translation Done
2024-06-08 12:38:41 +08:00
*/
2023-09-04 15:39:49 +08:00
void
2024-08-18 09:27:22 +08:00
chsrc_conclude ( SourceInfo * source , const char * last_word )
2023-09-04 15:39:49 +08:00
{
2024-06-08 09:37:27 +08:00
split_between_source_changing_process ;
2024-06-08 12:38:41 +08:00
if ( xy_streql ( ChsrcTypeAuto , last_word ) )
{
if ( source )
{
2024-06-13 23:27:59 +08:00
if ( source_is_userdefine ( source ) )
{
2024-08-18 09:04:25 +08:00
char * msg = CliOpt_InEnglish ? MSG_EN_FULLY_AUTO MSG_EN_PUBLIC_URL \
: MSG_CN_FULLY_AUTO " , " MSG_CN_PUBLIC_URL ;
chsrc_log ( msg ) ;
2024-06-13 23:27:59 +08:00
}
else
{
2024-08-18 09:04:25 +08:00
char * msg = CliOpt_InEnglish ? MSG_EN_FULLY_AUTO MSG_EN_THANKS \
: MSG_CN_FULLY_AUTO " , " MSG_CN_THANKS ;
2024-08-23 14:24:31 +08:00
thank_mirror ( msg ) ;
2024-06-13 23:27:59 +08:00
}
2024-06-08 12:38:41 +08:00
}
else
{
2024-08-18 09:04:25 +08:00
char * msg = CliOpt_InEnglish ? MSG_EN_FULLY_AUTO : MSG_CN_FULLY_AUTO ;
chsrc_log ( msg ) ;
2024-06-08 12:38:41 +08:00
}
}
else if ( xy_streql ( ChsrcTypeReset , last_word ) )
{
2024-06-13 23:27:59 +08:00
// source_is_upstream (source)
2024-08-18 09:04:25 +08:00
char * msg = CliOpt_InEnglish ? " Has been reset to the upstream default source " : " 已重置为上游默认源 " ;
2024-08-19 11:53:10 +08:00
chsrc_log ( purple ( msg ) ) ;
2024-06-08 12:38:41 +08:00
}
else if ( xy_streql ( ChsrcTypeSemiAuto , last_word ) )
{
if ( source )
{
2024-06-13 23:27:59 +08:00
if ( source_is_userdefine ( source ) )
{
2024-08-18 09:04:25 +08:00
char * msg = CliOpt_InEnglish ? MSG_EN_SEMI_AUTO MSG_EN_STILL MSG_EN_PUBLIC_URL \
: MSG_CN_SEMI_AUTO " , " MSG_CN_STILL " 。 " MSG_CN_PUBLIC_URL ;
chsrc_log ( msg ) ;
2024-06-13 23:27:59 +08:00
}
else
{
2024-08-18 09:04:25 +08:00
char * msg = CliOpt_InEnglish ? MSG_EN_SEMI_AUTO MSG_EN_STILL MSG_EN_THANKS \
: MSG_CN_SEMI_AUTO " , " MSG_CN_STILL " 。 " MSG_CN_THANKS ;
2024-08-23 14:24:31 +08:00
thank_mirror ( msg ) ;
2024-06-13 23:27:59 +08:00
}
2024-06-08 12:38:41 +08:00
}
else
{
2024-08-18 09:04:25 +08:00
char * msg = CliOpt_InEnglish ? MSG_EN_SEMI_AUTO MSG_EN_STILL \
: MSG_CN_SEMI_AUTO " , " MSG_CN_STILL ;
chsrc_log ( msg ) ;
2024-06-08 12:38:41 +08:00
}
2024-08-18 09:04:25 +08:00
char * msg = CliOpt_InEnglish ? MSG_EN_BETTER : MSG_CN_BETTER ;
chsrc_warn ( msg ) ;
2024-06-08 12:38:41 +08:00
}
else if ( xy_streql ( ChsrcTypeManual , last_word ) )
{
if ( source )
{
2024-06-13 23:27:59 +08:00
if ( source_is_userdefine ( source ) )
{
2024-08-18 09:04:25 +08:00
char * msg = CliOpt_InEnglish ? MSG_EN_CONSTRAINT MSG_EN_PUBLIC_URL \
: MSG_CN_CONSTRAINT " ; " MSG_CN_PUBLIC_URL ;
chsrc_log ( msg ) ;
2024-06-13 23:27:59 +08:00
}
else
{
2024-08-18 09:04:25 +08:00
char * msg = CliOpt_InEnglish ? MSG_EN_CONSTRAINT MSG_EN_THANKS \
: MSG_CN_CONSTRAINT " , " MSG_CN_THANKS ;
2024-08-23 14:24:31 +08:00
thank_mirror ( msg ) ;
2024-06-13 23:27:59 +08:00
}
2024-06-08 12:38:41 +08:00
}
else
{
2024-08-18 09:04:25 +08:00
char * msg = CliOpt_InEnglish ? MSG_EN_CONSTRAINT : MSG_CN_CONSTRAINT ;
chsrc_log ( msg ) ;
2024-06-08 12:38:41 +08:00
}
2024-08-18 09:04:25 +08:00
char * msg = CliOpt_InEnglish ? MSG_EN_BETTER : MSG_CN_BETTER ;
chsrc_warn ( msg ) ;
2024-06-08 12:38:41 +08:00
}
else if ( xy_streql ( ChsrcTypeUntested , last_word ) )
2024-06-07 23:51:11 +08:00
{
2024-06-08 12:38:41 +08:00
if ( source )
{
2024-06-13 23:27:59 +08:00
if ( source_is_userdefine ( source ) )
{
2024-08-18 09:04:25 +08:00
char * msg = CliOpt_InEnglish ? MSG_EN_PUBLIC_URL : MSG_CN_PUBLIC_URL ;
chsrc_log ( msg ) ;
2024-06-13 23:27:59 +08:00
}
else
{
2024-08-18 09:04:25 +08:00
char * msg = CliOpt_InEnglish ? MSG_EN_THANKS : MSG_CN_THANKS ;
2024-08-23 14:24:31 +08:00
thank_mirror ( msg ) ;
2024-06-13 23:27:59 +08:00
}
2024-06-08 12:38:41 +08:00
}
else
{
2024-08-18 09:04:25 +08:00
char * msg = CliOpt_InEnglish ? " Auto changed source " : " 自动换源完成 " ;
chsrc_log ( msg ) ;
2024-06-08 12:38:41 +08:00
}
2024-08-18 09:04:25 +08:00
char * msg = CliOpt_InEnglish ? " The method hasn't been tested or has any feedback, please report usage: chsrc issue " : " 该换源步骤已实现但未经测试或存在任何反馈,请报告使用情况: chsrc issue " ;
chsrc_warn ( msg ) ;
2024-06-07 23:51:11 +08:00
}
else
{
2024-08-18 09:04:25 +08:00
say ( last_word ) ;
2024-06-07 23:51:11 +08:00
}
2023-09-04 15:39:49 +08:00
}
2023-09-03 14:48:53 +08:00
2023-09-22 13:07:49 +08:00
void
2023-09-29 21:28:02 +08:00
chsrc_ensure_root ( )
2023-09-22 13:07:49 +08:00
{
2024-05-25 00:49:13 +08:00
char * euid = getenv ( " $EUID " ) ;
if ( NULL = = euid )
{
2024-06-11 17:05:15 +08:00
char * buf = xy_run ( " id -u " , 0 , NULL ) ;
2024-05-25 00:49:13 +08:00
if ( 0 ! = atoi ( buf ) ) goto not_root ;
else return ;
}
else
{
if ( 0 ! = atoi ( euid ) ) goto not_root ;
else return ;
}
2024-08-23 15:31:49 +08:00
char * msg = NULL ;
2023-09-22 13:07:49 +08:00
not_root :
2024-08-23 15:31:49 +08:00
msg = CliOpt_InEnglish ? " Use sudo before the command or switch to root to ensure the necessary permissions "
: " 请在命令前使用 sudo 或切换为root用户来保证必要的权限 " ;
2024-08-22 23:14:06 +08:00
chsrc_error ( msg ) ;
2024-06-14 15:01:52 +08:00
exit ( Exit_UserCause ) ;
2023-09-22 13:07:49 +08:00
}
2024-07-29 21:43:53 +08:00
# define RunOpt_Default 0x0000 // 默认若命令运行失败,直接退出
# define RunOpt_Dont_Notify_On_Success 0x0010 // 运行成功不提示用户,只有运行失败时才提示用户
# define RunOpt_No_Last_New_Line 0x0100 // 不输出最后的空行
# define RunOpt_Dont_Abort_On_Failure 0x1000 // 命令运行失败也不退出
2024-06-14 15:51:54 +08:00
2023-09-26 21:41:47 +08:00
static void
2024-06-14 15:51:54 +08:00
chsrc_run ( const char * cmd , int run_option )
2023-09-26 21:41:47 +08:00
{
2024-08-17 20:51:04 +08:00
if ( CliOpt_InEnglish )
2024-08-22 16:46:54 +08:00
xy_log_brkt ( blue ( App_Name ) , bdblue ( " RUN " ) , blue ( cmd ) ) ;
2024-08-17 20:51:04 +08:00
else
2024-08-22 16:46:54 +08:00
xy_log_brkt ( blue ( App_Name ) , bdblue ( " 运行 " ) , blue ( cmd ) ) ;
2024-08-09 01:46:58 +08:00
if ( CliOpt_DryRun )
{
return ; // Dry Run 此时立即结束,并不真正执行
}
2024-06-08 08:54:46 +08:00
int status = system ( cmd ) ;
if ( 0 = = status )
{
2024-07-29 21:43:53 +08:00
if ( ! ( RunOpt_Dont_Notify_On_Success & run_option ) )
2024-06-14 15:51:54 +08:00
{
2024-08-19 11:42:31 +08:00
log_cmd_result ( true , status ) ;
2024-06-14 15:51:54 +08:00
}
2024-06-08 08:54:46 +08:00
}
else
{
2024-08-19 11:42:31 +08:00
log_cmd_result ( false , status ) ;
2024-07-29 21:43:53 +08:00
if ( ! ( run_option & RunOpt_Dont_Abort_On_Failure ) )
2024-06-14 15:51:54 +08:00
{
2024-08-22 23:14:06 +08:00
char * msg = CliOpt_InEnglish ? " Fatal error, forced end " : " 关键错误,强制结束 " ;
chsrc_error ( msg ) ;
2024-06-14 15:51:54 +08:00
exit ( Exit_FatalUnkownError ) ;
}
}
if ( ! ( RunOpt_No_Last_New_Line & run_option ) )
{
2024-08-17 07:21:47 +08:00
br ( ) ;
2024-06-08 08:54:46 +08:00
}
2023-09-26 21:41:47 +08:00
}
2024-06-08 08:54:46 +08:00
2023-09-26 22:24:48 +08:00
static void
2024-07-09 13:04:37 +08:00
chsrc_view_file ( const char * path )
2023-09-26 22:24:48 +08:00
{
2024-05-25 00:49:13 +08:00
char * cmd = NULL ;
2023-09-27 18:31:45 +08:00
path = xy_uniform_path ( path ) ;
2024-07-31 12:38:52 +08:00
if ( xy_on_windows )
2024-05-25 00:49:13 +08:00
{
cmd = xy_2strjoin ( " type " , path ) ;
}
else
{
cmd = xy_2strjoin ( " cat " , path ) ;
}
2024-07-29 21:43:53 +08:00
chsrc_run ( cmd , RunOpt_Dont_Notify_On_Success | RunOpt_No_Last_New_Line ) ;
2023-09-26 22:24:48 +08:00
}
2023-09-29 21:23:58 +08:00
static void
2024-05-25 00:49:13 +08:00
chsrc_ensure_dir ( const char * dir )
2023-09-29 21:23:58 +08:00
{
2023-09-29 22:15:58 +08:00
dir = xy_uniform_path ( dir ) ;
2024-07-09 12:47:55 +08:00
2024-07-09 14:31:34 +08:00
if ( xy_dir_exist ( dir ) )
2024-07-09 12:47:55 +08:00
{
2024-07-09 14:31:34 +08:00
return ;
2024-07-09 12:47:55 +08:00
}
// 不存在就生成
2024-07-09 14:31:34 +08:00
char * mkdir_cmd = NULL ;
2024-05-25 00:49:13 +08:00
if ( xy_on_windows )
{
2024-07-09 12:47:55 +08:00
mkdir_cmd = " md " ; // 已存在时返回 errorlevel = 1
2024-05-25 00:49:13 +08:00
}
else
{
mkdir_cmd = " mkdir -p " ;
}
char * cmd = xy_2strjoin ( mkdir_cmd , dir ) ;
2023-09-29 21:23:58 +08:00
cmd = xy_str_to_quietcmd ( cmd ) ;
2024-07-29 21:43:53 +08:00
chsrc_run ( cmd , RunOpt_No_Last_New_Line | RunOpt_Dont_Notify_On_Success ) ;
2024-08-22 23:14:06 +08:00
char * msg = CliOpt_InEnglish ? " Directory doesn't exist, created automatically " : " 目录不存在,已自动创建 " ;
chsrc_note2 ( xy_2strjoin ( msg , dir ) ) ;
2023-09-29 21:23:58 +08:00
}
2023-09-26 21:41:47 +08:00
static void
2024-05-25 00:49:13 +08:00
chsrc_append_to_file ( const char * str , const char * file )
2023-09-26 21:41:47 +08:00
{
2023-09-27 18:31:45 +08:00
file = xy_uniform_path ( file ) ;
2024-05-25 00:49:13 +08:00
char * dir = xy_parent_dir ( file ) ;
2023-09-29 21:23:58 +08:00
chsrc_ensure_dir ( dir ) ;
2024-05-25 00:49:13 +08:00
char * cmd = NULL ;
if ( xy_on_windows )
{
cmd = xy_strjoin ( 4 , " echo " , str , " >> " , file ) ;
}
else
{
cmd = xy_strjoin ( 4 , " echo ' " , str , " ' >> " , file ) ;
}
2024-07-29 21:43:53 +08:00
chsrc_run ( cmd , RunOpt_No_Last_New_Line | RunOpt_Dont_Notify_On_Success ) ;
2024-07-03 13:59:06 +08:00
}
static void
chsrc_prepend_to_file ( const char * str , const char * file )
{
file = xy_uniform_path ( file ) ;
char * dir = xy_parent_dir ( file ) ;
chsrc_ensure_dir ( dir ) ;
char * cmd = NULL ;
if ( xy_on_windows )
{
xy_unimplement ;
}
else
{
2024-07-06 23:21:59 +08:00
cmd = xy_strjoin ( 4 , " sed -i '1i " , str , " ' " , file ) ;
2024-07-03 13:59:06 +08:00
}
2024-07-29 21:43:53 +08:00
chsrc_run ( cmd , RunOpt_No_Last_New_Line | RunOpt_Dont_Notify_On_Success ) ;
2023-09-26 21:41:47 +08:00
}
static void
2024-05-25 00:49:13 +08:00
chsrc_overwrite_file ( const char * str , const char * file )
2023-09-26 21:41:47 +08:00
{
2023-09-27 18:31:45 +08:00
file = xy_uniform_path ( file ) ;
2024-05-25 00:49:13 +08:00
char * dir = xy_parent_dir ( file ) ;
2023-09-29 21:23:58 +08:00
chsrc_ensure_dir ( dir ) ;
2024-05-25 00:49:13 +08:00
char * cmd = NULL ;
if ( xy_on_windows )
{
cmd = xy_strjoin ( 4 , " echo " , str , " > " , file ) ;
}
else
{
cmd = xy_strjoin ( 4 , " echo ' " , str , " ' > " , file ) ;
}
2024-06-14 15:51:54 +08:00
chsrc_run ( cmd , RunOpt_Default ) ;
2023-09-26 21:41:47 +08:00
}
2023-09-26 23:02:12 +08:00
static void
2024-05-25 00:49:13 +08:00
chsrc_backup ( const char * path )
2023-09-26 23:02:12 +08:00
{
2024-05-25 00:49:13 +08:00
char * cmd = NULL ;
2024-07-29 21:57:22 +08:00
bool exist = xy_file_exist ( path ) ;
if ( ! exist )
{
2024-08-22 23:14:06 +08:00
char * msg = CliOpt_InEnglish ? " File doesn't exist, skip backup: " : " 文件不存在,跳过备份: " ;
chsrc_note2 ( xy_2strjoin ( msg , path ) ) ;
2024-07-29 21:57:22 +08:00
return ;
}
2023-10-05 17:32:02 +08:00
2024-07-09 10:06:00 +08:00
if ( xy_on_bsd | | xy_on_macos )
2024-05-25 00:49:13 +08:00
{
2024-07-09 10:06:00 +08:00
/* BSD 和 macOS 的 cp 不支持 --backup 选项 */
2024-05-25 00:49:13 +08:00
cmd = xy_strjoin ( 5 , " cp -f " , path , " " , path , " .bak " ) ;
}
else if ( xy_on_windows )
{
// /Y 表示覆盖
cmd = xy_strjoin ( 5 , " copy /Y " , path , " " , path , " .bak " ) ;
}
else
{
cmd = xy_strjoin ( 5 , " cp " , path , " " , path , " .bak --backup='t' " ) ;
}
2023-10-05 17:32:02 +08:00
2024-07-29 21:43:53 +08:00
chsrc_run ( cmd , RunOpt_No_Last_New_Line | RunOpt_Dont_Notify_On_Success ) ;
2024-08-22 23:14:06 +08:00
chsrc_note2 ( xy_strjoin ( 3 ,
CliOpt_InEnglish ? " Backup file name is " : " 备份文件名为 " ,
path , " .bak " ) ) ;
2023-09-26 23:02:12 +08:00
}
2023-09-26 21:41:47 +08:00
2024-09-03 20:03:45 +08:00
/**
* 检 查 过 程 中 全 程 保 持 安 静
*/
2024-06-21 10:55:43 +08:00
static char *
chsrc_get_cpuarch ( )
{
char * ret ;
2024-09-03 21:43:57 +08:00
# if XY_On_Windows
SYSTEM_INFO info ;
GetSystemInfo ( & info ) ;
2024-09-04 07:57:54 +08:00
WORD num = info . wProcessorArchitecture ;
2024-09-03 21:43:57 +08:00
switch ( num )
{
case PROCESSOR_ARCHITECTURE_AMD64 :
ret = " x86_64 " ; break ;
case PROCESSOR_ARCHITECTURE_ARM :
ret = " arm " ; break ;
case PROCESSOR_ARCHITECTURE_INTEL :
ret = " x86 " ; break ;
case PROCESSOR_ARCHITECTURE_IA64 :
ret = " IA-64 " ; break ;
case PROCESSOR_ARCHITECTURE_UNKNOWN :
2024-09-04 07:57:54 +08:00
default :
2024-09-03 21:43:57 +08:00
char * msg = CliOpt_InEnglish ? " Unable to detect CPU type " : " 无法检测到CPU类型 " ;
chsrc_error ( msg ) ;
exit ( Exit_UserCause ) ;
2024-06-21 10:55:43 +08:00
}
2024-09-03 21:43:57 +08:00
# else
bool exist ;
2024-06-21 10:55:43 +08:00
2024-09-03 20:03:45 +08:00
exist = chsrc_check_program_quietly ( " arch " ) ;
2024-06-21 10:55:43 +08:00
if ( exist )
{
ret = xy_run ( " arch " , 0 , NULL ) ;
return ret ;
}
2024-09-03 20:03:45 +08:00
exist = chsrc_check_program_quietly ( " uname " ) ;
2024-06-21 10:55:43 +08:00
if ( exist )
{
2024-07-06 23:21:59 +08:00
ret = xy_run ( " uname -m " , 0 , NULL ) ;
2024-06-21 10:55:43 +08:00
return ret ;
}
else
{
2024-08-22 23:14:06 +08:00
char * msg = CliOpt_InEnglish ? " Unable to detect CPU type " : " 无法检测到CPU类型 " ;
chsrc_error ( msg ) ;
2024-06-21 10:55:43 +08:00
exit ( Exit_UserCause ) ;
}
2024-09-03 21:43:57 +08:00
# endif
2024-06-21 10:55:43 +08:00
}
2024-09-03 20:52:05 +08:00
static int
chsrc_get_cpucore ( )
{
int cores = 2 ;
# if XY_On_Windows
SYSTEM_INFO info ;
GetSystemInfo ( & info ) ;
2024-09-04 07:57:54 +08:00
DWORD num = info . dwNumberOfProcessors ;
2024-09-03 20:52:05 +08:00
cores = ( int ) num ;
# else
long num = sysconf ( _SC_NPROCESSORS_ONLN ) ;
cores = ( int ) num ;
# endif
return cores ;
}