ee-bin 1.0.0
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/index.js +53 -0
- package/package.json +23 -0
- package/tools/encrypt.js +323 -0
- package/tools/iconGen.js +183 -0
- package/tools/replaceDist.js +96 -0
package/index.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const program = require('commander');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* rd - Moves front-end resources to a specified directory
|
|
7
|
+
*/
|
|
8
|
+
program
|
|
9
|
+
.command('rd')
|
|
10
|
+
.description('Move frontend resources to public/dist')
|
|
11
|
+
.option('--dist-dir <folder>', 'title to use before name', './frontend/dist')
|
|
12
|
+
.action(function() {
|
|
13
|
+
const replaceDist = require('./tools/replaceDist');
|
|
14
|
+
replaceDist.run(this.opts());
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* encrypt - Code encryption
|
|
19
|
+
*/
|
|
20
|
+
program
|
|
21
|
+
.command('encrypt')
|
|
22
|
+
.description('Code encryption')
|
|
23
|
+
.option('--config <folder>', 'config file', './electron/config/encrypt.js')
|
|
24
|
+
.option('--out <folder>', 'output directory', './public')
|
|
25
|
+
.action(function() {
|
|
26
|
+
const encrypt = require('./tools/encrypt');
|
|
27
|
+
encrypt.run(this.opts());
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* clean - Clear the encrypted code
|
|
32
|
+
*/
|
|
33
|
+
program
|
|
34
|
+
.command('clean')
|
|
35
|
+
.description('Clear the encrypted code')
|
|
36
|
+
.option('-d, --dir <folder>', 'clean directory')
|
|
37
|
+
.action(function() {
|
|
38
|
+
const encrypt = require('./tools/encrypt');
|
|
39
|
+
encrypt.clean(this.opts());
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* icon
|
|
44
|
+
*/
|
|
45
|
+
program
|
|
46
|
+
.command('icon')
|
|
47
|
+
.description('Generate logo')
|
|
48
|
+
.action(function() {
|
|
49
|
+
const iconGen = require('./tools/iconGen');
|
|
50
|
+
iconGen.run();
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
program.parse();
|
package/package.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ee-bin",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "ee bin",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
8
|
+
},
|
|
9
|
+
"author": "",
|
|
10
|
+
"license": "ISC",
|
|
11
|
+
"bin": {
|
|
12
|
+
"ee-bin": "index.js"
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"bytenode": "^1.3.6",
|
|
16
|
+
"chalk": "^4.1.2",
|
|
17
|
+
"commander": "^11.0.0",
|
|
18
|
+
"fs-extra": "^10.0.0",
|
|
19
|
+
"globby": "^10.0.0",
|
|
20
|
+
"is-type-of": "^1.2.1",
|
|
21
|
+
"javascript-obfuscator": "^4.0.2"
|
|
22
|
+
}
|
|
23
|
+
}
|
package/tools/encrypt.js
ADDED
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const fsPro = require('fs-extra');
|
|
6
|
+
const is = require('is-type-of');
|
|
7
|
+
const bytenode = require('bytenode');
|
|
8
|
+
const crypto = require('crypto');
|
|
9
|
+
const JavaScriptObfuscator = require('javascript-obfuscator');
|
|
10
|
+
const globby = require('globby');
|
|
11
|
+
const chalk = require('chalk');
|
|
12
|
+
|
|
13
|
+
class Encrypt {
|
|
14
|
+
constructor(options = {}) {
|
|
15
|
+
// cli args
|
|
16
|
+
const outputFolder = options.out || './public';
|
|
17
|
+
const configFile = options.config || './electron/config/encrypt.js';
|
|
18
|
+
|
|
19
|
+
this.basePath = process.cwd();
|
|
20
|
+
this.encryptCodeDir = path.join(this.basePath, outputFolder);
|
|
21
|
+
this.config = this.loadConfig(configFile);
|
|
22
|
+
this.filesExt = this.config.fileExt || ['.js'];
|
|
23
|
+
this.type = this.config.type || 'confusion';
|
|
24
|
+
this.bOpt = this.config.bytecodeOptions || {};
|
|
25
|
+
this.cOpt = this.config.confusionOptions || {};
|
|
26
|
+
this.cleanFiles = this.config.cleanFiles || ['./public/electron'];
|
|
27
|
+
this.patterns = this.config.files || null;
|
|
28
|
+
this.specificFiles = [ 'electron/preload/bridge.js' ];
|
|
29
|
+
|
|
30
|
+
// 旧属性,将废弃
|
|
31
|
+
this.dirs = [];
|
|
32
|
+
const directory = this.config.directory || ['electron'];
|
|
33
|
+
for (let i = 0; i < directory.length; i++) {
|
|
34
|
+
let codeDirPath = path.join(this.basePath, directory[i]);
|
|
35
|
+
if (fs.existsSync(codeDirPath)) {
|
|
36
|
+
this.dirs.push(directory[i]);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
this.codefiles = this._initCodeFiles();
|
|
41
|
+
//console.log('[ee-core] [encrypt] codefiles:', this.codefiles);
|
|
42
|
+
console.log('[ee-core] [encrypt] cleanFiles:', this.cleanFiles);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* 初始化需要加密的文件列表
|
|
47
|
+
*/
|
|
48
|
+
_initCodeFiles() {
|
|
49
|
+
if (!this.patterns) return;
|
|
50
|
+
|
|
51
|
+
const files = globby.sync(this.patterns, { cwd: this.basePath });
|
|
52
|
+
return files;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* 备份代码
|
|
57
|
+
*/
|
|
58
|
+
backup() {
|
|
59
|
+
// clean
|
|
60
|
+
this.cleanCode();
|
|
61
|
+
|
|
62
|
+
console.log('[ee-core] [encrypt] backup start');
|
|
63
|
+
if (this.patterns) {
|
|
64
|
+
this.codefiles.forEach((filepath) => {
|
|
65
|
+
let source = path.join(this.basePath, filepath);
|
|
66
|
+
if (fs.existsSync(source)) {
|
|
67
|
+
let target = path.join(this.encryptCodeDir, filepath);
|
|
68
|
+
fsPro.copySync(source, target);
|
|
69
|
+
}
|
|
70
|
+
})
|
|
71
|
+
} else {
|
|
72
|
+
// 旧的逻辑,将废弃
|
|
73
|
+
for (let i = 0; i < this.dirs.length; i++) {
|
|
74
|
+
// check code dir
|
|
75
|
+
let codeDirPath = path.join(this.basePath, this.dirs[i]);
|
|
76
|
+
if (!fs.existsSync(codeDirPath)) {
|
|
77
|
+
console.log('[ee-core] [encrypt] ERROR: backup %s is not exist', codeDirPath);
|
|
78
|
+
return
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// copy
|
|
82
|
+
let targetDir = path.join(this.encryptCodeDir, this.dirs[i]);
|
|
83
|
+
console.log('[ee-core] [encrypt] backup target Dir:', targetDir);
|
|
84
|
+
if (!fs.existsSync(targetDir)) {
|
|
85
|
+
this.mkdir(targetDir);
|
|
86
|
+
this.chmodPath(targetDir, '777');
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
fsPro.copySync(codeDirPath, targetDir);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
console.log('[ee-core] [encrypt] backup end');
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* 清除加密代码
|
|
99
|
+
*/
|
|
100
|
+
cleanCode() {
|
|
101
|
+
this.cleanFiles.forEach((file) => {
|
|
102
|
+
let tmpFile = path.join(this.basePath, file);
|
|
103
|
+
this.rmBackup(tmpFile);
|
|
104
|
+
console.log('[ee-core] [encrypt] clean up tmp files:', tmpFile);
|
|
105
|
+
})
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* 加密代码
|
|
110
|
+
*/
|
|
111
|
+
encrypt() {
|
|
112
|
+
console.log('[ee-core] [encrypt] start ciphering');
|
|
113
|
+
if (this.patterns) {
|
|
114
|
+
for (const file of this.codefiles) {
|
|
115
|
+
const fullpath = path.join(this.encryptCodeDir, file);
|
|
116
|
+
if (!fs.statSync(fullpath).isFile()) continue;
|
|
117
|
+
|
|
118
|
+
// 特殊文件处理
|
|
119
|
+
if (this.specificFiles.includes(file)) {
|
|
120
|
+
this.generate(fullpath, 'confusion');
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
this.generate(fullpath);
|
|
125
|
+
}
|
|
126
|
+
} else {
|
|
127
|
+
// 旧逻辑,将废弃
|
|
128
|
+
console.log('[ee-core] [encrypt] !!!!!! please use the new encryption method !!!!!!');
|
|
129
|
+
for (let i = 0; i < this.dirs.length; i++) {
|
|
130
|
+
let codeDirPath = path.join(this.encryptCodeDir, this.dirs[i]);
|
|
131
|
+
this.loop(codeDirPath);
|
|
132
|
+
}
|
|
133
|
+
console.log('[ee-core] [encrypt] !!!!!! please use the new encryption method !!!!!!');
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
console.log('[ee-core] [encrypt] end ciphering');
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* 递归
|
|
141
|
+
*/
|
|
142
|
+
loop(dirPath) {
|
|
143
|
+
let files = [];
|
|
144
|
+
if (fs.existsSync(dirPath)) {
|
|
145
|
+
files = fs.readdirSync(dirPath);
|
|
146
|
+
files.forEach((file, index) => {
|
|
147
|
+
let curPath = dirPath + '/' + file;
|
|
148
|
+
if (fs.statSync(curPath).isDirectory()) {
|
|
149
|
+
this.loop(curPath);
|
|
150
|
+
} else {
|
|
151
|
+
const extname = path.extname(curPath);
|
|
152
|
+
if (this.filesExt.indexOf(extname) !== -1) {
|
|
153
|
+
this.generate(curPath);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* 生成文件
|
|
162
|
+
*/
|
|
163
|
+
generate(curPath, type) {
|
|
164
|
+
let encryptType = type ? type : this.type;
|
|
165
|
+
|
|
166
|
+
let tips = '[ee-core] [encrypt] file: ' + chalk.green(`${curPath}`) + ' ' + chalk.blue(`(${encryptType})`);
|
|
167
|
+
console.log(tips);
|
|
168
|
+
|
|
169
|
+
if (encryptType == 'bytecode') {
|
|
170
|
+
this.generateBytecodeFile(curPath);
|
|
171
|
+
} else if (encryptType == 'confusion') {
|
|
172
|
+
this.generateJSConfuseFile(curPath);
|
|
173
|
+
} else {
|
|
174
|
+
this.generateJSConfuseFile(curPath);
|
|
175
|
+
this.generateBytecodeFile(curPath);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* 使用 javascript-obfuscator 生成压缩/混淆文件
|
|
181
|
+
*/
|
|
182
|
+
generateJSConfuseFile(file) {
|
|
183
|
+
let opt = Object.assign({
|
|
184
|
+
compact: true,
|
|
185
|
+
stringArray: true,
|
|
186
|
+
stringArrayThreshold: 1,
|
|
187
|
+
}, this.cOpt);
|
|
188
|
+
|
|
189
|
+
let code = fs.readFileSync(file, "utf8");
|
|
190
|
+
let result = JavaScriptObfuscator.obfuscate(code, opt);
|
|
191
|
+
fs.writeFileSync(file, result.getObfuscatedCode(), "utf8");
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* 生成字节码文件
|
|
196
|
+
*/
|
|
197
|
+
generateBytecodeFile(curPath) {
|
|
198
|
+
if (path.extname(curPath) !== '.js') {
|
|
199
|
+
return
|
|
200
|
+
}
|
|
201
|
+
//let jscFile = curPath.replace(/.js/g, '.jsc');
|
|
202
|
+
let jscFile = curPath + 'c';
|
|
203
|
+
let opt = Object.assign({
|
|
204
|
+
filename: curPath,
|
|
205
|
+
output: jscFile,
|
|
206
|
+
electron: true
|
|
207
|
+
}, this.bOpt);
|
|
208
|
+
|
|
209
|
+
bytenode.compileFile(opt);
|
|
210
|
+
|
|
211
|
+
//fs.writeFileSync(curPath, 'require("bytenode");module.exports = require("./'+path.basename(jscFile)+'");', 'utf8');
|
|
212
|
+
|
|
213
|
+
fsPro.removeSync(curPath);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* 移除备份
|
|
218
|
+
*/
|
|
219
|
+
rmBackup(file) {
|
|
220
|
+
if (fs.existsSync(file)) {
|
|
221
|
+
fsPro.removeSync(file);
|
|
222
|
+
}
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* 检查文件是否存在
|
|
228
|
+
*/
|
|
229
|
+
fileExist(filePath) {
|
|
230
|
+
try {
|
|
231
|
+
return fs.statSync(filePath).isFile();
|
|
232
|
+
} catch (err) {
|
|
233
|
+
return false;
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
mkdir(dirpath, dirname) {
|
|
238
|
+
// 判断是否是第一次调用
|
|
239
|
+
if (typeof dirname === 'undefined') {
|
|
240
|
+
if (fs.existsSync(dirpath)) {
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
this.mkdir(dirpath, path.dirname(dirpath));
|
|
244
|
+
} else {
|
|
245
|
+
// 判断第二个参数是否正常,避免调用时传入错误参数
|
|
246
|
+
if (dirname !== path.dirname(dirpath)) {
|
|
247
|
+
this.mkdir(dirpath);
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
if (fs.existsSync(dirname)) {
|
|
251
|
+
fs.mkdirSync(dirpath);
|
|
252
|
+
} else {
|
|
253
|
+
this.mkdir(dirname, path.dirname(dirname));
|
|
254
|
+
fs.mkdirSync(dirpath);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
chmodPath(path, mode) {
|
|
260
|
+
let files = [];
|
|
261
|
+
if (fs.existsSync(path)) {
|
|
262
|
+
files = fs.readdirSync(path);
|
|
263
|
+
files.forEach((file, index) => {
|
|
264
|
+
const curPath = path + '/' + file;
|
|
265
|
+
if (fs.statSync(curPath).isDirectory()) {
|
|
266
|
+
this.chmodPath(curPath, mode); // 递归删除文件夹
|
|
267
|
+
} else {
|
|
268
|
+
fs.chmodSync(curPath, mode);
|
|
269
|
+
}
|
|
270
|
+
});
|
|
271
|
+
fs.chmodSync(path, mode);
|
|
272
|
+
}
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
loadConfig(prop) {
|
|
276
|
+
const filepath = path.join(this.basePath, prop);
|
|
277
|
+
if (!fs.existsSync(filepath)) {
|
|
278
|
+
const errorTips = 'config file ' + chalk.blue(`${filepath}`) + ' does not exist !';
|
|
279
|
+
throw new Error(errorTips)
|
|
280
|
+
}
|
|
281
|
+
const obj = require(filepath);
|
|
282
|
+
if (!obj) return obj;
|
|
283
|
+
|
|
284
|
+
let ret = obj;
|
|
285
|
+
if (is.function(obj) && !is.class(obj)) {
|
|
286
|
+
ret = obj();
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
return ret || {};
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
md5(file) {
|
|
293
|
+
const buffer = fs.readFileSync(file);
|
|
294
|
+
const hash = crypto.createHash('md5');
|
|
295
|
+
hash.update(buffer, 'utf8');
|
|
296
|
+
const str = hash.digest('hex');
|
|
297
|
+
return str;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
const run = (options = {}) => {
|
|
302
|
+
const e = new Encrypt(options);
|
|
303
|
+
if (!e.backup()) return;
|
|
304
|
+
e.encrypt();
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
const clean = (options = {}) => {
|
|
308
|
+
let files = options.dir !== undefined ? options.dir : ['./public/electron'];
|
|
309
|
+
files = is.string(files) ? [files] : files;
|
|
310
|
+
|
|
311
|
+
files.forEach((file) => {
|
|
312
|
+
const tmpFile = path.join(process.cwd(), file);
|
|
313
|
+
if (fs.existsSync(tmpFile)) {
|
|
314
|
+
fsPro.removeSync(tmpFile);
|
|
315
|
+
console.log('[ee-core] [encrypt] clean up tmp files:', tmpFile);
|
|
316
|
+
}
|
|
317
|
+
})
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
module.exports = {
|
|
321
|
+
run,
|
|
322
|
+
clean,
|
|
323
|
+
};
|
package/tools/iconGen.js
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require("fs");
|
|
4
|
+
const path = require("path");
|
|
5
|
+
const icongen = require("icon-gen");
|
|
6
|
+
|
|
7
|
+
class IconGen {
|
|
8
|
+
constructor() {
|
|
9
|
+
this._init();
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* _init
|
|
14
|
+
*/
|
|
15
|
+
_init() {
|
|
16
|
+
// ---> 处理参数
|
|
17
|
+
const args = process.argv.splice(3);
|
|
18
|
+
let params = {
|
|
19
|
+
input: "/public/images/logo.png",
|
|
20
|
+
output: "/build/icons/",
|
|
21
|
+
size: "16,32,64,256,512",
|
|
22
|
+
clear: false,
|
|
23
|
+
imagesDir: "/public/images/",
|
|
24
|
+
};
|
|
25
|
+
try {
|
|
26
|
+
const len = args.length;
|
|
27
|
+
for (let i = 0; i < len; i++) {
|
|
28
|
+
const arg = args[i];
|
|
29
|
+
if (arg.match(/^-i/) || arg.match(/^-input/)) {
|
|
30
|
+
params["input"] = args[i + 1];
|
|
31
|
+
i++;
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
if (arg.match(/^-o/) || arg.match(/^-output/)) {
|
|
35
|
+
params["output"] = args[i + 1];
|
|
36
|
+
i++;
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
if (arg.match(/^-s/) || arg.match(/^-size/)) {
|
|
40
|
+
params["size"] = args[i + 1];
|
|
41
|
+
i++;
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
if (arg.match(/^-c/) || arg.match(/^-clear/)) {
|
|
45
|
+
params["clear"] = true;
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
if (arg.match(/^-img/) || arg.match(/^-images/)) {
|
|
49
|
+
params["imagesDir"] = args[i + 1];
|
|
50
|
+
i++;
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
} catch (e) {
|
|
55
|
+
console.error("[ee-core] [tools/iconGen] args: ", args);
|
|
56
|
+
console.error("[ee-core] [tools/iconGen] ERROR: ", e);
|
|
57
|
+
throw new Error("参数错误!!");
|
|
58
|
+
}
|
|
59
|
+
this.params = params;
|
|
60
|
+
|
|
61
|
+
// ---> 组装参数
|
|
62
|
+
console.log("[ee-core] [tools/iconGen] icon 当前路径: ", process.cwd());
|
|
63
|
+
this.input = path.join(process.cwd(), params.input);
|
|
64
|
+
this.output = path.join(process.cwd(), params.output);
|
|
65
|
+
this.imagesDir = path.join(process.cwd(), params.imagesDir);
|
|
66
|
+
|
|
67
|
+
const sizeList = params.size.split(",").map((item) => parseInt(item));
|
|
68
|
+
this.iconOptions = {
|
|
69
|
+
report: false,
|
|
70
|
+
ico: {
|
|
71
|
+
name: "icon",
|
|
72
|
+
sizes: [256],
|
|
73
|
+
},
|
|
74
|
+
favicon: {
|
|
75
|
+
name: "logo-",
|
|
76
|
+
pngSizes: sizeList,
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* 生成图标
|
|
83
|
+
*/
|
|
84
|
+
generateIcons() {
|
|
85
|
+
console.log("[ee-core] [tools/iconGen] iconGen 开始处理生成logo图片");
|
|
86
|
+
if (!fs.existsSync(this.input)) {
|
|
87
|
+
console.error("[ee-core] [tools/iconGen] input: ", this.input);
|
|
88
|
+
throw new Error("输入的图片不存在或路径错误");
|
|
89
|
+
}
|
|
90
|
+
if (!fs.existsSync(this.output)) {
|
|
91
|
+
fs.mkdirSync(this.output, { recursive: true });
|
|
92
|
+
} else {
|
|
93
|
+
// 清空目录
|
|
94
|
+
this.params.clear && this.deleteGenFile(this.output);
|
|
95
|
+
}
|
|
96
|
+
if (!fs.existsSync(this.imagesDir)) {
|
|
97
|
+
fs.mkdirSync(this.imagesDir, { recursive: true });
|
|
98
|
+
}
|
|
99
|
+
icongen(this.input, this.output, this.iconOptions)
|
|
100
|
+
.then((results) => {
|
|
101
|
+
console.log("[ee-core] [tools/iconGen] iconGen 已生成下方图片资源");
|
|
102
|
+
console.log(results);
|
|
103
|
+
this._renameForEE(results);
|
|
104
|
+
})
|
|
105
|
+
.catch((err) => {
|
|
106
|
+
console.error(err);
|
|
107
|
+
throw new Error("[ee-core] [tools/iconGen] iconGen 生成失败!");
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* 删除生成的文件(.ico .png)
|
|
113
|
+
*/
|
|
114
|
+
deleteGenFile(dirPath) {
|
|
115
|
+
if (fs.existsSync(dirPath)) {
|
|
116
|
+
// 读取文件夹下的文件目录
|
|
117
|
+
const files = fs.readdirSync(dirPath);
|
|
118
|
+
files.forEach((file) => {
|
|
119
|
+
const curPath = path.join(dirPath, file);
|
|
120
|
+
// 判断是不是文件夹,如果是,继续递归
|
|
121
|
+
if (fs.lstatSync(curPath).isDirectory()) {
|
|
122
|
+
this.deleteGenFile(curPath);
|
|
123
|
+
} else {
|
|
124
|
+
// 删除文件
|
|
125
|
+
if ([".ico", ".png"].includes(path.extname(curPath))) {
|
|
126
|
+
fs.unlinkSync(curPath);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* 为生成的资源重命名 (logo-32.png -> 32x32.png)
|
|
135
|
+
*/
|
|
136
|
+
_renameForEE(filesPath) {
|
|
137
|
+
console.log("[ee-core] [tools/iconGen] iconGen 开始重新命名logo图片资源");
|
|
138
|
+
try {
|
|
139
|
+
const len = filesPath.length;
|
|
140
|
+
for (let i = 0; i < len; i++) {
|
|
141
|
+
const filePath = filesPath[i];
|
|
142
|
+
const extname = path.extname(filePath);
|
|
143
|
+
if ([".png"].includes(extname)) {
|
|
144
|
+
const filename = path.basename(filePath, extname);
|
|
145
|
+
const basename = filename.split("-")[1];
|
|
146
|
+
const dirname = path.dirname(filePath);
|
|
147
|
+
// 处理 tray 图标 --> 复制到 public/images 目录下
|
|
148
|
+
if ("16" === basename) {
|
|
149
|
+
const newName = "tray" + extname;
|
|
150
|
+
fs.copyFileSync(filePath, path.join(this.imagesDir, newName));
|
|
151
|
+
console.log(`${filename}${extname} --> ${this.params.imagesDir}/${newName} 复制成功!`);
|
|
152
|
+
fs.unlinkSync(filePath);
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
// 处理 win 窗口图标 --> 复制到 public/images 目录下
|
|
156
|
+
if ("32" === basename) {
|
|
157
|
+
const newName = filename + extname;
|
|
158
|
+
fs.copyFileSync(filePath, path.join(this.imagesDir, newName));
|
|
159
|
+
console.log(`${filename}${extname} --> ${this.params.imagesDir}/${newName} 复制成功!`);
|
|
160
|
+
}
|
|
161
|
+
// 重命名 --> 32x32.png
|
|
162
|
+
const newName = basename + "x" + basename + extname;
|
|
163
|
+
const newPath = path.join(dirname, newName);
|
|
164
|
+
fs.renameSync(filePath, newPath);
|
|
165
|
+
console.log(`${filename}${extname} --> ${newName} 重命名成功!`);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
console.log("[ee-core] [tools/iconGen] iconGen 资源处理完成!");
|
|
169
|
+
} catch (e) {
|
|
170
|
+
console.error("[ee-core] [tools/iconGen] ERROR: ", e);
|
|
171
|
+
throw new Error("重命名logo图片资源失败!!");
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const run = () => {
|
|
177
|
+
const i = new IconGen();
|
|
178
|
+
i.generateIcons();
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
module.exports = {
|
|
182
|
+
run,
|
|
183
|
+
};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const fsPro = require('fs-extra');
|
|
6
|
+
const chalk = require('chalk');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* 资源替换
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
module.exports = {
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* 执行
|
|
16
|
+
*/
|
|
17
|
+
run(options = {}) {
|
|
18
|
+
console.log('[ee-bin] [rd] Start moving resources');
|
|
19
|
+
const homeDir = process.cwd();
|
|
20
|
+
|
|
21
|
+
// argv
|
|
22
|
+
const distDir = options.distDir;
|
|
23
|
+
const sourceDir = path.join(homeDir, distDir);
|
|
24
|
+
const sourceIndexFile = path.join(sourceDir, 'index.html');
|
|
25
|
+
|
|
26
|
+
if (!this._fileExist(sourceIndexFile)) {
|
|
27
|
+
console.info(sourceIndexFile);
|
|
28
|
+
const errorTips = chalk.bgRed('Error') + ' Frontend resource does not exist, please build !';
|
|
29
|
+
console.error(errorTips);
|
|
30
|
+
return
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// 清空历史资源 并 复制到ee资源目录
|
|
34
|
+
const eeResourceDir = path.join(homeDir, 'public', 'dist');
|
|
35
|
+
if (!fs.existsSync(eeResourceDir)) {
|
|
36
|
+
fs.mkdirSync(eeResourceDir, {recursive: true, mode: 0o777});
|
|
37
|
+
}
|
|
38
|
+
this._rmFolder(eeResourceDir);
|
|
39
|
+
console.log('[ee-bin] [rd] Clear history resources:', eeResourceDir);
|
|
40
|
+
|
|
41
|
+
fsPro.copySync(sourceDir, eeResourceDir);
|
|
42
|
+
console.log('[ee-bin] [rd] Copy a resource to:', eeResourceDir);
|
|
43
|
+
console.log('[ee-bin] [rd] End');
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
_fileExist(filePath) {
|
|
47
|
+
try {
|
|
48
|
+
return fs.statSync(filePath).isFile();
|
|
49
|
+
} catch (err) {
|
|
50
|
+
// const errorTips = chalk.bgRed('Error') + ' [ee-bin] [rd] ';
|
|
51
|
+
// console.error(errorTips, err);
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* 删除文件夹
|
|
58
|
+
*/
|
|
59
|
+
_rmFolder(folder) {
|
|
60
|
+
const nodeVersion = (process.versions && process.versions.node) || null;
|
|
61
|
+
if (nodeVersion && this._compareVersion(nodeVersion, '14.14.0') == 1) {
|
|
62
|
+
fs.rmSync(folder, {recursive: true});
|
|
63
|
+
} else {
|
|
64
|
+
fs.rmdirSync(folder, {recursive: true});
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* 版本号比较
|
|
70
|
+
*/
|
|
71
|
+
_compareVersion(v1, v2) {
|
|
72
|
+
v1 = v1.split('.')
|
|
73
|
+
v2 = v2.split('.')
|
|
74
|
+
const len = Math.max(v1.length, v2.length)
|
|
75
|
+
|
|
76
|
+
while (v1.length < len) {
|
|
77
|
+
v1.push('0')
|
|
78
|
+
}
|
|
79
|
+
while (v2.length < len) {
|
|
80
|
+
v2.push('0')
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
for (let i = 0; i < len; i++) {
|
|
84
|
+
const num1 = parseInt(v1[i])
|
|
85
|
+
const num2 = parseInt(v2[i])
|
|
86
|
+
|
|
87
|
+
if (num1 > num2) {
|
|
88
|
+
return 1
|
|
89
|
+
} else if (num1 < num2) {
|
|
90
|
+
return -1
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return 0
|
|
95
|
+
}
|
|
96
|
+
}
|