Skip to content

Commit 3905eaf

Browse files
author
Mikachu2333
committed
fix(uv): 修复getsrc
1 parent 462bf86 commit 3905eaf

File tree

1 file changed

+232
-84
lines changed
  • src/recipe/lang/Python

1 file changed

+232
-84
lines changed

src/recipe/lang/Python/uv.c

Lines changed: 232 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -35,132 +35,280 @@ pl_python_uv_prelude (void)
3535
* 4. /etc/uv/uv.toml
3636
*/
3737

38-
#define PL_Python_uv_ConfigFile "uv.toml"
39-
#define PL_Python_uv_Local_ConfigPath "./"
40-
#define PL_Python_uv_User_ConfigPath "~/.config/uv/"
38+
#define PL_Python_uv_Proj_uv "uv.toml"
39+
#define PL_Python_uv_Proj_pyproj "pyproject.toml"
40+
#ifdef XY_Build_On_Windows
41+
#define PL_Python_uv_Local_ConfigPath "\\uv\\uv.toml"
42+
#define PL_Python_uv_User_ConfigPath "\\uv\\uv.toml"
43+
#else
44+
#define PL_Python_uv_Local_ConfigPath "~/.config/uv/"
45+
#define PL_Python_uv_User_ConfigPath "/etc/uv/uv.toml"
46+
#endif
4147

48+
typedef struct
49+
{
50+
bool is_empty;
51+
char *url;
52+
char *file_path;
53+
}
54+
PlPythonUvConfig;
4255

