UNPKG

@honor-minigame/cli

Version:

honor minigame pack cli

197 lines (176 loc) 7.5 kB
import path from 'path' import fs from 'fs-extra' import { fileURLToPath } from 'url' import { info } from '../../utils/logger.js' import * as paths from '../lib/paths.js' import { MAIN, RPK, RPK_SIGNED, LOG_TITLE } from '../lib/constanst.js' import readdir, { noDotSymbolsFiles, noDotFiles } from '../lib/readdir.js' import rpk from '../lib/rpk.js' import forge from 'node-forge' const __filename = fileURLToPath(import.meta.url) const __dirname = path.dirname(__filename) // 生成签名文件 async function generateReleaseSign(signFile, packageName) { const cachePath = path.join(__dirname, '../../../node_modules', packageName) // 判断本地是否有缓存 try { const privateFile = path.join(cachePath, 'private.pem') const certificateFile = path.join(cachePath, 'certificate.pem') if (fs.existsSync(privateFile) && fs.existsSync(certificateFile)) { info(`\n####检测到${cachePath}路径下有release签名缓存####`) // 自动使用缓存 fs.copySync(privateFile, signFile.privatekey) fs.copySync(certificateFile, signFile.certificate) return } } catch (err) { console.error(err) } // 使用rl.question()方法从命令行读取证书请求参数 info('\n本地检测到未包含release签名,正在生成release签名信息...') const organizationName = packageName // 使用包名作为名称 const commonName = packageName const countryName = 'CN' const stateName = 'ZJ' const localityName = 'HZ' // 生成RSA密钥对 const keys = forge.pki.rsa.generateKeyPair(2048) // 创建证书 const cert = forge.pki.createCertificate() cert.publicKey = keys.publicKey cert.serialNumber = '01' cert.validity.notBefore = new Date() cert.validity.notAfter = new Date() cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 10) const certObj = [ { name: 'commonName', value: commonName }, { name: 'countryName', value: countryName }, { shortName: 'ST', value: stateName }, { name: 'localityName', value: localityName }, { name: 'organizationName', value: organizationName }, { shortName: 'OU', value: 'MINIGAME' } ] cert.setSubject(certObj) info('release签名参数为:') console.log(certObj) cert.setIssuer(cert.subject.attributes) cert.setExtensions([ { name: 'basicConstraints', cA: true }, { name: 'keyUsage', digitalSignature: true, keyCertSign: true, cRLSign: true } ]) cert.sign(keys.privateKey) // 将密钥和证书保存到文件中 const pemPrivateKey = forge.pki.privateKeyToPem(keys.privateKey) const pemCertificate = forge.pki.certificateToPem(cert) // 如果release路径不存在 const dirPath = path.dirname(signFile.privatekey) if (!fs.existsSync(dirPath)) { fs.mkdirSync(dirPath, { recursive: true }) } info(`####签名生成成功####,写入签名privatekey:${signFile.privatekey}`) fs.outputFileSync(signFile.privatekey, pemPrivateKey) info(`写入签名certificate:${signFile.certificate}\n`) fs.outputFileSync(signFile.certificate, pemCertificate) // 缓存release签名到本地 try { if (!fs.existsSync(cachePath)) { fs.mkdirSync(cachePath, { recursive: true }) fs.outputFileSync(path.join(cachePath, 'private.pem'), pemPrivateKey) fs.outputFileSync(path.join(cachePath, 'certificate.pem'), pemCertificate) info(`####release签名需要保存好!!!#### 该文件已缓存到:${cachePath},若忘记签名,可在此路径下查找。`) } } catch (err) { console.error(err) } } export default async function zipPack(isRelease, packageName, singlePackage, subpackages, manifest, buildType, compileStartTime) { // 签名文件 const signFiles = { debug: { privatekey: paths.DEBUG_PRIVATE_KEY, certificate: paths.DEBUG_CERTIFICATE }, release: { privatekey: paths.RELEASE_PRIVATE_KEY, certificate: paths.RELEASE_CERTIFICATE } } // 编译完成开始打包,打包前先校验签名文件是否存在 const signFile = signFiles[isRelease ? 'release' : 'debug'] // debug包的后缀 .rpk release包的后缀 .signed.rpk // buildType 默认值为release let RPK_SIGNED_NEW = RPK_SIGNED let RPK_NEW = RPK if (buildType && !buildType.includes('release')) { RPK_SIGNED_NEW = `.${buildType}${RPK_SIGNED}` RPK_NEW = `.${buildType}${RPK}` } const ext = isRelease ? RPK_SIGNED_NEW : RPK_NEW /** * 如果本地不存在release签名文件,则自动帮助cp生成release签名文件 */ if (isRelease) { if (!fs.existsSync(signFile.privatekey) || !fs.existsSync(signFile.certificate)) { await generateReleaseSign(signFile, packageName) } } if (!fs.existsSync(signFile.privatekey)) { throw (new Error(`${LOG_TITLE}缺少私钥文件, 打包失败: ${signFile.privatekey}`)) } if (!fs.existsSync(signFile.certificate)) { throw (new Error(`${LOG_TITLE}缺少证书文件, 打包失败: ${signFile.certificate}`)) } return new Promise(resolve => { info(`${LOG_TITLE}${singlePackage ? '原整包编译完成,开始生成原整包' : '分包编译完成,开始生成分包'} 耗时:${(new Date()).valueOf() - compileStartTime}ms`) // 遍历出build目录所有文件 const files = readdir(paths.BUILD, isRelease ? noDotSymbolsFiles : noDotFiles) // 如果是打原整包 if (singlePackage) { // 打原整包到temp目录 有插件包的也走这个逻辑,因为需要打个兼容的包 rpk(`${packageName}${RPK}`, files, paths.BUILD, paths.TEMP, signFile, manifest).then(resolve) } else { // 如果存在分包,那么就打出各个分包,并和原整包一起再打一个rpk,到dist目录 const pkgRes = [] // 根据分包配置,找到各个包对应的资源。执行如下操作后,files中剩下的即为主包的资源 subpackages.forEach(({ name, root }) => { const matchFiles = [] for (let index = files.length - 1; index >= 0; index--) { const file = files[index] const ext = path.extname(root) if (isRelease && !noDotSymbolsFiles(file, 0, path.basename(file))) { continue } if (ext === '' && file.indexOf(root) === 0) { // 如果是目录,校验路径 matchFiles.push(files.splice(index, 1)[0]) } else if (ext !== '' && (file === root || file === `${root}.map`)) { // 如果是文件,校验是否为 xxx.js 和 xxx.js.map matchFiles.push(files.splice(index, 1)[0]) } } pkgRes.push({ name, matchFiles }) }) // 打各个分包 const rpkPromise = pkgRes.map(({ name, matchFiles }) => { return rpk(`${name}${RPK}`, matchFiles, paths.BUILD, paths.TEMP, signFile) }) const promiseArr = [rpk(`${MAIN}${RPK}`, files, paths.BUILD, paths.TEMP, signFile, manifest)] // 分包都打好后,连原整包一起打一个整包 Promise.all([...rpkPromise, ...promiseArr]).then(function () { rpk(`${packageName}${ext}`, readdir(paths.TEMP), paths.TEMP, paths.DIST, signFile).then(() => { resolve() }) }) } }) }