mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-16 01:25:36 -05:00
projectController.ts code cleanup (#21112)
* adding regions and doc comments in projectController.ts * cleanup * add param info to doc comment
This commit is contained in:
@@ -96,6 +96,7 @@ export class ProjectsController {
|
||||
this.autorestHelper = new AutorestHelper(this._outputChannel);
|
||||
}
|
||||
|
||||
//#region Dashboard
|
||||
public getDashboardPublishData(projectFile: string): (string | dataworkspace.IconCellValue)[][] {
|
||||
const infoRows: (string | dataworkspace.IconCellValue)[][] = [];
|
||||
|
||||
@@ -156,9 +157,9 @@ export class ProjectsController {
|
||||
return infoRows;
|
||||
}
|
||||
|
||||
public refreshProjectsTree(workspaceTreeItem: dataworkspace.WorkspaceTreeItem): void {
|
||||
(workspaceTreeItem.treeDataProvider as SqlDatabaseProjectTreeViewProvider).notifyTreeDataChanged();
|
||||
}
|
||||
//#endregion
|
||||
|
||||
//#region Create new project
|
||||
|
||||
/**
|
||||
* Creates a new folder with the project name in the specified location, and places the new .sqlproj inside it
|
||||
@@ -212,6 +213,36 @@ export class ProjectsController {
|
||||
return newProjFilePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the template files for the provided project type
|
||||
* @param newProjFilePath path to project to add template files to
|
||||
* @param projectTypeId project type id
|
||||
*/
|
||||
private async addTemplateFiles(newProjFilePath: string, projectTypeId: string): Promise<void> {
|
||||
if (projectTypeId === constants.emptySqlDatabaseProjectTypeId || newProjFilePath === '') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (projectTypeId === constants.edgeSqlDatabaseProjectTypeId) {
|
||||
const project = await Project.openProject(newProjFilePath);
|
||||
|
||||
await this.createFileFromTemplate(project, templates.get(ItemType.table), 'DataTable.sql', { 'OBJECT_NAME': 'DataTable' });
|
||||
await this.createFileFromTemplate(project, templates.get(ItemType.dataSource), 'EdgeHubInputDataSource.sql', { 'OBJECT_NAME': 'EdgeHubInputDataSource', 'LOCATION': 'edgehub://' });
|
||||
await this.createFileFromTemplate(project, templates.get(ItemType.dataSource), 'SqlOutputDataSource.sql', { 'OBJECT_NAME': 'SqlOutputDataSource', 'LOCATION': 'sqlserver://tcp:.,1433' });
|
||||
await this.createFileFromTemplate(project, templates.get(ItemType.fileFormat), 'StreamFileFormat.sql', { 'OBJECT_NAME': 'StreamFileFormat' });
|
||||
await this.createFileFromTemplate(project, templates.get(ItemType.externalStream), 'EdgeHubInputStream.sql', { 'OBJECT_NAME': 'EdgeHubInputStream', 'DATA_SOURCE_NAME': 'EdgeHubInputDataSource', 'LOCATION': 'input', 'OPTIONS': ',\n\tFILE_FORMAT = StreamFileFormat' });
|
||||
await this.createFileFromTemplate(project, templates.get(ItemType.externalStream), 'SqlOutputStream.sql', { 'OBJECT_NAME': 'SqlOutputStream', 'DATA_SOURCE_NAME': 'SqlOutputDataSource', 'LOCATION': 'TSQLStreaming.dbo.DataTable', 'OPTIONS': '' });
|
||||
await this.createFileFromTemplate(project, templates.get(ItemType.externalStreamingJob), 'EdgeStreamingJob.sql', { 'OBJECT_NAME': 'EdgeStreamingJob' });
|
||||
}
|
||||
}
|
||||
|
||||
private async createFileFromTemplate(project: Project, itemType: templates.ProjectScriptType, relativePath: string, expansionMacros: Record<string, string>): Promise<void> {
|
||||
const newFileText = templates.macroExpansion(itemType.templateScript, expansionMacros);
|
||||
await project.addScriptItem(relativePath, newFileText, itemType.type);
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
/**
|
||||
* Builds a project, producing a dacpac
|
||||
* @param treeNode a treeItem in a project's hierarchy, to be used to obtain a Project
|
||||
@@ -290,6 +321,8 @@ export class ProjectsController {
|
||||
}
|
||||
}
|
||||
|
||||
//#region Publish
|
||||
|
||||
/**
|
||||
* Publishes a project to a new Azure server
|
||||
* @param context a treeItem in a project's hierarchy, to be used to obtain a Project or the Project itself
|
||||
@@ -394,6 +427,10 @@ export class ProjectsController {
|
||||
}
|
||||
}
|
||||
|
||||
public getPublishDialog(project: Project): PublishDatabaseDialog {
|
||||
return new PublishDatabaseDialog(project);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create flow for Publishing a database using only VS Code-native APIs such as QuickPick
|
||||
*/
|
||||
@@ -536,6 +573,13 @@ export class ProjectsController {
|
||||
return result;
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
/**
|
||||
* Launches the schema compare extension with the source and target
|
||||
* @param source source for schema compare. Either a connection or project node
|
||||
* @param targetParam target for schema compare
|
||||
*/
|
||||
public async schemaCompare(source: dataworkspace.WorkspaceTreeItem | azdataType.IConnectionProfile, targetParam: any = undefined): Promise<void> {
|
||||
try {
|
||||
// check if schema compare extension is installed
|
||||
@@ -574,68 +618,7 @@ export class ProjectsController {
|
||||
}
|
||||
}
|
||||
|
||||
public async getProjectScriptFiles(projectFilePath: string): Promise<string[]> {
|
||||
const project = await Project.openProject(projectFilePath);
|
||||
|
||||
return project.files
|
||||
.filter(f => f.fsUri.fsPath.endsWith(constants.sqlFileExtension))
|
||||
.map(f => f.fsUri.fsPath);
|
||||
}
|
||||
|
||||
public async getProjectDatabaseSchemaProvider(projectFilePath: string): Promise<string> {
|
||||
const project = await Project.openProject(projectFilePath);
|
||||
return project.getProjectTargetVersion();
|
||||
}
|
||||
|
||||
public async schemaComparePublishProjectChanges(operationId: string, projectFilePath: string, folderStructure: string): Promise<mssql.SchemaComparePublishProjectResult> {
|
||||
const ext = vscode.extensions.getExtension(mssql.extension.name)!;
|
||||
const service = (await ext.activate() as mssql.IExtension).schemaCompare;
|
||||
|
||||
const projectPath = path.dirname(projectFilePath);
|
||||
|
||||
let fs: mssql.ExtractTarget;
|
||||
|
||||
switch (folderStructure) {
|
||||
case constants.file:
|
||||
fs = mssql.ExtractTarget.file;
|
||||
break;
|
||||
case constants.flat:
|
||||
fs = mssql.ExtractTarget.flat;
|
||||
break;
|
||||
case constants.objectType:
|
||||
fs = mssql.ExtractTarget.objectType;
|
||||
break;
|
||||
case constants.schema:
|
||||
fs = mssql.ExtractTarget.schema;
|
||||
break;
|
||||
case constants.schemaObjectType:
|
||||
default:
|
||||
fs = mssql.ExtractTarget.schemaObjectType;
|
||||
break;
|
||||
}
|
||||
|
||||
const result: mssql.SchemaComparePublishProjectResult = await service.schemaComparePublishProjectChanges(operationId, projectPath, fs, utils.getAzdataApi()!.TaskExecutionMode.execute);
|
||||
|
||||
if (!result.errorMessage) {
|
||||
const project = await Project.openProject(projectFilePath);
|
||||
|
||||
let toAdd: vscode.Uri[] = [];
|
||||
result.addedFiles.forEach((f: any) => toAdd.push(vscode.Uri.file(f)));
|
||||
await project.addToProject(toAdd);
|
||||
|
||||
let toRemove: vscode.Uri[] = [];
|
||||
result.deletedFiles.forEach((f: any) => toRemove.push(vscode.Uri.file(f)));
|
||||
|
||||
let toRemoveEntries: FileProjectEntry[] = [];
|
||||
toRemove.forEach(f => toRemoveEntries.push(new FileProjectEntry(f, f.path.replace(projectPath + '\\', ''), EntryType.File)));
|
||||
|
||||
toRemoveEntries.forEach(async f => await project.exclude(f));
|
||||
|
||||
await this.buildProject(project);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
//#region Add/Exclude/Delete Item
|
||||
|
||||
public async addFolderPrompt(treeNode: dataworkspace.WorkspaceTreeItem): Promise<void> {
|
||||
const project = this.getProjectFromContext(treeNode);
|
||||
@@ -666,6 +649,24 @@ export class ProjectsController {
|
||||
}
|
||||
}
|
||||
|
||||
private async promptForNewObjectName(itemType: templates.ProjectScriptType, _project: ISqlProject, folderPath: string, fileExtension?: string, defaultName?: string): Promise<string | undefined> {
|
||||
const suggestedName = defaultName ?? itemType.friendlyName.replace(/\s+/g, '');
|
||||
let counter: number = 0;
|
||||
|
||||
do {
|
||||
counter++;
|
||||
} while (counter < Number.MAX_SAFE_INTEGER
|
||||
&& await utils.exists(path.join(folderPath, `${suggestedName}${counter}${(fileExtension ?? '')}`)));
|
||||
|
||||
const itemObjectName = await vscode.window.showInputBox({
|
||||
prompt: constants.newObjectNamePrompt(itemType.friendlyName),
|
||||
value: `${suggestedName}${counter}`,
|
||||
ignoreFocusOut: true,
|
||||
});
|
||||
|
||||
return itemObjectName;
|
||||
}
|
||||
|
||||
public isReservedFolder(absoluteFolderPath: string, projectFolderPath: string): boolean {
|
||||
const sameName = reservedProjectFolders.find(f => f === path.parse(absoluteFolderPath).name) !== undefined;
|
||||
const sameLocation = path.parse(absoluteFolderPath).dir === projectFolderPath;
|
||||
@@ -830,21 +831,6 @@ export class ProjectsController {
|
||||
}
|
||||
}
|
||||
|
||||
private getFileProjectEntry(project: Project, context: BaseProjectTreeItem): FileProjectEntry | undefined {
|
||||
const root = context.root as ProjectRootTreeItem;
|
||||
const fileOrFolder = context as FileNode ? context as FileNode : context as FolderNode;
|
||||
|
||||
if (root && fileOrFolder) {
|
||||
// use relative path and not tree paths for files and folder
|
||||
const allFileEntries = project.files.concat(project.preDeployScripts).concat(project.postDeployScripts).concat(project.noneDeployScripts);
|
||||
|
||||
// trim trailing slash since folders with and without a trailing slash are allowed in a sqlproj
|
||||
const trimmedUri = utils.trimChars(utils.getPlatformSafeFileEntryPath(utils.trimUri(root.fileSystemUri, fileOrFolder.fileSystemUri)), '/');
|
||||
return allFileEntries.find(x => utils.trimChars(utils.getPlatformSafeFileEntryPath(x.relativePath), '/') === trimmedUri);
|
||||
}
|
||||
return project.files.find(x => utils.getPlatformSafeFileEntryPath(x.relativePath) === utils.getPlatformSafeFileEntryPath(utils.trimUri(context.root.projectUri, context.projectUri)));
|
||||
}
|
||||
|
||||
private getDatabaseReference(project: Project, context: BaseProjectTreeItem): IDatabaseReferenceProjectEntry | undefined {
|
||||
const root = context.root as ProjectRootTreeItem;
|
||||
const databaseReference = context as DatabaseReferenceTreeItem;
|
||||
@@ -856,6 +842,8 @@ export class ProjectsController {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
/**
|
||||
* Opens the folder containing the project
|
||||
* @param context a treeItem in a project's hierarchy, to be used to obtain a Project
|
||||
@@ -999,6 +987,8 @@ export class ProjectsController {
|
||||
});
|
||||
}
|
||||
|
||||
//#region database references
|
||||
|
||||
/**
|
||||
* Adds a database reference to the project
|
||||
* @param context a treeItem in a project's hierarchy, to be used to obtain a Project
|
||||
@@ -1021,6 +1011,10 @@ export class ProjectsController {
|
||||
}
|
||||
}
|
||||
|
||||
public getAddDatabaseReferenceDialog(project: Project): AddDatabaseReferenceDialog {
|
||||
return new AddDatabaseReferenceDialog(project);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a database reference to a project, after selections have been made in the dialog
|
||||
* @param project project to which to add the database reference
|
||||
@@ -1064,6 +1058,8 @@ export class ProjectsController {
|
||||
}
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
/**
|
||||
* Validates the contents of an external streaming job's query against the last-built dacpac.
|
||||
* If no dacpac exists at the output path, one will be built first.
|
||||
@@ -1107,6 +1103,8 @@ export class ProjectsController {
|
||||
return result;
|
||||
}
|
||||
|
||||
//#region AutoRest
|
||||
|
||||
public async selectAutorestSpecFile(): Promise<string | undefined> {
|
||||
let quickpickSelection = await vscode.window.showQuickPick(
|
||||
[constants.browseEllipsisWithIcon],
|
||||
@@ -1195,6 +1193,10 @@ export class ProjectsController {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the provided project in the workspace, opening it in the projects viewlet
|
||||
* @param projectFilePath
|
||||
*/
|
||||
public async openProjectInWorkspace(projectFilePath: string): Promise<void> {
|
||||
const workspaceApi = utils.getDataWorkspaceExtensionApi();
|
||||
await workspaceApi.validateWorkspace();
|
||||
@@ -1222,6 +1224,11 @@ export class ProjectsController {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prompts the user with vscode quickpicks to select an OpenApi or Swagger spec to generate sql project from
|
||||
* @param options optional options to pass in instead of using quickpicks to prompt
|
||||
* @returns created sql project
|
||||
*/
|
||||
public async generateProjectFromOpenApiSpec(options?: GenerateProjectFromOpenApiSpecOptions): Promise<Project | undefined> {
|
||||
try {
|
||||
TelemetryReporter.sendActionEvent(TelemetryViews.ProjectController, TelemetryActions.generateProjectFromOpenApiSpec);
|
||||
@@ -1325,37 +1332,23 @@ export class ProjectsController {
|
||||
return files;
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region Helper methods
|
||||
|
||||
public getPublishDialog(project: Project): PublishDatabaseDialog {
|
||||
return new PublishDatabaseDialog(project);
|
||||
}
|
||||
private getFileProjectEntry(project: Project, context: BaseProjectTreeItem): FileProjectEntry | undefined {
|
||||
const root = context.root as ProjectRootTreeItem;
|
||||
const fileOrFolder = context as FileNode ? context as FileNode : context as FolderNode;
|
||||
|
||||
public getAddDatabaseReferenceDialog(project: Project): AddDatabaseReferenceDialog {
|
||||
return new AddDatabaseReferenceDialog(project);
|
||||
}
|
||||
if (root && fileOrFolder) {
|
||||
// use relative path and not tree paths for files and folder
|
||||
const allFileEntries = project.files.concat(project.preDeployScripts).concat(project.postDeployScripts).concat(project.noneDeployScripts);
|
||||
|
||||
private async addTemplateFiles(newProjFilePath: string, projectTypeId: string): Promise<void> {
|
||||
if (projectTypeId === constants.emptySqlDatabaseProjectTypeId || newProjFilePath === '') {
|
||||
return;
|
||||
// trim trailing slash since folders with and without a trailing slash are allowed in a sqlproj
|
||||
const trimmedUri = utils.trimChars(utils.getPlatformSafeFileEntryPath(utils.trimUri(root.fileSystemUri, fileOrFolder.fileSystemUri)), '/');
|
||||
return allFileEntries.find(x => utils.trimChars(utils.getPlatformSafeFileEntryPath(x.relativePath), '/') === trimmedUri);
|
||||
}
|
||||
|
||||
if (projectTypeId === constants.edgeSqlDatabaseProjectTypeId) {
|
||||
const project = await Project.openProject(newProjFilePath);
|
||||
|
||||
await this.createFileFromTemplate(project, templates.get(ItemType.table), 'DataTable.sql', { 'OBJECT_NAME': 'DataTable' });
|
||||
await this.createFileFromTemplate(project, templates.get(ItemType.dataSource), 'EdgeHubInputDataSource.sql', { 'OBJECT_NAME': 'EdgeHubInputDataSource', 'LOCATION': 'edgehub://' });
|
||||
await this.createFileFromTemplate(project, templates.get(ItemType.dataSource), 'SqlOutputDataSource.sql', { 'OBJECT_NAME': 'SqlOutputDataSource', 'LOCATION': 'sqlserver://tcp:.,1433' });
|
||||
await this.createFileFromTemplate(project, templates.get(ItemType.fileFormat), 'StreamFileFormat.sql', { 'OBJECT_NAME': 'StreamFileFormat' });
|
||||
await this.createFileFromTemplate(project, templates.get(ItemType.externalStream), 'EdgeHubInputStream.sql', { 'OBJECT_NAME': 'EdgeHubInputStream', 'DATA_SOURCE_NAME': 'EdgeHubInputDataSource', 'LOCATION': 'input', 'OPTIONS': ',\n\tFILE_FORMAT = StreamFileFormat' });
|
||||
await this.createFileFromTemplate(project, templates.get(ItemType.externalStream), 'SqlOutputStream.sql', { 'OBJECT_NAME': 'SqlOutputStream', 'DATA_SOURCE_NAME': 'SqlOutputDataSource', 'LOCATION': 'TSQLStreaming.dbo.DataTable', 'OPTIONS': '' });
|
||||
await this.createFileFromTemplate(project, templates.get(ItemType.externalStreamingJob), 'EdgeStreamingJob.sql', { 'OBJECT_NAME': 'EdgeStreamingJob' });
|
||||
}
|
||||
}
|
||||
|
||||
private async createFileFromTemplate(project: Project, itemType: templates.ProjectScriptType, relativePath: string, expansionMacros: Record<string, string>): Promise<void> {
|
||||
const newFileText = templates.macroExpansion(itemType.templateScript, expansionMacros);
|
||||
await project.addScriptItem(relativePath, newFileText, itemType.type);
|
||||
return project.files.find(x => utils.getPlatformSafeFileEntryPath(x.relativePath) === utils.getPlatformSafeFileEntryPath(utils.trimUri(context.root.projectUri, context.projectUri)));
|
||||
}
|
||||
|
||||
private getProjectFromContext(context: Project | BaseProjectTreeItem | dataworkspace.WorkspaceTreeItem): Project {
|
||||
@@ -1374,28 +1367,29 @@ export class ProjectsController {
|
||||
}
|
||||
}
|
||||
|
||||
private async promptForNewObjectName(itemType: templates.ProjectScriptType, _project: ISqlProject, folderPath: string, fileExtension?: string, defaultName?: string): Promise<string | undefined> {
|
||||
const suggestedName = defaultName ?? itemType.friendlyName.replace(/\s+/g, '');
|
||||
let counter: number = 0;
|
||||
|
||||
do {
|
||||
counter++;
|
||||
} while (counter < Number.MAX_SAFE_INTEGER
|
||||
&& await utils.exists(path.join(folderPath, `${suggestedName}${counter}${(fileExtension ?? '')}`)));
|
||||
|
||||
const itemObjectName = await vscode.window.showInputBox({
|
||||
prompt: constants.newObjectNamePrompt(itemType.friendlyName),
|
||||
value: `${suggestedName}${counter}`,
|
||||
ignoreFocusOut: true,
|
||||
});
|
||||
|
||||
return itemObjectName;
|
||||
}
|
||||
|
||||
private getRelativePath(treeNode: BaseProjectTreeItem): string {
|
||||
return treeNode instanceof FolderNode ? utils.trimUri(treeNode.root.projectUri, treeNode.projectUri) : '';
|
||||
}
|
||||
|
||||
private getConnectionProfileFromContext(context: azdataType.IConnectionProfile | mssqlVscode.ITreeNodeInfo | undefined): azdataType.IConnectionProfile | mssqlVscode.IConnectionInfo | undefined {
|
||||
if (!context) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// depending on where import new project is launched from, the connection profile could be passed as just
|
||||
// the profile or it could be wrapped in another object
|
||||
return (<any>context)?.connectionProfile ?? (context as mssqlVscode.ITreeNodeInfo).connectionInfo ?? context;
|
||||
}
|
||||
|
||||
private refreshProjectsTree(workspaceTreeItem: dataworkspace.WorkspaceTreeItem): void {
|
||||
(workspaceTreeItem.treeDataProvider as SqlDatabaseProjectTreeViewProvider).notifyTreeDataChanged();
|
||||
}
|
||||
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region Create project from database
|
||||
|
||||
/**
|
||||
* Creates a new SQL database project from the existing database,
|
||||
* prompting the user for a name, file path location and extract target
|
||||
@@ -1488,22 +1482,6 @@ export class ProjectsController {
|
||||
}
|
||||
}
|
||||
|
||||
public setFilePath(model: ImportDataModel) {
|
||||
if (model.extractTarget === mssql.ExtractTarget.file) {
|
||||
model.filePath = path.join(model.filePath, `${model.projName}.sql`); // File extractTarget specifies the exact file rather than the containing folder
|
||||
}
|
||||
}
|
||||
|
||||
private getConnectionProfileFromContext(context: azdataType.IConnectionProfile | mssqlVscode.ITreeNodeInfo | undefined): azdataType.IConnectionProfile | mssqlVscode.IConnectionInfo | undefined {
|
||||
if (!context) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// depending on where import new project is launched from, the connection profile could be passed as just
|
||||
// the profile or it could be wrapped in another object
|
||||
return (<any>context)?.connectionProfile ?? (context as mssqlVscode.ITreeNodeInfo).connectionInfo ?? context;
|
||||
}
|
||||
|
||||
public async createProjectFromDatabaseApiCall(model: ImportDataModel): Promise<void> {
|
||||
const service = await utils.getDacFxService();
|
||||
const azdataApi = utils.getAzdataApi();
|
||||
@@ -1516,6 +1494,56 @@ export class ProjectsController {
|
||||
// TODO: Check for success; throw error
|
||||
}
|
||||
|
||||
public setFilePath(model: ImportDataModel) {
|
||||
if (model.extractTarget === mssql.ExtractTarget.file) {
|
||||
model.filePath = path.join(model.filePath, `${model.projName}.sql`); // File extractTarget specifies the exact file rather than the containing folder
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a flat list of all files and folder under a folder.
|
||||
* @param absolutePath absolute path to folder to generate the list of files from
|
||||
* @returns array of uris of files and folders under the provided folder
|
||||
*/
|
||||
public async generateList(absolutePath: string): Promise<vscode.Uri[]> {
|
||||
let fileFolderList: vscode.Uri[] = [];
|
||||
|
||||
if (!await utils.exists(absolutePath)) {
|
||||
if (await utils.exists(absolutePath + constants.sqlFileExtension)) {
|
||||
absolutePath += constants.sqlFileExtension;
|
||||
} else {
|
||||
void vscode.window.showErrorMessage(constants.cannotResolvePath(absolutePath));
|
||||
return fileFolderList;
|
||||
}
|
||||
}
|
||||
|
||||
const files = [absolutePath];
|
||||
do {
|
||||
const filepath = files.pop();
|
||||
|
||||
if (filepath) {
|
||||
const stat = await fs.stat(filepath);
|
||||
|
||||
if (stat.isDirectory()) {
|
||||
fileFolderList.push(vscode.Uri.file(filepath));
|
||||
(await fs
|
||||
.readdir(filepath))
|
||||
.forEach((f: string) => files.push(path.join(filepath, f)));
|
||||
}
|
||||
else if (stat.isFile()) {
|
||||
fileFolderList.push(vscode.Uri.file(filepath));
|
||||
}
|
||||
}
|
||||
|
||||
} while (files.length !== 0);
|
||||
|
||||
return fileFolderList;
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region Update project from database
|
||||
|
||||
/**
|
||||
* Display dialog for user to configure existing SQL Project with the changes/differences from a database
|
||||
*/
|
||||
@@ -1593,6 +1621,11 @@ export class ProjectsController {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a schema compare of the source and target and updates the project with the results
|
||||
* @param source source for schema comparison
|
||||
* @param target target sql project for schema comparison to update
|
||||
*/
|
||||
private async schemaCompareAndUpdateProject(source: mssql.SchemaCompareEndpointInfo, target: mssql.SchemaCompareEndpointInfo): Promise<void> {
|
||||
// Run schema comparison
|
||||
const ext = vscode.extensions.getExtension(mssql.extension.name)!;
|
||||
@@ -1640,42 +1673,74 @@ export class ProjectsController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a flat list of all files and folder under a folder.
|
||||
*/
|
||||
public async generateList(absolutePath: string): Promise<vscode.Uri[]> {
|
||||
let fileFolderList: vscode.Uri[] = [];
|
||||
public async getProjectScriptFiles(projectFilePath: string): Promise<string[]> {
|
||||
const project = await Project.openProject(projectFilePath);
|
||||
|
||||
if (!await utils.exists(absolutePath)) {
|
||||
if (await utils.exists(absolutePath + constants.sqlFileExtension)) {
|
||||
absolutePath += constants.sqlFileExtension;
|
||||
} else {
|
||||
void vscode.window.showErrorMessage(constants.cannotResolvePath(absolutePath));
|
||||
return fileFolderList;
|
||||
}
|
||||
return project.files
|
||||
.filter(f => f.fsUri.fsPath.endsWith(constants.sqlFileExtension))
|
||||
.map(f => f.fsUri.fsPath);
|
||||
}
|
||||
|
||||
public async getProjectDatabaseSchemaProvider(projectFilePath: string): Promise<string> {
|
||||
const project = await Project.openProject(projectFilePath);
|
||||
return project.getProjectTargetVersion();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the provided project with the results of the schema compare
|
||||
* @param operationId id of the schema comparison to update the project with
|
||||
* @param projectFilePath path to sql project to update
|
||||
* @param folderStructure folder structure to use when updating the target project
|
||||
* @returns
|
||||
*/
|
||||
public async schemaComparePublishProjectChanges(operationId: string, projectFilePath: string, folderStructure: string): Promise<mssql.SchemaComparePublishProjectResult> {
|
||||
const ext = vscode.extensions.getExtension(mssql.extension.name)!;
|
||||
const service = (await ext.activate() as mssql.IExtension).schemaCompare;
|
||||
|
||||
const projectPath = path.dirname(projectFilePath);
|
||||
|
||||
let fs: mssql.ExtractTarget;
|
||||
|
||||
switch (folderStructure) {
|
||||
case constants.file:
|
||||
fs = mssql.ExtractTarget.file;
|
||||
break;
|
||||
case constants.flat:
|
||||
fs = mssql.ExtractTarget.flat;
|
||||
break;
|
||||
case constants.objectType:
|
||||
fs = mssql.ExtractTarget.objectType;
|
||||
break;
|
||||
case constants.schema:
|
||||
fs = mssql.ExtractTarget.schema;
|
||||
break;
|
||||
case constants.schemaObjectType:
|
||||
default:
|
||||
fs = mssql.ExtractTarget.schemaObjectType;
|
||||
break;
|
||||
}
|
||||
|
||||
const files = [absolutePath];
|
||||
do {
|
||||
const filepath = files.pop();
|
||||
const result: mssql.SchemaComparePublishProjectResult = await service.schemaComparePublishProjectChanges(operationId, projectPath, fs, utils.getAzdataApi()!.TaskExecutionMode.execute);
|
||||
|
||||
if (filepath) {
|
||||
const stat = await fs.stat(filepath);
|
||||
if (!result.errorMessage) {
|
||||
const project = await Project.openProject(projectFilePath);
|
||||
|
||||
if (stat.isDirectory()) {
|
||||
fileFolderList.push(vscode.Uri.file(filepath));
|
||||
(await fs
|
||||
.readdir(filepath))
|
||||
.forEach((f: string) => files.push(path.join(filepath, f)));
|
||||
}
|
||||
else if (stat.isFile()) {
|
||||
fileFolderList.push(vscode.Uri.file(filepath));
|
||||
}
|
||||
}
|
||||
let toAdd: vscode.Uri[] = [];
|
||||
result.addedFiles.forEach((f: any) => toAdd.push(vscode.Uri.file(f)));
|
||||
await project.addToProject(toAdd);
|
||||
|
||||
} while (files.length !== 0);
|
||||
let toRemove: vscode.Uri[] = [];
|
||||
result.deletedFiles.forEach((f: any) => toRemove.push(vscode.Uri.file(f)));
|
||||
|
||||
return fileFolderList;
|
||||
let toRemoveEntries: FileProjectEntry[] = [];
|
||||
toRemove.forEach(f => toRemoveEntries.push(new FileProjectEntry(f, f.path.replace(projectPath + '\\', ''), EntryType.File)));
|
||||
|
||||
toRemoveEntries.forEach(async f => await project.exclude(f));
|
||||
|
||||
await this.buildProject(project);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
Reference in New Issue
Block a user