mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-03-18 11:03:18 -04:00
* Initial changes * Round trip feature implementation * Addressed PR comments * Addressed comments
162 lines
6.7 KiB
TypeScript
162 lines
6.7 KiB
TypeScript
/*---------------------------------------------------------------------------------------------
|
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
|
*--------------------------------------------------------------------------------------------*/
|
|
|
|
import * as vscode from 'vscode';
|
|
import * as path from 'path';
|
|
import * as fs from 'fs';
|
|
import * as os from 'os';
|
|
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';
|
|
export const NetCoreInstallLocationKey: string = 'netCoreSDKLocation';
|
|
export const NextCoreNonWindowsDefaultPath = '/usr/local/share';
|
|
export const NetCoreInstallationConfirmation: string = localize('sqlDatabaseProjects.NetCoreInstallationConfirmation', "The .NET Core SDK cannnot be located. Project build will not work. Please install the same or update the .Net Core SDK location in settings if already installed.");
|
|
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 {
|
|
|
|
private _outputChannel: vscode.OutputChannel = vscode.window.createOutputChannel(projectsOutputChannel);
|
|
|
|
public findOrInstallNetCore(): boolean {
|
|
if (!this.isNetCoreInstallationPresent) {
|
|
this.showInstallDialog();
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private showInstallDialog(): void {
|
|
vscode.window.showInformationMessage(NetCoreInstallationConfirmation, UpdateNetCoreLocation, InstallNetCore).then(async (result) => {
|
|
if (result === UpdateNetCoreLocation) {
|
|
//open settings
|
|
vscode.commands.executeCommand('workbench.action.openGlobalSettings');
|
|
}
|
|
else if (result === InstallNetCore) {
|
|
//open install link
|
|
const dotnetcoreURL = 'https://dotnet.microsoft.com/download/dotnet-core/3.1';
|
|
vscode.env.openExternal(vscode.Uri.parse(dotnetcoreURL));
|
|
}
|
|
});
|
|
}
|
|
|
|
private get isNetCoreInstallationPresent(): Boolean {
|
|
return (!isNullOrUndefined(this.netcoreInstallLocation) && fs.existsSync(this.netcoreInstallLocation));
|
|
}
|
|
|
|
public get netcoreInstallLocation(): string {
|
|
return vscode.workspace.getConfiguration(DBProjectConfigurationKey)[NetCoreInstallLocationKey] ||
|
|
this.defaultLocalInstallLocationByDistribution;
|
|
}
|
|
|
|
private get defaultLocalInstallLocationByDistribution(): string | undefined {
|
|
const osPlatform: string = os.platform();
|
|
return (osPlatform === 'win32') ? this.defaultWindowsLocation :
|
|
(osPlatform === 'darwin' || osPlatform === 'linux') ? this.defaultnonWindowsLocation :
|
|
undefined;
|
|
}
|
|
|
|
private get defaultnonWindowsLocation(): string | undefined {
|
|
const defaultNonWindowsInstallLocation = NextCoreNonWindowsDefaultPath; //default folder for net core sdk
|
|
return this.getDotnetPathIfPresent(defaultNonWindowsInstallLocation) ||
|
|
this.getDotnetPathIfPresent(os.homedir()) ||
|
|
undefined;
|
|
}
|
|
|
|
private get defaultWindowsLocation(): string | undefined {
|
|
return this.getDotnetPathIfPresent(process.env['ProgramW6432']) ||
|
|
this.getDotnetPathIfPresent(process.env['ProgramFiles(x86)']) ||
|
|
this.getDotnetPathIfPresent(process.env['ProgramFiles']);
|
|
}
|
|
|
|
private getDotnetPathIfPresent(folderPath: string | undefined): string | undefined {
|
|
if (!isNullOrUndefined(folderPath) && fs.existsSync(path.join(folderPath, 'dotnet'))) {
|
|
return path.join(folderPath, 'dotnet');
|
|
}
|
|
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 arguments 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);
|
|
});
|
|
}
|
|
}
|