Skip to content

Commit 2dd1e81

Browse files
committed
[WIP] fix cli -> tools cycle
Signed-off-by: David Thompson <davthomp@redhat.com>
1 parent dd788ac commit 2dd1e81

File tree

19 files changed

+191
-173
lines changed

19 files changed

+191
-173
lines changed

src/cli.ts

Lines changed: 4 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -8,76 +8,15 @@ import * as cp from 'child_process';
88
import * as vscode from 'vscode';
99
import { CommandText } from './base/command';
1010
import { ToolsConfig } from './tools';
11-
import { Filters } from './util/filters';
11+
import { ChildProcessUtil, CliExitData } from './util/childProcessUtil';
1212
import { WindowUtil } from './util/windowUtils';
1313
import { VsCommandError } from './vscommand';
1414

15-
export interface CliExitData {
16-
readonly error: cp.ExecException;
17-
readonly stdout: string;
18-
readonly stderr: string;
19-
readonly cwd?: string;
20-
}
21-
22-
export interface Cli {
23-
execute(cmd: string, opts?: cp.ExecOptions): Promise<CliExitData>;
24-
executeTool(command: CommandText, opts?: cp.ExecOptions): Promise<CliExitData>;
25-
spawn(cmd: string, params: string[], opts: cp.SpawnOptions): cp.ChildProcess;
26-
spawnTool(cmd: CommandText, opts: cp.SpawnOptions): Promise<cp.ChildProcess>;
27-
executeInTerminal(cmd: CommandText, cwd: string, terminalName: string): void;
28-
}
29-
30-
export interface OdoChannel {
31-
print(text: string): void;
32-
show(): void;
33-
}
34-
35-
function prettifyJson(str: string): string {
36-
let jsonData: string;
37-
try {
38-
jsonData = JSON.stringify(JSON.parse(str), null, 2);
39-
} catch (ignore) {
40-
const hidePass = Filters.filterToken(str);
41-
return Filters.filterPassword(hidePass);
42-
}
43-
return jsonData;
44-
}
45-
46-
class OdoChannelImpl implements OdoChannel {
47-
private readonly channel: vscode.OutputChannel = vscode.window.createOutputChannel('OpenShift');
48-
49-
show(): void {
50-
this.channel.show();
51-
}
52-
53-
print(text: string): void {
54-
const textData = prettifyJson(text);
55-
this.channel.append(textData);
56-
if (!textData.endsWith('\n')) {
57-
this.channel.append('\n');
58-
}
59-
if (
60-
vscode.workspace
61-
.getConfiguration('openshiftToolkit')
62-
.get<boolean>('showChannelOnOutput')
63-
) {
64-
this.channel.show();
65-
}
66-
}
67-
}
68-
69-
// TODO Refactor to OdoCli or OpenShiftCli class
70-
// This is Cli interface implementation that lets
71-
// execute commands and prints commands and output
72-
// to an output channel
73-
74-
export class CliChannel implements Cli {
15+
export class CliChannel {
7516

7617
private static telemetrySettings = new VSCodeSettings();
7718
private static instance: CliChannel;
7819

79-
private odoChannel: OdoChannel = new OdoChannelImpl();
80-
8120
static getInstance(): CliChannel {
8221
if (!CliChannel.instance) {
8322
CliChannel.instance = new CliChannel();
@@ -86,34 +25,9 @@ export class CliChannel implements Cli {
8625
}
8726

8827
showOutput(): void {
89-
this.odoChannel.show();
90-
}
91-
92-
execute(cmd: string, opts: cp.ExecOptions = {}): Promise<CliExitData> {
93-
return new Promise<CliExitData>((resolve) => {
94-
if (opts.maxBuffer === undefined) {
95-
opts.maxBuffer = 2 * 1024 * 1024;
96-
}
97-
cp.exec(cmd, opts, (error: cp.ExecException, stdout: string, stderr: string) => {
98-
// filter out info about update
99-
this.odoChannel.print(cmd);
100-
this.odoChannel.print(stdout);
101-
this.odoChannel.print(stderr);
102-
// do not reject it here, because caller in some cases need the error and the streams
103-
// to make a decision
104-
// Filter update message text which starts with `---`
105-
resolve({ error, stdout: stdout.trim(), stderr: stderr.trim(), cwd: opts?.cwd?.toString() });
106-
});
107-
});
28+
ChildProcessUtil.Instance.show();
10829
}
10930

110-
// if (TelemetryConfiguration.getInstance().isEnabled()) {
111-
// this.envVars.put("ODO_TRACKING_CONSENT", "yes");
112-
// this.envVars.put("TELEMETRY_CALLER", "intellij");
113-
// } else {
114-
// this.envVars.put("ODO_TRACKING_CONSENT", "no");
115-
// }
116-
11731
static createTelemetryEnv(): {[key:string]: string} {
11832
const env = {
11933
...process.env,
@@ -145,7 +59,7 @@ export class CliChannel implements Cli {
14559
const [cmd] = commandActual.split(' ');
14660
const toolLocation = await ToolsConfig.detect(cmd);
14761
const optsCopy = CliChannel.applyEnv(opts, CliChannel.createTelemetryEnv())
148-
const result: CliExitData = await this.execute(toolLocation ? commandActual.replace(cmd, `"${toolLocation}"`) : commandActual, optsCopy);
62+
const result: CliExitData = await ChildProcessUtil.Instance.execute(toolLocation ? commandActual.replace(cmd, `"${toolLocation}"`) : commandActual, optsCopy);
14963
if (result.error && fail) {
15064
throw new VsCommandError(`${result.error.message}`, `Error when running command: ${commandPrivacy}`, result.error);
15165
};
@@ -163,10 +77,6 @@ export class CliChannel implements Cli {
16377
terminal.show();
16478
}
16579

166-
spawn(cmd: string, params: string[], opts: cp.SpawnOptions = {cwd: undefined, env: process.env}): cp.ChildProcess {
167-
return cp.spawn(cmd, params, opts);
168-
}
169-
17080
async spawnTool(cmd: CommandText, opts: cp.SpawnOptions = {cwd: undefined, env: process.env}): Promise<cp.ChildProcess> {
17181
const toolLocation = await ToolsConfig.detect(cmd.command);
17282
const optWithTelemetryEnv = CliChannel.applyEnv(opts, CliChannel.createTelemetryEnv());

src/helm/helm.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
* Copyright (c) Red Hat, Inc. All rights reserved.
33
* Licensed under the MIT License. See LICENSE file in the project root for license information.
44
*-----------------------------------------------------------------------------------------------*/
5-
import { CliChannel, CliExitData } from '../cli';
5+
import { CliChannel } from '../cli';
6+
import { CliExitData } from '../util/childProcessUtil';
67
import * as HelmCommands from './helmCommands';
78

89
export type HelmRelease = {

src/k8s/build.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@
55

66
import { QuickPickItem, window } from 'vscode';
77
import { ClusterExplorerV1 } from 'vscode-kubernetes-tools-api';
8+
import { CommandOption, CommandText } from '../base/command';
9+
import { CliChannel } from '../cli';
810
import { Progress } from '../util/progress';
9-
import * as common from './common';
1011
import { vsCommand, VsCommandError } from '../vscommand';
11-
import { CommandOption, CommandText } from '../base/command';
12-
import { Cli, CliChannel } from '../cli';
12+
import * as common from './common';
1313

1414
export class Build {
1515

@@ -56,7 +56,7 @@ export class Build {
5656
}
5757
};
5858

59-
protected static readonly odo: Cli = CliChannel.getInstance();
59+
protected static readonly cli = CliChannel.getInstance();
6060

6161
static getNodeContributor(): ClusterExplorerV1.NodeContributor {
6262
return {
@@ -97,7 +97,7 @@ export class Build {
9797
let result: Promise<string> = null;
9898
if (!buildName) buildName = await common.selectResourceByName(await Build.getBuildConfigNames('You have no BuildConfigs available to start a build'), 'Select a BuildConfig to start a build');
9999
if (buildName) {
100-
result = Progress.execFunctionWithProgress('Starting build', () => Build.odo.executeTool(Build.command.startBuild(buildName)))
100+
result = Progress.execFunctionWithProgress('Starting build', () => Build.cli.executeTool(Build.command.startBuild(buildName)))
101101
.then(() => `Build '${buildName}' successfully started`)
102102
.catch((err) => Promise.reject(new VsCommandError(`Failed to start build with error '${err}'`, 'Failed to start build')));
103103
}
@@ -108,7 +108,7 @@ export class Build {
108108
static async showLog(context: { impl: any}): Promise<string> {
109109
const build = await Build.selectBuild(context, 'Select a Build to see the logs');
110110
if (build) {
111-
Build.odo.executeInTerminal(Build.command.showLog(build, '-build'), undefined, `OpenShift: Show '${build}' Build Log`);
111+
Build.cli.executeInTerminal(Build.command.showLog(build, '-build'), undefined, `OpenShift: Show '${build}' Build Log`);
112112
}
113113
return null;
114114
}
@@ -125,7 +125,7 @@ export class Build {
125125
}
126126
}
127127
if (resourceId) {
128-
Build.odo.executeInTerminal(Build.command.rebuildFrom(resourceId), undefined, `OpenShift: Rebuild '${resourceId}' Build`);
128+
Build.cli.executeInTerminal(Build.command.rebuildFrom(resourceId), undefined, `OpenShift: Rebuild '${resourceId}' Build`);
129129
}
130130
return null;
131131
}
@@ -134,7 +134,7 @@ export class Build {
134134
static async followLog(context: { impl: any}): Promise<string> {
135135
const build = await Build.selectBuild(context, 'Select a build to follow the logs');
136136
if (build) {
137-
Build.odo.executeInTerminal(Build.command.followLog(build, '-build'), undefined, `OpenShift: Follow '${build}' Build Log`);
137+
Build.cli.executeInTerminal(Build.command.followLog(build, '-build'), undefined, `OpenShift: Follow '${build}' Build Log`);
138138
}
139139
return null;
140140
}
@@ -144,7 +144,7 @@ export class Build {
144144
let result: null | string | Promise<string> | PromiseLike<string> = null;
145145
const build = await Build.selectBuild(context, 'Select a build to delete');
146146
if (build) {
147-
result = Progress.execFunctionWithProgress('Deleting build', () => Build.odo.executeTool(Build.command.delete(build)))
147+
result = Progress.execFunctionWithProgress('Deleting build', () => Build.cli.executeTool(Build.command.delete(build)))
148148
.then(() => `Build '${build}' successfully deleted`)
149149
.catch((err) => Promise.reject(new VsCommandError(`Failed to delete build with error '${err}'`, 'Failed to delete build')));
150150
}

src/odo.ts

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,15 @@ import * as fs from 'fs';
1414
import { pathExistsSync } from 'fs-extra';
1515
import * as path from 'path';
1616
import * as tempfile from 'tmp';
17-
import { ProviderResult, QuickPickItem, Terminal, Uri, WorkspaceFolder, commands, workspace } from 'vscode';
17+
import { commands, ProviderResult, QuickPickItem, Terminal, Uri, workspace, WorkspaceFolder } from 'vscode';
1818
import { CommandText } from './base/command';
1919
import * as cliInstance from './cli';
20-
import { CliExitData } from './cli';
2120
import { Command } from './odo/command';
2221
import { AnalyzeResponse, ComponentType, ComponentTypeAdapter, DevfileComponentType, Registry } from './odo/componentType';
2322
import { ComponentDescription } from './odo/componentTypeDescription';
2423
import { Project } from './odo/project';
2524
import { ToolsConfig } from './tools';
25+
import { ChildProcessUtil, CliExitData } from './util/childProcessUtil';
2626
import { KubeConfigUtils } from './util/kubeUtils';
2727
import { Platform } from './util/platform';
2828
import { WindowUtil } from './util/windowUtils';
@@ -58,14 +58,14 @@ export interface Odo {
5858
getProjects(): Promise<Project[]>;
5959
getCompTypesJson():Promise<DevfileComponentType[]>;
6060
getComponentTypes(): Promise<ComponentTypeAdapter[]>;
61-
execute(command: CommandText, cwd?: string, fail?: boolean, addEnv?: any): Promise<cliInstance.CliExitData>;
61+
execute(command: CommandText, cwd?: string, fail?: boolean, addEnv?: any): Promise<CliExitData>;
6262
executeInTerminal(command: CommandText, cwd?: string, name?: string, addEnv?: any): Promise<void>;
6363
requireLogin(): Promise<boolean>;
6464
createProject(name: string): Promise<void>;
6565
deleteProject(projectName: string): Promise<void>;
6666
createComponentFromFolder(type: string, registryName: string, name: string, path: Uri, starterName?: string, useExistingDevfile?: boolean, customDevfilePath?: string): Promise<void>;
6767
createService(formData: any): Promise<void>;
68-
loadItems<I>(result: cliInstance.CliExitData, fetch: (data) => I[]): I[];
68+
loadItems<I>(result: CliExitData, fetch: (data) => I[]): I[];
6969
getRegistries(): Promise<Registry[]>;
7070
addRegistry(name: string, url: string, token: string): Promise<Registry>;
7171
removeRegistry(name: string): Promise<void>;
@@ -118,7 +118,6 @@ export interface Odo {
118118
}
119119

120120
export class OdoImpl implements Odo {
121-
private static cli: cliInstance.Cli = cliInstance.CliChannel.getInstance();
122121

123122
private static instance: Odo;
124123

@@ -130,7 +129,7 @@ export class OdoImpl implements Odo {
130129
}
131130

132131
async getActiveCluster(): Promise<string> {
133-
const result: cliInstance.CliExitData = await this.execute(
132+
const result: CliExitData = await this.execute(
134133
Command.printOdoVersion(), process.cwd(), false
135134
);
136135

@@ -183,15 +182,15 @@ export class OdoImpl implements Odo {
183182
}
184183

185184
public async getCompTypesJson(): Promise<DevfileComponentType[]> {
186-
const result: cliInstance.CliExitData = await this.execute(Command.listCatalogComponentsJson(), undefined, true, this.getKubeconfigEnv());
185+
const result: CliExitData = await this.execute(Command.listCatalogComponentsJson(), undefined, true, this.getKubeconfigEnv());
187186
const componentTypes: DevfileComponentType[] = this.loadJSON(result.stdout);
188187
return componentTypes;
189188
}
190189

191190
public async getComponentTypes(): Promise<ComponentType[]> {
192191
// if kc is produced, KUBECONFIG env var is empty or pointing
193192

194-
const result: cliInstance.CliExitData = await this.execute(Command.listCatalogComponentsJson(), undefined, true, this.getKubeconfigEnv());
193+
const result: CliExitData = await this.execute(Command.listCatalogComponentsJson(), undefined, true, this.getKubeconfigEnv());
195194
const componentTypes: DevfileComponentType[] = this.loadJSON(result.stdout);
196195
const devfileItems: ComponentTypeAdapter[] = [];
197196

@@ -203,7 +202,7 @@ export class OdoImpl implements Odo {
203202
public async describeComponent(contextPath: string, experimental = false): Promise<ComponentDescription | undefined> {
204203
const expEnv = experimental ? {ODO_EXPERIMENTAL_MODE: 'true'} : {};
205204
try {
206-
const describeCmdResult: cliInstance.CliExitData = await this.execute(
205+
const describeCmdResult: CliExitData = await this.execute(
207206
Command.describeComponentJson(), contextPath, false, expEnv
208207
);
209208
return JSON.parse(describeCmdResult.stdout) as ComponentDescription;
@@ -220,13 +219,13 @@ export class OdoImpl implements Odo {
220219
terminal.show();
221220
}
222221

223-
public async execute(command: CommandText, cwd?: string, fail = true, addEnv = {}): Promise<cliInstance.CliExitData> {
222+
public async execute(command: CommandText, cwd?: string, fail = true, addEnv = {}): Promise<CliExitData> {
224223
const env = cliInstance.CliChannel.createTelemetryEnv();
225224
const commandActual = `${command}`;
226225
const commandPrivacy = `${command.privacyMode(true)}`;
227226
const [cmd] = commandActual.split(' ');
228227
const toolLocation = await ToolsConfig.detect(cmd);
229-
const result: cliInstance.CliExitData = await OdoImpl.cli.execute(
228+
const result: CliExitData = await ChildProcessUtil.Instance.execute(
230229
toolLocation ? commandActual.replace(cmd, `"${toolLocation}"`) : commandActual,
231230
cwd ? {cwd, env: {...env, ...addEnv}} : { env: {...env, ...addEnv} }
232231
);
@@ -293,7 +292,7 @@ export class OdoImpl implements Odo {
293292
return parse;
294293
}
295294

296-
public loadItems<I>(result: cliInstance.CliExitData, fetch: (data) => I[] = (data): I[] => data.items): I[] {
295+
public loadItems<I>(result: CliExitData, fetch: (data) => I[] = (data): I[] => data.items): I[] {
297296
let data: I[] = [];
298297
try {
299298
const items = fetch(JSON.parse(result.stdout));
@@ -372,7 +371,7 @@ export class OdoImpl implements Odo {
372371

373372
public async canCreatePod(): Promise<boolean> {
374373
try {
375-
const result: cliInstance.CliExitData = await this.execute(Command.canCreatePod());
374+
const result: CliExitData = await this.execute(Command.canCreatePod());
376375
if (result.stdout === 'yes') {
377376
return true;
378377
}
@@ -384,7 +383,7 @@ export class OdoImpl implements Odo {
384383

385384
public async isPodmanPresent(): Promise<boolean> {
386385
try {
387-
const result: cliInstance.CliExitData = await this.execute(Command.printOdoVersionJson());
386+
const result: CliExitData = await this.execute(Command.printOdoVersionJson());
388387
if ('podman' in JSON.parse(result.stdout)) {
389388
return true;
390389
}

src/odo3.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@
55

66
import { KubernetesObject } from '@kubernetes/client-node';
77
import { CommandText } from './base/command';
8-
import { CliChannel, CliExitData } from './cli';
8+
import { CliChannel } from './cli';
99
import { Command as CommonCommand, loadItems } from './k8s/common';
1010
import { Command as DeploymentCommand } from './k8s/deployment';
1111
import { DeploymentConfig } from './k8s/deploymentConfig';
1212
import { Command } from './odo/command';
1313
import { ComponentDescription } from './odo/componentTypeDescription';
14+
import { CliExitData } from './util/childProcessUtil';
1415

1516
export interface Odo3 {
1617
getNamespaces(): Promise<KubernetesObject[]>;

src/openshift/cluster.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,18 @@
44
*-----------------------------------------------------------------------------------------------*/
55

66
import { KubernetesObject } from '@kubernetes/client-node';
7-
import { ExtensionContext, QuickInputButton, QuickPickItem, QuickPickItemButtonEvent, Terminal, ThemeIcon, Uri, Progress as VProgress, WebviewPanel, commands, env, window, workspace } from 'vscode';
8-
import { CliChannel, CliExitData } from '../cli';
7+
import { commands, env, ExtensionContext, Progress as VProgress, QuickInputButton, QuickPickItem, QuickPickItemButtonEvent, Terminal, ThemeIcon, Uri, WebviewPanel, window, workspace } from 'vscode';
8+
import { CliChannel } from '../cli';
99
import { getInstance } from '../odo';
1010
import { Command } from '../odo/command';
11+
import { CliExitData } from '../util/childProcessUtil';
1112
import { TokenStore } from '../util/credentialManager';
1213
import { Filters } from '../util/filters';
1314
import { KubeConfigUtils } from '../util/kubeUtils';
1415
import { Platform } from '../util/platform';
1516
import { Progress } from '../util/progress';
1617
import { WindowUtil } from '../util/windowUtils';
17-
import { VsCommandError, vsCommand } from '../vscommand';
18+
import { vsCommand, VsCommandError } from '../vscommand';
1819
import ClusterViewLoader from '../webview/cluster/clusterViewLoader';
1920
import OpenShiftItem, { clusterRequired } from './openshiftItem';
2021
import fetch = require('make-fetch-happen');

src/registriesView.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import {
1010
EventEmitter, TreeDataProvider,
1111
TreeItem, TreeItemCollapsibleState, TreeView, Uri, window
1212
} from 'vscode';
13-
import { CliExitData } from './cli';
1413
import { getInstance, Odo, OdoImpl } from './odo';
1514
import { Command } from './odo/command';
1615
import {
@@ -19,6 +18,7 @@ import {
1918
Registry
2019
} from './odo/componentType';
2120
import { StarterProject } from './odo/componentTypeDescription';
21+
import { CliExitData } from './util/childProcessUtil';
2222
import { Progress } from './util/progress';
2323
import { vsCommand, VsCommandError } from './vscommand';
2424
import fetch = require('make-fetch-happen');

0 commit comments

Comments
 (0)