43-
char *
44-
pl_python_find_uv_config (bool mkdir)
56+
PlPythonUvConfig
57+
pl_python_uv_config_define_python (char *path)
4558
{
46-
if (chsrc_in_local_mode())
59+
PlPythonUvConfig config = {true, NULL, NULL};
60+
61+
char *content = xy_file_read (path);
62+
if (!content || strlen (content) == 0)
63+
return config;
64+
65+
char *formatted = xy_str_gsub (content, " ", "");
66+
formatted = xy_str_gsub (formatted, "'", "\"");
67+
68+
XyStrFindResult_t result = xy_str_find (formatted, "python-install-mirror");
69+
if (result.found)
4770
{
48-
return xy_2strcat (PL_Python_uv_Local_ConfigPath, PL_Python_uv_ConfigFile);
71+
char *url = xy_str_next_nonempty_line (formatted + result.end + 1);
72+
url = xy_str_gsub (url, "\"", "");
73+
url = xy_str_delete_prefix (url, "=");
74+
config.url = url;
75+
config.file_path = xy_strdup (path);
76+
config.is_empty = !config.url;
4977
}
50-
else
78+
return config;
79+
}
80+
81+
PlPythonUvConfig
82+
pl_python_uv_config_define_pypi (char *path)
83+
{
84+
PlPythonUvConfig config = {true, NULL, NULL};
85+
86+
char *content = xy_file_read (path);
87+
if (!content || strlen (content) == 0)
88+
return config;
89+
90+
char *formatted = xy_str_gsub (content, " ", "");
91+
formatted = xy_str_gsub (formatted, "'", "\"");
92+
93+
XyStrFindResult_t old_sytle_result = xy_str_find (formatted, "[[index]]");
94+
XyStrFindResult_t new_sytle_result = xy_str_find (formatted, "index-url");
95+
if (old_sytle_result.found && new_sytle_result.found)
5196
{
52-
if (xy.on_windows)
53-
{
54-
/* config path on Windows */
55-
char *appdata = getenv ("APPDATA");
97+
chsrc_error2 (path);
98+
char *msg = ENGLISH ? "UV config conflicted with old sytle and new style."
99+
: "UV 配置文件因同时存在新旧两种格式而冲突,请自行检查。";
100+
chsrc_error (msg);
101+
exit (Exit_UserCause);
102+
}
56103

57-
if (!appdata)
58-
{
59-
chsrc_error2 ("未能获取 APPDATA 环境变量");
60-
return NULL;
61-
}
104+
if (old_sytle_result.found)
105+
{
106+
char *current_pos = formatted + old_sytle_result.end + 1;
107+
char *url = NULL;
62108

63-
char *config_dir = xy_2strcat(appdata, "\\uv\\");
64-
if (mkdir)
109+
/* 循环读取下一行,直到找到包含 "url" 的行 */
110+
while (*current_pos != '\0')
111+
{
112+
char *line = xy_str_next_nonempty_line (current_pos);
113+
if (line && xy_str_find (line, "url").found)
65114
{
66-
chsrc_ensure_dir (config_dir);
115+
url = line;
116+
break;
67117
}
68-
return xy_2strcat (config_dir, PL_Python_uv_ConfigFile);
118+
119+
/* 移动到下一行的位置 */
120+
current_pos = strchr (current_pos, '\n');
121+
if (!current_pos)
122+
break;
123+
current_pos++;
69124
}
70-
else
125+
126+
if (url)
71127
{
72-
/* config path on Linux or macOS */
73-
if (mkdir)
74-
{
75-
chsrc_ensure_dir (PL_Python_uv_User_ConfigPath);
76-
}
77-
return xy_2strcat (PL_Python_uv_User_ConfigPath, PL_Python_uv_ConfigFile);
128+
url = xy_str_gsub (url, "\"", "");
129+
url = xy_str_delete_prefix (url, "url=");
130+
config.url = url;
131+
config.file_path = xy_strdup (path);
132+
config.is_empty = !config.url;
78133
}
79134
}
80-
}
81-
82-
void
83-
pl_python_uv_getsrc (char *option)
84-
{
85-
char *uv_config = pl_python_find_uv_config (false);
86-
87-
if (!chsrc_check_file (uv_config))
135+
else
88136
{
89-
chsrc_error2 ("未找到 uv 配置文件");
90-
return;
137+
char *url = xy_str_next_nonempty_line (formatted + new_sytle_result.end + 1);
138+
url = xy_str_gsub (url, "\"", "");
139+
url = xy_str_delete_prefix (url, "=");
140+
config.url = url;
141+
config.file_path = xy_strdup (path);
142+
config.is_empty = !config.url;
91143
}
144+
return config;
145+
}
92146

93-
/* 获取 [[index]] 配置项的 url */
94-
char *cmd = xy_str_gsub (RAWSTR_pl_python_get_uv_config, "@f@", uv_config);
95-
chsrc_run (cmd, RunOpt_Default);
147+
typedef struct
148+
{
149+
bool pypi;
150+
char *pypi_url;
151+
char *pypi_path;
152+
bool python;
153+
char *python_url;
154+
char *python_path;
96155
}
156+
PlPythonUvConfigSummary;
97157

158+
bool
159+
pl_python_uv_config_summary_struct_is_full (PlPythonUvConfigSummary *config)
160+
{
161+
return config->pypi == true &&
162+
config->python == true;
163+
}
98164

99165
/**
100-
* @consult https://docs.astral.sh/uv/configuration/files/
101-
* https://github.com/RubyMetric/chsrc/issues/139
166+
* @brief 按配置文件优先级依次查找镜像配置
167+
*
168+
* @return 返回优先级最高的有效配置,其余配置将被忽略。可能为空。
169+
*
170+
* @note 特殊情况(Local mode)时直接返回项目一级的配置,无论是否为空
102171
*/
103-
void
104-
pl_python_uv_setsrc (char *option)
172+
PlPythonUvConfigSummary
173+
pl_python_uv_config_find ()
105174
{
106-
chsrc_ensure_program ("uv");
175+
PlPythonUvConfigSummary result = {false, NULL, NULL, false, NULL, NULL};
176+
177+
// 第一优先级
178+
PlPythonUvConfig result1 = pl_python_uv_config_define_python (PL_Python_uv_Proj_uv);
179+
if (!result1.is_empty)
180+
{
181+
result.python = true;
182+
result.python_url = result1.url;
183+
result.python_path = result1.file_path;
184+
}
185+
186+
PlPythonUvConfig result2 = pl_python_uv_config_define_pypi (PL_Python_uv_Proj_uv);
187+
if (!result2.is_empty)
188+
{
189+
result.pypi = true;
190+
result.pypi_url = result2.url;
191+
result.pypi_path = result2.file_path;
192+
}
193+
if (pl_python_uv_config_summary_struct_is_full (&result) || chsrc_in_local_mode()) return result;
194+
195+
PlPythonUvConfig result3 = pl_python_uv_config_define_python (PL_Python_uv_Proj_pyproj);
196+
if (!result3.is_empty)
197+
{
198+
result.python = true;
199+
result.python_url = result3.url;
200+
result.python_path = result3.file_path;
201+
}
202+
if (pl_python_uv_config_summary_struct_is_full (&result)) return result;
107203

108-
Source_t source = chsrc_yield_source (&pl_python_group_target, option);
109-
if (chsrc_in_standalone_mode())
110-
chsrc_confirm_source(&source);
204+
PlPythonUvConfig result4 = pl_python_uv_config_define_pypi (PL_Python_uv_Proj_pyproj);
205+
if (!result4.is_empty)
206+
{
207+
result.pypi = true;
208+
result.pypi_url = result4.url;
209+
result.pypi_path = result4.file_path;
210+
}
211+
if (pl_python_uv_config_summary_struct_is_full (&result)) return result;
111212

112-
char *uv_config = pl_python_find_uv_config (true);
113-
if (NULL==uv_config)
213+
// 第二优先级
214+
char *uv_local_config_path = PL_Python_uv_Local_ConfigPath;
215+
if (xy.on_windows)
114216
{
115-
chsrc_error2 ("无法获取 uv 配置文件路径");
116-
return;
217+
uv_local_config_path = xy_2strcat (getenv ("APPDATA"), uv_local_config_path);
117218
}
118-
chsrc_backup (uv_config);
119219

120-
const char *source_content = xy_str_gsub (RAWSTR_pl_python_uv_config_source_content, "@url@", source.url);
220+
PlPythonUvConfig result5 = pl_python_uv_config_define_python (uv_local_config_path);
221+
if (!result5.is_empty)
222+
{
223+
result.python = true;
224+
result.python_path = result5.file_path;
225+
result.python_url = result5.url;
226+
}
227+
if (pl_python_uv_config_summary_struct_is_full (&result)) return result;
121228

122-
#if defined(XY_Build_On_macOS) || defined(XY_Build_On_BSD)
123-
char *sed_cmd = "sed -i '' ";
124-
#else
125-
char *sed_cmd = "sed -i ";
126-
#endif
229+
PlPythonUvConfig result6 = pl_python_uv_config_define_pypi (uv_local_config_path);
230+
if (!result6.is_empty)
231+
{
232+
result.pypi = true;
233+
result.pypi_path = result6.file_path;
234+
result.pypi_url = result6.url;
235+
}
236+
if (pl_python_uv_config_summary_struct_is_full (&result)) return result;
237+
238+
// 第三优先级
239+
char *uv_user_config_path = PL_Python_uv_User_ConfigPath;
240+
if (xy.on_windows)
241+
{
242+
uv_user_config_path = xy_2strcat (getenv ("APPDATA"), uv_user_config_path);
243+
}
244+
PlPythonUvConfig result7 = pl_python_uv_config_define_python (uv_user_config_path);
245+
if (!result7.is_empty)
246+
{
247+
result.python = true;
248+
result.python_path = result7.file_path;
249+
result.python_url = result7.url;
250+
}
251+
if (pl_python_uv_config_summary_struct_is_full (&result)) return result;
252+
253+
PlPythonUvConfig result8 = pl_python_uv_config_define_pypi (uv_user_config_path);
254+
if (!result8.is_empty)
255+
{
256+
result.pypi = true;
257+
result.pypi_path = result8.file_path;
258+
result.pypi_url = result8.url;
259+
}
260+
261+
return result;
262+
}
127263

128-
/**
129-
* 将 [[index]] 到 default = true 之间的 url = ".*" 替换为 url = "source.url"
130-
*/
131-
char *update_config_cmd = xy_str_gsub (RAWSTR_pl_python_set_uv_config, "@sed@", sed_cmd);
132-
update_config_cmd = xy_str_gsub (update_config_cmd, "@f@", uv_config);
133-
update_config_cmd = xy_str_gsub (update_config_cmd, "@url@", source.url);
264+
void
265+
pl_python_uv_getsrc (char *option)
266+
{
267+
PlPythonUvConfigSummary uv_config = pl_python_uv_config_find ();
134268

135-
if (!xy_file_exist (uv_config))
269+
if (uv_config.pypi)
136270
{
137-
/* 当 uv_config 不存在,直接写入文件 */
138-
chsrc_append_to_file (source_content, uv_config);
271+
chsrc_note2 ("uv pypi:");
272+
say (xy_2strcat (ENGLISH ? "Config Path: " : "文件路径:", uv_config.pypi_path));
273+
say (uv_config.pypi_url);
139274
}
140275
else
141276
{
142-
/* 当 uv_config 存在,如果存在 [[index]] 则更新,否则追加到文件末尾 */
143-
char *cmd = xy_str_gsub (RAWSTR_pl_python_test_uv_if_set_source, "@f@", uv_config);
144-
chsrc_ensure_program ("grep");
145-
int status = xy_run_get_status (cmd);
146-
if (0==status)
147-
{
148-
chsrc_run (update_config_cmd, RunOpt_Default);
149-
}
150-
else
151-
{
152-
chsrc_append_to_file (source_content, uv_config);
153-
}
277+
char *msg = ENGLISH ? "Can't find uv config for pypi, show default."
278+
: "未找到 uv 关于 pypi 的配置文件,显示默认值";
279+
chsrc_note2 (msg);
280+
say ("https://pypi.org/simple");
154281
}
155282

156-
if (chsrc_in_standalone_mode())
283+
if (uv_config.python)
284+
{
285+
chsrc_note2 ("uv Python:");
286+
say (xy_2strcat (ENGLISH ? "Config Path: " : "文件路径:", uv_config.python_path));
287+
say (uv_config.python_url);
288+
}
289+
else
157290
{
158-
chsrc_determine_chgtype (ChgType_Auto);
159-
chsrc_conclude (&source);
291+
char *msg = ENGLISH ? "Can't find uv config for Python, show default."
292+
: "未找到 uv 关于 Python 的配置文件,显示默认值";
293+
chsrc_note2 (msg);
294+
say ("https://github.com/astral-sh/python-build-standalone/releases/download");
160295
}
161296
}
162297

163298

299+
/**
300+
* @consult https://docs.astral.sh/uv/configuration/files/
301+
* https://github.com/RubyMetric/chsrc/issues/139
302+
*/
303+
void
304+
pl_python_uv_setsrc (char *option)
305+
{
306+
chsrc_ensure_program ("uv");
307+
308+
309+
}
310+
311+
164312
void
165313
pl_python_uv_resetsrc (char *option)
166314
{

0 commit comments

Comments
 (0)