Skip to content

Commit

Permalink
Added extensionDependency automatically downloading. Fixes: #4504
Browse files Browse the repository at this point in the history
Signed-off-by: Josh Pinkney <joshpinkney@gmail.com>
  • Loading branch information
JPinkney authored and akosyakov committed Aug 18, 2019
1 parent 0eebcf3 commit 2d4c845
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 43 deletions.
12 changes: 11 additions & 1 deletion packages/plugin-ext-vscode/src/node/scanner-vscode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { TheiaPluginScanner } from '@theia/plugin-ext/lib/hosted/node/scanners/s
@injectable()
export class VsCodePluginScanner extends TheiaPluginScanner implements PluginScanner {
private readonly VSCODE_TYPE: PluginEngine = 'vscode';
private readonly VSCODE_PREFIX: string = 'vscode:extension/';

get apiType(): PluginEngine {
return this.VSCODE_TYPE;
Expand All @@ -41,7 +42,8 @@ export class VsCodePluginScanner extends TheiaPluginScanner implements PluginSca
},
entryPoint: {
backend: plugin.main
}
},
extensionDependencies: this.getDeployableDependencies(plugin.extensionDependencies || [])
};
result.contributes = this.readContributions(plugin);
return result;
Expand All @@ -55,4 +57,12 @@ export class VsCodePluginScanner extends TheiaPluginScanner implements PluginSca
backendInitPath: __dirname + '/plugin-vscode-init.js'
};
}

/**
* Converts an array of extension dependencies
* to an array of deployable extension dependencies
*/
private getDeployableDependencies(dependencies: string[]): string[] {
return dependencies.map(dep => this.VSCODE_PREFIX + dep);
}
}
5 changes: 5 additions & 0 deletions packages/plugin-ext/src/common/plugin-protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,8 @@ export interface PluginDeployerResolverContext {

addPlugin(pluginId: string, path: string): void;

getPlugins(): PluginDeployerEntry[];

getOriginId(): string;

}
Expand Down Expand Up @@ -375,6 +377,7 @@ export interface PluginModel {
backend?: string;
};
contributes?: PluginContribution;
extensionDependencies?: string[];
}

/**
Expand Down Expand Up @@ -607,6 +610,8 @@ export const PluginDeployerHandler = Symbol('PluginDeployerHandler');
export interface PluginDeployerHandler {
deployFrontendPlugins(frontendPlugins: PluginDeployerEntry[]): Promise<void>;
deployBackendPlugins(backendPlugins: PluginDeployerEntry[]): Promise<void>;

getPluginDependencies(pluginToBeInstalled: PluginDeployerEntry): Promise<string[]>
}

export const HostedPluginServer = Symbol('HostedPluginServer');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,16 @@ export class HostedPluginDeployerHandler implements PluginDeployerHandler {
return this.currentBackendPluginsMetadata;
}

async getPluginDependencies(plugin: PluginDeployerEntry): Promise<string[]> {
const metadata = await this.reader.getPluginMetadata(plugin.path());
if (metadata) {
if (metadata.model.extensionDependencies) {
return metadata.model.extensionDependencies;
}
}
return [];
}

async deployFrontendPlugins(frontendPlugins: PluginDeployerEntry[]): Promise<void> {
for (const plugin of frontendPlugins) {
const metadata = await this.reader.getPluginMetadata(plugin.path());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ const INTERNAL_CONSOLE_OPTIONS_SCHEMA = {

@injectable()
export class TheiaPluginScanner implements PluginScanner {

private readonly _apiType: PluginEngine = 'theiaPlugin';

@inject(GrammarsReader)
Expand All @@ -97,7 +98,8 @@ export class TheiaPluginScanner implements PluginScanner {
entryPoint: {
frontend: plugin.theiaPlugin!.frontend,
backend: plugin.theiaPlugin!.backend
}
},
extensionDependencies: plugin.extensionDependencies || []
};
result.contributes = this.readContributions(plugin);
return result;
Expand Down
100 changes: 59 additions & 41 deletions packages/plugin-ext/src/main/node/plugin-deployer-impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,6 @@ export class PluginDeployerImpl implements PluginDeployer {
@inject(PluginCliContribution)
protected readonly cliContribution: PluginCliContribution;

/**
* Deployer entries.
*/
private pluginDeployerEntries: PluginDeployerEntry[];

