Skip to content

Watch view implementation to track running 'odo watch' commands #1612

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jul 6, 2020
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
24 changes: 24 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,8 @@
"onCommand:openshift.component.push.palette",
"onCommand:openshift.component.watch",
"onCommand:openshift.component.watch.palette",
"onCommand:openshift.component.watch.terminate",
"onCommand:openshift.component.watch.showLog",
"onCommand:openshift.catalog.listComponents",
"onCommand:openshift.catalog.listServices",
"onCommand:openshift.url.create",
Expand Down Expand Up @@ -434,6 +436,16 @@
"title": "Link Service",
"category": "OpenShift"
},
{
"command": "openshift.component.watch.terminate",
"title": "Stop",
"category": "OpenShift"
},
{
"command": "openshift.component.watch.showLog",
"title": "Show Log",
"category": "OpenShift"
},
{
"command": "openshift.openshiftConsole",
"title": "Open Console Dashboard",
Expand Down Expand Up @@ -712,6 +724,10 @@
{
"id": "openshiftProjectExplorer",
"name": "Application Explorer"
},
{
"id": "openshiftWatchView",
"name": "Watch Sessions"
}
]
},
Expand Down Expand Up @@ -1143,6 +1159,14 @@
{
"command": "openshift.explorer.login.credentialsLogin",
"when": "view == openshiftProjectExplorer && viewItem == loginRequired"
},
{
"command": "openshift.component.watch.terminate",
"when": "view == openshiftWatchView && viewItem == openshift.watch.process"
},
{
"command": "openshift.component.watch.showLog",
"when": "view == openshiftWatchView && viewItem == openshift.watch.process"
}
]
},
Expand Down
2 changes: 2 additions & 0 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { TokenStore } from './util/credentialManager';
import { registerCommands } from './vscommand';
import { ToolsConfig } from './tools';
import { extendClusterExplorer } from './k8s/clusterExplorer';
import { WatchSessionsView } from './watch';

import path = require('path');
import fsx = require('fs-extra');
Expand Down Expand Up @@ -68,6 +69,7 @@ export async function activate(extensionContext: ExtensionContext): Promise<any>
commands.executeCommand('extension.vsKubernetesUseNamespace', context),
),
OpenShiftExplorer.getInstance(),
WatchSessionsView.getInstance(),
...Component.init(extensionContext)
];
disposable.forEach((value) => extensionContext.subscriptions.push(value));
Expand Down
29 changes: 22 additions & 7 deletions src/odo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export interface OpenShiftObject extends QuickPickItem {
contextPath?: Uri;
path?: string;
builderImage?: BuilderImage;
iconPath?: Uri;
}

