yj-deploy 0.0.6 → 0.0.7
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 +1 -0
- package/dist/yj-deploy.mjs +340 -0
- package/dist/yj-deploy.umd.js +8 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
var x = Object.defineProperty;
|
|
2
|
+
var L = (f, e, t) => e in f ? x(f, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : f[e] = t;
|
|
3
|
+
var $ = (f, e, t) => (L(f, typeof e != "symbol" ? e + "" : e, t), t);
|
|
4
|
+
const { stdout: v } = require("single-line-log"), F = require("path"), k = require("fs"), { Client: A } = require("ssh2");
|
|
5
|
+
module.exports = class {
|
|
6
|
+
constructor(e) {
|
|
7
|
+
$(this, "config", {
|
|
8
|
+
host: "",
|
|
9
|
+
port: "",
|
|
10
|
+
username: "",
|
|
11
|
+
password: "",
|
|
12
|
+
namespace: "",
|
|
13
|
+
// 项目命名空间,等同于镜像地址目录名称
|
|
14
|
+
imageStore: "dev-images",
|
|
15
|
+
// 镜像仓库
|
|
16
|
+
tmpName: "dev",
|
|
17
|
+
// 镜像环境
|
|
18
|
+
delay: 0,
|
|
19
|
+
// 延迟上传时间
|
|
20
|
+
// 本地文件目录(必填)
|
|
21
|
+
fileDir: "",
|
|
22
|
+
// 远程sftp服务根目录
|
|
23
|
+
rootDir: "/home/yjweb",
|
|
24
|
+
// dockerfile文件信息
|
|
25
|
+
dockerfile: {
|
|
26
|
+
name: "Dockerfile",
|
|
27
|
+
content: [
|
|
28
|
+
"FROM harbor.yunjingtech.cn:30002/yj-base/nginx:latest",
|
|
29
|
+
"RUN rm -rf /usr/share/nginx/html/*",
|
|
30
|
+
"COPY dist /usr/share/nginx/html/"
|
|
31
|
+
]
|
|
32
|
+
},
|
|
33
|
+
// upload.sh文件信息
|
|
34
|
+
upload: {
|
|
35
|
+
name: "upload.sh",
|
|
36
|
+
content: [
|
|
37
|
+
"#!/bin/sh",
|
|
38
|
+
"tag=`basename \\`pwd\\``:$2-`date +%Y%m%d`",
|
|
39
|
+
'echo "- 镜像仓库: $1"',
|
|
40
|
+
'echo "- 镜像环境: $2"',
|
|
41
|
+
"docker build -t harbor.yunjingtech.cn:30002/$1/$tag .",
|
|
42
|
+
"docker push harbor.yunjingtech.cn:30002/$1/$tag",
|
|
43
|
+
"echo - 镜像地址: harbor.yunjingtech.cn:30002/$1/$tag"
|
|
44
|
+
]
|
|
45
|
+
},
|
|
46
|
+
// 上传dist目录信息
|
|
47
|
+
dist: {
|
|
48
|
+
name: "dist"
|
|
49
|
+
},
|
|
50
|
+
parallelDir: 20,
|
|
51
|
+
// 文件夹并行创建数量,如果报错,可以减少此配置
|
|
52
|
+
parallelFile: 50,
|
|
53
|
+
// 文件并行上传数量,如果报错,可以减少此配置
|
|
54
|
+
allLog: !1,
|
|
55
|
+
// 是否显示全部日志
|
|
56
|
+
lazyUpload: !1
|
|
57
|
+
// 是否开启懒上传
|
|
58
|
+
});
|
|
59
|
+
$(this, "ssh2Conn", null);
|
|
60
|
+
// 上传状态
|
|
61
|
+
$(this, "uploading", !1);
|
|
62
|
+
// 定时器
|
|
63
|
+
$(this, "trim", null);
|
|
64
|
+
return this.config = Object.assign(this.config, e), {
|
|
65
|
+
name: "yj-deploy",
|
|
66
|
+
isPut: this.isPut.bind(this),
|
|
67
|
+
upload: this.upload.bind(this),
|
|
68
|
+
// webpack钩子
|
|
69
|
+
apply: this.apply.bind(this),
|
|
70
|
+
// vite上传钩子
|
|
71
|
+
closeBundle: this.isPut.bind(this)
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
// webpack钩子
|
|
75
|
+
apply(e) {
|
|
76
|
+
return e && e.hooks && e.hooks.done && e.hooks.done.tap("yj-deploy", () => {
|
|
77
|
+
this.isPut();
|
|
78
|
+
}), "build";
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* 判断是否需要上传,
|
|
82
|
+
* vite和 webpack环境在每次编译完都会触发当前方法
|
|
83
|
+
* 需要通过是否有命令行参数 --deploy
|
|
84
|
+
*/
|
|
85
|
+
isPut() {
|
|
86
|
+
this.getArgv("--deploy") != null && (clearTimeout(this.trim), this.trim = setTimeout(() => {
|
|
87
|
+
this.upload();
|
|
88
|
+
}, this.config.delay || 0));
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* 连接跳板机并开始上传
|
|
92
|
+
*/
|
|
93
|
+
upload() {
|
|
94
|
+
if (console.log("-------------- deploy-start --------------"), !this.config.host) {
|
|
95
|
+
console.log("- 请配置跳板机地址 host");
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
if (!this.config.port) {
|
|
99
|
+
console.log("- 请配置跳板机端口 port");
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
if (!this.config.username) {
|
|
103
|
+
console.log("- 请配置跳板机账号 username");
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
if (!this.config.password) {
|
|
107
|
+
console.log("- 请配置跳板机密码 password");
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
this.uploading || (this.ssh2Conn = new A(), this.ssh2Conn.on("ready", () => {
|
|
111
|
+
console.log("- 跳板机连接成功!"), this.ssh2Conn.sftp(async (e, t) => {
|
|
112
|
+
e && (console.log("- sftp连接失败"), this.breakConnect()), this.config.namespace || (console.log("- 请配置项目命名空间 namespace"), this.breakConnect()), this.uploading = !0, this.getArgv("--reset") !== void 0 && (console.log("- 重置项目"), await this.onShell(`rm -r ${this.config.rootDir}/${this.config.namespace}`)), this.upLoadProject(t, `${this.config.rootDir}/${this.config.namespace}`);
|
|
113
|
+
});
|
|
114
|
+
}).connect({
|
|
115
|
+
host: this.config.host,
|
|
116
|
+
port: this.config.port,
|
|
117
|
+
username: this.config.username,
|
|
118
|
+
password: this.config.password
|
|
119
|
+
}), this.ssh2Conn.on("error", (e) => {
|
|
120
|
+
console.log(`- 连接失败: ${e}`), this.breakConnect();
|
|
121
|
+
}), this.ssh2Conn.on("end", () => {
|
|
122
|
+
this.uploading = !1;
|
|
123
|
+
}));
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* 断开连接
|
|
127
|
+
*/
|
|
128
|
+
breakConnect() {
|
|
129
|
+
this.uploading = !1, console.log("- 已断开连接"), console.log("-------------- deploy-end --------------"), this.ssh2Conn.end();
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* 运行shell命令
|
|
133
|
+
* @param {*} shell
|
|
134
|
+
* @returns Promise
|
|
135
|
+
*/
|
|
136
|
+
onShell(e) {
|
|
137
|
+
const t = this.getArgv("--allLog") !== void 0;
|
|
138
|
+
return new Promise((i, s) => {
|
|
139
|
+
this.ssh2Conn.shell((n, l) => {
|
|
140
|
+
if (n) {
|
|
141
|
+
console.log("- 远程命令错误:" + n, e), this.breakConnect(), s(n);
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
let r = [];
|
|
145
|
+
l.on("close", () => {
|
|
146
|
+
i(r.toString());
|
|
147
|
+
}).on("data", (c) => {
|
|
148
|
+
let a = c.toString();
|
|
149
|
+
(t || this.config.allLog || a.startsWith("- ")) && r.push(`
|
|
150
|
+
` + a);
|
|
151
|
+
}).stderr.on("data", (c) => {
|
|
152
|
+
console.log(`- 远程命令错误:
|
|
153
|
+
` + c), this.breakConnect(), s(c);
|
|
154
|
+
}), l.end(e + `
|
|
155
|
+
exit
|
|
156
|
+
`);
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* 初始化项目
|
|
162
|
+
* @param {*} sftp
|
|
163
|
+
* @param {*} dir
|
|
164
|
+
*/
|
|
165
|
+
projectInit(e, t) {
|
|
166
|
+
return new Promise(async (i, s) => {
|
|
167
|
+
e.mkdir(t, async (n) => {
|
|
168
|
+
if (n)
|
|
169
|
+
s(n);
|
|
170
|
+
else {
|
|
171
|
+
console.log("- 正在创建dockerfile");
|
|
172
|
+
const l = `${t}/${this.config.dockerfile.name}`;
|
|
173
|
+
await this.onShell(`touch ${l}`), await this.onShell(`echo '${this.config.dockerfile.content.join(`
|
|
174
|
+
`)}' > ${l}`), console.log("- 正在创建upload.sh");
|
|
175
|
+
const r = `${t}/${this.config.upload.name}`;
|
|
176
|
+
await this.onShell(`touch ${r}`), await this.onShell(`echo '${this.config.upload.content.join(`
|
|
177
|
+
`)}' > ${r}`), i();
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* 判断文件是否存在
|
|
184
|
+
* @param {*} sftp
|
|
185
|
+
* @param {*} remotePath
|
|
186
|
+
* @returns
|
|
187
|
+
*/
|
|
188
|
+
checkRemoteFile(e, t) {
|
|
189
|
+
return new Promise((i) => {
|
|
190
|
+
e.stat(t, (s) => {
|
|
191
|
+
i(!s);
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* 上传项目
|
|
197
|
+
* @param {*} sftp
|
|
198
|
+
* @param {*} dir
|
|
199
|
+
*/
|
|
200
|
+
upLoadProject(e, t) {
|
|
201
|
+
e.readdir(t, async (i) => {
|
|
202
|
+
if (i) {
|
|
203
|
+
console.log("- 跳板机不存在项目, 开始创建项目"), this.projectInit(e, t).then(() => {
|
|
204
|
+
console.log(`- ${this.config.namespace}项目创建成功`), this.upLoadProject(e, t);
|
|
205
|
+
}).catch((o) => {
|
|
206
|
+
console.log(`- 创建项目失败: ${o}`), this.breakConnect();
|
|
207
|
+
});
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
const s = this.getArgv("--lazyUpload") !== void 0 || this.config.lazyUpload, n = `${t}/${this.config.dist.name}`;
|
|
211
|
+
if (s || await this.onShell(`rm -rf ${n}`), await this.onShell(`mkdir ${n}`), !this.config.fileDir) {
|
|
212
|
+
console.log("- 请配置待上传文件目录 fileDir"), this.breakConnect();
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
const { localFileList: l, dirList: r } = await this.getFilesInDirectory(this.config.fileDir);
|
|
216
|
+
if (l.length === 0) {
|
|
217
|
+
console.log("- 待上传目录没有获取到文件,请检查"), this.breakConnect();
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
let c = 0, a = l.length;
|
|
221
|
+
const w = (o) => new Promise(async (u, g) => {
|
|
222
|
+
try {
|
|
223
|
+
if (s && await this.checkRemoteFile(e, `${n}${o.remotePath}`))
|
|
224
|
+
return u();
|
|
225
|
+
const h = k.createReadStream(o.localPath), S = e.createWriteStream(`${n}${o.remotePath}`);
|
|
226
|
+
S.on("close", () => {
|
|
227
|
+
this.progressBar(++c, a), u();
|
|
228
|
+
}), S.on("error", (b) => {
|
|
229
|
+
console.log(`- 文件 ${o.remotePath} 上传失败:${b}`), g(b), this.breakConnect();
|
|
230
|
+
}), h.pipe(S);
|
|
231
|
+
} catch (h) {
|
|
232
|
+
g(h);
|
|
233
|
+
}
|
|
234
|
+
}), m = (o, u) => {
|
|
235
|
+
let g = [];
|
|
236
|
+
for (let h = 0; h < o.length; h += u)
|
|
237
|
+
g.push(o.slice(h, h + u));
|
|
238
|
+
return g;
|
|
239
|
+
}, d = (o) => {
|
|
240
|
+
if (o.length === 0)
|
|
241
|
+
return Promise.resolve();
|
|
242
|
+
const u = o.shift();
|
|
243
|
+
return Promise.all(u.map((g) => w(g))).then(() => d(o));
|
|
244
|
+
}, p = (o) => {
|
|
245
|
+
if (o.length === 0)
|
|
246
|
+
return Promise.resolve();
|
|
247
|
+
let g = o.shift().map((h) => `${n}${h}`).join(" ");
|
|
248
|
+
return this.onShell(`mkdir -p ${g}`).then(() => p(o));
|
|
249
|
+
};
|
|
250
|
+
let C = [...m(r, this.config.parallelDir || 20)];
|
|
251
|
+
await p(C), console.log("- 创建目录完成"), await new Promise((o) => {
|
|
252
|
+
setTimeout(() => {
|
|
253
|
+
o();
|
|
254
|
+
}, 500);
|
|
255
|
+
});
|
|
256
|
+
let y = [...m(l, this.config.parallelFile || 50)];
|
|
257
|
+
await d(y), s && (this.progressBar(a, a), console.log("\x1B[32m%s\x1B[0m", `- 已开启懒上传,本次共上传 ${c} 个文件`)), console.log("- 文件上传成功"), console.log("- 开始推送镜像");
|
|
258
|
+
let P = `cd ${t} && sh ${this.config.upload.name}`;
|
|
259
|
+
if (await this.isNewShell(e, t)) {
|
|
260
|
+
const o = this.getArgv("--imageStore") || this.config.imageStore;
|
|
261
|
+
P += ` ${o}`;
|
|
262
|
+
} else
|
|
263
|
+
console.log(`
|
|
264
|
+
- warning 检测到当前脚本为手动创建,不支持镜像仓库配置,imageStore将失效`), console.log("- warning 如需支持imageStore参数,请在命令行后添加 --reset 重新生成脚本");
|
|
265
|
+
const j = this.getArgv("--tmpName") || this.config.tmpName;
|
|
266
|
+
P += ` ${j}`;
|
|
267
|
+
const D = await this.onShell(P);
|
|
268
|
+
console.log(D), console.log("- 镜像推送完成"), this.breakConnect();
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* 获取脚本内容是不是自动创建的脚本
|
|
273
|
+
* 兼容用户手动根据运维文档创建的推送脚本,因参数不同可能报错的问题
|
|
274
|
+
* 有 $2代表是自动创建的版本,否则老版本
|
|
275
|
+
*/
|
|
276
|
+
async isNewShell(e, t) {
|
|
277
|
+
return new Promise((i, s) => {
|
|
278
|
+
e.readFile(`${t}/${this.config.upload.name}`, (n, l) => {
|
|
279
|
+
if (n)
|
|
280
|
+
return s(!1);
|
|
281
|
+
const r = l.toString();
|
|
282
|
+
i(r.includes("$2"));
|
|
283
|
+
});
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* 进度条
|
|
288
|
+
* @param description 命令行开头的文字信息
|
|
289
|
+
* @param bar_length 进度条的长度(单位:字符),默认设为 25
|
|
290
|
+
*/
|
|
291
|
+
progressBar(e, t, i = 25) {
|
|
292
|
+
let s = (e / t).toFixed(4), n = Math.floor(s * i), l = "";
|
|
293
|
+
for (let a = 0; a < n; a++)
|
|
294
|
+
l += "█";
|
|
295
|
+
let r = "";
|
|
296
|
+
for (let a = 0; a < i - n; a++)
|
|
297
|
+
r += "░";
|
|
298
|
+
let c = `- 文件上传进度: ${l}${r} (${e}/${t}) ${(100 * s).toFixed(2)}%`;
|
|
299
|
+
v(c), e == t && console.log("");
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* 获取目录下所有文件并分类
|
|
303
|
+
* @param {*} dir
|
|
304
|
+
*/
|
|
305
|
+
getFilesInDirectory(e) {
|
|
306
|
+
const t = [], i = [];
|
|
307
|
+
return new Promise((s, n) => {
|
|
308
|
+
const l = (r, c, a) => {
|
|
309
|
+
const w = k.readdirSync(r);
|
|
310
|
+
let m = !1;
|
|
311
|
+
w.forEach((d) => {
|
|
312
|
+
const p = F.join(r, d), y = k.statSync(p).isDirectory();
|
|
313
|
+
y ? m = !0 : t.push({
|
|
314
|
+
localPath: p,
|
|
315
|
+
// 本地路径
|
|
316
|
+
remotePath: `${c}${d}`,
|
|
317
|
+
// 远程路径
|
|
318
|
+
level: a
|
|
319
|
+
// 文件或目录层级
|
|
320
|
+
}), y && l(p, `${c}${d}/`, a + 1);
|
|
321
|
+
}), m || i.push(c);
|
|
322
|
+
};
|
|
323
|
+
l(e, "/", 0), s({
|
|
324
|
+
localFileList: t,
|
|
325
|
+
dirList: i
|
|
326
|
+
});
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* 获取命令行参数
|
|
331
|
+
* @param { string } name
|
|
332
|
+
*/
|
|
333
|
+
getArgv(e) {
|
|
334
|
+
const t = process.argv;
|
|
335
|
+
let i;
|
|
336
|
+
return t.forEach((s) => {
|
|
337
|
+
s.indexOf(e) > -1 && (i = s.split("=")[1] || "");
|
|
338
|
+
}), i;
|
|
339
|
+
}
|
|
340
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
(function(h){typeof define=="function"&&define.amd?define(h):h()})(function(){"use strict";var v=Object.defineProperty;var F=(h,f,u)=>f in h?v(h,f,{enumerable:!0,configurable:!0,writable:!0,value:u}):h[f]=u;var w=(h,f,u)=>(F(h,typeof f!="symbol"?f+"":f,u),u);const{stdout:h}=require("single-line-log"),f=require("path"),u=require("fs"),{Client:D}=require("ssh2");module.exports=class{constructor(e){w(this,"config",{host:"",port:"",username:"",password:"",namespace:"",imageStore:"dev-images",tmpName:"dev",delay:0,fileDir:"",rootDir:"/home/yjweb",dockerfile:{name:"Dockerfile",content:["FROM harbor.yunjingtech.cn:30002/yj-base/nginx:latest","RUN rm -rf /usr/share/nginx/html/*","COPY dist /usr/share/nginx/html/"]},upload:{name:"upload.sh",content:["#!/bin/sh","tag=`basename \\`pwd\\``:$2-`date +%Y%m%d`",'echo "- 镜像仓库: $1"','echo "- 镜像环境: $2"',"docker build -t harbor.yunjingtech.cn:30002/$1/$tag .","docker push harbor.yunjingtech.cn:30002/$1/$tag","echo - 镜像地址: harbor.yunjingtech.cn:30002/$1/$tag"]},dist:{name:"dist"},parallelDir:20,parallelFile:50,allLog:!1,lazyUpload:!1});w(this,"ssh2Conn",null);w(this,"uploading",!1);w(this,"trim",null);return this.config=Object.assign(this.config,e),{name:"yj-deploy",isPut:this.isPut.bind(this),upload:this.upload.bind(this),apply:this.apply.bind(this),closeBundle:this.isPut.bind(this)}}apply(e){return e&&e.hooks&&e.hooks.done&&e.hooks.done.tap("yj-deploy",()=>{this.isPut()}),"build"}isPut(){this.getArgv("--deploy")!=null&&(clearTimeout(this.trim),this.trim=setTimeout(()=>{this.upload()},this.config.delay||0))}upload(){if(console.log("-------------- deploy-start --------------"),!this.config.host){console.log("- 请配置跳板机地址 host");return}if(!this.config.port){console.log("- 请配置跳板机端口 port");return}if(!this.config.username){console.log("- 请配置跳板机账号 username");return}if(!this.config.password){console.log("- 请配置跳板机密码 password");return}this.uploading||(this.ssh2Conn=new D,this.ssh2Conn.on("ready",()=>{console.log("- 跳板机连接成功!"),this.ssh2Conn.sftp(async(e,t)=>{e&&(console.log("- sftp连接失败"),this.breakConnect()),this.config.namespace||(console.log("- 请配置项目命名空间 namespace"),this.breakConnect()),this.uploading=!0,this.getArgv("--reset")!==void 0&&(console.log("- 重置项目"),await this.onShell(`rm -r ${this.config.rootDir}/${this.config.namespace}`)),this.upLoadProject(t,`${this.config.rootDir}/${this.config.namespace}`)})}).connect({host:this.config.host,port:this.config.port,username:this.config.username,password:this.config.password}),this.ssh2Conn.on("error",e=>{console.log(`- 连接失败: ${e}`),this.breakConnect()}),this.ssh2Conn.on("end",()=>{this.uploading=!1}))}breakConnect(){this.uploading=!1,console.log("- 已断开连接"),console.log("-------------- deploy-end --------------"),this.ssh2Conn.end()}onShell(e){const t=this.getArgv("--allLog")!==void 0;return new Promise((n,s)=>{this.ssh2Conn.shell((i,l)=>{if(i){console.log("- 远程命令错误:"+i,e),this.breakConnect(),s(i);return}let r=[];l.on("close",()=>{n(r.toString())}).on("data",c=>{let a=c.toString();(t||this.config.allLog||a.startsWith("- "))&&r.push(`
|
|
2
|
+
`+a)}).stderr.on("data",c=>{console.log(`- 远程命令错误:
|
|
3
|
+
`+c),this.breakConnect(),s(c)}),l.end(e+`
|
|
4
|
+
exit
|
|
5
|
+
`)})})}projectInit(e,t){return new Promise(async(n,s)=>{e.mkdir(t,async i=>{if(i)s(i);else{console.log("- 正在创建dockerfile");const l=`${t}/${this.config.dockerfile.name}`;await this.onShell(`touch ${l}`),await this.onShell(`echo '${this.config.dockerfile.content.join(`
|
|
6
|
+
`)}' > ${l}`),console.log("- 正在创建upload.sh");const r=`${t}/${this.config.upload.name}`;await this.onShell(`touch ${r}`),await this.onShell(`echo '${this.config.upload.content.join(`
|
|
7
|
+
`)}' > ${r}`),n()}})})}checkRemoteFile(e,t){return new Promise(n=>{e.stat(t,s=>{n(!s)})})}upLoadProject(e,t){e.readdir(t,async n=>{if(n){console.log("- 跳板机不存在项目, 开始创建项目"),this.projectInit(e,t).then(()=>{console.log(`- ${this.config.namespace}项目创建成功`),this.upLoadProject(e,t)}).catch(o=>{console.log(`- 创建项目失败: ${o}`),this.breakConnect()});return}const s=this.getArgv("--lazyUpload")!==void 0||this.config.lazyUpload,i=`${t}/${this.config.dist.name}`;if(s||await this.onShell(`rm -rf ${i}`),await this.onShell(`mkdir ${i}`),!this.config.fileDir){console.log("- 请配置待上传文件目录 fileDir"),this.breakConnect();return}const{localFileList:l,dirList:r}=await this.getFilesInDirectory(this.config.fileDir);if(l.length===0){console.log("- 待上传目录没有获取到文件,请检查"),this.breakConnect();return}let c=0,a=l.length;const S=o=>new Promise(async(p,d)=>{try{if(s&&await this.checkRemoteFile(e,`${i}${o.remotePath}`))return p();const g=u.createReadStream(o.localPath),k=e.createWriteStream(`${i}${o.remotePath}`);k.on("close",()=>{this.progressBar(++c,a),p()}),k.on("error",C=>{console.log(`- 文件 ${o.remotePath} 上传失败:${C}`),d(C),this.breakConnect()}),g.pipe(k)}catch(g){d(g)}}),y=(o,p)=>{let d=[];for(let g=0;g<o.length;g+=p)d.push(o.slice(g,g+p));return d},m=o=>{if(o.length===0)return Promise.resolve();const p=o.shift();return Promise.all(p.map(d=>S(d))).then(()=>m(o))},$=o=>{if(o.length===0)return Promise.resolve();let d=o.shift().map(g=>`${i}${g}`).join(" ");return this.onShell(`mkdir -p ${d}`).then(()=>$(o))};let j=[...y(r,this.config.parallelDir||20)];await $(j),console.log("- 创建目录完成"),await new Promise(o=>{setTimeout(()=>{o()},500)});let P=[...y(l,this.config.parallelFile||50)];await m(P),s&&(this.progressBar(a,a),console.log("\x1B[32m%s\x1B[0m",`- 已开启懒上传,本次共上传 ${c} 个文件`)),console.log("- 文件上传成功"),console.log("- 开始推送镜像");let b=`cd ${t} && sh ${this.config.upload.name}`;if(await this.isNewShell(e,t)){const o=this.getArgv("--imageStore")||this.config.imageStore;b+=` ${o}`}else console.log(`
|
|
8
|
+
- warning 检测到当前脚本为手动创建,不支持镜像仓库配置,imageStore将失效`),console.log("- warning 如需支持imageStore参数,请在命令行后添加 --reset 重新生成脚本");const x=this.getArgv("--tmpName")||this.config.tmpName;b+=` ${x}`;const L=await this.onShell(b);console.log(L),console.log("- 镜像推送完成"),this.breakConnect()})}async isNewShell(e,t){return new Promise((n,s)=>{e.readFile(`${t}/${this.config.upload.name}`,(i,l)=>{if(i)return s(!1);const r=l.toString();n(r.includes("$2"))})})}progressBar(e,t,n=25){let s=(e/t).toFixed(4),i=Math.floor(s*n),l="";for(let a=0;a<i;a++)l+="█";let r="";for(let a=0;a<n-i;a++)r+="░";let c=`- 文件上传进度: ${l}${r} (${e}/${t}) ${(100*s).toFixed(2)}%`;h(c),e==t&&console.log("")}getFilesInDirectory(e){const t=[],n=[];return new Promise((s,i)=>{const l=(r,c,a)=>{const S=u.readdirSync(r);let y=!1;S.forEach(m=>{const $=f.join(r,m),P=u.statSync($).isDirectory();P?y=!0:t.push({localPath:$,remotePath:`${c}${m}`,level:a}),P&&l($,`${c}${m}/`,a+1)}),y||n.push(c)};l(e,"/",0),s({localFileList:t,dirList:n})})}getArgv(e){const t=process.argv;let n;return t.forEach(s=>{s.indexOf(e)>-1&&(n=s.split("=")[1]||"")}),n}}});
|