@tltdh61/dotenvrtdb 1.260331.11828 → 1.260331.11957
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/cli.js +352 -154
- package/package.json +1 -1
package/cli.js
CHANGED
|
@@ -15,6 +15,33 @@ const spawn = require("cross-spawn");
|
|
|
15
15
|
const path = require("path");
|
|
16
16
|
const fs = require("fs");
|
|
17
17
|
|
|
18
|
+
function formatErrorMessage(context = "unknown", err) {
|
|
19
|
+
if (!err) return `[${context}] Unknown error`;
|
|
20
|
+
const message = err && err.message ? err.message : String(err);
|
|
21
|
+
const code = err && err.code ? ` | code=${err.code}` : "";
|
|
22
|
+
const syscall = err && err.syscall ? ` | syscall=${err.syscall}` : "";
|
|
23
|
+
const filePath = err && err.path ? ` | path=${err.path}` : "";
|
|
24
|
+
const cause =
|
|
25
|
+
err && err.cause
|
|
26
|
+
? ` | cause=${err.cause && err.cause.message ? err.cause.message : String(err.cause)}`
|
|
27
|
+
: "";
|
|
28
|
+
return `[${context}] ${message}${code}${syscall}${filePath}${cause}`;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function logSyncStatus(action = "sync", { status = "unknown", file = "-", varCount = 0, message = "" } = {}) {
|
|
32
|
+
const normalizedStatus = `${status || "unknown"}`.toUpperCase();
|
|
33
|
+
const safeAction = `${action || "sync"}`.toUpperCase();
|
|
34
|
+
const detail = message ? ` | reason=${message}` : "";
|
|
35
|
+
console.log(`[${safeAction}] status=${normalizedStatus} | file=${file || "-"} | vars=${Number.isFinite(varCount) ? varCount : 0}${detail}`);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function ensureParentDirExists(filePath = "") {
|
|
39
|
+
const target = `${filePath || ""}`.trim();
|
|
40
|
+
if (!target) return;
|
|
41
|
+
const absPath = path.resolve(target);
|
|
42
|
+
fs.mkdirSync(path.dirname(absPath), { recursive: true });
|
|
43
|
+
}
|
|
44
|
+
|
|
18
45
|
const rtdbUtils = (() => {
|
|
19
46
|
let rtdbUrl = ``;
|
|
20
47
|
|
|
@@ -52,6 +79,49 @@ const rtdbUtils = (() => {
|
|
|
52
79
|
return resolved.trim();
|
|
53
80
|
}
|
|
54
81
|
|
|
82
|
+
function parseFileValueDirective(value = "") {
|
|
83
|
+
if (typeof value !== "string") return null;
|
|
84
|
+
const v = value.trim();
|
|
85
|
+
if (!v) return null;
|
|
86
|
+
|
|
87
|
+
if (v.startsWith("file:raw:")) {
|
|
88
|
+
const filePath = v.slice("file:raw:".length).trim();
|
|
89
|
+
if (!filePath) return null;
|
|
90
|
+
return { type: "raw", filePath };
|
|
91
|
+
}
|
|
92
|
+
if (v.startsWith("file:base64:")) {
|
|
93
|
+
const filePath = v.slice("file:base64:".length).trim();
|
|
94
|
+
if (!filePath) return null;
|
|
95
|
+
return { type: "base64", filePath };
|
|
96
|
+
}
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function resolveEnvFileDirectives(objVar = {}, options = {}) {
|
|
101
|
+
const baseDir = options && options.baseDir ? options.baseDir : process.cwd();
|
|
102
|
+
const next = { ...objVar };
|
|
103
|
+
|
|
104
|
+
for (const [key, val] of Object.entries(objVar || {})) {
|
|
105
|
+
const directive = parseFileValueDirective(val);
|
|
106
|
+
if (!directive) continue;
|
|
107
|
+
|
|
108
|
+
const fullPath = path.isAbsolute(directive.filePath) ? directive.filePath : path.resolve(baseDir, directive.filePath);
|
|
109
|
+
if (!fs.existsSync(fullPath)) {
|
|
110
|
+
throw new Error(`[directive] File not found for key "${key}": ${fullPath}`);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (directive.type === "raw") {
|
|
114
|
+
next[key] = fs.readFileSync(fullPath, "utf8");
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
if (directive.type === "base64") {
|
|
118
|
+
next[key] = fs.readFileSync(fullPath).toString("base64");
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return next;
|
|
123
|
+
}
|
|
124
|
+
|
|
55
125
|
// --- pushTo ---
|
|
56
126
|
const pushTo = async (objVar = {}) => {
|
|
57
127
|
try {
|
|
@@ -82,7 +152,7 @@ const rtdbUtils = (() => {
|
|
|
82
152
|
}
|
|
83
153
|
return true;
|
|
84
154
|
} catch (err) {
|
|
85
|
-
console.error(
|
|
155
|
+
console.error(formatErrorMessage("rtdb PATCH error", err));
|
|
86
156
|
return false;
|
|
87
157
|
}
|
|
88
158
|
};
|
|
@@ -93,18 +163,21 @@ const rtdbUtils = (() => {
|
|
|
93
163
|
const p = `${envPath || ""}`.trim();
|
|
94
164
|
if (!p) {
|
|
95
165
|
console.error(`[rtdb] Missing -e <path> for --push`);
|
|
96
|
-
return false;
|
|
166
|
+
return { ok: false, file: p || "-", varCount: 0 };
|
|
97
167
|
}
|
|
98
168
|
if (!fs.existsSync(p)) {
|
|
99
169
|
console.error(`[rtdb] Env file not found: ${p}`);
|
|
100
|
-
return false;
|
|
170
|
+
return { ok: false, file: p, varCount: 0 };
|
|
101
171
|
}
|
|
102
172
|
const content = fs.readFileSync(p, "utf8");
|
|
103
173
|
const parsed = dotenv.parse(content); // {KEY:VAL}
|
|
104
|
-
|
|
174
|
+
const resolvedVars = resolveEnvFileDirectives(parsed, { baseDir: path.dirname(path.resolve(p)) });
|
|
175
|
+
const varCount = Object.keys(resolvedVars || {}).length;
|
|
176
|
+
const ok = await pushTo(resolvedVars);
|
|
177
|
+
return { ok, file: p, varCount, reason: ok ? "" : "RTDB PATCH failed" };
|
|
105
178
|
} catch (err) {
|
|
106
|
-
console.error(
|
|
107
|
-
return false;
|
|
179
|
+
console.error(formatErrorMessage("rtdb envPathPushTo error", err));
|
|
180
|
+
return { ok: false, file: `${envPath || "-"} `.trim(), varCount: 0, reason: err && err.message ? err.message : String(err) };
|
|
108
181
|
}
|
|
109
182
|
};
|
|
110
183
|
|
|
@@ -125,7 +198,7 @@ const rtdbUtils = (() => {
|
|
|
125
198
|
if (!data || typeof data !== "object" || Array.isArray(data)) return {};
|
|
126
199
|
return data;
|
|
127
200
|
} catch (err) {
|
|
128
|
-
console.error(
|
|
201
|
+
console.error(formatErrorMessage("rtdb GET error", err));
|
|
129
202
|
return {};
|
|
130
203
|
}
|
|
131
204
|
};
|
|
@@ -199,7 +272,7 @@ const rtdbUtils = (() => {
|
|
|
199
272
|
}
|
|
200
273
|
return { ok: true, value: `${parsed[key] ?? ""}` };
|
|
201
274
|
} catch (err) {
|
|
202
|
-
console.error(
|
|
275
|
+
console.error(formatErrorMessage("env readEnvVarFromPath error", err));
|
|
203
276
|
return { ok: false, value: "" };
|
|
204
277
|
}
|
|
205
278
|
}
|
|
@@ -226,7 +299,7 @@ const rtdbUtils = (() => {
|
|
|
226
299
|
}
|
|
227
300
|
return { ok: true, buffer };
|
|
228
301
|
} catch (err) {
|
|
229
|
-
console.error(
|
|
302
|
+
console.error(formatErrorMessage("env decodeBase64ToBuffer error", err));
|
|
230
303
|
return { ok: false, buffer: Buffer.alloc(0) };
|
|
231
304
|
}
|
|
232
305
|
}
|
|
@@ -304,6 +377,8 @@ const rtdbUtils = (() => {
|
|
|
304
377
|
serializeEnv,
|
|
305
378
|
readEnvVarFromPath,
|
|
306
379
|
decodeBase64ToBuffer,
|
|
380
|
+
parseFileValueDirective,
|
|
381
|
+
resolveEnvFileDirectives,
|
|
307
382
|
ensureEnvPathProvidedAndExists,
|
|
308
383
|
normalizeLegacyArgs,
|
|
309
384
|
getVietnamDateTime,
|
|
@@ -334,7 +409,9 @@ function printHelp() {
|
|
|
334
409
|
' also supports inline env: dotenvrtdb --shell -- FOO=bar "echo %FOO%"',
|
|
335
410
|
" --writefileraw=<path> write raw value from --var=<name> in -e <path> env file to <path>",
|
|
336
411
|
" --writefilebase64=<path> read --var=<name> from -e <path>, decode base64, then write binary to <path>",
|
|
337
|
-
" --var=<name> env variable name used by --writefileraw/--writefilebase64",
|
|
412
|
+
" --var=<name> env variable name used by --writefileraw/--writefilebase64 (repeatable, mapped by order)",
|
|
413
|
+
" --varraw=<name> optional explicit variable for --writefileraw (repeatable, one-to-one with --writefileraw)",
|
|
414
|
+
" --varbase64=<name> optional explicit variable for --writefilebase64 (repeatable, one-to-one with --writefilebase64)",
|
|
338
415
|
" -v <name>=<value> put variable <name> into environment using value <value>",
|
|
339
416
|
" -v <name>=<value> multiple -v flags are allowed",
|
|
340
417
|
" -p <variable> print value of <variable> to the console. If you specify this, you do not have to specify a `command`",
|
|
@@ -356,25 +433,26 @@ function validateCmdVariable(param) {
|
|
|
356
433
|
}
|
|
357
434
|
|
|
358
435
|
async function main() {
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
436
|
+
try {
|
|
437
|
+
if (argv.help) {
|
|
438
|
+
printHelp();
|
|
439
|
+
process.exit();
|
|
440
|
+
}
|
|
363
441
|
|
|
364
|
-
|
|
442
|
+
const override = argv.o || argv.override;
|
|
365
443
|
|
|
366
|
-
|
|
367
|
-
|
|
444
|
+
// Handle quiet flag - default is true (quiet), can be disabled with --quiet=false or -q=false
|
|
445
|
+
const isQuiet = !(argv.quiet === false || argv.q === false || argv.quiet === "false" || argv.q === "false");
|
|
368
446
|
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
447
|
+
if (argv.c && override) {
|
|
448
|
+
console.error("Invalid arguments. Cascading env variables conflicts with overrides.");
|
|
449
|
+
process.exit(1);
|
|
450
|
+
}
|
|
373
451
|
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
452
|
+
// Setup RTDB URL if provided
|
|
453
|
+
if (argv.eUrl) {
|
|
454
|
+
rtdbUtils.setUrl(argv.eUrl);
|
|
455
|
+
}
|
|
378
456
|
|
|
379
457
|
const executePush = async () => {
|
|
380
458
|
/**
|
|
@@ -383,13 +461,26 @@ async function main() {
|
|
|
383
461
|
if (!argv.push) return false;
|
|
384
462
|
if (!argv.eUrl) {
|
|
385
463
|
console.error(`Missing --eUrl=<url>. This is required for --push.`);
|
|
464
|
+
logSyncStatus("push", { status: "failed", file: "-", varCount: 0, message: "missing --eUrl" });
|
|
386
465
|
return true; // đã "xử lý" case push nhưng lỗi => vẫn kết thúc luồng
|
|
387
466
|
}
|
|
388
467
|
const { ok, envPath } = rtdbUtils.ensureEnvPathProvidedAndExists();
|
|
389
|
-
if (!ok)
|
|
468
|
+
if (!ok) {
|
|
469
|
+
logSyncStatus("push", { status: "failed", file: envPath || "-", varCount: 0, message: "missing/invalid -e path" });
|
|
470
|
+
return true;
|
|
471
|
+
}
|
|
390
472
|
|
|
391
|
-
const
|
|
392
|
-
if (!
|
|
473
|
+
const pushResult = await rtdbUtils.envPathPushTo(envPath);
|
|
474
|
+
if (!pushResult.ok) {
|
|
475
|
+
logSyncStatus("push", {
|
|
476
|
+
status: "failed",
|
|
477
|
+
file: pushResult.file || envPath,
|
|
478
|
+
varCount: pushResult.varCount || 0,
|
|
479
|
+
message: pushResult.reason || "unable to push env vars to RTDB",
|
|
480
|
+
});
|
|
481
|
+
process.exit(1);
|
|
482
|
+
}
|
|
483
|
+
logSyncStatus("push", { status: "success", file: pushResult.file || envPath, varCount: pushResult.varCount || 0 });
|
|
393
484
|
return true;
|
|
394
485
|
};
|
|
395
486
|
|
|
@@ -400,21 +491,47 @@ async function main() {
|
|
|
400
491
|
if (!argv.pull) return false;
|
|
401
492
|
if (!argv.eUrl) {
|
|
402
493
|
console.error(`Missing --eUrl=<url>. This is required for --pull.`);
|
|
494
|
+
logSyncStatus("pull", { status: "failed", file: "-", varCount: 0, message: "missing --eUrl" });
|
|
403
495
|
return true; // đã "xử lý" case pull nhưng lỗi => vẫn kết thúc luồng
|
|
404
496
|
}
|
|
405
|
-
|
|
406
|
-
if (
|
|
497
|
+
let envPath = "";
|
|
498
|
+
if (argv.e) {
|
|
499
|
+
envPath = typeof argv.e === "string" ? argv.e : argv.e[0];
|
|
500
|
+
}
|
|
501
|
+
envPath = `${envPath || ""}`.trim();
|
|
502
|
+
if (!envPath) {
|
|
503
|
+
logSyncStatus("pull", { status: "failed", file: "-", varCount: 0, message: "missing -e <path>" });
|
|
504
|
+
return true;
|
|
505
|
+
}
|
|
506
|
+
if (!fs.existsSync(envPath)) {
|
|
507
|
+
try {
|
|
508
|
+
const absPath = path.resolve(envPath);
|
|
509
|
+
fs.mkdirSync(path.dirname(absPath), { recursive: true });
|
|
510
|
+
fs.writeFileSync(absPath, "", "utf8");
|
|
511
|
+
} catch (err) {
|
|
512
|
+
logSyncStatus("pull", {
|
|
513
|
+
status: "failed",
|
|
514
|
+
file: envPath,
|
|
515
|
+
varCount: 0,
|
|
516
|
+
message: formatErrorMessage("pull create env file failed", err),
|
|
517
|
+
});
|
|
518
|
+
process.exit(1);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
407
521
|
|
|
408
522
|
const objVar = {
|
|
409
523
|
...rtdbUtils.getDefaultRtdbEnv(),
|
|
410
524
|
...(await rtdbUtils.pullFrom()),
|
|
411
525
|
};
|
|
526
|
+
const pullVarCount = Object.keys(objVar || {}).length;
|
|
412
527
|
|
|
413
528
|
try {
|
|
414
529
|
const out = rtdbUtils.serializeEnv(objVar);
|
|
415
530
|
fs.writeFileSync(envPath, out, "utf8");
|
|
531
|
+
logSyncStatus("pull", { status: "success", file: envPath, varCount: pullVarCount });
|
|
416
532
|
} catch (err) {
|
|
417
533
|
console.error(`[pull] write error: ${err && err.message ? err.message : err}`);
|
|
534
|
+
logSyncStatus("pull", { status: "failed", file: envPath, varCount: pullVarCount, message: "write file failed" });
|
|
418
535
|
process.exit(1);
|
|
419
536
|
}
|
|
420
537
|
return true;
|
|
@@ -426,28 +543,54 @@ async function main() {
|
|
|
426
543
|
*/
|
|
427
544
|
if (!argv.writefileraw) return false;
|
|
428
545
|
|
|
429
|
-
const
|
|
430
|
-
|
|
546
|
+
const outPaths = (Array.isArray(argv.writefileraw) ? argv.writefileraw : [argv.writefileraw])
|
|
547
|
+
.map((v) => (typeof v === "string" ? v.trim() : ""))
|
|
548
|
+
.filter(Boolean);
|
|
549
|
+
if (outPaths.length === 0) {
|
|
431
550
|
console.error(`Missing --writefileraw=<path>.`);
|
|
432
551
|
return true;
|
|
433
552
|
}
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
553
|
+
|
|
554
|
+
const explicitRawVars = (Array.isArray(argv.varraw || argv.varRaw) ? argv.varraw || argv.varRaw : [argv.varraw || argv.varRaw])
|
|
555
|
+
.map((v) => (typeof v === "string" ? v.trim() : ""))
|
|
556
|
+
.filter(Boolean);
|
|
557
|
+
|
|
558
|
+
const varNames = [];
|
|
559
|
+
if (explicitRawVars.length > 0) {
|
|
560
|
+
if (explicitRawVars.length !== outPaths.length) {
|
|
561
|
+
console.error(`--varraw must have the same number of entries as --writefileraw.`);
|
|
562
|
+
return true;
|
|
563
|
+
}
|
|
564
|
+
varNames.push(...explicitRawVars);
|
|
565
|
+
} else {
|
|
566
|
+
for (let i = 0; i < outPaths.length; i++) {
|
|
567
|
+
const v = varPool[varCursor++] || "";
|
|
568
|
+
varNames.push(v.trim());
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
if (varNames.some((v) => !v)) {
|
|
573
|
+
console.error(`Missing --var=<name>. This is required for --writefileraw (one var per output path).`);
|
|
437
574
|
return true;
|
|
438
575
|
}
|
|
439
576
|
|
|
440
577
|
const { ok, envPath } = rtdbUtils.ensureEnvPathProvidedAndExists();
|
|
441
578
|
if (!ok) return true;
|
|
442
579
|
|
|
443
|
-
|
|
444
|
-
|
|
580
|
+
for (let i = 0; i < outPaths.length; i++) {
|
|
581
|
+
const outPath = outPaths[i];
|
|
582
|
+
const varName = varNames[i];
|
|
445
583
|
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
584
|
+
const envVar = rtdbUtils.readEnvVarFromPath(envPath, varName);
|
|
585
|
+
if (!envVar.ok) process.exit(1);
|
|
586
|
+
|
|
587
|
+
try {
|
|
588
|
+
ensureParentDirExists(outPath);
|
|
589
|
+
fs.writeFileSync(outPath, envVar.value, "utf8");
|
|
590
|
+
} catch (err) {
|
|
591
|
+
console.error(`[writefileraw] write error: ${err && err.message ? err.message : err}`);
|
|
592
|
+
process.exit(1);
|
|
593
|
+
}
|
|
451
594
|
}
|
|
452
595
|
return true;
|
|
453
596
|
};
|
|
@@ -458,74 +601,110 @@ async function main() {
|
|
|
458
601
|
*/
|
|
459
602
|
if (!argv.writefilebase64) return false;
|
|
460
603
|
|
|
461
|
-
const
|
|
462
|
-
|
|
604
|
+
const outPaths = (Array.isArray(argv.writefilebase64) ? argv.writefilebase64 : [argv.writefilebase64])
|
|
605
|
+
.map((v) => (typeof v === "string" ? v.trim() : ""))
|
|
606
|
+
.filter(Boolean);
|
|
607
|
+
if (outPaths.length === 0) {
|
|
463
608
|
console.error(`Missing --writefilebase64=<path>.`);
|
|
464
609
|
return true;
|
|
465
610
|
}
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
611
|
+
|
|
612
|
+
const explicitB64Vars = (Array.isArray(argv.varbase64 || argv.varBase64) ? argv.varbase64 || argv.varBase64 : [argv.varbase64 || argv.varBase64])
|
|
613
|
+
.map((v) => (typeof v === "string" ? v.trim() : ""))
|
|
614
|
+
.filter(Boolean);
|
|
615
|
+
|
|
616
|
+
const varNames = [];
|
|
617
|
+
if (explicitB64Vars.length > 0) {
|
|
618
|
+
if (explicitB64Vars.length !== outPaths.length) {
|
|
619
|
+
console.error(`--varbase64 must have the same number of entries as --writefilebase64.`);
|
|
620
|
+
return true;
|
|
621
|
+
}
|
|
622
|
+
varNames.push(...explicitB64Vars);
|
|
623
|
+
} else {
|
|
624
|
+
for (let i = 0; i < outPaths.length; i++) {
|
|
625
|
+
const v = varPool[varCursor++] || "";
|
|
626
|
+
varNames.push(v.trim());
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
if (varNames.some((v) => !v)) {
|
|
631
|
+
console.error(`Missing --var=<name>. This is required for --writefilebase64 (one var per output path).`);
|
|
469
632
|
return true;
|
|
470
633
|
}
|
|
471
634
|
|
|
472
635
|
const { ok, envPath } = rtdbUtils.ensureEnvPathProvidedAndExists();
|
|
473
636
|
if (!ok) return true;
|
|
474
637
|
|
|
475
|
-
|
|
476
|
-
|
|
638
|
+
for (let i = 0; i < outPaths.length; i++) {
|
|
639
|
+
const outPath = outPaths[i];
|
|
640
|
+
const varName = varNames[i];
|
|
477
641
|
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
console.error(`[writefilebase64] Invalid base64 content in variable: ${varName}`);
|
|
481
|
-
process.exit(1);
|
|
482
|
-
}
|
|
642
|
+
const envVar = rtdbUtils.readEnvVarFromPath(envPath, varName);
|
|
643
|
+
if (!envVar.ok) process.exit(1);
|
|
483
644
|
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
645
|
+
const decoded = rtdbUtils.decodeBase64ToBuffer(envVar.value);
|
|
646
|
+
if (!decoded.ok) {
|
|
647
|
+
console.error(`[writefilebase64] Invalid base64 content in variable: ${varName}`);
|
|
648
|
+
process.exit(1);
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
try {
|
|
652
|
+
ensureParentDirExists(outPath);
|
|
653
|
+
fs.writeFileSync(outPath, decoded.buffer);
|
|
654
|
+
} catch (err) {
|
|
655
|
+
console.error(`[writefilebase64] write error: ${err && err.message ? err.message : err}`);
|
|
656
|
+
process.exit(1);
|
|
657
|
+
}
|
|
489
658
|
}
|
|
490
659
|
return true;
|
|
491
660
|
};
|
|
492
661
|
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
if (didPush === true || didPull === true || didWriteFileRaw === true || didWriteFileBase64 === true) {
|
|
498
|
-
// Push/Pull/WriteFile là mode riêng, chạy xong thoát
|
|
499
|
-
process.exit(0);
|
|
500
|
-
}
|
|
662
|
+
const varPool = (Array.isArray(argv.var) ? argv.var : [argv.var])
|
|
663
|
+
.map((v) => (typeof v === "string" ? v.trim() : ""))
|
|
664
|
+
.filter(Boolean);
|
|
665
|
+
let varCursor = 0;
|
|
501
666
|
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
} else {
|
|
507
|
-
paths.push(...argv.e);
|
|
667
|
+
const didPush = await executePush();
|
|
668
|
+
if (didPush === true) {
|
|
669
|
+
// push là mode riêng
|
|
670
|
+
process.exit(0);
|
|
508
671
|
}
|
|
509
|
-
} else {
|
|
510
|
-
paths.push(".env");
|
|
511
|
-
}
|
|
512
672
|
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
673
|
+
const didPull = await executePull();
|
|
674
|
+
const didWriteFileRaw = await executeWriteFileRaw();
|
|
675
|
+
const didWriteFileBase64 = await executeWriteFileBase64();
|
|
676
|
+
if (didPull === true || didWriteFileRaw === true || didWriteFileBase64 === true) {
|
|
677
|
+
// pull/writefile là mode riêng; cho phép kết hợp pull + writefile trong cùng một lệnh.
|
|
678
|
+
process.exit(0);
|
|
679
|
+
}
|
|
520
680
|
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
681
|
+
let paths = [];
|
|
682
|
+
if (argv.e) {
|
|
683
|
+
if (typeof argv.e === "string") {
|
|
684
|
+
paths.push(argv.e);
|
|
685
|
+
} else {
|
|
686
|
+
paths.push(...argv.e);
|
|
687
|
+
}
|
|
525
688
|
} else {
|
|
526
|
-
|
|
689
|
+
paths.push(".env");
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
if (argv.c) {
|
|
693
|
+
paths = paths.reduce(
|
|
694
|
+
(accumulator, p) =>
|
|
695
|
+
accumulator.concat(typeof argv.c === "string" ? [`${p}.${argv.c}.local`, `${p}.local`, `${p}.${argv.c}`, p] : [`${p}.local`, p]),
|
|
696
|
+
[],
|
|
697
|
+
);
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
const variables = [];
|
|
701
|
+
if (argv.v) {
|
|
702
|
+
if (typeof argv.v === "string") {
|
|
703
|
+
variables.push(validateCmdVariable(argv.v));
|
|
704
|
+
} else {
|
|
705
|
+
variables.push(...argv.v.map(validateCmdVariable));
|
|
706
|
+
}
|
|
527
707
|
}
|
|
528
|
-
}
|
|
529
708
|
|
|
530
709
|
const parseUrlToArgV = async () => {
|
|
531
710
|
/**
|
|
@@ -553,42 +732,52 @@ async function main() {
|
|
|
553
732
|
}
|
|
554
733
|
};
|
|
555
734
|
|
|
556
|
-
|
|
735
|
+
await parseUrlToArgV();
|
|
557
736
|
|
|
558
737
|
// Merge default env với variables (variables sẽ override default)
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
738
|
+
const defaultEnv = rtdbUtils.getDefaultRtdbEnv() || {};
|
|
739
|
+
const parsedVariables = {
|
|
740
|
+
...defaultEnv,
|
|
741
|
+
...Object.fromEntries(variables),
|
|
742
|
+
};
|
|
564
743
|
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
744
|
+
if (argv.debug) {
|
|
745
|
+
console.log(paths);
|
|
746
|
+
console.log(parsedVariables);
|
|
747
|
+
process.exit();
|
|
748
|
+
}
|
|
570
749
|
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
750
|
+
paths.forEach(function (env) {
|
|
751
|
+
try {
|
|
752
|
+
dotenv.config({ path: path.resolve(env), override, quiet: isQuiet });
|
|
753
|
+
} catch (err) {
|
|
754
|
+
console.error(formatErrorMessage(`dotenv config failed for ${env}`, err));
|
|
755
|
+
process.exit(1);
|
|
756
|
+
}
|
|
757
|
+
});
|
|
574
758
|
|
|
575
759
|
// Expand when all path configs are loaded
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
760
|
+
if (argv.expand !== false) {
|
|
761
|
+
try {
|
|
762
|
+
dotenvExpand({
|
|
763
|
+
parsed: process.env,
|
|
764
|
+
});
|
|
765
|
+
} catch (err) {
|
|
766
|
+
console.error(formatErrorMessage("dotenv expand failed", err));
|
|
767
|
+
process.exit(1);
|
|
768
|
+
}
|
|
769
|
+
}
|
|
581
770
|
|
|
582
|
-
|
|
771
|
+
Object.assign(process.env, parsedVariables);
|
|
583
772
|
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
773
|
+
if (argv.p) {
|
|
774
|
+
let value = process.env[argv.p];
|
|
775
|
+
if (typeof value === "string") {
|
|
776
|
+
value = `${value}`;
|
|
777
|
+
}
|
|
778
|
+
console.log(value != null ? value : "");
|
|
779
|
+
process.exit();
|
|
588
780
|
}
|
|
589
|
-
console.log(value != null ? value : "");
|
|
590
|
-
process.exit();
|
|
591
|
-
}
|
|
592
781
|
|
|
593
782
|
// cross-env-shell style: allow `KEY=VALUE` at the beginning of the command section (after `--`)
|
|
594
783
|
function parseLeadingEnvAssignments(args = []) {
|
|
@@ -608,59 +797,68 @@ async function main() {
|
|
|
608
797
|
return { env, rest: args.slice(i) };
|
|
609
798
|
}
|
|
610
799
|
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
800
|
+
const shellOptRaw = argv.shell;
|
|
801
|
+
let shellOpt = shellOptRaw;
|
|
802
|
+
if (typeof shellOptRaw === "string") {
|
|
803
|
+
const t = shellOptRaw.trim().toLowerCase();
|
|
804
|
+
if (t === "true" || t === "1" || t === "yes") shellOpt = true;
|
|
805
|
+
else if (t === "false" || t === "0" || t === "no") shellOpt = false;
|
|
806
|
+
else shellOpt = shellOptRaw.trim();
|
|
807
|
+
}
|
|
619
808
|
|
|
620
|
-
|
|
621
|
-
|
|
809
|
+
const runInShell = shellOpt === true || (typeof shellOpt === "string" && shellOpt !== "");
|
|
810
|
+
const { env: inlineEnv, rest: cmdArgs } = runInShell ? parseLeadingEnvAssignments(argv._) : { env: {}, rest: argv._ };
|
|
622
811
|
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
812
|
+
if (cmdArgs.length === 0) {
|
|
813
|
+
printHelp();
|
|
814
|
+
process.exit(1);
|
|
815
|
+
}
|
|
627
816
|
|
|
628
|
-
|
|
817
|
+
const childEnv = Object.keys(inlineEnv).length ? Object.assign({}, process.env, inlineEnv) : process.env;
|
|
629
818
|
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
819
|
+
const spawnOpts = {
|
|
820
|
+
stdio: "inherit",
|
|
821
|
+
env: childEnv,
|
|
822
|
+
};
|
|
634
823
|
|
|
635
824
|
// If --shell is provided:
|
|
636
825
|
// - boolean true => use platform default shell
|
|
637
826
|
// - string => pass through to node spawn `shell` option (advanced)
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
} else {
|
|
644
|
-
const command = cmdArgs[0];
|
|
645
|
-
child = spawn(command, cmdArgs.slice(1), spawnOpts);
|
|
646
|
-
}
|
|
647
|
-
|
|
648
|
-
child.on("exit", function (exitCode, signal) {
|
|
649
|
-
if (typeof exitCode === "number") {
|
|
650
|
-
process.exit(exitCode);
|
|
827
|
+
let child;
|
|
828
|
+
if (runInShell) {
|
|
829
|
+
const shellCommand = cmdArgs.length === 1 ? cmdArgs[0] : cmdArgs.join(" ");
|
|
830
|
+
const shellVal = typeof shellOpt === "string" ? shellOpt : true;
|
|
831
|
+
child = spawn(shellCommand, [], Object.assign({}, spawnOpts, { shell: shellVal }));
|
|
651
832
|
} else {
|
|
652
|
-
|
|
833
|
+
const command = cmdArgs[0];
|
|
834
|
+
child = spawn(command, cmdArgs.slice(1), spawnOpts);
|
|
653
835
|
}
|
|
654
|
-
});
|
|
655
836
|
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
837
|
+
child.on("error", function (err) {
|
|
838
|
+
console.error(formatErrorMessage("spawn process error", err));
|
|
839
|
+
process.exit(1);
|
|
659
840
|
});
|
|
841
|
+
|
|
842
|
+
child.on("exit", function (exitCode, signal) {
|
|
843
|
+
if (typeof exitCode === "number") {
|
|
844
|
+
process.exit(exitCode);
|
|
845
|
+
} else {
|
|
846
|
+
process.kill(process.pid, signal);
|
|
847
|
+
}
|
|
848
|
+
});
|
|
849
|
+
|
|
850
|
+
for (const signal of ["SIGINT", "SIGTERM", "SIGPIPE", "SIGHUP", "SIGBREAK", "SIGWINCH", "SIGUSR1", "SIGUSR2"]) {
|
|
851
|
+
process.on(signal, function () {
|
|
852
|
+
child.kill(signal);
|
|
853
|
+
});
|
|
854
|
+
}
|
|
855
|
+
} catch (err) {
|
|
856
|
+
console.error(formatErrorMessage("main error", err));
|
|
857
|
+
process.exit(1);
|
|
660
858
|
}
|
|
661
859
|
}
|
|
662
860
|
|
|
663
861
|
main().catch((err) => {
|
|
664
|
-
console.error(
|
|
862
|
+
console.error(formatErrorMessage("fatal error", err));
|
|
665
863
|
process.exit(1);
|
|
666
864
|
});
|