Skip to content
This repository has been archived by the owner on Apr 4, 2023. It is now read-only.

Commit

Permalink
Export tasks and launch configurations in config files of workspace f…
Browse files Browse the repository at this point in the history
…older

Signed-off-by: Roman Nikitenko <rnikiten@redhat.com>
  • Loading branch information
RomanNikitenko committed May 16, 2019
1 parent 6394f35 commit 2704f52
Show file tree
Hide file tree
Showing 11 changed files with 333 additions and 39 deletions.
3 changes: 2 additions & 1 deletion plugins/task-plugin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
"reflect-metadata": "0.1.8",
"vscode-uri": "1.0.5",
"vscode-ws-jsonrpc": "^0.0.2-1",
"ws": "^5.2.2"
"ws": "^5.2.2",
"jsonc-parser": "^2.0.2"
}
}
6 changes: 6 additions & 0 deletions plugins/task-plugin/src/che-task-backend-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ import { PreviewUrlsWidgetFactory, PreviewUrlsWidget, PreviewUrlsWidgetOptions }
import { CheTaskPreviewMode } from './preview/task-preview-mode';
import { PreviewUrlOpenService } from './preview/preview-url-open-service';
import { CheWorkspaceClient } from './che-workspace-client';
import { LaunchConfigurationsExporter } from './export/launch-configs-exporter';
import { TaskConfigurationsExporter } from './export/task-configs-exporter';
import { ConfigurationsExporter, ExportConfigurationsManager } from './export/export-configs-manager';

const container = new Container();
container.bind(CheTaskProvider).toSelf().inSingletonScope();
Expand All @@ -39,6 +42,9 @@ container.bind(ProjectPathVariableResolver).toSelf().inSingletonScope();
container.bind(CheWorkspaceClient).toSelf().inSingletonScope();
container.bind(CheTaskPreviewMode).toSelf().inSingletonScope();
container.bind(PreviewUrlOpenService).toSelf().inSingletonScope();
container.bind<ConfigurationsExporter>(ConfigurationsExporter).to(TaskConfigurationsExporter).inSingletonScope();
container.bind<ConfigurationsExporter>(ConfigurationsExporter).to(LaunchConfigurationsExporter).inSingletonScope();
container.bind(ExportConfigurationsManager).toSelf().inSingletonScope();

