From 27678bc1238fc7c0681a828b6b75852a920d96b3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 26 Sep 2025 08:48:53 +0000 Subject: [PATCH 1/7] Initial plan From 3f9d071b776eb26ead4d4fd5fdc46c2ef2ceccbe Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 26 Sep 2025 08:58:32 +0000 Subject: [PATCH 2/7] Add unpack command functionality to DacFXTool Co-authored-by: ErikEJ <4169187+ErikEJ@users.noreply.github.com> --- src/DacFXTool/Program.cs | 21 +++++++++++++++++++++ src/DacFXToolLib/DacPackageUnpacker.cs | 13 +++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 src/DacFXToolLib/DacPackageUnpacker.cs diff --git a/src/DacFXTool/Program.cs b/src/DacFXTool/Program.cs index c3f8afa..aecc05b 100644 --- a/src/DacFXTool/Program.cs +++ b/src/DacFXTool/Program.cs @@ -149,6 +149,27 @@ public static async System.Threading.Tasks.Task Main(string[] args) return 0; } + + // unpack "dacpac path" "output path" + if (args.Length == 3 + && args[0] == "unpack") + { + if (!new FileInfo(args[1]).Exists) + { + await Console.Out.WriteLineAsync("Error:"); + await Console.Out.WriteLineAsync($"DACPAC file '{args[1]}' not found"); + return 1; + } + + var unpacker = new DacPackageUnpacker(); + + unpacker.Unpack(args[1], args[2]); + + await Console.Out.WriteLineAsync("Result:"); + await Console.Out.WriteLineAsync("OK"); + + return 0; + } } else { diff --git a/src/DacFXToolLib/DacPackageUnpacker.cs b/src/DacFXToolLib/DacPackageUnpacker.cs new file mode 100644 index 0000000..5f5d093 --- /dev/null +++ b/src/DacFXToolLib/DacPackageUnpacker.cs @@ -0,0 +1,13 @@ +using Microsoft.SqlServer.Dac; + +namespace DacFXToolLib +{ + public class DacPackageUnpacker + { + public void Unpack(string dacpacPath, string outputPath) + { + var package = DacPackage.Load(dacpacPath); + DacServices.Unpack(package, outputPath); + } + } +} \ No newline at end of file From 8e32ff0db988ec57bb9a2093db6e211658fae8d6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 26 Sep 2025 09:01:38 +0000 Subject: [PATCH 3/7] Enhance unpack command with output directory creation Co-authored-by: ErikEJ <4169187+ErikEJ@users.noreply.github.com> --- src/DacFXToolLib/DacPackageUnpacker.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/DacFXToolLib/DacPackageUnpacker.cs b/src/DacFXToolLib/DacPackageUnpacker.cs index 5f5d093..901e22e 100644 --- a/src/DacFXToolLib/DacPackageUnpacker.cs +++ b/src/DacFXToolLib/DacPackageUnpacker.cs @@ -6,6 +6,9 @@ public class DacPackageUnpacker { public void Unpack(string dacpacPath, string outputPath) { + // Ensure output directory exists + Directory.CreateDirectory(outputPath); + var package = DacPackage.Load(dacpacPath); DacServices.Unpack(package, outputPath); } From 084c408c0a2e26de31f58b539e8ad66b0b01ed26 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 26 Sep 2025 09:07:06 +0000 Subject: [PATCH 4/7] Complete unpack functionality with VSIX integration Co-authored-by: ErikEJ <4169187+ErikEJ@users.noreply.github.com> --- src/Vsix/Commands/UnpackCommand.cs | 7 ++- src/Vsix/Handlers/ProcessLauncher.cs | 9 ++++ src/Vsix/Handlers/UnpackHandler.cs | 81 ++++++++++++++++++++++++++++ 3 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 src/Vsix/Handlers/UnpackHandler.cs diff --git a/src/Vsix/Commands/UnpackCommand.cs b/src/Vsix/Commands/UnpackCommand.cs index 2408cbc..0e98580 100644 --- a/src/Vsix/Commands/UnpackCommand.cs +++ b/src/Vsix/Commands/UnpackCommand.cs @@ -13,7 +13,12 @@ protected override void BeforeQueryStatus(EventArgs e) protected override async Task ExecuteAsync(OleMenuCmdEventArgs e) { - await VS.MessageBox.ShowWarningAsync("UnpackCommand", "Button clicked"); + var project = await VS.Solutions.GetActiveProjectAsync(); + + if (project != null) + { + await new UnpackHandler().UnpackAsync(project.FullPath); + } } } } diff --git a/src/Vsix/Handlers/ProcessLauncher.cs b/src/Vsix/Handlers/ProcessLauncher.cs index 0e1c9a7..b4c29e8 100644 --- a/src/Vsix/Handlers/ProcessLauncher.cs +++ b/src/Vsix/Handlers/ProcessLauncher.cs @@ -66,6 +66,15 @@ public async Task GetImportAsync(int fileGenerationMode, string optionsP return filePath; } + public async Task GetUnpackAsync(string dacpacPath, string outputPath) + { + var arguments = "unpack \"" + dacpacPath.Replace("\"", "\\\"") + "\" \"" + outputPath.Replace("\"", "\\\"") + "\""; + + var filePath = await GetDiagramInternalAsync(arguments); + + return filePath; + } + public async Task GetErDiagramAsync(string optionsPath, string connectionString) { var arguments = "erdiagram " + " \"" + optionsPath.Replace("\"", "\\\"") + "\" " + " \"" + connectionString.Replace("\"", "\\\"") + "\" "; diff --git a/src/Vsix/Handlers/UnpackHandler.cs b/src/Vsix/Handlers/UnpackHandler.cs new file mode 100644 index 0000000..90c35d9 --- /dev/null +++ b/src/Vsix/Handlers/UnpackHandler.cs @@ -0,0 +1,81 @@ +using System; +using System.IO; +using System.Threading.Tasks; + +namespace SqlProjectsPowerTools +{ + internal class UnpackHandler + { + public async Task UnpackAsync(string projectPath) + { + await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); + + try + { + if (await VSHelper.IsDebugModeAsync()) + { + VSHelper.ShowError("Cannot unpack while debugging"); + return; + } + + var projectDir = Path.GetDirectoryName(projectPath); + + // Let user select DACPAC file + var dacpacPath = await SelectDacpacFileAsync(); + if (string.IsNullOrEmpty(dacpacPath)) + { + return; + } + + // Use project directory as default output location + var outputPath = Path.Combine(projectDir, "UnpackedSchema"); + + await VS.StatusBar.ShowMessageAsync("Unpacking DACPAC..."); + + var result = await RunUnpackAsync(dacpacPath, outputPath); + + if (result == "OK") + { + VSHelper.ShowMessage($"DACPAC unpacked successfully to '{outputPath}'"); + } + } + catch (AggregateException ae) + { + foreach (var innerException in ae.Flatten().InnerExceptions) + { + await VS.MessageBox.ShowErrorAsync("SQL Database Project Power Tools", innerException.Message); + } + } + catch (Exception exception) + { + await VS.MessageBox.ShowErrorAsync("SQL Database Project Power Tools", exception.Message); + } + finally + { + await VS.StatusBar.ClearAsync(); + } + } + + private static async Task RunUnpackAsync(string dacpacPath, string outputPath) + { + var launcher = new ProcessLauncher(); + return await launcher.GetUnpackAsync(dacpacPath, outputPath); + } + + private static async Task SelectDacpacFileAsync() + { + await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); + + var dialog = new Microsoft.Win32.OpenFileDialog + { + Title = "Select DACPAC file to unpack", + Filter = "DACPAC files (*.dacpac)|*.dacpac|All files (*.*)|*.*", + CheckFileExists = true, + Multiselect = false + }; + + var result = dialog.ShowDialog(); + return result == true ? dialog.FileName : null; + } + } +} \ No newline at end of file From 788c7ce0c44cfdabeded904297c088547f6351e2 Mon Sep 17 00:00:00 2001 From: Erik Ejlskov Jensen Date: Fri, 26 Sep 2025 11:34:31 +0200 Subject: [PATCH 5/7] Update src/DacFXToolLib/DacPackageUnpacker.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/DacFXToolLib/DacPackageUnpacker.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/DacFXToolLib/DacPackageUnpacker.cs b/src/DacFXToolLib/DacPackageUnpacker.cs index 901e22e..eeabd5e 100644 --- a/src/DacFXToolLib/DacPackageUnpacker.cs +++ b/src/DacFXToolLib/DacPackageUnpacker.cs @@ -9,8 +9,10 @@ public void Unpack(string dacpacPath, string outputPath) // Ensure output directory exists Directory.CreateDirectory(outputPath); - var package = DacPackage.Load(dacpacPath); - DacServices.Unpack(package, outputPath); + using (var package = DacPackage.Load(dacpacPath)) + { + DacServices.Unpack(package, outputPath); + } } } } \ No newline at end of file From cffa79f7657ca1fb58aa6909ea3c3cfb66b60bfb Mon Sep 17 00:00:00 2001 From: Erik Ejlskov Jensen Date: Fri, 26 Sep 2025 11:34:50 +0200 Subject: [PATCH 6/7] Update src/DacFXToolLib/DacPackageUnpacker.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/DacFXToolLib/DacPackageUnpacker.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/DacFXToolLib/DacPackageUnpacker.cs b/src/DacFXToolLib/DacPackageUnpacker.cs index eeabd5e..6dd9af7 100644 --- a/src/DacFXToolLib/DacPackageUnpacker.cs +++ b/src/DacFXToolLib/DacPackageUnpacker.cs @@ -1,4 +1,5 @@ using Microsoft.SqlServer.Dac; +using System.IO; namespace DacFXToolLib { From b67468a2c993bfc6571b668b64584c6a53c71940 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 26 Sep 2025 09:40:33 +0000 Subject: [PATCH 7/7] Revert Visual Studio extension changes in src/Vsix folder Co-authored-by: ErikEJ <4169187+ErikEJ@users.noreply.github.com> --- src/Vsix/Commands/UnpackCommand.cs | 7 +-- src/Vsix/Handlers/ProcessLauncher.cs | 9 ---- src/Vsix/Handlers/UnpackHandler.cs | 81 ---------------------------- 3 files changed, 1 insertion(+), 96 deletions(-) delete mode 100644 src/Vsix/Handlers/UnpackHandler.cs diff --git a/src/Vsix/Commands/UnpackCommand.cs b/src/Vsix/Commands/UnpackCommand.cs index 0e98580..2408cbc 100644 --- a/src/Vsix/Commands/UnpackCommand.cs +++ b/src/Vsix/Commands/UnpackCommand.cs @@ -13,12 +13,7 @@ protected override void BeforeQueryStatus(EventArgs e) protected override async Task ExecuteAsync(OleMenuCmdEventArgs e) { - var project = await VS.Solutions.GetActiveProjectAsync(); - - if (project != null) - { - await new UnpackHandler().UnpackAsync(project.FullPath); - } + await VS.MessageBox.ShowWarningAsync("UnpackCommand", "Button clicked"); } } } diff --git a/src/Vsix/Handlers/ProcessLauncher.cs b/src/Vsix/Handlers/ProcessLauncher.cs index b4c29e8..0e1c9a7 100644 --- a/src/Vsix/Handlers/ProcessLauncher.cs +++ b/src/Vsix/Handlers/ProcessLauncher.cs @@ -66,15 +66,6 @@ public async Task GetImportAsync(int fileGenerationMode, string optionsP return filePath; } - public async Task GetUnpackAsync(string dacpacPath, string outputPath) - { - var arguments = "unpack \"" + dacpacPath.Replace("\"", "\\\"") + "\" \"" + outputPath.Replace("\"", "\\\"") + "\""; - - var filePath = await GetDiagramInternalAsync(arguments); - - return filePath; - } - public async Task GetErDiagramAsync(string optionsPath, string connectionString) { var arguments = "erdiagram " + " \"" + optionsPath.Replace("\"", "\\\"") + "\" " + " \"" + connectionString.Replace("\"", "\\\"") + "\" "; diff --git a/src/Vsix/Handlers/UnpackHandler.cs b/src/Vsix/Handlers/UnpackHandler.cs deleted file mode 100644 index 90c35d9..0000000 --- a/src/Vsix/Handlers/UnpackHandler.cs +++ /dev/null @@ -1,81 +0,0 @@ -using System; -using System.IO; -using System.Threading.Tasks; - -namespace SqlProjectsPowerTools -{ - internal class UnpackHandler - { - public async Task UnpackAsync(string projectPath) - { - await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); - - try - { - if (await VSHelper.IsDebugModeAsync()) - { - VSHelper.ShowError("Cannot unpack while debugging"); - return; - } - - var projectDir = Path.GetDirectoryName(projectPath); - - // Let user select DACPAC file - var dacpacPath = await SelectDacpacFileAsync(); - if (string.IsNullOrEmpty(dacpacPath)) - { - return; - } - - // Use project directory as default output location - var outputPath = Path.Combine(projectDir, "UnpackedSchema"); - - await VS.StatusBar.ShowMessageAsync("Unpacking DACPAC..."); - - var result = await RunUnpackAsync(dacpacPath, outputPath); - - if (result == "OK") - { - VSHelper.ShowMessage($"DACPAC unpacked successfully to '{outputPath}'"); - } - } - catch (AggregateException ae) - { - foreach (var innerException in ae.Flatten().InnerExceptions) - { - await VS.MessageBox.ShowErrorAsync("SQL Database Project Power Tools", innerException.Message); - } - } - catch (Exception exception) - { - await VS.MessageBox.ShowErrorAsync("SQL Database Project Power Tools", exception.Message); - } - finally - { - await VS.StatusBar.ClearAsync(); - } - } - - private static async Task RunUnpackAsync(string dacpacPath, string outputPath) - { - var launcher = new ProcessLauncher(); - return await launcher.GetUnpackAsync(dacpacPath, outputPath); - } - - private static async Task SelectDacpacFileAsync() - { - await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); - - var dialog = new Microsoft.Win32.OpenFileDialog - { - Title = "Select DACPAC file to unpack", - Filter = "DACPAC files (*.dacpac)|*.dacpac|All files (*.*)|*.*", - CheckFileExists = true, - Multiselect = false - }; - - var result = dialog.ShowDialog(); - return result == true ? dialog.FileName : null; - } - } -} \ No newline at end of file