@lazycatcloud/lzc-cli 1.1.0 → 1.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/lib/api.js +34 -36
  2. package/lib/archiver.js +50 -31
  3. package/lib/box/hportal.js +113 -0
  4. package/lib/box/index.js +135 -0
  5. package/lib/box/qemu_vm_mgr.js +553 -0
  6. package/lib/box/schemes/vm_box_system_debian.json +47 -0
  7. package/lib/builder.js +154 -35
  8. package/lib/dev.js +39 -31
  9. package/lib/env.js +276 -58
  10. package/lib/generator.js +31 -0
  11. package/lib/git/git-commit.sh +7 -0
  12. package/lib/git/git-reset.sh +15 -0
  13. package/lib/key.js +14 -25
  14. package/lib/sdk.js +7 -10
  15. package/lib/utils.js +149 -52
  16. package/package.json +14 -2
  17. package/scripts/auto-completion.sh +46 -0
  18. package/scripts/cli.js +134 -70
  19. package/template/_lazycat/app-config +1 -0
  20. package/template/_lazycat/docker-compose.yml.in +3 -5
  21. package/template/golang/README.md +3 -4
  22. package/template/golang/assets/css/bootstrap-responsive.css +26 -23
  23. package/template/golang/assets/css/bootstrap-responsive.min.css +1065 -1
  24. package/template/golang/assets/css/bootstrap.css +733 -362
  25. package/template/golang/assets/css/bootstrap.min.css +5299 -1
  26. package/template/golang/assets/css/rego.css +17 -17
  27. package/template/golang/assets/js/bootstrap.js +1340 -1311
  28. package/template/golang/assets/js/bootstrap.min.js +1240 -5
  29. package/template/golang/assets/js/rego.js +80 -69
  30. package/template/golang/index.html +61 -59
  31. package/template/ionic_vue3/README.md +46 -0
  32. package/template/ionic_vue3/_eslintrc.cjs +24 -0
  33. package/template/ionic_vue3/_gitignore +29 -0
  34. package/template/ionic_vue3/_vscode/extensions.json +6 -0
  35. package/template/ionic_vue3/capacitor.config.ts +10 -0
  36. package/template/ionic_vue3/env.d.ts +1 -0
  37. package/template/ionic_vue3/index.html +13 -0
  38. package/template/ionic_vue3/ionic.config.json +7 -0
  39. package/template/ionic_vue3/package.json +52 -0
  40. package/template/ionic_vue3/postcss.config.js +6 -0
  41. package/template/ionic_vue3/public/favicon.ico +0 -0
  42. package/template/ionic_vue3/src/App.vue +11 -0
  43. package/template/ionic_vue3/src/assets/logo.svg +1 -0
  44. package/template/ionic_vue3/src/index.css +3 -0
  45. package/template/ionic_vue3/src/main.ts +35 -0
  46. package/template/ionic_vue3/src/router/index.ts +15 -0
  47. package/template/ionic_vue3/src/theme/variables.css +231 -0
  48. package/template/ionic_vue3/src/views/Home.vue +38 -0
  49. package/template/ionic_vue3/tailwind.config.js +7 -0
  50. package/template/ionic_vue3/tsconfig.json +16 -0
  51. package/template/ionic_vue3/tsconfig.vite-config.json +8 -0
  52. package/template/ionic_vue3/vite.config.ts +28 -0
  53. package/template/release/golang/build.sh +1 -2
  54. package/template/release/ionic_vue3/Dockerfile +10 -0
  55. package/template/release/ionic_vue3/build.sh +9 -0
  56. package/template/release/ionic_vue3/docker-compose.yml.in +8 -0
  57. package/template/release/vue/Dockerfile +3 -2
  58. package/template/release/vue/build.sh +4 -2
  59. package/template/vue/README.md +5 -0
  60. package/template/vue/babel.config.js +2 -4
package/lib/utils.js CHANGED
@@ -5,7 +5,6 @@ import os from "os";
5
5
  import chalk from "chalk";
6
6
  import archiver from "archiver";
7
7
  import glob from "fast-glob";
