1 | #!/usr/bin/env node
|
2 |
|
3 | const yargs = require("yargs");
|
4 | const path = require("path");
|
5 | const fs = require("fs-extra");
|
6 | const chalk = require('chalk');
|
7 | const inquirer = require('inquirer');
|
8 | const ora = require('ora');
|
9 | const shelljs = require('shelljs');
|
10 | const utils = require("./lib/utils");
|
11 | const logger = require("./lib/utils/logger");
|
12 | const backup = require("./lib/utils/backup");
|
13 | const runapp = require("./lib/run");
|
14 | const builder = require("./lib/builder");
|
15 | const plugin = require('./lib/plugin');
|
16 | const create = require('./lib/plugin/create');
|
17 | const publish = require('./lib/plugin/publish');
|
18 |
|
19 | const TemplateRelease = require("./template-release");
|
20 | const constants = require('./index').constants;
|
21 | const templateRelease = new TemplateRelease(constants.cacheDirName, constants.templateReleaseUrl);
|
22 |
|
23 | let questions = function (inputName, releaseLists) {
|
24 | let applicationid = "";
|
25 | return [{
|
26 | type: 'input',
|
27 | name: 'name',
|
28 | default: function () {
|
29 | if (typeof inputName !== 'string') inputName = "";
|
30 | return inputName.trim() ? inputName.trim() : 'weiui-demo';
|
31 | },
|
32 | message: "请输入项目名称",
|
33 | validate: function (value) {
|
34 | let pass = value.match(/^[0-9a-z\-_]+$/i);
|
35 | if (pass) {
|
36 | return true;
|
37 | }
|
38 |
|
39 | return '输入格式错误,请重新输入。';
|
40 | }
|
41 | }, {
|
42 | type: 'input',
|
43 | name: 'appName',
|
44 | default: function () {
|
45 | return 'Weiui演示';
|
46 | },
|
47 | message: "请输入app名称",
|
48 | validate: function (value) {
|
49 | return value !== ''
|
50 | }
|
51 | }, {
|
52 | type: 'input',
|
53 | name: 'applicationID',
|
54 | default: function () {
|
55 | return 'cc.weiui.demo';
|
56 | },
|
57 | message: "请输入Android应用ID",
|
58 | validate: function (value) {
|
59 | let pass = value.match(/^[a-zA-Z_][a-zA-Z0-9_]*[.][a-zA-Z_][a-zA-Z0-9_]*[.][a-zA-Z_][a-zA-Z0-9_]+$/);
|
60 | if (pass) {
|
61 | applicationid = value;
|
62 | return true;
|
63 | }
|
64 | return '输入格式错误,请重新输入。';
|
65 | }
|
66 | }, {
|
67 | type: 'input',
|
68 | name: 'bundleIdentifier',
|
69 | default: function () {
|
70 | return applicationid;
|
71 | },
|
72 | message: "请输入iOS应用Bundle ID",
|
73 | validate: function (value) {
|
74 | let pass = value.match(/^[a-zA-Z_][a-zA-Z0-9_]*[.][a-zA-Z_][a-zA-Z0-9_]*[.][a-zA-Z_][a-zA-Z0-9_]+$/);
|
75 | if (pass) {
|
76 | return true;
|
77 | }
|
78 | return '输入格式错误,请重新输入。';
|
79 | }
|
80 | }, {
|
81 | type: 'list',
|
82 | name: 'release',
|
83 | message: "请选择模板版本",
|
84 | choices: releaseLists
|
85 | }];
|
86 | };
|
87 |
|
88 | let runQuestions = [{
|
89 | type: 'list',
|
90 | name: 'platform',
|
91 | message: '您可以安装或更新Weiui SDK',
|
92 | choices: [{
|
93 | name: "ios",
|
94 | value: "ios"
|
95 | }, {
|
96 | name: "android",
|
97 | value: "android"
|
98 | }
|
99 | ]
|
100 | }];
|
101 |
|
102 |
|
103 |
|
104 |
|
105 | function initProject(createName) {
|
106 | let spinFetch = ora('正在下载版本列表...');
|
107 | spinFetch.start();
|
108 | templateRelease.fetchReleaseVersions((err, result) => {
|
109 | spinFetch.stop();
|
110 | if (err) {
|
111 | logger.error(err);
|
112 | return;
|
113 | }
|
114 |
|
115 | let lists = [];
|
116 | result.forEach(t => {
|
117 | if (lists.length === 0) {
|
118 | lists.push({
|
119 | name: t + " (Latest)",
|
120 | value: t
|
121 | });
|
122 | } else if (lists.length < 5) {
|
123 | lists.push({
|
124 | name: t,
|
125 | value: t
|
126 | });
|
127 | }
|
128 | });
|
129 |
|
130 | if (lists.length === 0) {
|
131 | logger.error("没有找到可用的版本。");
|
132 | return;
|
133 | }
|
134 |
|
135 | inquirer.prompt(questions(createName, lists)).then(function (answers) {
|
136 | let _answers = JSON.parse(JSON.stringify(answers));
|
137 | let {name, appName, release, applicationID, bundleIdentifier} = _answers;
|
138 | let rundir = path.resolve(process.cwd(), name);
|
139 |
|
140 | if (fs.existsSync(name)) {
|
141 | logger.error(`目录[${name}]已经存在。`);
|
142 | return;
|
143 | }
|
144 |
|
145 | templateRelease.fetchRelease(release === 'latest' ? '' : release, function (error, releasePath) {
|
146 | if (error) {
|
147 | logger.error(error);
|
148 | return;
|
149 | }
|
150 |
|
151 | logger.weiui("正在复制模板文件...");
|
152 | fs.copySync(releasePath, name);
|
153 |
|
154 | changeFile(rundir + '/platforms/android/WeexWeiui/build.gradle', 'cc.weiui.playground', applicationID);
|
155 | changeFile(rundir + '/platforms/android/WeexWeiui/app/src/main/res/values/strings.xml', 'WeexWeiui', appName);
|
156 |
|
157 | changeFile(rundir + '/platforms/ios/WeexWeiui/WeexWeiui.xcodeproj/project.pbxproj', 'PRODUCT_BUNDLE_IDENTIFIER = cc.weiui.playground;', 'PRODUCT_BUNDLE_IDENTIFIER = ' + bundleIdentifier + ';');
|
158 | changeFile(rundir + '/platforms/ios/WeexWeiui/WeexWeiui/Info.plist', 'WeexWeiui', appName);
|
159 | utils.replaceDictString(rundir + '/platforms/ios/WeexWeiui/WeexWeiui/Info.plist', 'weiuiAppName', 'weiuiApp' + replaceUpperCase(bundleIdentifier));
|
160 |
|
161 | changeAppKey(rundir);
|
162 |
|
163 | logger.sep();
|
164 | logger.weiui("创建项目完成。");
|
165 | logger.sep();
|
166 |
|
167 | let finalLog = function () {
|
168 | logger.weiui("您可以运行一下命令开始。");
|
169 | logger.weiui(chalk.white(`1. cd ${name}`));
|
170 | logger.weiui(chalk.white(`2. npm install`));
|
171 | logger.weiui(chalk.white(`3. npm run dev`));
|
172 | };
|
173 |
|
174 | if (shelljs.which('pod')) {
|
175 | let spinPod = ora('正在运行pod安装...');
|
176 | spinPod.start();
|
177 | shelljs.cd(rundir + '/platforms/ios/WeexWeiui');
|
178 | shelljs.exec('pod install', {silent: true}, function (code, stdout, stderr) {
|
179 | spinPod.stop();
|
180 | if (code !== 0) {
|
181 | logger.warn("运行pod安装错误:" + code + ",请稍后手动运行!");
|
182 | }
|
183 | finalLog();
|
184 | });
|
185 | } else {
|
186 | logger.warn('未检测到系统安装pod,请安装pod后手动执行pod install!');
|
187 | finalLog();
|
188 | }
|
189 | });
|
190 | });
|
191 | });
|
192 | }
|
193 |
|
194 |
|
195 |
|
196 |
|
197 | function displayReleases() {
|
198 | logger.info("正在获取版本信息...");
|
199 | templateRelease.fetchReleaseVersions((err, result) => {
|
200 | if (err) {
|
201 | logger.error(err);
|
202 | return;
|
203 | }
|
204 | console.log("可用的版本:");
|
205 | result.forEach(t => {
|
206 | console.log(chalk.green.underline(t));
|
207 | });
|
208 | })
|
209 | }
|
210 |
|
211 |
|
212 |
|
213 |
|
214 |
|
215 |
|
216 |
|
217 | function changeFile(path, oldText, newText) {
|
218 | if (!fs.existsSync(path)) {
|
219 | return;
|
220 | }
|
221 | let result = fs.readFileSync(path, 'utf8').replace(new RegExp(oldText, "g"), newText);
|
222 | if (result) {
|
223 | fs.writeFileSync(path, result, 'utf8');
|
224 | }
|
225 | }
|
226 |
|
227 |
|
228 |
|
229 |
|
230 |
|
231 | function changeAppKey(path) {
|
232 | let configPath = path + "/weiui.config.js";
|
233 | if (!fs.existsSync(configPath)) {
|
234 | return;
|
235 | }
|
236 | let config = require(configPath);
|
237 | let content = '';
|
238 | if (config === null || typeof config !== 'object') {
|
239 | return;
|
240 | }
|
241 | if (typeof config.appKey === 'undefined') {
|
242 | return;
|
243 | }
|
244 | let createRand = function (len) {
|
245 | len = len || 32;
|
246 | let $chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678oOLl9gqVvUuI1';
|
247 | let maxPos = $chars.length;
|
248 | let pwd = '';
|
249 | for (let i = 0; i < len; i++) {
|
250 | pwd += $chars.charAt(Math.floor(Math.random() * maxPos));
|
251 | }
|
252 | return pwd;
|
253 | };
|
254 | logger.weiui("正在创建appKey...");
|
255 | config.appKey = createRand(32);
|
256 | content += "/**\n * 配置文件\n * 参数详细说明:https://weiui.app/guide/config.html\n */\n";
|
257 | content += "module.exports = ";
|
258 | content += JSON.stringify(config, null, "\t");
|
259 | content += ";";
|
260 | fs.writeFileSync(configPath, content, 'utf8');
|
261 |
|
262 | let androidPath = path + "/platforms/android/WeexWeiui/app/src/main/assets/weiui/config.json";
|
263 | if (fs.existsSync(androidPath)) {
|
264 | fs.writeFileSync(androidPath, JSON.stringify(config), 'utf8');
|
265 | }
|
266 | let iosPath = path + "/platforms/ios/WeexWeiui/bundlejs/weiui/config.json";
|
267 | if (fs.existsSync(androidPath)) {
|
268 | fs.writeFileSync(iosPath, JSON.stringify(config), 'utf8');
|
269 | }
|
270 | }
|
271 |
|
272 |
|
273 |
|
274 |
|
275 |
|
276 |
|
277 | function replaceUpperCase(string) {
|
278 | try {
|
279 | return string.replace(/^[a-z]/g, function ($1) {
|
280 | return $1.toLocaleUpperCase()
|
281 | }).replace(/\.+(\w)/g, function ($1) {
|
282 | return $1.toLocaleUpperCase()
|
283 | }).replace(/\./g, '');
|
284 | } catch (e) {
|
285 | return string;
|
286 | }
|
287 | }
|
288 |
|
289 | let args = yargs
|
290 | .command({
|
291 | command: "create [name]",
|
292 | desc: "创建一个weiui项目",
|
293 | handler: function (argv) {
|
294 | if (typeof argv.name === "string") {
|
295 | if (fs.existsSync(argv.name)) {
|
296 | logger.error(`目录“${argv.name}”已经存在。`);
|
297 | return;
|
298 | }
|
299 | }
|
300 | initProject(argv.name);
|
301 | }
|
302 | })
|
303 | .command({
|
304 | command: "lists",
|
305 | desc: "列出可用的模板版本",
|
306 | handler: function () {
|
307 | displayReleases();
|
308 | }
|
309 | })
|
310 | .command({
|
311 | command: "vue <pageName>",
|
312 | desc: "创建vue页面示例模板",
|
313 | handler: function (argv) {
|
314 | if (typeof argv.pageName === "string" && argv.pageName) {
|
315 | let dir = path.resolve(process.cwd(), "src");
|
316 | if (!fs.existsSync(dir)) {
|
317 | logger.error(`目录“src”不存在。`);
|
318 | return;
|
319 | }
|
320 | let filePath = dir + "/pages/" + argv.pageName + ".vue";
|
321 | if (fs.existsSync(filePath)) {
|
322 | logger.error(`文件“${argv.pageName}.vue”已经存在。`);
|
323 | return;
|
324 | }
|
325 | let tmlPath = __dirname + "/lib/template/_template.vue";
|
326 | if (!fs.existsSync(tmlPath)) {
|
327 | logger.error(`模板文件不存在。`);
|
328 | return;
|
329 | }
|
330 | fs.copySync(tmlPath, filePath);
|
331 | logger.success(`模板文件“${argv.pageName}.vue”成功创建。`);
|
332 | }
|
333 | }
|
334 | })
|
335 | .command({
|
336 | command: "plugin <command> <name> [simple]",
|
337 | desc: "添加、删除、创建或发布插件",
|
338 | handler: function (argv) {
|
339 | let op = {};
|
340 | op.name = argv.name;
|
341 | op.dir = path.basename(process.cwd());
|
342 | op.simple = argv.simple === true;
|
343 | op.platform = "all";
|
344 | switch (argv.command) {
|
345 | case 'add':
|
346 | case 'install':
|
347 | case 'i':
|
348 | plugin.add(op);
|
349 | break;
|
350 | case 'remove':
|
351 | case 'uninstall':
|
352 | case 'un':
|
353 | plugin.remove(op);
|
354 | break;
|
355 | case 'create':
|
356 | create.create(op);
|
357 | break;
|
358 | case 'publish':
|
359 | publish.publish(op);
|
360 | break;
|
361 | }
|
362 | }
|
363 | })
|
364 | .command({
|
365 | command: "login",
|
366 | desc: "登录云中心",
|
367 | handler: function () {
|
368 | utils.login((data) => {
|
369 | logger.weiuis(data.username + ' 登录成功!');
|
370 | });
|
371 | }
|
372 | })
|
373 | .command({
|
374 | command: "logout",
|
375 | desc: "登出云中心",
|
376 | handler: function () {
|
377 | utils.logout(() => {
|
378 | logger.weiuis('退出成功!');
|
379 | });
|
380 | }
|
381 | })
|
382 | .command({
|
383 | command: "backup",
|
384 | desc: "备份项目开发文件",
|
385 | handler: function () {
|
386 | backup.backup();
|
387 | }
|
388 | })
|
389 | .command({
|
390 | command: "recovery",
|
391 | desc: "恢复项目备份文件",
|
392 | handler: function () {
|
393 | backup.recovery();
|
394 | }
|
395 | })
|
396 | .command({
|
397 | command: "dev",
|
398 | desc: "调试开发",
|
399 | handler: function () {
|
400 | builder.dev();
|
401 | }
|
402 | })
|
403 | .command({
|
404 | command: "build",
|
405 | desc: "编译构造",
|
406 | handler: function () {
|
407 | builder.build();
|
408 | }
|
409 | })
|
410 | .command({
|
411 | command: "run [platform]",
|
412 | desc: "在你的设备上运行app (实验功能)",
|
413 | handler: function (argv) {
|
414 | let dir = path.basename(process.cwd());
|
415 | if (argv.platform === "ios") {
|
416 | runapp.runIOS({dir});
|
417 | } else if (argv.platform === "android") {
|
418 | runapp.runAndroid({dir});
|
419 | } else {
|
420 | inquirer.prompt(runQuestions).then(function (answers) {
|
421 | let platform = JSON.parse(JSON.stringify(answers)).platform;
|
422 | if (platform === 'ios') {
|
423 | runapp.runIOS({dir});
|
424 | } else if (platform === 'android') {
|
425 | runapp.runAndroid({dir});
|
426 | }
|
427 | });
|
428 | }
|
429 | }
|
430 | })
|
431 | .version(require('./package.json').version)
|
432 | .help()
|
433 | .alias({
|
434 | "h": "help",
|
435 | "v": "version",
|
436 | "s": "simple"
|
437 | })
|
438 | .strict(true)
|
439 | .demandCommand()
|
440 | .argv;
|
441 |
|
442 |
|