chsrc/include/chsrc.h

1068 lines
30 KiB
C
Raw Normal View History

/** ------------------------------------------------------------
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
* |
* Created on : <2023-08-29>
2024-09-03 17:52:03 +08:00
* Last modified : <2024-09-03>
*
2024-06-11 20:18:02 +08:00
* chsrc
* ------------------------------------------------------------*/
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-08-23 08:09:39 +08:00
bool CliOpt_IPv6 = false;
bool CliOpt_Locally = false;
bool CliOpt_InEnglish = false;
2024-08-23 08:09:39 +08:00
bool CliOpt_DryRun = false;
bool CliOpt_NoColor = false;
/**
* -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
#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
/**
* @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
{
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
/**
* @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
{
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: ";
}
else
2024-08-08 16:25:36 +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
}
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
bool
is_url (const char *str)
{
return (xy_str_start_with (str, "http://") || xy_str_start_with (str, "https://"));
}
2023-09-15 12:50:56 +08:00
/**
*
*
* @param check_cmd `prog_name` `prog_name`
2023-09-15 12:50:56 +08:00
* 使 python Windows上
* Microsoft Store
*
* @param prog_name
*
* @translation Done
2023-09-15 12:50:56 +08:00
*/
bool
query_program_exist (char *check_cmd, char *prog_name)
2023-09-15 12:50:56 +08:00
{
char *which = check_cmd;
2023-09-15 12:50:56 +08:00
int ret = system(which);
// char buf[32] = {0}; sprintf(buf, "错误码: %d", ret);
char *msg = CliOpt_InEnglish ? "command" : "命令";
if (0 != ret)
{
// xy_warn (xy_strjoin(4, "× 命令 ", progname, " 不存在,", buf));
2024-08-19 11:42:31 +08:00
log_check_result (prog_name, msg, false);
return false;
}
else
{
2024-08-19 11:42:31 +08:00
log_check_result (prog_name, msg, true);
return true;
}
2023-09-15 12:50:56 +08:00
}
2024-06-14 01:02:23 +08:00
/**
* @note --version
*/
bool
chsrc_check_program (char *prog_name)
{
char *quiet_cmd = xy_str_to_quietcmd (xy_2strjoin (prog_name, " --version"));
return query_program_exist (quiet_cmd, prog_name);
}
/**
* @note 退
*/
void
chsrc_ensure_program (char *prog_name)
{
char *quiet_cmd = xy_str_to_quietcmd (xy_2strjoin (prog_name, " --version"));
bool exist = query_program_exist (quiet_cmd, prog_name);
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
}
}
bool
2024-06-14 15:15:59 +08:00
chsrc_check_file (char *path)
{
2024-08-22 23:14:06 +08:00
char *msg = CliOpt_InEnglish ? "file" : "文件";
if (xy_file_exist (path))
{
2024-08-22 23:14:06 +08:00
log_check_result (path, msg, true);
return true;
}
else
{
2024-08-22 23:14:06 +08:00
log_check_result (path, msg, false);
return false;
}
}
2023-09-15 12:50:56 +08:00
/**
* _setsrc codetarget可用源中
*
* @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
{
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-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-08-23 14:24:31 +08:00
char *msg2 = CliOpt_InEnglish ? " the only mirror site available currently, thanks for their generous support"
: " 目前唯一可用镜像站,感谢他们的慷慨支持";
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
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];
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 *
measure_speed (void *url)
2023-09-15 12:50:56 +08:00
{
2024-09-03 17:52:03 +08:00
char *time_sec = "9";
2023-09-15 12:50:56 +08:00
/* 现在我们切换至跳转后的链接来测速,不再使用下述判断
2023-09-15 12:50:56 +08:00
if (xy_str_start_with(url, "https://registry.npmmirror"))
{
// 这里 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
// 我们用 —L因为Ruby China源会跳转到其他地方
// npmmirror 也会跳转
char *curl_cmd = xy_strjoin (7, "curl -qsL ", ipv6,
" -o " xy_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-03 17:52:03 +08:00
char *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;
}
2023-09-27 09:40:31 +08:00
/**
*
*
* @translation Done
2023-09-27 09:40:31 +08:00
*/
#define auto_select(s) auto_select_(s##_sources, s##_sources_n, (char*)#s+3)
2023-09-15 12:50:56 +08:00
int
2024-08-16 19:06:16 +08:00
auto_select_ (SourceInfo *sources, size_t size, const char *target_name)
2023-09-15 12:50:56 +08:00
{
2024-06-07 23:51:11 +08:00
if (0==size || 1==size)
2024-05-25 00:49:13 +08:00
{
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));
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-08-09 01:46:58 +08:00
if (CliOpt_DryRun)
{
return 1; // Dry Run 时,跳过测速
}
bool only_one = false;
if (2==size) only_one = true;
2023-09-15 12:50:56 +08:00
2024-06-13 00:17:01 +08:00
char *check_curl = xy_str_to_quietcmd ("curl --version");
bool exist_curl = query_program_exist (check_curl, "curl");
if (!exist_curl)
{
char *msg = CliOpt_InEnglish ? "No curl, unable to measure speed" : "没有curl命令无法测速";
chsrc_error (msg);
2024-06-14 15:01:52 +08:00
exit (Exit_UserCause);
2024-06-13 00:17:01 +08:00
}
2023-09-15 12:50:56 +08:00
double speeds[size];
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++)
{
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-03 17:52:03 +08:00
speed = 0; // 上游源不测速直接置0
2024-08-09 01:46:58 +08:00
}
else
{
char *msg1 = CliOpt_InEnglish ? "Dev team doesn't offer " : "开发者未提供 ";
char *msg2 = CliOpt_InEnglish ? " mirror site's speed measurement link,so skip it" : " 镜像站测速链接,跳过该站点";
chsrc_warn (xy_strjoin (3, msg1, src.mirror->code, msg2));
2024-08-09 01:46:58 +08:00
speed = 0;
}
2024-09-01 23:27:49 +08:00
speeds[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-08-22 23:14:06 +08:00
char *msg = CliOpt_InEnglish ? "Measure speed> " : "测速 ";
2024-09-03 17:52:03 +08:00
measure_msgs[i] = xy_strjoin (3, msg, src.mirror->site , " ... ");
printf ("%s", measure_msgs[i]);
say ("");
// fflush (stdout);
2024-09-01 23:27:49 +08:00
char *url_ = xy_strdup (url);
int ret = pthread_create (&threads[i], NULL, measure_speed, url_);
if (ret!=0)
{
chsrc_error ("Unable to measure speed\n");
exit (Exit_UserCause);
}
else
{
2024-09-03 17:52:03 +08:00
get_measured[i] = true;
get_measured_n += 1;
2024-09-01 23:27:49 +08:00
}
}
}
2024-09-03 17:52:03 +08:00
2024-09-01 23:27:49 +08:00
/* 汇总 */
2024-09-03 17:52:03 +08:00
char **curl_results = xy_malloc0 (sizeof(char *) * size);
2024-09-01 23:27:49 +08:00
for (int i=0; i<size; i++)
{
2024-09-03 17:52:03 +08:00
if (get_measured[i]==true)
pthread_join (threads[i], (void *)&curl_results[i]);
}
for (int i=0; i<get_measured_n; i++)
printf("\033[A\033[2K");
2024-09-01 23:27:49 +08:00
2024-09-03 17:52:03 +08:00
for (int i=0; i<size; i++)
{
if (get_measured[i]==true)
2024-09-01 23:27:49 +08:00
{
2024-09-03 17:52:03 +08:00
printf ("%s", measure_msgs[i]);
double speed = parse_and_say_curl_result (curl_results[i]);
// puts("");
speeds[i] = speed;
2024-08-09 01:46:58 +08:00
}
}
2024-09-03 17:52:03 +08:00
/* 汇总结束 */
/* DEBUG */
// for (int i=0; i<size; i++)
// {
// printf ("speeds[%d] = %f\n", i, speeds[i]);
// }
2024-08-09 01:46:58 +08:00
int fast_idx = get_max_ele_idx_in_dbl_ary (speeds, size);
2023-09-15 12:50:56 +08:00
2024-08-09 01:46:58 +08:00
if (only_one)
{
2024-08-23 14:24:31 +08:00
char *is = CliOpt_InEnglish ? " is " : "";
char *msg = CliOpt_InEnglish ? "the ONLY mirror available currently, thanks for their generous support"
: " 目前唯一可用镜像站,感谢他们的慷慨支持";
const char *name = CliOpt_InEnglish ? sources[fast_idx].mirror->abbr
: sources[fast_idx].mirror->name;
chsrc_succ (xy_strjoin (4, name, is, target_name, msg));
}
2023-09-15 12:50:56 +08:00
else
{
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)));
}
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) \
(NULL!=(input)) ? find_mirror(s, input) : auto_select(s)
2024-06-07 23:51:11 +08:00
bool
source_is_upstream (SourceInfo *source)
2024-06-07 23:51:11 +08:00
{
return xy_streql (source->mirror->code, "upstream");
}
bool
source_is_userdefine (SourceInfo *source)
{
return xy_streql (source->mirror->code, "user");
}
2024-06-07 23:51:11 +08:00
bool
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); \
source = for_what##_sources[__index]; \
2024-06-13 23:43:31 +08:00
}
2024-06-07 23:51:11 +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.
*
* @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 我们并没有实现,我们在这里阻止这些邪恶的用户
if (source_is_upstream (source) && source_has_empty_url (source))
2024-06-07 23:51:11 +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
}
else if (source_has_empty_url (source))
2024-06-07 23:51:11 +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
{
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
}
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
#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)))
/**
* @param source NULL
* @param last_word 5ChsrcTypeAuto | ChsrcTypeReset | ChsrcTypeSemiAuto | ChsrcTypeManual | ChsrcTypeUntested
2024-08-18 09:04:25 +08:00
* @translation Done
*/
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
{
split_between_source_changing_process;
if (xy_streql (ChsrcTypeAuto, last_word))
{
if (source)
{
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);
}
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);
}
}
else
{
2024-08-18 09:04:25 +08:00
char *msg = CliOpt_InEnglish ? MSG_EN_FULLY_AUTO : MSG_CN_FULLY_AUTO;
chsrc_log (msg);
}
}
else if (xy_streql (ChsrcTypeReset, last_word))
{
// 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));
}
else if (xy_streql (ChsrcTypeSemiAuto, last_word))
{
if (source)
{
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);
}
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);
}
}
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-08-18 09:04:25 +08:00
char *msg = CliOpt_InEnglish ? MSG_EN_BETTER : MSG_CN_BETTER;
chsrc_warn (msg);
}
else if (xy_streql (ChsrcTypeManual, last_word))
{
if (source)
{
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);
}
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);
}
}
else
{
2024-08-18 09:04:25 +08:00
char *msg = CliOpt_InEnglish ? MSG_EN_CONSTRAINT : MSG_CN_CONSTRAINT;
chsrc_log (msg);
}
2024-08-18 09:04:25 +08:00
char *msg = CliOpt_InEnglish ? MSG_EN_BETTER : MSG_CN_BETTER;
chsrc_warn (msg);
}
else if (xy_streql (ChsrcTypeUntested, last_word))
2024-06-07 23:51:11 +08:00
{
if (source)
{
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);
}
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);
}
}
else
{
2024-08-18 09:04:25 +08:00
char *msg = CliOpt_InEnglish ? "Auto changed source" : "自动换源完成";
chsrc_log (msg);
}
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)
{
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
{
if (CliOpt_InEnglish)
2024-08-22 16:46:54 +08:00
xy_log_brkt (blue (App_Name), bdblue ("RUN"), blue (cmd));
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 此时立即结束,并不真正执行
}
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
}
}
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();
}
2023-09-26 21:41:47 +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
{
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;
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));
return;
}
2023-10-05 17:32:02 +08:00
if (xy_on_bsd || xy_on_macos)
2024-05-25 00:49:13 +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-06-21 10:55:43 +08:00
static char *
chsrc_get_cpuarch ()
{
char *ret;
bool exist;
if (xy_on_windows)
{
xy_unimplement;
}
exist = chsrc_check_program ("arch");
if (exist)
{
ret = xy_run ("arch", 0, NULL);
return ret;
}
exist = chsrc_check_program ("uname");
if (exist)
{
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);
}
}