统一 Alpine/Debian 分支,QL_SCHEDULER 参数化调度

* 修改获取示例文件 api path

* 增加 debian-slim 基础镜像

* 修复 debian apt 命令,支持 qinglong 命令

* 更新 npm 版本 0.7.7

* 更新 npm v0.8.4

* 修复linux依赖检测 (#2082)

* 修复拉取私有仓库

* 修复 shell check_server

* 修复 qinglong 命令

* 更新 npm 版本 v0.13.2

* 增加 debian 开发版本

* 修改切换 linux 镜像源

* 修复 qinglong 命令

* 移除 qinglong 命令 npm 默认镜像源

* 修复 workflow

* 更新 npm 版本 v0.14.5

* 增加 npx 命令

* 更新 workflow action 版本

* 更新 npm 版本 v0.16.0

* 修复 linux 镜像源

* 更新 npm 版本 v0.17.0

* 更新 npm 版本 v0.18.0

* 修改 npm 安装启动命令

* 更新 npm 版本 v0.19.9

* 修复 debian netcat 包名

* 更新 npm 版本 v0.20.4

* 安装 linux 依赖自动识别 alpine 和 debian

* 修改 apt 命令

* 更新 npm 版本 v0.21.2

* 修改 ts 文件执行依赖

* npm 启动增加 reload 逻辑

* 更新 npm 版本 v2.17.8

* 修复 qinglong 命令

* 更新 npm 版本 v2.17.9

* 更新 npm 版本 v2.17.10

* 更新 npm 版本 v2.17.11

* 修改 debian 版本为 12 bookworm

* 更新 npm 版本 v2.17.12

* 修改本地服务启动提示

* 更新 npm 版本 v2.17.13

* 写入文件增加文件锁

* 修复系统安装依赖提示

* 更新 npm 版本 v2.18.2-6

* 更新 nodejs 版本

* 更新 npm 版本 v2.18.3-3

* 修复 command 变量

* 移除自动清除 deb

* 修复 npm 启动脚本

* 修复发布 npm包依赖文件

* 修改 linux 启动文件逻辑

* 更新 npm 版本 v2.19.0-10

* 修复 apt 命令

* 更新 npm 版本 v2.19.1-0

* 更新 npm 版本 v2.19.2-2

* 增加 packageManager

* 增加用户 qinglong

* 更新 pipeline

* 移除 init_nginx

* 更新 npm 版本 v2.20.0

* 更新 npm 版本 2.20.1

* 更新 npm 版本 2.20.2

* fix: 修复非 root 用户启动

* chore: 合并 debian 和 alpine 逻辑

---------

Co-authored-by: dream10201 <xiuxiu10201@gmail.com>
This commit is contained in:
whyour
2026-05-30 18:03:51 +08:00
committed by GitHub
parent 57d58c871e
commit 84d730d510
19 changed files with 1018 additions and 113 deletions
+35
View File
@@ -49,3 +49,38 @@ export const NotificationModeStringMap = {
19: 'ntfy',
20: 'wxPusherBot',
} as const;
export const LINUX_DEPENDENCE_COMMAND: Record<
'Debian' | 'Ubuntu' | 'Alpine',
{
install: string;
uninstall: string;
info: string;
check(info: string): boolean;
}
> = {
Debian: {
install: 'apt-get install -y',
uninstall: 'apt-get remove -y',
info: 'dpkg-query -s',
check(info: string) {
return info.includes('install ok installed');
},
},
Ubuntu: {
install: 'apt-get install -y',
uninstall: 'apt-get remove -y',
info: 'dpkg-query -s',
check(info: string) {
return info.includes('install ok installed');
},
},
Alpine: {
install: 'apk add --no-check-certificate',
uninstall: 'apk del',
info: 'apk info -es',
check(info: string) {
return info.includes('installed');
},
},
};
+196 -4
View File
@@ -1,6 +1,6 @@
import * as fs from 'fs/promises';
import * as path from 'path';
import { exec } from 'child_process';
import { exec, execSync } from 'child_process';
import psTreeFun from 'ps-tree';
import { promisify } from 'util';
import { load } from 'js-yaml';
@@ -10,9 +10,38 @@ import Logger from '../loaders/logger';
import { writeFileWithLock } from '../shared/utils';
import { DependenceTypes } from '../data/dependence';
import { FormData } from 'undici';
import os from 'os';
export * from './share';
let osType: 'Debian' | 'Ubuntu' | 'Alpine' | undefined;
function getOsTypeSync(): 'Debian' | 'Ubuntu' | 'Alpine' | undefined {
// 1. 环境变量覆盖
const envOs = process.env.QL_OS_TYPE?.toLowerCase();
if (envOs === 'alpine') return 'Alpine';
if (envOs === 'debian') return 'Debian';
if (envOs === 'ubuntu') return 'Ubuntu';
// 2. 模块缓存(由 detectOS 设置)
if (osType) return osType;
// 3. 能力检测:检查包管理器二进制
try {
execSync('which apt-get', { stdio: 'ignore' });
return 'Debian';
} catch {
try {
execSync('which apk', { stdio: 'ignore' });
return 'Alpine';
} catch {
// macOS / 未知系统
}
}
return undefined;
}
export async function getFileContentByName(fileName: string) {
const _exsit = await fileExist(fileName);
if (_exsit) {
@@ -550,7 +579,9 @@ except:
spec=u.find_spec(name)
print(name if spec else '')
''')"`,
[DependenceTypes.linux]: `apk info -es ${name}`,
[DependenceTypes.linux]: getOsTypeSync() === 'Alpine'
? `apk info -es ${name}`
: `dpkg-query -s ${name}`,
};
return baseCommands[type];
@@ -561,7 +592,9 @@ export function getInstallCommand(type: DependenceTypes, name: string): string {
[DependenceTypes.nodejs]: 'pnpm add -g',
[DependenceTypes.python3]:
'pip3 install --disable-pip-version-check --root-user-action=ignore',
[DependenceTypes.linux]: 'apk add --no-check-certificate',
[DependenceTypes.linux]: getOsTypeSync() === 'Alpine'
? 'apk add --no-check-certificate'
: 'apt-get install -y',
};
let command = baseCommands[type];
@@ -581,7 +614,9 @@ export function getUninstallCommand(
[DependenceTypes.nodejs]: 'pnpm remove -g',
[DependenceTypes.python3]:
'pip3 uninstall --disable-pip-version-check --root-user-action=ignore -y',
[DependenceTypes.linux]: 'apk del',
[DependenceTypes.linux]: getOsTypeSync() === 'Alpine'
? 'apk del'
: 'apt-get remove -y',
};
return `${baseCommands[type]} ${name.trim()}`;
@@ -590,3 +625,160 @@ export function getUninstallCommand(
export function isDemoEnv() {
return process.env.DeployEnv === 'demo';
}
async function getOSReleaseInfo(): Promise<string> {
const osRelease = await fs.readFile('/etc/os-release', 'utf8');
return osRelease;
}
function isDebian(osReleaseInfo: string): boolean {
return osReleaseInfo.includes('Debian');
}
function isUbuntu(osReleaseInfo: string): boolean {
return osReleaseInfo.includes('Ubuntu');
}
function isCentOS(osReleaseInfo: string): boolean {
return osReleaseInfo.includes('CentOS') || osReleaseInfo.includes('Red Hat');
}
function isAlpine(osReleaseInfo: string): boolean {
return osReleaseInfo.includes('Alpine');
}
export async function detectOS(): Promise<
'Debian' | 'Ubuntu' | 'Alpine' | undefined
> {
if (osType) return osType;
const envOs = process.env.QL_OS_TYPE?.toLowerCase();
if (envOs === 'alpine') {
osType = 'Alpine';
return osType;
}
if (envOs === 'debian') {
osType = 'Debian';
return osType;
}
if (envOs === 'ubuntu') {
osType = 'Ubuntu';
return osType;
}
const platform = os.platform();
if (platform === 'linux') {
const osReleaseInfo = await getOSReleaseInfo();
if (isDebian(osReleaseInfo)) {
osType = 'Debian';
} else if (isUbuntu(osReleaseInfo)) {
osType = 'Ubuntu';
} else if (isAlpine(osReleaseInfo)) {
osType = 'Alpine';
} else {
Logger.error(`Unknown Linux Distribution: ${osReleaseInfo}`);
console.error(`Unknown Linux Distribution: ${osReleaseInfo}`);
}
} else if (platform === 'darwin') {
osType = undefined;
} else {
Logger.error(`Unsupported platform: ${platform}`);
console.error(`Unsupported platform: ${platform}`);
}
return osType;
}
async function getCurrentMirrorDomain(
filePath: string,
): Promise<string | null> {
const fileContent = await fs.readFile(filePath, 'utf8');
const lines = fileContent.split('\n');
for (const line of lines) {
if (line.trim().startsWith('#')) {
continue;
}
const match = line.match(/https?:\/\/[^\/]+/);
if (match) {
return match[0];
}
}
return null;
}
async function replaceDomainInFile(
filePath: string,
oldDomainWithScheme: string,
newDomainWithScheme: string,
): Promise<void> {
let fileContent = await fs.readFile(filePath, 'utf8');
let updatedContent = fileContent.replace(
new RegExp(oldDomainWithScheme, 'g'),
newDomainWithScheme,
);
if (!newDomainWithScheme.endsWith('/')) {
newDomainWithScheme += '/';
}
await writeFileWithLock(filePath, updatedContent);
}
async function _updateLinuxMirror(
osType: string,
mirrorDomainWithScheme: string,
): Promise<string> {
let filePath: string, currentDomainWithScheme: string | null;
switch (osType) {
case 'Debian':
filePath = '/etc/apt/sources.list.d/debian.sources';
currentDomainWithScheme = await getCurrentMirrorDomain(filePath);
if (currentDomainWithScheme) {
await replaceDomainInFile(
filePath,
currentDomainWithScheme,
mirrorDomainWithScheme || 'http://deb.debian.org',
);
return 'apt-get update';
} else {
throw Error(`Current mirror domain not found.`);
}
case 'Ubuntu':
filePath = '/etc/apt/sources.list.d/ubuntu.sources';
currentDomainWithScheme = await getCurrentMirrorDomain(filePath);
if (currentDomainWithScheme) {
await replaceDomainInFile(
filePath,
currentDomainWithScheme,
mirrorDomainWithScheme || 'http://archive.ubuntu.com',
);
return 'apt-get update';
} else {
throw Error(`Current mirror domain not found.`);
}
case 'Alpine':
filePath = '/etc/apk/repositories';
currentDomainWithScheme = await getCurrentMirrorDomain(filePath);
if (currentDomainWithScheme) {
await replaceDomainInFile(
filePath,
currentDomainWithScheme,
mirrorDomainWithScheme || 'http://dl-cdn.alpinelinux.org',
);
return 'apk update';
} else {
throw Error(`Current mirror domain not found.`);
}
default:
throw Error('Unsupported OS type for updating mirrors.');
}
}
export async function updateLinuxMirrorFile(mirror: string): Promise<string> {
const detectedOS = await detectOS();
if (!detectedOS) {
throw Error(`Unknown Linux Distribution`);
}
return await _updateLinuxMirror(detectedOS, mirror);
}