/**
* Inject all plugin resolvers found at runtime.
*/
Expand Down Expand Up @@ -114,25 +109,55 @@ export class PluginDeployerImpl implements PluginDeployer {
}

protected async deployMultipleEntries(pluginEntries: string[]): Promise<void> {
// resolve plugins
this.pluginDeployerEntries = await this.resolvePlugins(pluginEntries);

// now that we have plugins check if we have File Handler for them
await this.applyFileHandlers();
const deployedPlugins = new Set<string>();

/**
* Iterate over all the plugins, resolving them one at a time and adding
* in extension dependencies
*/
const futurePlugins = [];
while (pluginEntries.length !== 0) {
const currentPlugin = pluginEntries.pop() as string;
if (deployedPlugins.has(currentPlugin)) {
continue;
}

// resolve plugins
const pluginDeployerEntries = await this.resolvePlugin(currentPlugin);

// ok now ask for directory handlers
await this.applyDirectoryFileHandlers();
// now that we have plugins check if we have File Handler for them
await this.applyFileHandlers(pluginDeployerEntries);

// ok now ask for directory handlers
await this.applyDirectoryFileHandlers(pluginDeployerEntries);

// add current plugin deployer entries first because dependencies to be installed first
futurePlugins.unshift(...pluginDeployerEntries);

deployedPlugins.add(currentPlugin);

// gather all dependencies needed for current plugin
for (const deployerEntry of pluginDeployerEntries) {
const deployDependencies = await this.pluginDeployerHandler.getPluginDependencies(deployerEntry);
pluginEntries.push(...deployDependencies);
}

}

await this.deployPlugins(futurePlugins);

return Promise.resolve();

await this.deployPlugins();
}

