@rushstack/package-extractor 0.12.0 → 0.12.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/CHANGELOG.json +49 -0
- package/CHANGELOG.md +15 -1
- package/dist/scripts/create-links.js +17161 -1197
- package/dist/scripts/create-links.js.map +1 -1
- package/dist/tsdoc-metadata.json +1 -1
- package/lib-commonjs/ArchiveManager.js +64 -0
- package/lib-commonjs/ArchiveManager.js.map +1 -0
- package/lib-commonjs/AssetHandler.js +171 -0
- package/lib-commonjs/AssetHandler.js.map +1 -0
- package/lib-commonjs/PackageExtractor.js +568 -0
- package/lib-commonjs/PackageExtractor.js.map +1 -0
- package/lib-commonjs/PathConstants.js +11 -0
- package/lib-commonjs/PathConstants.js.map +1 -0
- package/lib-commonjs/SymlinkAnalyzer.js +159 -0
- package/lib-commonjs/SymlinkAnalyzer.js.map +1 -0
- package/lib-commonjs/Utils.js +85 -0
- package/lib-commonjs/Utils.js.map +1 -0
- package/lib-commonjs/index.js +8 -0
- package/lib-commonjs/index.js.map +1 -0
- package/lib-commonjs/scripts/createLinks/cli/CreateLinksCommandLineParser.js +35 -0
- package/lib-commonjs/scripts/createLinks/cli/CreateLinksCommandLineParser.js.map +1 -0
- package/lib-commonjs/scripts/createLinks/cli/actions/CreateLinksAction.js +91 -0
- package/lib-commonjs/scripts/createLinks/cli/actions/CreateLinksAction.js.map +1 -0
- package/lib-commonjs/scripts/createLinks/cli/actions/RemoveLinksAction.js +38 -0
- package/lib-commonjs/scripts/createLinks/cli/actions/RemoveLinksAction.js.map +1 -0
- package/lib-commonjs/scripts/createLinks/start.js +10 -0
- package/lib-commonjs/scripts/createLinks/start.js.map +1 -0
- package/lib-commonjs/scripts/createLinks/utilities/CreateLinksUtilities.js +14 -0
- package/lib-commonjs/scripts/createLinks/utilities/CreateLinksUtilities.js.map +1 -0
- package/lib-commonjs/scripts/createLinks/utilities/constants.js +44 -0
- package/lib-commonjs/scripts/createLinks/utilities/constants.js.map +1 -0
- package/lib-dts/ArchiveManager.d.ts +13 -0
- package/lib-dts/ArchiveManager.d.ts.map +1 -0
- package/lib-dts/AssetHandler.d.ts +52 -0
- package/lib-dts/AssetHandler.d.ts.map +1 -0
- package/lib-dts/PackageExtractor.d.ts +280 -0
- package/lib-dts/PackageExtractor.d.ts.map +1 -0
- package/lib-dts/PathConstants.d.ts +4 -0
- package/lib-dts/PathConstants.d.ts.map +1 -0
- package/lib-dts/SymlinkAnalyzer.d.ts +73 -0
- package/lib-dts/SymlinkAnalyzer.d.ts.map +1 -0
- package/lib-dts/Utils.d.ts +30 -0
- package/lib-dts/Utils.d.ts.map +1 -0
- package/lib-dts/index.d.ts +3 -0
- package/lib-dts/index.d.ts.map +1 -0
- package/lib-dts/scripts/createLinks/cli/CreateLinksCommandLineParser.d.ts +8 -0
- package/lib-dts/scripts/createLinks/cli/CreateLinksCommandLineParser.d.ts.map +1 -0
- package/lib-dts/scripts/createLinks/cli/actions/CreateLinksAction.d.ts +10 -0
- package/lib-dts/scripts/createLinks/cli/actions/CreateLinksAction.d.ts.map +1 -0
- package/lib-dts/scripts/createLinks/cli/actions/RemoveLinksAction.d.ts +10 -0
- package/lib-dts/scripts/createLinks/cli/actions/RemoveLinksAction.d.ts.map +1 -0
- package/lib-dts/scripts/createLinks/start.d.ts +2 -0
- package/lib-dts/scripts/createLinks/start.d.ts.map +1 -0
- package/lib-dts/scripts/createLinks/utilities/CreateLinksUtilities.d.ts +3 -0
- package/lib-dts/scripts/createLinks/utilities/CreateLinksUtilities.d.ts.map +1 -0
- package/lib-dts/scripts/createLinks/utilities/constants.d.ts +34 -0
- package/lib-dts/scripts/createLinks/utilities/constants.d.ts.map +1 -0
- package/lib-esm/ArchiveManager.js +57 -0
- package/lib-esm/ArchiveManager.js.map +1 -0
- package/lib-esm/AssetHandler.js +164 -0
- package/lib-esm/AssetHandler.js.map +1 -0
- package/lib-esm/PackageExtractor.js +528 -0
- package/lib-esm/PackageExtractor.js.map +1 -0
- package/lib-esm/PathConstants.js +8 -0
- package/lib-esm/PathConstants.js.map +1 -0
- package/lib-esm/SymlinkAnalyzer.js +122 -0
- package/lib-esm/SymlinkAnalyzer.js.map +1 -0
- package/lib-esm/Utils.js +76 -0
- package/lib-esm/Utils.js.map +1 -0
- package/lib-esm/index.js +4 -0
- package/lib-esm/index.js.map +1 -0
- package/lib-esm/scripts/createLinks/cli/CreateLinksCommandLineParser.js +31 -0
- package/lib-esm/scripts/createLinks/cli/CreateLinksCommandLineParser.js.map +1 -0
- package/lib-esm/scripts/createLinks/cli/actions/CreateLinksAction.js +84 -0
- package/lib-esm/scripts/createLinks/cli/actions/CreateLinksAction.js.map +1 -0
- package/lib-esm/scripts/createLinks/cli/actions/RemoveLinksAction.js +30 -0
- package/lib-esm/scripts/createLinks/cli/actions/RemoveLinksAction.js.map +1 -0
- package/lib-esm/scripts/createLinks/start.js +8 -0
- package/lib-esm/scripts/createLinks/start.js.map +1 -0
- package/lib-esm/scripts/createLinks/utilities/CreateLinksUtilities.js +11 -0
- package/lib-esm/scripts/createLinks/utilities/CreateLinksUtilities.js.map +1 -0
- package/lib-esm/scripts/createLinks/utilities/constants.js +38 -0
- package/lib-esm/scripts/createLinks/utilities/constants.js.map +1 -0
- package/package.json +9 -7
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ITerminal } from '@rushstack/terminal';
|
|
2
|
+
import { CommandLineAction } from '@rushstack/ts-command-line';
|
|
3
|
+
export declare class CreateLinksAction extends CommandLineAction {
|
|
4
|
+
private _terminal;
|
|
5
|
+
private _realizeFilesParameter;
|
|
6
|
+
private _linkBinsParameter;
|
|
7
|
+
constructor(terminal: ITerminal);
|
|
8
|
+
protected onExecuteAsync(): Promise<void>;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=CreateLinksAction.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CreateLinksAction.d.ts","sourceRoot":"","sources":["../../../../../src/scripts/createLinks/cli/actions/CreateLinksAction.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAiC,MAAM,4BAA4B,CAAC;AAsE9F,qBAAa,iBAAkB,SAAQ,iBAAiB;IACtD,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,sBAAsB,CAA2B;IACzD,OAAO,CAAC,kBAAkB,CAA2B;gBAElC,QAAQ,EAAE,SAAS;cAoBb,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;CAsBzD"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ITerminal } from '@rushstack/terminal';
|
|
2
|
+
import { CommandLineAction } from '@rushstack/ts-command-line';
|
|
3
|
+
import type { IExtractorMetadataJson } from '../../../../PackageExtractor';
|
|
4
|
+
export declare function removeLinksAsync(terminal: ITerminal, targetRootFolder: string, extractorMetadataObject: IExtractorMetadataJson): Promise<void>;
|
|
5
|
+
export declare class RemoveLinksAction extends CommandLineAction {
|
|
6
|
+
private _terminal;
|
|
7
|
+
constructor(terminal: ITerminal);
|
|
8
|
+
protected onExecuteAsync(): Promise<void>;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=RemoveLinksAction.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RemoveLinksAction.d.ts","sourceRoot":"","sources":["../../../../../src/scripts/createLinks/cli/actions/RemoveLinksAction.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAE/D,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AAI3E,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,SAAS,EACnB,gBAAgB,EAAE,MAAM,EACxB,uBAAuB,EAAE,sBAAsB,GAC9C,OAAO,CAAC,IAAI,CAAC,CAUf;AAED,qBAAa,iBAAkB,SAAQ,iBAAiB;IACtD,OAAO,CAAC,SAAS,CAAY;gBAEV,QAAQ,EAAE,SAAS;cAUb,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;CAMzD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../../../src/scripts/createLinks/start.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CreateLinksUtilities.d.ts","sourceRoot":"","sources":["../../../../src/scripts/createLinks/utilities/CreateLinksUtilities.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AAGxE,wBAAsB,yBAAyB,IAAI,OAAO,CAAC,sBAAsB,CAAC,CAKjF"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { TARGET_ROOT_SCRIPT_RELATIVE_PATH_TEMPLATE_STRING as TargetRootScriptRelativePathTemplateString } from '../../../PackageExtractor';
|
|
2
|
+
/**
|
|
3
|
+
* The maximum number of concurrent operations to perform.
|
|
4
|
+
*/
|
|
5
|
+
export declare const MAX_CONCURRENCY: number;
|
|
6
|
+
/**
|
|
7
|
+
* The name of the action to create symlinks.
|
|
8
|
+
*/
|
|
9
|
+
export declare const CREATE_ACTION_NAME: 'create';
|
|
10
|
+
/**
|
|
11
|
+
* The name of the action to remove symlinks.
|
|
12
|
+
*/
|
|
13
|
+
export declare const REMOVE_ACTION_NAME: 'remove';
|
|
14
|
+
/**
|
|
15
|
+
* The name of the parameter to realize files when creating symlinks.
|
|
16
|
+
*/
|
|
17
|
+
export declare const REALIZE_FILES_PARAMETER_NAME: '--realize-files';
|
|
18
|
+
/**
|
|
19
|
+
* The name of the parameter to link bins when creating symlinks.
|
|
20
|
+
*/
|
|
21
|
+
export declare const LINK_BINS_PARAMETER_NAME: '--link-bins';
|
|
22
|
+
/**
|
|
23
|
+
* The name of the parameter to link packages when creating symlinks. The actual value of this
|
|
24
|
+
* export is modified after bundling the script to ensure that the extracted version of the script
|
|
25
|
+
* contains the relative path from the extraction target folder to the script. Generally, this
|
|
26
|
+
* value should not be used directly, but rather the `TARGET_ROOT_FOLDER` export should be used
|
|
27
|
+
* instead.
|
|
28
|
+
*/
|
|
29
|
+
export declare const TARGET_ROOT_SCRIPT_RELATIVE_PATH: typeof TargetRootScriptRelativePathTemplateString;
|
|
30
|
+
/**
|
|
31
|
+
* The path to the root folder where symlinks are created.
|
|
32
|
+
*/
|
|
33
|
+
export declare const TARGET_ROOT_FOLDER: string;
|
|
34
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../../src/scripts/createLinks/utilities/constants.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,gDAAgD,IAAI,0CAA0C,EAAE,MAAM,2BAA2B,CAAC;AAEhJ;;GAEG;AACH,eAAO,MAAM,eAAe,EAAE,MAA8D,CAAC;AAE7F;;GAEG;AACH,eAAO,MAAM,kBAAkB,EAAE,QAAmB,CAAC;AAErD;;GAEG;AACH,eAAO,MAAM,kBAAkB,EAAE,QAAmB,CAAC;AAErD;;GAEG;AACH,eAAO,MAAM,4BAA4B,EAAE,iBAAqC,CAAC;AAEjF;;GAEG;AACH,eAAO,MAAM,wBAAwB,EAAE,aAA6B,CAAC;AAErE;;;;;;GAMG;AACH,eAAO,MAAM,gCAAgC,EAAE,OAAO,0CAChB,CAAC;AAEvC;;GAEG;AACH,eAAO,MAAM,kBAAkB,EAAE,MAAkE,CAAC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
|
|
2
|
+
// See LICENSE in the project root for license information.
|
|
3
|
+
import JSZip from 'jszip';
|
|
4
|
+
import { FileSystem, Path } from '@rushstack/node-core-library';
|
|
5
|
+
// 755 are default permissions to allow read/write/execute for owner and read/execute for group and others.
|
|
6
|
+
const DEFAULT_FILE_PERMISSIONS = 0o755;
|
|
7
|
+
// This value sets the allowed permissions when preserving symbolic links.
|
|
8
|
+
// 120000 is the symbolic link identifier, and is OR'd with the default file permissions.
|
|
9
|
+
// See: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/stat.h#n10
|
|
10
|
+
// eslint-disable-next-line no-bitwise
|
|
11
|
+
const SYMBOLIC_LINK_PERMISSIONS = 0o120000 | DEFAULT_FILE_PERMISSIONS;
|
|
12
|
+
export class ArchiveManager {
|
|
13
|
+
constructor() {
|
|
14
|
+
this._zip = new JSZip();
|
|
15
|
+
}
|
|
16
|
+
async addToArchiveAsync(options) {
|
|
17
|
+
var _a;
|
|
18
|
+
const { filePath, fileData, archivePath } = options;
|
|
19
|
+
let data;
|
|
20
|
+
let permissions;
|
|
21
|
+
if (filePath) {
|
|
22
|
+
const stats = (_a = options.stats) !== null && _a !== void 0 ? _a : (await FileSystem.getLinkStatisticsAsync(filePath));
|
|
23
|
+
if (stats.isSymbolicLink()) {
|
|
24
|
+
data = await FileSystem.readLinkAsync(filePath);
|
|
25
|
+
permissions = SYMBOLIC_LINK_PERMISSIONS;
|
|
26
|
+
}
|
|
27
|
+
else if (stats.isDirectory()) {
|
|
28
|
+
throw new Error('Directories cannot be added to the archive');
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
data = await FileSystem.readFileToBufferAsync(filePath);
|
|
32
|
+
permissions = stats.mode;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
else if (fileData) {
|
|
36
|
+
data = fileData;
|
|
37
|
+
permissions = DEFAULT_FILE_PERMISSIONS;
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
throw new Error('Either filePath or fileData must be provided');
|
|
41
|
+
}
|
|
42
|
+
// Replace backslashes for Unix compat
|
|
43
|
+
const addPath = Path.convertToSlashes(archivePath);
|
|
44
|
+
this._zip.file(addPath, data, {
|
|
45
|
+
unixPermissions: permissions,
|
|
46
|
+
dir: false
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
async createArchiveAsync(archiveFilePath) {
|
|
50
|
+
const zipContent = await this._zip.generateAsync({
|
|
51
|
+
type: 'nodebuffer',
|
|
52
|
+
platform: 'UNIX'
|
|
53
|
+
});
|
|
54
|
+
await FileSystem.writeFileAsync(archiveFilePath, zipContent);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=ArchiveManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ArchiveManager.js","sourceRoot":"","sources":["../src/ArchiveManager.ts"],"names":[],"mappings":"AAAA,4FAA4F;AAC5F,2DAA2D;AAE3D,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,UAAU,EAAwB,IAAI,EAAE,MAAM,8BAA8B,CAAC;AAEtF,2GAA2G;AAC3G,MAAM,wBAAwB,GAAW,KAAK,CAAC;AAC/C,0EAA0E;AAC1E,yFAAyF;AACzF,6GAA6G;AAC7G,sCAAsC;AACtC,MAAM,yBAAyB,GAAW,QAAQ,GAAG,wBAAwB,CAAC;AAS9E,MAAM,OAAO,cAAc;IAA3B;QACU,SAAI,GAAU,IAAI,KAAK,EAAE,CAAC;IAwCpC,CAAC;IAtCQ,KAAK,CAAC,iBAAiB,CAAC,OAA6B;;QAC1D,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC;QAEpD,IAAI,IAAqB,CAAC;QAC1B,IAAI,WAAmB,CAAC;QACxB,IAAI,QAAQ,EAAE,CAAC;YACb,MAAM,KAAK,GAAoB,MAAA,OAAO,CAAC,KAAK,mCAAI,CAAC,MAAM,UAAU,CAAC,sBAAsB,CAAC,QAAQ,CAAC,CAAC,CAAC;YACpG,IAAI,KAAK,CAAC,cAAc,EAAE,EAAE,CAAC;gBAC3B,IAAI,GAAG,MAAM,UAAU,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;gBAChD,WAAW,GAAG,yBAAyB,CAAC;YAC1C,CAAC;iBAAM,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;gBAC/B,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;YAChE,CAAC;iBAAM,CAAC;gBACN,IAAI,GAAG,MAAM,UAAU,CAAC,qBAAqB,CAAC,QAAQ,CAAC,CAAC;gBACxD,WAAW,GAAG,KAAK,CAAC,IAAI,CAAC;YAC3B,CAAC;QACH,CAAC;aAAM,IAAI,QAAQ,EAAE,CAAC;YACpB,IAAI,GAAG,QAAQ,CAAC;YAChB,WAAW,GAAG,wBAAwB,CAAC;QACzC,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;QAClE,CAAC;QAED,sCAAsC;QACtC,MAAM,OAAO,GAAW,IAAI,CAAC,gBAAgB,CAAC,WAAW,CAAC,CAAC;QAC3D,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE;YAC5B,eAAe,EAAE,WAAW;YAC5B,GAAG,EAAE,KAAK;SACX,CAAC,CAAC;IACL,CAAC;IAEM,KAAK,CAAC,kBAAkB,CAAC,eAAuB;QACrD,MAAM,UAAU,GAAW,MAAM,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC;YACvD,IAAI,EAAE,YAAY;YAClB,QAAQ,EAAE,MAAM;SACjB,CAAC,CAAC;QACH,MAAM,UAAU,CAAC,cAAc,CAAC,eAAe,EAAE,UAAU,CAAC,CAAC;IAC/D,CAAC;CACF","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport JSZip from 'jszip';\n\nimport { FileSystem, type FileSystemStats, Path } from '@rushstack/node-core-library';\n\n// 755 are default permissions to allow read/write/execute for owner and read/execute for group and others.\nconst DEFAULT_FILE_PERMISSIONS: number = 0o755;\n// This value sets the allowed permissions when preserving symbolic links.\n// 120000 is the symbolic link identifier, and is OR'd with the default file permissions.\n// See: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/stat.h#n10\n// eslint-disable-next-line no-bitwise\nconst SYMBOLIC_LINK_PERMISSIONS: number = 0o120000 | DEFAULT_FILE_PERMISSIONS;\n\nexport interface IAddToArchiveOptions {\n filePath?: string;\n fileData?: Buffer | string;\n archivePath: string;\n stats?: FileSystemStats;\n}\n\nexport class ArchiveManager {\n private _zip: JSZip = new JSZip();\n\n public async addToArchiveAsync(options: IAddToArchiveOptions): Promise<void> {\n const { filePath, fileData, archivePath } = options;\n\n let data: Buffer | string;\n let permissions: number;\n if (filePath) {\n const stats: FileSystemStats = options.stats ?? (await FileSystem.getLinkStatisticsAsync(filePath));\n if (stats.isSymbolicLink()) {\n data = await FileSystem.readLinkAsync(filePath);\n permissions = SYMBOLIC_LINK_PERMISSIONS;\n } else if (stats.isDirectory()) {\n throw new Error('Directories cannot be added to the archive');\n } else {\n data = await FileSystem.readFileToBufferAsync(filePath);\n permissions = stats.mode;\n }\n } else if (fileData) {\n data = fileData;\n permissions = DEFAULT_FILE_PERMISSIONS;\n } else {\n throw new Error('Either filePath or fileData must be provided');\n }\n\n // Replace backslashes for Unix compat\n const addPath: string = Path.convertToSlashes(archivePath);\n this._zip.file(addPath, data, {\n unixPermissions: permissions,\n dir: false\n });\n }\n\n public async createArchiveAsync(archiveFilePath: string): Promise<void> {\n const zipContent: Buffer = await this._zip.generateAsync({\n type: 'nodebuffer',\n platform: 'UNIX'\n });\n await FileSystem.writeFileAsync(archiveFilePath, zipContent);\n }\n}\n"]}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
|
|
2
|
+
// See LICENSE in the project root for license information.
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import fs from 'node:fs';
|
|
5
|
+
import { Async, FileSystem, Path } from '@rushstack/node-core-library';
|
|
6
|
+
import { ArchiveManager } from './ArchiveManager';
|
|
7
|
+
import { remapSourcePathForTargetFolder } from './Utils';
|
|
8
|
+
export class AssetHandler {
|
|
9
|
+
constructor(options) {
|
|
10
|
+
this._includedAssetPaths = new Set();
|
|
11
|
+
this._isFinalized = false;
|
|
12
|
+
const { terminal, sourceRootFolder, targetRootFolder, linkCreation, symlinkAnalyzer, createArchiveFilePath, createArchiveOnly = false } = options;
|
|
13
|
+
this._terminal = terminal;
|
|
14
|
+
this._sourceRootFolder = sourceRootFolder;
|
|
15
|
+
this._targetRootFolder = targetRootFolder;
|
|
16
|
+
this._symlinkAnalyzer = symlinkAnalyzer;
|
|
17
|
+
if (createArchiveFilePath) {
|
|
18
|
+
if (path.extname(createArchiveFilePath) !== '.zip') {
|
|
19
|
+
throw new Error('Only archives with the .zip file extension are currently supported.');
|
|
20
|
+
}
|
|
21
|
+
this._archiveFilePath = path.resolve(targetRootFolder, createArchiveFilePath);
|
|
22
|
+
this._archiveManager = new ArchiveManager();
|
|
23
|
+
}
|
|
24
|
+
if (createArchiveOnly && !this._archiveManager) {
|
|
25
|
+
throw new Error('createArchiveOnly cannot be true if createArchiveFilePath is not provided');
|
|
26
|
+
}
|
|
27
|
+
this._createArchiveOnly = createArchiveOnly;
|
|
28
|
+
this._linkCreationMode = linkCreation || 'default';
|
|
29
|
+
}
|
|
30
|
+
async includeAssetAsync(options) {
|
|
31
|
+
const { sourceFileContent, targetFilePath, ignoreIfExisting = false } = options;
|
|
32
|
+
let { sourceFilePath } = options;
|
|
33
|
+
if (this._isFinalized) {
|
|
34
|
+
throw new Error('includeAssetAsync() cannot be called after finalizeAsync()');
|
|
35
|
+
}
|
|
36
|
+
if (!sourceFilePath && !sourceFileContent) {
|
|
37
|
+
if (!Path.isUnder(targetFilePath, this._targetRootFolder)) {
|
|
38
|
+
throw new Error('The existing asset path must be under the target root folder');
|
|
39
|
+
}
|
|
40
|
+
sourceFilePath = targetFilePath;
|
|
41
|
+
}
|
|
42
|
+
if (sourceFilePath && sourceFileContent) {
|
|
43
|
+
throw new Error('Either sourceFilePath or sourceFileContent must be provided, but not both');
|
|
44
|
+
}
|
|
45
|
+
if (this._includedAssetPaths.has(targetFilePath)) {
|
|
46
|
+
if (ignoreIfExisting) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
throw new Error(`The asset at path "${targetFilePath}" has already been included`);
|
|
50
|
+
}
|
|
51
|
+
if (!this._createArchiveOnly) {
|
|
52
|
+
// Ignore when the source file is the same as the target file, as it's a no-op
|
|
53
|
+
if (sourceFilePath && sourceFilePath !== targetFilePath) {
|
|
54
|
+
// Use the fs.copyFile API instead of FileSystem.copyFileAsync() since copyFileAsync performs
|
|
55
|
+
// a needless stat() call to determine if it's a file or folder, and we already know it's a file.
|
|
56
|
+
try {
|
|
57
|
+
await fs.promises.copyFile(sourceFilePath, targetFilePath, fs.constants.COPYFILE_EXCL);
|
|
58
|
+
}
|
|
59
|
+
catch (e) {
|
|
60
|
+
if (!FileSystem.isNotExistError(e)) {
|
|
61
|
+
throw e;
|
|
62
|
+
}
|
|
63
|
+
// The parent folder may not exist, so ensure it exists before trying to copy again
|
|
64
|
+
await FileSystem.ensureFolderAsync(path.dirname(targetFilePath));
|
|
65
|
+
await fs.promises.copyFile(sourceFilePath, targetFilePath, fs.constants.COPYFILE_EXCL);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
else if (sourceFileContent) {
|
|
69
|
+
await FileSystem.writeFileAsync(targetFilePath, sourceFileContent, {
|
|
70
|
+
ensureFolderExists: true
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (this._archiveManager) {
|
|
75
|
+
const targetRelativeFilePath = path.relative(this._targetRootFolder, targetFilePath);
|
|
76
|
+
if (sourceFilePath) {
|
|
77
|
+
await this._archiveManager.addToArchiveAsync({
|
|
78
|
+
filePath: sourceFilePath,
|
|
79
|
+
archivePath: targetRelativeFilePath
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
else if (sourceFileContent) {
|
|
83
|
+
await this._archiveManager.addToArchiveAsync({
|
|
84
|
+
fileData: sourceFileContent,
|
|
85
|
+
archivePath: targetRelativeFilePath
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
this._includedAssetPaths.add(targetFilePath);
|
|
90
|
+
}
|
|
91
|
+
get assetPaths() {
|
|
92
|
+
return [...this._includedAssetPaths];
|
|
93
|
+
}
|
|
94
|
+
async finalizeAsync(options) {
|
|
95
|
+
const { onAfterExtractSymlinksAsync } = options !== null && options !== void 0 ? options : {};
|
|
96
|
+
if (this._isFinalized) {
|
|
97
|
+
throw new Error('finalizeAsync() has already been called');
|
|
98
|
+
}
|
|
99
|
+
if (this._linkCreationMode === 'default') {
|
|
100
|
+
this._terminal.writeLine('Creating symlinks');
|
|
101
|
+
const linksToCopy = this._symlinkAnalyzer.reportSymlinks();
|
|
102
|
+
await Async.forEachAsync(linksToCopy, async (linkToCopy) => {
|
|
103
|
+
await this._extractSymlinkAsync(linkToCopy);
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
await (onAfterExtractSymlinksAsync === null || onAfterExtractSymlinksAsync === void 0 ? void 0 : onAfterExtractSymlinksAsync());
|
|
107
|
+
if (this._archiveManager && this._archiveFilePath) {
|
|
108
|
+
this._terminal.writeLine(`Creating archive at "${this._archiveFilePath}"`);
|
|
109
|
+
await this._archiveManager.createArchiveAsync(this._archiveFilePath);
|
|
110
|
+
}
|
|
111
|
+
this._isFinalized = true;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Create a symlink as described by the ILinkInfo object.
|
|
115
|
+
*/
|
|
116
|
+
async _extractSymlinkAsync(linkInfo) {
|
|
117
|
+
const { kind, linkPath, targetPath } = {
|
|
118
|
+
...linkInfo,
|
|
119
|
+
linkPath: remapSourcePathForTargetFolder({
|
|
120
|
+
sourceRootFolder: this._sourceRootFolder,
|
|
121
|
+
targetRootFolder: this._targetRootFolder,
|
|
122
|
+
sourcePath: linkInfo.linkPath
|
|
123
|
+
}),
|
|
124
|
+
targetPath: remapSourcePathForTargetFolder({
|
|
125
|
+
sourceRootFolder: this._sourceRootFolder,
|
|
126
|
+
targetRootFolder: this._targetRootFolder,
|
|
127
|
+
sourcePath: linkInfo.targetPath
|
|
128
|
+
})
|
|
129
|
+
};
|
|
130
|
+
const newLinkFolder = path.dirname(linkPath);
|
|
131
|
+
await FileSystem.ensureFolderAsync(newLinkFolder);
|
|
132
|
+
// Link to the relative path for symlinks
|
|
133
|
+
const relativeTargetPath = path.relative(newLinkFolder, targetPath);
|
|
134
|
+
// NOTE: This logic is based on NpmLinkManager._createSymlink()
|
|
135
|
+
if (kind === 'fileLink') {
|
|
136
|
+
// For files, we use a Windows "hard link", because creating a symbolic link requires
|
|
137
|
+
// administrator permission. However hard links seem to cause build failures on Mac,
|
|
138
|
+
// so for all other operating systems we use symbolic links for this case.
|
|
139
|
+
if (process.platform === 'win32') {
|
|
140
|
+
await FileSystem.createHardLinkAsync({
|
|
141
|
+
linkTargetPath: relativeTargetPath,
|
|
142
|
+
newLinkPath: linkPath
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
await FileSystem.createSymbolicLinkFileAsync({
|
|
147
|
+
linkTargetPath: relativeTargetPath,
|
|
148
|
+
newLinkPath: linkPath
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
// Junctions are only supported on Windows. This will create a symbolic link on other platforms.
|
|
154
|
+
await FileSystem.createSymbolicLinkJunctionAsync({
|
|
155
|
+
linkTargetPath: relativeTargetPath,
|
|
156
|
+
newLinkPath: linkPath
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
// Since the created symlinks have the required relative paths, they can be added directly to
|
|
160
|
+
// the archive.
|
|
161
|
+
await this.includeAssetAsync({ targetFilePath: linkPath });
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
//# sourceMappingURL=AssetHandler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AssetHandler.js","sourceRoot":"","sources":["../src/AssetHandler.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport path from 'node:path';\nimport fs from 'node:fs';\n\nimport { Async, FileSystem, Path, type FileSystemStats } from '@rushstack/node-core-library';\nimport type { ITerminal } from '@rushstack/terminal';\n\nimport { ArchiveManager } from './ArchiveManager';\nimport type { IExtractorOptions, LinkCreationMode } from './PackageExtractor';\nimport type { ILinkInfo, SymlinkAnalyzer } from './SymlinkAnalyzer';\nimport { remapSourcePathForTargetFolder } from './Utils';\n\nexport interface IIncludeAssetOptions {\n sourceFilePath?: string;\n sourceFileStats?: FileSystemStats;\n sourceFileContent?: string | Buffer;\n targetFilePath: string;\n ignoreIfExisting?: boolean;\n}\n\nexport interface IIncludeAssetPathOptions extends IIncludeAssetOptions {\n sourceFilePath: string;\n sourceFileContent?: never;\n}\n\nexport interface IIncludeExistingAssetPathOptions extends IIncludeAssetOptions {\n sourceFilePath?: never;\n sourceFileContent?: never;\n}\n\nexport interface IIncludeAssetContentOptions extends IIncludeAssetOptions {\n sourceFileContent: string | Buffer;\n sourceFilePath?: never;\n sourceFileStats?: never;\n}\n\nexport interface IAssetHandlerOptions extends IExtractorOptions {\n symlinkAnalyzer: SymlinkAnalyzer;\n}\n\nexport interface IFinalizeOptions {\n onAfterExtractSymlinksAsync: () => Promise<void>;\n}\n\nexport class AssetHandler {\n private readonly _terminal: ITerminal;\n private readonly _sourceRootFolder: string;\n private readonly _targetRootFolder: string;\n private readonly _createArchiveOnly: boolean;\n private readonly _symlinkAnalyzer: SymlinkAnalyzer;\n private readonly _archiveManager: ArchiveManager | undefined;\n private readonly _archiveFilePath: string | undefined;\n private readonly _linkCreationMode: LinkCreationMode;\n private readonly _includedAssetPaths: Set<string> = new Set<string>();\n private _isFinalized: boolean = false;\n\n public constructor(options: IAssetHandlerOptions) {\n const {\n terminal,\n sourceRootFolder,\n targetRootFolder,\n linkCreation,\n symlinkAnalyzer,\n createArchiveFilePath,\n createArchiveOnly = false\n } = options;\n this._terminal = terminal;\n this._sourceRootFolder = sourceRootFolder;\n this._targetRootFolder = targetRootFolder;\n this._symlinkAnalyzer = symlinkAnalyzer;\n if (createArchiveFilePath) {\n if (path.extname(createArchiveFilePath) !== '.zip') {\n throw new Error('Only archives with the .zip file extension are currently supported.');\n }\n this._archiveFilePath = path.resolve(targetRootFolder, createArchiveFilePath);\n this._archiveManager = new ArchiveManager();\n }\n if (createArchiveOnly && !this._archiveManager) {\n throw new Error('createArchiveOnly cannot be true if createArchiveFilePath is not provided');\n }\n this._createArchiveOnly = createArchiveOnly;\n this._linkCreationMode = linkCreation || 'default';\n }\n\n public async includeAssetAsync(options: IIncludeAssetPathOptions): Promise<void>;\n public async includeAssetAsync(options: IIncludeExistingAssetPathOptions): Promise<void>;\n public async includeAssetAsync(options: IIncludeAssetContentOptions): Promise<void>;\n public async includeAssetAsync(options: IIncludeAssetOptions): Promise<void> {\n const { sourceFileContent, targetFilePath, ignoreIfExisting = false } = options;\n let { sourceFilePath } = options;\n\n if (this._isFinalized) {\n throw new Error('includeAssetAsync() cannot be called after finalizeAsync()');\n }\n if (!sourceFilePath && !sourceFileContent) {\n if (!Path.isUnder(targetFilePath, this._targetRootFolder)) {\n throw new Error('The existing asset path must be under the target root folder');\n }\n sourceFilePath = targetFilePath;\n }\n if (sourceFilePath && sourceFileContent) {\n throw new Error('Either sourceFilePath or sourceFileContent must be provided, but not both');\n }\n if (this._includedAssetPaths.has(targetFilePath)) {\n if (ignoreIfExisting) {\n return;\n }\n throw new Error(`The asset at path \"${targetFilePath}\" has already been included`);\n }\n\n if (!this._createArchiveOnly) {\n // Ignore when the source file is the same as the target file, as it's a no-op\n if (sourceFilePath && sourceFilePath !== targetFilePath) {\n // Use the fs.copyFile API instead of FileSystem.copyFileAsync() since copyFileAsync performs\n // a needless stat() call to determine if it's a file or folder, and we already know it's a file.\n try {\n await fs.promises.copyFile(sourceFilePath, targetFilePath, fs.constants.COPYFILE_EXCL);\n } catch (e: unknown) {\n if (!FileSystem.isNotExistError(e as Error)) {\n throw e;\n }\n // The parent folder may not exist, so ensure it exists before trying to copy again\n await FileSystem.ensureFolderAsync(path.dirname(targetFilePath));\n await fs.promises.copyFile(sourceFilePath, targetFilePath, fs.constants.COPYFILE_EXCL);\n }\n } else if (sourceFileContent) {\n await FileSystem.writeFileAsync(targetFilePath, sourceFileContent, {\n ensureFolderExists: true\n });\n }\n }\n\n if (this._archiveManager) {\n const targetRelativeFilePath: string = path.relative(this._targetRootFolder, targetFilePath);\n if (sourceFilePath) {\n await this._archiveManager.addToArchiveAsync({\n filePath: sourceFilePath,\n archivePath: targetRelativeFilePath\n });\n } else if (sourceFileContent) {\n await this._archiveManager.addToArchiveAsync({\n fileData: sourceFileContent,\n archivePath: targetRelativeFilePath\n });\n }\n }\n\n this._includedAssetPaths.add(targetFilePath);\n }\n\n public get assetPaths(): string[] {\n return [...this._includedAssetPaths];\n }\n\n public async finalizeAsync(options?: IFinalizeOptions): Promise<void> {\n const { onAfterExtractSymlinksAsync } = options ?? {};\n\n if (this._isFinalized) {\n throw new Error('finalizeAsync() has already been called');\n }\n\n if (this._linkCreationMode === 'default') {\n this._terminal.writeLine('Creating symlinks');\n const linksToCopy: ILinkInfo[] = this._symlinkAnalyzer.reportSymlinks();\n await Async.forEachAsync(linksToCopy, async (linkToCopy: ILinkInfo) => {\n await this._extractSymlinkAsync(linkToCopy);\n });\n }\n\n await onAfterExtractSymlinksAsync?.();\n\n if (this._archiveManager && this._archiveFilePath) {\n this._terminal.writeLine(`Creating archive at \"${this._archiveFilePath}\"`);\n await this._archiveManager.createArchiveAsync(this._archiveFilePath);\n }\n\n this._isFinalized = true;\n }\n\n /**\n * Create a symlink as described by the ILinkInfo object.\n */\n private async _extractSymlinkAsync(linkInfo: ILinkInfo): Promise<void> {\n const { kind, linkPath, targetPath } = {\n ...linkInfo,\n linkPath: remapSourcePathForTargetFolder({\n sourceRootFolder: this._sourceRootFolder,\n targetRootFolder: this._targetRootFolder,\n sourcePath: linkInfo.linkPath\n }),\n targetPath: remapSourcePathForTargetFolder({\n sourceRootFolder: this._sourceRootFolder,\n targetRootFolder: this._targetRootFolder,\n sourcePath: linkInfo.targetPath\n })\n };\n\n const newLinkFolder: string = path.dirname(linkPath);\n await FileSystem.ensureFolderAsync(newLinkFolder);\n\n // Link to the relative path for symlinks\n const relativeTargetPath: string = path.relative(newLinkFolder, targetPath);\n\n // NOTE: This logic is based on NpmLinkManager._createSymlink()\n if (kind === 'fileLink') {\n // For files, we use a Windows \"hard link\", because creating a symbolic link requires\n // administrator permission. However hard links seem to cause build failures on Mac,\n // so for all other operating systems we use symbolic links for this case.\n if (process.platform === 'win32') {\n await FileSystem.createHardLinkAsync({\n linkTargetPath: relativeTargetPath,\n newLinkPath: linkPath\n });\n } else {\n await FileSystem.createSymbolicLinkFileAsync({\n linkTargetPath: relativeTargetPath,\n newLinkPath: linkPath\n });\n }\n } else {\n // Junctions are only supported on Windows. This will create a symbolic link on other platforms.\n await FileSystem.createSymbolicLinkJunctionAsync({\n linkTargetPath: relativeTargetPath,\n newLinkPath: linkPath\n });\n }\n\n // Since the created symlinks have the required relative paths, they can be added directly to\n // the archive.\n await this.includeAssetAsync({ targetFilePath: linkPath });\n }\n}\n"]}
|