UNPKG

@oppo-minigame/cli

Version:

Command line interface for rapid OPPO minigame development

1 lines 15.4 kB
const path=require("path"),fs=require("fs-extra"),chalk=require("chalk"),shell=require("shelljs"),os=require("os"),ora=require("ora"),{spawn:spawn}=require("child_process"),qrcode=require("qrcode-terminal"),util=require("util"),LOG_FORMAT_SYMBOL="###",LOG_FORMAT="### %s ### %s",TPL_PATH=path.resolve(__dirname,"../tpl"),REQUIRE_MODULE_REG_PATTERN=e=>`(?:require\\((?:(?:'((?:./)?${e})')|(?:"((?:./)?${e})"))\\);?)`,RPK_REG=/^(?!.*[oO][pP][pP][oO])(?:(?:[a-zA-Z][0-9a-zA-Z_]*[0-9a-zA-Z])|(?:[a-zA-Z]))(?:\.(?:(?:[a-zA-Z][0-9a-zA-Z_]*[0-9a-zA-Z])|(?:[a-zA-Z])))*$/,FULL_RPK_REG=/^(?!.*[oO][pP][pP][oO])(?:(?:[a-zA-Z][0-9a-zA-Z_]*[0-9a-zA-Z])|(?:[a-zA-Z]))(?:\.(?:(?:[a-zA-Z][0-9a-zA-Z_]*[0-9a-zA-Z])|(?:[a-zA-Z])))*\.nearme\.gamecenter$/,POSITIVE_INT_REG=/^\+?[1-9]\d*$/,LINUX_PATH_REG=/^\/(?:[^/]+\/)*[^/]+$/,EMAIL_REG=/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,INQUIRE_QUESTION_KEY="inquirerKey",INQUIRE_CHOICE_YES={name:"是",value:"yes"},INQUIRE_CHOICE_NO={name:"否",value:"no"},SIGN_DIR="sign";function createRpkQrcode(e,t,n){if(!e)return;const r=getIPAddress();let s="./dist";if("laya"==n)s="./release/quickgame/dist";else if("egret"==n){const e=process.cwd().split("/");s=`../${e[e.length-1]}_quickgame/dist`}else"cocos"==n&&(s="./build/quickgame/dist");const i=spawn("npx",["http-server",`${s}`,"-p",9999,"-a",r],{shell:"win32"==process.platform});let c=!1;const o=debounce(()=>{if(!c){c=!0;const n=`http://${r}:9999/${t}?pkg=${e}`;qrcode.generate(n,{small:!0})}});i.stdout.on("data",e=>{console.log(chalk.green(`${e}`)),o()}),i.stderr.on("data",e=>{console.error(chalk.red(`${e}`))})}function debounce(e,t=10){let n=null;return function(){clearTimeout(n),n=setTimeout(()=>{e.apply(this,arguments)},t)}}function getIPAddress(){const e=os.networkInterfaces();for(const t in e){const n=e[t];for(const e of n)if("IPv4"===e.family&&"127.0.0.1"!==e.address&&!e.internal)return e.address}return null}function mkdirsSync(e){return!!fs.existsSync(e)||(mkdirsSync(path.dirname(e))?(fs.mkdirSync(e),!0):void 0)}async function traverseDir(e,t,n=null){const r=await fs.readdir(e);for(let s of r)if(s=path.resolve(path.join(e,s)),n&&n.indexOf(s)>-1);else{const e=await fs.stat(s);e&&e.isDirectory()?await traverseDir(s,t,n):t.push(s)}}function traverseDirSync(e,t,n=null){fs.readdirSync(e).forEach(function(r){if(r=path.resolve(path.join(e,r)),n&&n.indexOf(r)>-1);else{const e=fs.statSync(r);e&&e.isDirectory()?traverseDirSync(r,t,n):t.push(r)}})}function clearDirSync(e){let t=[];fs.existsSync(e)&&(t=fs.readdirSync(e),t.forEach(function(t,n){const r=e+"/"+t;fs.statSync(r).isDirectory()?clearDirSync(r):fs.unlinkSync(r)}),fs.rmdirSync(e))}const colorconsole={trace(...e){console.trace(...e)},log(...e){console.log(chalk.green(...e))},info(...e){console.info(chalk.green(...e))},warn(...e){console.warn(chalk.yellow.bold(...e))},error(...e){console.error(chalk.red.bold(...e))},throw(...e){throw new Error(chalk.red.bold(...e))}};function loadBabelModule(e){const t=path.resolve(__dirname,"..","node_modules",e),n=path.resolve(process.cwd(),"node_modules",e);return fs.existsSync(t)?t:fs.existsSync(n)?n:e}function createMainifestJson(e,t,n,r,s="portrait",i){let c={},o=!1;function a(){i&&(c.workers=i)}if(r&&r.packageName&&r.projectName||(console.log(chalk.red("lack suggestPackJson config")),shell.exit(1)),fs.existsSync(path.join(t,"manifest.json")))o=!0,c=fs.readJSONSync(path.join(t,"manifest.json")),a(),fs.writeFileSync(path.join(t,"manifest.json"),JSON.stringify(c)),t!=n&&copyFiles(path.join(t,"manifest.json"),n),RPK_REG.test(c.package)||(console.log(chalk.red("package incorrect in the file "+path.join(t,"manifest.json"))),shell.exit(1));else{c=fs.readJSONSync(path.join(e,"manifest.json"));let t=r.projectName,i=r.packageName;RPK_REG.test(i)||(i="com.quickgame.demo",t="QuickgameDemo"),c.package=i,c.name=t,c.orientation=s,a();let o=JSON.stringify(c);fs.writeFileSync(path.join(n,"manifest.json"),o)}return{option:c,manifestExist:o}}function getSuggestPackNameJson(e,t,n){if("cocos"===e){if(fs.existsSync(path.join(n,".cocos-project.json"))){let e=null;try{e=fs.readJSONSync(path.join(n,".cocos-project.json"))}catch(e){}if(e&&e.projectName&&e.packageName)return{projectName:e.projectName,packageName:e.packageName}}}else if("egret"===e){let e=null,t=path.join(n,"project.config.json");if(fs.existsSync(t)){try{e=fs.readJSONSync(t)}catch(e){}if(e&&e.projectname)return{projectName:e.projectname,packageName:e.projectname}}}else if("unity"===e){let e=null,r=path.join(n,"Build",path.basename(t)+".json");if(fs.existsSync(r)){try{e=fs.readJSONSync(r)}catch(e){}if(e&&e.productName)return{projectName:e.productName,packageName:"com."+e.companyName+"."+e.productName}}}let r=path.basename(t);return{projectName:r,packageName:"com."+r}}function copySignFile(e,t,n,r){let s=path.join(e,n.SIGN_DIR_NAME),i=path.resolve(t,"./sign");fs.existsSync(s)||console.log(chalk.yellow("### no sign files ### copy default to the project"));let c=r?n.SIGN_DEBUG_DIR:n.SIGN_RELEASE_DIR,o=path.join(s,c,n.PRIVATE_FILE_NAME),a=path.join(s,c,n.CERTIFICATE_FILE_NAME);return fs.existsSync(o)&&fs.existsSync(a)||(r?(console.log(chalk.yellow("### no sign files ### copy default to the project")),copyFiles(path.join(i,c),path.join(s,c))):(console.log(chalk.red(`### no release sign files ### please make sure that the sign files exist:privatekey:${o}, certificate:${a}`)),shell.exit(1))),{privatekey:o,certificate:a}}function getOrientation(e,t){let n="portrait";if("cocos"==t){let t=path.resolve(e,"./src/settings.js");if(fs.existsSync(t)){global.window={};try{require(t),n=window._CCSettings&&window._CCSettings.orientation?window._CCSettings.orientation:n}catch(e){console.log(chalk.yellow("加载Settings文件失败,无法获得orientation"))}}}else if("laya"==t||"egret"==t){let t=path.resolve(e,"./game.json");if(fs.existsSync(t))try{let e=require(t);n=e.deviceOrientation?e.deviceOrientation:n}catch(e){console.log(chalk.yellow("加载Settings文件失败,无法获得orientation"))}}return n}function mkBuildDirs(e,t,n,r,s,i,c){let o=path.resolve(e,"../",("egret"==s?getProjectName(t)+"_":"")+n.QUICKGAME_DIR),a=path.resolve(e,"../",n.QUICKGAME_DIR_TMP),l=path.join(o,n.DEST_DIR);fs.emptyDirSync(a);let p="commands"===path.basename(__dirname)?path.resolve(__dirname,"..",".."):path.resolve(__dirname,".."),f=path.join(p,"tpl"),u=path.join(p,s),y=getOrientation(e,s),h=createMainifestJson(f,o,a,getSuggestPackNameJson(s,t,e),y,c);if(r.DEFAULT_TPL_FILES&&r.DEFAULT_TPL_FILES.forEach(e=>{let t=path.join(o,e);fs.existsSync(t)?copyFiles(t,a):copyFiles(path.join(f,e),a)}),h.option.icon){let e=path.resolve(path.join(o,h.option.icon));fs.existsSync(e)?copyFiles(e,path.join(a,path.dirname(h.option.icon))):copyFiles(path.join(f,"logo.png"),a)}if(r.DEFAULT_TPL_FILES_JS&&r.DEFAULT_TPL_FILES_JS.forEach(e=>{let n=path.join(p,"tpl",s,e);if(fs.existsSync(n)&&(copyFiles(n,a),"main.js"===e))r.DEFAULT_MAIN_JS_CONTENT&&fs.appendFileSync(path.join(a,e),"\n"+r.DEFAULT_MAIN_JS_CONTENT(path.basename(t)).join("\n"))}),fs.existsSync(path.join(o,n.SIGN_DIR_NAME))){let e=path.join(a,n.SIGN_DIR_NAME);copyFiles(path.join(o,n.SIGN_DIR_NAME),e)}fs.emptyDirSync(o),copyFiles(a,o),fs.existsSync(u)&&r.DEFAULT_TPL_FILES_JS&&r.DEFAULT_TPL_FILES_JS.forEach(e=>{copyFiles(path.join(u,e),o)}),fs.ensureDirSync(l),console.log(chalk.green("[准备工作]build&dist 文件夹已删除, manifest配置文件已生成"));let d=copySignFile(o,p,n,i);return fs.removeSync(a),{signFiles:d,distDir:l,quickgameDir:o,manifestJson:h}}function getProjectName(e){return path.basename(e).replace("wxgame","")}function copyFiles(e,t,n=null,r=null,s=!1){if(fs.statSync(e).isDirectory()){const i=[];traverseDirSync(e,i,r=r||[]),i.forEach(r=>{const i=path.relative(e,r),c=path.resolve(path.join(t,i));fs.existsSync(c)?s?fs.copySync(r,c):console.log(chalk.white(`[信息]文件: ${c} 已存在`)):n&&n.length>0&&n.indexOf(path.extname(r))>-1||fs.copySync(r,c)})}else n&&n.length>0&&n.indexOf(path.extname(e))>-1||fs.copySync(e,path.resolve(path.join(t,path.basename(e))))}function prePackWorker(e,t){if(!e)return;fs.existsSync(e)||(console.log(chalk.red(`worker路径"${e}"不存在,请检查绝对路径是否正确并重试`)),shell.exit(1));const n=path.resolve(e);fs.statSync(e).isDirectory()&&n.toLowerCase()!==path.resolve(e,"../").toLowerCase()||(console.log(chalk.red(`worker路径"${e}"不是有效目录,请检查绝对路径是否正确并重试`)),shell.exit(1));let r="";const s=path.resolve(t);if(n.startsWith(s))return r=n.substring(s.length+1).replace("\\","/"),r;r=e.replace("/","\\").split("\\").pop();const i=path.join(t,r);if(fs.existsSync(i))try{fs.rmSync(i,{recursive:!0,force:!0})}catch(e){console.log(chalk.red("worker目录已存在,自动覆盖失败,请手动删除后重试")),shell.exit(1)}try{console.log(e),console.log(i),fs.copySync(e,i)}catch(e){console.log(chalk.red(e)),shell.exit(1)}return r}function getFormatLog(e,t){return util.format(LOG_FORMAT,void 0===e?"":e,void 0===t?"":t)}function formatLog(e,t,n){console.log(chalk[n](getFormatLog(e,t)))}function packLog(e,t){formatLog(e,t,"greenBright")}function packWarn(e,t){formatLog(e,t,"yellowBright")}function packError(e,t){formatLog(e,t,"redBright")}function packSpinner(e,t=""){function n(e){return`${e} ###`}const r=ora({text:`${n(e)} ${t}`,prefixText:"###"}).start(),s={succeed:function(e,t=""){return r.succeed(e?n(e)+" "+t:void 0)},fail:function(e,t=""){return r.prefixText=chalk.red("###"),r.fail(e?chalk.red(n(e)+" "+t):void 0)},warn:function(e,t=""){return r.warn(e?chalk.yellow(n(e)+" "+t):void 0)},info:function(e,t=""){return r.info(e?n(e)+" "+t:void 0)},setText:function(e,t=""){r.text=n(e)+" "+t}};return s}function clearDirRecursively(e,t){if(!fs.existsSync(e))return;const n=fs.readdirSync(e);for(const r of n){const n=path.join(e,r);t&&t.exclude&&t.exclude.test(n)||(fs.statSync(n).isDirectory()?(clearDirRecursively(n,t),fs.readdirSync(n).length||fs.rmdirSync(n)):fs.unlinkSync(n))}}function shouldExcludePath(e,t){if(e){if(e.excludeRegExp&&e.excludeRegExp instanceof RegExp&&e.excludeRegExp.test(t))return!0;if(e.excludes&&Array.isArray(e.excludes)&&e.excludes.includes(t))return!0}return!1}async function copyDirRecursivelyAsync(e,t,n=[]){const r=e;await async function e(t,n,s=[]){if(!await fs.exists(n))try{await fs.mkdir(n,{recursive:!0})}catch(e){throw e}const i=await fs.readdir(t,{withFileTypes:!0});for(const c of i){const i=path.join(t,c.name),o=path.join(n,c.name);s.includes(path.relative(r,i))||(c.isDirectory()?await e(i,o,s):await fs.copy(i,o))}}(e,t,n)}function copyDirRecursively(e,t,n){n&&(n.basePath=path.normalize(e)),copyDirRecursively_impl(e,t,n)}function copyDirRecursively_impl(e,t,n){if(!fs.existsSync(e))return;let r=!1;if(n&&(r=n.basePath===path.normalize(e),!r)){if(shouldExcludePath(n,path.relative(n.basePath,path.normalize(e))))return}if(fs.statSync(e).isDirectory()){fs.existsSync(t)||fs.mkdirSync(t);const s=fs.readdirSync(e);for(const i of s)r&&shouldExcludePath(n,i)||copyDirRecursively_impl(path.join(e,i),path.join(t,i),n)}else fs.copySync(e,t)}function parseJSONFile(e){return fs.existsSync(e)?JSON.parse(fs.readFileSync(e)):{}}function replaceString(e,t){if(!(e&&t&&t.map&&t.map.test(e)))return;const n=new RegExp(t.map,"g"),r=t.replaceFrom&&t.replaceTo,s=t.replaceCaptures&&t.replaceCaptures.length;if(r||s){let s,i;for(;null!==(s=n.exec(e));){if(r)i=s[0].replace(t.replaceFrom,t.replaceTo);else{i=s[0];for(let e=0;e<t.replaceCaptures.length;e++){const n=s[e+1];n&&(i=i.replace(n,t.replaceCaptures[e]))}}e=e.replace(s[0],i)}}else void 0!==t.to&&(e=e.replace(n,t.to));return e}function replaceFileContent(e,t){if(!fs.existsSync(e)||!t||!t.map)return;let n=fs.readFileSync(e,{encoding:"utf8"});const r=replaceString(n,t);r&&r!==n&&fs.writeFileSync(e,r)}function deleteDirectoryIfEmpty(e){fs.existsSync(e)&&0===fs.readdirSync(e).length&&fs.removeSync(e)}function shellExec(e,t="",n="",r=!1,s=!0){const i=shell.exec(e,{silent:r});return 0!==i.code&&((t||n)&&packError(t,n),s&&shellExit()),i}function shellExecSilentlyAsync(e){return new Promise((t,n)=>{shell.exec(e,{silent:!0},(e,r,s)=>{0!==e?n(s||r):t(r)})})}function shellOpenDirectory(e,t="",n="",r=!0,s=!1){let i="";return"win32"===process.platform?i="start":"darwin"===process.platform&&(i="open"),i?shellExec(`${i} ${e}`,t,n,r,s):null}function shellExit(){shell.exit(1)}function installRpkAsync(e){return new Promise(async(t,n)=>{const r={win32:{whereADBCommand:"where adb",internalADBDir:"window",adbSuffix:".exe"},darwin:{whereADBCommand:"which adb",internalADBDir:"mac",adbSuffix:""}},s=process.platform;if(!s in r)return void n(`当前操作系统 "${s}" 不支持自动安装 rpk`);const i=r[s];let c="adb";try{await shellExecSilentlyAsync(i.whereADBCommand)}catch(e){if(c=path.resolve(__dirname,`../node_modules/adb-driver/bin/${i.internalADBDir}/adb${i.adbSuffix}`),!await fs.exists(c))return void n(`当前操作系统 "${s}" 没有安装全局adb,也没有找到内置 adb,安装失败`)}const o=await async function(e="adb"){const t={success:!1,msg:""};let n="";try{n=await shellExecSilentlyAsync(`${e} devices`)}catch(e){return t.msg="查找设备出错,安装失败",t}const r=n.split("\n").map(e=>e.trim());if(!r[1])return t.msg="设备未连接或 USB 调试已关闭,安装失败",t;let s=1;do{if("device"===r[s].split("\t")[1])break;s++}while(r[s]);return r[s]?(t.success=!0,t.msg=r[s].split("\t")[0],t):(t.msg="设备未授权,请先允许进行调试,安装失败",t)}(c);if(o.success){try{await function(t="adb"){return shellExecSilentlyAsync(`"${t}" push "${e}" /sdcard/games/${path.basename(e)}`)}(c)}catch(e){return void n(`adb 安装命令执行异常,安装失败: ${e}`)}t(`已安装至设备 ${o.msg}`)}else n(o.msg)})}async function execInstallRpkProcess(e,t){const n="安装小游戏",r=packSpinner(n);try{const s=await installRpkAsync(e);await sleep(2e3),r.succeed(n,s),t&&t.success&&await t.success()}catch(e){await sleep(2e3),r.fail(n,e),t&&t.fail&&await t.fail(e)}}function sleep(e){return new Promise(t=>{setTimeout(t,e)})}module.exports={colorconsole:colorconsole,createRpkQrcode:createRpkQrcode,debounce:debounce,getIPAddress:getIPAddress,mkdirsSync:mkdirsSync,traverseDir:traverseDir,traverseDirSync:traverseDirSync,clearDirSync:clearDirSync,loadBabelModule:loadBabelModule,createMainifestJson:createMainifestJson,getSuggestPackNameJson:getSuggestPackNameJson,copySignFile:copySignFile,mkBuildDirs:mkBuildDirs,copyFiles:copyFiles,prePackWorker:prePackWorker,packLog:packLog,packWarn:packWarn,packError:packError,packSpinner:packSpinner,clearDirRecursively:clearDirRecursively,copyDirRecursively:copyDirRecursively,copyDirRecursivelyAsync:copyDirRecursivelyAsync,parseJSONFile:parseJSONFile,replaceString:replaceString,replaceFileContent:replaceFileContent,deleteDirectoryIfEmpty:deleteDirectoryIfEmpty,REQUIRE_MODULE_REG_PATTERN:REQUIRE_MODULE_REG_PATTERN,shellExec:shellExec,shellExecSilentlyAsync:shellExecSilentlyAsync,shellOpenDirectory:shellOpenDirectory,shellExit:shellExit,RPK_REG:RPK_REG,FULL_RPK_REG:FULL_RPK_REG,POSITIVE_INT_REG:POSITIVE_INT_REG,LINUX_PATH_REG:LINUX_PATH_REG,EMAIL_REG:EMAIL_REG,INQUIRE_QUESTION_KEY:"inquirerKey",INQUIRE_CHOICE_YES:INQUIRE_CHOICE_YES,INQUIRE_CHOICE_NO:INQUIRE_CHOICE_NO,TPL_PATH:TPL_PATH,execInstallRpkProcess:execInstallRpkProcess,installRpkAsync:installRpkAsync,sleep:sleep};