@theia/core 1.77.0-next.1 → 1.77.0-next.6
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/lib/browser/catalog.json +6 -0
- package/lib/node/backend-application-module.d.ts.map +1 -1
- package/lib/node/backend-application-module.js +3 -0
- package/lib/node/backend-application-module.js.map +1 -1
- package/lib/node/bundled-resource-provider.d.ts +86 -0
- package/lib/node/bundled-resource-provider.d.ts.map +1 -0
- package/lib/node/bundled-resource-provider.js +241 -0
- package/lib/node/bundled-resource-provider.js.map +1 -0
- package/lib/node/bundled-resource-provider.spec.d.ts +2 -0
- package/lib/node/bundled-resource-provider.spec.d.ts.map +1 -0
- package/lib/node/bundled-resource-provider.spec.js +160 -0
- package/lib/node/bundled-resource-provider.spec.js.map +1 -0
- package/lib/node/index.d.ts +1 -0
- package/lib/node/index.d.ts.map +1 -1
- package/lib/node/index.js +3 -1
- package/lib/node/index.js.map +1 -1
- package/package.json +4 -4
- package/src/node/backend-application-module.ts +4 -0
- package/src/node/bundled-resource-provider.spec.ts +196 -0
- package/src/node/bundled-resource-provider.ts +266 -0
- package/src/node/index.ts +1 -0
package/lib/browser/catalog.json
CHANGED
|
@@ -1477,6 +1477,12 @@
|
|
|
1477
1477
|
"fileMatch": [],
|
|
1478
1478
|
"url": "https://raw.githubusercontent.com/SchemaStore/schemastore/master/src/schemas/json/partial-scheduled.json"
|
|
1479
1479
|
},
|
|
1480
|
+
{
|
|
1481
|
+
"name": "partial-inwards.json",
|
|
1482
|
+
"description": "Inwards architecture linter configuration for pyproject.toml",
|
|
1483
|
+
"fileMatch": [],
|
|
1484
|
+
"url": "https://raw.githubusercontent.com/SchemaStore/schemastore/master/src/schemas/json/partial-inwards.json"
|
|
1485
|
+
},
|
|
1480
1486
|
{
|
|
1481
1487
|
"name": "bozr.suite.json",
|
|
1482
1488
|
"description": "Bozr test suite file",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"backend-application-module.d.ts","sourceRoot":"","sources":["../../src/node/backend-application-module.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,eAAe,EAAwB,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"backend-application-module.d.ts","sourceRoot":"","sources":["../../src/node/backend-application-module.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,eAAe,EAAwB,MAAM,WAAW,CAAC;AAiElE,eAAO,MAAM,wBAAwB,iBAwGnC,CAAC"}
|
|
@@ -40,6 +40,7 @@ const performance_1 = require("./performance");
|
|
|
40
40
|
const os_backend_provider_1 = require("./os-backend-provider");
|
|
41
41
|
const backend_request_facade_1 = require("./request/backend-request-facade");
|
|
42
42
|
const filesystem_locking_1 = require("./filesystem-locking");
|
|
43
|
+
const bundled_resource_provider_1 = require("./bundled-resource-provider");
|
|
43
44
|
const backend_remote_service_1 = require("./remote/backend-remote-service");
|
|
44
45
|
const remote_cli_contribution_1 = require("./remote/remote-cli-contribution");
|
|
45
46
|
const setting_service_1 = require("./setting-service");
|
|
@@ -115,6 +116,8 @@ exports.backendApplicationModule = new inversify_1.ContainerModule(bind => {
|
|
|
115
116
|
(0, performance_1.bindNodeStopwatch)(bind);
|
|
116
117
|
(0, performance_1.bindBackendStopwatchServer)(bind);
|
|
117
118
|
bind(filesystem_locking_1.FileSystemLocking).to(filesystem_locking_1.FileSystemLockingImpl).inSingletonScope();
|
|
119
|
+
bind(bundled_resource_provider_1.BundledResourceProviderImpl).toSelf().inSingletonScope();
|
|
120
|
+
bind(bundled_resource_provider_1.BundledResourceProvider).toService(bundled_resource_provider_1.BundledResourceProviderImpl);
|
|
118
121
|
bind(setting_service_1.SettingServiceImpl).toSelf().inSingletonScope();
|
|
119
122
|
bind(setting_service_1.SettingService).toService(setting_service_1.SettingServiceImpl);
|
|
120
123
|
(0, common_1.bindPreferenceConfigurations)(bind);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"backend-application-module.js","sourceRoot":"","sources":["../../src/node/backend-application-module.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"backend-application-module.js","sourceRoot":"","sources":["../../src/node/backend-application-module.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import { interfaces } from 'inversify';
|
|
3
|
+
import { EnvVariablesServer } from '../common/env-variables';
|
|
4
|
+
import { ILogger } from '../common/logger';
|
|
5
|
+
import { FileSystemLocking } from './filesystem-locking';
|
|
6
|
+
export declare const BundledResourceProvider: symbol & interfaces.Abstract<BundledResourceProvider>;
|
|
7
|
+
/**
|
|
8
|
+
* Provides paths to resources that are bundled with the application, in a form that can also be used by
|
|
9
|
+
* processes which do not run inside the application, such as shells, debug adapters or other external tools.
|
|
10
|
+
*
|
|
11
|
+
* When an Electron application is packaged with `asar: true`, the resources of the application are stored in
|
|
12
|
+
* an `app.asar` archive. Paths pointing into such an archive can only be read through Electron's patched `fs`
|
|
13
|
+
* module, so handing them to an external process fails. Therefore, always resolve a bundled resource through
|
|
14
|
+
* this service before passing its path to a process outside of the application.
|
|
15
|
+
*/
|
|
16
|
+
export interface BundledResourceProvider {
|
|
17
|
+
/**
|
|
18
|
+
* Resolve the given path of a bundled file or directory to a path that external processes can read.
|
|
19
|
+
*
|
|
20
|
+
* If the resource is not packaged into an archive, its path is returned unchanged. Otherwise the copy that
|
|
21
|
+
* the packaging step has left outside of the archive is used, if it is complete, and the resource is
|
|
22
|
+
* extracted from the archive into the configuration directory as a last resort.
|
|
23
|
+
*
|
|
24
|
+
* Results are cached, so that a resource is extracted at most once per application version.
|
|
25
|
+
*
|
|
26
|
+
* @param resourcePath the path of the bundled resource, typically resolved against `__dirname`.
|
|
27
|
+
* @returns the path to use outside of the application.
|
|
28
|
+
* @throws if the resource does not exist or cannot be made available.
|
|
29
|
+
*/
|
|
30
|
+
resolveExternalPath(resourcePath: string): Promise<string>;
|
|
31
|
+
}
|
|
32
|
+
export declare class BundledResourceProviderImpl implements BundledResourceProvider {
|
|
33
|
+
protected readonly logger: ILogger;
|
|
34
|
+
protected readonly envVariablesServer: EnvVariablesServer;
|
|
35
|
+
protected readonly fileSystemLocking: FileSystemLocking;
|
|
36
|
+
/** The folder within the configuration directory into which resources are extracted. */
|
|
37
|
+
protected readonly extractionFolder = "bundled-resources";
|
|
38
|
+
/** Resources extracted for another application version are removed when they are older than this. */
|
|
39
|
+
protected readonly staleExtractionAge: number;
|
|
40
|
+
protected readonly resolved: Map<string, Promise<string>>;
|
|
41
|
+
protected temporaryExtractionPath: Promise<string> | undefined;
|
|
42
|
+
resolveExternalPath(resourcePath: string): Promise<string>;
|
|
43
|
+
protected doResolveExternalPath(resourcePath: string): Promise<string>;
|
|
44
|
+
/**
|
|
45
|
+
* Find the archive that the given resource is packaged into, if any.
|
|
46
|
+
*
|
|
47
|
+
* @returns the path of the archive, i.e. the shortest prefix of the given path ending in an `.asar` segment,
|
|
48
|
+
* which is also how Electron itself determines the archive that a path refers to.
|
|
49
|
+
*/
|
|
50
|
+
protected findArchivePath(resourcePath: string): string | undefined;
|
|
51
|
+
/**
|
|
52
|
+
* Whether every file of the given resource is already available at the given target path. Packaging tools
|
|
53
|
+
* only unpack the files that the application configured them to unpack, so a partial copy must be ignored.
|
|
54
|
+
*/
|
|
55
|
+
protected isExtracted(resourcePath: string, targetPath: string): Promise<boolean>;
|
|
56
|
+
protected extract(resourcePath: string, targetPath: string): Promise<void>;
|
|
57
|
+
/**
|
|
58
|
+
* Collect the files of the given resource as paths relative to it. The relative path of a resource that is
|
|
59
|
+
* a plain file is the empty string.
|
|
60
|
+
*/
|
|
61
|
+
protected collectFiles(resourcePath: string, relativePath?: string): Promise<string[]>;
|
|
62
|
+
protected copyFile(sourcePath: string, targetPath: string): Promise<void>;
|
|
63
|
+
protected isUpToDate(targetPath: string, sourceStat: fs.Stats): Promise<boolean>;
|
|
64
|
+
/**
|
|
65
|
+
* The directory into which resources of the given archive are extracted. It is specific to the content of
|
|
66
|
+
* the archive, so that updating the application invalidates previously extracted copies.
|
|
67
|
+
*/
|
|
68
|
+
protected getExtractionPath(archivePath: string): Promise<string>;
|
|
69
|
+
/**
|
|
70
|
+
* Fallback for applications whose configuration directory cannot be written to. The directory is unique to
|
|
71
|
+
* this run of the application, so that resources are extracted again whenever the application is started.
|
|
72
|
+
*/
|
|
73
|
+
protected getTemporaryExtractionPath(): Promise<string>;
|
|
74
|
+
/**
|
|
75
|
+
* Identify the content of the given archive. `process.noAsar` is toggled around the synchronous `stat` call
|
|
76
|
+
* to get the stats of the archive file itself rather than of the directory that it appears as.
|
|
77
|
+
*/
|
|
78
|
+
protected getArchiveStamp(archivePath: string): string;
|
|
79
|
+
/**
|
|
80
|
+
* Remove resources that were extracted from an earlier version of the archive, unless they were used
|
|
81
|
+
* recently, because another application instance may still be running on that version.
|
|
82
|
+
*/
|
|
83
|
+
protected removeStaleExtractions(extractionRoot: string, prefix: string, currentPath: string): void;
|
|
84
|
+
protected exists(targetPath: string): Promise<boolean>;
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=bundled-resource-provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bundled-resource-provider.d.ts","sourceRoot":"","sources":["../../src/node/bundled-resource-provider.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AAGzB,OAAO,EAAsB,UAAU,EAAS,MAAM,WAAW,CAAC;AAClE,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAE7D,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAEzD,eAAO,MAAM,uBAAuB,EAAwC,MAAM,GAAG,UAAU,CAAC,QAAQ,CAAC,uBAAuB,CAAC,CAAC;AAClI;;;;;;;;GAQG;AACH,MAAM,WAAW,uBAAuB;IACpC;;;;;;;;;;;;OAYG;IACH,mBAAmB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAC9D;AAED,qBACa,2BAA4B,YAAW,uBAAuB;IAGvE,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IAGnC,SAAS,CAAC,QAAQ,CAAC,kBAAkB,EAAE,kBAAkB,CAAC;IAG1D,SAAS,CAAC,QAAQ,CAAC,iBAAiB,EAAE,iBAAiB,CAAC;IAExD,wFAAwF;IACxF,SAAS,CAAC,QAAQ,CAAC,gBAAgB,uBAAuB;IAE1D,qGAAqG;IACrG,SAAS,CAAC,QAAQ,CAAC,kBAAkB,SAA2B;IAEhE,SAAS,CAAC,QAAQ,CAAC,QAAQ,+BAAsC;IACjE,SAAS,CAAC,uBAAuB,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC;IAEzD,mBAAmB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;cAmBhD,qBAAqB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAoB5E;;;;;OAKG;IACH,SAAS,CAAC,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAMnE;;;OAGG;cACa,WAAW,CAAC,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;cASvE,OAAO,CAAC,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMhF;;;OAGG;cACa,YAAY,CAAC,YAAY,EAAE,MAAM,EAAE,YAAY,GAAE,MAAW,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;cAYhF,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;cAyB/D,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,CAAC,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC;IAQtF;;;OAGG;cACa,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAcvE;;;OAGG;IACH,SAAS,CAAC,0BAA0B,IAAI,OAAO,CAAC,MAAM,CAAC;IAIvD;;;OAGG;IACH,SAAS,CAAC,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM;IAYtD;;;OAGG;IACH,SAAS,CAAC,sBAAsB,CAAC,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI;cAiBnF,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAS/D"}
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// *****************************************************************************
|
|
3
|
+
// Copyright (C) 2026 EclipseSource GmbH and others.
|
|
4
|
+
//
|
|
5
|
+
// This program and the accompanying materials are made available under the
|
|
6
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
7
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
8
|
+
//
|
|
9
|
+
// This Source Code may also be made available under the following Secondary
|
|
10
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
11
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
12
|
+
// with the GNU Classpath Exception which is available at
|
|
13
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
14
|
+
//
|
|
15
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
16
|
+
// *****************************************************************************
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.BundledResourceProviderImpl = exports.BundledResourceProvider = void 0;
|
|
19
|
+
const tslib_1 = require("tslib");
|
|
20
|
+
const crypto = require("crypto");
|
|
21
|
+
const fs = require("fs");
|
|
22
|
+
const os = require("os");
|
|
23
|
+
const path = require("path");
|
|
24
|
+
const inversify_1 = require("inversify");
|
|
25
|
+
const env_variables_1 = require("../common/env-variables");
|
|
26
|
+
const file_uri_1 = require("../common/file-uri");
|
|
27
|
+
const logger_1 = require("../common/logger");
|
|
28
|
+
const filesystem_locking_1 = require("./filesystem-locking");
|
|
29
|
+
exports.BundledResourceProvider = Symbol('BundledResourceProvider');
|
|
30
|
+
let BundledResourceProviderImpl = class BundledResourceProviderImpl {
|
|
31
|
+
constructor() {
|
|
32
|
+
/** The folder within the configuration directory into which resources are extracted. */
|
|
33
|
+
this.extractionFolder = 'bundled-resources';
|
|
34
|
+
/** Resources extracted for another application version are removed when they are older than this. */
|
|
35
|
+
this.staleExtractionAge = 7 * 24 * 60 * 60 * 1000;
|
|
36
|
+
this.resolved = new Map();
|
|
37
|
+
}
|
|
38
|
+
async resolveExternalPath(resourcePath) {
|
|
39
|
+
const normalizedPath = path.resolve(resourcePath);
|
|
40
|
+
const pending = this.resolved.get(normalizedPath);
|
|
41
|
+
if (pending) {
|
|
42
|
+
try {
|
|
43
|
+
const resolvedPath = await pending;
|
|
44
|
+
if (await this.exists(resolvedPath)) {
|
|
45
|
+
return resolvedPath;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
// the previous attempt failed, so try again below
|
|
50
|
+
}
|
|
51
|
+
this.resolved.delete(normalizedPath);
|
|
52
|
+
}
|
|
53
|
+
const result = this.doResolveExternalPath(normalizedPath);
|
|
54
|
+
this.resolved.set(normalizedPath, result);
|
|
55
|
+
return result;
|
|
56
|
+
}
|
|
57
|
+
async doResolveExternalPath(resourcePath) {
|
|
58
|
+
if (!await this.exists(resourcePath)) {
|
|
59
|
+
throw new Error(`Bundled resource does not exist: ${resourcePath}`);
|
|
60
|
+
}
|
|
61
|
+
const archivePath = this.findArchivePath(resourcePath);
|
|
62
|
+
if (!archivePath) {
|
|
63
|
+
// The resource is not packaged into an archive, so external processes can read it directly.
|
|
64
|
+
return resourcePath;
|
|
65
|
+
}
|
|
66
|
+
const relativePath = path.relative(archivePath, resourcePath);
|
|
67
|
+
const unpackedPath = path.join(`${archivePath}.unpacked`, relativePath);
|
|
68
|
+
if (await this.isExtracted(resourcePath, unpackedPath)) {
|
|
69
|
+
return unpackedPath;
|
|
70
|
+
}
|
|
71
|
+
const extractionPath = path.join(await this.getExtractionPath(archivePath), relativePath);
|
|
72
|
+
await this.fileSystemLocking.lockPath(archivePath, () => this.extract(resourcePath, extractionPath));
|
|
73
|
+
this.logger.info(`Extracted bundled resource '${resourcePath}' to '${extractionPath}'.`);
|
|
74
|
+
return extractionPath;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Find the archive that the given resource is packaged into, if any.
|
|
78
|
+
*
|
|
79
|
+
* @returns the path of the archive, i.e. the shortest prefix of the given path ending in an `.asar` segment,
|
|
80
|
+
* which is also how Electron itself determines the archive that a path refers to.
|
|
81
|
+
*/
|
|
82
|
+
findArchivePath(resourcePath) {
|
|
83
|
+
const segments = resourcePath.split(/[\\/]/);
|
|
84
|
+
const archiveIndex = segments.findIndex(segment => segment.toLowerCase().endsWith('.asar'));
|
|
85
|
+
return archiveIndex < 0 ? undefined : segments.slice(0, archiveIndex + 1).join(path.sep);
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Whether every file of the given resource is already available at the given target path. Packaging tools
|
|
89
|
+
* only unpack the files that the application configured them to unpack, so a partial copy must be ignored.
|
|
90
|
+
*/
|
|
91
|
+
async isExtracted(resourcePath, targetPath) {
|
|
92
|
+
for (const file of await this.collectFiles(resourcePath)) {
|
|
93
|
+
if (!await this.exists(path.join(targetPath, file))) {
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
async extract(resourcePath, targetPath) {
|
|
100
|
+
for (const file of await this.collectFiles(resourcePath)) {
|
|
101
|
+
await this.copyFile(path.join(resourcePath, file), path.join(targetPath, file));
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Collect the files of the given resource as paths relative to it. The relative path of a resource that is
|
|
106
|
+
* a plain file is the empty string.
|
|
107
|
+
*/
|
|
108
|
+
async collectFiles(resourcePath, relativePath = '') {
|
|
109
|
+
const currentPath = path.join(resourcePath, relativePath);
|
|
110
|
+
if (!(await fs.promises.stat(currentPath)).isDirectory()) {
|
|
111
|
+
return [relativePath];
|
|
112
|
+
}
|
|
113
|
+
const files = [];
|
|
114
|
+
for (const entry of await fs.promises.readdir(currentPath)) {
|
|
115
|
+
files.push(...await this.collectFiles(resourcePath, path.join(relativePath, entry)));
|
|
116
|
+
}
|
|
117
|
+
return files;
|
|
118
|
+
}
|
|
119
|
+
async copyFile(sourcePath, targetPath) {
|
|
120
|
+
const sourceStat = await fs.promises.stat(sourcePath);
|
|
121
|
+
if (await this.isUpToDate(targetPath, sourceStat)) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
await fs.promises.mkdir(path.dirname(targetPath), { recursive: true, mode: 0o700 });
|
|
125
|
+
// Write to a temporary file and move it into place, so that a concurrently starting application
|
|
126
|
+
// instance never reads partially written content.
|
|
127
|
+
const temporaryPath = `${targetPath}.${process.pid}.tmp`;
|
|
128
|
+
try {
|
|
129
|
+
// Electron reports the files of an asar archive as not executable, even those that the archive marks as
|
|
130
|
+
// executable, so every extracted file is made executable for the owner to keep bundled executables usable.
|
|
131
|
+
await fs.promises.writeFile(temporaryPath, await fs.promises.readFile(sourcePath), { mode: sourceStat.mode & 0o777 | 0o700 });
|
|
132
|
+
try {
|
|
133
|
+
await fs.promises.rename(temporaryPath, targetPath);
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
// renaming onto an existing file is not supported on all platforms
|
|
137
|
+
await fs.promises.rm(targetPath, { force: true });
|
|
138
|
+
await fs.promises.rename(temporaryPath, targetPath);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
finally {
|
|
142
|
+
await fs.promises.rm(temporaryPath, { force: true });
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
async isUpToDate(targetPath, sourceStat) {
|
|
146
|
+
try {
|
|
147
|
+
return (await fs.promises.stat(targetPath)).size === sourceStat.size;
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* The directory into which resources of the given archive are extracted. It is specific to the content of
|
|
155
|
+
* the archive, so that updating the application invalidates previously extracted copies.
|
|
156
|
+
*/
|
|
157
|
+
async getExtractionPath(archivePath) {
|
|
158
|
+
const archiveName = path.basename(archivePath, path.extname(archivePath));
|
|
159
|
+
try {
|
|
160
|
+
const extractionRoot = path.join(file_uri_1.FileUri.fsPath(await this.envVariablesServer.getConfigDirUri()), this.extractionFolder);
|
|
161
|
+
const extractionPath = path.join(extractionRoot, `${archiveName}-${this.getArchiveStamp(archivePath)}`);
|
|
162
|
+
await fs.promises.mkdir(extractionPath, { recursive: true, mode: 0o700 });
|
|
163
|
+
this.removeStaleExtractions(extractionRoot, `${archiveName}-`, extractionPath);
|
|
164
|
+
return extractionPath;
|
|
165
|
+
}
|
|
166
|
+
catch (error) {
|
|
167
|
+
this.logger.warn('Could not extract bundled resources into the configuration directory, using a temporary directory instead.', error);
|
|
168
|
+
return this.getTemporaryExtractionPath();
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Fallback for applications whose configuration directory cannot be written to. The directory is unique to
|
|
173
|
+
* this run of the application, so that resources are extracted again whenever the application is started.
|
|
174
|
+
*/
|
|
175
|
+
getTemporaryExtractionPath() {
|
|
176
|
+
return this.temporaryExtractionPath ??= fs.promises.mkdtemp(path.join(os.tmpdir(), 'theia-bundled-resources-'));
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Identify the content of the given archive. `process.noAsar` is toggled around the synchronous `stat` call
|
|
180
|
+
* to get the stats of the archive file itself rather than of the directory that it appears as.
|
|
181
|
+
*/
|
|
182
|
+
getArchiveStamp(archivePath) {
|
|
183
|
+
const asarProcess = process;
|
|
184
|
+
const noAsar = asarProcess.noAsar;
|
|
185
|
+
try {
|
|
186
|
+
asarProcess.noAsar = true;
|
|
187
|
+
const stat = fs.statSync(archivePath);
|
|
188
|
+
return crypto.createHash('sha256').update(`${archivePath}:${stat.size}:${stat.mtimeMs}`).digest('hex').substring(0, 12);
|
|
189
|
+
}
|
|
190
|
+
finally {
|
|
191
|
+
asarProcess.noAsar = noAsar;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Remove resources that were extracted from an earlier version of the archive, unless they were used
|
|
196
|
+
* recently, because another application instance may still be running on that version.
|
|
197
|
+
*/
|
|
198
|
+
removeStaleExtractions(extractionRoot, prefix, currentPath) {
|
|
199
|
+
const removeStale = async () => {
|
|
200
|
+
for (const entry of await fs.promises.readdir(extractionRoot)) {
|
|
201
|
+
const entryPath = path.join(extractionRoot, entry);
|
|
202
|
+
if (!entry.startsWith(prefix) || entryPath === currentPath) {
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
const stat = await fs.promises.stat(entryPath);
|
|
206
|
+
if (Date.now() - stat.mtimeMs > this.staleExtractionAge) {
|
|
207
|
+
await fs.promises.rm(entryPath, { recursive: true, force: true });
|
|
208
|
+
this.logger.info(`Removed stale extracted resources: ${entryPath}`);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
removeStale().catch(error => this.logger.warn(`Could not remove stale extracted resources in '${extractionRoot}'.`, error));
|
|
213
|
+
}
|
|
214
|
+
async exists(targetPath) {
|
|
215
|
+
try {
|
|
216
|
+
await fs.promises.stat(targetPath);
|
|
217
|
+
return true;
|
|
218
|
+
}
|
|
219
|
+
catch {
|
|
220
|
+
return false;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
exports.BundledResourceProviderImpl = BundledResourceProviderImpl;
|
|
225
|
+
tslib_1.__decorate([
|
|
226
|
+
(0, inversify_1.inject)(logger_1.ILogger),
|
|
227
|
+
(0, inversify_1.named)('core:BundledResourceProviderImpl'),
|
|
228
|
+
tslib_1.__metadata("design:type", Object)
|
|
229
|
+
], BundledResourceProviderImpl.prototype, "logger", void 0);
|
|
230
|
+
tslib_1.__decorate([
|
|
231
|
+
(0, inversify_1.inject)(env_variables_1.EnvVariablesServer),
|
|
232
|
+
tslib_1.__metadata("design:type", Object)
|
|
233
|
+
], BundledResourceProviderImpl.prototype, "envVariablesServer", void 0);
|
|
234
|
+
tslib_1.__decorate([
|
|
235
|
+
(0, inversify_1.inject)(filesystem_locking_1.FileSystemLocking),
|
|
236
|
+
tslib_1.__metadata("design:type", Object)
|
|
237
|
+
], BundledResourceProviderImpl.prototype, "fileSystemLocking", void 0);
|
|
238
|
+
exports.BundledResourceProviderImpl = BundledResourceProviderImpl = tslib_1.__decorate([
|
|
239
|
+
(0, inversify_1.injectable)()
|
|
240
|
+
], BundledResourceProviderImpl);
|
|
241
|
+
//# sourceMappingURL=bundled-resource-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bundled-resource-provider.js","sourceRoot":"","sources":["../../src/node/bundled-resource-provider.ts"],"names":[],"mappings":";AAAA,gFAAgF;AAChF,oDAAoD;AACpD,EAAE;AACF,2EAA2E;AAC3E,mEAAmE;AACnE,wCAAwC;AACxC,EAAE;AACF,4EAA4E;AAC5E,8EAA8E;AAC9E,6EAA6E;AAC7E,yDAAyD;AACzD,uDAAuD;AACvD,EAAE;AACF,gFAAgF;AAChF,gFAAgF;;;;AAEhF,iCAAiC;AACjC,yBAAyB;AACzB,yBAAyB;AACzB,6BAA6B;AAC7B,yCAAkE;AAClE,2DAA6D;AAC7D,iDAA6C;AAC7C,6CAA2C;AAC3C,6DAAyD;AAE5C,QAAA,uBAAuB,GAAG,MAAM,CAAC,yBAAyB,CAA0D,CAAC;AA4B3H,IAAM,2BAA2B,GAAjC,MAAM,2BAA2B;IAAjC;QAWH,wFAAwF;QACrE,qBAAgB,GAAG,mBAAmB,CAAC;QAE1D,qGAAqG;QAClF,uBAAkB,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;QAE7C,aAAQ,GAAG,IAAI,GAAG,EAA2B,CAAC;IAkMrE,CAAC;IA/LG,KAAK,CAAC,mBAAmB,CAAC,YAAoB;QAC1C,MAAM,cAAc,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;QAClD,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;QAClD,IAAI,OAAO,EAAE,CAAC;YACV,IAAI,CAAC;gBACD,MAAM,YAAY,GAAG,MAAM,OAAO,CAAC;gBACnC,IAAI,MAAM,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC;oBAClC,OAAO,YAAY,CAAC;gBACxB,CAAC;YACL,CAAC;YAAC,MAAM,CAAC;gBACL,kDAAkD;YACtD,CAAC;YACD,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;QACzC,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,CAAC,qBAAqB,CAAC,cAAc,CAAC,CAAC;QAC1D,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC;QAC1C,OAAO,MAAM,CAAC;IAClB,CAAC;IAES,KAAK,CAAC,qBAAqB,CAAC,YAAoB;QACtD,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC;YACnC,MAAM,IAAI,KAAK,CAAC,oCAAoC,YAAY,EAAE,CAAC,CAAC;QACxE,CAAC;QACD,MAAM,WAAW,GAAG,IAAI,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC;QACvD,IAAI,CAAC,WAAW,EAAE,CAAC;YACf,4FAA4F;YAC5F,OAAO,YAAY,CAAC;QACxB,CAAC;QACD,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC;QAC9D,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,WAAW,WAAW,EAAE,YAAY,CAAC,CAAC;QACxE,IAAI,MAAM,IAAI,CAAC,WAAW,CAAC,YAAY,EAAE,YAAY,CAAC,EAAE,CAAC;YACrD,OAAO,YAAY,CAAC;QACxB,CAAC;QACD,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,iBAAiB,CAAC,WAAW,CAAC,EAAE,YAAY,CAAC,CAAC;QAC1F,MAAM,IAAI,CAAC,iBAAiB,CAAC,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,cAAc,CAAC,CAAC,CAAC;QACrG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,+BAA+B,YAAY,SAAS,cAAc,IAAI,CAAC,CAAC;QACzF,OAAO,cAAc,CAAC;IAC1B,CAAC;IAED;;;;;OAKG;IACO,eAAe,CAAC,YAAoB;QAC1C,MAAM,QAAQ,GAAG,YAAY,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC7C,MAAM,YAAY,GAAG,QAAQ,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;QAC5F,OAAO,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,YAAY,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC7F,CAAC;IAED;;;OAGG;IACO,KAAK,CAAC,WAAW,CAAC,YAAoB,EAAE,UAAkB;QAChE,KAAK,MAAM,IAAI,IAAI,MAAM,IAAI,CAAC,YAAY,CAAC,YAAY,CAAC,EAAE,CAAC;YACvD,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC;gBAClD,OAAO,KAAK,CAAC;YACjB,CAAC;QACL,CAAC;QACD,OAAO,IAAI,CAAC;IAChB,CAAC;IAES,KAAK,CAAC,OAAO,CAAC,YAAoB,EAAE,UAAkB;QAC5D,KAAK,MAAM,IAAI,IAAI,MAAM,IAAI,CAAC,YAAY,CAAC,YAAY,CAAC,EAAE,CAAC;YACvD,MAAM,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,CAAC;QACpF,CAAC;IACL,CAAC;IAED;;;OAGG;IACO,KAAK,CAAC,YAAY,CAAC,YAAoB,EAAE,eAAuB,EAAE;QACxE,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC;QAC1D,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;YACvD,OAAO,CAAC,YAAY,CAAC,CAAC;QAC1B,CAAC;QACD,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;YACzD,KAAK,CAAC,IAAI,CAAC,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,YAAY,EAAE,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;QACzF,CAAC;QACD,OAAO,KAAK,CAAC;IACjB,CAAC;IAES,KAAK,CAAC,QAAQ,CAAC,UAAkB,EAAE,UAAkB;QAC3D,MAAM,UAAU,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACtD,IAAI,MAAM,IAAI,CAAC,UAAU,CAAC,UAAU,EAAE,UAAU,CAAC,EAAE,CAAC;YAChD,OAAO;QACX,CAAC;QACD,MAAM,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QACpF,gGAAgG;QAChG,kDAAkD;QAClD,MAAM,aAAa,GAAG,GAAG,UAAU,IAAI,OAAO,CAAC,GAAG,MAAM,CAAC;QACzD,IAAI,CAAC;YACD,wGAAwG;YACxG,2GAA2G;YAC3G,MAAM,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,aAAa,EAAE,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,EAAE,IAAI,EAAE,UAAU,CAAC,IAAI,GAAG,KAAK,GAAG,KAAK,EAAE,CAAC,CAAC;YAC9H,IAAI,CAAC;gBACD,MAAM,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,aAAa,EAAE,UAAU,CAAC,CAAC;YACxD,CAAC;YAAC,MAAM,CAAC;gBACL,mEAAmE;gBACnE,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,UAAU,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;gBAClD,MAAM,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,aAAa,EAAE,UAAU,CAAC,CAAC;YACxD,CAAC;QACL,CAAC;gBAAS,CAAC;YACP,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,aAAa,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACzD,CAAC;IACL,CAAC;IAES,KAAK,CAAC,UAAU,CAAC,UAAkB,EAAE,UAAoB;QAC/D,IAAI,CAAC;YACD,OAAO,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,KAAK,UAAU,CAAC,IAAI,CAAC;QACzE,CAAC;QAAC,MAAM,CAAC;YACL,OAAO,KAAK,CAAC;QACjB,CAAC;IACL,CAAC;IAED;;;OAGG;IACO,KAAK,CAAC,iBAAiB,CAAC,WAAmB;QACjD,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC;QAC1E,IAAI,CAAC;YACD,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,kBAAO,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,kBAAkB,CAAC,eAAe,EAAE,CAAC,EAAE,IAAI,CAAC,gBAAgB,CAAC,CAAC;YACzH,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,GAAG,WAAW,IAAI,IAAI,CAAC,eAAe,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;YACxG,MAAM,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;YAC1E,IAAI,CAAC,sBAAsB,CAAC,cAAc,EAAE,GAAG,WAAW,GAAG,EAAE,cAAc,CAAC,CAAC;YAC/E,OAAO,cAAc,CAAC;QAC1B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,4GAA4G,EAAE,KAAK,CAAC,CAAC;YACtI,OAAO,IAAI,CAAC,0BAA0B,EAAE,CAAC;QAC7C,CAAC;IACL,CAAC;IAED;;;OAGG;IACO,0BAA0B;QAChC,OAAO,IAAI,CAAC,uBAAuB,KAAK,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,0BAA0B,CAAC,CAAC,CAAC;IACpH,CAAC;IAED;;;OAGG;IACO,eAAe,CAAC,WAAmB;QACzC,MAAM,WAAW,GAAG,OAAgD,CAAC;QACrE,MAAM,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC;QAClC,IAAI,CAAC;YACD,WAAW,CAAC,MAAM,GAAG,IAAI,CAAC;YAC1B,MAAM,IAAI,GAAG,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;YACtC,OAAO,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,GAAG,WAAW,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC5H,CAAC;gBAAS,CAAC;YACP,WAAW,CAAC,MAAM,GAAG,MAAM,CAAC;QAChC,CAAC;IACL,CAAC;IAED;;;OAGG;IACO,sBAAsB,CAAC,cAAsB,EAAE,MAAc,EAAE,WAAmB;QACxF,MAAM,WAAW,GAAG,KAAK,IAAI,EAAE;YAC3B,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,CAAC;gBAC5D,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;gBACnD,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,SAAS,KAAK,WAAW,EAAE,CAAC;oBACzD,SAAS;gBACb,CAAC;gBACD,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;gBAC/C,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,kBAAkB,EAAE,CAAC;oBACtD,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;oBAClE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,sCAAsC,SAAS,EAAE,CAAC,CAAC;gBACxE,CAAC;YACL,CAAC;QACL,CAAC,CAAC;QACF,WAAW,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,kDAAkD,cAAc,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;IAChI,CAAC;IAES,KAAK,CAAC,MAAM,CAAC,UAAkB;QACrC,IAAI,CAAC;YACD,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YACnC,OAAO,IAAI,CAAC;QAChB,CAAC;QAAC,MAAM,CAAC;YACL,OAAO,KAAK,CAAC;QACjB,CAAC;IACL,CAAC;CAEJ,CAAA;AAnNY,kEAA2B;AAGjB;IADlB,IAAA,kBAAM,EAAC,gBAAO,CAAC;IAAE,IAAA,iBAAK,EAAC,kCAAkC,CAAC;;2DACxB;AAGhB;IADlB,IAAA,kBAAM,EAAC,kCAAkB,CAAC;;uEAC+B;AAGvC;IADlB,IAAA,kBAAM,EAAC,sCAAiB,CAAC;;sEAC8B;sCAT/C,2BAA2B;IADvC,IAAA,sBAAU,GAAE;GACA,2BAA2B,CAmNvC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bundled-resource-provider.spec.d.ts","sourceRoot":"","sources":["../../src/node/bundled-resource-provider.spec.ts"],"names":[],"mappings":"AAgBA,OAAO,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// *****************************************************************************
|
|
3
|
+
// Copyright (C) 2026 EclipseSource GmbH and others.
|
|
4
|
+
//
|
|
5
|
+
// This program and the accompanying materials are made available under the
|
|
6
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
7
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
8
|
+
//
|
|
9
|
+
// This Source Code may also be made available under the following Secondary
|
|
10
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
11
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
12
|
+
// with the GNU Classpath Exception which is available at
|
|
13
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
14
|
+
//
|
|
15
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
16
|
+
// *****************************************************************************
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
require("reflect-metadata");
|
|
19
|
+
const chai_1 = require("chai");
|
|
20
|
+
const fs = require("fs");
|
|
21
|
+
const os = require("os");
|
|
22
|
+
const path = require("path");
|
|
23
|
+
const temp = require("temp");
|
|
24
|
+
const inversify_1 = require("inversify");
|
|
25
|
+
const env_variables_1 = require("../common/env-variables");
|
|
26
|
+
const logger_1 = require("../common/logger");
|
|
27
|
+
const mock_logger_1 = require("../common/test/mock-logger");
|
|
28
|
+
const file_uri_1 = require("../common/file-uri");
|
|
29
|
+
const bundled_resource_provider_1 = require("./bundled-resource-provider");
|
|
30
|
+
const filesystem_locking_1 = require("./filesystem-locking");
|
|
31
|
+
/**
|
|
32
|
+
* The provider recognizes archives by their `.asar` path segment and reads them through `fs`, which Electron
|
|
33
|
+
* patches to transparently read from the archive. Plain directories named `*.asar` therefore behave like
|
|
34
|
+
* archives from the point of view of the provider and let us test it outside of Electron.
|
|
35
|
+
*/
|
|
36
|
+
describe('BundledResourceProvider', () => {
|
|
37
|
+
const track = temp.track();
|
|
38
|
+
let configDir;
|
|
39
|
+
let appDir;
|
|
40
|
+
let provider;
|
|
41
|
+
beforeEach(() => {
|
|
42
|
+
const root = track.mkdirSync();
|
|
43
|
+
configDir = path.join(root, 'config');
|
|
44
|
+
appDir = path.join(root, 'app');
|
|
45
|
+
fs.mkdirSync(configDir);
|
|
46
|
+
fs.mkdirSync(appDir);
|
|
47
|
+
provider = createProvider();
|
|
48
|
+
});
|
|
49
|
+
/** Each provider instance stands for one run of the application, as resolved paths are cached. */
|
|
50
|
+
function createProvider() {
|
|
51
|
+
const container = new inversify_1.Container();
|
|
52
|
+
container.bind(logger_1.ILogger).toConstantValue(new mock_logger_1.MockLogger());
|
|
53
|
+
container.bind(filesystem_locking_1.FileSystemLocking).to(filesystem_locking_1.FileSystemLockingImpl).inSingletonScope();
|
|
54
|
+
container.bind(env_variables_1.EnvVariablesServer).toConstantValue({
|
|
55
|
+
getConfigDirUri: async () => file_uri_1.FileUri.create(configDir).toString()
|
|
56
|
+
});
|
|
57
|
+
container.bind(bundled_resource_provider_1.BundledResourceProviderImpl).toSelf().inSingletonScope();
|
|
58
|
+
container.bind(bundled_resource_provider_1.BundledResourceProvider).toService(bundled_resource_provider_1.BundledResourceProviderImpl);
|
|
59
|
+
return container.get(bundled_resource_provider_1.BundledResourceProvider);
|
|
60
|
+
}
|
|
61
|
+
afterEach(() => track.cleanupSync());
|
|
62
|
+
/**
|
|
63
|
+
* Assert that the given path is nested in the given directory. The provider derives the configuration
|
|
64
|
+
* directory from a URI, which on Windows yields a lower-case drive letter, so the paths cannot simply be
|
|
65
|
+
* compared by prefix. `path.relative` ignores the case of a path on Windows.
|
|
66
|
+
*/
|
|
67
|
+
function expectNestedIn(directoryPath, nestedPath) {
|
|
68
|
+
const relativePath = path.relative(directoryPath, nestedPath);
|
|
69
|
+
(0, chai_1.expect)(relativePath).to.not.be.empty;
|
|
70
|
+
(0, chai_1.expect)(relativePath.split(path.sep)).to.not.contain('..');
|
|
71
|
+
}
|
|
72
|
+
function writeResources(rootPath, files) {
|
|
73
|
+
for (const [relativePath, content] of Object.entries(files)) {
|
|
74
|
+
const filePath = path.join(rootPath, relativePath);
|
|
75
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
76
|
+
fs.writeFileSync(filePath, content);
|
|
77
|
+
}
|
|
78
|
+
return rootPath;
|
|
79
|
+
}
|
|
80
|
+
it('returns the path of a resource that is not packaged into an archive', async () => {
|
|
81
|
+
const resourcePath = path.join(writeResources(appDir, { 'scripts/greet.sh': 'echo hello' }), 'scripts');
|
|
82
|
+
(0, chai_1.expect)(await provider.resolveExternalPath(resourcePath)).to.equal(resourcePath);
|
|
83
|
+
});
|
|
84
|
+
it('rejects for a resource that does not exist', async () => {
|
|
85
|
+
const resourcePath = path.join(appDir, 'scripts');
|
|
86
|
+
await provider.resolveExternalPath(resourcePath).then(() => chai_1.expect.fail('should have been rejected'), error => (0, chai_1.expect)(String(error)).to.contain(resourcePath));
|
|
87
|
+
});
|
|
88
|
+
it('extracts a packaged resource into the configuration directory', async () => {
|
|
89
|
+
const archivePath = path.join(appDir, 'app.asar');
|
|
90
|
+
writeResources(archivePath, { 'scripts/greet.sh': 'echo hello', 'scripts/nested/.hidden': 'secret' });
|
|
91
|
+
const resolvedPath = await provider.resolveExternalPath(path.join(archivePath, 'scripts'));
|
|
92
|
+
(0, chai_1.expect)(resolvedPath).to.not.contain('.asar');
|
|
93
|
+
expectNestedIn(configDir, resolvedPath);
|
|
94
|
+
(0, chai_1.expect)(fs.readFileSync(path.join(resolvedPath, 'greet.sh'), 'utf8')).to.equal('echo hello');
|
|
95
|
+
(0, chai_1.expect)(fs.readFileSync(path.join(resolvedPath, 'nested', '.hidden'), 'utf8')).to.equal('secret');
|
|
96
|
+
});
|
|
97
|
+
it('extracts a packaged resource that is a plain file', async () => {
|
|
98
|
+
const archivePath = path.join(appDir, 'app.asar');
|
|
99
|
+
writeResources(archivePath, { 'scripts/greet.sh': 'echo hello' });
|
|
100
|
+
const resolvedPath = await provider.resolveExternalPath(path.join(archivePath, 'scripts', 'greet.sh'));
|
|
101
|
+
expectNestedIn(configDir, resolvedPath);
|
|
102
|
+
(0, chai_1.expect)(fs.readFileSync(resolvedPath, 'utf8')).to.equal('echo hello');
|
|
103
|
+
});
|
|
104
|
+
it('extracts a packaged file as executable', async function () {
|
|
105
|
+
if (process.platform === 'win32') {
|
|
106
|
+
this.skip();
|
|
107
|
+
}
|
|
108
|
+
// Electron reports the files of an asar archive with this mode, even executables.
|
|
109
|
+
const archivePath = path.join(appDir, 'app.asar');
|
|
110
|
+
writeResources(archivePath, { 'native/tool': 'binary' });
|
|
111
|
+
fs.chmodSync(path.join(archivePath, 'native', 'tool'), 0o644);
|
|
112
|
+
const resolvedPath = await provider.resolveExternalPath(path.join(archivePath, 'native', 'tool'));
|
|
113
|
+
(0, chai_1.expect)(fs.statSync(resolvedPath).mode & 0o700).to.equal(0o700);
|
|
114
|
+
});
|
|
115
|
+
it('prefers the copy that the packaging step has left outside of the archive', async () => {
|
|
116
|
+
const archivePath = path.join(appDir, 'app.asar');
|
|
117
|
+
writeResources(archivePath, { 'scripts/greet.sh': 'echo hello' });
|
|
118
|
+
const unpackedPath = writeResources(`${archivePath}.unpacked`, { 'scripts/greet.sh': 'echo hello' });
|
|
119
|
+
const resolvedPath = await provider.resolveExternalPath(path.join(archivePath, 'scripts'));
|
|
120
|
+
(0, chai_1.expect)(resolvedPath).to.equal(path.join(unpackedPath, 'scripts'));
|
|
121
|
+
});
|
|
122
|
+
it('extracts a packaged resource that was only unpacked partially', async () => {
|
|
123
|
+
const archivePath = path.join(appDir, 'app.asar');
|
|
124
|
+
writeResources(archivePath, { 'scripts/greet.sh': 'echo hello', 'scripts/farewell.sh': 'echo bye' });
|
|
125
|
+
writeResources(`${archivePath}.unpacked`, { 'scripts/greet.sh': 'echo hello' });
|
|
126
|
+
const resolvedPath = await provider.resolveExternalPath(path.join(archivePath, 'scripts'));
|
|
127
|
+
expectNestedIn(configDir, resolvedPath);
|
|
128
|
+
(0, chai_1.expect)(fs.readFileSync(path.join(resolvedPath, 'farewell.sh'), 'utf8')).to.equal('echo bye');
|
|
129
|
+
});
|
|
130
|
+
it('re-extracts a resource that was removed from the configuration directory', async () => {
|
|
131
|
+
const archivePath = path.join(appDir, 'app.asar');
|
|
132
|
+
writeResources(archivePath, { 'scripts/greet.sh': 'echo hello' });
|
|
133
|
+
const resourcePath = path.join(archivePath, 'scripts');
|
|
134
|
+
const resolvedPath = await provider.resolveExternalPath(resourcePath);
|
|
135
|
+
fs.rmSync(resolvedPath, { recursive: true });
|
|
136
|
+
(0, chai_1.expect)(await provider.resolveExternalPath(resourcePath)).to.equal(resolvedPath);
|
|
137
|
+
(0, chai_1.expect)(fs.readFileSync(path.join(resolvedPath, 'greet.sh'), 'utf8')).to.equal('echo hello');
|
|
138
|
+
});
|
|
139
|
+
it('extracts into a temporary directory if the configuration directory cannot be written to', async () => {
|
|
140
|
+
const archivePath = path.join(appDir, 'app.asar');
|
|
141
|
+
writeResources(archivePath, { 'scripts/greet.sh': 'echo hello' });
|
|
142
|
+
// a configuration directory that is a regular file cannot hold the extracted resources
|
|
143
|
+
configDir = path.join(appDir, 'not-a-directory');
|
|
144
|
+
fs.writeFileSync(configDir, '');
|
|
145
|
+
const resolvedPath = await createProvider().resolveExternalPath(path.join(archivePath, 'scripts'));
|
|
146
|
+
expectNestedIn(os.tmpdir(), resolvedPath);
|
|
147
|
+
(0, chai_1.expect)(fs.readFileSync(path.join(resolvedPath, 'greet.sh'), 'utf8')).to.equal('echo hello');
|
|
148
|
+
fs.rmSync(resolvedPath, { recursive: true, force: true });
|
|
149
|
+
});
|
|
150
|
+
it('updates an extracted resource when the application has been updated', async () => {
|
|
151
|
+
const archivePath = path.join(appDir, 'app.asar');
|
|
152
|
+
writeResources(archivePath, { 'scripts/greet.sh': 'echo hello' });
|
|
153
|
+
const resourcePath = path.join(archivePath, 'scripts');
|
|
154
|
+
await provider.resolveExternalPath(resourcePath);
|
|
155
|
+
writeResources(archivePath, { 'scripts/greet.sh': 'echo hello again' });
|
|
156
|
+
const resolvedPath = await createProvider().resolveExternalPath(resourcePath);
|
|
157
|
+
(0, chai_1.expect)(fs.readFileSync(path.join(resolvedPath, 'greet.sh'), 'utf8')).to.equal('echo hello again');
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
//# sourceMappingURL=bundled-resource-provider.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bundled-resource-provider.spec.js","sourceRoot":"","sources":["../../src/node/bundled-resource-provider.spec.ts"],"names":[],"mappings":"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"}
|
package/lib/node/index.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ export * from './messaging';
|
|
|
6
6
|
export * from './cli';
|
|
7
7
|
export * from './setting-service';
|
|
8
8
|
export { FileSystemLocking } from './filesystem-locking';
|
|
9
|
+
export { BundledResourceProvider } from './bundled-resource-provider';
|
|
9
10
|
export { BackendRequestAllowedContribution } from './request/backend-request-facade';
|
|
10
11
|
export { HttpConnectionValidator } from './hosting/browser-connection-token';
|
|
11
12
|
//# sourceMappingURL=index.d.ts.map
|
package/lib/node/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/node/index.ts"],"names":[],"mappings":"AAgBA,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC;AACjC,cAAc,SAAS,CAAC;AACxB,cAAc,oBAAoB,CAAC;AACnC,cAAc,aAAa,CAAC;AAC5B,cAAc,OAAO,CAAC;AACtB,cAAc,mBAAmB,CAAC;AAClC,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,iCAAiC,EAAE,MAAM,kCAAkC,CAAC;AACrF,OAAO,EAAE,uBAAuB,EAAE,MAAM,oCAAoC,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/node/index.ts"],"names":[],"mappings":"AAgBA,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC;AACjC,cAAc,SAAS,CAAC;AACxB,cAAc,oBAAoB,CAAC;AACnC,cAAc,aAAa,CAAC;AAC5B,cAAc,OAAO,CAAC;AACtB,cAAc,mBAAmB,CAAC;AAClC,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AACtE,OAAO,EAAE,iCAAiC,EAAE,MAAM,kCAAkC,CAAC;AACrF,OAAO,EAAE,uBAAuB,EAAE,MAAM,oCAAoC,CAAC"}
|
package/lib/node/index.js
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
16
16
|
// *****************************************************************************
|
|
17
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
-
exports.HttpConnectionValidator = exports.BackendRequestAllowedContribution = exports.FileSystemLocking = void 0;
|
|
18
|
+
exports.HttpConnectionValidator = exports.BackendRequestAllowedContribution = exports.BundledResourceProvider = exports.FileSystemLocking = void 0;
|
|
19
19
|
const tslib_1 = require("tslib");
|
|
20
20
|
tslib_1.__exportStar(require("./backend-application"), exports);
|
|
21
21
|
tslib_1.__exportStar(require("./backend-global"), exports);
|
|
@@ -26,6 +26,8 @@ tslib_1.__exportStar(require("./cli"), exports);
|
|
|
26
26
|
tslib_1.__exportStar(require("./setting-service"), exports);
|
|
27
27
|
var filesystem_locking_1 = require("./filesystem-locking");
|
|
28
28
|
Object.defineProperty(exports, "FileSystemLocking", { enumerable: true, get: function () { return filesystem_locking_1.FileSystemLocking; } });
|
|
29
|
+
var bundled_resource_provider_1 = require("./bundled-resource-provider");
|
|
30
|
+
Object.defineProperty(exports, "BundledResourceProvider", { enumerable: true, get: function () { return bundled_resource_provider_1.BundledResourceProvider; } });
|
|
29
31
|
var backend_request_facade_1 = require("./request/backend-request-facade");
|
|
30
32
|
Object.defineProperty(exports, "BackendRequestAllowedContribution", { enumerable: true, get: function () { return backend_request_facade_1.BackendRequestAllowedContribution; } });
|
|
31
33
|
var browser_connection_token_1 = require("./hosting/browser-connection-token");
|
package/lib/node/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/node/index.ts"],"names":[],"mappings":";AAAA,gFAAgF;AAChF,yCAAyC;AACzC,EAAE;AACF,2EAA2E;AAC3E,mEAAmE;AACnE,wCAAwC;AACxC,EAAE;AACF,4EAA4E;AAC5E,8EAA8E;AAC9E,6EAA6E;AAC7E,yDAAyD;AACzD,uDAAuD;AACvD,EAAE;AACF,gFAAgF;AAChF,gFAAgF;;;;AAEhF,gEAAsC;AACtC,2DAAiC;AACjC,kDAAwB;AACxB,6DAAmC;AACnC,sDAA4B;AAC5B,gDAAsB;AACtB,4DAAkC;AAClC,2DAAyD;AAAhD,uHAAA,iBAAiB,OAAA;AAC1B,2EAAqF;AAA5E,2IAAA,iCAAiC,OAAA;AAC1C,+EAA6E;AAApE,mIAAA,uBAAuB,OAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/node/index.ts"],"names":[],"mappings":";AAAA,gFAAgF;AAChF,yCAAyC;AACzC,EAAE;AACF,2EAA2E;AAC3E,mEAAmE;AACnE,wCAAwC;AACxC,EAAE;AACF,4EAA4E;AAC5E,8EAA8E;AAC9E,6EAA6E;AAC7E,yDAAyD;AACzD,uDAAuD;AACvD,EAAE;AACF,gFAAgF;AAChF,gFAAgF;;;;AAEhF,gEAAsC;AACtC,2DAAiC;AACjC,kDAAwB;AACxB,6DAAmC;AACnC,sDAA4B;AAC5B,gDAAsB;AACtB,4DAAkC;AAClC,2DAAyD;AAAhD,uHAAA,iBAAiB,OAAA;AAC1B,yEAAsE;AAA7D,oIAAA,uBAAuB,OAAA;AAChC,2EAAqF;AAA5E,2IAAA,iCAAiC,OAAA;AAC1C,+EAA6E;AAApE,mIAAA,uBAAuB,OAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@theia/core",
|
|
3
|
-
"version": "1.77.0-next.
|
|
3
|
+
"version": "1.77.0-next.6+c1feaf3f9",
|
|
4
4
|
"description": "Theia is a cloud & desktop IDE framework implemented in TypeScript.",
|
|
5
5
|
"main": "lib/common/index.js",
|
|
6
6
|
"typings": "lib/common/index.d.ts",
|
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
"@lumino/virtualdom": "^2.0.5",
|
|
18
18
|
"@lumino/widgets": "2.7.5",
|
|
19
19
|
"@parcel/watcher": "^2.6.0",
|
|
20
|
-
"@theia/application-package": "1.77.0-next.
|
|
21
|
-
"@theia/request": "1.77.0-next.
|
|
20
|
+
"@theia/application-package": "1.77.0-next.6+c1feaf3f9",
|
|
21
|
+
"@theia/request": "1.77.0-next.6+c1feaf3f9",
|
|
22
22
|
"@types/body-parser": "^1.19.6",
|
|
23
23
|
"@types/express": "^4.17.25",
|
|
24
24
|
"@types/fs-extra": "^4.0.15",
|
|
@@ -233,5 +233,5 @@
|
|
|
233
233
|
"nyc": {
|
|
234
234
|
"extends": "../../configs/nyc.json"
|
|
235
235
|
},
|
|
236
|
-
"gitHead": "
|
|
236
|
+
"gitHead": "c1feaf3f9adaa19555ccbc4eff7214b5a6601f53"
|
|
237
237
|
}
|
|
@@ -57,6 +57,7 @@ import { bindNodeStopwatch, bindBackendStopwatchServer } from './performance';
|
|
|
57
57
|
import { OSBackendProviderImpl } from './os-backend-provider';
|
|
58
58
|
import { BackendRequestFacade, BackendRequestAllowedContribution } from './request/backend-request-facade';
|
|
59
59
|
import { FileSystemLocking, FileSystemLockingImpl } from './filesystem-locking';
|
|
60
|
+
import { BundledResourceProvider, BundledResourceProviderImpl } from './bundled-resource-provider';
|
|
60
61
|
import { BackendRemoteService } from './remote/backend-remote-service';
|
|
61
62
|
import { RemoteCliContribution } from './remote/remote-cli-contribution';
|
|
62
63
|
import { SettingService, SettingServiceImpl } from './setting-service';
|
|
@@ -164,6 +165,9 @@ export const backendApplicationModule = new ContainerModule(bind => {
|
|
|
164
165
|
|
|
165
166
|
bind(FileSystemLocking).to(FileSystemLockingImpl).inSingletonScope();
|
|
166
167
|
|
|
168
|
+
bind(BundledResourceProviderImpl).toSelf().inSingletonScope();
|
|
169
|
+
bind(BundledResourceProvider).toService(BundledResourceProviderImpl);
|
|
170
|
+
|
|
167
171
|
bind(SettingServiceImpl).toSelf().inSingletonScope();
|
|
168
172
|
bind(SettingService).toService(SettingServiceImpl);
|
|
169
173
|
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2026 EclipseSource GmbH and others.
|
|
3
|
+
//
|
|
4
|
+
// This program and the accompanying materials are made available under the
|
|
5
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
//
|
|
8
|
+
// This Source Code may also be made available under the following Secondary
|
|
9
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
// with the GNU Classpath Exception which is available at
|
|
12
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
//
|
|
14
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
|
+
// *****************************************************************************
|
|
16
|
+
|
|
17
|
+
import 'reflect-metadata';
|
|
18
|
+
import { expect } from 'chai';
|
|
19
|
+
import * as fs from 'fs';
|
|
20
|
+
import * as os from 'os';
|
|
21
|
+
import * as path from 'path';
|
|
22
|
+
import * as temp from 'temp';
|
|
23
|
+
import { Container } from 'inversify';
|
|
24
|
+
import { EnvVariablesServer } from '../common/env-variables';
|
|
25
|
+
import { ILogger } from '../common/logger';
|
|
26
|
+
import { MockLogger } from '../common/test/mock-logger';
|
|
27
|
+
import { FileUri } from '../common/file-uri';
|
|
28
|
+
import { BundledResourceProvider, BundledResourceProviderImpl } from './bundled-resource-provider';
|
|
29
|
+
import { FileSystemLocking, FileSystemLockingImpl } from './filesystem-locking';
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* The provider recognizes archives by their `.asar` path segment and reads them through `fs`, which Electron
|
|
33
|
+
* patches to transparently read from the archive. Plain directories named `*.asar` therefore behave like
|
|
34
|
+
* archives from the point of view of the provider and let us test it outside of Electron.
|
|
35
|
+
*/
|
|
36
|
+
describe('BundledResourceProvider', () => {
|
|
37
|
+
|
|
38
|
+
const track = temp.track();
|
|
39
|
+
|
|
40
|
+
let configDir: string;
|
|
41
|
+
let appDir: string;
|
|
42
|
+
let provider: BundledResourceProvider;
|
|
43
|
+
|
|
44
|
+
beforeEach(() => {
|
|
45
|
+
const root = track.mkdirSync();
|
|
46
|
+
configDir = path.join(root, 'config');
|
|
47
|
+
appDir = path.join(root, 'app');
|
|
48
|
+
fs.mkdirSync(configDir);
|
|
49
|
+
fs.mkdirSync(appDir);
|
|
50
|
+
provider = createProvider();
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
/** Each provider instance stands for one run of the application, as resolved paths are cached. */
|
|
54
|
+
function createProvider(): BundledResourceProvider {
|
|
55
|
+
const container = new Container();
|
|
56
|
+
container.bind(ILogger).toConstantValue(new MockLogger());
|
|
57
|
+
container.bind(FileSystemLocking).to(FileSystemLockingImpl).inSingletonScope();
|
|
58
|
+
container.bind(EnvVariablesServer).toConstantValue({
|
|
59
|
+
getConfigDirUri: async () => FileUri.create(configDir).toString()
|
|
60
|
+
} as unknown as EnvVariablesServer);
|
|
61
|
+
container.bind(BundledResourceProviderImpl).toSelf().inSingletonScope();
|
|
62
|
+
container.bind(BundledResourceProvider).toService(BundledResourceProviderImpl);
|
|
63
|
+
return container.get(BundledResourceProvider);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
afterEach(() => track.cleanupSync());
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Assert that the given path is nested in the given directory. The provider derives the configuration
|
|
70
|
+
* directory from a URI, which on Windows yields a lower-case drive letter, so the paths cannot simply be
|
|
71
|
+
* compared by prefix. `path.relative` ignores the case of a path on Windows.
|
|
72
|
+
*/
|
|
73
|
+
function expectNestedIn(directoryPath: string, nestedPath: string): void {
|
|
74
|
+
const relativePath = path.relative(directoryPath, nestedPath);
|
|
75
|
+
expect(relativePath).to.not.be.empty;
|
|
76
|
+
expect(relativePath.split(path.sep)).to.not.contain('..');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function writeResources(rootPath: string, files: Record<string, string>): string {
|
|
80
|
+
for (const [relativePath, content] of Object.entries(files)) {
|
|
81
|
+
const filePath = path.join(rootPath, relativePath);
|
|
82
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
83
|
+
fs.writeFileSync(filePath, content);
|
|
84
|
+
}
|
|
85
|
+
return rootPath;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
it('returns the path of a resource that is not packaged into an archive', async () => {
|
|
89
|
+
const resourcePath = path.join(writeResources(appDir, { 'scripts/greet.sh': 'echo hello' }), 'scripts');
|
|
90
|
+
expect(await provider.resolveExternalPath(resourcePath)).to.equal(resourcePath);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('rejects for a resource that does not exist', async () => {
|
|
94
|
+
const resourcePath = path.join(appDir, 'scripts');
|
|
95
|
+
await provider.resolveExternalPath(resourcePath).then(
|
|
96
|
+
() => expect.fail('should have been rejected'),
|
|
97
|
+
error => expect(String(error)).to.contain(resourcePath)
|
|
98
|
+
);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('extracts a packaged resource into the configuration directory', async () => {
|
|
102
|
+
const archivePath = path.join(appDir, 'app.asar');
|
|
103
|
+
writeResources(archivePath, { 'scripts/greet.sh': 'echo hello', 'scripts/nested/.hidden': 'secret' });
|
|
104
|
+
|
|
105
|
+
const resolvedPath = await provider.resolveExternalPath(path.join(archivePath, 'scripts'));
|
|
106
|
+
|
|
107
|
+
expect(resolvedPath).to.not.contain('.asar');
|
|
108
|
+
expectNestedIn(configDir, resolvedPath);
|
|
109
|
+
expect(fs.readFileSync(path.join(resolvedPath, 'greet.sh'), 'utf8')).to.equal('echo hello');
|
|
110
|
+
expect(fs.readFileSync(path.join(resolvedPath, 'nested', '.hidden'), 'utf8')).to.equal('secret');
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it('extracts a packaged resource that is a plain file', async () => {
|
|
114
|
+
const archivePath = path.join(appDir, 'app.asar');
|
|
115
|
+
writeResources(archivePath, { 'scripts/greet.sh': 'echo hello' });
|
|
116
|
+
|
|
117
|
+
const resolvedPath = await provider.resolveExternalPath(path.join(archivePath, 'scripts', 'greet.sh'));
|
|
118
|
+
|
|
119
|
+
expectNestedIn(configDir, resolvedPath);
|
|
120
|
+
expect(fs.readFileSync(resolvedPath, 'utf8')).to.equal('echo hello');
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it('extracts a packaged file as executable', async function (): Promise<void> {
|
|
124
|
+
if (process.platform === 'win32') {
|
|
125
|
+
this.skip();
|
|
126
|
+
}
|
|
127
|
+
// Electron reports the files of an asar archive with this mode, even executables.
|
|
128
|
+
const archivePath = path.join(appDir, 'app.asar');
|
|
129
|
+
writeResources(archivePath, { 'native/tool': 'binary' });
|
|
130
|
+
fs.chmodSync(path.join(archivePath, 'native', 'tool'), 0o644);
|
|
131
|
+
|
|
132
|
+
const resolvedPath = await provider.resolveExternalPath(path.join(archivePath, 'native', 'tool'));
|
|
133
|
+
|
|
134
|
+
expect(fs.statSync(resolvedPath).mode & 0o700).to.equal(0o700);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it('prefers the copy that the packaging step has left outside of the archive', async () => {
|
|
138
|
+
const archivePath = path.join(appDir, 'app.asar');
|
|
139
|
+
writeResources(archivePath, { 'scripts/greet.sh': 'echo hello' });
|
|
140
|
+
const unpackedPath = writeResources(`${archivePath}.unpacked`, { 'scripts/greet.sh': 'echo hello' });
|
|
141
|
+
|
|
142
|
+
const resolvedPath = await provider.resolveExternalPath(path.join(archivePath, 'scripts'));
|
|
143
|
+
|
|
144
|
+
expect(resolvedPath).to.equal(path.join(unpackedPath, 'scripts'));
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it('extracts a packaged resource that was only unpacked partially', async () => {
|
|
148
|
+
const archivePath = path.join(appDir, 'app.asar');
|
|
149
|
+
writeResources(archivePath, { 'scripts/greet.sh': 'echo hello', 'scripts/farewell.sh': 'echo bye' });
|
|
150
|
+
writeResources(`${archivePath}.unpacked`, { 'scripts/greet.sh': 'echo hello' });
|
|
151
|
+
|
|
152
|
+
const resolvedPath = await provider.resolveExternalPath(path.join(archivePath, 'scripts'));
|
|
153
|
+
|
|
154
|
+
expectNestedIn(configDir, resolvedPath);
|
|
155
|
+
expect(fs.readFileSync(path.join(resolvedPath, 'farewell.sh'), 'utf8')).to.equal('echo bye');
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it('re-extracts a resource that was removed from the configuration directory', async () => {
|
|
159
|
+
const archivePath = path.join(appDir, 'app.asar');
|
|
160
|
+
writeResources(archivePath, { 'scripts/greet.sh': 'echo hello' });
|
|
161
|
+
const resourcePath = path.join(archivePath, 'scripts');
|
|
162
|
+
|
|
163
|
+
const resolvedPath = await provider.resolveExternalPath(resourcePath);
|
|
164
|
+
fs.rmSync(resolvedPath, { recursive: true });
|
|
165
|
+
|
|
166
|
+
expect(await provider.resolveExternalPath(resourcePath)).to.equal(resolvedPath);
|
|
167
|
+
expect(fs.readFileSync(path.join(resolvedPath, 'greet.sh'), 'utf8')).to.equal('echo hello');
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
it('extracts into a temporary directory if the configuration directory cannot be written to', async () => {
|
|
171
|
+
const archivePath = path.join(appDir, 'app.asar');
|
|
172
|
+
writeResources(archivePath, { 'scripts/greet.sh': 'echo hello' });
|
|
173
|
+
// a configuration directory that is a regular file cannot hold the extracted resources
|
|
174
|
+
configDir = path.join(appDir, 'not-a-directory');
|
|
175
|
+
fs.writeFileSync(configDir, '');
|
|
176
|
+
|
|
177
|
+
const resolvedPath = await createProvider().resolveExternalPath(path.join(archivePath, 'scripts'));
|
|
178
|
+
|
|
179
|
+
expectNestedIn(os.tmpdir(), resolvedPath);
|
|
180
|
+
expect(fs.readFileSync(path.join(resolvedPath, 'greet.sh'), 'utf8')).to.equal('echo hello');
|
|
181
|
+
fs.rmSync(resolvedPath, { recursive: true, force: true });
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
it('updates an extracted resource when the application has been updated', async () => {
|
|
185
|
+
const archivePath = path.join(appDir, 'app.asar');
|
|
186
|
+
writeResources(archivePath, { 'scripts/greet.sh': 'echo hello' });
|
|
187
|
+
const resourcePath = path.join(archivePath, 'scripts');
|
|
188
|
+
|
|
189
|
+
await provider.resolveExternalPath(resourcePath);
|
|
190
|
+
writeResources(archivePath, { 'scripts/greet.sh': 'echo hello again' });
|
|
191
|
+
const resolvedPath = await createProvider().resolveExternalPath(resourcePath);
|
|
192
|
+
|
|
193
|
+
expect(fs.readFileSync(path.join(resolvedPath, 'greet.sh'), 'utf8')).to.equal('echo hello again');
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
});
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2026 EclipseSource GmbH and others.
|
|
3
|
+
//
|
|
4
|
+
// This program and the accompanying materials are made available under the
|
|
5
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
//
|
|
8
|
+
// This Source Code may also be made available under the following Secondary
|
|
9
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
// with the GNU Classpath Exception which is available at
|
|
12
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
//
|
|
14
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
|
+
// *****************************************************************************
|
|
16
|
+
|
|
17
|
+
import * as crypto from 'crypto';
|
|
18
|
+
import * as fs from 'fs';
|
|
19
|
+
import * as os from 'os';
|
|
20
|
+
import * as path from 'path';
|
|
21
|
+
import { inject, injectable, interfaces, named } from 'inversify';
|
|
22
|
+
import { EnvVariablesServer } from '../common/env-variables';
|
|
23
|
+
import { FileUri } from '../common/file-uri';
|
|
24
|
+
import { ILogger } from '../common/logger';
|
|
25
|
+
import { FileSystemLocking } from './filesystem-locking';
|
|
26
|
+
|
|
27
|
+
export const BundledResourceProvider = Symbol('BundledResourceProvider') as symbol & interfaces.Abstract<BundledResourceProvider>;
|
|
28
|
+
/**
|
|
29
|
+
* Provides paths to resources that are bundled with the application, in a form that can also be used by
|
|
30
|
+
* processes which do not run inside the application, such as shells, debug adapters or other external tools.
|
|
31
|
+
*
|
|
32
|
+
* When an Electron application is packaged with `asar: true`, the resources of the application are stored in
|
|
33
|
+
* an `app.asar` archive. Paths pointing into such an archive can only be read through Electron's patched `fs`
|
|
34
|
+
* module, so handing them to an external process fails. Therefore, always resolve a bundled resource through
|
|
35
|
+
* this service before passing its path to a process outside of the application.
|
|
36
|
+
*/
|
|
37
|
+
export interface BundledResourceProvider {
|
|
38
|
+
/**
|
|
39
|
+
* Resolve the given path of a bundled file or directory to a path that external processes can read.
|
|
40
|
+
*
|
|
41
|
+
* If the resource is not packaged into an archive, its path is returned unchanged. Otherwise the copy that
|
|
42
|
+
* the packaging step has left outside of the archive is used, if it is complete, and the resource is
|
|
43
|
+
* extracted from the archive into the configuration directory as a last resort.
|
|
44
|
+
*
|
|
45
|
+
* Results are cached, so that a resource is extracted at most once per application version.
|
|
46
|
+
*
|
|
47
|
+
* @param resourcePath the path of the bundled resource, typically resolved against `__dirname`.
|
|
48
|
+
* @returns the path to use outside of the application.
|
|
49
|
+
* @throws if the resource does not exist or cannot be made available.
|
|
50
|
+
*/
|
|
51
|
+
resolveExternalPath(resourcePath: string): Promise<string>;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
@injectable()
|
|
55
|
+
export class BundledResourceProviderImpl implements BundledResourceProvider {
|
|
56
|
+
|
|
57
|
+
@inject(ILogger) @named('core:BundledResourceProviderImpl')
|
|
58
|
+
protected readonly logger: ILogger;
|
|
59
|
+
|
|
60
|
+
@inject(EnvVariablesServer)
|
|
61
|
+
protected readonly envVariablesServer: EnvVariablesServer;
|
|
62
|
+
|
|
63
|
+
@inject(FileSystemLocking)
|
|
64
|
+
protected readonly fileSystemLocking: FileSystemLocking;
|
|
65
|
+
|
|
66
|
+
/** The folder within the configuration directory into which resources are extracted. */
|
|
67
|
+
protected readonly extractionFolder = 'bundled-resources';
|
|
68
|
+
|
|
69
|
+
/** Resources extracted for another application version are removed when they are older than this. */
|
|
70
|
+
protected readonly staleExtractionAge = 7 * 24 * 60 * 60 * 1000;
|
|
71
|
+
|
|
72
|
+
protected readonly resolved = new Map<string, Promise<string>>();
|
|
73
|
+
protected temporaryExtractionPath: Promise<string> | undefined;
|
|
74
|
+
|
|
75
|
+
async resolveExternalPath(resourcePath: string): Promise<string> {
|
|
76
|
+
const normalizedPath = path.resolve(resourcePath);
|
|
77
|
+
const pending = this.resolved.get(normalizedPath);
|
|
78
|
+
if (pending) {
|
|
79
|
+
try {
|
|
80
|
+
const resolvedPath = await pending;
|
|
81
|
+
if (await this.exists(resolvedPath)) {
|
|
82
|
+
return resolvedPath;
|
|
83
|
+
}
|
|
84
|
+
} catch {
|
|
85
|
+
// the previous attempt failed, so try again below
|
|
86
|
+
}
|
|
87
|
+
this.resolved.delete(normalizedPath);
|
|
88
|
+
}
|
|
89
|
+
const result = this.doResolveExternalPath(normalizedPath);
|
|
90
|
+
this.resolved.set(normalizedPath, result);
|
|
91
|
+
return result;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
protected async doResolveExternalPath(resourcePath: string): Promise<string> {
|
|
95
|
+
if (!await this.exists(resourcePath)) {
|
|
96
|
+
throw new Error(`Bundled resource does not exist: ${resourcePath}`);
|
|
97
|
+
}
|
|
98
|
+
const archivePath = this.findArchivePath(resourcePath);
|
|
99
|
+
if (!archivePath) {
|
|
100
|
+
// The resource is not packaged into an archive, so external processes can read it directly.
|
|
101
|
+
return resourcePath;
|
|
102
|
+
}
|
|
103
|
+
const relativePath = path.relative(archivePath, resourcePath);
|
|
104
|
+
const unpackedPath = path.join(`${archivePath}.unpacked`, relativePath);
|
|
105
|
+
if (await this.isExtracted(resourcePath, unpackedPath)) {
|
|
106
|
+
return unpackedPath;
|
|
107
|
+
}
|
|
108
|
+
const extractionPath = path.join(await this.getExtractionPath(archivePath), relativePath);
|
|
109
|
+
await this.fileSystemLocking.lockPath(archivePath, () => this.extract(resourcePath, extractionPath));
|
|
110
|
+
this.logger.info(`Extracted bundled resource '${resourcePath}' to '${extractionPath}'.`);
|
|
111
|
+
return extractionPath;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Find the archive that the given resource is packaged into, if any.
|
|
116
|
+
*
|
|
117
|
+
* @returns the path of the archive, i.e. the shortest prefix of the given path ending in an `.asar` segment,
|
|
118
|
+
* which is also how Electron itself determines the archive that a path refers to.
|
|
119
|
+
*/
|
|
120
|
+
protected findArchivePath(resourcePath: string): string | undefined {
|
|
121
|
+
const segments = resourcePath.split(/[\\/]/);
|
|
122
|
+
const archiveIndex = segments.findIndex(segment => segment.toLowerCase().endsWith('.asar'));
|
|
123
|
+
return archiveIndex < 0 ? undefined : segments.slice(0, archiveIndex + 1).join(path.sep);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Whether every file of the given resource is already available at the given target path. Packaging tools
|
|
128
|
+
* only unpack the files that the application configured them to unpack, so a partial copy must be ignored.
|
|
129
|
+
*/
|
|
130
|
+
protected async isExtracted(resourcePath: string, targetPath: string): Promise<boolean> {
|
|
131
|
+
for (const file of await this.collectFiles(resourcePath)) {
|
|
132
|
+
if (!await this.exists(path.join(targetPath, file))) {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return true;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
protected async extract(resourcePath: string, targetPath: string): Promise<void> {
|
|
140
|
+
for (const file of await this.collectFiles(resourcePath)) {
|
|
141
|
+
await this.copyFile(path.join(resourcePath, file), path.join(targetPath, file));
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Collect the files of the given resource as paths relative to it. The relative path of a resource that is
|
|
147
|
+
* a plain file is the empty string.
|
|
148
|
+
*/
|
|
149
|
+
protected async collectFiles(resourcePath: string, relativePath: string = ''): Promise<string[]> {
|
|
150
|
+
const currentPath = path.join(resourcePath, relativePath);
|
|
151
|
+
if (!(await fs.promises.stat(currentPath)).isDirectory()) {
|
|
152
|
+
return [relativePath];
|
|
153
|
+
}
|
|
154
|
+
const files: string[] = [];
|
|
155
|
+
for (const entry of await fs.promises.readdir(currentPath)) {
|
|
156
|
+
files.push(...await this.collectFiles(resourcePath, path.join(relativePath, entry)));
|
|
157
|
+
}
|
|
158
|
+
return files;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
protected async copyFile(sourcePath: string, targetPath: string): Promise<void> {
|
|
162
|
+
const sourceStat = await fs.promises.stat(sourcePath);
|
|
163
|
+
if (await this.isUpToDate(targetPath, sourceStat)) {
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
await fs.promises.mkdir(path.dirname(targetPath), { recursive: true, mode: 0o700 });
|
|
167
|
+
// Write to a temporary file and move it into place, so that a concurrently starting application
|
|
168
|
+
// instance never reads partially written content.
|
|
169
|
+
const temporaryPath = `${targetPath}.${process.pid}.tmp`;
|
|
170
|
+
try {
|
|
171
|
+
// Electron reports the files of an asar archive as not executable, even those that the archive marks as
|
|
172
|
+
// executable, so every extracted file is made executable for the owner to keep bundled executables usable.
|
|
173
|
+
await fs.promises.writeFile(temporaryPath, await fs.promises.readFile(sourcePath), { mode: sourceStat.mode & 0o777 | 0o700 });
|
|
174
|
+
try {
|
|
175
|
+
await fs.promises.rename(temporaryPath, targetPath);
|
|
176
|
+
} catch {
|
|
177
|
+
// renaming onto an existing file is not supported on all platforms
|
|
178
|
+
await fs.promises.rm(targetPath, { force: true });
|
|
179
|
+
await fs.promises.rename(temporaryPath, targetPath);
|
|
180
|
+
}
|
|
181
|
+
} finally {
|
|
182
|
+
await fs.promises.rm(temporaryPath, { force: true });
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
protected async isUpToDate(targetPath: string, sourceStat: fs.Stats): Promise<boolean> {
|
|
187
|
+
try {
|
|
188
|
+
return (await fs.promises.stat(targetPath)).size === sourceStat.size;
|
|
189
|
+
} catch {
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* The directory into which resources of the given archive are extracted. It is specific to the content of
|
|
196
|
+
* the archive, so that updating the application invalidates previously extracted copies.
|
|
197
|
+
*/
|
|
198
|
+
protected async getExtractionPath(archivePath: string): Promise<string> {
|
|
199
|
+
const archiveName = path.basename(archivePath, path.extname(archivePath));
|
|
200
|
+
try {
|
|
201
|
+
const extractionRoot = path.join(FileUri.fsPath(await this.envVariablesServer.getConfigDirUri()), this.extractionFolder);
|
|
202
|
+
const extractionPath = path.join(extractionRoot, `${archiveName}-${this.getArchiveStamp(archivePath)}`);
|
|
203
|
+
await fs.promises.mkdir(extractionPath, { recursive: true, mode: 0o700 });
|
|
204
|
+
this.removeStaleExtractions(extractionRoot, `${archiveName}-`, extractionPath);
|
|
205
|
+
return extractionPath;
|
|
206
|
+
} catch (error) {
|
|
207
|
+
this.logger.warn('Could not extract bundled resources into the configuration directory, using a temporary directory instead.', error);
|
|
208
|
+
return this.getTemporaryExtractionPath();
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Fallback for applications whose configuration directory cannot be written to. The directory is unique to
|
|
214
|
+
* this run of the application, so that resources are extracted again whenever the application is started.
|
|
215
|
+
*/
|
|
216
|
+
protected getTemporaryExtractionPath(): Promise<string> {
|
|
217
|
+
return this.temporaryExtractionPath ??= fs.promises.mkdtemp(path.join(os.tmpdir(), 'theia-bundled-resources-'));
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Identify the content of the given archive. `process.noAsar` is toggled around the synchronous `stat` call
|
|
222
|
+
* to get the stats of the archive file itself rather than of the directory that it appears as.
|
|
223
|
+
*/
|
|
224
|
+
protected getArchiveStamp(archivePath: string): string {
|
|
225
|
+
const asarProcess = process as NodeJS.Process & { noAsar?: boolean };
|
|
226
|
+
const noAsar = asarProcess.noAsar;
|
|
227
|
+
try {
|
|
228
|
+
asarProcess.noAsar = true;
|
|
229
|
+
const stat = fs.statSync(archivePath);
|
|
230
|
+
return crypto.createHash('sha256').update(`${archivePath}:${stat.size}:${stat.mtimeMs}`).digest('hex').substring(0, 12);
|
|
231
|
+
} finally {
|
|
232
|
+
asarProcess.noAsar = noAsar;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Remove resources that were extracted from an earlier version of the archive, unless they were used
|
|
238
|
+
* recently, because another application instance may still be running on that version.
|
|
239
|
+
*/
|
|
240
|
+
protected removeStaleExtractions(extractionRoot: string, prefix: string, currentPath: string): void {
|
|
241
|
+
const removeStale = async () => {
|
|
242
|
+
for (const entry of await fs.promises.readdir(extractionRoot)) {
|
|
243
|
+
const entryPath = path.join(extractionRoot, entry);
|
|
244
|
+
if (!entry.startsWith(prefix) || entryPath === currentPath) {
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
247
|
+
const stat = await fs.promises.stat(entryPath);
|
|
248
|
+
if (Date.now() - stat.mtimeMs > this.staleExtractionAge) {
|
|
249
|
+
await fs.promises.rm(entryPath, { recursive: true, force: true });
|
|
250
|
+
this.logger.info(`Removed stale extracted resources: ${entryPath}`);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
removeStale().catch(error => this.logger.warn(`Could not remove stale extracted resources in '${extractionRoot}'.`, error));
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
protected async exists(targetPath: string): Promise<boolean> {
|
|
258
|
+
try {
|
|
259
|
+
await fs.promises.stat(targetPath);
|
|
260
|
+
return true;
|
|
261
|
+
} catch {
|
|
262
|
+
return false;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
}
|
package/src/node/index.ts
CHANGED
|
@@ -22,5 +22,6 @@ export * from './messaging';
|
|
|
22
22
|
export * from './cli';
|
|
23
23
|
export * from './setting-service';
|
|
24
24
|
export { FileSystemLocking } from './filesystem-locking';
|
|
25
|
+
export { BundledResourceProvider } from './bundled-resource-provider';
|
|
25
26
|
export { BackendRequestAllowedContribution } from './request/backend-request-facade';
|
|
26
27
|
export { HttpConnectionValidator } from './hosting/browser-connection-token';
|