Skip to content

Commit

Permalink
fix: workaround for # in the app path
Browse files Browse the repository at this point in the history
Closes #1815
Ref eclipse-theia/theia#12064

Signed-off-by: Akos Kitta <a.kitta@arduino.cc>
  • Loading branch information
Akos Kitta committed Jan 13, 2023
1 parent 26d3963 commit f2a2821
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 0 deletions.
11 changes: 11 additions & 0 deletions arduino-ide-extension/src/node/arduino-ide-backend-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,11 @@ import { MessagingContribution } from './theia/core/messaging-contribution';
import { MessagingService } from '@theia/core/lib/node/messaging/messaging-service';
import { HostedPluginReader } from './theia/plugin-ext/plugin-reader';
import { HostedPluginReader as TheiaHostedPluginReader } from '@theia/plugin-ext/lib/hosted/node/plugin-reader';
import { PluginDeployer } from '@theia/plugin-ext/lib/common/plugin-protocol';
import {
LocalDirectoryPluginDeployerResolverWithFallback,
PluginDeployer_GH_12064,
} from './theia/plugin-ext/plugin-deployer';

export default new ContainerModule((bind, unbind, isBound, rebind) => {
bind(BackendApplication).toSelf().inSingletonScope();
Expand Down Expand Up @@ -392,6 +397,12 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
// https://github.com/arduino/arduino-ide/pull/1706#pullrequestreview-1195595080
bind(HostedPluginReader).toSelf().inSingletonScope();
rebind(TheiaHostedPluginReader).toService(HostedPluginReader);

// https://github.com/eclipse-theia/theia/issues/12064
bind(LocalDirectoryPluginDeployerResolverWithFallback)
.toSelf()
.inSingletonScope();
rebind(PluginDeployer).to(PluginDeployer_GH_12064).inSingletonScope();
});

function bindChildLogger(bind: interfaces.Bind, name: string): void {
Expand Down
100 changes: 100 additions & 0 deletions arduino-ide-extension/src/node/theia/plugin-ext/plugin-deployer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,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);
}
}
}

0 comments on commit f2a2821

Please sign in to comment.