@oppo-minigame/cli
Version:
Command line interface for rapid OPPO minigame development
1 lines • 6.2 kB
JavaScript
const fs=require("fs-extra"),JSZip=require("jszip"),jszip=require("jszip"),path=require("path"),{SIGN_DIR_NAME:SIGN_DIR_NAME,SIGN_RELEASE_DIR:SIGN_RELEASE_DIR,PRIVATE_FILE_NAME:PRIVATE_FILE_NAME,CERTIFICATE_FILE_NAME:CERTIFICATE_FILE_NAME,MANIFEST_FILE_NAME:MANIFEST_FILE_NAME,SIGN_DEBUG_DIR:SIGN_DEBUG_DIR,EXCLUDES:EXCLUDES,DEST_DIR:DEST_DIR,DS_STORE_FILE_NAME:DS_STORE_FILE_NAME,MAIN_PACK_NAME:MAIN_PACK_NAME,VSCODE_DIR:VSCODE_DIR}=require("../../config/config"),signer=require("../../sign/bundle"),{shellExit:shellExit,packError:packError,packSpinner:packSpinner,TPL_PATH:TPL_PATH,traverseDir:traverseDir,execInstallRpkProcess:execInstallRpkProcess}=require("../../utils"),DEFAULT_ENTRY_FILE="game.js",RPK_COMPRESS_OPTION={type:"nodebuffer",compression:"DEFLATE",compressionOptions:{level:9}},RPK_DIR="dist",RPK_FILE_EXT=".rpk",MAIN_RPK_FILE=MAIN_PACK_NAME+".rpk",RPK_FILE_SIGNED_FLAG=".signed",LOG_ERROR_TAG_PROJECT="工程错误",LOG_ERROR_TAG_SIGN="签名错误",UNITY_SYMBOL_FILE_NAME="webgl.wasm.symbols.unityweb",PLUGIN_CACHE_DIR_NAME=".plugincache";let _cwd=process.cwd(),distRpkName="",distRpkPath="",_isDebugEnv=!1,_manifestObj=null,_privatekeyBuffer=null,_certificateBuffer=null,subpackageFullPaths=[],mainPackageFullPaths=[],_totalZipper=null;async function start(a){_isDebugEnv=a.isDebugEnv,_cwd=a.pub_dir||_cwd,_manifestObj=await fs.readJson(path.join(_cwd,MANIFEST_FILE_NAME)),distRpkName=`${_manifestObj.package}${_isDebugEnv?"":".signed"}.rpk`;const e=path.join(_cwd,DEST_DIR);return distRpkPath=path.join(e,distRpkName),await checkProjectStructure(),await checkSubpackagesConfig(a),await fs.emptyDir(e),await loadPrivateKeyCertificate(a),a.subpack?await subpackProcess(a):await packProcess(a),a.autoInstall&&await execInstallRpkProcess(distRpkPath,{fail:a.fail}),distRpkPath}async function checkProjectStructure(){_manifestObj||(packError("工程错误",`工程缺少配置文件 [${MANIFEST_FILE_NAME}]`),shellExit()),await fs.exists(path.join(_cwd,"game.js"))||(packError("工程错误","工程缺少入口文件 [game.js]"),shellExit())}async function checkSubpackagesConfig(a){if(!_manifestObj.subpackages)return;const e="检查分包配置",i=packSpinner(e);async function t(t){i.fail(e,t),a.fail&&await a.fail(t),shellExit()}for(let a=0;a<_manifestObj.subpackages.length;a++){const e=_manifestObj.subpackages[a];e.name||await t(`subpackages[${a}] 缺少 "name" 字段`),"string"!=typeof e.name&&await t(`subpackages[${a}] "name" 字段必须为字符串`),e.root||await t(`subpackages[${a}] 缺少 "root" 字段`),"string"!=typeof e.root&&await t(`subpackages[${a}] "root" 字段必须为字符串`);const i=path.basename(e.root),s=!path.extname(i),r=path.join(_cwd,e.root);s?(await fs.exists(r)||await t(`分包 [${e.name}] 指定的 "root" 目录不存在`),(await fs.readdir(r)).length||await t(`分包 [${e.name}] 指定的 "root" 目录为空`),await fs.exists(path.join(r,"game.js"))||await t(`分包 [${e.name}] 指定的 "root" 目录中不存在入口文件 "game.js"`)):(i.endsWith(".js")||await t(`分包 [${e.name}] "root" 文件类型只支持 ".js"`),await fs.exists(r)||await t(`分包 [${e.name}] 指定的 "root" 文件 "${e.root}" 不存在`))}i.succeed()}async function loadPrivateKeyCertificate(a){const e=packSpinner("加载证书和私钥");if(_isDebugEnv?(_privatekeyBuffer=await fs.readFile(path.resolve(TPL_PATH,`../${SIGN_DIR_NAME}/${SIGN_DEBUG_DIR}/${PRIVATE_FILE_NAME}`)),_certificateBuffer=await fs.readFile(path.resolve(TPL_PATH,`../${SIGN_DIR_NAME}/${SIGN_DEBUG_DIR}/${CERTIFICATE_FILE_NAME}`))):(_privatekeyBuffer=await fs.readFile(path.join(_cwd,SIGN_DIR_NAME,SIGN_RELEASE_DIR,PRIVATE_FILE_NAME)),_certificateBuffer=await fs.readFile(path.join(_cwd,SIGN_DIR_NAME,SIGN_RELEASE_DIR,CERTIFICATE_FILE_NAME))),!_privatekeyBuffer||!_certificateBuffer){const i="证书或私钥文件不存在";e.fail("签名错误",i),a.fail&&await a.fail(i),shellExit()}e.succeed()}async function zipSign(a){const e=packSpinner(a.title),i=[];for(let t of a.datas){const s="string"==typeof t,r=s?path.relative(_cwd,t).replaceBackslash():t.name;e.setText(a.title+": 归档",r);const n=s?await fs.readFile(t):t.buffer;a.zipper.file(r,n),i.push({name:Buffer.from(r),hash:signer.hashFileBuffer(n)})}const t=await a.zipper.generateAsync(RPK_COMPRESS_OPTION,i=>{i.currentFile&&e.setText(a.title+": 压缩",i.currentFile)}),s=signer.signZipBuffer({buffer:t,files:i},_privatekeyBuffer,_certificateBuffer);if(s.errMsg){const i=`${a.errMsgPrefix}${s.errMsg}`;e.fail("签名错误",i),a.fail&&await a.fail(i),shellExit()}return e.succeed(a.title+": 完成"),s.signedBuffer}async function packProcess(a){const e=await buildMainRPK(a),i=packSpinner("生成整包",distRpkName);await fs.writeFile(distRpkPath,e),i.succeed()}async function subpackProcess(a){_totalZipper=new jszip;const e=await buildSubpackagesRPK(a),i=await buildMainRPK(a),t=await buildWholeRPK(a),s=await zipSign({zipper:new jszip,datas:[{name:distRpkName,buffer:t},{name:MAIN_RPK_FILE,buffer:i},...e],errMsgPrefix:"总包",title:"构建总包",fail:a.fail});await fs.writeFile(distRpkPath,s)}async function buildMainRPK(a){const e=[];await traverseDir(_cwd,e,[path.join(_cwd,UNITY_SYMBOL_FILE_NAME),path.join(_cwd,".plugincache"),path.join(_cwd,DEST_DIR),path.join(_cwd,SIGN_DIR_NAME),path.join(_cwd,VSCODE_DIR)]),mainPackageFullPaths=e.filter(a=>(a=a.replaceBackslash(),!subpackageFullPaths.includes(a)&&path.basename(a)!==DS_STORE_FILE_NAME));return await zipSign({zipper:new jszip,datas:mainPackageFullPaths,errMsgPrefix:"主包",title:"构建主包",fail:a.fail})}async function buildSubpackagesRPK(a){const e=[];for(const i of _manifestObj.subpackages){const t=[],s=path.join(_cwd,i.root);path.extname(path.basename(i.root))?t.push(s):await traverseDir(s,t),subpackageFullPaths.push(...t.map(a=>a.replaceBackslash()));const r=await zipSign({zipper:new jszip,datas:t,errMsgPrefix:`分包 [${i.name}] `,title:`构建分包 [${i.name}]`,fail:a.fail});e.push({name:i.name+".rpk",buffer:r})}return e}async function buildWholeRPK(a){return await zipSign({zipper:new jszip,datas:[...mainPackageFullPaths,...subpackageFullPaths],errMsgPrefix:"整包",title:"构建整包",fail:a.fail})}module.exports={start:start};