container.bind(CheTerminalWidget).toSelf().inTransientScope();
container.bind(TerminalWidgetFactory).toDynamicValue(ctx => ({
Expand Down
82 changes: 82 additions & 0 deletions plugins/task-plugin/src/export/export-configs-manager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*********************************************************************
* Copyright (c) 2019 Red Hat, Inc.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
**********************************************************************/

import { injectable, inject, multiInject } from 'inversify';
import { CheWorkspaceClient } from '../che-workspace-client';
import * as theia from '@theia/plugin';
import { che as cheApi } from '@eclipse-che/api';

export const ConfigurationsExporter = Symbol('ConfigurationsExporter');

/** Exports content with configurations in the config file */
export interface ConfigurationsExporter {

/** Type of the exporter corresponds to type of command which brings content with configs */
readonly type: string;

/**
* Exports given content with configurations in the config file of given workspace folder
* @param configsContent content with configurations for export
* @param workspaceFolder workspace folder for exporting configs in the config file
*/
export(configsContent: string, workspaceFolder: theia.WorkspaceFolder): void;
}

/** Reads the commands from the current Che workspace and exports task and launch configurations in the config files. */
@injectable()
export class ExportConfigurationsManager {

@inject(CheWorkspaceClient)
protected readonly cheWorkspaceClient: CheWorkspaceClient;

@multiInject(ConfigurationsExporter)
protected readonly exporters: ConfigurationsExporter[];

async export() {
const workspaceFolders = theia.workspace.workspaceFolders;
if (!workspaceFolders || workspaceFolders.length < 1) {
return;
}

const cheCommands = await this.cheWorkspaceClient.getCommands();
for (const exporter of this.exporters) {
const configsContent = this.extractConfigsContent(exporter.type, cheCommands);
if (!configsContent) {
continue;
}

this.exportContent(configsContent, exporter, workspaceFolders);
}
}

private exportContent(configsContent: string, exporter: ConfigurationsExporter, workspaceFolders: theia.WorkspaceFolder[]) {
for (const workspaceFolder of workspaceFolders) {
exporter.export(configsContent, workspaceFolder);
}
}

private extractConfigsContent(type: string, commands: cheApi.workspace.Command[]): string {
const configCommands = commands.filter(command => command.type === type);
if (configCommands.length === 0) {
return '';
}

if (configCommands.length > 1) {
console.warn(`Found duplicate entry for type ${type}`);
}

const configCommand = configCommands[0];
if (!configCommand || !configCommand.attributes || !configCommand.attributes.actionReferenceContent) {
return '';
}

return configCommand.attributes.actionReferenceContent;
}
}
64 changes: 64 additions & 0 deletions plugins/task-plugin/src/export/launch-configs-exporter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*********************************************************************
* Copyright (c) 2019 Red Hat, Inc.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
**********************************************************************/

import { injectable } from 'inversify';
import * as theia from '@theia/plugin';
import { resolve } from 'path';
import { readFileSync, writeFileSync, format, modify, parse } from '../utils';
import { ConfigurationsExporter } from './export-configs-manager';

const CONFIG_DIR = '.theia';
const LAUNCH_CONFIG_FILE = 'launch.json';
const formattingOptions = { tabSize: 4, insertSpaces: true, eol: '' };

export const VSCODE_LAUNCH_TYPE = 'vscode-launch';

/** Exports content with launch configurations in the config file. */
@injectable()
export class LaunchConfigurationsExporter implements ConfigurationsExporter {
readonly type: string = VSCODE_LAUNCH_TYPE;

export(configsContent: string, workspaceFolder: theia.WorkspaceFolder): void {
const launchConfigFileUri = this.getConfigFileUri(workspaceFolder.uri.path);
const existingContent = readFileSync(launchConfigFileUri);
if (configsContent === existingContent) {
return;
}

const configsJson = parse(configsContent);
if (!configsJson || !configsJson.configurations) {
return;
}

const existingJson = parse(existingContent);
if (!existingJson || !existingJson.configurations) {
writeFileSync(launchConfigFileUri, format(configsContent, formattingOptions));
return;
}

const mergedConfigs = this.merge(existingJson.configurations, configsJson.configurations);
const result = modify(configsContent, ['configurations'], mergedConfigs, formattingOptions);
writeFileSync(launchConfigFileUri, result);
}

private merge(existingConfigs: theia.DebugConfiguration[], newConfigs: theia.DebugConfiguration[]): theia.DebugConfiguration[] {
const result: theia.DebugConfiguration[] = Object.assign([], newConfigs);
for (const existing of existingConfigs) {
if (!newConfigs.some(config => config.name === existing.name)) {
result.push(existing);
}
}
return result;
}

private getConfigFileUri(rootDir: string): string {
return resolve(rootDir.toString(), CONFIG_DIR, LAUNCH_CONFIG_FILE);
}
}
65 changes: 65 additions & 0 deletions plugins/task-plugin/src/export/task-configs-exporter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*********************************************************************
* Copyright (c) 2019 Red Hat, Inc.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
**********************************************************************/

import { injectable } from 'inversify';
import * as theia from '@theia/plugin';
import { TaskConfiguration } from '@eclipse-che/plugin';
import { resolve } from 'path';
import { readFileSync, writeFileSync, format, modify, parse } from '../utils';
import { ConfigurationsExporter } from './export-configs-manager';

const CONFIG_DIR = '.theia';
const TASK_CONFIG_FILE = 'tasks.json';
const formattingOptions = { tabSize: 4, insertSpaces: true, eol: '' };

export const VSCODE_TASK_TYPE = 'vscode-task';

/** Exports configurations of tasks in the config file. */
@injectable()
export class TaskConfigurationsExporter implements ConfigurationsExporter {
readonly type: string = VSCODE_TASK_TYPE;

export(tasksContent: string, workspaceFolder: theia.WorkspaceFolder): void {
const tasksConfigFileUri = this.getConfigFileUri(workspaceFolder.uri.path);
const existingContent = readFileSync(tasksConfigFileUri);
if (tasksContent === existingContent) {
return;
}

const tasksJson = parse(tasksContent);
if (!tasksJson || !tasksJson.tasks) {
return;
}

const existingJson = parse(existingContent);
if (!existingJson || !existingJson.tasks) {
writeFileSync(tasksConfigFileUri, format(tasksContent, formattingOptions));
return;
}

const mergedConfigs = this.merge(existingJson.tasks, tasksJson.tasks);
const result = modify(tasksContent, ['tasks'], mergedConfigs, formattingOptions);
writeFileSync(tasksConfigFileUri, result);
}

private merge(existingConfigs: TaskConfiguration[], newConfigs: TaskConfiguration[]): TaskConfiguration[] {
const result: TaskConfiguration[] = Object.assign([], newConfigs);
for (const existing of existingConfigs) {
if (!newConfigs.some(config => config.label === existing.label)) {
result.push(existing);
}
}
return result;
}

private getConfigFileUri(rootDir: string): string {
return resolve(rootDir.toString(), CONFIG_DIR, TASK_CONFIG_FILE);
}
}
2 changes: 1 addition & 1 deletion plugins/task-plugin/src/machine/attach-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import { injectable, inject } from 'inversify';
import { CheWorkspaceClient } from '../che-workspace-client';
import { ReconnectingWebSocket } from './websocket';
import { applySegmentsToUri } from '../uri-helper';
import { applySegmentsToUri } from '../utils';
import { MachineExecWatcher } from './machine-exec-watcher';
import * as startPoint from '../task-plugin-backend';

Expand Down
2 changes: 1 addition & 1 deletion plugins/task-plugin/src/machine/machine-exec-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import * as rpc from 'vscode-ws-jsonrpc';
import { injectable, inject, postConstruct } from 'inversify';
import { CheWorkspaceClient } from '../che-workspace-client';
import { createConnection } from './websocket';
import { applySegmentsToUri } from '../uri-helper';
import { applySegmentsToUri } from '../utils';
import { MachineExecWatcher } from './machine-exec-watcher';

const CREATE_METHOD_NAME: string = 'create';
Expand Down
4 changes: 4 additions & 0 deletions plugins/task-plugin/src/task-plugin-backend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { ServerVariableResolver } from './variable/server-variable-resolver';
import { ProjectPathVariableResolver } from './variable/project-path-variable-resolver';
import { CheTaskEventsHandler } from './preview/task-events-handler';
import { TasksPreviewManager } from './preview/tasks-preview-manager';
import { ExportConfigurationsManager } from './export/export-configs-manager';

let pluginContext: theia.PluginContext;

Expand All @@ -44,6 +45,9 @@ export async function start(context: theia.PluginContext) {
const cheTaskRunner = container.get<CheTaskRunner>(CheTaskRunner);
const taskRunnerSubscription = await che.task.registerTaskRunner(CHE_TASK_TYPE, cheTaskRunner);
getSubscriptions().push(taskRunnerSubscription);

const exportConfigurationsManager = container.get<ExportConfigurationsManager>(ExportConfigurationsManager);
exportConfigurationsManager.export();
}

export function stop() { }
Expand Down
7 changes: 6 additions & 1 deletion plugins/task-plugin/src/task/che-task-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import { Task } from '@theia/plugin';
import { CHE_TASK_TYPE, MACHINE_NAME_ATTRIBUTE, PREVIEW_URL_ATTRIBUTE, WORKING_DIR_ATTRIBUTE, CheTaskDefinition, Target } from './task-protocol';
import { MachinesPicker } from '../machine/machines-picker';
import { CheWorkspaceClient } from '../che-workspace-client';
import { VSCODE_LAUNCH_TYPE } from '../export/launch-configs-exporter';
import { VSCODE_TASK_TYPE } from '../export/task-configs-exporter';

/** Reads the commands from the current Che workspace and provides it as Task Configurations. */
@injectable()
Expand All @@ -27,7 +29,10 @@ export class CheTaskProvider {

async provideTasks(): Promise<Task[]> {
const commands = await this.cheWorkspaceClient.getCommands();
return commands.map(command => this.toTask(command));
const filteredCommands = commands.filter(command =>
command.type !== VSCODE_TASK_TYPE &&
command.type !== VSCODE_LAUNCH_TYPE);
return filteredCommands.map(command => this.toTask(command));
}

async resolveTask(task: Task): Promise<Task> {
Expand Down
35 changes: 0 additions & 35 deletions plugins/task-plugin/src/uri-helper.ts

This file was deleted.

Loading

0 comments on commit 2704f52

Please sign in to comment.