mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-10-14 21:20:48 +08:00
132 lines
3.7 KiB
JavaScript
132 lines
3.7 KiB
JavaScript
import { execFileSync, spawn } from 'node:child_process'
|
|
import { access } from 'node:fs/promises'
|
|
import { dirname, join, resolve } from 'node:path'
|
|
import { fileURLToPath } from 'node:url'
|
|
|
|
export const developmentServiceDirectoryEnvironment =
|
|
'CLASH_VERGE_DEV_SERVICE_DIR'
|
|
const repositoryRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..')
|
|
const serviceRepository = resolve(
|
|
repositoryRoot,
|
|
'..',
|
|
'clash-verge-service-ipc',
|
|
)
|
|
const serviceManifest = join(serviceRepository, 'Cargo.toml')
|
|
export const developmentServiceWatchPaths = [
|
|
'src',
|
|
'resources',
|
|
'Cargo.toml',
|
|
'Cargo.lock',
|
|
].map((name) => join(serviceRepository, name))
|
|
|
|
function run(command, args, options = {}) {
|
|
return new Promise((resolvePromise, reject) => {
|
|
const child = spawn(command, args, {
|
|
env: options.env ?? process.env,
|
|
stdio: options.stdio ?? 'inherit',
|
|
windowsHide: true,
|
|
})
|
|
let stdout = ''
|
|
child.stdout?.setEncoding('utf8')
|
|
child.stdout?.on('data', (chunk) => {
|
|
stdout += chunk
|
|
})
|
|
child.once('error', reject)
|
|
child.once('close', (code, signal) => {
|
|
if (code === 0) {
|
|
resolvePromise(stdout)
|
|
return
|
|
}
|
|
const error = new Error(
|
|
`${command} failed with ${signal ? `signal ${signal}` : `exit code ${code}`}`,
|
|
)
|
|
error.exitCode = code
|
|
reject(error)
|
|
})
|
|
})
|
|
}
|
|
|
|
export async function prepareDevelopmentService() {
|
|
await access(serviceManifest)
|
|
const output = await run(
|
|
'cargo',
|
|
[
|
|
'build',
|
|
'--manifest-path',
|
|
serviceManifest,
|
|
'--target-dir',
|
|
process.env.CARGO_TARGET_DIR ||
|
|
join(serviceRepository, 'target', 'development'),
|
|
'--features',
|
|
'standalone,client,development-channel',
|
|
'--bins',
|
|
'--message-format=json-render-diagnostics',
|
|
],
|
|
{ stdio: ['inherit', 'pipe', 'inherit'] },
|
|
)
|
|
|
|
const artifacts = new Map()
|
|
for (const line of output.split(/\r?\n/).filter(Boolean)) {
|
|
const artifact = JSON.parse(line)
|
|
if (
|
|
artifact.reason === 'compiler-artifact' &&
|
|
resolve(artifact.manifest_path) === serviceManifest &&
|
|
artifact.target.kind.includes('bin') &&
|
|
artifact.executable
|
|
) {
|
|
artifacts.set(artifact.target.name, resolve(artifact.executable))
|
|
}
|
|
}
|
|
const executables = [
|
|
'clash-verge-service',
|
|
'clash-verge-service-install',
|
|
'clash-verge-service-uninstall',
|
|
'service-integration-driver',
|
|
].map((name) => {
|
|
const executable = artifacts.get(name)
|
|
if (!executable)
|
|
throw new Error(`Cargo did not report the ${name} executable`)
|
|
return executable
|
|
})
|
|
const serviceDirectory = dirname(executables[0])
|
|
for (const executable of executables) {
|
|
if (dirname(executable) !== serviceDirectory) {
|
|
throw new Error(
|
|
'Development service tools were built in different directories',
|
|
)
|
|
}
|
|
await access(executable)
|
|
}
|
|
return serviceDirectory
|
|
}
|
|
|
|
export async function ensureDevelopmentService({
|
|
platform = process.platform,
|
|
} = {}) {
|
|
const serviceDirectory = await prepareDevelopmentService()
|
|
const extension = platform === 'win32' ? '.exe' : ''
|
|
const installer = join(
|
|
serviceDirectory,
|
|
`clash-verge-service-install${extension}`,
|
|
)
|
|
const host = execFileSync('rustc', ['-vV'], { encoding: 'utf8' }).match(
|
|
/^host: (.+)$/m,
|
|
)?.[1]
|
|
if (!host) throw new Error('rustc did not report its host target')
|
|
const args = ['--prepare-install', '--ensure']
|
|
for (const name of ['verge-mihomo', 'verge-mihomo-alpha']) {
|
|
args.push(
|
|
'--core',
|
|
`${name}${extension}`,
|
|
join(
|
|
repositoryRoot,
|
|
'src-tauri',
|
|
'sidecar',
|
|
`${name}-${host}${extension}`,
|
|
),
|
|
)
|
|
}
|
|
await run(installer, args)
|
|
return serviceDirectory
|
|
}
|