Feature/project build (#10332)

* initial build command execution

* adding tests

* Clean up test names

* update SqltoolsService release in ADS for Build

* Updating as per PR comments

* updating yarn lock

* Adding one more test for command run

* Test fixes
This commit is contained in:
Udeesha Gautam
2020-05-12 20:17:37 -07:00
committed by GitHub
parent ab374e362a
commit ddb9a806cc
13 changed files with 319 additions and 22 deletions

View File

@@ -7,8 +7,10 @@ import * as vscode from 'vscode';
import * as path from 'path';
import * as fs from 'fs';
import * as os from 'os';
import { isNullOrUndefined } from 'util';
import * as cp from 'promisify-child-process';
import * as nls from 'vscode-nls';
import { isNullOrUndefined } from 'util';
import * as utils from '../common/utils';
const localize = nls.loadMessageBundle();
export const DBProjectConfigurationKey: string = 'sqlDatabaseProjects';
@@ -18,12 +20,26 @@ export const NetCoreInstallationConfirmation: string = localize('sqlDatabaseProj
export const UpdateNetCoreLocation: string = localize('sqlDatabaseProjects.UpdateNetCoreLocation', "Update .Net Core location");
export const InstallNetCore: string = localize('sqlDatabaseProjects.InstallNetCore', "Install .Net Core SDK");
const projectsOutputChannel = localize('sqlDatabaseProjects.outputChannel', "Database Projects");
const dotnet = os.platform() === 'win32' ? 'dotnet.exe' : 'dotnet';
export interface DotNetCommandOptions {
workingDirectory?: string;
additionalEnvironmentVariables?: NodeJS.ProcessEnv;
commandTitle?: string;
argument?: string;
}
export class NetCoreTool {
public findOrInstallNetCore(): void {
private _outputChannel: vscode.OutputChannel = vscode.window.createOutputChannel(projectsOutputChannel);
public findOrInstallNetCore(): boolean {
if (!this.isNetCoreInstallationPresent) {
this.showInstallDialog();
return false;
}
return true;
}
private showInstallDialog(): void {
@@ -40,7 +56,7 @@ export class NetCoreTool {
});
}
public get isNetCoreInstallationPresent(): Boolean {
private get isNetCoreInstallationPresent(): Boolean {
return (!isNullOrUndefined(this.netcoreInstallLocation) && fs.existsSync(this.netcoreInstallLocation));
}
@@ -75,4 +91,71 @@ export class NetCoreTool {
}
return undefined;
}
public async runDotnetCommand(options: DotNetCommandOptions): Promise<string> {
if (options && options.commandTitle !== undefined && options.commandTitle !== null) {
this._outputChannel.appendLine(`\t[ ${options.commandTitle} ]`);
}
if (!this.findOrInstallNetCore()) {
throw new Error(NetCoreInstallationConfirmation);
}
const dotnetPath = utils.getSafePath(path.join(this.netcoreInstallLocation, dotnet));
const command = dotnetPath + ' ' + options.argument;
try {
return await this.runStreamedCommand(command, this._outputChannel, options);
} catch (error) {
this._outputChannel.append(localize('sqlDatabaseProject.RunCommand.ErroredOut', "\t>>> {0} … errored out: {1}", command, utils.getErrorMessage(error))); //errors are localized in our code where emitted, other errors are pass through from external components that are not easily localized
throw error;
}
}
// spawns the dotnet command with aruments and redirects the error and output to ADS output channel
public async runStreamedCommand(command: string, outputChannel: vscode.OutputChannel, options?: DotNetCommandOptions): Promise<string> {
const stdoutData: string[] = [];
outputChannel.appendLine(` > ${command}`);
const spawnOptions = {
cwd: options && options.workingDirectory,
env: Object.assign({}, process.env, options && options.additionalEnvironmentVariables),
encoding: 'utf8',
maxBuffer: 10 * 1024 * 1024, // 10 Mb of output can be captured.
shell: true,
detached: false,
windowsHide: true
};
const child = cp.spawn(command, [], spawnOptions);
outputChannel.show();
// Add listeners to print stdout and stderr and exit code
child.on('exit', (code: number | null, signal: string | null) => {
if (code !== null) {
outputChannel.appendLine(localize('sqlDatabaseProjects.RunStreamedCommand.ExitedWithCode', " >>> {0} … exited with code: {1}", command, code));
} else {
outputChannel.appendLine(localize('sqlDatabaseProjects.RunStreamedCommand.ExitedWithSignal', " >>> {0} … exited with signal: {1}", command, signal));
}
});
child.stdout!.on('data', (data: string | Buffer) => {
stdoutData.push(data.toString());
this.outputDataChunk(data, outputChannel, localize('sqlDatabaseProjects.RunCommand.stdout', " stdout: "));
});
child.stderr!.on('data', (data: string | Buffer) => {
this.outputDataChunk(data, outputChannel, localize('sqlDatabaseProjects.RunCommand.stderr', " stderr: "));
});
await child;
return stdoutData.join('');
}
private outputDataChunk(data: string | Buffer, outputChannel: vscode.OutputChannel, header: string): void {
data.toString().split(/\r?\n/)
.forEach(line => {
outputChannel.appendLine(header + line);
});
}
}