8
- import envsub from "envsub";
9
8
  import yaml from "js-yaml";
10
9
  import mergeWith from "lodash.mergewith";
11
10
  import isArray from "lodash.isarray";
@@ -13,43 +12,130 @@ import fetch from "node-fetch";
13
12
  import { dirname } from "path";
14
13
  import { fileURLToPath } from "url";
15
14
  import ignore from "ignore";
15
+ import ora from "ora";
16
+ import { desireStatusTimer } from "../lib/api.js";
17
+ import { warn } from "console";
16
18
 
17
- const controller = new AbortController();
18
19
  const META_MARK = "x-lazycat-app";
19
20
  const APP_FOLDER = ".lazycat";
20
21
  const APP_CONFIG_FILE = "app-config";
21
22
  const APP_SDK_HOSTNAME = "box";
23
+ export const GLOBAL_CONFIG_DIR = path.join(os.homedir(), "/.config/lazycat");
22
24
 
23
25
  export const envsubstr = async (templateContents, args) => {
24
26
  const parse = await importDefault("envsub/js/envsub-parser.js");
25
27
  return parse(templateContents, args);
26
28
  };
27
-
28
- // commander passes the Command object itself as options,
29
- // extract only actual options into a fresh object.
30
- async function checkURL(url) {
31
- const timeout = setTimeout(() => {
32
- controller.abort();
33
- }, 5000);
34
-
29
+ /**
30
+ * 为盒子安装SDK应用
31
+ * @param box_url 盒子入口地址
32
+ **/
33
+ async function InstallSDK(box_url) {
35
34
  try {
36
- const resp = await fetch(url, { signal: controller.signal });
35
+ let url = `${box_url}/api/app/apply?id=sdk`;
36
+ const resp = await fetch(url, { method: "post" });
37
37
  if (resp.status != 200) {
38
- throw new Error(chalk.red(
39
- `无法连接 sdk 服务, 请确保 ${chalk.yellow(
40
- new URL(url).origin
41
- )} 可以访问或者在应用商店安装 sdk`
42
- ));
38
+ throw new Error(
39
+ chalk.red(
40
+ `无法安装, 请确保 ${chalk.yellow(
41
+ new URL(url).origin
42
+ )} 可以访问或者在应用商店安装 sdk`
43
+ )
44
+ );
45
+ }
46
+ } catch (err) {
47
+ throw err;
48
+ }
49
+ }
50
+ /**
51
+ * 检查SDK安装部署的状态
52
+ * @param box_url 盒子入口地址
53
+ **/
54
+ async function checkSDKInstallStatus(box_url) {
55
+ const checkSDKstatus = async function (box_url) {
56
+ let url = `${box_url}/api/app/status?id=sdk`;
57
+ const resp = await fetch(url);
58
+ if (resp.status == 200) {
59
+ const status = await resp.json();
60
+ return status;
61
+ } else {
62
+ let text = await resp.text();
63
+ throw text;
64
+ }
65
+ };
66
+ const spinner = ora().start();
67
+ let { status, info } = await checkSDKstatus(box_url);
68
+ spinner.text = "部署进度";
69
+ switch (status) {
70
+ case "running":
71
+ console.log(chalk.yellow("应用正在运行中"));
72
+ break;
73
+ case "error":
74
+ spinner.stop();
75
+ console.log(status, info);
76
+ throw info.msg;
77
+ default:
78
+ try {
79
+ await desireStatusTimer(
80
+ (result) => {
81
+ spinner.text = "部署进度 " + result.status;
82
+ return result.status === "running";
83
+ },
84
+ () => {
85
+ return checkSDKstatus(box_url);
86
+ }
87
+ );
88
+ } catch (error) {
89
+ throw error;
90
+ } finally {
91
+ spinner.stop();
92
+ }
93
+ break;
94
+ }
95
+ spinner.stop();
96
+ }
97
+
98
+ /**
99
+ * 获取所有已安装的app
100
+ * @param box_url 盒子入口地址
101
+ **/
102
+ async function getInstalledApps(box_url) {
103
+ try {
104
+ let url = `${box_url}/api/app/dump`;
105
+ const resp = await fetch(url);
106
+ if (resp.status != 200) throw new Error(chalk.red("获取所有已安装App失败"));
107
+ return await resp.json();
108
+ } catch (e) {
109
+ console.log(e);
110
+ }
111
+ }
112
+ /**
113
+ * 查找某个app是否已安装]
114
+ * @param box_url 盒子入口地址
115
+ * @param app_id app名
116
+ * */
117
+ async function findAppIsInstalled(box_url, app_id) {
118
+ const apps = await getInstalledApps(box_url);
119
+ for (let app in apps) {
120
+ if (app == app_id) {
121
+ return true;
43
122
  }
44
- } catch (error) {
45
- throw error;
46
- } finally {
47
- clearTimeout(timeout);
48
123
  }
124
+ return false;
49
125
  }
50
126
 
127
+ /**
128
+ * 确保文件夹存在
129
+ * @param filePath {string} 如果为文件路径 确保其文件夹存在; 如果为文件夹, 则确保该文件夹存在
130
+ *
131
+ */
51
132
  function ensureDir(filePath) {
52
- const dirPath = path.dirname(filePath);
133
+ let dirPath;
134
+ if (filePath.endsWith("/")) {
135
+ dirPath = filePath;
136
+ } else {
137
+ dirPath = path.dirname(filePath);
138
+ }
53
139
  if (!fs.existsSync(dirPath)) {
54
140
  fs.mkdirSync(dirPath, { recursive: true });
55
141
  }
@@ -117,7 +203,7 @@ function getMetaInfo(composeFile) {
117
203
  return doc[META_MARK];
118
204
  }
119
205
 
120
- async function convertTemplateFile(templateFile, outputFile, env) {
206
+ async function createTemplateFile(templateFile, outputFile, env) {
121
207
  const template = yaml.load(fs.readFileSync(templateFile, "utf8"));
122
208
  // const meta = template[META_MARK];
123
209
  // if (
@@ -134,7 +220,7 @@ async function convertTemplateFile(templateFile, outputFile, env) {
134
220
  // authcallback: "/lzcapis/oidc-callback",
135
221
  // });
136
222
  // template["services"]["lazycat-apis-sidecar"] = {
137
- // image: "registry.linakesi.com/lazycat-apis-sidecar",
223
+ // image: "registry.lazycat.cloud/lazycat-apis-sidecar",
138
224
  // // volumes_from: ["${APP_NAME}:rw"],
139
225
  // volumes: ["lzcapis-lzcapp:/lzcapp"],
140
226
  // command: [
@@ -191,7 +277,7 @@ async function copyDotAppDir(from, to, opts = {}) {
191
277
  }
192
278
  ensureDir(outputFile);
193
279
  if (needConvert) {
194
- await convertTemplateFile(templateFile, outputFile, env);
280
+ await createTemplateFile(templateFile, outputFile, env);
195
281
  } else {
196
282
  fs.copyFileSync(templateFile, outputFile);
197
283
  }
@@ -255,8 +341,8 @@ function archiveFolder(appDir, format = "zip") {
255
341
  });
256
342
  }
257
343
 
258
- function contextDirname() {
259
- return dirname(fileURLToPath(import.meta.url));
344
+ function contextDirname(url = import.meta.url) {
345
+ return dirname(fileURLToPath(url));
260
346
  }
261
347
 
262
348
  async function importDefault(pkgPath) {
@@ -265,39 +351,39 @@ async function importDefault(pkgPath) {
265
351
  }
266
352
 
267
353
  class GitIgnore {
268
- constructor() {
269
- this.ig = ignore({ allowRelativePaths: true });
354
+ constructor(root) {
355
+ this.root = root;
356
+ this.ignores = [];
270
357
  }
271
358
 
272
- // 扫面一个指定的文件夹, 将.gitignore中的规则添加到this.gitignore
273
- scan(dir) {
274
- try {
275
- let data = fs.readFileSync(path.join(dir, ".gitignore"), "utf8");
276
- this.ig.add(data.split("\n"));
277
- } catch {
278
- // if not exist .gitignore
279
- }
280
- }
359
+ async collect() {
360
+ const files = await glob(["**/.gitignore"], {
361
+ cwd: this.root,
362
+ dot: true,
363
+ deep: 3,
364
+ });
281
365
 
282
- contain(filepath) {
283
- return this.ig.ignores(filepath);
366
+ files.forEach((f) => this._add(f));
284
367
  }
285
368
 
286
- // node.js fs.readdir的封装,会自动扫描.gitignore并过滤
287
- async readdir(dir, callback) {
288
- await this.scan(dir);
289
-
290
- if (this.ig.ignores(dir)) {
291
- return callback("", []);
292
- }
369
+ _add(ignoreFile) {
370
+ let data = fs.readFileSync(ignoreFile, "utf8");
371
+ let ig = ignore({ allowRelativePaths: true });
372
+ ig.add(data.split("\n"));
373
+ this.ignores.push({
374
+ ig,
375
+ dir: path.dirname(ignoreFile),
376
+ });
377
+ }
293
378
 
294
- return fs.readdir(dir, { withFileTypes: true }, (err, files) => {
295
- if (err) {
296
- return callback(err, []);
379
+ contain(filepath) {
380
+ return this.ignores.some(({ ig, dir }) => {
381
+ // 去除不应该计算ignore 的文件
382
+ if (!filepath.startsWith(dir)) {
383
+ return false;
297
384
  }
298
385
 
299
- let validFiles = files.filter((f) => !this.ig.ignores(f.name));
300
- return callback(err, validFiles);
386
+ return ig.ignores(path.relative(dir, filepath));
301
387
  });
302
388
  }
303
389
  }
@@ -324,6 +410,12 @@ function urlHostname(url) {
324
410
  return u.hostname;
325
411
  }
326
412
 
413
+ // REVIEW: 用户输入的app-id 空格替换为减号并且转换为全小写。
414
+ // 这会影响默认的app-name,因为app-name的默认值依赖app-id,但是如果特定输入了app-name则正常
415
+ function parse2CorrectName(name) {
416
+ return name.replaceAll(" ", "-").toLowerCase();
417
+ }
418
+
327
419
  export {
328
420
  ensureDir,
329
421
  copyDotAppDir,
@@ -332,7 +424,6 @@ export {
332
424
  findAppRootPath,
333
425
  archiveFolder,
334
426
  mergeYaml,
335
- checkURL,
336
427
  loadFromYaml,
337
428
  dumpToYaml,
338
429
  importDefault,
@@ -346,4 +437,10 @@ export {
346
437
  GitIgnore,
347
438
  isFileExist,
348
439
  urlHostname,
440
+ InstallSDK,
441
+ findAppIsInstalled,
442
+ getInstalledApps,
443
+ checkSDKInstallStatus,
444
+ createTemplateFile,
445
+ parse2CorrectName,
349
446
  };
package/package.json CHANGED
@@ -1,9 +1,15 @@
1
1
  {
2
2
  "name": "@lazycatcloud/lzc-cli",
3
- "version": "1.1.0",
3
+ "version": "1.1.3",
4
4
  "description": "lazycat cloud developer kit",
5
5
  "scripts": {
6
- "test": "echo \"Error: no test specified\" && exit 1"
6
+ "test": "mocha",
7
+ "publish": "npm publish --access public"
8
+ },
9
+ "mocha": {
10
+ "recursive": true,
11
+ "reporter": "spec",
12
+ "timeout": 5000
7
13
  },
8
14
  "files": [
9
15
  "template",
@@ -23,7 +29,9 @@
23
29
  "@balena/dockerignore": "^1.0.2",
24
30
  "archiver": "^5.3.0",
25
31
  "chalk": "^4.1.2",
32
+ "chokidar": "^3.5.3",
26
33
  "commander": "^8.3.0",
34
+ "commander-completion": "^1.0.1",
27
35
  "dockerfile-ast": "^0.4.1",
28
36
  "dockerode": "^3.3.1",
29
37
  "ejs": "^3.1.6",
@@ -40,14 +48,18 @@
40
48
  "lodash.merge": "^4.6.2",
41
49
  "lodash.mergewith": "^4.6.2",
42
50
  "log-update": "^5.0.0",
51
+ "lz4": "^0.6.5",
43
52
  "minimist": "^1.2.5",
44
53
  "node-fetch": "^2.6.6",
54
+ "node-stream-zip": "^1.15.0",
45
55
  "ora": "^6.0.1",
46
56
  "semver": "^7.3.5",
47
57
  "ssh2": "^1.5.0",
48
58
  "ssh2-promise": "^1.0.2"
49
59
  },
50
60
  "devDependencies": {
61
+ "chai": "^4.3.6",
62
+ "mocha": "^9.2.2",
51
63
  "prettier": "^2.5.0"
52
64
  }
53
65
  }
@@ -0,0 +1,46 @@
1
+ # Forked from https://github.com/isaacs/npm/blob/v1.3.17/lib/utils/completion.sh
2
+ # Forked from https://github.com/twolfson/foundry/blob/4.3.3/bin/completion/foundry
3
+ #!/bin/bash
4
+ ###-begin-lzc-cli-completion-###
5
+ #
6
+ # foundry command completion script
7
+ #
8
+ # Installation: lzc-cli completion >> ~/.bashrc (or ~/.zshrc)
9
+ # Or, maybe: lzc-cli completion > /usr/local/etc/bash_completion.d/lzc-cli
10
+ #
11
+
12
+ COMP_WORDBREAKS=${COMP_WORDBREAKS/=/}
13
+ COMP_WORDBREAKS=${COMP_WORDBREAKS/@/}
14
+ export COMP_WORDBREAKS
15
+
16
+ if type complete &>/dev/null; then
17
+ _lzc_cli_completion () {
18
+ local si="$IFS"
19
+ IFS=$'\n' COMPREPLY=($(COMP_CWORD="$COMP_CWORD" \
20
+ COMP_LINE="$COMP_LINE" \
21
+ COMP_POINT="$COMP_POINT" \
22
+ lzc-cli completion -- "${COMP_WORDS[@]}" \
23
+ 2>/dev/null)) || return $?
24
+ IFS="$si"
25
+ }
26
+ complete -F _lzc_cli_completion lzc-cli
27
+ # DEV: We removed `compdef` due to issues with `zsh` (zsh 5.0.0 (x86_64-unknown-linux-gnu))
28
+ elif type compctl &>/dev/null; then
29
+ _lzc_cli_completion () {
30
+ local cword line point words si
31
+ read -Ac words
32
+ read -cn cword
33
+ let cword-=1
34
+ read -l line
35
+ read -ln point
36
+ si="$IFS"
37
+ IFS=$'\n' reply=($(COMP_CWORD="$cword" \
38
+ COMP_LINE="$line" \
39
+ COMP_POINT="$point" \
40
+ lzc-cli completion -- "${words[@]}" \
41
+ 2>/dev/null)) || return $?
42
+ IFS="$si"
43
+ }
44
+ compctl -K _lzc_cli_completion lzc-cli
45
+ fi
46
+ ###-end-lzc-cli-completion-###
package/scripts/cli.js CHANGED
@@ -1,98 +1,162 @@
1
1
  #!/usr/bin/env node
2
-
3
- import program from "commander";
4
2
  import process from "process";
5
3
  import path from "path";
6
4
  import fs from "fs";
7
5
  import { contextDirname, importDefault } from "../lib/utils.js";
8
- import Env from "../lib/env.js";
6
+ import yargs from "yargs";
7
+ import { hideBin } from "yargs/helpers";
9
8
 
9
+ import Env from "../lib/env.js";
10
+ import { boxCommand } from "../lib/box/index.js";
10
11
  const pkgInfo = JSON.parse(
11
- fs.readFileSync(path.join(contextDirname(), "../package.json"))
12
+ fs.readFileSync(path.join(contextDirname(import.meta.url), "../package.json"))
12
13
  );
13
14
 
14
- program.usage("<command> [options]");
15
-
16
- program
17
- .version(`lzc-cli ${pkgInfo.version}`)
15
+ const program = yargs(hideBin(process.argv))
16
+ .scriptName("lzc-cli")
18
17
  .usage("<command> [options]")
19
- .command("create <name>")
20
- .description("创建懒猫云应用")
21
- .action(async (name, cmd) => {
18
+ .version(`lzc-cli ${pkgInfo.version}`)
19
+ .completion("completion", "生成bash/zsh补全脚本");
20
+
21
+ program.command({
22
+ command: "create <name>",
23
+ desc: "创建懒猫云应用",
24
+ aliases: ["c"],
25
+ handler: async ({ name }) => {
22
26
  let create = await importDefault("../cmds/create.js");
23
27
  await create({ name });
24
- });
28
+ },
29
+ });
25
30
 
26
- program
27
- .command("init")
28
- .description("初始化懒猫云应用配置")
29
- .action(async (options) => {
31
+ program.command({
32
+ command: "init",
33
+ desc: "初始化懒猫云应用配置",
34
+ handler: async () => {
30
35
  const { Init } = await import("../cmds/init.js");
31
36
  new Init({ cwd: process.cwd() }).create();
32
- });
37
+ },
38
+ });
33
39
 
34
- program
35
- .command("uninstall")
36
- .description("卸载应用")
37
- .action(async (options) => {
40
+ program.command({
41
+ command: "uninstall",
42
+ desc: "卸载应用",
43
+ handler: async () => {
38
44
  const { uninstall } = await importDefault("../cmds/app.js");
39
45
  await uninstall();
40
- });
46
+ },
47
+ });
48
+
49
+ program.command({
50
+ command: "publish",
51
+ desc: "发布应用",
52
+ handler: async () => {
53
+ // 第一步 打包镜像
54
+ const Publisher = await importDefault("../cmds/publish.js");
55
+ const publisher = new Publisher();
56
+ await publisher.run();
57
+ // const b = builder();
58
+ // const contextDir = process.cwd()
59
+ // const dockerfile = Env.get("BUILD_CONTEXT")
60
+ // b.dockerRemoteBuildV2()
61
+ // 第二步
62
+ },
63
+ });
41
64
 
42
- program
43
- .command("deploy")
44
- .description("部署应用至设备")
45
- .action(async (url, _options) => {
65
+ program.command({
66
+ command: "deploy",
67
+ desc: "部署应用至设备",
68
+ handler: async () => {
46
69
  const { deploy } = await importDefault("../cmds/app.js");
47
70
  await deploy();
48
- });
49
-
50
- program
51
- .command("build")
52
- .argument("[context]", "integer argument")
53
- .option("-f, --file <file>", "", "Dockerfile")
54
- .action(async (context, options) => {
55
- const builder = await importDefault("../lib/builder.js");
56
- const b = builder({ env: Env(process.cwd()).all });
57
- b.dockerRemoteBuildV2(context, options.file);
58
- });
71
+ },
72
+ });
59
73
 
60
- let dev = program.command("dev").description("dev [forward [addr] | shell]");
74
+ program.command({
75
+ command: "build [context]",
76
+ desc: "构建",
77
+ builder: (args) => {
78
+ args.option("f", {
79
+ alias: "file",
80
+ describe: "Dockerfile",
81
+ default: "Dockerfile",
82
+ });
83
+ },
84
+ handler: async ({ context, file }) => {
85
+ const Builder = await importDefault("../lib/builder.js");
86
+ Env.load(process.cwd());
87
+ const b = new Builder({ env: Env.all });
88
+ b.dockerRemoteBuildV2(context, file);
89
+ },
90
+ });
61
91
 
62
- dev
63
- .command("forward [addr]")
64
- .description("本地端口转发")
65
- .action(async (addr) => {
66
- const { dev } = await importDefault("../cmds/dev.js");
67
- await dev(addr);
68
- });
92
+ let devSubCommands = [
93
+ {
94
+ command: "forward [addr]",
95
+ desc: "本地端口转发",
96
+ handler: async ({ addr }) => {
97
+ const { dev } = await importDefault("../cmds/dev.js");
98
+ await dev(addr);
99
+ },
100
+ },
101
+ {
102
+ command: "shell",
103
+ desc: "远程连接盒子",
104
+ builder: (args) => {
105
+ args.option("b", {
106
+ alias: "build",
107
+ desc: "重新部署应用",
108
+ type: "boolean",
109
+ });
110
+ },
111
+ handler: async (args) => {
112
+ const { devShell } = await importDefault("../cmds/dev.js");
113
+ await devShell(args);
114
+ },
115
+ },
116
+ ];
117
+ program.command({
118
+ command: "dev",
119
+ desc: "dev [forward [addr] | shell]",
120
+ builder: (args) => {
121
+ args.command(devSubCommands);
122
+ },
123
+ });
69
124
 
70
- dev
71
- .command("shell")
72
- .option("-b, --build", "重新部署应用")
73
- .description("本地开发应用")
74
- .action(async (options) => {
75
- const { devShell } = await importDefault("../cmds/dev.js");
76
- await devShell(options);
77
- });
78
-
79
- program
80
- .command("log [project]")
81
- .description("查看应用日志")
82
- .action(async (projectName) => {
125
+ program.command({
126
+ command: "log [project]",
127
+ desc: "查看应用日志",
128
+ builder: (args) => {
129
+ args.option("u", {
130
+ alias: "user",
131
+ describe: "多实例对应的用户",
132
+ demandOption: true,
133
+ type: "string",
134
+ });
135
+ },
136
+ handler: async (args) => {
83
137
  const { monitor } = await importDefault("../cmds/log.js");
84
- await monitor(projectName);
85
- });
138
+ await monitor(args.project, args);
139
+ },
140
+ });
86
141
 
87
- program
88
- .command("config")
89
- .description("应用配置项")
90
- .argument("[key]", "key argument")
91
- .argument("[value]", "integer argument")
92
- .option("-g, --global", "global config", false)
93
- .action(async (key, value, options) => {
142
+ program.command({
143
+ command: "config [key] [value]",
144
+ desc: "应用配置项",
145
+ builder: (args) => {
146
+ args.implies("key", "value");
147
+ args.option("g", {
148
+ alias: "global",
149
+ describe: "global config",
150
+ type: "boolean",
151
+ default: false,
152
+ });
153
+ },
154
+ handler: async (args) => {
94
155
  const { config } = await importDefault("../cmds/config.js");
95
- await config([key, value, options]);
96
- });
156
+ await config([args.key, args.value, args]);
157
+ },
158
+ });
159
+
160
+ boxCommand(program);
97
161
 
98
- program.parse(process.argv);
162
+ program.parse();
@@ -0,0 +1 @@
1
+ {}
@@ -1,8 +1,8 @@
1
1
  version: "3.9"
2
2
  x-lazycat-app:
3
3
  id: ${APP_ID}
4
- title: ${APP_NAME}
5
- version: 1.0.0
4
+ title: ${APP_DESCRIPTION}
5
+ version: ${APP_VERSION}
6
6
  description:
7
7
  icon: icon.svg
8
8
  categories:
@@ -12,6 +12,4 @@ x-lazycat-app:
12
12
  - service: ${APP_ID}
13
13
  port: ${HTTP_SERVICE_PORT}
14
14
  subdomain: ${APP_ID}
15
- permissions:
16
- - lzcapis
17
-
15
+ auth: auto
@@ -1,5 +1,4 @@
1
- rego
2
- ====
1
+ # rego
3
2
 
4
3
  Rego is an online Go regular expression tester
5
4
 
@@ -9,5 +8,5 @@ It's currently deployed on Heroku at [http://regoio.herokuapp.com/](http://regoi
9
8
 
10
9
  ## TODO
11
10
 
12
- * Sharing (permalink)
13
- * Add developer documentation
11
+ - Sharing (permalink)
12
+ - Add developer documentation