@mikeyt23/node-cli-utils 1.4.1 → 2.0.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -87
- package/dist/cjs/GitUtility.d.ts +7 -0
- package/dist/cjs/GitUtility.d.ts.map +1 -0
- package/dist/cjs/GitUtility.js +49 -0
- package/dist/cjs/NodeCliUtilsConfig.d.ts +21 -0
- package/dist/cjs/NodeCliUtilsConfig.d.ts.map +1 -0
- package/dist/cjs/NodeCliUtilsConfig.js +41 -0
- package/dist/cjs/TarballUtility.d.ts +63 -0
- package/dist/cjs/TarballUtility.d.ts.map +1 -0
- package/dist/cjs/TarballUtility.js +143 -0
- package/dist/cjs/certUtils.d.ts +66 -0
- package/dist/cjs/certUtils.d.ts.map +1 -0
- package/dist/cjs/certUtils.js +283 -0
- package/dist/cjs/dbMigrationUtils.d.ts +39 -0
- package/dist/cjs/dbMigrationUtils.d.ts.map +1 -0
- package/dist/cjs/dbMigrationUtils.js +195 -0
- package/dist/cjs/dotnetUtils.d.ts +25 -0
- package/dist/cjs/dotnetUtils.d.ts.map +1 -0
- package/dist/cjs/dotnetUtils.js +61 -0
- package/dist/cjs/esmSpecific.d.mts +7 -0
- package/dist/cjs/esmSpecific.d.mts.map +1 -0
- package/dist/cjs/esmSpecific.mjs +15 -0
- package/dist/cjs/generalUtils.d.ts +565 -0
- package/dist/cjs/generalUtils.d.ts.map +1 -0
- package/dist/cjs/generalUtils.js +1068 -0
- package/dist/cjs/generalUtilsInternal.d.ts +15 -0
- package/dist/cjs/generalUtilsInternal.d.ts.map +1 -0
- package/dist/cjs/generalUtilsInternal.js +317 -0
- package/dist/cjs/hostsUtils.d.ts +16 -0
- package/dist/cjs/hostsUtils.d.ts.map +1 -0
- package/dist/cjs/hostsUtils.js +82 -0
- package/dist/cjs/index.d.ts +4 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +25 -0
- package/dist/cjs/package.json +5 -0
- package/dist/cjs/runWhileParentAlive.d.ts +2 -0
- package/dist/cjs/runWhileParentAlive.d.ts.map +1 -0
- package/dist/cjs/runWhileParentAlive.js +159 -0
- package/dist/esm/GitUtility.d.ts +7 -0
- package/dist/esm/GitUtility.d.ts.map +1 -0
- package/dist/esm/GitUtility.js +43 -0
- package/dist/esm/NodeCliUtilsConfig.d.ts +21 -0
- package/dist/esm/NodeCliUtilsConfig.d.ts.map +1 -0
- package/dist/esm/NodeCliUtilsConfig.js +35 -0
- package/dist/esm/TarballUtility.d.ts +63 -0
- package/dist/esm/TarballUtility.d.ts.map +1 -0
- package/dist/esm/TarballUtility.js +139 -0
- package/dist/esm/certUtils.d.ts +66 -0
- package/dist/esm/certUtils.d.ts.map +1 -0
- package/dist/esm/certUtils.js +271 -0
- package/dist/esm/dbMigrationUtils.d.ts +39 -0
- package/dist/esm/dbMigrationUtils.d.ts.map +1 -0
- package/dist/esm/dbMigrationUtils.js +184 -0
- package/dist/esm/dotnetUtils.d.ts +25 -0
- package/dist/esm/dotnetUtils.d.ts.map +1 -0
- package/dist/esm/dotnetUtils.js +54 -0
- package/dist/esm/esmSpecific.d.mts +7 -0
- package/dist/esm/esmSpecific.d.mts.map +1 -0
- package/dist/esm/esmSpecific.mjs +11 -0
- package/dist/esm/generalUtils.d.ts +565 -0
- package/dist/esm/generalUtils.d.ts.map +1 -0
- package/dist/esm/generalUtils.js +976 -0
- package/dist/esm/generalUtilsInternal.d.ts +15 -0
- package/dist/esm/generalUtilsInternal.d.ts.map +1 -0
- package/dist/esm/generalUtilsInternal.js +278 -0
- package/dist/esm/hostsUtils.d.ts +16 -0
- package/dist/esm/hostsUtils.d.ts.map +1 -0
- package/dist/esm/hostsUtils.js +69 -0
- package/dist/esm/index.d.ts +4 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +4 -0
- package/dist/esm/runWhileParentAlive.d.ts +2 -0
- package/dist/esm/runWhileParentAlive.d.ts.map +1 -0
- package/dist/esm/runWhileParentAlive.js +151 -0
- package/package.json +69 -10
- package/index.js +0 -627
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.trace = void 0;
|
|
7
|
+
// runWhileParentAlive.ts
|
|
8
|
+
// Also referred to as "orphan protection" or "long running windows process workaround script"
|
|
9
|
+
const node_child_process_1 = require("node:child_process");
|
|
10
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
11
|
+
const NodeCliUtilsConfig_js_1 = require("./NodeCliUtilsConfig.js");
|
|
12
|
+
const DEV_LOGGING = false; // Set to true while developing this script to see more logging in the console
|
|
13
|
+
let loggingEnabled = true; // Will be set below by process.argv[2] === 'true' from spawnAsync in generalUtils.js
|
|
14
|
+
let traceEnabled = true; // Will be set below by process.argv[3] === 'true' from spawnAsync in generalUtils.js
|
|
15
|
+
let pollingMillis = NodeCliUtilsConfig_js_1.config.orphanProtectionPollingIntervalMillis; // Will be set by process.argv[4] from spawnAsync in generalUtils.js
|
|
16
|
+
function getLogPrefix() {
|
|
17
|
+
const now = new Date();
|
|
18
|
+
const hours = now.getHours().toString().padStart(2, '0');
|
|
19
|
+
const minutes = now.getMinutes().toString().padStart(2, '0');
|
|
20
|
+
const seconds = now.getSeconds().toString().padStart(2, '0');
|
|
21
|
+
const milliseconds = now.getMilliseconds().toString().padStart(3, '0');
|
|
22
|
+
return `[${hours}:${minutes}:${seconds}:${milliseconds}] `;
|
|
23
|
+
}
|
|
24
|
+
// Using this trace method instead of importing from generalUtils.js since config is not shared between processes
|
|
25
|
+
function trace(message, ...optionalParams) {
|
|
26
|
+
const prefix = `[TRACE]`;
|
|
27
|
+
console.log(prefix, message, ...optionalParams);
|
|
28
|
+
}
|
|
29
|
+
exports.trace = trace;
|
|
30
|
+
function logToFile(message) {
|
|
31
|
+
node_fs_1.default.appendFileSync(NodeCliUtilsConfig_js_1.config.orphanProtectionLoggingPath, `${getLogPrefix()}${message}` + !(message === null || message === void 0 ? void 0 : message.endsWith('\n')) ? '\n' : '');
|
|
32
|
+
}
|
|
33
|
+
function traceAndLog(message, isDevTrace = false) {
|
|
34
|
+
if (isDevTrace && !DEV_LOGGING) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
if (isDevTrace && DEV_LOGGING) {
|
|
38
|
+
trace(getLogPrefix() + message);
|
|
39
|
+
logToFile(message);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
if (traceEnabled) {
|
|
43
|
+
trace(getLogPrefix() + message);
|
|
44
|
+
}
|
|
45
|
+
if (loggingEnabled) {
|
|
46
|
+
logToFile(message);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function isParentProcessAlive(parentId) {
|
|
50
|
+
var _a, _b, _c;
|
|
51
|
+
try {
|
|
52
|
+
const result = (0, node_child_process_1.spawnSync)('C:\\Windows\\system32\\tasklist.exe');
|
|
53
|
+
const resultToLog = {
|
|
54
|
+
status: result.status,
|
|
55
|
+
stderr: (_a = result.stderr) === null || _a === void 0 ? void 0 : _a.toString(),
|
|
56
|
+
stdoutIncludesParentId: (_c = (_b = result.stdout) === null || _b === void 0 ? void 0 : _b.toString().includes(parentId.toString())) !== null && _c !== void 0 ? _c : false
|
|
57
|
+
};
|
|
58
|
+
traceAndLog('tasklist result: ' + JSON.stringify(resultToLog), true);
|
|
59
|
+
return resultToLog.stdoutIncludesParentId;
|
|
60
|
+
}
|
|
61
|
+
catch (err) {
|
|
62
|
+
if (err instanceof Error) {
|
|
63
|
+
console.log(err.message);
|
|
64
|
+
console.log(err.stack);
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
console.error(err);
|
|
68
|
+
}
|
|
69
|
+
traceAndLog(`Error attempting to fetch task list using 'tasklist' - returning false for isParentAlive(): ${err instanceof Error ? err.toString() : err}`);
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function killTree(pid) {
|
|
74
|
+
try {
|
|
75
|
+
(0, node_child_process_1.spawnSync)(`C:\\Windows\\system32\\taskkill.exe /pid ${pid} /T /F`);
|
|
76
|
+
traceAndLog(`No errors running killTree`);
|
|
77
|
+
}
|
|
78
|
+
catch (err) {
|
|
79
|
+
traceAndLog(`Error running taskkill with PID ${pid}: ${err instanceof Error ? err.toString() : err}`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
try {
|
|
83
|
+
loggingEnabled = process.argv[2] === 'true';
|
|
84
|
+
traceEnabled = process.argv[3] === 'true';
|
|
85
|
+
pollingMillis = Number(process.argv[4]);
|
|
86
|
+
if (Number.isNaN(pollingMillis) || pollingMillis < 0 || pollingMillis > (3600 * 1000)) {
|
|
87
|
+
pollingMillis = NodeCliUtilsConfig_js_1.config.orphanProtectionPollingIntervalMillis;
|
|
88
|
+
}
|
|
89
|
+
const passthroughArgs = process.argv.slice(5);
|
|
90
|
+
if (loggingEnabled) {
|
|
91
|
+
traceAndLog(`Logging enabled with polling rate set to: ${pollingMillis}ms`);
|
|
92
|
+
traceAndLog(`Trace enabled: ${traceEnabled}`);
|
|
93
|
+
}
|
|
94
|
+
if (DEV_LOGGING) {
|
|
95
|
+
const argvString = JSON.stringify(process.argv);
|
|
96
|
+
console.log(argvString);
|
|
97
|
+
logToFile(argvString);
|
|
98
|
+
traceAndLog(`process.argv[2] (logging enabled): ${process.argv[2]}`, true);
|
|
99
|
+
traceAndLog(`process.argv[3] (trace enabled): ${process.argv[3]}`, true);
|
|
100
|
+
traceAndLog(`process.argv[4] (polling millis): ${process.argv[4]}`, true);
|
|
101
|
+
traceAndLog(`rest of process.argv: ${JSON.stringify(passthroughArgs)}`, true);
|
|
102
|
+
}
|
|
103
|
+
const parentId = process.ppid;
|
|
104
|
+
if (!parentId) {
|
|
105
|
+
const noParentIdMessage = `Middle process cannot continue - parent process id not found`;
|
|
106
|
+
console.error(noParentIdMessage);
|
|
107
|
+
traceAndLog(noParentIdMessage);
|
|
108
|
+
process.exit(1);
|
|
109
|
+
}
|
|
110
|
+
const [command, ...args] = passthroughArgs;
|
|
111
|
+
const child = (0, node_child_process_1.spawn)(command, args, { stdio: 'inherit', shell: 'cmd.exe' });
|
|
112
|
+
const childId = child.pid;
|
|
113
|
+
if (!childId) {
|
|
114
|
+
const noChildIdMessage = 'spawning ChildProcess failed - no pid on returned handle';
|
|
115
|
+
console.error(noChildIdMessage);
|
|
116
|
+
traceAndLog(noChildIdMessage);
|
|
117
|
+
process.exit(1);
|
|
118
|
+
}
|
|
119
|
+
const interval = setInterval(() => {
|
|
120
|
+
if (!isParentProcessAlive(parentId)) {
|
|
121
|
+
traceAndLog('Parent process is not alive. Shutting down.');
|
|
122
|
+
killTree(childId);
|
|
123
|
+
clearInterval(interval);
|
|
124
|
+
traceAndLog('Used taskkill and cleared interval - exiting...');
|
|
125
|
+
process.exit(0);
|
|
126
|
+
}
|
|
127
|
+
if (DEV_LOGGING) {
|
|
128
|
+
traceAndLog('Parent is alive, keep running.');
|
|
129
|
+
}
|
|
130
|
+
}, pollingMillis);
|
|
131
|
+
child.on('exit', (code, signal) => {
|
|
132
|
+
const andSignal = signal ? ` and signal ${signal}` : '';
|
|
133
|
+
traceAndLog(`ChildProcess exit event emitted with code ${code}${andSignal} - exiting`);
|
|
134
|
+
clearInterval(interval);
|
|
135
|
+
process.exit(code !== null && code !== void 0 ? code : 1);
|
|
136
|
+
});
|
|
137
|
+
const signals = ['SIGINT', 'SIGTERM', 'SIGQUIT'];
|
|
138
|
+
signals.forEach((signal) => {
|
|
139
|
+
process.on(signal, () => {
|
|
140
|
+
traceAndLog(`Middle process received signal ${signal} - will attempt to kill child process tree, clear interval and exit`);
|
|
141
|
+
try {
|
|
142
|
+
clearInterval(interval);
|
|
143
|
+
traceAndLog(`Ran clearInterval in signal event ${signal} - exiting`);
|
|
144
|
+
process.exit(0);
|
|
145
|
+
}
|
|
146
|
+
catch (err) {
|
|
147
|
+
traceAndLog(`Error attempting to run clearInterval during signal event ${signal}: ${err instanceof Error ? err.toString() : err}`);
|
|
148
|
+
process.exit(1);
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
catch (err) {
|
|
154
|
+
const msg = `Unexpected error in runWhileParentAlive: ${err instanceof Error ? err.toString() : err}`;
|
|
155
|
+
console.error(msg);
|
|
156
|
+
logToFile(msg);
|
|
157
|
+
process.exit(1);
|
|
158
|
+
}
|
|
159
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnVuV2hpbGVQYXJlbnRBbGl2ZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9ydW5XaGlsZVBhcmVudEFsaXZlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7OztBQUFBLHlCQUF5QjtBQUN6Qiw4RkFBOEY7QUFDOUYsMkRBQXFEO0FBQ3JELHNEQUF3QjtBQUN4QixtRUFBZ0Q7QUFFaEQsTUFBTSxXQUFXLEdBQUcsS0FBSyxDQUFBLENBQUMsOEVBQThFO0FBQ3hHLElBQUksY0FBYyxHQUFHLElBQUksQ0FBQSxDQUFDLHFGQUFxRjtBQUMvRyxJQUFJLFlBQVksR0FBRyxJQUFJLENBQUEsQ0FBQyxxRkFBcUY7QUFDN0csSUFBSSxhQUFhLEdBQVcsOEJBQU0sQ0FBQyxxQ0FBcUMsQ0FBQSxDQUFDLG9FQUFvRTtBQUU3SSxTQUFTLFlBQVk7SUFDbkIsTUFBTSxHQUFHLEdBQUcsSUFBSSxJQUFJLEVBQUUsQ0FBQTtJQUN0QixNQUFNLEtBQUssR0FBRyxHQUFHLENBQUMsUUFBUSxFQUFFLENBQUMsUUFBUSxFQUFFLENBQUMsUUFBUSxDQUFDLENBQUMsRUFBRSxHQUFHLENBQUMsQ0FBQTtJQUN4RCxNQUFNLE9BQU8sR0FBRyxHQUFHLENBQUMsVUFBVSxFQUFFLENBQUMsUUFBUSxFQUFFLENBQUMsUUFBUSxDQUFDLENBQUMsRUFBRSxHQUFHLENBQUMsQ0FBQTtJQUM1RCxNQUFNLE9BQU8sR0FBRyxHQUFHLENBQUMsVUFBVSxFQUFFLENBQUMsUUFBUSxFQUFFLENBQUMsUUFBUSxDQUFDLENBQUMsRUFBRSxHQUFHLENBQUMsQ0FBQTtJQUM1RCxNQUFNLFlBQVksR0FBRyxHQUFHLENBQUMsZUFBZSxFQUFFLENBQUMsUUFBUSxFQUFFLENBQUMsUUFBUSxDQUFDLENBQUMsRUFBRSxHQUFHLENBQUMsQ0FBQTtJQUN0RSxPQUFPLElBQUksS0FBSyxJQUFJLE9BQU8sSUFBSSxPQUFPLElBQUksWUFBWSxJQUFJLENBQUE7QUFDNUQsQ0FBQztB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
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { spawnAsync } from './generalUtils.js';
|
|
2
|
+
export interface GitUtilityDependencies {
|
|
3
|
+
spawnAsyncFn: typeof spawnAsync;
|
|
4
|
+
}
|
|
5
|
+
export declare const isValidBranchName: (branchName: string) => boolean;
|
|
6
|
+
export declare const cloneProject: (repoUrl: string, localDestPath: string, branchName?: string, deleteGitFolder?: boolean) => Promise<void>;
|
|
7
|
+
//# sourceMappingURL=GitUtility.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GitUtility.d.ts","sourceRoot":"","sources":["../../src/GitUtility.ts"],"names":[],"mappings":"AAEA,OAAO,EAAU,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAGtD,MAAM,WAAW,sBAAsB;IACrC,YAAY,EAAE,OAAO,UAAU,CAAA;CAChC;AAgDD,eAAO,MAAM,iBAAiB,eAvCE,MAAM,KAAG,OAuC2B,CAAA;AACpE,eAAO,MAAM,YAAY,YAzBK,MAAM,iBAAiB,MAAM,eAAc,MAAM,oBAA4B,OAAO,kBAyBxD,CAAA"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import fsp from 'node:fs/promises';
|
|
3
|
+
import { mkdirp, spawnAsync } from './generalUtils.js';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
class GitUtility {
|
|
6
|
+
spawnAsyncFn;
|
|
7
|
+
constructor(dependencies = {}) {
|
|
8
|
+
this.spawnAsyncFn = dependencies.spawnAsyncFn ?? spawnAsync;
|
|
9
|
+
}
|
|
10
|
+
isValidBranchName(branchName) {
|
|
11
|
+
if (branchName.startsWith('-') || branchName.endsWith('/') || branchName.endsWith('.') || branchName.endsWith('@{') || branchName.includes('..')) {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
const invalidChars = [' ', '~', '^', ':', '\\', '*', '?', '[', ']', '/'];
|
|
15
|
+
for (const char of branchName) {
|
|
16
|
+
if (invalidChars.includes(char)) {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
async cloneProject(repoUrl, localDestPath, branchName = 'main', deleteGitFolder = true) {
|
|
23
|
+
if (fs.existsSync(localDestPath)) {
|
|
24
|
+
throw new Error(`Cannot clone project - destination path already exists: ${localDestPath}`);
|
|
25
|
+
}
|
|
26
|
+
if (!this.isValidBranchName(branchName)) {
|
|
27
|
+
throw new Error(`Cannot clone project - invalid branch name: ${branchName}`);
|
|
28
|
+
}
|
|
29
|
+
await mkdirp(localDestPath);
|
|
30
|
+
const cloneArgs = `clone -b ${branchName} --single-branch --depth 1 ${repoUrl} ${localDestPath}`.split(' ');
|
|
31
|
+
const result = await this.spawnAsyncFn('git', cloneArgs);
|
|
32
|
+
if (result.code !== 0) {
|
|
33
|
+
throw new Error(`Failed to clone project '${result.stderr}' to '${localDestPath}'`);
|
|
34
|
+
}
|
|
35
|
+
if (deleteGitFolder) {
|
|
36
|
+
await fsp.rm(join(localDestPath, '.git'), { recursive: true });
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
const defaultGitUtility = new GitUtility();
|
|
41
|
+
export const isValidBranchName = defaultGitUtility.isValidBranchName;
|
|
42
|
+
export const cloneProject = defaultGitUtility.cloneProject;
|
|
43
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiR2l0VXRpbGl0eS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9HaXRVdGlsaXR5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxNQUFNLFNBQVMsQ0FBQTtBQUN4QixPQUFPLEdBQUcsTUFBTSxrQkFBa0IsQ0FBQTtBQUNsQyxPQUFPLEVBQUUsTUFBTSxFQUFFLFVBQVUsRUFBRSxNQUFNLG1CQUFtQixDQUFBO0FBQ3RELE9BQU8sRUFBRSxJQUFJLEVBQUUsTUFBTSxXQUFXLENBQUE7QUFNaEMsTUFBTSxVQUFVO0lBQ04sWUFBWSxDQUFtQjtJQUV2QyxZQUFZLGVBQWdELEVBQUU7UUFDNUQsSUFBSSxDQUFDLFlBQVksR0FBRyxZQUFZLENBQUMsWUFBWSxJQUFJLFVBQVUsQ0FBQTtJQUM3RCxDQUFDO0lBRUQsaUJBQWlCLENBQUMsVUFBa0I7UUFDbEMsSUFBSSxVQUFVLENBQUMsVUFBVSxDQUFDLEdBQUcsQ0FBQyxJQUFJLFVBQVUsQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLElBQUksVUFBVSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsSUFBSSxVQUFVLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxJQUFJLFVBQVUsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLEVBQUU7WUFDaEosT0FBTyxLQUFLLENBQUE7U0FDYjtRQUVELE1BQU0sWUFBWSxHQUFHLENBQUMsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLElBQUksRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxDQUFDLENBQUE7UUFDeEUsS0FBSyxNQUFNLElBQUksSUFBSSxVQUFVLEVBQUU7WUFDN0IsSUFBSSxZQUFZLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxFQUFFO2dCQUMvQixPQUFPLEtBQUssQ0FBQTthQUNiO1NBQ0Y7UUFFRCxPQUFPLElBQUksQ0FBQTtJQUNiLENBQUM7SUFFRCxLQUFLLENBQUMsWUFBWSxDQUFDLE9BQWUsRUFBRSxhQUFxQixFQUFFLGFBQXFCLE1BQU0sRUFBRSxrQkFBMkIsSUFBSTtRQUNySCxJQUFJLEVBQUUsQ0FBQyxVQUFVLENBQUMsYUFBYSxDQUFDLEVBQUU7WUFDaEMsTUFBTSxJQUFJLEtBQUssQ0FBQywyREFBMkQsYUFBYSxFQUFFLENBQUMsQ0FBQTtTQUM1RjtRQUNELElBQUksQ0FBQyxJQUFJLENBQUMsaUJBQWlCLENBQUMsVUFBVSxDQUFDLEVBQUU7WUFDdkMsTUFBTSxJQUFJLEtBQUssQ0FBQywrQ0FBK0MsVUFBVSxFQUFFLENBQUMsQ0FBQTtTQUM3RTtRQUVELE1BQU0sTUFBTSxDQUFDLGFBQWEsQ0FBQyxDQUFBO1FBRTNCLE1BQU0sU0FBUyxHQUFHLFlBQVksVUFBVSw4QkFBOEIsT0FBTyxJQUFJLGFBQWEsRUFBRSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQTtRQUMzRyxNQUFNLE1BQU0sR0FBRyxNQUFNLElBQUksQ0FBQyxZQUFZLENBQUMsS0FBSyxFQUFFLFNBQVMsQ0FBQyxDQUFBO1FBQ3hELElBQUksTUFBTSxDQUFDLElBQUksS0FBSyxDQUFDLEVBQUU7WUFDckIsTUFBTSxJQUFJLEtBQUssQ0FBQyw0QkFBNEIsTUFBTSxDQUFDLE1BQU0sU0FBUyxhQUFhLEdBQUcsQ0FBQyxDQUFBO1NBQ3BGO1FBRUQsSUFBSSxlQUFlLEVBQUU7WUFDbkIsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxhQUFhLEVBQUUsTUFBTSxDQUFDLEVBQUUsRUFBRSxTQUFTLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQTtTQUMvRDtJQUNILENBQUM7Q0FDRjtBQUVELE1BQU0saUJBQWlCLEdBQUcsSUFBSSxVQUFVLEVBQUUsQ0FBQTtBQUUxQyxNQUFNLENBQUMsTUFBTSxpQkFBaUIsR0FBRyxpQkFBaUIsQ0FBQyxpQkFBaUIsQ0FBQTtBQUNwRSxNQUFNLENBQUMsTUFBTSxZQUFZLEdBQUcsaUJBQWlCLENBQUMsWUFBWSxDQUFBIn0=
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config to control a few misc settings in the node-cli-utils package. This module exports a singleton instance.
|
|
3
|
+
*/
|
|
4
|
+
export declare class NodeCliUtilsConfig {
|
|
5
|
+
private _traceEnabled;
|
|
6
|
+
private _orphanProtectionPollingIntervalMillis;
|
|
7
|
+
private _orphanProtectionLoggingEnabled;
|
|
8
|
+
private _orphanProtectionLoggingPath;
|
|
9
|
+
get traceEnabled(): boolean;
|
|
10
|
+
set traceEnabled(value: boolean);
|
|
11
|
+
get orphanProtectionPollingIntervalMillis(): number;
|
|
12
|
+
set orphanProtectionPollingIntervalMillis(value: number);
|
|
13
|
+
get orphanProtectionLoggingEnabled(): boolean;
|
|
14
|
+
set orphanProtectionLoggingEnabled(value: boolean);
|
|
15
|
+
get orphanProtectionLoggingPath(): string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Singleton instance of {@link NodeCliUtilsConfig}.
|
|
19
|
+
*/
|
|
20
|
+
export declare const config: NodeCliUtilsConfig;
|
|
21
|
+
//# sourceMappingURL=NodeCliUtilsConfig.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NodeCliUtilsConfig.d.ts","sourceRoot":"","sources":["../../src/NodeCliUtilsConfig.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,aAAa,CAAkB;IACvC,OAAO,CAAC,sCAAsC,CAAQ;IACtD,OAAO,CAAC,+BAA+B,CAAQ;IAC/C,OAAO,CAAC,4BAA4B,CAA2B;IAE/D,IAAI,YAAY,IAAI,OAAO,CAE1B;IAED,IAAI,YAAY,CAAC,KAAK,EAAE,OAAO,EAE9B;IAED,IAAI,qCAAqC,IAAI,MAAM,CAElD;IAED,IAAI,qCAAqC,CAAC,KAAK,EAAE,MAAM,EAEtD;IAED,IAAI,8BAA8B,IAAI,OAAO,CAE5C;IAED,IAAI,8BAA8B,CAAC,KAAK,EAAE,OAAO,EAEhD;IAED,IAAI,2BAA2B,IAAI,MAAM,CAExC;CACF;AAED;;GAEG;AACH,eAAO,MAAM,MAAM,oBAA2B,CAAA"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config to control a few misc settings in the node-cli-utils package. This module exports a singleton instance.
|
|
3
|
+
*/
|
|
4
|
+
export class NodeCliUtilsConfig {
|
|
5
|
+
_traceEnabled = false;
|
|
6
|
+
_orphanProtectionPollingIntervalMillis = 15000;
|
|
7
|
+
_orphanProtectionLoggingEnabled = false;
|
|
8
|
+
_orphanProtectionLoggingPath = './orphanProtection.log';
|
|
9
|
+
get traceEnabled() {
|
|
10
|
+
return this._traceEnabled;
|
|
11
|
+
}
|
|
12
|
+
set traceEnabled(value) {
|
|
13
|
+
this._traceEnabled = value;
|
|
14
|
+
}
|
|
15
|
+
get orphanProtectionPollingIntervalMillis() {
|
|
16
|
+
return this._orphanProtectionPollingIntervalMillis;
|
|
17
|
+
}
|
|
18
|
+
set orphanProtectionPollingIntervalMillis(value) {
|
|
19
|
+
this._orphanProtectionPollingIntervalMillis = value;
|
|
20
|
+
}
|
|
21
|
+
get orphanProtectionLoggingEnabled() {
|
|
22
|
+
return this._orphanProtectionLoggingEnabled;
|
|
23
|
+
}
|
|
24
|
+
set orphanProtectionLoggingEnabled(value) {
|
|
25
|
+
this._orphanProtectionLoggingEnabled = value;
|
|
26
|
+
}
|
|
27
|
+
get orphanProtectionLoggingPath() {
|
|
28
|
+
return this._orphanProtectionLoggingPath;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Singleton instance of {@link NodeCliUtilsConfig}.
|
|
33
|
+
*/
|
|
34
|
+
export const config = new NodeCliUtilsConfig();
|
|
35
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTm9kZUNsaVV0aWxzQ29uZmlnLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL05vZGVDbGlVdGlsc0NvbmZpZy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7R0FFRztBQUNILE1BQU0sT0FBTyxrQkFBa0I7SUFDckIsYUFBYSxHQUFZLEtBQUssQ0FBQztJQUMvQixzQ0FBc0MsR0FBRyxLQUFLLENBQUE7SUFDOUMsK0JBQStCLEdBQUcsS0FBSyxDQUFBO0lBQ3ZDLDRCQUE0QixHQUFHLHdCQUF3QixDQUFBO0lBRS9ELElBQUksWUFBWTtRQUNkLE9BQU8sSUFBSSxDQUFDLGFBQWEsQ0FBQTtJQUMzQixDQUFDO0lBRUQsSUFBSSxZQUFZLENBQUMsS0FBYztRQUM3QixJQUFJLENBQUMsYUFBYSxHQUFHLEtBQUssQ0FBQTtJQUM1QixDQUFDO0lBRUQsSUFBSSxxQ0FBcUM7UUFDdkMsT0FBTyxJQUFJLENBQUMsc0NBQXNDLENBQUE7SUFDcEQsQ0FBQztJQUVELElBQUkscUNBQXFDLENBQUMsS0FBYTtRQUNyRCxJQUFJLENBQUMsc0NBQXNDLEdBQUcsS0FBSyxDQUFBO0lBQ3JELENBQUM7SUFFRCxJQUFJLDhCQUE4QjtRQUNoQyxPQUFPLElBQUksQ0FBQywrQkFBK0IsQ0FBQTtJQUM3QyxDQUFDO0lBRUQsSUFBSSw4QkFBOEIsQ0FBQyxLQUFjO1FBQy9DLElBQUksQ0FBQywrQkFBK0IsR0FBRyxLQUFLLENBQUE7SUFDOUMsQ0FBQztJQUVELElBQUksMkJBQTJCO1FBQzdCLE9BQU8sSUFBSSxDQUFDLDRCQUE0QixDQUFBO0lBQzFDLENBQUM7Q0FDRjtBQUVEOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sTUFBTSxHQUFHLElBQUksa0JBQWtCLEVBQUUsQ0FBQSJ9
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import { mkdirp, spawnAsync, whichSync } from './generalUtils.js';
|
|
3
|
+
export interface CreateTarballOptions {
|
|
4
|
+
/**
|
|
5
|
+
* A list of files or directories to exclude from the tarball.
|
|
6
|
+
* The paths should be relative to the directoryToTarball.
|
|
7
|
+
*/
|
|
8
|
+
excludes?: string[];
|
|
9
|
+
}
|
|
10
|
+
export interface TarballUnpackOptions {
|
|
11
|
+
createDirIfNotExists: boolean;
|
|
12
|
+
stripComponents: number;
|
|
13
|
+
throwOnNonEmptyUnpackDir: boolean;
|
|
14
|
+
}
|
|
15
|
+
export interface TarballUtilityDependencies {
|
|
16
|
+
whichSyncFn: typeof whichSync;
|
|
17
|
+
spawnAsyncFn: typeof spawnAsync;
|
|
18
|
+
statSyncFn: typeof fs.statSync;
|
|
19
|
+
mkdirpFn: typeof mkdirp;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* This utility class exists so we can mock the `which` dependency in unit tests without resorting to libraries that hack the import system.
|
|
23
|
+
*/
|
|
24
|
+
export declare class TarballUtility {
|
|
25
|
+
private whichSyncFn;
|
|
26
|
+
private spawnAsyncFn;
|
|
27
|
+
private statSyncFn;
|
|
28
|
+
private mkdirpFn;
|
|
29
|
+
constructor(dependencies?: Partial<TarballUtilityDependencies>);
|
|
30
|
+
/**
|
|
31
|
+
* Creates a gzipped tarball from a directory by spawning a process to run OS-installed `tar` to avoid pulling in npm package dependencies.
|
|
32
|
+
* Note that Windows has tar since Windows 10 1803 (see https://devblogs.microsoft.com/commandline/windows10v1803/.
|
|
33
|
+
*
|
|
34
|
+
* It's possible this isn't 100% reliable due to differences in `tar` versions across platforms. If better normalization
|
|
35
|
+
* is required, consider using the npm package `node-tar` instead.
|
|
36
|
+
* @param directoryToTarball The directory to tarball. The directory name will be used as the root directory in the tarball
|
|
37
|
+
* @param tarballPath The path to the tarball to create - must end with '.tar.gz'
|
|
38
|
+
* @param options See {@link CreateTarballOptions}
|
|
39
|
+
*/
|
|
40
|
+
createTarball: (directoryToTarball: string, tarballPath: string, options?: CreateTarballOptions) => Promise<void>;
|
|
41
|
+
/**
|
|
42
|
+
* Unpacks a gzipped tarball by spawning a process to run OS-installed `tar` to avoid pulling in npm package dependencies.
|
|
43
|
+
* This method will throw an error if the unpackDirectory is not empty, unless the `throwOnNonEmptyUnpackDir` option is set to false.
|
|
44
|
+
* @param tarballPath The path to the tarball to unpack
|
|
45
|
+
* @param unpackDirectory The directory to unpack the tarball into
|
|
46
|
+
* @param options The options to use when unpacking the tarball. See {@link TarballUnpackOptions}.
|
|
47
|
+
*/
|
|
48
|
+
unpackTarball: (tarballPath: string, unpackDirectory: string, options?: Partial<TarballUnpackOptions>) => Promise<void>;
|
|
49
|
+
/**
|
|
50
|
+
* A more opinionated version of {@link unpackTarball} that assumes you want to create the directory and strip the first directory out of the unpacked files.
|
|
51
|
+
* @param tarballPath The path to the tarball to unpack
|
|
52
|
+
* @param unpackDirectory The directory to unpack the tarball into - will be created if it doesn't exist and will throw if it exists but is not empty
|
|
53
|
+
* @param stripComponents The number of leading directories to strip out of the unpacked files, defaults to 1
|
|
54
|
+
*/
|
|
55
|
+
unpackTarballContents: (tarballPath: string, unpackDirectory: string, stripComponents?: number) => Promise<void>;
|
|
56
|
+
private isDirectory;
|
|
57
|
+
private dirIsNotEmpty;
|
|
58
|
+
private tryCreateDirectory;
|
|
59
|
+
}
|
|
60
|
+
export declare const createTarball: (directoryToTarball: string, tarballPath: string, options?: CreateTarballOptions) => Promise<void>;
|
|
61
|
+
export declare const unpackTarball: (tarballPath: string, unpackDirectory: string, options?: Partial<TarballUnpackOptions>) => Promise<void>;
|
|
62
|
+
export declare const unpackTarballContents: (tarballPath: string, unpackDirectory: string, stripComponents?: number) => Promise<void>;
|
|
63
|
+
//# sourceMappingURL=TarballUtility.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TarballUtility.d.ts","sourceRoot":"","sources":["../../src/TarballUtility.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAA;AAExB,OAAO,EAAiB,MAAM,EAAmC,UAAU,EAAS,SAAS,EAAE,MAAM,mBAAmB,CAAA;AAGxH,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;CACpB;AAED,MAAM,WAAW,oBAAoB;IACnC,oBAAoB,EAAE,OAAO,CAAA;IAC7B,eAAe,EAAE,MAAM,CAAA;IACvB,wBAAwB,EAAE,OAAO,CAAA;CAClC;AAED,MAAM,WAAW,0BAA0B;IACzC,WAAW,EAAE,OAAO,SAAS,CAAA;IAC7B,YAAY,EAAE,OAAO,UAAU,CAAA;IAC/B,UAAU,EAAE,OAAO,EAAE,CAAC,QAAQ,CAAA;IAC9B,QAAQ,EAAE,OAAO,MAAM,CAAA;CACxB;AAED;;GAEG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,WAAW,CAAkB;IACrC,OAAO,CAAC,YAAY,CAAmB;IACvC,OAAO,CAAC,UAAU,CAAoB;IACtC,OAAO,CAAC,QAAQ,CAAe;gBAEnB,YAAY,GAAE,OAAO,CAAC,0BAA0B,CAAM;IAOlE;;;;;;;;;OASG;IACH,aAAa,uBAA8B,MAAM,eAAe,MAAM,YAAY,oBAAoB,mBAsCrG;IAED;;;;;;OAMG;IACH,aAAa,gBAAuB,MAAM,mBAAmB,MAAM,YAAY,QAAQ,oBAAoB,CAAC,mBA0C3G;IAED;;;;;OAKG;IACH,qBAAqB,gBAAuB,MAAM,mBAAmB,MAAM,oBAAmB,MAAM,mBAEnG;IAED,OAAO,CAAC,WAAW,CAQlB;IAED,OAAO,CAAC,aAAa,CAOpB;IAED,OAAO,CAAC,kBAAkB,CAMzB;CACF;AAID,eAAO,MAAM,aAAa,uBAnImB,MAAM,eAAe,MAAM,YAAY,oBAAoB,kBAmIlD,CAAA;AACtD,eAAO,MAAM,aAAa,gBArFY,MAAM,mBAAmB,MAAM,YAAY,QAAQ,oBAAoB,CAAC,kBAqFxD,CAAA;AACtD,eAAO,MAAM,qBAAqB,gBApCY,MAAM,mBAAmB,MAAM,oBAAmB,MAAM,kBAoChC,CAAA"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { ExtendedError, mkdirp, requireString, requireValidPath, spawnAsync, trace, whichSync } from './generalUtils.js';
|
|
4
|
+
import { config } from './NodeCliUtilsConfig.js';
|
|
5
|
+
/**
|
|
6
|
+
* This utility class exists so we can mock the `which` dependency in unit tests without resorting to libraries that hack the import system.
|
|
7
|
+
*/
|
|
8
|
+
export class TarballUtility {
|
|
9
|
+
whichSyncFn;
|
|
10
|
+
spawnAsyncFn;
|
|
11
|
+
statSyncFn;
|
|
12
|
+
mkdirpFn;
|
|
13
|
+
constructor(dependencies = {}) {
|
|
14
|
+
this.whichSyncFn = dependencies.whichSyncFn ?? whichSync;
|
|
15
|
+
this.spawnAsyncFn = dependencies.spawnAsyncFn ?? spawnAsync;
|
|
16
|
+
this.statSyncFn = dependencies.statSyncFn ?? fs.statSync;
|
|
17
|
+
this.mkdirpFn = dependencies.mkdirpFn ?? mkdirp;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Creates a gzipped tarball from a directory by spawning a process to run OS-installed `tar` to avoid pulling in npm package dependencies.
|
|
21
|
+
* Note that Windows has tar since Windows 10 1803 (see https://devblogs.microsoft.com/commandline/windows10v1803/.
|
|
22
|
+
*
|
|
23
|
+
* It's possible this isn't 100% reliable due to differences in `tar` versions across platforms. If better normalization
|
|
24
|
+
* is required, consider using the npm package `node-tar` instead.
|
|
25
|
+
* @param directoryToTarball The directory to tarball. The directory name will be used as the root directory in the tarball
|
|
26
|
+
* @param tarballPath The path to the tarball to create - must end with '.tar.gz'
|
|
27
|
+
* @param options See {@link CreateTarballOptions}
|
|
28
|
+
*/
|
|
29
|
+
createTarball = async (directoryToTarball, tarballPath, options) => {
|
|
30
|
+
requireValidPath('directoryToTarball', directoryToTarball);
|
|
31
|
+
requireString('tarballPath', tarballPath);
|
|
32
|
+
const defaultOptions = { excludes: [] };
|
|
33
|
+
const mergedOptions = { ...defaultOptions, ...options };
|
|
34
|
+
if (!this.whichSyncFn('tar').location) {
|
|
35
|
+
throw new Error('tar command not found - please install tar on your OS to use this method, or consider using the npm package node-tar instead');
|
|
36
|
+
}
|
|
37
|
+
if (tarballPath.endsWith('.tar.gz') === false) {
|
|
38
|
+
throw new Error(`tarballPath must end with '.tar.gz': ${tarballPath}`);
|
|
39
|
+
}
|
|
40
|
+
const directoryToTarballParentDir = path.dirname(directoryToTarball);
|
|
41
|
+
const directoryToTarballName = path.basename(directoryToTarball);
|
|
42
|
+
const outputDirectory = path.dirname(tarballPath);
|
|
43
|
+
if (!fs.existsSync(outputDirectory)) {
|
|
44
|
+
trace(`tarballPath directory does not exist - creating '${outputDirectory}'`);
|
|
45
|
+
await this.mkdirpFn(outputDirectory);
|
|
46
|
+
}
|
|
47
|
+
else if (fs.existsSync(tarballPath)) {
|
|
48
|
+
throw new Error(`tarballPath already exists - delete, move or rename it first: ${tarballPath}`);
|
|
49
|
+
}
|
|
50
|
+
const excludesArgs = mergedOptions.excludes.length > 0 ? mergedOptions.excludes.map(exclude => `--exclude=${exclude}`) : [];
|
|
51
|
+
const verboseFlag = config.traceEnabled ? ['-v'] : [];
|
|
52
|
+
const args = [...(verboseFlag), '-czf', tarballPath, '-C', directoryToTarballParentDir, ...excludesArgs, directoryToTarballName];
|
|
53
|
+
const result = await this.spawnAsyncFn('tar', args);
|
|
54
|
+
if (result.code !== 0) {
|
|
55
|
+
throw new Error(`tar command failed with code ${result.code}`);
|
|
56
|
+
}
|
|
57
|
+
trace('tarball created: ' + tarballPath);
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Unpacks a gzipped tarball by spawning a process to run OS-installed `tar` to avoid pulling in npm package dependencies.
|
|
61
|
+
* This method will throw an error if the unpackDirectory is not empty, unless the `throwOnNonEmptyUnpackDir` option is set to false.
|
|
62
|
+
* @param tarballPath The path to the tarball to unpack
|
|
63
|
+
* @param unpackDirectory The directory to unpack the tarball into
|
|
64
|
+
* @param options The options to use when unpacking the tarball. See {@link TarballUnpackOptions}.
|
|
65
|
+
*/
|
|
66
|
+
unpackTarball = async (tarballPath, unpackDirectory, options) => {
|
|
67
|
+
requireValidPath('tarballPath', tarballPath);
|
|
68
|
+
requireString('unpackDirectory', unpackDirectory);
|
|
69
|
+
if (!this.whichSyncFn('tar').location) {
|
|
70
|
+
throw new Error('tar command not found - please install tar on your OS to use this method, or consider using the npm package node-tar instead');
|
|
71
|
+
}
|
|
72
|
+
const defaultOptions = { createDirIfNotExists: false, stripComponents: 0, throwOnNonEmptyUnpackDir: true };
|
|
73
|
+
const mergedOptions = { ...defaultOptions, ...options };
|
|
74
|
+
if (mergedOptions.stripComponents < 0) {
|
|
75
|
+
throw new Error('stripComponents must be greater than or equal to 0 if provided');
|
|
76
|
+
}
|
|
77
|
+
const unpackedDirExists = fs.existsSync(unpackDirectory);
|
|
78
|
+
if (unpackedDirExists && !this.isDirectory(unpackDirectory)) {
|
|
79
|
+
throw new Error(`unpackDirectory exists but is not a directory: ${unpackDirectory}`);
|
|
80
|
+
}
|
|
81
|
+
if (mergedOptions.createDirIfNotExists && !unpackedDirExists) {
|
|
82
|
+
await this.tryCreateDirectory(unpackDirectory);
|
|
83
|
+
}
|
|
84
|
+
if (!mergedOptions.createDirIfNotExists && !unpackedDirExists) {
|
|
85
|
+
throw new Error(`unpackDirectory does not exist: ${unpackDirectory}`);
|
|
86
|
+
}
|
|
87
|
+
if (mergedOptions.throwOnNonEmptyUnpackDir && this.dirIsNotEmpty(unpackDirectory)) {
|
|
88
|
+
throw new Error(`unpackDirectory exists but is not empty: ${unpackDirectory}`);
|
|
89
|
+
}
|
|
90
|
+
const verboseFlag = config.traceEnabled ? ['-v'] : [];
|
|
91
|
+
const args = [...(verboseFlag), '-xzf', tarballPath, '-C', unpackDirectory, '--strip-components', mergedOptions.stripComponents.toString()];
|
|
92
|
+
const result = await this.spawnAsyncFn('tar', args);
|
|
93
|
+
if (result.code !== 0) {
|
|
94
|
+
throw new Error(`tar command failed with code ${result.code}`);
|
|
95
|
+
}
|
|
96
|
+
trace(`tarball unpacked at ${unpackDirectory}`);
|
|
97
|
+
};
|
|
98
|
+
/**
|
|
99
|
+
* A more opinionated version of {@link unpackTarball} that assumes you want to create the directory and strip the first directory out of the unpacked files.
|
|
100
|
+
* @param tarballPath The path to the tarball to unpack
|
|
101
|
+
* @param unpackDirectory The directory to unpack the tarball into - will be created if it doesn't exist and will throw if it exists but is not empty
|
|
102
|
+
* @param stripComponents The number of leading directories to strip out of the unpacked files, defaults to 1
|
|
103
|
+
*/
|
|
104
|
+
unpackTarballContents = async (tarballPath, unpackDirectory, stripComponents = 1) => {
|
|
105
|
+
await this.unpackTarball(tarballPath, unpackDirectory, { stripComponents, createDirIfNotExists: true });
|
|
106
|
+
};
|
|
107
|
+
isDirectory = (path) => {
|
|
108
|
+
try {
|
|
109
|
+
const stats = this.statSyncFn(path);
|
|
110
|
+
return stats.isDirectory();
|
|
111
|
+
}
|
|
112
|
+
catch (err) {
|
|
113
|
+
trace('error checking idDirectory (returning false)', err);
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
dirIsNotEmpty = (dirPath) => {
|
|
118
|
+
try {
|
|
119
|
+
const stats = this.statSyncFn(dirPath);
|
|
120
|
+
return stats.isDirectory() && fs.readdirSync(dirPath).length > 0;
|
|
121
|
+
}
|
|
122
|
+
catch (err) {
|
|
123
|
+
throw new ExtendedError('Error checking dirIsNotEmpty - see innerError', err);
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
tryCreateDirectory = async (dirPath) => {
|
|
127
|
+
try {
|
|
128
|
+
await this.mkdirpFn(dirPath);
|
|
129
|
+
}
|
|
130
|
+
catch (err) {
|
|
131
|
+
throw new ExtendedError('Error creating unpackDirectory - see innerError', err);
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
const defaultUtil = new TarballUtility();
|
|
136
|
+
export const createTarball = defaultUtil.createTarball;
|
|
137
|
+
export const unpackTarball = defaultUtil.unpackTarball;
|
|
138
|
+
export const unpackTarballContents = defaultUtil.unpackTarballContents;
|
|
139
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiVGFyYmFsbFV0aWxpdHkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvVGFyYmFsbFV0aWxpdHkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLE1BQU0sU0FBUyxDQUFBO0FBQ3hCLE9BQU8sSUFBSSxNQUFNLFdBQVcsQ0FBQTtBQUM1QixPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sRUFBRSxhQUFhLEVBQUUsZ0JBQWdCLEVBQUUsVUFBVSxFQUFFLEtBQUssRUFBRSxTQUFTLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQTtBQUN4SCxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0seUJBQXlCLENBQUE7QUF1QmhEOztHQUVHO0FBQ0gsTUFBTSxPQUFPLGNBQWM7SUFDakIsV0FBVyxDQUFrQjtJQUM3QixZQUFZLENBQW1CO0lBQy9CLFVBQVUsQ0FBb0I7SUFDOUIsUUFBUSxDQUFlO0lBRS9CLFlBQVksZUFBb0QsRUFBRTtRQUNoRSxJQUFJLENBQUMsV0FBVyxHQUFHLFlBQVksQ0FBQyxXQUFXLElBQUksU0FBUyxDQUFBO1FBQ3hELElBQUksQ0FBQyxZQUFZLEdBQUcsWUFBWSxDQUFDLFlBQVksSUFBSSxVQUFVLENBQUE7UUFDM0QsSUFBSSxDQUFDLFVBQVUsR0FBRyxZQUFZLENBQUMsVUFBVSxJQUFJLEVBQUUsQ0FBQyxRQUFRLENBQUE7UUFDeEQsSUFBSSxDQUFDLFFBQVEsR0FBRyxZQUFZLENBQUMsUUFBUSxJQUFJLE1BQU0sQ0FBQTtJQUNqRCxDQUFDO0lBRUQ7Ozs7Ozs7OztPQVNHO0lBQ0gsYUFBYSxHQUFHLEtBQUssRUFBRSxrQkFBMEIsRUFBRSxXQUFtQixFQUFFLE9BQThCLEVBQUUsRUFBRTtRQUN4RyxnQkFBZ0IsQ0FBQyxvQkFBb0IsRUFBRSxrQkFBa0IsQ0FBQyxDQUFBO1FBQzFELGFBQWEsQ0FBQyxhQUFhLEVBQUUsV0FBVyxDQUFDLENBQUE7UUFFekMsTUFBTSxjQUFjLEdBQUcsRUFBRSxRQUFRLEVB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
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/** Control what is logged when running certUtils functions. */
|
|
2
|
+
export interface CertLogOptions {
|
|
3
|
+
logSpawnOutput: boolean;
|
|
4
|
+
logTraceMessages: boolean;
|
|
5
|
+
logElevatedPermissionsMessage: boolean;
|
|
6
|
+
logSuccess: boolean;
|
|
7
|
+
}
|
|
8
|
+
export interface GenerateCertOptions extends CertLogOptions {
|
|
9
|
+
/** The directory to write the generated cert files to. Defaults to `./cert`. */
|
|
10
|
+
outputDirectory: string;
|
|
11
|
+
}
|
|
12
|
+
/** Subject, thumbprint or path to the pfx file. Used with the {@link winUninstallCert} function. */
|
|
13
|
+
export type CertIdentifier = string | {
|
|
14
|
+
thumbprint: string;
|
|
15
|
+
} | {
|
|
16
|
+
pfxPath: string;
|
|
17
|
+
};
|
|
18
|
+
/** The subject or path to the pfx file. Used with the {@link winCertIsInstalled} function. */
|
|
19
|
+
export type CertIdentifierWithoutThumbprint = string | {
|
|
20
|
+
pfxPath: string;
|
|
21
|
+
};
|
|
22
|
+
/** Cert info returned by {@link winGetPfxInfo}. */
|
|
23
|
+
export type CertInfo = {
|
|
24
|
+
subject: string;
|
|
25
|
+
thumbprint: string;
|
|
26
|
+
pfxPath: string;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Wrapper function for calling openssl to generate a self-signed cert to be used for developing a local website with trusted https.
|
|
30
|
+
* @param url The url to generate a cert for. This will be used as the common name (CN) in the cert as well as the filename for the generated cert files.
|
|
31
|
+
* @param options Options for generating the cert.
|
|
32
|
+
* @returns The path to the generated pfx file.
|
|
33
|
+
*/
|
|
34
|
+
export declare function generateCertWithOpenSsl(url: string, options?: Partial<GenerateCertOptions>): Promise<string>;
|
|
35
|
+
/**
|
|
36
|
+
* Uses Powershell to install a cert to the local machine's trusted root store. Must have elevated permissions.
|
|
37
|
+
* If the cert is already installed, this function will do nothing.
|
|
38
|
+
* @param pfxPath The path to the pfx file to install.
|
|
39
|
+
*/
|
|
40
|
+
export declare function winInstallCert(pfxPath: string, options?: Partial<CertLogOptions>): Promise<void>;
|
|
41
|
+
/**
|
|
42
|
+
* Uses Powershell to check if a cert is already installed to the local machine's trusted root store.
|
|
43
|
+
* Uses the subject of the cert in order to avoid false negatives from regenerating the same self-signed cert
|
|
44
|
+
* with the same subject but different thumbprint. Note that this method is geared towards use with certs generated
|
|
45
|
+
* with the {@link generateCertWithOpenSsl} function, so this may not work using subject if your subject is not precisely "`CN=<url>`".
|
|
46
|
+
* @param identifier The subject or path to the pfx file of the cert to check.
|
|
47
|
+
* @returns `true` if the cert is already installed, `false` otherwise.
|
|
48
|
+
*/
|
|
49
|
+
export declare function winCertIsInstalled(identifier: CertIdentifierWithoutThumbprint, options?: Partial<CertLogOptions>): Promise<boolean>;
|
|
50
|
+
/**
|
|
51
|
+
* Uses Powershell to uninstall a cert from the local machine's trusted root store. Must have elevated permissions.
|
|
52
|
+
* @param identifier The subject, thumbprint or path to the pfx file of the cert to uninstall.
|
|
53
|
+
* @param options Options for uninstalling the cert.
|
|
54
|
+
*/
|
|
55
|
+
export declare function winUninstallCert(identifier: CertIdentifier, options?: Partial<CertLogOptions>): Promise<void>;
|
|
56
|
+
/**
|
|
57
|
+
* Uses Powershell to get info about a cert.
|
|
58
|
+
* @param pfxPath The path to the pfx file to get info for.
|
|
59
|
+
* @returns The subject, thumbprint and pfxPath of the cert.
|
|
60
|
+
*/
|
|
61
|
+
export declare function winGetPfxInfo(pfxPath: string): Promise<CertInfo>;
|
|
62
|
+
/**
|
|
63
|
+
* Does not actually do anything - just outputs the manual instructions for installing a cert for use by chrome on linux.
|
|
64
|
+
*/
|
|
65
|
+
export declare function linuxInstallCert(): void;
|
|
66
|
+
//# sourceMappingURL=certUtils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"certUtils.d.ts","sourceRoot":"","sources":["../../src/certUtils.ts"],"names":[],"mappings":"AAqBA,+DAA+D;AAC/D,MAAM,WAAW,cAAc;IAC7B,cAAc,EAAE,OAAO,CAAA;IACvB,gBAAgB,EAAE,OAAO,CAAA;IACzB,6BAA6B,EAAE,OAAO,CAAA;IACtC,UAAU,EAAE,OAAO,CAAA;CACpB;AAED,MAAM,WAAW,mBAAoB,SAAQ,cAAc;IACzD,gFAAgF;IAChF,eAAe,EAAE,MAAM,CAAA;CACxB;AASD,oGAAoG;AACpG,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,CAAA;AAElF,8FAA8F;AAC9F,MAAM,MAAM,+BAA+B,GAAG,MAAM,GAAG;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,CAAA;AAE1E,mDAAmD;AACnD,MAAM,MAAM,QAAQ,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAA;AAE/E;;;;;GAKG;AACH,wBAAsB,uBAAuB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,mBAAmB,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAkElH;AAED;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,iBAwBtF;AAED;;;;;;;GAOG;AACH,wBAAsB,kBAAkB,CAAC,UAAU,EAAE,+BAA+B,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAkCzI;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,CAAC,UAAU,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,iBA+BnG;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAqBtE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,SAU/B"}
|