@lazycatcloud/lzc-cli 1.2.0 → 1.2.2
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.
- package/README.md +30 -62
- package/lib/app/lpk_debug_bridge.js +13 -3
- package/lib/app/lpk_devshell.js +12 -10
- package/lib/utils.js +4 -0
- package/package.json +2 -3
- package/template/_lpk/exec.sh +1 -0
- package/lib/lzc_sdk.js +0 -83
package/README.md
CHANGED
|
@@ -1,79 +1,47 @@
|
|
|
1
|
-
#
|
|
2
|
-
```
|
|
3
|
-
<command> [options]
|
|
4
|
-
|
|
5
|
-
Commands:
|
|
6
|
-
lzc-cli box 盒子管理 lzc-cli app 应用管理 lzc-cli project 项目管理 lzc-cli appstore 应用商店
|
|
7
|
-
Options:
|
|
8
|
-
-h, --help [boolean] [default: false]
|
|
9
|
-
--version Show version number [boolean]
|
|
10
|
-
--log log level 'trace', 'debug', 'info', 'warn', 'error'
|
|
11
|
-
[string] [default: "info"]
|
|
12
|
-
```
|
|
1
|
+
# lzc-cli 指南
|
|
13
2
|
|
|
14
|
-
|
|
15
|
-
```
|
|
16
|
-
npm install -g @lazycatcloud/lzc-cli
|
|
17
|
-
```
|
|
3
|
+
#### 依赖
|
|
18
4
|
|
|
19
|
-
|
|
5
|
+
1. `ssh`
|
|
6
|
+
2. `ssh-copy-id`
|
|
7
|
+
3. `rsync`
|
|
20
8
|
|
|
21
|
-
|
|
22
|
-
```
|
|
23
|
-
lzc-cli box create
|
|
24
|
-
```
|
|
25
|
-
将从 https://dl.lazycat.cloud 中下载最新的盒子系统数据,跟创建对应的 qemu 虚拟盒子。
|
|
9
|
+
#### 快速上手
|
|
26
10
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
lzc-cli
|
|
30
|
-
|
|
11
|
+
```bash
|
|
12
|
+
npm install -g @lazycatcloud/lzc-cli
|
|
13
|
+
# 将 lzc-cli 添加 bash/zsh 补全支持
|
|
14
|
+
lzc-cli completion >> ~/.zshrc
|
|
31
15
|
```
|
|
32
|
-
启动盒子成功后,就可以在 https://<mydemobox>.heiyu.space 中看到盒子的主页了。
|
|
33
16
|
|
|
34
|
-
|
|
35
|
-
```
|
|
36
|
-
lzc-cli box switch <otherBoxName>
|
|
37
|
-
```
|
|
17
|
+
下面开始使用 `lzc-cli` 去创建一个项目吧!
|
|
38
18
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
lzc-cli box info
|
|
42
|
-
```
|
|
19
|
+
```bash
|
|
20
|
+
lzc-cli project create you_project
|
|
43
21
|
|
|
44
|
-
|
|
22
|
+
# 构建懒猫云平台lpk包
|
|
23
|
+
lzc-cli project build
|
|
45
24
|
|
|
46
|
-
|
|
25
|
+
# 将lpk包安装到盒子中去
|
|
26
|
+
lzc-cli app install
|
|
47
27
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
lzc-cli app install https://repo.lazycat.cloud/pkgs/cloud.lazycat.app.kityminder/cloud.lazycat.app.kityminder-v1.0.3.lpk
|
|
51
|
-
```
|
|
28
|
+
# 使用 devshell 可以让你在盒子中开发调试
|
|
29
|
+
lzc-cli project devshell
|
|
52
30
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
lzc-cli app install ./kityminder.lpk
|
|
31
|
+
# 经过测试后,将包发布到懒猫云商店中去
|
|
32
|
+
lzc-cli appstore publish
|
|
56
33
|
```
|
|
57
34
|
|
|
58
|
-
###
|
|
59
|
-
```
|
|
60
|
-
lzc-cli app uninstall cloud.lazycat.app.kityminder
|
|
61
|
-
```
|
|
35
|
+
### FAQ
|
|
62
36
|
|
|
63
|
-
|
|
37
|
+
#### 1. 开发者工具 ssh 的帐号密码是多少?
|
|
64
38
|
|
|
65
|
-
|
|
66
|
-
```
|
|
67
|
-
lzc-cli project create yourappname
|
|
68
|
-
```
|
|
39
|
+
现在帐号密码设置为 box:box,后面会使用 pam 模块对接盒子帐号体系。
|
|
69
40
|
|
|
70
|
-
|
|
71
|
-
```
|
|
72
|
-
lzc-cli project build -o yourappname.lpk
|
|
73
|
-
```
|
|
41
|
+
#### 2. 如何切换默认的开发的盒子?
|
|
74
42
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
43
|
+
目前不支持通过 lzc-cli 工具切换默认的盒子,所以你需要在 lzc-client-desktop 客户端上点击你要使用的盒子来切换。
|
|
44
|
+
|
|
45
|
+
#### 3. 如果在盒子中构建镜像? 不想在本地构建
|
|
46
|
+
|
|
47
|
+
现在已经把在盒子中构建镜像的功能去掉了,只能在本地或者其他地方构建好,然后指定 image 字段来选择你需要的开发环境。
|
|
@@ -71,7 +71,10 @@ export class DebugBridge {
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
async isDevshell(appId) {
|
|
74
|
-
const stdout = await this.common(this.sshCmd, [
|
|
74
|
+
const stdout = await this.common(this.sshCmd, [
|
|
75
|
+
`isDevshell --uid ${this.uid}`,
|
|
76
|
+
appId,
|
|
77
|
+
]);
|
|
75
78
|
return stdout == "true";
|
|
76
79
|
}
|
|
77
80
|
|
|
@@ -83,10 +86,17 @@ export class DebugBridge {
|
|
|
83
86
|
return this.common(this.sshCmd, [`uninstall --uid ${this.uid}`, appId]);
|
|
84
87
|
}
|
|
85
88
|
|
|
86
|
-
async devshell(appId) {
|
|
89
|
+
async devshell(appId, isUserApp) {
|
|
87
90
|
const stream = spawn(
|
|
88
91
|
this.sshCmd,
|
|
89
|
-
[
|
|
92
|
+
[
|
|
93
|
+
"-t",
|
|
94
|
+
"devshell",
|
|
95
|
+
`--uid ${this.uid}`,
|
|
96
|
+
isUserApp ? "--userapp" : "",
|
|
97
|
+
appId,
|
|
98
|
+
"/lzcapp/pkg/content/devshell/exec.sh",
|
|
99
|
+
],
|
|
90
100
|
{
|
|
91
101
|
shell: true,
|
|
92
102
|
stdio: "inherit",
|
package/lib/app/lpk_devshell.js
CHANGED
|
@@ -15,12 +15,12 @@ import {
|
|
|
15
15
|
md5File,
|
|
16
16
|
loadFromYaml,
|
|
17
17
|
FileLocker,
|
|
18
|
+
isUserApp,
|
|
18
19
|
} from "../utils.js";
|
|
19
20
|
import os from "node:os";
|
|
20
21
|
import commandExists from "command-exists";
|
|
21
22
|
import chokidar from "chokidar";
|
|
22
23
|
import _ from "lodash";
|
|
23
|
-
import { getUidByManifest } from "../lzc_sdk.js";
|
|
24
24
|
import { DebugBridge } from "./lpk_debug_bridge.js";
|
|
25
25
|
import shellApi from "../shellapi.js";
|
|
26
26
|
|
|
@@ -107,16 +107,16 @@ export class AppDevShell {
|
|
|
107
107
|
this.lpkBuild = lpkBuild;
|
|
108
108
|
this.monitor = undefined;
|
|
109
109
|
this.forceBuild = forceBuild;
|
|
110
|
+
this.isUserApp = false;
|
|
110
111
|
}
|
|
111
112
|
|
|
112
113
|
async init() {
|
|
113
114
|
const manifest = await this.lpkBuild.getManifest();
|
|
114
|
-
const uid = await getUidByManifest(manifest);
|
|
115
115
|
this.monitor = await new AppDevShellMonitor(
|
|
116
116
|
this.cwd,
|
|
117
|
-
manifest["package"]
|
|
118
|
-
uid
|
|
117
|
+
manifest["package"]
|
|
119
118
|
).init();
|
|
119
|
+
this.isUserApp = isUserApp(manifest);
|
|
120
120
|
}
|
|
121
121
|
|
|
122
122
|
async build() {
|
|
@@ -337,8 +337,7 @@ export class AppDevShell {
|
|
|
337
337
|
logger.debug(err);
|
|
338
338
|
}
|
|
339
339
|
|
|
340
|
-
const
|
|
341
|
-
const devshell = new DevShell(pkgId, uid);
|
|
340
|
+
const devshell = new DevShell(pkgId, this.isUserApp);
|
|
342
341
|
if (isSync) {
|
|
343
342
|
await devshell.shell();
|
|
344
343
|
} else {
|
|
@@ -352,9 +351,9 @@ export class AppDevShell {
|
|
|
352
351
|
}
|
|
353
352
|
|
|
354
353
|
class DevShell {
|
|
355
|
-
constructor(appId,
|
|
354
|
+
constructor(appId, isUserApp) {
|
|
356
355
|
this.appId = appId;
|
|
357
|
-
this.
|
|
356
|
+
this.isUserApp = isUserApp;
|
|
358
357
|
}
|
|
359
358
|
|
|
360
359
|
async syncProject(appId) {
|
|
@@ -377,7 +376,10 @@ class DevShell {
|
|
|
377
376
|
}
|
|
378
377
|
|
|
379
378
|
const rsyncDebug = process.env.RSYNCDEBUG ? "-P" : "";
|
|
380
|
-
const
|
|
379
|
+
const host = this.isUserApp
|
|
380
|
+
? `${shellApi.uid}.app.${appId}.lzcapp`
|
|
381
|
+
: `app.${appId}.lzcapp`;
|
|
382
|
+
const dest = `root@${host}:/lzcapp/cache/devshell`;
|
|
381
383
|
try {
|
|
382
384
|
execSync(
|
|
383
385
|
`rsync ${rsyncDebug} --rsh='${rsh}' --recursive --relative --perms --update --filter=':- .gitignore' --ignore-errors --usermap=:nobody --groupmap=*:nobody . ${dest}`,
|
|
@@ -466,6 +468,6 @@ class DevShell {
|
|
|
466
468
|
|
|
467
469
|
async connectShell() {
|
|
468
470
|
const bridge = new DebugBridge();
|
|
469
|
-
await bridge.devshell(this.appId);
|
|
471
|
+
await bridge.devshell(this.appId, this.isUserApp);
|
|
470
472
|
}
|
|
471
473
|
}
|
package/lib/utils.js
CHANGED
|
@@ -294,3 +294,7 @@ export function isValidPackageName(packageName) {
|
|
|
294
294
|
const regex = new RegExp("^(?:[a-z][a-z0-9_]*\\.)+[a-z][a-z0-9_]*$");
|
|
295
295
|
return regex.test(packageName);
|
|
296
296
|
}
|
|
297
|
+
|
|
298
|
+
export function isUserApp(manifest) {
|
|
299
|
+
return !!manifest["application"]["user_app"];
|
|
300
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lazycatcloud/lzc-cli",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.2",
|
|
4
4
|
"description": "lazycat cloud developer kit",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "tap",
|
|
@@ -15,8 +15,7 @@
|
|
|
15
15
|
"files": [
|
|
16
16
|
"template",
|
|
17
17
|
"scripts",
|
|
18
|
-
"lib"
|
|
19
|
-
"cmds"
|
|
18
|
+
"lib"
|
|
20
19
|
],
|
|
21
20
|
"bin": {
|
|
22
21
|
"lzc-cli": "./scripts/cli.js"
|
package/template/_lpk/exec.sh
CHANGED
package/lib/lzc_sdk.js
DELETED
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
import grpc from "@grpc/grpc-js";
|
|
2
|
-
import protoLoader from "@grpc/proto-loader";
|
|
3
|
-
import { contextDirname } from "./utils.js";
|
|
4
|
-
import path from "node:path";
|
|
5
|
-
import env from "./env.js";
|
|
6
|
-
import logger from "loglevel";
|
|
7
|
-
import os from "node:os";
|
|
8
|
-
import fs from "node:fs";
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* @link {https://www.npmjs.com/package/appdirs}
|
|
12
|
-
*/
|
|
13
|
-
function getShellAPIConfigDir() {
|
|
14
|
-
const home = os.homedir();
|
|
15
|
-
const isMacos = process.platform == "darwin";
|
|
16
|
-
let sufix = "/.config/hportal-client";
|
|
17
|
-
if (isMacos) {
|
|
18
|
-
sufix = "/Library/Application Support/hportal-client";
|
|
19
|
-
} // TODO: need reimpl fetch windows
|
|
20
|
-
const SHELLAPI_CONFIG_DIR = path.join(home, sufix);
|
|
21
|
-
return SHELLAPI_CONFIG_DIR;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const coreDefinition = protoLoader.loadSync(
|
|
25
|
-
path.join(contextDirname(), "./shellapi.proto"),
|
|
26
|
-
{
|
|
27
|
-
keepCase: true,
|
|
28
|
-
longs: String,
|
|
29
|
-
enums: String,
|
|
30
|
-
defaults: true,
|
|
31
|
-
oneofs: true,
|
|
32
|
-
}
|
|
33
|
-
);
|
|
34
|
-
const core =
|
|
35
|
-
grpc.loadPackageDefinition(coreDefinition).space.heiyu.hportal.shell;
|
|
36
|
-
|
|
37
|
-
let client;
|
|
38
|
-
|
|
39
|
-
function readShellApiInfo() {
|
|
40
|
-
const SHELLAPI_CONFIG_DIR = getShellAPIConfigDir();
|
|
41
|
-
const addr = fs.readFileSync(
|
|
42
|
-
path.resolve(SHELLAPI_CONFIG_DIR, "shellapi_addr"),
|
|
43
|
-
{ encoding: "utf-8" }
|
|
44
|
-
);
|
|
45
|
-
const cred = fs.readFileSync(
|
|
46
|
-
path.resolve(SHELLAPI_CONFIG_DIR, "shellapi_cred"),
|
|
47
|
-
{ encoding: "utf-8" }
|
|
48
|
-
);
|
|
49
|
-
return { addr, cred };
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export async function getUidByManifest(manifest) {
|
|
53
|
-
if (!manifest["application"]["user_app"]) {
|
|
54
|
-
return "";
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const { addr, cred } = readShellApiInfo();
|
|
58
|
-
|
|
59
|
-
if (!client) {
|
|
60
|
-
client = new core.ShellCore(addr, grpc.credentials.createInsecure());
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const metadata = new grpc.Metadata();
|
|
64
|
-
metadata.add("lzc-shellapi-cred", cred);
|
|
65
|
-
|
|
66
|
-
const boxName = env.get("DEFAULT_BOXNAME");
|
|
67
|
-
return new Promise((resolve, reject) => {
|
|
68
|
-
client.queryBoxList({}, metadata, function (err, response) {
|
|
69
|
-
if (err) {
|
|
70
|
-
reject(err);
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
for (let box of response.boxes) {
|
|
74
|
-
if (box.box_name == boxName) {
|
|
75
|
-
logger.debug("当前登录用户: ", box.login_user);
|
|
76
|
-
resolve(box.login_user);
|
|
77
|
-
return;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
reject("没有默认盒子信息");
|
|
81
|
-
});
|
|
82
|
-
});
|
|
83
|
-
}
|