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

Export configurations from devfile in a launch.json and tasks.json files #218

Merged
merged 1 commit into from
May 24, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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"
}
}
7 changes: 7 additions & 0 deletions plugins/task-plugin/src/che-task-backend-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,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 @@ -36,6 +39,10 @@ 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(PreviewUrlsWidget).toSelf().inTransientScope();
container.bind(PreviewUrlsWidgetFactory).toDynamicValue(ctx => ({
createWidget: (options: PreviewUrlsWidgetOptions) => {
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/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