Files
FileHost/scripts/build-fpk.mjs
T
2026-10-18 16:17:01 +08:00

131 lines
4.2 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { createHash } from 'node:crypto'
import {
access,
chmod,
cp,
mkdir,
readFile,
readdir,
rename,
rm,
writeFile
} from 'node:fs/promises'
import { spawnSync } from 'node:child_process'
import path from 'node:path'
import { fileURLToPath } from 'node:url'
import sharp from 'sharp'
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..')
const pkg = JSON.parse(await readFile(path.join(root, 'package.json'), 'utf8'))
const outputRoot = path.join(root, 'dist-fpk')
const stage = path.join(outputRoot, 'staging')
const source = path.join(root, 'packaging', 'fnos')
const cache = path.join(outputRoot, 'cache')
const image = process.env.PICHOST_IMAGE
|| `yeomaiyelove/pichost:${pkg.version}`
const platform = process.env.FPK_PLATFORM || 'x86'
const fnpackVersion = '1.2.3'
function run(command, args, cwd = root) {
const result = spawnSync(command, args, {
cwd,
stdio: 'inherit',
windowsHide: true
})
if (result.error) throw result.error
if (result.status !== 0) {
throw new Error(`${command} ${args.join(' ')} 失败,退出代码 ${result.status}`)
}
}
async function exists(file) {
try {
await access(file)
return true
} catch {
return false
}
}
async function getFnpack() {
const systems = {
win32: 'windows',
linux: 'linux',
darwin: 'darwin'
}
const architectures = {
x64: 'amd64',
arm64: 'arm64'
}
const system = systems[process.platform]
const architecture = architectures[process.arch]
if (!system || !architecture) {
throw new Error(`不支持自动下载 fnpack:${process.platform}/${process.arch}`)
}
const executable = path.join(
cache,
`fnpack-${fnpackVersion}-${system}-${architecture}${process.platform === 'win32' ? '.exe' : ''}`
)
if (!await exists(executable)) {
await mkdir(cache, { recursive: true })
const url = `https://static2.fnnas.com/fnpack/fnpack-${fnpackVersion}-${system}-${architecture}`
console.log(`下载 fnpack:${url}`)
const response = await fetch(url)
if (!response.ok) throw new Error(`fnpack 下载失败:${response.status}`)
await writeFile(executable, Buffer.from(await response.arrayBuffer()))
if (process.platform !== 'win32') await chmod(executable, 0o755)
}
return executable
}
async function replace(file, replacer) {
const original = await readFile(file, 'utf8')
await writeFile(file, replacer(original))
}
await rm(stage, { recursive: true, force: true })
await cp(source, stage, { recursive: true })
const cmdDir = path.join(stage, 'cmd')
for (const file of await readdir(cmdDir)) {
await chmod(path.join(cmdDir, file), 0o755)
}
await chmod(path.join(stage, 'app', 'docker', 'start.sh'), 0o755)
await replace(path.join(stage, 'manifest'), text => text
.replace(/^version\s*=.*$/m, `version = ${pkg.version}`)
.replace(/^platform\s*=.*$/m, `platform = ${platform}`))
await replace(path.join(stage, 'app', 'docker', 'docker-compose.yaml'), text => text
.replace(/image:\s*\S+/, `image: ${image}`))
await replace(path.join(stage, 'wizard', 'install'), text => text
.replaceAll(/yeomaiyelove\/pichost:[0-9]+\.[0-9]+\.[0-9]+/g, image))
const logo = path.join(root, 'app', 'assets', 'image', 'logo-light.png')
const resize = size => sharp(logo)
.resize(size, size, {
fit: 'contain',
background: { r: 0, g: 0, b: 0, alpha: 0 }
})
.png()
await mkdir(path.join(stage, 'app', 'ui', 'images'), { recursive: true })
await resize(64).toFile(path.join(stage, 'ICON.PNG'))
await resize(256).toFile(path.join(stage, 'ICON_256.PNG'))
await resize(64).toFile(path.join(stage, 'app', 'ui', 'images', 'icon_64.png'))
await resize(256).toFile(path.join(stage, 'app', 'ui', 'images', 'icon_256.png'))
const fnpack = await getFnpack()
run(fnpack, ['build', '--directory', stage], outputRoot)
const output = path.join(outputRoot, `pichost-${pkg.version}.fpk`)
await rm(output, { force: true })
await rename(path.join(outputRoot, 'pichost.fpk'), output)
const hash = createHash('sha256')
hash.update(await readFile(output))
const digest = hash.digest('hex')
await writeFile(`${output}.sha256`, `${digest} ${path.basename(output)}\n`)
console.log(`FPK:${output}`)
console.log(`SHA256:${digest}`)