/**
* deploy all plugins that have been accepted
*/
async deployPlugins(): Promise<any> {
const acceptedPlugins = this.pluginDeployerEntries.filter(pluginDeployerEntry => pluginDeployerEntry.isAccepted());
const acceptedFrontendPlugins = this.pluginDeployerEntries.filter(pluginDeployerEntry => pluginDeployerEntry.isAccepted(PluginDeployerEntryType.FRONTEND));
const acceptedBackendPlugins = this.pluginDeployerEntries.filter(pluginDeployerEntry => pluginDeployerEntry.isAccepted(PluginDeployerEntryType.BACKEND));
async deployPlugins(pluginsToDeploy: PluginDeployerEntry[]): Promise<any> {
const acceptedPlugins = pluginsToDeploy.filter(pluginDeployerEntry => pluginDeployerEntry.isAccepted());
const acceptedFrontendPlugins = pluginsToDeploy.filter(pluginDeployerEntry => pluginDeployerEntry.isAccepted(PluginDeployerEntryType.FRONTEND));
const acceptedBackendPlugins = pluginsToDeploy.filter(pluginDeployerEntry => pluginDeployerEntry.isAccepted(PluginDeployerEntryType.BACKEND));

this.logger.debug('the accepted plugins are', acceptedPlugins);
this.logger.debug('the acceptedFrontendPlugins plugins are', acceptedFrontendPlugins);
Expand All @@ -157,10 +182,10 @@ export class PluginDeployerImpl implements PluginDeployer {
/**
* If there are some single files, try to see if we can work on these files (like unpacking it, etc)
*/
public async applyFileHandlers(): Promise<any> {
public async applyFileHandlers(pluginDeployerEntries: PluginDeployerEntry[]): Promise<any> {
const waitPromises: Array<Promise<any>> = [];

this.pluginDeployerEntries.filter(pluginDeployerEntry => pluginDeployerEntry.isResolved()).map(pluginDeployerEntry => {
pluginDeployerEntries.filter(pluginDeployerEntry => pluginDeployerEntry.isResolved()).map(pluginDeployerEntry => {
this.pluginDeployerFileHandlers.map(pluginFileHandler => {
const proxyPluginDeployerEntry = new ProxyPluginDeployerEntry(pluginFileHandler, (pluginDeployerEntry) as PluginDeployerEntryImpl);
if (pluginFileHandler.accept(proxyPluginDeployerEntry)) {
Expand All @@ -177,10 +202,10 @@ export class PluginDeployerImpl implements PluginDeployer {
/**
* Check for all registered directories to see if there are some plugins that can be accepted to be deployed.
*/
public async applyDirectoryFileHandlers(): Promise<any> {
public async applyDirectoryFileHandlers(pluginDeployerEntries: PluginDeployerEntry[]): Promise<any> {
const waitPromises: Array<Promise<any>> = [];

this.pluginDeployerEntries.filter(pluginDeployerEntry => pluginDeployerEntry.isResolved()).map(pluginDeployerEntry => {
pluginDeployerEntries.filter(pluginDeployerEntry => pluginDeployerEntry.isResolved()).map(pluginDeployerEntry => {
this.pluginDeployerDirectoryHandlers.map(pluginDirectoryHandler => {
const proxyPluginDeployerEntry = new ProxyPluginDeployerEntry(pluginDirectoryHandler, (pluginDeployerEntry) as PluginDeployerEntryImpl);
if (pluginDirectoryHandler.accept(proxyPluginDeployerEntry)) {
Expand All @@ -195,32 +220,25 @@ export class PluginDeployerImpl implements PluginDeployer {
}

/**
* Check a given set of plugin IDs to see if there are some resolvers that can handle them. If there is a matching resolver, then we resolve the plugin
* Check a plugin ID see if there are some resolvers that can handle it. If there is a matching resolver, then we resolve the plugin
*/
public async resolvePlugins(pluginIdList: string[]): Promise<PluginDeployerEntry[]> {
public async resolvePlugin(pluginId: string): Promise<PluginDeployerEntry[]> {
const pluginDeployerEntries: PluginDeployerEntry[] = [];
const foundPluginResolver = this.pluginResolvers.find(pluginResolver => pluginResolver.accept(pluginId));
// there is a resolver for the input
if (foundPluginResolver) {

// check if accepted ?
const promises = pluginIdList.map(async pluginId => {
// create context object
const context = new PluginDeployerResolverContextImpl(foundPluginResolver, pluginId);

const foundPluginResolver = this.pluginResolvers.find(pluginResolver => pluginResolver.accept(pluginId));
// there is a resolver for the input
if (foundPluginResolver) {
await foundPluginResolver.resolve(context);

// create context object
const context = new PluginDeployerResolverContextImpl(foundPluginResolver, pluginId);

await foundPluginResolver.resolve(context);

context.getPlugins().forEach(entry => pluginDeployerEntries.push(entry));
} else {
// log it for now
this.logger.error('No plugin resolver found for the entry', pluginId);
pluginDeployerEntries.push(new PluginDeployerEntryImpl(pluginId, pluginId));
}
// you can do other stuff with the `item` here
});
await Promise.all(promises);
context.getPlugins().forEach(entry => pluginDeployerEntries.push(entry));
} else {
// log it for now
this.logger.error('No plugin resolver found for the entry', pluginId);
pluginDeployerEntries.push(new PluginDeployerEntryImpl(pluginId, pluginId));
}

return pluginDeployerEntries;
}
Expand Down

0 comments on commit 2d4c845

Please sign in to comment.