UNPKG

gchcg-cli

Version:
1 lines 8.61 kB
"use strict";const fs=require("fs"),path=require("path"),inquirer=require("inquirer").default,fse=require("fs-extra"),pathExists=require("path-exists").sync,glob=require("glob"),ejs=require("ejs"),semver=require("semver"),userHome=require("user-home"),Command=require("./command"),Package=require("./package"),log=require("./log"),Git=require("./git"),{spinnerStart:spinnerStart,sleep:sleep,execAsync:execAsync}=require("./utils"),getProjectTemplate=require("./getProjectTemplate"),TYPE_COMPONENT="component",WHITE_COMMAND=["npm","cnpm"],COMPONENT_FILE=".componentrc",TEMPLATE_ID=563;class InitCommand extends Command{init(){this.projectName=this._argv[0]||"",this.force=!!this._cmd.force,this.ssh=!!this._cmd.ssh,this.refreshToken=!!this._cmd.refreshToken,this.templateId="",this.type="feat"}async exec(){const e=(new Date).getTime();try{const e=await this.prepare();e&&(this.projectInfo=e,await this.downloadTemplate(),await this.installTemplate())}catch(e){log.error(e.message)}log.verbose("本次执行指令耗时:"+((new Date).getTime()-e)/1e3+"秒")}async initGit(){const e=path.resolve(process.cwd(),this.projectInfo.projectName),t=this.projectInfo.className,s=this.projectInfo.version,r=this.ssh?this.projectInfo.ssh_url_to_repo:this.projectInfo.http_url_to_repo,i=new Git({name:t,version:s,dir:e,type:this.type,pid:this.projectInfo.namespace.id,ssh:this.ssh,repoUrl:r.split("/").slice(0,-1).join("/")+"/"+this.projectInfo.className+".git"});await i.prepare(),log.success("git初始化成功")}async installTemplate(){if(!this.templateInfo)throw new Error("项目信息不存在!");await this.installNormalTemplate()}checkCommand(e){return WHITE_COMMAND.includes(e)?e:null}async execCommand(e,t){let s;if(e){const t=e.split(" "),r=this.checkCommand(t[0]);if(!r)throw new Error("命令不存在!命令:"+e);const i=t.slice(1);s=await execAsync(r,i,{stdio:"inherit",cwd:path.resolve(process.cwd(),this.projectInfo.projectName)})}if(0!==s)throw new Error(t);return s}async ejsRender(e){const t=process.cwd(),s=this.projectInfo;return new Promise(((r,i)=>{glob(`${s.name}/**`,{cwd:t,ignore:e.ignore,nodir:!0},(function(e,a){e&&i(e),Promise.all(a.map((e=>{const r=path.join(t,e);return e.endsWith(".vue")||e.endsWith(".js")||e.endsWith(".html")||e.endsWith(".json")?new Promise(((e,t)=>{ejs.renderFile(r,s,{},((s,i)=>{s?t(s):(fse.writeFileSync(r,i),e(i))}))})):Promise.resolve()}))).then((()=>{r()})).catch((e=>{i(e)}))}))}))}async installNormalTemplate(){let e=spinnerStart("正在安装项目...");await sleep();const t=path.resolve(process.cwd(),this.projectInfo.projectName);try{const e=path.resolve(this.templateNpm.cacheFilePath);fse.ensureDirSync(e),fse.ensureDirSync(t),fse.copySync(e,t,{filter:e=>!(this.templateId&&!e.includes(".gitignore"))||!e.includes(".git")})}catch(e){throw e}finally{e.stop(!0),log.success("项目安装成功")}if(this.templateId){const e=["**/node_modules/**"];await this.ejsRender({ignore:e})}if(this.templateId||563!==this.templateInfo.id){const e=path.resolve(t,"package.json");if(!fs.existsSync(e))throw new Error("package.json不存在!");const s=fse.readJsonSync(e),{name:r,version:i,scripts:a}=s;if(log.verbose("package.json 检查必填信息 name, version, scripts"),!r||!i||!a||!a.build&&!a["build:prod"])throw new Error("package.json信息不全,请检查是否存在name、version和scripts(需提供build或build:prod命令)!");await this.execCommand("npm install","依赖安装失败!");const n={start:"start",dev:"dev"};await this.execCommand(`npm run ${a[n.start]?n.start:a[n.dev]?n.dev:"serve"}`,"启动执行命令失败,请检查是否存在start、dev、serve命令!")}else log.success("子项目模板拉取成功,跳过依赖安装和启动命令")}async createComponentFile(e){const t=this.templateInfo,s=this.projectInfo;if(t.tag.includes("component")){const r={...s,buildPath:t.buildPath,examplePath:t.examplePath,npmName:t.npmName,npmVersion:t.version},i=path.resolve(e,".componentrc");fs.writeFileSync(i,JSON.stringify(r))}}async downloadTemplate(){const e=this.projectInfo,t=path.resolve(userHome,".gchcg-cli","template",e.projectName),s=path.resolve(userHome,".gchcg-cli","template");this.templateInfo=e;const r=new Package({targetPath:t,storeDir:s,packageName:e.path,packageVersion:e.version,gitUrl:e.http_url_to_repo});if(await r.exists()){const e=spinnerStart("正在更新项目...");await sleep();try{await r.update()}catch(e){throw e}finally{e.stop(!0),await r.exists()&&(log.success("更新项目成功"),this.templateNpm=r)}}else{const e=spinnerStart("正在下载项目...");await sleep();try{await r.install()}catch(e){throw e}finally{e.stop(!0),await r.exists()&&(log.success("下载项目成功"),this.templateNpm=r)}}}async initDir(e){const t=path.resolve(process.cwd(),e);if(t&&!pathExists(t)&&fse.mkdirpSync(t),t&&!this.isDirEmpty(t)){let e=!1;if(!this.force&&(e=(await inquirer.prompt([{type:"confirm",name:"ifContinue",default:!1,message:"文件夹不为空,是否继续创建项目?"}])).ifContinue,!e))return;if(e||this.force){const{confirmDelete:e}=await inquirer.prompt([{type:"confirm",name:"confirmDelete",default:!1,message:"是否确认清空当前目录下的文件?"}]);e&&fse.emptyDirSync(t)}}}async prepare(){const e=await getProjectTemplate(this.refreshToken);if(!Array.isArray(e))throw new Error("无权限访问,请联系管理员");if(0===e.length)throw new Error("项目不存在或无权限访问,请联系管理员");return this.template=e,this.getProjectInfo()}getChoices(e){const t=[];return e.forEach((e=>{"group"===e.type?e.children&&e.children.length>0?t.push({name:e.name,value:e,short:`Group: ${e.name}`}):t.push({name:`${e.name}(无子项)`,value:null,disabled:!0}):"project"===e.type&&t.push({name:e.name,value:e,short:`Project: ${e.name}`})})),401!==e[0].parent_id&&t.push({name:"返回上一级",value:{type:"back",id:"group"===e[0].type?e[0].parent_id:e[0].namespace.id},short:"返回上一级"}),t}getBackChoices(e,t){const s=[];return e.forEach((r=>{"group"===r.type&&(r.id===t?s.push(...e):r.children&&r.children.length>0&&s.push(...this.getBackChoices(r.children,t)))})),s}async promptProject(e){const t=this.getChoices(e);if(0===t.length)return;const s=await inquirer.prompt([{type:"list",name:"selection",message:"请选择组或项目:",choices:t.concat(new inquirer.Separator,{name:"退出",value:"exit"})}]);return"back"===s.selection.type?await this.promptProject(this.getBackChoices(this.template,s.selection.id)):"group"===s.selection.type?await this.promptProject(s.selection.children):"project"===s.selection.type?(log.success("你选择了项目",s.selection.name),s.selection):s.selection}isValidName(e){return/^(@[a-zA-Z0-9-_]+\/)?[a-zA-Z]+([-][a-zA-Z][a-zA-Z0-9]*|[_][a-zA-Z][a-zA-Z0-9]*|[a-zA-Z0-9])*$/.test(e)}async getProjectInfo(){let e=this.isValidName(this.projectName);const t=await this.promptProject(this.template);if("exit"===t)throw new Error("退出选择");if(563===t.id){const e=(await inquirer.prompt([{type:"confirm",name:"isNewTemplate",default:!0,message:"是否创建子应用(默认创建子应用,输入n不创建)?"}])).isNewTemplate;this.templateId=e?563:""}const s=this.isValidName,r=`请输入合法的${this.templateId?"子应用":"项目文件夹"}名称【1.首字符必须为英文字符;2.尾字符必须为英文或数字,不能为字符;3.字符仅允许"-_"】`,i={type:"input",name:"projectName",message:`请输入${this.templateId?"子应用":"项目文件夹"}名称`,default:"",validate:function(e){return!!s(e)||r},filter:function(e){return e}},a=[];this.projectName&&!e&&(i.default=this.projectName,a.push(i)),this.templateId&&(this.projectName&&e?t.projectName=this.projectName:0===a.length&&a.push(i)),this.templateId&&a.push({type:"input",name:"projectVersion",message:"请输入子模块版本号(默认1.0.0)",default:"1.0.0",validate:function(e){return!!semver.valid(e)||"请输入合法的版本号"},filter:function(e){return semver.valid(e)?semver.valid(e):e}});const n=await inquirer.prompt(a);return t.projectName=e?this.projectName:n.projectName||t.name,t.projectVersion=n.projectVersion||"1.0.0",await this.initDir(t.projectName),this.templateId&&(t.name=t.projectName,t.className=require("kebab-case")(t.projectName).replace(/^-/,""),t.version=t.projectVersion),t}isDirEmpty(e){let t=fs.readdirSync(e);return t=t.filter((e=>!e.startsWith(".")&&["node_modules"].indexOf(e)<0)),!t||t.length<=0}createTemplateChoice(){return this.template.map((e=>({value:e.npmName,name:e.name})))}}function init(e){return new InitCommand(e)}module.exports=init,module.exports.InitCommand=InitCommand;