@intecoag/inteco-cli 0.5.1 → 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/.github/workflows/publish.yml +31 -0
- package/README.md +3 -3
- package/package.json +44 -35
- package/src/index.js +85 -85
- package/src/modules/adbBridge.js +51 -51
- package/src/modules/adbIntentSender.js +81 -81
- package/src/modules/bundleProduct.js +160 -160
- package/src/modules/csvMerger.js +117 -117
- package/src/modules/deleteDB.js +83 -83
- package/src/modules/dumpDB.js +215 -215
- package/src/modules/dumpTableToCSV.js +153 -153
- package/src/modules/extdSearch.js +226 -226
- package/src/modules/graphqlSchemaExport.js +60 -60
- package/src/modules/importDB.js +120 -120
- package/src/modules/rewriteConfig.js +78 -78
- package/src/modules/setCLIConfig.js +32 -32
- package/src/modules/syncConfig.js +264 -264
- package/src/modules/t003Rewrite.js +63 -63
- package/src/ressources/cmds.json +46 -46
- package/src/utils/config/config.js +70 -70
- package/src/utils/config/default.json +8 -8
- package/src/utils/db/DB.js +53 -53
- package/src/utils/fs/FS.js +87 -87
package/src/ressources/cmds.json
CHANGED
|
@@ -1,47 +1,47 @@
|
|
|
1
|
-
{
|
|
2
|
-
"dump_db": {
|
|
3
|
-
"desc": "Dumps a DB-Export from local MYSQL-Instance (optionally with table selection or data only)."
|
|
4
|
-
},
|
|
5
|
-
"import_db": {
|
|
6
|
-
"desc": "Imports a DB-Export (in Archive) to the local MYSQL-Instance"
|
|
7
|
-
},
|
|
8
|
-
"config_rewrite": {
|
|
9
|
-
"desc": "Rewrites WEGAS-Config"
|
|
10
|
-
},
|
|
11
|
-
"sync_config": {
|
|
12
|
-
"desc": "Synchronize Config/ConfigIndividual-Folders between Work and Repository (Eclipse-Repo)"
|
|
13
|
-
},
|
|
14
|
-
"t003_rewrite": {
|
|
15
|
-
"desc": "Rewrites t003 in DB"
|
|
16
|
-
},
|
|
17
|
-
"bundle_product":{
|
|
18
|
-
"desc": "Bundles the jWEGAS-Product after an Eclipse-Export"
|
|
19
|
-
},
|
|
20
|
-
"dump_db_mand": {
|
|
21
|
-
"desc": "Export a DB-Dump for a single Mandant"
|
|
22
|
-
},
|
|
23
|
-
"delete_db_mand": {
|
|
24
|
-
"desc": "Delete all Mandant-Data from a db"
|
|
25
|
-
},
|
|
26
|
-
"extd_search": {
|
|
27
|
-
"desc": "Search EXTD/EXTI interactively with full text search"
|
|
28
|
-
},
|
|
29
|
-
"set_cli_config": {
|
|
30
|
-
"desc": "Configure the Inteco CLI"
|
|
31
|
-
},
|
|
32
|
-
"dump_table_to_csv": {
|
|
33
|
-
"desc": "Dumps a specific table from multiple SQL-Exports to a CSV"
|
|
34
|
-
},
|
|
35
|
-
"csv_merge": {
|
|
36
|
-
"desc": "Merge multiple CSV-Files (with same headers) into single file (with optional filter)"
|
|
37
|
-
},
|
|
38
|
-
"adb_bridge": {
|
|
39
|
-
"desc": "Activates an ADB-Bridge-Connection to an Android-Device"
|
|
40
|
-
},
|
|
41
|
-
"adb_intent": {
|
|
42
|
-
"desc": "Sends a configurable Intent to an Android-Device"
|
|
43
|
-
},
|
|
44
|
-
"graphql_schema_export": {
|
|
45
|
-
"desc": "Dump the Graph-QL-Schema from an Endpoint"
|
|
46
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"dump_db": {
|
|
3
|
+
"desc": "Dumps a DB-Export from local MYSQL-Instance (optionally with table selection or data only)."
|
|
4
|
+
},
|
|
5
|
+
"import_db": {
|
|
6
|
+
"desc": "Imports a DB-Export (in Archive) to the local MYSQL-Instance"
|
|
7
|
+
},
|
|
8
|
+
"config_rewrite": {
|
|
9
|
+
"desc": "Rewrites WEGAS-Config"
|
|
10
|
+
},
|
|
11
|
+
"sync_config": {
|
|
12
|
+
"desc": "Synchronize Config/ConfigIndividual-Folders between Work and Repository (Eclipse-Repo)"
|
|
13
|
+
},
|
|
14
|
+
"t003_rewrite": {
|
|
15
|
+
"desc": "Rewrites t003 in DB"
|
|
16
|
+
},
|
|
17
|
+
"bundle_product":{
|
|
18
|
+
"desc": "Bundles the jWEGAS-Product after an Eclipse-Export"
|
|
19
|
+
},
|
|
20
|
+
"dump_db_mand": {
|
|
21
|
+
"desc": "Export a DB-Dump for a single Mandant"
|
|
22
|
+
},
|
|
23
|
+
"delete_db_mand": {
|
|
24
|
+
"desc": "Delete all Mandant-Data from a db"
|
|
25
|
+
},
|
|
26
|
+
"extd_search": {
|
|
27
|
+
"desc": "Search EXTD/EXTI interactively with full text search"
|
|
28
|
+
},
|
|
29
|
+
"set_cli_config": {
|
|
30
|
+
"desc": "Configure the Inteco CLI"
|
|
31
|
+
},
|
|
32
|
+
"dump_table_to_csv": {
|
|
33
|
+
"desc": "Dumps a specific table from multiple SQL-Exports to a CSV"
|
|
34
|
+
},
|
|
35
|
+
"csv_merge": {
|
|
36
|
+
"desc": "Merge multiple CSV-Files (with same headers) into single file (with optional filter)"
|
|
37
|
+
},
|
|
38
|
+
"adb_bridge": {
|
|
39
|
+
"desc": "Activates an ADB-Bridge-Connection to an Android-Device"
|
|
40
|
+
},
|
|
41
|
+
"adb_intent": {
|
|
42
|
+
"desc": "Sends a configurable Intent to an Android-Device"
|
|
43
|
+
},
|
|
44
|
+
"graphql_schema_export": {
|
|
45
|
+
"desc": "Dump the Graph-QL-Schema from an Endpoint"
|
|
46
|
+
}
|
|
47
47
|
}
|
|
@@ -1,70 +1,70 @@
|
|
|
1
|
-
import cfg from "application-config"
|
|
2
|
-
import defaultCFG from './default.json' with {type: 'json'};
|
|
3
|
-
|
|
4
|
-
export class Config{
|
|
5
|
-
static config = cfg("inteco_cli");
|
|
6
|
-
static configData;
|
|
7
|
-
|
|
8
|
-
static async initConfig(){
|
|
9
|
-
if(this.configData == null){
|
|
10
|
-
this.configData = await this.config.read();
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
if(Object.keys(this.configData).length === 0){
|
|
14
|
-
// Default Configuration
|
|
15
|
-
this.configData = defaultCFG
|
|
16
|
-
this.config.write(defaultCFG)
|
|
17
|
-
}else{
|
|
18
|
-
let data = this.configData;
|
|
19
|
-
let hasChange = false;
|
|
20
|
-
Object.keys(defaultCFG).forEach(key => {
|
|
21
|
-
// Write new config-entries if not present
|
|
22
|
-
if(!Object.keys(this.configData).includes(key)){
|
|
23
|
-
data[key] = defaultCFG[key];
|
|
24
|
-
hasChange = true;
|
|
25
|
-
}
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
Object.keys(this.configData).forEach(key => {
|
|
29
|
-
if(!Object.keys(defaultCFG).includes(key)){
|
|
30
|
-
delete data[key]
|
|
31
|
-
hasChange = true;
|
|
32
|
-
}
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
if(hasChange){
|
|
36
|
-
this.configData = data;
|
|
37
|
-
this.config.write(data);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
static async getConfig(){
|
|
43
|
-
await this.initConfig()
|
|
44
|
-
|
|
45
|
-
return this.configData
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
static async getConfigPath(){
|
|
49
|
-
await this.initConfig();
|
|
50
|
-
return this.config.filePath;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
static async setConfigField(field, value){
|
|
54
|
-
await this.initConfig();
|
|
55
|
-
|
|
56
|
-
let data = this.configData;
|
|
57
|
-
|
|
58
|
-
data[field] = value;
|
|
59
|
-
|
|
60
|
-
this.configData = data;
|
|
61
|
-
this.config.write(data);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
static async setConfig(data){
|
|
65
|
-
this.configData = data;
|
|
66
|
-
this.config.write(data);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}
|
|
1
|
+
import cfg from "application-config"
|
|
2
|
+
import defaultCFG from './default.json' with {type: 'json'};
|
|
3
|
+
|
|
4
|
+
export class Config{
|
|
5
|
+
static config = cfg("inteco_cli");
|
|
6
|
+
static configData;
|
|
7
|
+
|
|
8
|
+
static async initConfig(){
|
|
9
|
+
if(this.configData == null){
|
|
10
|
+
this.configData = await this.config.read();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if(Object.keys(this.configData).length === 0){
|
|
14
|
+
// Default Configuration
|
|
15
|
+
this.configData = defaultCFG
|
|
16
|
+
this.config.write(defaultCFG)
|
|
17
|
+
}else{
|
|
18
|
+
let data = this.configData;
|
|
19
|
+
let hasChange = false;
|
|
20
|
+
Object.keys(defaultCFG).forEach(key => {
|
|
21
|
+
// Write new config-entries if not present
|
|
22
|
+
if(!Object.keys(this.configData).includes(key)){
|
|
23
|
+
data[key] = defaultCFG[key];
|
|
24
|
+
hasChange = true;
|
|
25
|
+
}
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
Object.keys(this.configData).forEach(key => {
|
|
29
|
+
if(!Object.keys(defaultCFG).includes(key)){
|
|
30
|
+
delete data[key]
|
|
31
|
+
hasChange = true;
|
|
32
|
+
}
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
if(hasChange){
|
|
36
|
+
this.configData = data;
|
|
37
|
+
this.config.write(data);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
static async getConfig(){
|
|
43
|
+
await this.initConfig()
|
|
44
|
+
|
|
45
|
+
return this.configData
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
static async getConfigPath(){
|
|
49
|
+
await this.initConfig();
|
|
50
|
+
return this.config.filePath;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
static async setConfigField(field, value){
|
|
54
|
+
await this.initConfig();
|
|
55
|
+
|
|
56
|
+
let data = this.configData;
|
|
57
|
+
|
|
58
|
+
data[field] = value;
|
|
59
|
+
|
|
60
|
+
this.configData = data;
|
|
61
|
+
this.config.write(data);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
static async setConfig(data){
|
|
65
|
+
this.configData = data;
|
|
66
|
+
this.config.write(data);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
{
|
|
2
|
-
"configIndividualPath": "C:/Daten/eclipse_mars64_1/eclipse/configIndividual",
|
|
3
|
-
"configIndividualPathWrite": "C:\\\\Daten\\\\eclipse_mars64_1\\\\eclipse\\\\configIndividual",
|
|
4
|
-
"configIndividualPathEclipse": "C:/Daten/wegas-ws-mars/ch.inteco.wegas.model/configIndividual",
|
|
5
|
-
"dbURL": "127.0.0.1",
|
|
6
|
-
"dbUser": "",
|
|
7
|
-
"dbPassword": "",
|
|
8
|
-
"wegasUsername": ""
|
|
1
|
+
{
|
|
2
|
+
"configIndividualPath": "C:/Daten/eclipse_mars64_1/eclipse/configIndividual",
|
|
3
|
+
"configIndividualPathWrite": "C:\\\\Daten\\\\eclipse_mars64_1\\\\eclipse\\\\configIndividual",
|
|
4
|
+
"configIndividualPathEclipse": "C:/Daten/wegas-ws-mars/ch.inteco.wegas.model/configIndividual",
|
|
5
|
+
"dbURL": "127.0.0.1",
|
|
6
|
+
"dbUser": "",
|
|
7
|
+
"dbPassword": "",
|
|
8
|
+
"wegasUsername": ""
|
|
9
9
|
}
|
package/src/utils/db/DB.js
CHANGED
|
@@ -1,54 +1,54 @@
|
|
|
1
|
-
import mysql from "mysql-await"
|
|
2
|
-
import { Config } from "../config/config.js";
|
|
3
|
-
|
|
4
|
-
export class DB{
|
|
5
|
-
static connection;
|
|
6
|
-
|
|
7
|
-
static async connect(db){
|
|
8
|
-
const config = await Config.getConfig();
|
|
9
|
-
|
|
10
|
-
this.connection = mysql.createConnection({
|
|
11
|
-
host:config.dbURL,
|
|
12
|
-
user:config.dbUser,
|
|
13
|
-
password:config.dbPassword,
|
|
14
|
-
database: db!=null?db:""
|
|
15
|
-
})
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
static async executeQuery(query){
|
|
19
|
-
await this.connect(null)
|
|
20
|
-
|
|
21
|
-
let results = await this.connection.awaitQuery(query)
|
|
22
|
-
|
|
23
|
-
this.connection.end();
|
|
24
|
-
|
|
25
|
-
return results
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
static async executeQueryOnDB(query, db){
|
|
29
|
-
await this.connect(db)
|
|
30
|
-
|
|
31
|
-
let results = await this.connection.awaitQuery(query)
|
|
32
|
-
|
|
33
|
-
this.connection.end();
|
|
34
|
-
|
|
35
|
-
return results
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
static async getDatabaseNames(){
|
|
39
|
-
await this.connect(null)
|
|
40
|
-
|
|
41
|
-
let results = await this.connection.awaitQuery("SHOW DATABASES")
|
|
42
|
-
|
|
43
|
-
this.connection.end();
|
|
44
|
-
|
|
45
|
-
results = results.filter((val) => {
|
|
46
|
-
if(val.Database == "sys" || val.Database == "information_schema" || val.Database == "mysql" || val.Database == "performance_schema"){
|
|
47
|
-
return false;
|
|
48
|
-
}
|
|
49
|
-
return true
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
return results.map(result => {return {"name":result.Database}})
|
|
53
|
-
}
|
|
1
|
+
import mysql from "mysql-await"
|
|
2
|
+
import { Config } from "../config/config.js";
|
|
3
|
+
|
|
4
|
+
export class DB{
|
|
5
|
+
static connection;
|
|
6
|
+
|
|
7
|
+
static async connect(db){
|
|
8
|
+
const config = await Config.getConfig();
|
|
9
|
+
|
|
10
|
+
this.connection = mysql.createConnection({
|
|
11
|
+
host:config.dbURL,
|
|
12
|
+
user:config.dbUser,
|
|
13
|
+
password:config.dbPassword,
|
|
14
|
+
database: db!=null?db:""
|
|
15
|
+
})
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
static async executeQuery(query){
|
|
19
|
+
await this.connect(null)
|
|
20
|
+
|
|
21
|
+
let results = await this.connection.awaitQuery(query)
|
|
22
|
+
|
|
23
|
+
this.connection.end();
|
|
24
|
+
|
|
25
|
+
return results
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
static async executeQueryOnDB(query, db){
|
|
29
|
+
await this.connect(db)
|
|
30
|
+
|
|
31
|
+
let results = await this.connection.awaitQuery(query)
|
|
32
|
+
|
|
33
|
+
this.connection.end();
|
|
34
|
+
|
|
35
|
+
return results
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
static async getDatabaseNames(){
|
|
39
|
+
await this.connect(null)
|
|
40
|
+
|
|
41
|
+
let results = await this.connection.awaitQuery("SHOW DATABASES")
|
|
42
|
+
|
|
43
|
+
this.connection.end();
|
|
44
|
+
|
|
45
|
+
results = results.filter((val) => {
|
|
46
|
+
if(val.Database == "sys" || val.Database == "information_schema" || val.Database == "mysql" || val.Database == "performance_schema"){
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
return true
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
return results.map(result => {return {"name":result.Database}})
|
|
53
|
+
}
|
|
54
54
|
}
|
package/src/utils/fs/FS.js
CHANGED
|
@@ -1,88 +1,88 @@
|
|
|
1
|
-
import { statSync, mkdirSync, existsSync, copyFileSync, readdirSync } from "fs";
|
|
2
|
-
import chalk from "chalk";
|
|
3
|
-
import path from "path";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
export class FS {
|
|
7
|
-
static copyUpdatedFiles(sourceDir, destDir, dryRun = false, stats = { added: 0, updated: 0 }, filenameBlacklist = []) {
|
|
8
|
-
if (!existsSync(destDir)) {
|
|
9
|
-
if (dryRun) {
|
|
10
|
-
console.log(chalk.gray(`[DryRun] Would create directory: ${destDir}`));
|
|
11
|
-
} else {
|
|
12
|
-
mkdirSync(destDir, { recursive: true });
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const entries = readdirSync(sourceDir, { withFileTypes: true });
|
|
17
|
-
|
|
18
|
-
for (const entry of entries) {
|
|
19
|
-
if(filenameBlacklist.includes(entry.name)) {
|
|
20
|
-
continue;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const sourcePath = path.join(sourceDir, entry.name);
|
|
24
|
-
const destPath = path.join(destDir, entry.name);
|
|
25
|
-
|
|
26
|
-
if (entry.isDirectory()) {
|
|
27
|
-
FS.copyUpdatedFiles(sourcePath, destPath, dryRun, stats, filenameBlacklist);
|
|
28
|
-
} else {
|
|
29
|
-
let shouldCopy = false;
|
|
30
|
-
|
|
31
|
-
if (!existsSync(destPath)) {
|
|
32
|
-
shouldCopy = true;
|
|
33
|
-
} else {
|
|
34
|
-
const sourceStat = statSync(sourcePath);
|
|
35
|
-
const destStat = statSync(destPath);
|
|
36
|
-
|
|
37
|
-
if (sourceStat.mtime > destStat.mtime) {
|
|
38
|
-
shouldCopy = true;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
if (shouldCopy) {
|
|
43
|
-
if (dryRun) {
|
|
44
|
-
console.log(chalk.blue(`[DryRun] Would update file: ${destPath}`));
|
|
45
|
-
} else {
|
|
46
|
-
copyFileSync(sourcePath, destPath);
|
|
47
|
-
}
|
|
48
|
-
stats.updated++;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
static copyAllFiles(sourceDir, destDir, dryRun = false, stats = { copied: 0 }, filenameBlacklist = []) {
|
|
56
|
-
if (!existsSync(destDir)) {
|
|
57
|
-
if (dryRun) {
|
|
58
|
-
console.log(chalk.gray(`[DryRun] Would create directory: ${destDir}`));
|
|
59
|
-
} else {
|
|
60
|
-
mkdirSync(destDir, { recursive: true });
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const entries = readdirSync(sourceDir, { withFileTypes: true });
|
|
65
|
-
|
|
66
|
-
for (const entry of entries) {
|
|
67
|
-
if(filenameBlacklist.includes(entry.name)) {
|
|
68
|
-
continue;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
const sourcePath = path.join(sourceDir, entry.name);
|
|
72
|
-
const destPath = path.join(destDir, entry.name);
|
|
73
|
-
|
|
74
|
-
if (entry.isDirectory()) {
|
|
75
|
-
FS.copyAllFiles(sourcePath, destPath, dryRun, stats, filenameBlacklist);
|
|
76
|
-
} else {
|
|
77
|
-
if (dryRun) {
|
|
78
|
-
console.log(chalk.magenta(`[DryRun] Would copy file: ${destPath}`));
|
|
79
|
-
} else {
|
|
80
|
-
copyFileSync(sourcePath, destPath);
|
|
81
|
-
}
|
|
82
|
-
stats.copied++;
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
|
|
1
|
+
import { statSync, mkdirSync, existsSync, copyFileSync, readdirSync } from "fs";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import path from "path";
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
export class FS {
|
|
7
|
+
static copyUpdatedFiles(sourceDir, destDir, dryRun = false, stats = { added: 0, updated: 0 }, filenameBlacklist = []) {
|
|
8
|
+
if (!existsSync(destDir)) {
|
|
9
|
+
if (dryRun) {
|
|
10
|
+
console.log(chalk.gray(`[DryRun] Would create directory: ${destDir}`));
|
|
11
|
+
} else {
|
|
12
|
+
mkdirSync(destDir, { recursive: true });
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const entries = readdirSync(sourceDir, { withFileTypes: true });
|
|
17
|
+
|
|
18
|
+
for (const entry of entries) {
|
|
19
|
+
if(filenameBlacklist.includes(entry.name)) {
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const sourcePath = path.join(sourceDir, entry.name);
|
|
24
|
+
const destPath = path.join(destDir, entry.name);
|
|
25
|
+
|
|
26
|
+
if (entry.isDirectory()) {
|
|
27
|
+
FS.copyUpdatedFiles(sourcePath, destPath, dryRun, stats, filenameBlacklist);
|
|
28
|
+
} else {
|
|
29
|
+
let shouldCopy = false;
|
|
30
|
+
|
|
31
|
+
if (!existsSync(destPath)) {
|
|
32
|
+
shouldCopy = true;
|
|
33
|
+
} else {
|
|
34
|
+
const sourceStat = statSync(sourcePath);
|
|
35
|
+
const destStat = statSync(destPath);
|
|
36
|
+
|
|
37
|
+
if (sourceStat.mtime > destStat.mtime) {
|
|
38
|
+
shouldCopy = true;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (shouldCopy) {
|
|
43
|
+
if (dryRun) {
|
|
44
|
+
console.log(chalk.blue(`[DryRun] Would update file: ${destPath}`));
|
|
45
|
+
} else {
|
|
46
|
+
copyFileSync(sourcePath, destPath);
|
|
47
|
+
}
|
|
48
|
+
stats.updated++;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
static copyAllFiles(sourceDir, destDir, dryRun = false, stats = { copied: 0 }, filenameBlacklist = []) {
|
|
56
|
+
if (!existsSync(destDir)) {
|
|
57
|
+
if (dryRun) {
|
|
58
|
+
console.log(chalk.gray(`[DryRun] Would create directory: ${destDir}`));
|
|
59
|
+
} else {
|
|
60
|
+
mkdirSync(destDir, { recursive: true });
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const entries = readdirSync(sourceDir, { withFileTypes: true });
|
|
65
|
+
|
|
66
|
+
for (const entry of entries) {
|
|
67
|
+
if(filenameBlacklist.includes(entry.name)) {
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const sourcePath = path.join(sourceDir, entry.name);
|
|
72
|
+
const destPath = path.join(destDir, entry.name);
|
|
73
|
+
|
|
74
|
+
if (entry.isDirectory()) {
|
|
75
|
+
FS.copyAllFiles(sourcePath, destPath, dryRun, stats, filenameBlacklist);
|
|
76
|
+
} else {
|
|
77
|
+
if (dryRun) {
|
|
78
|
+
console.log(chalk.magenta(`[DryRun] Would copy file: ${destPath}`));
|
|
79
|
+
} else {
|
|
80
|
+
copyFileSync(sourcePath, destPath);
|
|
81
|
+
}
|
|
82
|
+
stats.copied++;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
|
|
88
88
|
}
|