-
-
Notifications
You must be signed in to change notification settings - Fork 431
/
Copy pathplugin-deployer.ts
100 lines (95 loc) · 3.48 KB
/
plugin-deployer.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import { URI } from '@theia/core/lib/common/uri';
import {
inject,
injectable,
postConstruct,
} from '@theia/core/shared/inversify';
import {
PluginDeployerResolver,
PluginDeployerResolverContext,
} from '@theia/plugin-ext/lib/common/plugin-protocol';
import { PluginDeployerImpl } from '@theia/plugin-ext/lib/main/node/plugin-deployer-impl';
import { LocalDirectoryPluginDeployerResolver } from '@theia/plugin-ext/lib/main/node/resolvers/local-directory-plugin-deployer-resolver';
import { constants, promises as fs } from 'fs';
import { isAbsolute, resolve } from 'path';
@injectable()
export class LocalDirectoryPluginDeployerResolverWithFallback extends LocalDirectoryPluginDeployerResolver {
override async resolve(
pluginResolverContext: PluginDeployerResolverContext
): Promise<void> {
const origin = pluginResolverContext.getOriginId();
// The original implementation must not run when there is a hash in the path. Otherwise, it can resolve an undesired directory.
// Consider app under c:\Users\username\Desktop\# here is my app\
// Then the flawed logic will incorrectly find c:\Users\username\Desktop location after stripping the rest of the path after the hash.
// The implementation which provides a workaround for the hash in the path assumes that the original Theia logic is correct, when no hash present in the URI path.
let localPath: string | null;
if (origin.includes('#')) {
localPath = await resolveLocalPluginPathFallback(
pluginResolverContext,
this.supportedScheme
);
} else {
localPath = await this.originalResolveLocalPluginPath(
pluginResolverContext,
this.supportedScheme
);
}
if (localPath) {
await this.resolveFromLocalPath(pluginResolverContext, localPath);
}
}
private async originalResolveLocalPluginPath(
context: PluginDeployerResolverContext,
scheme: string
): Promise<string | null> {
const object = <Record<string, unknown>>this;
if (
'resolveLocalPluginPath' in object &&
typeof object['resolveLocalPluginPath'] === 'function'
) {
return object['resolveLocalPluginPath'](context, scheme);
}
return null;
}
}
async function resolveLocalPluginPathFallback(
context: PluginDeployerResolverContext,
scheme: string
): Promise<string | null> {
const uri = new URI(context.getOriginId());
if (uri.scheme === scheme) {
const unencodedRawUri = uri.toString(true);
let fsPath = unencodedRawUri.substring(`${scheme}:`.length);
if (!isAbsolute(fsPath)) {
fsPath = resolve(process.cwd(), fsPath);
}
try {
await fs.access(fsPath, constants.R_OK);
return fsPath;
} catch {
console.warn(
`The local plugin referenced by ${context.getOriginId()} does not exist.`
);
}
}
return null;
}
@injectable()
export class PluginDeployer_GH_12064 extends PluginDeployerImpl {
@inject(LocalDirectoryPluginDeployerResolverWithFallback)
private readonly pluginResolver: LocalDirectoryPluginDeployerResolverWithFallback;
@postConstruct()
protected adjustPluginResolvers(): void {
const pluginResolvers = <PluginDeployerResolver[]>(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(this as any).pluginResolvers
);
const index = pluginResolvers.findIndex(
(pluginResolver) =>
pluginResolver instanceof LocalDirectoryPluginDeployerResolver
);
if (index >= 0) {
pluginResolvers.splice(index, 1, this.pluginResolver);
}
}
}