From f526d3f972ac5aa9b8bc67140e7283585f96405a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 27 Dec 2025 08:41:43 +0000 Subject: [PATCH] Add support for GitHub URLs and requirements files in Python dependencies Co-authored-by: whyour <22700758+whyour@users.noreply.github.com> --- back/config/util.ts | 43 ++++++++++++++++++++++++--- shell/update.sh | 54 ++++++++++++++++++++++++++++++++++ src/pages/dependence/modal.tsx | 20 +++++++++++-- 3 files changed, 111 insertions(+), 6 deletions(-) diff --git a/back/config/util.ts b/back/config/util.ts index 7d61f74f..21da14f4 100644 --- a/back/config/util.ts +++ b/back/config/util.ts @@ -536,11 +536,26 @@ export async function setSystemTimezone(timezone: string): Promise { } 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( diff --git a/shell/update.sh b/shell/update.sh index 613ebe69..ab40cf72 100755 --- a/shell/update.sh +++ b/shell/update.sh @@ -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" diff --git a/src/pages/dependence/modal.tsx b/src/pages/dependence/modal.tsx index 91891faf..6fbf0fc6 100644 --- a/src/pages/dependence/modal.tsx +++ b/src/pages/dependence/modal.tsx @@ -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]} > - setSelectedType(value)}> {config.dependenceTypes.map((x, i) => (