export enum ContextType {
Expand Down Expand Up @@ -76,10 +77,20 @@ export abstract class OpenShiftObjectImpl implements OpenShiftObject {
public readonly icon: string,
// eslint-disable-next-line no-shadow
public readonly collapsibleState: TreeItemCollapsibleState = Collapsed,
public contextPath: Uri = undefined,
private contextPathValue: Uri = undefined,
public readonly compType: string = undefined,
public readonly builderImage: BuilderImage = undefined) {
OdoImpl.data.setPathToObject(this);
OdoImpl.data.setContextToObject(this);
}

set contextPath(cp: Uri) {
this.contextPathValue = cp;
OdoImpl.data.setContextToObject(this);
}

get contextPath(): Uri {
return this.contextPathValue;
}

get path(): string {
Expand Down Expand Up @@ -290,6 +301,7 @@ export interface Odo {
deleteService(service: OpenShiftObject): Promise<OpenShiftObject>;
deleteURL(url: OpenShiftObject): Promise<OpenShiftObject>;
createComponentCustomUrl(component: OpenShiftObject, name: string, port: string, secure?: boolean): Promise<OpenShiftObject>;
getOpenShiftObjectByContext(context: string): OpenShiftObject;
readonly subject: Subject<OdoEvent>;
}

Expand All @@ -307,7 +319,7 @@ class OdoModel {

private pathToObject = new Map<string, OpenShiftObject>();

private contextToObject = new Map<Uri, OpenShiftObject>();
private contextToObject = new Map<string, OpenShiftObject>();

private contextToSettings = new Map<string, odo.Component>();

Expand Down Expand Up @@ -342,14 +354,14 @@ class OdoModel {

public setContextToObject(object: OpenShiftObject): void {
if (object.contextPath) {
if (!this.contextToObject.has(object.contextPath)) {
this.contextToObject.set(object.contextPath, object );
if (!this.contextToObject.has(object.contextPath.fsPath)) {
this.contextToObject.set(object.contextPath.fsPath, object );
}
}
}

public getObjectByContext(context: Uri): OpenShiftObject {
return this.contextToObject.get(context);
return this.contextToObject.get(context.fsPath);
}

public setContextToSettings (settings: odo.Component): void {
Expand Down Expand Up @@ -392,7 +404,7 @@ class OdoModel {
const array = await item.getParent().getChildren();
array.splice(array.indexOf(item), 1);
this.pathToObject.delete(item.path);
this.contextToObject.delete(item.contextPath);
this.contextToObject.delete(item.contextPath.fsPath);
}

public deleteContext(context: string): void {
Expand Down Expand Up @@ -933,6 +945,10 @@ export class OdoImpl implements Odo {
this.subject.next(new OdoEventImpl('changed', null));
}

getOpenShiftObjectByContext(context: string): OpenShiftObject {
return OdoImpl.data.getObjectByContext(Uri.file(context));
}

async loadWorkspaceComponents(event: WorkspaceFoldersChangeEvent): Promise<void> {
const clusters = (await this.getClusters());
if(!clusters) return;
Expand Down Expand Up @@ -1009,7 +1025,6 @@ export class OdoImpl implements Odo {
if ((result2.stdout !== '' && sis.length > 0) || (result1.stdout !== '' && dcs.length > 0)) {
projectsToMigrate.push(project);
}

}
if (projectsToMigrate.length > 0) {
const choice = await window.showWarningMessage(`Found the resources in cluster that must be updated to work with latest release of OpenShift Connector Extension.`, 'Update', 'Help', 'Cancel');
Expand Down
54 changes: 52 additions & 2 deletions src/openshift/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import { window, commands, QuickPickItem, Uri, workspace, ExtensionContext, debug, DebugConfiguration, extensions, ProgressLocation, DebugSession, Disposable } from 'vscode';
import { ChildProcess , exec } from 'child_process';
import { isURL } from 'validator';
import { Subject } from 'rxjs';
import OpenShiftItem, { selectTargetApplication, selectTargetComponent } from './openshiftItem';
import { OpenShiftObject, ContextType } from '../odo';
import { Command } from "../odo/command";
Expand All @@ -30,9 +31,17 @@ import treeKill = require('tree-kill');

const waitPort = require('wait-port');

export class ComponentEvent {
readonly type: 'watchStarted' | 'watchTerminated';
readonly component: OpenShiftObject;
readonly process?: ChildProcess;
}

export class Component extends OpenShiftItem {
public static extensionContext: ExtensionContext;
public static debugSessions: Map<string, DebugSession> = new Map();
public static watchSessions: Map<string, ChildProcess> = new Map();
public static readonly watchSubject: Subject<ComponentEvent> = new Subject<ComponentEvent>();

public static init(context: ExtensionContext): Disposable[] {
Component.extensionContext = context;
Expand All @@ -57,6 +66,13 @@ export class Component extends OpenShiftItem {
}
}

static stopWatchSession(component: OpenShiftObject): void {
const ws = Component.watchSessions.get(component.contextPath.fsPath);
if (ws) {
treeKill(ws.pid);
}
}

static async getOpenshiftData(context: OpenShiftObject): Promise<OpenShiftObject> {
return Component.getOpenShiftCmdData(context,
"In which Project you want to create a Component",
Expand Down Expand Up @@ -119,6 +135,7 @@ export class Component extends OpenShiftItem {
await Component.unlinkAllComponents(component);
}
Component.stopDebugSession(component);
Component.stopWatchSession(component);
await Component.odo.deleteComponent(component);

}).then(() => `Component '${name}' successfully deleted`)
Expand All @@ -140,6 +157,7 @@ export class Component extends OpenShiftItem {
if (value === 'Yes') {
return Progress.execFunctionWithProgress(`Undeploying the Component '${component.getName()} '`, async () => {
Component.stopDebugSession(component);
Component.stopWatchSession(component);
await Component.odo.undeployComponent(component);
}).then(() => `Component '${name}' successfully undeployed`)
.catch((err) => Promise.reject(new VsCommandError(`Failed to undeploy Component with error '${err}'`)));
Expand Down Expand Up @@ -451,16 +469,48 @@ export class Component extends OpenShiftItem {
}
}

static addWatchSession(component: OpenShiftObject, process: ChildProcess): void {
Component.watchSessions.set(component.contextPath.fsPath, process);
Component.watchSubject.next({
type: 'watchStarted',
component,
process
});
}

static removeWatchSession(component: OpenShiftObject): void {
Component.watchSessions.delete(component.contextPath.fsPath);
Component.watchSubject.next({
type: 'watchTerminated',
component
});
}

@vsCommand('openshift.component.watch', true)
@selectTargetComponent(
'Select a Project',
'Select an Application',
'Select a Component you want to watch',
(target) => target.contextValue === ContextType.COMPONENT_PUSHED
)
static watch(component: OpenShiftObject): Promise<void> {
static async watch(component: OpenShiftObject): Promise<void> {
if (!component) return null;
Component.odo.executeInTerminal(Command.watchComponent(component.getParent().getParent().getName(), component.getParent().getName(), component.getName()), component.contextPath.fsPath, `OpenShift: Watch '${component.getName()}' Component`);
if (component.compType !== SourceType.LOCAL && component.compType !== SourceType.BINARY) {
window.showInformationMessage(`Watch is supported only for Components with local or binary source type.`)
return null;
}
if (Component.watchSessions.get(component.contextPath.fsPath)) {
const sel = await window.showInformationMessage(`Watch process is already running for '${component.getName()}'`, 'Show Log');
if (sel === 'Show Log') {
commands.executeCommand('openshift.component.watch.showLog', component.contextPath.fsPath);
}
} else {
const process: ChildProcess = await Component.odo.spawn(Command.watchComponent(component.getParent().getParent().getName(), component.getParent().getName(), component.getName()), component.contextPath.fsPath);
Component.addWatchSession(component, process);
process.on('exit', () => {
Component.removeWatchSession(component);
});
}
}

@vsCommand('openshift.component.openUrl', true)
Expand Down
15 changes: 9 additions & 6 deletions src/view/log/LogViewLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@ import { ExtenisonID } from '../../util/constants';
import { OpenShiftObject } from '../../odo';
import * as odo from '../../odo';
import treeKill = require('tree-kill');
import { ChildProcess } from 'child_process';

export default class LogViewLoader {

static get extensionPath() {
return vscode.extensions.getExtension(ExtenisonID).extensionPath
}

static async loadView(title: string, cmdFunction: (prj, app, comp) => string, target: OpenShiftObject): Promise<vscode.WebviewPanel> {
static async loadView(title: string, cmdFunction: (prj, app, comp) => string, target: OpenShiftObject, existingProcess?: ChildProcess): Promise<vscode.WebviewPanel> {
const localResourceRoot = vscode.Uri.file(path.join(LogViewLoader.extensionPath, 'out', 'logViewer'));

const panel = vscode.window.createWebviewPanel('logView', title, vscode.ViewColumn.One, {
Expand All @@ -29,9 +30,9 @@ export default class LogViewLoader {
const cmd = cmdFunction(target.getParent().getParent().getName(), target.getParent().getName(), target.getName());

// TODO: When webview is going to be ready?
panel.webview.html = LogViewLoader.getWebviewContent(LogViewLoader.extensionPath, cmd);
panel.webview.html = LogViewLoader.getWebviewContent(LogViewLoader.extensionPath, cmd.replace(/\\/g, '\\\\'));

const process = await odo.getInstance().spawn(cmd, target.contextPath.fsPath);
const process = existingProcess? existingProcess : await odo.getInstance().spawn(cmd, target.contextPath.fsPath);
process.stdout.on('data', (data) => {
panel.webview.postMessage({action: 'add', data: `${data}`.trim().split('\n')});
}).on('close', ()=>{
Expand All @@ -43,9 +44,11 @@ export default class LogViewLoader {
recieveDisposable.dispose();
}
})
const disposable = panel.onDidDispose(()=> {
treeKill(process.pid);
disposable.dispose();
panel.onDidDispose(()=> {
process.stdout.removeAllListeners();
if(!existingProcess) {
treeKill(process.pid);
}
});
return panel;
}
Expand Down
3 changes: 2 additions & 1 deletion src/view/log/app/spinner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,9 @@ declare global {
}
}

const vscode = window.acquireVsCodeApi();

function stop() {
const vscode = window.acquireVsCodeApi();
vscode.postMessage({action: 'stop'});
}

Expand Down
Loading