@naturalcycles/nodejs-lib 13.31.1 → 13.33.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/dist/csv/csvReader.js +2 -2
- package/dist/fs/fs2.js +6 -3
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/slack/slack.service.js +2 -4
- package/dist/stream/ndjson/transformJsonParse.js +1 -1
- package/dist/stream/transform/transformMap.d.ts +4 -2
- package/dist/stream/transform/transformMap.js +2 -2
- package/dist/stream/transform/transformSplit.js +2 -2
- package/dist/stream/transform/worker/workerClassProxy.js +2 -2
- package/dist/stream/writable/writableLimit.js +1 -1
- package/dist/stream/writable/writableVoid.js +1 -1
- package/dist/util/buildInfo.util.js +5 -5
- package/dist/util/exec2.d.ts +167 -0
- package/dist/util/exec2.js +204 -0
- package/dist/util/git2.d.ts +25 -0
- package/dist/util/git2.js +95 -0
- package/dist/validation/joi/number.extensions.d.ts +2 -1
- package/dist/validation/joi/string.extensions.d.ts +2 -1
- package/package.json +3 -2
- package/src/csv/csvReader.ts +2 -7
- package/src/fs/fs2.ts +11 -7
- package/src/index.ts +2 -2
- package/src/secret/secrets-decrypt.util.ts +1 -1
- package/src/secret/secrets-encrypt.util.ts +1 -1
- package/src/slack/slack.service.ts +2 -3
- package/src/stream/ndjson/transformJsonParse.ts +1 -1
- package/src/stream/stream.model.ts +2 -2
- package/src/stream/transform/transformMap.ts +5 -3
- package/src/stream/transform/transformSplit.ts +3 -3
- package/src/stream/transform/worker/workerClassProxy.js +2 -2
- package/src/stream/writable/writableLimit.ts +1 -1
- package/src/stream/writable/writableVoid.ts +1 -1
- package/src/util/buildInfo.util.ts +5 -10
- package/src/util/exec2.ts +326 -0
- package/src/util/git2.ts +105 -0
- package/src/validation/joi/number.extensions.ts +2 -1
- package/src/validation/joi/string.extensions.ts +2 -1
- package/dist/util/exec.util.d.ts +0 -10
- package/dist/util/exec.util.js +0 -58
- package/dist/util/git.util.d.ts +0 -18
- package/dist/util/git.util.js +0 -109
- package/src/util/exec.util.ts +0 -79
- package/src/util/git.util.ts +0 -113
package/dist/csv/csvReader.js
CHANGED
|
@@ -34,14 +34,14 @@ function csvStringParse(str, cfg = {}) {
|
|
|
34
34
|
});
|
|
35
35
|
}
|
|
36
36
|
function csvStringToArray(str) {
|
|
37
|
-
const objPattern =
|
|
37
|
+
const objPattern = /(,|\r?\n|\r|^)(?:"([^"]*(?:""[^"]*)*)"|([^,\r\n]*))/gi;
|
|
38
38
|
let matches;
|
|
39
39
|
const arr = [[]];
|
|
40
40
|
while ((matches = objPattern.exec(str))) {
|
|
41
41
|
if (matches[1].length && matches[1] !== ',') {
|
|
42
42
|
arr.push([]);
|
|
43
43
|
}
|
|
44
|
-
arr[arr.length - 1].push(matches[2] ? matches[2].replaceAll(
|
|
44
|
+
arr[arr.length - 1].push(matches[2] ? matches[2].replaceAll('""', '"') : matches[3]);
|
|
45
45
|
}
|
|
46
46
|
return arr;
|
|
47
47
|
}
|
package/dist/fs/fs2.js
CHANGED
|
@@ -188,8 +188,10 @@ class FS2 {
|
|
|
188
188
|
}
|
|
189
189
|
catch (err) {
|
|
190
190
|
// If the stat call above failed because the directory doesn't exist, create it
|
|
191
|
-
if (err?.code === 'ENOENT')
|
|
192
|
-
|
|
191
|
+
if (err?.code === 'ENOENT') {
|
|
192
|
+
this.ensureDir(dir);
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
193
195
|
throw err;
|
|
194
196
|
}
|
|
195
197
|
node_fs_1.default.writeFileSync(filePath, '');
|
|
@@ -230,7 +232,8 @@ class FS2 {
|
|
|
230
232
|
items = node_fs_1.default.readdirSync(dirPath);
|
|
231
233
|
}
|
|
232
234
|
catch {
|
|
233
|
-
|
|
235
|
+
this.ensureDir(dirPath);
|
|
236
|
+
return;
|
|
234
237
|
}
|
|
235
238
|
items.forEach(item => this.removePath(node_path_1.default.join(dirPath, item)));
|
|
236
239
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -62,8 +62,8 @@ export * from './stream/writable/writableVoid';
|
|
|
62
62
|
export * from './string/inspect';
|
|
63
63
|
export * from './util/buildInfo.util';
|
|
64
64
|
export * from './util/env.util';
|
|
65
|
-
export * from './util/
|
|
66
|
-
export * from './util/
|
|
65
|
+
export * from './util/exec2';
|
|
66
|
+
export * from './util/git2';
|
|
67
67
|
export * from './util/lruMemoCache';
|
|
68
68
|
export * from './util/zip.util';
|
|
69
69
|
export * from './validation/ajv/ajv.util';
|
package/dist/index.js
CHANGED
|
@@ -66,8 +66,8 @@ tslib_1.__exportStar(require("./stream/writable/writableVoid"), exports);
|
|
|
66
66
|
tslib_1.__exportStar(require("./string/inspect"), exports);
|
|
67
67
|
tslib_1.__exportStar(require("./util/buildInfo.util"), exports);
|
|
68
68
|
tslib_1.__exportStar(require("./util/env.util"), exports);
|
|
69
|
-
tslib_1.__exportStar(require("./util/
|
|
70
|
-
tslib_1.__exportStar(require("./util/
|
|
69
|
+
tslib_1.__exportStar(require("./util/exec2"), exports);
|
|
70
|
+
tslib_1.__exportStar(require("./util/git2"), exports);
|
|
71
71
|
tslib_1.__exportStar(require("./util/lruMemoCache"), exports);
|
|
72
72
|
tslib_1.__exportStar(require("./util/zip.util"), exports);
|
|
73
73
|
tslib_1.__exportStar(require("./validation/ajv/ajv.util"), exports);
|
|
@@ -65,7 +65,7 @@ class SlackService {
|
|
|
65
65
|
if (msg.kv) {
|
|
66
66
|
;
|
|
67
67
|
(msg.attachments ||= []).push({ fields: this.kvToFields(msg.kv) });
|
|
68
|
-
|
|
68
|
+
msg.kv = undefined; // to not pass it all the way to Slack Api
|
|
69
69
|
}
|
|
70
70
|
let text;
|
|
71
71
|
// Array has a special treatment here
|
|
@@ -101,9 +101,7 @@ class SlackService {
|
|
|
101
101
|
if (msg.throwOnError) {
|
|
102
102
|
throw err;
|
|
103
103
|
}
|
|
104
|
-
|
|
105
|
-
console.log(err);
|
|
106
|
-
}
|
|
104
|
+
console.log(err);
|
|
107
105
|
});
|
|
108
106
|
}
|
|
109
107
|
kvToFields(kv) {
|
|
@@ -43,7 +43,7 @@ function transformJsonParse(opt = {}) {
|
|
|
43
43
|
});
|
|
44
44
|
}
|
|
45
45
|
// Based on: https://stackoverflow.com/a/34557997/4919972
|
|
46
|
-
const bufferReviver = (
|
|
46
|
+
const bufferReviver = (_k, v) => {
|
|
47
47
|
if (v !== null && typeof v === 'object' && v.type === 'Buffer' && Array.isArray(v.data)) {
|
|
48
48
|
return Buffer.from(v.data);
|
|
49
49
|
}
|
|
@@ -18,10 +18,12 @@ export interface TransformMapOptions<IN = any, OUT = IN> {
|
|
|
18
18
|
/**
|
|
19
19
|
* Number of concurrently pending promises returned by `mapper`.
|
|
20
20
|
*
|
|
21
|
-
* Default is
|
|
21
|
+
* Default is 16.
|
|
22
22
|
* It was recently changed up from 16, after some testing that shown that
|
|
23
23
|
* for simple low-cpu mapper functions 32 produces almost 2x throughput.
|
|
24
24
|
* For example, in scenarios like streaming a query from Datastore.
|
|
25
|
+
* UPD: changed back from 32 to 16, "to be on a safe side", as 32 sometimes
|
|
26
|
+
* causes "Datastore timeout errors".
|
|
25
27
|
*/
|
|
26
28
|
concurrency?: number;
|
|
27
29
|
/**
|
|
@@ -86,7 +88,7 @@ export interface TransformMapStatsSummary extends TransformMapStats {
|
|
|
86
88
|
*
|
|
87
89
|
* Only works in objectMode (due to through2Concurrent).
|
|
88
90
|
*
|
|
89
|
-
* Concurrency defaults to
|
|
91
|
+
* Concurrency defaults to 16.
|
|
90
92
|
*
|
|
91
93
|
* If an Array is returned by `mapper` - it will be flattened and multiple results will be emitted from it. Tested by Array.isArray().
|
|
92
94
|
*/
|
|
@@ -16,12 +16,12 @@ const stream_util_1 = require("../stream.util");
|
|
|
16
16
|
*
|
|
17
17
|
* Only works in objectMode (due to through2Concurrent).
|
|
18
18
|
*
|
|
19
|
-
* Concurrency defaults to
|
|
19
|
+
* Concurrency defaults to 16.
|
|
20
20
|
*
|
|
21
21
|
* If an Array is returned by `mapper` - it will be flattened and multiple results will be emitted from it. Tested by Array.isArray().
|
|
22
22
|
*/
|
|
23
23
|
function transformMap(mapper, opt = {}) {
|
|
24
|
-
const { concurrency =
|
|
24
|
+
const { concurrency = 16, predicate, // we now default to "no predicate" (meaning pass-everything)
|
|
25
25
|
errorMode = js_lib_1.ErrorMode.THROW_IMMEDIATELY, flattenArrayOutput, onError, onDone, metric = 'stream', logger = console, } = opt;
|
|
26
26
|
const started = Date.now();
|
|
27
27
|
let index = -1;
|
|
@@ -17,7 +17,7 @@ function transformSplitOnNewline() {
|
|
|
17
17
|
return new node_stream_1.Transform({
|
|
18
18
|
readableObjectMode: true,
|
|
19
19
|
writableHighWaterMark: 64 * 1024,
|
|
20
|
-
transform(buf,
|
|
20
|
+
transform(buf, _enc, done) {
|
|
21
21
|
let offset = 0;
|
|
22
22
|
let lastMatch = 0;
|
|
23
23
|
if (buffered) {
|
|
@@ -61,7 +61,7 @@ function transformSplit(separator = '\n') {
|
|
|
61
61
|
return new node_stream_1.Transform({
|
|
62
62
|
readableObjectMode: true,
|
|
63
63
|
writableHighWaterMark: 64 * 1024,
|
|
64
|
-
transform(buf,
|
|
64
|
+
transform(buf, _enc, done) {
|
|
65
65
|
let offset = 0;
|
|
66
66
|
let lastMatch = 0;
|
|
67
67
|
if (buffered) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const started = Date.now()
|
|
2
|
-
const { workerData, parentPort } = require('worker_threads')
|
|
3
|
-
const { inspect } = require('util')
|
|
2
|
+
const { workerData, parentPort } = require('node:worker_threads')
|
|
3
|
+
const { inspect } = require('node:util')
|
|
4
4
|
const { workerFile, workerIndex, logEvery = 1000, metric = 'worker' } = workerData || {}
|
|
5
5
|
|
|
6
6
|
if (!workerFile) {
|
|
@@ -3,14 +3,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.generateBuildInfo = generateBuildInfo;
|
|
4
4
|
const js_lib_1 = require("@naturalcycles/js-lib");
|
|
5
5
|
const fs2_1 = require("../fs/fs2");
|
|
6
|
-
const
|
|
6
|
+
const git2_1 = require("./git2");
|
|
7
7
|
function generateBuildInfo(opt = {}) {
|
|
8
8
|
const now = js_lib_1.localTime.orNow(opt.overrideTimestamp);
|
|
9
9
|
const ts = now.unix;
|
|
10
|
-
const rev =
|
|
11
|
-
const branchName =
|
|
12
|
-
const repoName =
|
|
13
|
-
const tsCommit =
|
|
10
|
+
const rev = git2_1.git2.gitCurrentCommitSha();
|
|
11
|
+
const branchName = git2_1.git2.gitCurrentBranchName();
|
|
12
|
+
const repoName = git2_1.git2.gitCurrentRepoName();
|
|
13
|
+
const tsCommit = git2_1.git2.gitCurrentCommitTimestamp();
|
|
14
14
|
const ver = [now.toStringCompact(), repoName, branchName, rev].join('_');
|
|
15
15
|
let { APP_ENV: env } = process.env;
|
|
16
16
|
if (!env) {
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { AnyObject, AppError, NumberOfMilliseconds } from '@naturalcycles/js-lib';
|
|
2
|
+
/**
|
|
3
|
+
* Set of utility functions to work with Spawn / Exec.
|
|
4
|
+
*
|
|
5
|
+
* How to decide between Spawn and Exec?
|
|
6
|
+
*
|
|
7
|
+
* Long-running job that prints output, and no need to return the output - use Spawn.
|
|
8
|
+
*
|
|
9
|
+
* Short-running job, no need to print the output, might want to return the output - use Exec.
|
|
10
|
+
*
|
|
11
|
+
* Need to both print and return the output - use SpawnAsync.
|
|
12
|
+
*
|
|
13
|
+
* ***
|
|
14
|
+
*
|
|
15
|
+
* Spawn is good for long-running large-output processes, that continuously output data.
|
|
16
|
+
* E.g running `jest`.
|
|
17
|
+
*
|
|
18
|
+
* Exec is the opposite - good for short-running processes that output small data.
|
|
19
|
+
* Exec allows to return the output as a string.
|
|
20
|
+
* Exec doesn't stream data during execution, so the output/error will only be printed
|
|
21
|
+
* at the end.
|
|
22
|
+
* Exec always uses the shell (there's no option to disable it).
|
|
23
|
+
*/
|
|
24
|
+
declare class Exec2 {
|
|
25
|
+
/**
|
|
26
|
+
* Advanced/async version of Spawn.
|
|
27
|
+
* Consider simpler `spawn` or `exec` first, which are also sync.
|
|
28
|
+
*
|
|
29
|
+
* spawnAsync features:
|
|
30
|
+
*
|
|
31
|
+
* 1. Async
|
|
32
|
+
* 2. Allows to collect the output AND print it while running.
|
|
33
|
+
* 3. Returns SpawnOutput with stdout, stderr and exitCode.
|
|
34
|
+
* 4. Allows to not throw on error, but just return SpawnOutput for further inspection.
|
|
35
|
+
*
|
|
36
|
+
* Defaults:
|
|
37
|
+
*
|
|
38
|
+
* shell: true
|
|
39
|
+
* printWhileRunning: true
|
|
40
|
+
* collectOutputWhileRunning: true
|
|
41
|
+
* throwOnNonZeroCode: true
|
|
42
|
+
* log: true
|
|
43
|
+
*/
|
|
44
|
+
spawnAsync(cmd: string, opt?: SpawnAsyncOptions): Promise<SpawnOutput>;
|
|
45
|
+
/**
|
|
46
|
+
* Reasons to use it:
|
|
47
|
+
* - Sync
|
|
48
|
+
* - Need to print output while running
|
|
49
|
+
*
|
|
50
|
+
* Limitations:
|
|
51
|
+
* - Cannot return stdout/stderr (use exec or spawnAsync for that)
|
|
52
|
+
*
|
|
53
|
+
* Defaults:
|
|
54
|
+
*
|
|
55
|
+
* shell: true
|
|
56
|
+
* log: true
|
|
57
|
+
*/
|
|
58
|
+
spawn(cmd: string, opt?: SpawnOptions): void;
|
|
59
|
+
/**
|
|
60
|
+
* Reasons to use it:
|
|
61
|
+
*
|
|
62
|
+
* - Sync
|
|
63
|
+
* - Need to return output
|
|
64
|
+
*
|
|
65
|
+
* Limitations:
|
|
66
|
+
* - Cannot print while running (use spawn or spawnAsync for that)
|
|
67
|
+
*
|
|
68
|
+
* Defaults:
|
|
69
|
+
*
|
|
70
|
+
* shell: true
|
|
71
|
+
* log: true
|
|
72
|
+
*/
|
|
73
|
+
exec(cmd: string, opt?: ExecOptions): string;
|
|
74
|
+
throwOnNonZeroExitCode(o: SpawnOutput): void;
|
|
75
|
+
private logStart;
|
|
76
|
+
private logFinish;
|
|
77
|
+
}
|
|
78
|
+
export declare const exec2: Exec2;
|
|
79
|
+
export declare class SpawnError extends AppError<SpawnErrorData> {
|
|
80
|
+
constructor(message: string, data: SpawnErrorData);
|
|
81
|
+
}
|
|
82
|
+
export interface SpawnErrorData extends SpawnOutput {
|
|
83
|
+
}
|
|
84
|
+
export interface SpawnOutput {
|
|
85
|
+
/**
|
|
86
|
+
* Exit code of the spawned process.
|
|
87
|
+
* 0 means success, anything else means failure.
|
|
88
|
+
*/
|
|
89
|
+
exitCode: number;
|
|
90
|
+
stdout: string;
|
|
91
|
+
stderr: string;
|
|
92
|
+
}
|
|
93
|
+
export interface SpawnAsyncOptions extends SpawnOptions {
|
|
94
|
+
/**
|
|
95
|
+
* Defaults to true.
|
|
96
|
+
* If true - prints both stdout and stderr to console while running,
|
|
97
|
+
* otherwise runs "silently".
|
|
98
|
+
* Returns SpawnOutput in the same way, regardless of `printWhileRunning` setting.
|
|
99
|
+
*/
|
|
100
|
+
printWhileRunning?: boolean;
|
|
101
|
+
/**
|
|
102
|
+
* Defaults to true.
|
|
103
|
+
* If true - collects stdout and stderr while running, and return it in the end.
|
|
104
|
+
* stdout/stderr are collected and returned regardless if it returns with error or not.
|
|
105
|
+
* On success - stdout/stderr are available from `SpawnOutput`.
|
|
106
|
+
* On error - stdout/stderr are available from `SpawnError.data`.
|
|
107
|
+
*/
|
|
108
|
+
collectOutputWhileRunning?: boolean;
|
|
109
|
+
/**
|
|
110
|
+
* Defaults to true.
|
|
111
|
+
* If true - throws SpawnError if non-zero code is returned.
|
|
112
|
+
* SpawnError conveniently contains .data.stdout and .data.strerr for inspection.
|
|
113
|
+
* If false - will not throw, but return SpawnOutput with stdout, stderr and exitCode.
|
|
114
|
+
*/
|
|
115
|
+
throwOnNonZeroCode?: boolean;
|
|
116
|
+
}
|
|
117
|
+
export interface SpawnOptions {
|
|
118
|
+
args?: string[];
|
|
119
|
+
/**
|
|
120
|
+
* Defaults to true.
|
|
121
|
+
*/
|
|
122
|
+
logStart?: boolean;
|
|
123
|
+
/**
|
|
124
|
+
* Defaults to true.
|
|
125
|
+
*/
|
|
126
|
+
logFinish?: boolean;
|
|
127
|
+
/**
|
|
128
|
+
* Defaults to true.
|
|
129
|
+
* Controls/overrides both logStart and logFinish simultaneously.
|
|
130
|
+
*/
|
|
131
|
+
log?: boolean;
|
|
132
|
+
/**
|
|
133
|
+
* Defaults to true.
|
|
134
|
+
*/
|
|
135
|
+
shell?: boolean;
|
|
136
|
+
/**
|
|
137
|
+
* If specified - will be used as "command name" for logging purposes,
|
|
138
|
+
* instead of "cmd + args"
|
|
139
|
+
*/
|
|
140
|
+
name?: string;
|
|
141
|
+
cwd?: string;
|
|
142
|
+
env?: AnyObject;
|
|
143
|
+
}
|
|
144
|
+
export interface ExecOptions {
|
|
145
|
+
/**
|
|
146
|
+
* Defaults to false.
|
|
147
|
+
*/
|
|
148
|
+
logStart?: boolean;
|
|
149
|
+
/**
|
|
150
|
+
* Defaults to false.
|
|
151
|
+
*/
|
|
152
|
+
logFinish?: boolean;
|
|
153
|
+
/**
|
|
154
|
+
* Defaults to false.
|
|
155
|
+
* Controls/overrides both logStart and logFinish simultaneously.
|
|
156
|
+
*/
|
|
157
|
+
log?: boolean;
|
|
158
|
+
/**
|
|
159
|
+
* If specified - will be used as "command name" for logging purposes,
|
|
160
|
+
* instead of "cmd + args"
|
|
161
|
+
*/
|
|
162
|
+
name?: string;
|
|
163
|
+
cwd?: string;
|
|
164
|
+
timeout?: NumberOfMilliseconds;
|
|
165
|
+
env?: AnyObject;
|
|
166
|
+
}
|
|
167
|
+
export {};
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SpawnError = exports.exec2 = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const node_child_process_1 = tslib_1.__importDefault(require("node:child_process"));
|
|
6
|
+
const js_lib_1 = require("@naturalcycles/js-lib");
|
|
7
|
+
const colors_1 = require("../colors/colors");
|
|
8
|
+
/**
|
|
9
|
+
* Set of utility functions to work with Spawn / Exec.
|
|
10
|
+
*
|
|
11
|
+
* How to decide between Spawn and Exec?
|
|
12
|
+
*
|
|
13
|
+
* Long-running job that prints output, and no need to return the output - use Spawn.
|
|
14
|
+
*
|
|
15
|
+
* Short-running job, no need to print the output, might want to return the output - use Exec.
|
|
16
|
+
*
|
|
17
|
+
* Need to both print and return the output - use SpawnAsync.
|
|
18
|
+
*
|
|
19
|
+
* ***
|
|
20
|
+
*
|
|
21
|
+
* Spawn is good for long-running large-output processes, that continuously output data.
|
|
22
|
+
* E.g running `jest`.
|
|
23
|
+
*
|
|
24
|
+
* Exec is the opposite - good for short-running processes that output small data.
|
|
25
|
+
* Exec allows to return the output as a string.
|
|
26
|
+
* Exec doesn't stream data during execution, so the output/error will only be printed
|
|
27
|
+
* at the end.
|
|
28
|
+
* Exec always uses the shell (there's no option to disable it).
|
|
29
|
+
*/
|
|
30
|
+
class Exec2 {
|
|
31
|
+
/**
|
|
32
|
+
* Advanced/async version of Spawn.
|
|
33
|
+
* Consider simpler `spawn` or `exec` first, which are also sync.
|
|
34
|
+
*
|
|
35
|
+
* spawnAsync features:
|
|
36
|
+
*
|
|
37
|
+
* 1. Async
|
|
38
|
+
* 2. Allows to collect the output AND print it while running.
|
|
39
|
+
* 3. Returns SpawnOutput with stdout, stderr and exitCode.
|
|
40
|
+
* 4. Allows to not throw on error, but just return SpawnOutput for further inspection.
|
|
41
|
+
*
|
|
42
|
+
* Defaults:
|
|
43
|
+
*
|
|
44
|
+
* shell: true
|
|
45
|
+
* printWhileRunning: true
|
|
46
|
+
* collectOutputWhileRunning: true
|
|
47
|
+
* throwOnNonZeroCode: true
|
|
48
|
+
* log: true
|
|
49
|
+
*/
|
|
50
|
+
async spawnAsync(cmd, opt = {}) {
|
|
51
|
+
const started = Date.now();
|
|
52
|
+
this.logStart(cmd, opt);
|
|
53
|
+
const { shell = true, printWhileRunning = true, collectOutputWhileRunning = true, throwOnNonZeroCode = true, cwd, env, } = opt;
|
|
54
|
+
let stdout = '';
|
|
55
|
+
let stderr = '';
|
|
56
|
+
return await new Promise((resolve, reject) => {
|
|
57
|
+
const p = node_child_process_1.default.spawn(cmd, opt.args || [], {
|
|
58
|
+
shell,
|
|
59
|
+
cwd,
|
|
60
|
+
env,
|
|
61
|
+
// ...process.env, // not passing by default for security reasons
|
|
62
|
+
});
|
|
63
|
+
p.stdout.on('data', data => {
|
|
64
|
+
if (collectOutputWhileRunning) {
|
|
65
|
+
stdout += data.toString();
|
|
66
|
+
// console.log('stdout:', data.toString())
|
|
67
|
+
}
|
|
68
|
+
if (printWhileRunning) {
|
|
69
|
+
process.stdout.write(data);
|
|
70
|
+
// console.log('stderr:', data.toString())
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
p.stderr.on('data', data => {
|
|
74
|
+
if (collectOutputWhileRunning) {
|
|
75
|
+
stderr += data.toString();
|
|
76
|
+
}
|
|
77
|
+
if (printWhileRunning) {
|
|
78
|
+
process.stderr.write(data);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
p.on('close', code => {
|
|
82
|
+
this.logFinish(cmd, opt, started);
|
|
83
|
+
const exitCode = code || 0;
|
|
84
|
+
const o = {
|
|
85
|
+
exitCode,
|
|
86
|
+
stdout: stdout.trim(),
|
|
87
|
+
stderr: stderr.trim(),
|
|
88
|
+
};
|
|
89
|
+
if (throwOnNonZeroCode && code) {
|
|
90
|
+
return reject(new SpawnError(`spawnAsync exited with code ${code}: ${cmd}`, o));
|
|
91
|
+
}
|
|
92
|
+
resolve(o);
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Reasons to use it:
|
|
98
|
+
* - Sync
|
|
99
|
+
* - Need to print output while running
|
|
100
|
+
*
|
|
101
|
+
* Limitations:
|
|
102
|
+
* - Cannot return stdout/stderr (use exec or spawnAsync for that)
|
|
103
|
+
*
|
|
104
|
+
* Defaults:
|
|
105
|
+
*
|
|
106
|
+
* shell: true
|
|
107
|
+
* log: true
|
|
108
|
+
*/
|
|
109
|
+
spawn(cmd, opt = {}) {
|
|
110
|
+
const started = Date.now();
|
|
111
|
+
this.logStart(cmd, opt);
|
|
112
|
+
const { shell = true, cwd, env } = opt;
|
|
113
|
+
const r = node_child_process_1.default.spawnSync(cmd, opt.args, {
|
|
114
|
+
encoding: 'utf8',
|
|
115
|
+
stdio: 'inherit',
|
|
116
|
+
shell,
|
|
117
|
+
cwd,
|
|
118
|
+
env,
|
|
119
|
+
// ...process.env, // not passing by default for security reasons
|
|
120
|
+
});
|
|
121
|
+
this.logFinish(cmd, opt, started);
|
|
122
|
+
if (r.error) {
|
|
123
|
+
throw r.error;
|
|
124
|
+
}
|
|
125
|
+
if (r.status) {
|
|
126
|
+
throw new Error(`spawn exited with code ${r.status}: ${cmd}`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Reasons to use it:
|
|
131
|
+
*
|
|
132
|
+
* - Sync
|
|
133
|
+
* - Need to return output
|
|
134
|
+
*
|
|
135
|
+
* Limitations:
|
|
136
|
+
* - Cannot print while running (use spawn or spawnAsync for that)
|
|
137
|
+
*
|
|
138
|
+
* Defaults:
|
|
139
|
+
*
|
|
140
|
+
* shell: true
|
|
141
|
+
* log: true
|
|
142
|
+
*/
|
|
143
|
+
exec(cmd, opt = {}) {
|
|
144
|
+
const started = Date.now();
|
|
145
|
+
this.logStart(cmd, opt);
|
|
146
|
+
const { cwd, env, timeout } = opt;
|
|
147
|
+
try {
|
|
148
|
+
return node_child_process_1.default
|
|
149
|
+
.execSync(cmd, {
|
|
150
|
+
encoding: 'utf8',
|
|
151
|
+
// stdio: 'inherit', // no, otherwise we don't get the output returned
|
|
152
|
+
stdio: undefined,
|
|
153
|
+
// shell: undefined,
|
|
154
|
+
cwd,
|
|
155
|
+
timeout,
|
|
156
|
+
env,
|
|
157
|
+
// ...process.env, // not passing by default for security reasons
|
|
158
|
+
})
|
|
159
|
+
.trim();
|
|
160
|
+
}
|
|
161
|
+
catch (err) {
|
|
162
|
+
// Not logging stderr, as it's printed by execSync by default (somehow)
|
|
163
|
+
// stdout is not printed by execSync though, therefor we print it here
|
|
164
|
+
// if ((err as any).stderr) {
|
|
165
|
+
// process.stderr.write((err as any).stderr)
|
|
166
|
+
// }
|
|
167
|
+
if (err.stdout) {
|
|
168
|
+
process.stdout.write(err.stdout);
|
|
169
|
+
}
|
|
170
|
+
throw new Error(`exec exited with code ${err.status}: ${cmd}`);
|
|
171
|
+
}
|
|
172
|
+
finally {
|
|
173
|
+
this.logFinish(cmd, opt, started);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
throwOnNonZeroExitCode(o) {
|
|
177
|
+
if (o.exitCode) {
|
|
178
|
+
throw new SpawnError(`spawn exited with code ${o.exitCode}`, o);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
logStart(cmd, opt) {
|
|
182
|
+
if (!opt.logStart && !opt.log)
|
|
183
|
+
return;
|
|
184
|
+
console.log([
|
|
185
|
+
(0, colors_1.dimGrey)(...Object.entries(opt.env || {}).map(([k, v]) => [k, v].join('='))),
|
|
186
|
+
(0, colors_1.white)(opt.name || cmd),
|
|
187
|
+
...((!opt.name && opt.args) || []),
|
|
188
|
+
]
|
|
189
|
+
.filter(Boolean)
|
|
190
|
+
.join(' '));
|
|
191
|
+
}
|
|
192
|
+
logFinish(cmd, opt, started) {
|
|
193
|
+
if (!opt.logFinish && !opt.log)
|
|
194
|
+
return;
|
|
195
|
+
console.log([(0, colors_1.white)(opt.name || cmd), (0, colors_1.dimGrey)('took ' + (0, js_lib_1._since)(started))].join(' '));
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
exports.exec2 = new Exec2();
|
|
199
|
+
class SpawnError extends js_lib_1.AppError {
|
|
200
|
+
constructor(message, data) {
|
|
201
|
+
super(message, data, { name: 'SpawnError' });
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
exports.SpawnError = SpawnError;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { UnixTimestampNumber } from '@naturalcycles/js-lib';
|
|
2
|
+
/**
|
|
3
|
+
* Set of utility functions to work with git.
|
|
4
|
+
*/
|
|
5
|
+
declare class Git2 {
|
|
6
|
+
getLastGitCommitMsg(): string;
|
|
7
|
+
commitMessageToTitleMessage(msg: string): string;
|
|
8
|
+
gitHasUncommittedChanges(): boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Returns true if there were changes
|
|
11
|
+
*/
|
|
12
|
+
gitCommitAll(msg: string): boolean;
|
|
13
|
+
/**
|
|
14
|
+
* @returns true if there are not pushed commits.
|
|
15
|
+
*/
|
|
16
|
+
gitIsAhead(): boolean;
|
|
17
|
+
gitPull(): void;
|
|
18
|
+
gitPush(): void;
|
|
19
|
+
gitCurrentCommitSha(full?: boolean): string;
|
|
20
|
+
gitCurrentCommitTimestamp(): UnixTimestampNumber;
|
|
21
|
+
gitCurrentBranchName(): string;
|
|
22
|
+
gitCurrentRepoName(): string;
|
|
23
|
+
}
|
|
24
|
+
export declare const git2: Git2;
|
|
25
|
+
export {};
|