Add support for GitHub URLs and requirements files in Python dependencies

Co-authored-by: whyour <22700758+whyour@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot] 2025-12-27 08:41:43 +00:00
parent e28f746294
commit f526d3f972
3 changed files with 111 additions and 6 deletions

View File

@ -536,11 +536,26 @@ export async function setSystemTimezone(timezone: string): Promise<boolean> {
}
export function getGetCommand(type: DependenceTypes, name: string): string {
const trimmedName = name.trim();
// For Python dependencies installed from GitHub or requirements files,
// we can't reliably check if they're installed, so skip the check
if (type === DependenceTypes.python3) {
if (trimmedName.match(/^(https?:\/\/|git\+)/i) ||
trimmedName.match(/\.(txt|in)$/i) ||
trimmedName.includes('requirements') ||
trimmedName.endsWith('pyproject.toml')) {
// Return a command that will always indicate not installed
// This ensures GitHub URLs and requirements files are always installed
return 'echo ""';
}
}
const baseCommands = {
[DependenceTypes.nodejs]: `pnpm ls -g | grep "${name}" | head -1`,
[DependenceTypes.nodejs]: `pnpm ls -g | grep "${trimmedName}" | head -1`,
[DependenceTypes.python3]: `
python3 -c "exec('''
name='${name}'
name='${trimmedName}'
try:
from importlib.metadata import version
print(version(name))
@ -550,7 +565,7 @@ except:
spec=u.find_spec(name)
print(name if spec else '')
''')"`,
[DependenceTypes.linux]: `apk info -es ${name}`,
[DependenceTypes.linux]: `apk info -es ${trimmedName}`,
};
return baseCommands[type];
@ -570,7 +585,27 @@ export function getInstallCommand(type: DependenceTypes, name: string): string {
command = `${command} --prefix=${PYTHON_INSTALL_DIR}`;
}
return `${command} ${name.trim()}`;
const trimmedName = name.trim();
// Handle different installation methods for Python
if (type === DependenceTypes.python3) {
// Check if it's a GitHub URL (support both git+ and direct URLs)
if (trimmedName.match(/^(https?:\/\/|git\+)/i)) {
return `${command} ${trimmedName}`;
}
// Check if it's a requirements file path
if (trimmedName.match(/\.(txt|in)$/i) || trimmedName.includes('requirements')) {
return `${command} -r ${trimmedName}`;
}
// Check if it's a pyproject.toml file
if (trimmedName.endsWith('pyproject.toml')) {
// For pyproject.toml, install from the directory containing it
const dir = trimmedName.replace(/\/pyproject\.toml$/, '') || '.';
return `${command} ${dir}`;
}
}
return `${command} ${trimmedName}`;
}
export function getUninstallCommand(

View File

@ -111,6 +111,56 @@ add_cron() {
notify_api "$path 新增任务" "$detail"
}
## 自动安装订阅仓库中的Python依赖
auto_install_python_deps() {
local repo_path="$1"
local uniq_path="$2"
echo -e "\n检测订阅仓库中的Python依赖文件...\n"
get_token
# 检查 requirements.txt
if [[ -f "${repo_path}/requirements.txt" ]]; then
echo -e "发现 requirements.txt开始自动安装依赖...\n"
local req_file="${dir_scripts}/${uniq_path}/requirements.txt"
cp -f "${repo_path}/requirements.txt" "${req_file}"
# 调用API添加依赖安装任务
local dep_name="${uniq_path}/requirements.txt"
local currentTimeStamp=$(date +%s)
local result=$(curl -s --noproxy "*" "http://127.0.0.1:${ql_port}/open/dependencies?t=$currentTimeStamp" \
-X POST \
-H "Content-Type: application/json;charset=UTF-8" \
-H "Authorization: Bearer ${__ql_token__}" \
--data-raw "[{\"name\":\"${dep_name}\",\"type\":1,\"remark\":\"自动检测:${uniq_path} 订阅依赖\"}]" | jq -r '.code')
if [[ "$result" == "200" ]]; then
echo -e "已添加 requirements.txt 依赖安装任务\n"
fi
fi
# 检查 pyproject.toml
if [[ -f "${repo_path}/pyproject.toml" ]]; then
echo -e "发现 pyproject.toml开始自动安装依赖...\n"
local pyproject_file="${dir_scripts}/${uniq_path}/pyproject.toml"
cp -f "${repo_path}/pyproject.toml" "${pyproject_file}"
# 调用API添加依赖安装任务
local dep_name="${uniq_path}/pyproject.toml"
local currentTimeStamp=$(date +%s)
local result=$(curl -s --noproxy "*" "http://127.0.0.1:${ql_port}/open/dependencies?t=$currentTimeStamp" \
-X POST \
-H "Content-Type: application/json;charset=UTF-8" \
-H "Authorization: Bearer ${__ql_token__}" \
--data-raw "[{\"name\":\"${dep_name}\",\"type\":1,\"remark\":\"自动检测:${uniq_path} 订阅依赖\"}]" | jq -r '.code')
if [[ "$result" == "200" ]]; then
echo -e "已添加 pyproject.toml 依赖安装任务\n"
fi
fi
}
## 更新仓库
update_repo() {
local url="$1"
@ -137,6 +187,10 @@ update_repo() {
if [[ $exit_status -eq 0 ]]; then
echo -e "拉取 ${uniq_path} 成功...\n"
# 自动检测并安装Python依赖
auto_install_python_deps "${repo_path}" "${uniq_path}"
diff_scripts "$repo_path" "$author" "$path" "$blackword" "$dependence" "$extensions" "$autoAddCron" "$autoDelCron"
else
echo -e "拉取 ${uniq_path} 失败,请检查日志...\n"

View File

@ -22,6 +22,9 @@ const DependenceModal = ({
}) => {
const [form] = Form.useForm();
const [loading, setLoading] = useState(false);
const [selectedType, setSelectedType] = useState(
DependenceTypes[defaultType as any],
);
const handleOk = async (values: any) => {
setLoading(true);
@ -90,7 +93,7 @@ const DependenceModal = ({
label={intl.get('依赖类型')}
initialValue={DependenceTypes[defaultType as any]}
>
<Select>
<Select onChange={(value) => setSelectedType(value)}>
{config.dependenceTypes.map((x, i) => (
<Option key={i} value={i}>
{x}
@ -121,11 +124,24 @@ const DependenceModal = ({
whitespace: true,
},
]}
tooltip={
selectedType === DependenceTypes.python3
? intl.get(
'Python支持多种安装方式\n1. 包名requests\n2. GitHub链接git+https://github.com/user/repo.git\n3. requirements文件路径path/to/requirements.txt\n4. pyproject.toml文件路径',
)
: undefined
}
>
<Input.TextArea
rows={4}
autoSize={{ minRows: 1, maxRows: 5 }}
placeholder={intl.get('请输入依赖名称')}
placeholder={
selectedType === DependenceTypes.python3
? intl.get(
'支持包名、GitHub链接、requirements.txt或pyproject.toml路径',
)
: intl.get('请输入依赖名称')
}
/>
</Form.Item>
<Form.Item name="remark" label={intl.get('备注')}>