@lazycatcloud/lzc-cli 1.1.7 → 1.1.9
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 +69 -11
- package/lib/api.js +71 -36
- package/lib/app/index.js +79 -23
- package/lib/app/lpk_build.js +96 -52
- package/lib/app/lpk_create.js +63 -41
- package/lib/app/lpk_create_generator.js +202 -0
- package/lib/app/lpk_devshell.js +393 -328
- package/lib/app/lpk_devshell_docker.js +211 -0
- package/lib/app/lpk_installer.js +63 -26
- package/lib/app/lpk_log.js +68 -0
- package/lib/app/lpk_status.js +18 -0
- package/lib/app/lpk_uninstall.js +19 -0
- package/lib/appstore/index.js +37 -0
- package/lib/appstore/login.js +137 -0
- package/lib/appstore/publish.js +62 -0
- package/lib/autologin.js +0 -80
- package/lib/box/api/clientapi.js +1322 -0
- package/lib/box/api/empty.js +35 -0
- package/lib/box/check_qemu.js +1 -0
- package/lib/box/index.js +41 -94
- package/lib/box/qemu_vm_mgr.js +208 -239
- package/lib/box/schemes/vm_box_system_debian.json +1 -1
- package/lib/docker-compose.js +1 -2
- package/lib/env.js +23 -142
- package/lib/key.js +1 -0
- package/lib/sdk.js +10 -25
- package/lib/utils.js +156 -233
- package/package.json +19 -11
- package/scripts/cli.js +14 -135
- package/template/_lpk/README.md +31 -0
- package/template/_lpk/exec.sh +19 -0
- package/template/_lpk/golang.manifest.yml.in +16 -0
- package/template/_lpk/lazycat.png +0 -0
- package/template/_lpk/lite.manifest.yml.in +19 -0
- package/template/_lpk/local_devshell/Dockerfile +16 -0
- package/template/_lpk/local_devshell/build.sh +5 -0
- package/template/_lpk/local_devshell/entrypoint.sh +87 -0
- package/template/{_lazycat/debug/shell → _lpk/local_devshell}/sshd_config +8 -8
- package/template/_lpk/manifest.yml.in +0 -1
- package/template/{vue/lzc-build.yml → _lpk/vue.lzc-build.yml.in} +9 -1
- package/template/golang/README.md +0 -2
- package/template/golang/_gitignore +2 -0
- package/template/golang/build.sh +6 -0
- package/template/golang/lazycat.png +0 -0
- package/template/golang/lzc-build.yml +9 -1
- package/template/golang/rego.go +15 -16
- package/template/golang/rego_test.go +13 -0
- package/template/ionic_vue3/lazycat.png +0 -0
- package/template/ionic_vue3/lzc-build.yml +9 -1
- package/template/lite/error_pages/502.html.tpl +13 -0
- package/template/lite/lazycat.png +0 -0
- package/template/lite/lzc-build.yml +60 -0
- package/cmds/app.js +0 -133
- package/cmds/config.js +0 -55
- package/cmds/create.js +0 -55
- package/cmds/dev.js +0 -130
- package/cmds/init.js +0 -125
- package/cmds/log.js +0 -103
- package/cmds/publish.js +0 -116
- package/lib/archiver.js +0 -105
- package/lib/box/hportal.js +0 -120
- package/lib/builder.js +0 -313
- package/lib/dev.js +0 -314
- package/lib/generator.js +0 -146
- package/template/_lazycat/_gitignore +0 -1
- package/template/_lazycat/app-config +0 -1
- package/template/_lazycat/debug/devforward/50x.html +0 -30
- package/template/_lazycat/debug/devforward/Dockerfile +0 -16
- package/template/_lazycat/debug/devforward/docker-compose.override.yml.in +0 -11
- package/template/_lazycat/debug/devforward/entrypoint.sh +0 -10
- package/template/_lazycat/debug/devforward/nginx.conf.template +0 -56
- package/template/_lazycat/debug/devforward/sshd_config +0 -116
- package/template/_lazycat/debug/shell/50x.html +0 -32
- package/template/_lazycat/debug/shell/Dockerfile +0 -18
- package/template/_lazycat/debug/shell/build.sh +0 -15
- package/template/_lazycat/debug/shell/docker-compose.override.yml.in +0 -13
- package/template/_lazycat/debug/shell/entrypoint.sh +0 -12
- package/template/_lazycat/docker-compose.yml.in +0 -15
- package/template/_lazycat/icon.svg +0 -1
- package/template/_lazycat/screenshot.png +0 -0
- package/template/_lpk/sync/Dockerfile +0 -16
- package/template/_lpk/sync/build.sh +0 -5
- package/template/_lpk/sync/entrypoint.sh +0 -8
- package/template/_lpk/sync/sshd_config +0 -117
- package/template/_lpk/sync.manifest.yml.in +0 -3
- package/template/release/golang/Dockerfile +0 -18
- package/template/release/golang/build.sh +0 -13
- package/template/release/ionic_vue3/Dockerfile +0 -10
- package/template/release/ionic_vue3/build.sh +0 -7
- package/template/release/ionic_vue3/docker-compose.yml.in +0 -3
- package/template/release/vue/Dockerfile +0 -10
- package/template/release/vue/build.sh +0 -10
- package/template/release/vue/docker-compose.yml.in +0 -3
- package/template/vue/README.md +0 -29
- package/template/vue/_dockerignore +0 -1
- package/template/vue/babel.config.js +0 -3
- package/template/vue/package.json +0 -43
- package/template/vue/public/favicon.ico +0 -0
- package/template/vue/public/index.html +0 -33
- package/template/vue/src/App.vue +0 -39
- package/template/vue/src/main.js +0 -8
- package/template/vue/src/todo.vue +0 -640
- package/template/vue/src/top-bar.vue +0 -100
- package/template/vue/src/webdav.vue +0 -183
- package/template/vue/vue.config.js +0 -21
package/lib/utils.js
CHANGED
|
@@ -1,136 +1,36 @@
|
|
|
1
1
|
import path from "path";
|
|
2
2
|
import fs from "fs";
|
|
3
|
-
import { mkdtemp } from "fs/promises";
|
|
4
3
|
import os from "os";
|
|
5
|
-
import chalk from "chalk";
|
|
6
|
-
import archiver from "archiver";
|
|
7
4
|
import glob from "fast-glob";
|
|
8
5
|
import yaml from "js-yaml";
|
|
9
6
|
import mergeWith from "lodash.mergewith";
|
|
10
|
-
import isArray from "lodash.isarray";
|
|
11
|
-
import { request } from "./autologin.js";
|
|
12
7
|
import { dirname } from "path";
|
|
13
8
|
import { fileURLToPath } from "url";
|
|
14
9
|
import ignore from "ignore";
|
|
15
|
-
import
|
|
16
|
-
import
|
|
17
|
-
import
|
|
18
|
-
import
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const
|
|
10
|
+
import { createHash, randomBytes } from "node:crypto";
|
|
11
|
+
import https from "node:https";
|
|
12
|
+
import http from "node:http";
|
|
13
|
+
import zlib from "node:zlib";
|
|
14
|
+
import process from "node:process";
|
|
15
|
+
import { spawnSync } from "node:child_process";
|
|
16
|
+
import logger from "loglevel";
|
|
17
|
+
|
|
18
|
+
export const APP_FOLDER = ".lazycat";
|
|
19
|
+
export const APP_CONFIG_FILE = "app-config";
|
|
20
|
+
export const APP_SDK_HOSTNAME = "box";
|
|
24
21
|
export const GLOBAL_CONFIG_DIR = path.join(os.homedir(), "/.config/lazycat");
|
|
25
22
|
|
|
26
23
|
export const envsubstr = async (templateContents, args) => {
|
|
27
24
|
const parse = await importDefault("envsub/js/envsub-parser.js");
|
|
28
25
|
return parse(templateContents, args);
|
|
29
26
|
};
|
|
30
|
-
/**
|
|
31
|
-
* 为盒子安装SDK应用
|
|
32
|
-
* @param box_url 盒子入口地址
|
|
33
|
-
**/
|
|
34
|
-
async function InstallSDK(box_url) {
|
|
35
|
-
try {
|
|
36
|
-
let url = `${box_url}/api/app/apply?id=sdk`;
|
|
37
|
-
const resp = await request(url, { method: "post" });
|
|
38
|
-
if (resp.status != 200) {
|
|
39
|
-
throw new Error(
|
|
40
|
-
chalk.red(
|
|
41
|
-
`无法安装, 请确保 ${chalk.yellow(
|
|
42
|
-
new URL(url).origin
|
|
43
|
-
)} 可以访问或者在应用商店安装 sdk`
|
|
44
|
-
)
|
|
45
|
-
);
|
|
46
|
-
}
|
|
47
|
-
} catch (err) {
|
|
48
|
-
throw err;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* 检查SDK安装部署的状态
|
|
53
|
-
* @param box_url 盒子入口地址
|
|
54
|
-
**/
|
|
55
|
-
async function checkSDKInstallStatus(box_url) {
|
|
56
|
-
const checkSDKstatus = async function (box_url) {
|
|
57
|
-
let url = `${box_url}/api/app/status?id=sdk`;
|
|
58
|
-
const resp = await request(url);
|
|
59
|
-
if (resp.status == 200) {
|
|
60
|
-
const status = await resp.json();
|
|
61
|
-
return status;
|
|
62
|
-
} else {
|
|
63
|
-
let text = await resp.text();
|
|
64
|
-
throw text;
|
|
65
|
-
}
|
|
66
|
-
};
|
|
67
|
-
const spinner = ora().start();
|
|
68
|
-
let { status, info } = await checkSDKstatus(box_url);
|
|
69
|
-
spinner.text = "部署进度";
|
|
70
|
-
switch (status) {
|
|
71
|
-
case "running":
|
|
72
|
-
console.log(chalk.yellow("应用正在运行中"));
|
|
73
|
-
break;
|
|
74
|
-
case "error":
|
|
75
|
-
spinner.stop();
|
|
76
|
-
console.log(status, info);
|
|
77
|
-
throw info.msg;
|
|
78
|
-
default:
|
|
79
|
-
try {
|
|
80
|
-
await desireStatusTimer(
|
|
81
|
-
(result) => {
|
|
82
|
-
spinner.text = "部署进度 " + result.status;
|
|
83
|
-
return result.status === "running";
|
|
84
|
-
},
|
|
85
|
-
() => {
|
|
86
|
-
return checkSDKstatus(box_url);
|
|
87
|
-
}
|
|
88
|
-
);
|
|
89
|
-
} catch (error) {
|
|
90
|
-
throw error;
|
|
91
|
-
} finally {
|
|
92
|
-
spinner.stop();
|
|
93
|
-
}
|
|
94
|
-
break;
|
|
95
|
-
}
|
|
96
|
-
spinner.stop();
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* 获取所有已安装的app
|
|
101
|
-
* @param box_url 盒子入口地址
|
|
102
|
-
**/
|
|
103
|
-
async function getInstalledApps(box_url) {
|
|
104
|
-
try {
|
|
105
|
-
let url = `${box_url}/api/app/dump`;
|
|
106
|
-
const resp = await request(url);
|
|
107
|
-
if (resp.status != 200) throw new Error(chalk.red("获取所有已安装App失败"));
|
|
108
|
-
return await resp.json();
|
|
109
|
-
} catch (e) {
|
|
110
|
-
console.log(e);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
/**
|
|
114
|
-
* 查找某个app是否已安装]
|
|
115
|
-
* @param box_url 盒子入口地址
|
|
116
|
-
* @param app_id app名
|
|
117
|
-
* */
|
|
118
|
-
async function findAppIsInstalled(box_url, app_id) {
|
|
119
|
-
const apps = await getInstalledApps(box_url);
|
|
120
|
-
for (let app in apps) {
|
|
121
|
-
if (app == app_id) {
|
|
122
|
-
return true;
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
return false;
|
|
126
|
-
}
|
|
127
27
|
|
|
128
28
|
/**
|
|
129
29
|
* 确保文件夹存在
|
|
130
30
|
* @param filePath {string} 如果为文件路径 确保其文件夹存在; 如果为文件夹, 则确保该文件夹存在
|
|
131
31
|
*
|
|
132
32
|
*/
|
|
133
|
-
function ensureDir(filePath) {
|
|
33
|
+
export function ensureDir(filePath) {
|
|
134
34
|
let dirPath;
|
|
135
35
|
if (filePath.endsWith("/")) {
|
|
136
36
|
dirPath = filePath;
|
|
@@ -142,11 +42,11 @@ function ensureDir(filePath) {
|
|
|
142
42
|
}
|
|
143
43
|
}
|
|
144
44
|
|
|
145
|
-
function loadFromYaml(file) {
|
|
45
|
+
export function loadFromYaml(file) {
|
|
146
46
|
return yaml.load(fs.readFileSync(file, "utf8"));
|
|
147
47
|
}
|
|
148
48
|
|
|
149
|
-
function dumpToYaml(template, target) {
|
|
49
|
+
export function dumpToYaml(template, target) {
|
|
150
50
|
fs.writeFileSync(
|
|
151
51
|
target,
|
|
152
52
|
yaml.dump(template, {
|
|
@@ -157,42 +57,10 @@ function dumpToYaml(template, target) {
|
|
|
157
57
|
);
|
|
158
58
|
}
|
|
159
59
|
|
|
160
|
-
function
|
|
161
|
-
function doCheck(next = true) {
|
|
162
|
-
const files = ["docker-compose.yml", "docker-compose.yml.in"];
|
|
163
|
-
for (let f of files) {
|
|
164
|
-
const composeFile = path.join(appDir, f);
|
|
165
|
-
if (fs.existsSync(composeFile)) {
|
|
166
|
-
const doc = yaml.load(fs.readFileSync(composeFile, "utf8"));
|
|
167
|
-
if (doc[META_MARK]) {
|
|
168
|
-
return { appDir, isTemplate: f == "docker-compose.yml.in" };
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
if (next) {
|
|
173
|
-
appDir = path.join(appDir, APP_FOLDER);
|
|
174
|
-
return doCheck(false);
|
|
175
|
-
}
|
|
176
|
-
return { appDir: false, isTemplate: false };
|
|
177
|
-
}
|
|
178
|
-
return doCheck();
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
// find any valid app path till root folder
|
|
182
|
-
function findAppRootPath(aPath) {
|
|
183
|
-
const sep = "/";
|
|
184
|
-
const folders = aPath.split(sep);
|
|
185
|
-
for (let i = folders.length; i >= 0; i--) {
|
|
186
|
-
if (folders[i] == APP_FOLDER) {
|
|
187
|
-
return folders.slice(0, i + 1).join(sep);
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
return false;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
function toPair(object) {
|
|
60
|
+
export function toPair(object) {
|
|
194
61
|
return Object.keys(object).map((key) => {
|
|
195
62
|
let value = object[key] ? object[key].toString() : "";
|
|
63
|
+
key = key.replaceAll("-", "_");
|
|
196
64
|
return {
|
|
197
65
|
name: key,
|
|
198
66
|
value,
|
|
@@ -200,12 +68,7 @@ function toPair(object) {
|
|
|
200
68
|
});
|
|
201
69
|
}
|
|
202
70
|
|
|
203
|
-
function
|
|
204
|
-
const doc = yaml.load(fs.readFileSync(composeFile, "utf8"));
|
|
205
|
-
return doc[META_MARK];
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
async function envTemplateFile(templateFile, env) {
|
|
71
|
+
export async function envTemplateFile(templateFile, env) {
|
|
209
72
|
const template = yaml.load(fs.readFileSync(templateFile, "utf8"));
|
|
210
73
|
const options = {
|
|
211
74
|
envs: toPair(env),
|
|
@@ -222,12 +85,12 @@ async function envTemplateFile(templateFile, env) {
|
|
|
222
85
|
);
|
|
223
86
|
}
|
|
224
87
|
|
|
225
|
-
async function createTemplateFile(templateFile, outputFile, env) {
|
|
88
|
+
export async function createTemplateFile(templateFile, outputFile, env) {
|
|
226
89
|
let output = await envTemplateFile(templateFile, env);
|
|
227
90
|
fs.writeFileSync(outputFile, output);
|
|
228
91
|
}
|
|
229
92
|
|
|
230
|
-
async function createTemplateFileCommon(templateFile, outputFile, env) {
|
|
93
|
+
export async function createTemplateFileCommon(templateFile, outputFile, env) {
|
|
231
94
|
const template = yaml.load(fs.readFileSync(templateFile, "utf8"));
|
|
232
95
|
const options = {
|
|
233
96
|
envs: toPair(env),
|
|
@@ -240,8 +103,17 @@ async function createTemplateFileCommon(templateFile, outputFile, env) {
|
|
|
240
103
|
fs.writeFileSync(outputFile, output);
|
|
241
104
|
}
|
|
242
105
|
|
|
106
|
+
export async function envsubstrDefault(templateContents, env) {
|
|
107
|
+
const options = {
|
|
108
|
+
envs: toPair(env),
|
|
109
|
+
syntax: "default",
|
|
110
|
+
protect: false,
|
|
111
|
+
};
|
|
112
|
+
return envsubstr(templateContents, { options });
|
|
113
|
+
}
|
|
114
|
+
|
|
243
115
|
// this will copy current app to a tmp dir
|
|
244
|
-
async function copyDotAppDir(from, to, opts = {}) {
|
|
116
|
+
export async function copyDotAppDir(from, to, opts = {}) {
|
|
245
117
|
const {
|
|
246
118
|
include = [],
|
|
247
119
|
ignore = ["app-config", "output", "box-config.json"],
|
|
@@ -278,7 +150,7 @@ async function copyDotAppDir(from, to, opts = {}) {
|
|
|
278
150
|
}
|
|
279
151
|
}
|
|
280
152
|
|
|
281
|
-
function mergeYamlInMemory(args) {
|
|
153
|
+
export function mergeYamlInMemory(args) {
|
|
282
154
|
if (args.length == 0) {
|
|
283
155
|
return {};
|
|
284
156
|
} else if (args.length == 1) {
|
|
@@ -286,7 +158,7 @@ function mergeYamlInMemory(args) {
|
|
|
286
158
|
}
|
|
287
159
|
return args.reduce((prev, curr) => {
|
|
288
160
|
let result = mergeWith(prev, curr, (objValue, srcValue) => {
|
|
289
|
-
if (isArray(objValue)) {
|
|
161
|
+
if (Array.isArray(objValue)) {
|
|
290
162
|
return objValue.concat(srcValue);
|
|
291
163
|
}
|
|
292
164
|
});
|
|
@@ -295,14 +167,14 @@ function mergeYamlInMemory(args) {
|
|
|
295
167
|
}
|
|
296
168
|
|
|
297
169
|
// override yaml, notice this will change target file
|
|
298
|
-
function mergeYaml(target, source) {
|
|
170
|
+
export function mergeYaml(target, source) {
|
|
299
171
|
const targetContent = yaml.load(fs.readFileSync(target, "utf8"));
|
|
300
172
|
const sourceContent = yaml.load(fs.readFileSync(source, "utf8"));
|
|
301
173
|
const merged = mergeWith(
|
|
302
174
|
targetContent,
|
|
303
175
|
sourceContent,
|
|
304
176
|
(objValue, srcValue) => {
|
|
305
|
-
if (isArray(objValue)) {
|
|
177
|
+
if (Array.isArray(objValue)) {
|
|
306
178
|
return objValue.concat(srcValue);
|
|
307
179
|
}
|
|
308
180
|
}
|
|
@@ -310,44 +182,16 @@ function mergeYaml(target, source) {
|
|
|
310
182
|
dumpToYaml(merged, target);
|
|
311
183
|
}
|
|
312
184
|
|
|
313
|
-
function
|
|
314
|
-
return new Promise(async (resolve, reject) => {
|
|
315
|
-
if (!fs.existsSync(appDir)) {
|
|
316
|
-
reject(new Error("folder does not exist"));
|
|
317
|
-
return;
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
const tempDir = await mkdtemp(path.join(os.tmpdir(), "hc-"));
|
|
321
|
-
const out = path.join(tempDir, "app." + format);
|
|
322
|
-
|
|
323
|
-
// console.log(chalk.green("start archive app ..."));
|
|
324
|
-
const output = fs.createWriteStream(out);
|
|
325
|
-
const archive = archiver(format);
|
|
326
|
-
|
|
327
|
-
archive.on("error", (e) => {
|
|
328
|
-
reject(e);
|
|
329
|
-
// console.log(e);
|
|
330
|
-
});
|
|
331
|
-
archive.on("end", () => {
|
|
332
|
-
resolve(output);
|
|
333
|
-
});
|
|
334
|
-
archive.pipe(output);
|
|
335
|
-
|
|
336
|
-
archive.directory(appDir, false);
|
|
337
|
-
archive.finalize();
|
|
338
|
-
});
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
function contextDirname(url = import.meta.url) {
|
|
185
|
+
export function contextDirname(url = import.meta.url) {
|
|
342
186
|
return dirname(fileURLToPath(url));
|
|
343
187
|
}
|
|
344
188
|
|
|
345
|
-
async function importDefault(pkgPath) {
|
|
189
|
+
export async function importDefault(pkgPath) {
|
|
346
190
|
let mod = await import(pkgPath);
|
|
347
191
|
return mod.default;
|
|
348
192
|
}
|
|
349
193
|
|
|
350
|
-
class GitIgnore {
|
|
194
|
+
export class GitIgnore {
|
|
351
195
|
constructor(root) {
|
|
352
196
|
this.root = root;
|
|
353
197
|
this.ignores = [];
|
|
@@ -385,12 +229,12 @@ class GitIgnore {
|
|
|
385
229
|
}
|
|
386
230
|
}
|
|
387
231
|
|
|
388
|
-
function isDirSync(path) {
|
|
232
|
+
export function isDirSync(path) {
|
|
389
233
|
let stat = fs.statSync(path);
|
|
390
234
|
return stat.isDirectory();
|
|
391
235
|
}
|
|
392
236
|
|
|
393
|
-
function isDirExist(path) {
|
|
237
|
+
export function isDirExist(path) {
|
|
394
238
|
try {
|
|
395
239
|
return isDirSync(path);
|
|
396
240
|
} catch {
|
|
@@ -398,7 +242,7 @@ function isDirExist(path) {
|
|
|
398
242
|
}
|
|
399
243
|
}
|
|
400
244
|
|
|
401
|
-
function isFileExist(path) {
|
|
245
|
+
export function isFileExist(path) {
|
|
402
246
|
try {
|
|
403
247
|
fs.accessSync(
|
|
404
248
|
path,
|
|
@@ -410,60 +254,139 @@ function isFileExist(path) {
|
|
|
410
254
|
}
|
|
411
255
|
}
|
|
412
256
|
|
|
413
|
-
function urlHostname(url) {
|
|
257
|
+
export function urlHostname(url) {
|
|
414
258
|
let u = new URL(url);
|
|
415
259
|
return u.hostname;
|
|
416
260
|
}
|
|
417
261
|
|
|
418
262
|
// REVIEW: 用户输入的app-id 空格替换为减号并且转换为全小写。
|
|
419
263
|
// 这会影响默认的app-name,因为app-name的默认值依赖app-id,但是如果特定输入了app-name则正常
|
|
420
|
-
function parse2CorrectName(name) {
|
|
264
|
+
export function parse2CorrectName(name) {
|
|
421
265
|
return name.replaceAll(" ", "-").toLowerCase();
|
|
422
266
|
}
|
|
423
267
|
|
|
424
|
-
async function sleep(ms) {
|
|
268
|
+
export async function sleep(ms) {
|
|
425
269
|
return new Promise((resolve) => {
|
|
426
270
|
setTimeout(resolve, ms);
|
|
427
271
|
});
|
|
428
272
|
}
|
|
429
273
|
|
|
430
|
-
async function md5String(str) {
|
|
274
|
+
export async function md5String(str) {
|
|
431
275
|
const hash = createHash("md5");
|
|
432
276
|
hash.update(str);
|
|
433
277
|
return hash.digest("hex");
|
|
434
278
|
}
|
|
435
279
|
|
|
436
|
-
export {
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
280
|
+
export async function md5File(filepath) {
|
|
281
|
+
const hash = createHash("md5");
|
|
282
|
+
const input = fs.createReadStream(filepath);
|
|
283
|
+
return new Promise((resolve) => {
|
|
284
|
+
input.on("readable", () => {
|
|
285
|
+
const data = input.read();
|
|
286
|
+
if (data) {
|
|
287
|
+
hash.update(data);
|
|
288
|
+
} else {
|
|
289
|
+
resolve(hash.digest("hex"));
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
export class Downloader {
|
|
296
|
+
constructor() {}
|
|
297
|
+
|
|
298
|
+
showDownloadingProgress(received, total) {
|
|
299
|
+
let percentage = ((received * 100) / total).toFixed(2);
|
|
300
|
+
process.stdout.write("\r");
|
|
301
|
+
process.stdout.write(
|
|
302
|
+
percentage +
|
|
303
|
+
"% | " +
|
|
304
|
+
received +
|
|
305
|
+
" bytes downloaded out of " +
|
|
306
|
+
total +
|
|
307
|
+
" bytes."
|
|
308
|
+
);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
download(url, savePath, enableGzip = false) {
|
|
312
|
+
let tmpPath = savePath + ".tmp";
|
|
313
|
+
const options = new URL(url);
|
|
314
|
+
let request = url.startsWith("https") ? https.request : http.request;
|
|
315
|
+
|
|
316
|
+
return new Promise((resolve, reject) => {
|
|
317
|
+
const req = request(options, (res) => {
|
|
318
|
+
if (res.statusCode != 200) {
|
|
319
|
+
reject(`下载 ${url} 失败`);
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
let total = parseInt(res.headers["content-length"]);
|
|
324
|
+
let recive = 0;
|
|
325
|
+
res.on("data", (chunk) => {
|
|
326
|
+
recive += chunk.length;
|
|
327
|
+
this.showDownloadingProgress(recive, total);
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
let outputFile = fs.createWriteStream(tmpPath, { flags: "w+" });
|
|
331
|
+
if (enableGzip) {
|
|
332
|
+
let decoder = zlib.createUnzip();
|
|
333
|
+
res.pipe(decoder).pipe(outputFile);
|
|
334
|
+
} else {
|
|
335
|
+
res.pipe(outputFile);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
outputFile.on("error", reject);
|
|
339
|
+
outputFile.on("finish", () => {
|
|
340
|
+
fs.renameSync(tmpPath, savePath);
|
|
341
|
+
process.stdout.write("\n");
|
|
342
|
+
resolve();
|
|
343
|
+
});
|
|
344
|
+
});
|
|
345
|
+
req.on("error", reject);
|
|
346
|
+
req.end();
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
export function randomString(length = 4) {
|
|
352
|
+
return randomBytes(length).toString("hex");
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
export class FileLocker {
|
|
356
|
+
constructor(id) {
|
|
357
|
+
this.filename = undefined;
|
|
358
|
+
this.fd = undefined;
|
|
359
|
+
this.id = id;
|
|
360
|
+
}
|
|
361
|
+
lock() {
|
|
362
|
+
this.filename = path.resolve(os.tmpdir(), "lzc-cli-file-lock", this.id);
|
|
363
|
+
ensureDir(this.filename);
|
|
364
|
+
|
|
365
|
+
try {
|
|
366
|
+
this.fd = fs.openSync(this.filename, "wx+");
|
|
367
|
+
} catch (e) {
|
|
368
|
+
if (e.code == "EEXIST" && !this.withOpen(this.filename)) {
|
|
369
|
+
logger.debug("filelock exist open with w+");
|
|
370
|
+
this.fd = fs.openSync(this.filename, "w+");
|
|
371
|
+
} else {
|
|
372
|
+
throw e;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
unlock() {
|
|
377
|
+
if (this.fd) {
|
|
378
|
+
fs.closeSync(this.fd);
|
|
379
|
+
fs.rmSync(this.filename);
|
|
380
|
+
this.fd = undefined;
|
|
381
|
+
this.filename = undefined;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
withOpen(filename) {
|
|
385
|
+
const p = spawnSync("lsof", ["-w", "-t", filename]);
|
|
386
|
+
if (p.status === 0) {
|
|
387
|
+
return true;
|
|
388
|
+
} else {
|
|
389
|
+
return false;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
}
|
package/package.json
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lazycatcloud/lzc-cli",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.9",
|
|
4
4
|
"description": "lazycat cloud developer kit",
|
|
5
5
|
"scripts": {
|
|
6
|
-
"
|
|
7
|
-
"
|
|
6
|
+
"postinstall": "cp .githooks/* .git/hooks/",
|
|
7
|
+
"test": "tap",
|
|
8
|
+
"snap": "tap"
|
|
8
9
|
},
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
"tap": {
|
|
11
|
+
"node-arg": [
|
|
12
|
+
"--loader=esmock",
|
|
13
|
+
"--experimental-vm-modules"
|
|
14
|
+
]
|
|
13
15
|
},
|
|
14
16
|
"files": [
|
|
15
17
|
"template",
|
|
@@ -28,7 +30,10 @@
|
|
|
28
30
|
"license": "ISC",
|
|
29
31
|
"dependencies": {
|
|
30
32
|
"@balena/dockerignore": "^1.0.2",
|
|
33
|
+
"@improbable-eng/grpc-web": "^0.15.0",
|
|
34
|
+
"@improbable-eng/grpc-web-node-http-transport": "^0.15.0",
|
|
31
35
|
"archiver": "^5.3.0",
|
|
36
|
+
"browser-headers": "^0.4.1",
|
|
32
37
|
"chalk": "^4.1.2",
|
|
33
38
|
"chokidar": "^3.5.3",
|
|
34
39
|
"command-exists": "^1.2.9",
|
|
@@ -43,8 +48,8 @@
|
|
|
43
48
|
"inquirer": "^8.2.0",
|
|
44
49
|
"isbinaryfile": "^4.0.8",
|
|
45
50
|
"js-yaml": "^4.1.0",
|
|
51
|
+
"lodash.debounce": "^4.0.8",
|
|
46
52
|
"lodash.get": "^4.4.2",
|
|
47
|
-
"lodash.isarray": "^4.0.0",
|
|
48
53
|
"lodash.merge": "^4.6.2",
|
|
49
54
|
"lodash.mergewith": "^4.6.2",
|
|
50
55
|
"log-update": "^5.0.0",
|
|
@@ -53,17 +58,20 @@
|
|
|
53
58
|
"node-fetch": "^2.6.6",
|
|
54
59
|
"node-stream-zip": "^1.15.0",
|
|
55
60
|
"ora": "^6.0.1",
|
|
61
|
+
"protobufjs": "^7.1.1",
|
|
62
|
+
"rxjs": "^7.5.6",
|
|
56
63
|
"semver": "^7.3.5",
|
|
57
64
|
"ssh2": "^1.5.0",
|
|
58
65
|
"ssh2-promise": "^1.0.2",
|
|
59
66
|
"tar": "^6.1.11",
|
|
67
|
+
"urllib": "^3.1.0",
|
|
60
68
|
"yargs": "^17.5.1"
|
|
61
69
|
},
|
|
62
70
|
"devDependencies": {
|
|
63
71
|
"@types/command-exists": "^1.2.0",
|
|
64
|
-
"
|
|
65
|
-
"
|
|
66
|
-
"
|
|
72
|
+
"esmock": "^2.0.0",
|
|
73
|
+
"prettier": "^2.5.0",
|
|
74
|
+
"tap": "^16.3.0"
|
|
67
75
|
},
|
|
68
76
|
"publishConfig": {
|
|
69
77
|
"registry": "https://registry.npmjs.org",
|