diff --git a/extensions/sql-database-projects/package.json b/extensions/sql-database-projects/package.json index 8d51c0365a..d8949c1a2c 100644 --- a/extensions/sql-database-projects/package.json +++ b/extensions/sql-database-projects/package.json @@ -63,6 +63,10 @@ "sqlDatabaseProjects.collapseProjectNodes": { "type": "boolean", "description": "%sqlDatabaseProjects.collapseProjectNodes%" + }, + "sqlDatabaseProjects.microsoftBuildSqlVersion": { + "type": "string", + "description": "%sqlDatabaseProjects.microsoftBuildSqlVersion%" } } } diff --git a/extensions/sql-database-projects/package.nls.json b/extensions/sql-database-projects/package.nls.json index 51dbbbe405..642266a451 100644 --- a/extensions/sql-database-projects/package.nls.json +++ b/extensions/sql-database-projects/package.nls.json @@ -41,5 +41,6 @@ "sqlDatabaseProjects.nodejsDoNotAsk": "Whether to prompt the user to install Node.js when not detected.", "sqlDatabaseProjects.autorestSqlVersion": "Which version of Autorest.Sql to use from NPM. Latest will be used if not set.", "sqlDatabaseProjects.collapseProjectNodes": "Whether project nodes start collapsed", + "sqlDatabaseProjects.microsoftBuildSqlVersion": "Which version of Microsoft.Build.Sql SDK to use for building legacy sql projects. Example: 0.1.3-preview", "sqlDatabaseProjects.welcome": "No database projects currently open.\n[New Project](command:sqlDatabaseProjects.new)\n[Open Project](command:sqlDatabaseProjects.open)\n[Create Project From Database](command:sqlDatabaseProjects.importDatabase)" } diff --git a/extensions/sql-database-projects/src/common/constants.ts b/extensions/sql-database-projects/src/common/constants.ts index 570ab345a2..9bb78519de 100644 --- a/extensions/sql-database-projects/src/common/constants.ts +++ b/extensions/sql-database-projects/src/common/constants.ts @@ -354,6 +354,7 @@ export const parentTreeItemUnknown = localize('parentTreeItemUnknown', "Cannot a export const prePostDeployCount = localize('prePostDeployCount', "To successfully build, update the project to have one pre-deployment script and/or one post-deployment script"); export const invalidProjectReload = localize('invalidProjectReload', "Cannot access provided database project. Only valid, open database projects can be reloaded."); export const externalStreamingJobValidationPassed = localize('externalStreamingJobValidationPassed', "Validation of external streaming job passed."); +export const errorRetrievingBuildFiles = localize('errorRetrievingBuildFiles', "Could not build project. Error retrieving files needed to build."); export function projectAlreadyOpened(path: string) { return localize('projectAlreadyOpened', "Project '{0}' is already opened.", path); } export function projectAlreadyExists(name: string, path: string) { return localize('projectAlreadyExists', "A project named {0} already exists in {1}.", name, path); } export function noFileExist(fileName: string) { return localize('noFileExist', "File {0} doesn't exist", fileName); } @@ -614,7 +615,9 @@ export enum PublishTargetType { newAzureServer = 'newAzureServer' } +// Configuration keys export const CollapseProjectNodesKey = 'collapseProjectNodes'; +export const microsoftBuildSqlVersionKey = 'microsoftBuildSqlVersion'; // httpClient export const downloadError = localize('downloadError', "Download error"); @@ -623,6 +626,7 @@ export const downloading = localize('downloading', "Downloading"); // buildHelper export const downloadingDacFxDlls = localize('downloadingDacFxDlls', "Downloading Microsoft.Build.Sql nuget to get build DLLs"); -export const extractingDacFxDlls = localize('extractingDacFxDlls', "Extracting DacFx build DLLs"); +export function downloadingFromTo(from: string, to: string) { return localize('downloadingFromTo', "Downloading from {0} to {1}", from, to); } +export function extractingDacFxDlls(location: string) { return localize('extractingDacFxDlls', "Extracting DacFx build DLLs to {0}", location); } export function errorDownloading(url: string, error: string) { return localize('errorDownloading', "Error downloading {0}. Error: {1}", url, error); } export function errorExtracting(path: string, error: string) { return localize('errorExtracting', "Error extracting files from {0}. Error: {1}", path, error); } diff --git a/extensions/sql-database-projects/src/controllers/projectController.ts b/extensions/sql-database-projects/src/controllers/projectController.ts index 415044ae40..70c071e907 100644 --- a/extensions/sql-database-projects/src/controllers/projectController.ts +++ b/extensions/sql-database-projects/src/controllers/projectController.ts @@ -238,7 +238,12 @@ export class ProjectsController { // get dlls and targets file needed for building for legacy style projects if (!project.isSdkStyleProject) { - await this.buildHelper.createBuildDirFolder(this._outputChannel); + const result = await this.buildHelper.createBuildDirFolder(this._outputChannel); + + if (!result) { + void vscode.window.showErrorMessage(constants.errorRetrievingBuildFiles); + return ''; + } } const options: ShellCommandOptions = { diff --git a/extensions/sql-database-projects/src/tools/buildHelper.ts b/extensions/sql-database-projects/src/tools/buildHelper.ts index 0a3567590c..85dd889609 100644 --- a/extensions/sql-database-projects/src/tools/buildHelper.ts +++ b/extensions/sql-database-projects/src/tools/buildHelper.ts @@ -11,12 +11,11 @@ import * as sqldbproj from 'sqldbproj'; import * as extractZip from 'extract-zip'; import * as constants from '../common/constants'; import { HttpClient } from '../common/httpClient'; +import { DBProjectConfigurationKey } from './netcoreTool'; const buildDirectory = 'BuildDirectory'; const sdkName = 'Microsoft.Build.Sql'; -const microsoftBuildSqlVersion = '0.1.3-preview'; // TODO: have this be configurable -const fullSdkName = `${sdkName}.${microsoftBuildSqlVersion}`; -const microsoftBuildSqlUrl = `https://www.nuget.org/api/v2/package/${sdkName}/${microsoftBuildSqlVersion}`; +const microsoftBuildSqlDefaultVersion = '0.1.3-preview'; const buildFiles: string[] = [ 'Microsoft.Data.SqlClient.dll', @@ -48,16 +47,21 @@ export class BuildHelper { * Create build dlls directory with the dlls and targets needed for building a sqlproj * @param outputChannel */ - public async createBuildDirFolder(outputChannel: vscode.OutputChannel): Promise { + public async createBuildDirFolder(outputChannel: vscode.OutputChannel): Promise { if (this.initialized) { - return; + return true; } if (!await utils.exists(this.extensionBuildDir)) { await fs.mkdir(this.extensionBuildDir); } + // check if the settings has a version specified for Microsoft.Build.Sql, otherwise use default + const microsoftBuildSqlVersionConfig = vscode.workspace.getConfiguration(DBProjectConfigurationKey)[constants.microsoftBuildSqlVersionKey]; + const sdkVersion = !!microsoftBuildSqlVersionConfig ? microsoftBuildSqlVersionConfig : microsoftBuildSqlDefaultVersion; + const fullSdkName = `${sdkName}.${sdkVersion}`; + // check if this if the nuget needs to be downloaded const nugetPath = path.join(this.extensionBuildDir, `${fullSdkName}.nupkg`); @@ -73,7 +77,7 @@ export class BuildHelper { // if all the files are there, no need to continue if (!missingFiles) { - return; + return true; } } @@ -81,23 +85,26 @@ export class BuildHelper { // download the Microsoft.Build.Sql sdk nuget outputChannel.appendLine(constants.downloadingDacFxDlls); + const microsoftBuildSqlUrl = `https://www.nuget.org/api/v2/package/${sdkName}/${sdkVersion}`; + try { const httpClient = new HttpClient(); + outputChannel.appendLine(constants.downloadingFromTo(microsoftBuildSqlUrl, nugetPath)); await httpClient.download(microsoftBuildSqlUrl, nugetPath, outputChannel); } catch (e) { void vscode.window.showErrorMessage(constants.errorDownloading(microsoftBuildSqlUrl, utils.getErrorMessage(e))); - return; + return false; } // extract the files from the nuget - outputChannel.appendLine(constants.extractingDacFxDlls); const extractedFolderPath = path.join(this.extensionDir, buildDirectory, sdkName); + outputChannel.appendLine(constants.extractingDacFxDlls(extractedFolderPath)); try { await extractZip(nugetPath, { dir: extractedFolderPath }); } catch (e) { void vscode.window.showErrorMessage(constants.errorExtracting(nugetPath, utils.getErrorMessage(e))); - return; + return false; } // copy the dlls and targets file to the BuildDirectory folder @@ -113,6 +120,7 @@ export class BuildHelper { await fs.rm(extractedFolderPath, { recursive: true }); this.initialized = true; + return true; } public get extensionBuildDirPath(): string {