diff options
Diffstat (limited to 'src')
16 files changed, 653 insertions, 201 deletions
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Bind/BindTransformCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Bind/BindTransformCommand.cs index 3379ec5d..3d8e7595 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Bind/BindTransformCommand.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Bind/BindTransformCommand.cs | |||
| @@ -62,18 +62,19 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
| 62 | 62 | ||
| 63 | if (this.Transform.TryGetTable("Property", out var propertyTable)) | 63 | if (this.Transform.TryGetTable("Property", out var propertyTable)) |
| 64 | { | 64 | { |
| 65 | for (int i = propertyTable.Rows.Count - 1; i >= 0; i--) | 65 | for (var i = propertyTable.Rows.Count - 1; i >= 0; i--) |
| 66 | { | 66 | { |
| 67 | Row row = propertyTable.Rows[i]; | 67 | var row = propertyTable.Rows[i]; |
| 68 | var id = row.FieldAsString(0); | ||
| 68 | 69 | ||
| 69 | if ("ProductCode" == (string)row[0] || "ProductLanguage" == (string)row[0] || "ProductVersion" == (string)row[0] || "UpgradeCode" == (string)row[0]) | 70 | if ("ProductCode" == id || "ProductLanguage" == id || "ProductVersion" == id) |
| 70 | { | 71 | { |
| 71 | propertyTable.Rows.RemoveAt(i); | 72 | propertyTable.Rows.RemoveAt(i); |
| 72 | 73 | } | |
| 73 | if ("UpgradeCode" == (string)row[0]) | 74 | else if ("UpgradeCode" == id) |
| 74 | { | 75 | { |
| 75 | updatedUpgradeCode = (string)row[1]; | 76 | updatedUpgradeCode = id; |
| 76 | } | 77 | propertyTable.Rows.RemoveAt(i); |
| 77 | } | 78 | } |
| 78 | } | 79 | } |
| 79 | } | 80 | } |
| @@ -383,11 +384,6 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
| 383 | } | 384 | } |
| 384 | } | 385 | } |
| 385 | 386 | ||
| 386 | //foreach (BinderExtension extension in this.Extensions) | ||
| 387 | //{ | ||
| 388 | // extension.PostBind(this.Context); | ||
| 389 | //} | ||
| 390 | |||
| 391 | // Any errors encountered up to this point can cause errors during generation. | 387 | // Any errors encountered up to this point can cause errors during generation. |
| 392 | if (this.Messaging.EncounteredError) | 388 | if (this.Messaging.EncounteredError) |
| 393 | { | 389 | { |
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Bind/LoadTableDefinitionsCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Bind/LoadTableDefinitionsCommand.cs index 2eb95bc5..475a88f9 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Bind/LoadTableDefinitionsCommand.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Bind/LoadTableDefinitionsCommand.cs | |||
| @@ -2,9 +2,7 @@ | |||
| 2 | 2 | ||
| 3 | namespace WixToolset.Core.WindowsInstaller.Bind | 3 | namespace WixToolset.Core.WindowsInstaller.Bind |
| 4 | { | 4 | { |
| 5 | using System; | ||
| 6 | using System.Collections.Generic; | 5 | using System.Collections.Generic; |
| 7 | using System.Globalization; | ||
| 8 | using System.Linq; | 6 | using System.Linq; |
| 9 | using WixToolset.Data; | 7 | using WixToolset.Data; |
| 10 | using WixToolset.Data.Symbols; | 8 | using WixToolset.Data.Symbols; |
| @@ -32,9 +30,9 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
| 32 | public TableDefinitionCollection Execute() | 30 | public TableDefinitionCollection Execute() |
| 33 | { | 31 | { |
| 34 | var tableDefinitions = new TableDefinitionCollection(WindowsInstallerTableDefinitions.All); | 32 | var tableDefinitions = new TableDefinitionCollection(WindowsInstallerTableDefinitions.All); |
| 35 | var customColumnsById = this.Section.Symbols.OfType<WixCustomTableColumnSymbol>().ToDictionary(t => t.Id.Id); | 33 | var customColumnsById = this.Section?.Symbols.OfType<WixCustomTableColumnSymbol>().ToDictionary(t => t.Id.Id); |
| 36 | 34 | ||
| 37 | if (customColumnsById.Any()) | 35 | if (customColumnsById?.Any() == true) |
| 38 | { | 36 | { |
| 39 | foreach (var symbol in this.Section.Symbols.OfType<WixCustomTableSymbol>()) | 37 | foreach (var symbol in this.Section.Symbols.OfType<WixCustomTableSymbol>()) |
| 40 | { | 38 | { |
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/CommandLine/TransformSubcommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/CommandLine/TransformSubcommand.cs new file mode 100644 index 00000000..7ed41d1a --- /dev/null +++ b/src/wix/WixToolset.Core.WindowsInstaller/CommandLine/TransformSubcommand.cs | |||
| @@ -0,0 +1,352 @@ | |||
| 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | ||
| 2 | |||
| 3 | namespace WixToolset.Core.WindowsInstaller.CommandLine | ||
| 4 | { | ||
| 5 | using System; | ||
| 6 | using System.IO; | ||
| 7 | using System.Threading; | ||
| 8 | using System.Threading.Tasks; | ||
| 9 | using WixToolset.Core.WindowsInstaller.Bind; | ||
| 10 | using WixToolset.Core.WindowsInstaller.Unbind; | ||
| 11 | using WixToolset.Data; | ||
| 12 | using WixToolset.Data.Symbols; | ||
| 13 | using WixToolset.Data.WindowsInstaller; | ||
| 14 | using WixToolset.Extensibility; | ||
| 15 | using WixToolset.Extensibility.Services; | ||
| 16 | |||
| 17 | internal class TransformSubcommand : WindowsInstallerSubcommandBase | ||
| 18 | { | ||
| 19 | public TransformSubcommand(IServiceProvider serviceProvider) | ||
| 20 | { | ||
| 21 | this.Messaging = serviceProvider.GetService<IMessaging>(); | ||
| 22 | this.BackendHelper = serviceProvider.GetService<IBackendHelper>(); | ||
| 23 | this.ExtensionManager = serviceProvider.GetService<IExtensionManager>(); | ||
| 24 | } | ||
| 25 | |||
| 26 | private IMessaging Messaging { get; } | ||
| 27 | |||
| 28 | private IBackendHelper BackendHelper { get; } | ||
| 29 | |||
| 30 | private IExtensionManager ExtensionManager { get; } | ||
| 31 | |||
| 32 | private string OutputPath { get; set; } | ||
| 33 | |||
| 34 | private string TargetPath { get; set; } | ||
| 35 | |||
| 36 | private string UpdatedPath { get; set; } | ||
| 37 | |||
| 38 | private string ExportBasePath { get; set; } | ||
| 39 | |||
| 40 | private string IntermediateFolder { get; set; } | ||
| 41 | |||
| 42 | private bool IsAdminImage { get; set; } | ||
| 43 | |||
| 44 | private bool PreserveUnchangedRows { get; set; } | ||
| 45 | |||
| 46 | private bool ShowPedanticMessages { get; set; } | ||
| 47 | |||
| 48 | private bool SuppressKeepingSpecialRows { get; set; } | ||
| 49 | |||
| 50 | private bool OutputAsWixout { get; set; } | ||
| 51 | |||
| 52 | private TransformFlags ValidationFlags { get; set; } | ||
| 53 | |||
| 54 | public override Task<int> ExecuteAsync(CancellationToken cancellationToken) | ||
| 55 | { | ||
| 56 | if (String.IsNullOrEmpty(this.TargetPath)) | ||
| 57 | { | ||
| 58 | Console.Error.WriteLine("Input file required"); | ||
| 59 | return Task.FromResult(-1); | ||
| 60 | } | ||
| 61 | |||
| 62 | if (String.IsNullOrEmpty(this.OutputPath)) | ||
| 63 | { | ||
| 64 | Console.Error.WriteLine("Output file required"); | ||
| 65 | return Task.FromResult(-1); | ||
| 66 | } | ||
| 67 | |||
| 68 | if (String.IsNullOrEmpty(this.IntermediateFolder)) | ||
| 69 | { | ||
| 70 | this.IntermediateFolder = Path.GetTempPath(); | ||
| 71 | } | ||
| 72 | |||
| 73 | var transform = this.LoadTransform(); | ||
| 74 | |||
| 75 | if (!this.Messaging.EncounteredError) | ||
| 76 | { | ||
| 77 | this.SaveTransform(transform); | ||
| 78 | } | ||
| 79 | |||
| 80 | return Task.FromResult(this.Messaging.EncounteredError ? 1 : 0); | ||
| 81 | } | ||
| 82 | |||
| 83 | public override bool TryParseArgument(ICommandLineParser parser, string argument) | ||
| 84 | { | ||
| 85 | if (parser.IsSwitch(argument)) | ||
| 86 | { | ||
| 87 | var parameter = argument.Substring(1); | ||
| 88 | switch (parameter.ToLowerInvariant()) | ||
| 89 | { | ||
| 90 | case "a": | ||
| 91 | this.IsAdminImage = true; | ||
| 92 | return true; | ||
| 93 | |||
| 94 | case "intermediatefolder": | ||
| 95 | this.IntermediateFolder = parser.GetNextArgumentAsDirectoryOrError(argument); | ||
| 96 | return true; | ||
| 97 | |||
| 98 | case "o": | ||
| 99 | case "out": | ||
| 100 | this.OutputPath = parser.GetNextArgumentAsFilePathOrError(argument); | ||
| 101 | return true; | ||
| 102 | |||
| 103 | case "p": | ||
| 104 | this.PreserveUnchangedRows = true; | ||
| 105 | return true; | ||
| 106 | |||
| 107 | case "pedantic": | ||
| 108 | this.ShowPedanticMessages = true; | ||
| 109 | return true; | ||
| 110 | |||
| 111 | case "serr": | ||
| 112 | { | ||
| 113 | var serr = parser.GetNextArgumentOrError(argument); | ||
| 114 | |||
| 115 | switch (serr.ToLowerInvariant()) | ||
| 116 | { | ||
| 117 | case "a": | ||
| 118 | this.ValidationFlags |= TransformFlags.ErrorAddExistingRow; | ||
| 119 | return true; | ||
| 120 | |||
| 121 | case "b": | ||
| 122 | this.ValidationFlags |= TransformFlags.ErrorDeleteMissingRow; | ||
| 123 | return true; | ||
| 124 | |||
| 125 | case "c": | ||
| 126 | this.ValidationFlags |= TransformFlags.ErrorAddExistingTable; | ||
| 127 | return true; | ||
| 128 | |||
| 129 | case "d": | ||
| 130 | this.ValidationFlags |= TransformFlags.ErrorDeleteMissingTable; | ||
| 131 | return true; | ||
| 132 | |||
| 133 | case "e": | ||
| 134 | this.ValidationFlags |= TransformFlags.ErrorUpdateMissingRow; | ||
| 135 | return true; | ||
| 136 | |||
| 137 | case "f": | ||
| 138 | this.ValidationFlags |= TransformFlags.ErrorChangeCodePage; | ||
| 139 | return true; | ||
| 140 | |||
| 141 | default: | ||
| 142 | this.Messaging.Write(ErrorMessages.ExpectedArgument(serr)); | ||
| 143 | return true; | ||
| 144 | } | ||
| 145 | } | ||
| 146 | |||
| 147 | case "val": | ||
| 148 | { | ||
| 149 | var val = parser.GetNextArgumentOrError(argument); | ||
| 150 | |||
| 151 | switch (val.ToLowerInvariant()) | ||
| 152 | { | ||
| 153 | case "language": | ||
| 154 | this.ValidationFlags |= TransformFlags.LanguageTransformDefault; | ||
| 155 | return true; | ||
| 156 | |||
| 157 | case "instance": | ||
| 158 | this.ValidationFlags |= TransformFlags.InstanceTransformDefault; | ||
| 159 | return true; | ||
| 160 | |||
| 161 | case "patch": | ||
| 162 | this.ValidationFlags |= TransformFlags.PatchTransformDefault; | ||
| 163 | return true; | ||
| 164 | |||
| 165 | case "g": | ||
| 166 | this.ValidationFlags |= TransformFlags.ValidateUpgradeCode; | ||
| 167 | return true; | ||
| 168 | |||
| 169 | case "l": | ||
| 170 | this.ValidationFlags |= TransformFlags.ValidateLanguage; | ||
| 171 | return true; | ||
| 172 | |||
| 173 | case "r": | ||
| 174 | this.ValidationFlags |= TransformFlags.ValidateProduct; | ||
| 175 | return true; | ||
| 176 | |||
| 177 | case "s": | ||
| 178 | this.ValidationFlags |= TransformFlags.ValidateMajorVersion; | ||
| 179 | return true; | ||
| 180 | |||
| 181 | case "t": | ||
| 182 | this.ValidationFlags |= TransformFlags.ValidateMinorVersion; | ||
| 183 | return true; | ||
| 184 | |||
| 185 | case "u": | ||
| 186 | this.ValidationFlags |= TransformFlags.ValidateUpdateVersion; | ||
| 187 | return true; | ||
| 188 | |||
| 189 | case "v": | ||
| 190 | this.ValidationFlags |= TransformFlags.ValidateNewLessBaseVersion; | ||
| 191 | return true; | ||
| 192 | |||
| 193 | case "w": | ||
| 194 | this.ValidationFlags |= TransformFlags.ValidateNewLessEqualBaseVersion; | ||
| 195 | return true; | ||
| 196 | |||
| 197 | case "x": | ||
| 198 | this.ValidationFlags |= TransformFlags.ValidateNewEqualBaseVersion; | ||
| 199 | return true; | ||
| 200 | |||
| 201 | case "y": | ||
| 202 | this.ValidationFlags |= TransformFlags.ValidateNewGreaterEqualBaseVersion; | ||
| 203 | return true; | ||
| 204 | |||
| 205 | case "z": | ||
| 206 | this.ValidationFlags |= TransformFlags.ValidateNewGreaterBaseVersion; | ||
| 207 | return true; | ||
| 208 | |||
| 209 | default: | ||
| 210 | this.Messaging.Write(ErrorMessages.ExpectedArgument(val)); | ||
| 211 | return true; | ||
| 212 | } | ||
| 213 | } | ||
| 214 | |||
| 215 | case "x": | ||
| 216 | this.ExportBasePath = parser.GetNextArgumentAsDirectoryOrError(argument); | ||
| 217 | return true; | ||
| 218 | |||
| 219 | case "xo": | ||
| 220 | this.OutputAsWixout = true; | ||
| 221 | return true; | ||
| 222 | } | ||
| 223 | } | ||
| 224 | else if (String.IsNullOrEmpty(this.TargetPath)) | ||
| 225 | { | ||
| 226 | this.TargetPath = argument; | ||
| 227 | return true; | ||
| 228 | } | ||
| 229 | else if (String.IsNullOrEmpty(this.UpdatedPath)) | ||
| 230 | { | ||
| 231 | this.UpdatedPath = argument; | ||
| 232 | return true; | ||
| 233 | } | ||
| 234 | |||
| 235 | return false; | ||
| 236 | } | ||
| 237 | |||
| 238 | private WindowsInstallerData LoadTransform() | ||
| 239 | { | ||
| 240 | WindowsInstallerData transform; | ||
| 241 | |||
| 242 | if (String.IsNullOrEmpty(this.UpdatedPath)) | ||
| 243 | { | ||
| 244 | Exception exception; | ||
| 245 | |||
| 246 | (transform, exception) = LoadWindowsInstallerDataSafely(this.TargetPath); | ||
| 247 | |||
| 248 | if (transform?.Type != OutputType.Transform) | ||
| 249 | { | ||
| 250 | this.Messaging.Write(WindowsInstallerBackendErrors.CannotLoadWixoutAsTransform(new SourceLineNumber(this.TargetPath), exception)); | ||
| 251 | } | ||
| 252 | } | ||
| 253 | else | ||
| 254 | { | ||
| 255 | transform = this.CreateTransform(); | ||
| 256 | |||
| 257 | if (null == transform.Tables || 0 >= transform.Tables.Count) | ||
| 258 | { | ||
| 259 | this.Messaging.Write(ErrorMessages.NoDifferencesInTransform(new SourceLineNumber(this.OutputPath))); | ||
| 260 | } | ||
| 261 | } | ||
| 262 | |||
| 263 | return transform; | ||
| 264 | } | ||
| 265 | |||
| 266 | private void SaveTransform(WindowsInstallerData transform) | ||
| 267 | { | ||
| 268 | if (this.OutputAsWixout) | ||
| 269 | { | ||
| 270 | using (var output = WixOutput.Create(this.OutputPath)) | ||
| 271 | { | ||
| 272 | transform.Save(output); | ||
| 273 | } | ||
| 274 | } | ||
| 275 | else | ||
| 276 | { | ||
| 277 | var fileSystemExtensions = this.ExtensionManager.GetServices<IFileSystemExtension>(); | ||
| 278 | var fileSystemManager = new FileSystemManager(fileSystemExtensions); | ||
| 279 | |||
| 280 | var tableDefinitions = this.GetTableDefinitions(); | ||
| 281 | |||
| 282 | var bindCommand = new BindTransformCommand(this.Messaging, this.BackendHelper, fileSystemManager, this.IntermediateFolder, transform, this.OutputPath, tableDefinitions); | ||
| 283 | bindCommand.Execute(); | ||
| 284 | } | ||
| 285 | } | ||
| 286 | |||
| 287 | private WindowsInstallerData CreateTransform() | ||
| 288 | { | ||
| 289 | if (!TryLoadWindowsInstallerData(this.TargetPath, out var targetOutput)) | ||
| 290 | { | ||
| 291 | var unbindCommand = new UnbindMsiOrMsmCommand(this.Messaging, this.BackendHelper, this.TargetPath, this.ExportBasePath, this.IntermediateFolder, this.IsAdminImage, suppressDemodularization: true, suppressExtractCabinets: true); | ||
| 292 | targetOutput = unbindCommand.Execute(); | ||
| 293 | } | ||
| 294 | |||
| 295 | if (!TryLoadWindowsInstallerData(this.TargetPath, out var updatedOutput)) | ||
| 296 | { | ||
| 297 | var unbindCommand = new UnbindMsiOrMsmCommand(this.Messaging, this.BackendHelper, this.UpdatedPath, this.ExportBasePath, this.IntermediateFolder, this.IsAdminImage, suppressDemodularization: true, suppressExtractCabinets: true); | ||
| 298 | updatedOutput = unbindCommand.Execute(); | ||
| 299 | } | ||
| 300 | |||
| 301 | var differ = new Differ(this.Messaging) | ||
| 302 | { | ||
| 303 | PreserveUnchangedRows = this.PreserveUnchangedRows, | ||
| 304 | ShowPedanticMessages = this.ShowPedanticMessages, | ||
| 305 | SuppressKeepingSpecialRows = this.SuppressKeepingSpecialRows | ||
| 306 | }; | ||
| 307 | |||
| 308 | return differ.Diff(targetOutput, updatedOutput, this.ValidationFlags); | ||
| 309 | } | ||
| 310 | |||
| 311 | private TableDefinitionCollection GetTableDefinitions() | ||
| 312 | { | ||
| 313 | var backendExtensions = this.ExtensionManager.GetServices<IWindowsInstallerBackendBinderExtension>(); | ||
| 314 | |||
| 315 | var loadTableDefinitions = new LoadTableDefinitionsCommand(this.Messaging, null, backendExtensions); | ||
| 316 | return loadTableDefinitions.Execute(); | ||
| 317 | } | ||
| 318 | |||
| 319 | private static bool TryLoadWindowsInstallerData(string path, out WindowsInstallerData data) | ||
| 320 | { | ||
| 321 | data = null; | ||
| 322 | |||
| 323 | var extension = Path.GetExtension(path); | ||
| 324 | |||
| 325 | // If the path is _not_ obviously a Windows Installer database, let's try opening it as | ||
| 326 | // our own data file format. | ||
| 327 | if (!extension.Equals(".msi", StringComparison.OrdinalIgnoreCase) && !extension.Equals(".msm", StringComparison.OrdinalIgnoreCase)) | ||
| 328 | { | ||
| 329 | (data, _) = LoadWindowsInstallerDataSafely(path); | ||
| 330 | } | ||
| 331 | |||
| 332 | return data != null; | ||
| 333 | } | ||
| 334 | |||
| 335 | private static (WindowsInstallerData, Exception) LoadWindowsInstallerDataSafely(string path) | ||
| 336 | { | ||
| 337 | WindowsInstallerData data = null; | ||
| 338 | Exception exception = null; | ||
| 339 | |||
| 340 | try | ||
| 341 | { | ||
| 342 | data = WindowsInstallerData.Load(path); | ||
| 343 | } | ||
| 344 | catch (Exception e) | ||
| 345 | { | ||
| 346 | exception = e; | ||
| 347 | } | ||
| 348 | |||
| 349 | return (data, exception); | ||
| 350 | } | ||
| 351 | } | ||
| 352 | } | ||
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/CommandLine/WindowsInstallerCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/CommandLine/WindowsInstallerCommand.cs index a0da7fa4..ed0c0658 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/CommandLine/WindowsInstallerCommand.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/CommandLine/WindowsInstallerCommand.cs | |||
| @@ -49,6 +49,10 @@ namespace WixToolset.Core.WindowsInstaller.CommandLine | |||
| 49 | this.Subcommand = new InscribeSubcommand(this.ServiceProvider); | 49 | this.Subcommand = new InscribeSubcommand(this.ServiceProvider); |
| 50 | return true; | 50 | return true; |
| 51 | 51 | ||
| 52 | case "transform": | ||
| 53 | this.Subcommand = new TransformSubcommand(this.ServiceProvider); | ||
| 54 | return true; | ||
| 55 | |||
| 52 | case "validate": | 56 | case "validate": |
| 53 | this.Subcommand = new ValidateSubcommand(this.ServiceProvider); | 57 | this.Subcommand = new ValidateSubcommand(this.ServiceProvider); |
| 54 | return true; | 58 | return true; |
| @@ -72,6 +76,7 @@ namespace WixToolset.Core.WindowsInstaller.CommandLine | |||
| 72 | Console.WriteLine("Commands:"); | 76 | Console.WriteLine("Commands:"); |
| 73 | Console.WriteLine(); | 77 | Console.WriteLine(); |
| 74 | Console.WriteLine(" inscribe Updates MSI database with cabinet signature information."); | 78 | Console.WriteLine(" inscribe Updates MSI database with cabinet signature information."); |
| 79 | Console.WriteLine(" transform Creates an MST transform file."); | ||
| 75 | Console.WriteLine(" validate Validates MSI database using standard or custom ICEs."); | 80 | Console.WriteLine(" validate Validates MSI database using standard or custom ICEs."); |
| 76 | } | 81 | } |
| 77 | } | 82 | } |
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Differ.cs b/src/wix/WixToolset.Core.WindowsInstaller/Differ.cs index 304d0152..8b474605 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Differ.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Differ.cs | |||
| @@ -1,18 +1,15 @@ | |||
| 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. |
| 2 | 2 | ||
| 3 | #if DELETE | ||
| 4 | |||
| 5 | namespace WixToolset.Core.WindowsInstaller | 3 | namespace WixToolset.Core.WindowsInstaller |
| 6 | { | 4 | { |
| 7 | using System; | 5 | using System; |
| 8 | using System.Collections; | 6 | using System.Collections; |
| 9 | using System.Collections.Generic; | 7 | using System.Collections.Generic; |
| 10 | using System.Globalization; | 8 | using System.Globalization; |
| 11 | using WixToolset.Core.WindowsInstaller.Msi; | 9 | using WixToolset.Core.Native.Msi; |
| 12 | using WixToolset.Data; | 10 | using WixToolset.Data; |
| 13 | using WixToolset.Data.Symbols; | 11 | using WixToolset.Data.Symbols; |
| 14 | using WixToolset.Data.WindowsInstaller; | 12 | using WixToolset.Data.WindowsInstaller; |
| 15 | using WixToolset.Data.WindowsInstaller.Rows; | ||
| 16 | using WixToolset.Extensibility; | 13 | using WixToolset.Extensibility; |
| 17 | using WixToolset.Extensibility.Services; | 14 | using WixToolset.Extensibility.Services; |
| 18 | 15 | ||
| @@ -22,9 +19,6 @@ namespace WixToolset.Core.WindowsInstaller | |||
| 22 | public sealed class Differ | 19 | public sealed class Differ |
| 23 | { | 20 | { |
| 24 | private readonly List<IInspectorExtension> inspectorExtensions; | 21 | private readonly List<IInspectorExtension> inspectorExtensions; |
| 25 | private bool showPedanticMessages; | ||
| 26 | private bool suppressKeepingSpecialRows; | ||
| 27 | private bool preserveUnchangedRows; | ||
| 28 | private const char sectionDelimiter = '/'; | 22 | private const char sectionDelimiter = '/'; |
| 29 | private readonly IMessaging messaging; | 23 | private readonly IMessaging messaging; |
| 30 | private SummaryInformationStreams transformSummaryInfo; | 24 | private SummaryInformationStreams transformSummaryInfo; |
| @@ -42,31 +36,19 @@ namespace WixToolset.Core.WindowsInstaller | |||
| 42 | /// Gets or sets the option to show pedantic messages. | 36 | /// Gets or sets the option to show pedantic messages. |
| 43 | /// </summary> | 37 | /// </summary> |
| 44 | /// <value>The option to show pedantic messages.</value> | 38 | /// <value>The option to show pedantic messages.</value> |
| 45 | public bool ShowPedanticMessages | 39 | public bool ShowPedanticMessages { get; set; } |
| 46 | { | ||
| 47 | get { return this.showPedanticMessages; } | ||
| 48 | set { this.showPedanticMessages = value; } | ||
| 49 | } | ||
| 50 | 40 | ||
| 51 | /// <summary> | 41 | /// <summary> |
| 52 | /// Gets or sets the option to suppress keeping special rows. | 42 | /// Gets or sets the option to suppress keeping special rows. |
| 53 | /// </summary> | 43 | /// </summary> |
| 54 | /// <value>The option to suppress keeping special rows.</value> | 44 | /// <value>The option to suppress keeping special rows.</value> |
| 55 | public bool SuppressKeepingSpecialRows | 45 | public bool SuppressKeepingSpecialRows { get; set; } |
| 56 | { | ||
| 57 | get { return this.suppressKeepingSpecialRows; } | ||
| 58 | set { this.suppressKeepingSpecialRows = value; } | ||
| 59 | } | ||
| 60 | 46 | ||
| 61 | /// <summary> | 47 | /// <summary> |
| 62 | /// Gets or sets the flag to determine if all rows, even unchanged ones will be persisted in the output. | 48 | /// Gets or sets the flag to determine if all rows, even unchanged ones will be persisted in the output. |
| 63 | /// </summary> | 49 | /// </summary> |
| 64 | /// <value>The option to keep all rows including unchanged rows.</value> | 50 | /// <value>The option to keep all rows including unchanged rows.</value> |
| 65 | public bool PreserveUnchangedRows | 51 | public bool PreserveUnchangedRows { get; set; } |
| 66 | { | ||
| 67 | get { return this.preserveUnchangedRows; } | ||
| 68 | set { this.preserveUnchangedRows = value; } | ||
| 69 | } | ||
| 70 | 52 | ||
| 71 | /// <summary> | 53 | /// <summary> |
| 72 | /// Adds an extension. | 54 | /// Adds an extension. |
| @@ -97,7 +79,7 @@ namespace WixToolset.Core.WindowsInstaller | |||
| 97 | /// <returns>The transform.</returns> | 79 | /// <returns>The transform.</returns> |
| 98 | public WindowsInstallerData Diff(WindowsInstallerData targetOutput, WindowsInstallerData updatedOutput, TransformFlags validationFlags) | 80 | public WindowsInstallerData Diff(WindowsInstallerData targetOutput, WindowsInstallerData updatedOutput, TransformFlags validationFlags) |
| 99 | { | 81 | { |
| 100 | WindowsInstallerData transform = new WindowsInstallerData(null); | 82 | var transform = new WindowsInstallerData(null); |
| 101 | transform.Type = OutputType.Transform; | 83 | transform.Type = OutputType.Transform; |
| 102 | transform.Codepage = updatedOutput.Codepage; | 84 | transform.Codepage = updatedOutput.Codepage; |
| 103 | this.transformSummaryInfo = new SummaryInformationStreams(); | 85 | this.transformSummaryInfo = new SummaryInformationStreams(); |
| @@ -119,34 +101,34 @@ namespace WixToolset.Core.WindowsInstaller | |||
| 119 | } | 101 | } |
| 120 | 102 | ||
| 121 | // compare the contents of the tables | 103 | // compare the contents of the tables |
| 122 | foreach (Table targetTable in targetOutput.Tables) | 104 | foreach (var targetTable in targetOutput.Tables) |
| 123 | { | 105 | { |
| 124 | Table updatedTable = updatedOutput.Tables[targetTable.Name]; | 106 | var updatedTable = updatedOutput.Tables[targetTable.Name]; |
| 125 | TableOperation operation = TableOperation.None; | 107 | var operation = TableOperation.None; |
| 126 | 108 | ||
| 127 | List<Row> rows = this.CompareTables(targetOutput, targetTable, updatedTable, out operation); | 109 | var rows = this.CompareTables(targetOutput, targetTable, updatedTable, out operation); |
| 128 | 110 | ||
| 129 | if (TableOperation.Drop == operation) | 111 | if (TableOperation.Drop == operation) |
| 130 | { | 112 | { |
| 131 | Table droppedTable = transform.EnsureTable(targetTable.Definition); | 113 | var droppedTable = transform.EnsureTable(targetTable.Definition); |
| 132 | droppedTable.Operation = TableOperation.Drop; | 114 | droppedTable.Operation = TableOperation.Drop; |
| 133 | } | 115 | } |
| 134 | else if (TableOperation.None == operation) | 116 | else if (TableOperation.None == operation) |
| 135 | { | 117 | { |
| 136 | Table modified = transform.EnsureTable(updatedTable.Definition); | 118 | var modified = transform.EnsureTable(updatedTable.Definition); |
| 137 | rows.ForEach(r => modified.Rows.Add(r)); | 119 | rows.ForEach(r => modified.Rows.Add(r)); |
| 138 | } | 120 | } |
| 139 | } | 121 | } |
| 140 | 122 | ||
| 141 | // added tables | 123 | // added tables |
| 142 | foreach (Table updatedTable in updatedOutput.Tables) | 124 | foreach (var updatedTable in updatedOutput.Tables) |
| 143 | { | 125 | { |
| 144 | if (null == targetOutput.Tables[updatedTable.Name]) | 126 | if (null == targetOutput.Tables[updatedTable.Name]) |
| 145 | { | 127 | { |
| 146 | Table addedTable = transform.EnsureTable(updatedTable.Definition); | 128 | var addedTable = transform.EnsureTable(updatedTable.Definition); |
| 147 | addedTable.Operation = TableOperation.Add; | 129 | addedTable.Operation = TableOperation.Add; |
| 148 | 130 | ||
| 149 | foreach (Row updatedRow in updatedTable.Rows) | 131 | foreach (var updatedRow in updatedTable.Rows) |
| 150 | { | 132 | { |
| 151 | updatedRow.Operation = RowOperation.Add; | 133 | updatedRow.Operation = RowOperation.Add; |
| 152 | updatedRow.SectionId = sectionDelimiter + updatedRow.SectionId; | 134 | updatedRow.SectionId = sectionDelimiter + updatedRow.SectionId; |
| @@ -156,9 +138,9 @@ namespace WixToolset.Core.WindowsInstaller | |||
| 156 | } | 138 | } |
| 157 | 139 | ||
| 158 | // set summary information properties | 140 | // set summary information properties |
| 159 | if (!this.suppressKeepingSpecialRows) | 141 | if (!this.SuppressKeepingSpecialRows) |
| 160 | { | 142 | { |
| 161 | Table summaryInfoTable = transform.Tables["_SummaryInformation"]; | 143 | var summaryInfoTable = transform.Tables["_SummaryInformation"]; |
| 162 | this.UpdateTransformSummaryInformationTable(summaryInfoTable, validationFlags); | 144 | this.UpdateTransformSummaryInformationTable(summaryInfoTable, validationFlags); |
| 163 | } | 145 | } |
| 164 | 146 | ||
| @@ -170,53 +152,56 @@ namespace WixToolset.Core.WindowsInstaller | |||
| 170 | /// </summary> | 152 | /// </summary> |
| 171 | /// <param name="index">The indexed rows.</param> | 153 | /// <param name="index">The indexed rows.</param> |
| 172 | /// <param name="row">The row to index.</param> | 154 | /// <param name="row">The row to index.</param> |
| 173 | private void AddIndexedRow(IDictionary index, Row row) | 155 | private void AddIndexedRow(IDictionary<string, Row> index, Row row) |
| 174 | { | 156 | { |
| 175 | string primaryKey = row.GetPrimaryKey('/'); | 157 | var primaryKey = row.GetPrimaryKey('/'); |
| 176 | if (null != primaryKey) | 158 | |
| 159 | // If there is no primary, use the string representation of the row as its | ||
| 160 | // primary key (even though it may not be unique). | ||
| 161 | if (String.IsNullOrEmpty(primaryKey)) | ||
| 177 | { | 162 | { |
| 178 | // Overriding WixActionRows have a primary key defined and take precedence in the index. | 163 | // This is provided for compatibility with unreal tables with no primary key |
| 179 | if (row is WixActionRow) | 164 | // all real tables must specify at least one column as the primary key. |
| 165 | primaryKey = row.ToString(); | ||
| 166 | index[primaryKey] = row; | ||
| 167 | } | ||
| 168 | else | ||
| 169 | { | ||
| 170 | if (!index.TryGetValue(primaryKey, out var existingRow)) | ||
| 171 | { | ||
| 172 | index.Add(primaryKey, row); | ||
| 173 | } | ||
| 174 | else | ||
| 180 | { | 175 | { |
| 181 | WixActionRow currentRow = (WixActionRow)row; | 176 | #if TODO |
| 182 | if (index.Contains(primaryKey)) | 177 | // Overriding WixActionRows have a primary key defined and take precedence in the index. |
| 178 | if (row is WixActionRow currentActionRow) | ||
| 183 | { | 179 | { |
| 184 | // If the current row is not overridable, see if the indexed row is. | 180 | // If the current row is not overridable, see if the indexed row is. |
| 185 | if (!currentRow.Overridable) | 181 | if (!currentActionRow.Overridable) |
| 186 | { | 182 | { |
| 187 | WixActionRow indexedRow = index[primaryKey] as WixActionRow; | 183 | if (existingRow is WixActionRow existingActionRow && existingActionRow.Overridable) |
| 188 | if (null != indexedRow && indexedRow.Overridable) | ||
| 189 | { | 184 | { |
| 190 | // The indexed key is overridable and should be replaced | 185 | // The indexed key is overridable and should be replaced |
| 191 | // (not removed and re-added which results in two Array.Copy | 186 | // (not removed and re-added which results in two Array.Copy |
| 192 | // operations for SortedList, or may be re-hashing in other | 187 | // operations for SortedList, or may be re-hashing in other |
| 193 | // implementations of IDictionary). | 188 | // implementations of IDictionary). |
| 194 | index[primaryKey] = currentRow; | 189 | index[primaryKey] = currentActionRow; |
| 195 | } | 190 | } |
| 196 | } | 191 | } |
| 197 | 192 | ||
| 198 | // If we got this far, the row does not need to be indexed. | 193 | // If we got this far, the row does not need to be indexed. |
| 199 | return; | 194 | return; |
| 200 | } | 195 | } |
| 201 | } | 196 | #endif |
| 202 | 197 | ||
| 203 | // Nothing else should be added more than once. | 198 | // Nothing else should be added more than once. |
| 204 | if (!index.Contains(primaryKey)) | 199 | if (this.ShowPedanticMessages) |
| 205 | { | 200 | { |
| 206 | index.Add(primaryKey, row); | 201 | this.messaging.Write(ErrorMessages.DuplicatePrimaryKey(row.SourceLineNumbers, primaryKey, row.Table.Name)); |
| 207 | } | 202 | } |
| 208 | else if (this.showPedanticMessages) | ||
| 209 | { | ||
| 210 | this.messaging.Write(ErrorMessages.DuplicatePrimaryKey(row.SourceLineNumbers, primaryKey, row.Table.Name)); | ||
| 211 | } | 203 | } |
| 212 | } | 204 | } |
| 213 | else // use the string representation of the row as its primary key (it may not be unique) | ||
| 214 | { | ||
| 215 | // this is provided for compatibility with unreal tables with no primary key | ||
| 216 | // all real tables must specify at least one column as the primary key | ||
| 217 | primaryKey = row.ToString(); | ||
| 218 | index[primaryKey] = row; | ||
| 219 | } | ||
| 220 | } | 205 | } |
| 221 | 206 | ||
| 222 | private Row CompareRows(Table targetTable, Row targetRow, Row updatedRow, out RowOperation operation, out bool keepRow) | 207 | private Row CompareRows(Table targetTable, Row targetRow, Row updatedRow, out RowOperation operation, out bool keepRow) |
| @@ -235,7 +220,7 @@ namespace WixToolset.Core.WindowsInstaller | |||
| 235 | else if (null == updatedRow) | 220 | else if (null == updatedRow) |
| 236 | { | 221 | { |
| 237 | operation = targetRow.Operation = RowOperation.Delete; | 222 | operation = targetRow.Operation = RowOperation.Delete; |
| 238 | targetRow.SectionId = targetRow.SectionId + sectionDelimiter; | 223 | targetRow.SectionId += sectionDelimiter; |
| 239 | comparedRow = targetRow; | 224 | comparedRow = targetRow; |
| 240 | keepRow = true; | 225 | keepRow = true; |
| 241 | } | 226 | } |
| @@ -243,7 +228,7 @@ namespace WixToolset.Core.WindowsInstaller | |||
| 243 | else // possibly modified | 228 | else // possibly modified |
| 244 | { | 229 | { |
| 245 | updatedRow.Operation = RowOperation.None; | 230 | updatedRow.Operation = RowOperation.None; |
| 246 | if (!this.suppressKeepingSpecialRows && "_SummaryInformation" == targetTable.Name) | 231 | if (!this.SuppressKeepingSpecialRows && "_SummaryInformation" == targetTable.Name) |
| 247 | { | 232 | { |
| 248 | // ignore rows that shouldn't be in a transform | 233 | // ignore rows that shouldn't be in a transform |
| 249 | if (Enum.IsDefined(typeof(SummaryInformation.Transform), (int)updatedRow[0])) | 234 | if (Enum.IsDefined(typeof(SummaryInformation.Transform), (int)updatedRow[0])) |
| @@ -256,18 +241,18 @@ namespace WixToolset.Core.WindowsInstaller | |||
| 256 | } | 241 | } |
| 257 | else | 242 | else |
| 258 | { | 243 | { |
| 259 | if (this.preserveUnchangedRows) | 244 | if (this.PreserveUnchangedRows) |
| 260 | { | 245 | { |
| 261 | keepRow = true; | 246 | keepRow = true; |
| 262 | } | 247 | } |
| 263 | 248 | ||
| 264 | for (int i = 0; i < updatedRow.Fields.Length; i++) | 249 | for (var i = 0; i < updatedRow.Fields.Length; i++) |
| 265 | { | 250 | { |
| 266 | ColumnDefinition columnDefinition = updatedRow.Fields[i].Column; | 251 | var columnDefinition = updatedRow.Fields[i].Column; |
| 267 | 252 | ||
| 268 | if (!columnDefinition.PrimaryKey) | 253 | if (!columnDefinition.PrimaryKey) |
| 269 | { | 254 | { |
| 270 | bool modified = false; | 255 | var modified = false; |
| 271 | 256 | ||
| 272 | if (i >= targetRow.Fields.Length) | 257 | if (i >= targetRow.Fields.Length) |
| 273 | { | 258 | { |
| @@ -290,12 +275,12 @@ namespace WixToolset.Core.WindowsInstaller | |||
| 290 | updatedRow.Fields[i].PreviousData = (string)targetRow.Fields[i].Data; | 275 | updatedRow.Fields[i].PreviousData = (string)targetRow.Fields[i].Data; |
| 291 | 276 | ||
| 292 | // keep rows containing preserved fields so the historical data is available to the binder | 277 | // keep rows containing preserved fields so the historical data is available to the binder |
| 293 | keepRow = !this.suppressKeepingSpecialRows; | 278 | keepRow = !this.SuppressKeepingSpecialRows; |
| 294 | } | 279 | } |
| 295 | else if (ColumnType.Object == columnDefinition.Type) | 280 | else if (ColumnType.Object == columnDefinition.Type) |
| 296 | { | 281 | { |
| 297 | ObjectField targetObjectField = (ObjectField)targetRow.Fields[i]; | 282 | var targetObjectField = (ObjectField)targetRow.Fields[i]; |
| 298 | ObjectField updatedObjectField = (ObjectField)updatedRow.Fields[i]; | 283 | var updatedObjectField = (ObjectField)updatedRow.Fields[i]; |
| 299 | 284 | ||
| 300 | updatedObjectField.PreviousEmbeddedFileIndex = targetObjectField.EmbeddedFileIndex; | 285 | updatedObjectField.PreviousEmbeddedFileIndex = targetObjectField.EmbeddedFileIndex; |
| 301 | updatedObjectField.PreviousBaseUri = targetObjectField.BaseUri; | 286 | updatedObjectField.PreviousBaseUri = targetObjectField.BaseUri; |
| @@ -308,7 +293,7 @@ namespace WixToolset.Core.WindowsInstaller | |||
| 308 | updatedObjectField.UnresolvedPreviousData = (string)targetObjectField.UnresolvedData; | 293 | updatedObjectField.UnresolvedPreviousData = (string)targetObjectField.UnresolvedData; |
| 309 | 294 | ||
| 310 | // keep rows containing object fields so the files can be compared in the binder | 295 | // keep rows containing object fields so the files can be compared in the binder |
| 311 | keepRow = !this.suppressKeepingSpecialRows; | 296 | keepRow = !this.SuppressKeepingSpecialRows; |
| 312 | } | 297 | } |
| 313 | else | 298 | else |
| 314 | { | 299 | { |
| @@ -342,7 +327,7 @@ namespace WixToolset.Core.WindowsInstaller | |||
| 342 | 327 | ||
| 343 | private List<Row> CompareTables(WindowsInstallerData targetOutput, Table targetTable, Table updatedTable, out TableOperation operation) | 328 | private List<Row> CompareTables(WindowsInstallerData targetOutput, Table targetTable, Table updatedTable, out TableOperation operation) |
| 344 | { | 329 | { |
| 345 | List<Row> rows = new List<Row>(); | 330 | var rows = new List<Row>(); |
| 346 | operation = TableOperation.None; | 331 | operation = TableOperation.None; |
| 347 | 332 | ||
| 348 | // dropped tables | 333 | // dropped tables |
| @@ -360,8 +345,8 @@ namespace WixToolset.Core.WindowsInstaller | |||
| 360 | } | 345 | } |
| 361 | else // possibly modified tables | 346 | else // possibly modified tables |
| 362 | { | 347 | { |
| 363 | SortedList updatedPrimaryKeys = new SortedList(); | 348 | var updatedPrimaryKeys = new SortedDictionary<string, Row>(); |
| 364 | SortedList targetPrimaryKeys = new SortedList(); | 349 | var targetPrimaryKeys = new SortedDictionary<string, Row>(); |
| 365 | 350 | ||
| 366 | // compare the table definitions | 351 | // compare the table definitions |
| 367 | if (0 != targetTable.Definition.CompareTo(updatedTable.Definition)) | 352 | if (0 != targetTable.Definition.CompareTo(updatedTable.Definition)) |
| @@ -374,13 +359,10 @@ namespace WixToolset.Core.WindowsInstaller | |||
| 374 | this.IndexPrimaryKeys(targetTable, targetPrimaryKeys, updatedTable, updatedPrimaryKeys); | 359 | this.IndexPrimaryKeys(targetTable, targetPrimaryKeys, updatedTable, updatedPrimaryKeys); |
| 375 | 360 | ||
| 376 | // diff the target and updated rows | 361 | // diff the target and updated rows |
| 377 | foreach (DictionaryEntry targetPrimaryKeyEntry in targetPrimaryKeys) | 362 | foreach (var targetPrimaryKeyEntry in targetPrimaryKeys) |
| 378 | { | 363 | { |
| 379 | string targetPrimaryKey = (string)targetPrimaryKeyEntry.Key; | 364 | var targetPrimaryKey = targetPrimaryKeyEntry.Key; |
| 380 | bool keepRow = false; | 365 | var compared = this.CompareRows(targetTable, targetPrimaryKeyEntry.Value, updatedPrimaryKeys[targetPrimaryKey], out var _, out var keepRow); |
| 381 | RowOperation rowOperation = RowOperation.None; | ||
| 382 | |||
| 383 | Row compared = this.CompareRows(targetTable, targetPrimaryKeyEntry.Value as Row, updatedPrimaryKeys[targetPrimaryKey] as Row, out rowOperation, out keepRow); | ||
| 384 | 366 | ||
| 385 | if (keepRow) | 367 | if (keepRow) |
| 386 | { | 368 | { |
| @@ -389,13 +371,13 @@ namespace WixToolset.Core.WindowsInstaller | |||
| 389 | } | 371 | } |
| 390 | 372 | ||
| 391 | // find the inserted rows | 373 | // find the inserted rows |
| 392 | foreach (DictionaryEntry updatedPrimaryKeyEntry in updatedPrimaryKeys) | 374 | foreach (var updatedPrimaryKeyEntry in updatedPrimaryKeys) |
| 393 | { | 375 | { |
| 394 | string updatedPrimaryKey = (string)updatedPrimaryKeyEntry.Key; | 376 | var updatedPrimaryKey = (string)updatedPrimaryKeyEntry.Key; |
| 395 | 377 | ||
| 396 | if (!targetPrimaryKeys.Contains(updatedPrimaryKey)) | 378 | if (!targetPrimaryKeys.ContainsKey(updatedPrimaryKey)) |
| 397 | { | 379 | { |
| 398 | Row updatedRow = (Row)updatedPrimaryKeyEntry.Value; | 380 | var updatedRow = (Row)updatedPrimaryKeyEntry.Value; |
| 399 | 381 | ||
| 400 | updatedRow.Operation = RowOperation.Add; | 382 | updatedRow.Operation = RowOperation.Add; |
| 401 | updatedRow.SectionId = sectionDelimiter + updatedRow.SectionId; | 383 | updatedRow.SectionId = sectionDelimiter + updatedRow.SectionId; |
| @@ -408,10 +390,10 @@ namespace WixToolset.Core.WindowsInstaller | |||
| 408 | return rows; | 390 | return rows; |
| 409 | } | 391 | } |
| 410 | 392 | ||
| 411 | private void IndexPrimaryKeys(Table targetTable, SortedList targetPrimaryKeys, Table updatedTable, SortedList updatedPrimaryKeys) | 393 | private void IndexPrimaryKeys(Table targetTable, SortedDictionary<string, Row> targetPrimaryKeys, Table updatedTable, SortedDictionary<string, Row> updatedPrimaryKeys) |
| 412 | { | 394 | { |
| 413 | // index the target rows | 395 | // index the target rows |
| 414 | foreach (Row row in targetTable.Rows) | 396 | foreach (var row in targetTable.Rows) |
| 415 | { | 397 | { |
| 416 | this.AddIndexedRow(targetPrimaryKeys, row); | 398 | this.AddIndexedRow(targetPrimaryKeys, row); |
| 417 | 399 | ||
| @@ -452,7 +434,7 @@ namespace WixToolset.Core.WindowsInstaller | |||
| 452 | } | 434 | } |
| 453 | 435 | ||
| 454 | // index the updated rows | 436 | // index the updated rows |
| 455 | foreach (Row row in updatedTable.Rows) | 437 | foreach (var row in updatedTable.Rows) |
| 456 | { | 438 | { |
| 457 | this.AddIndexedRow(updatedPrimaryKeys, row); | 439 | this.AddIndexedRow(updatedPrimaryKeys, row); |
| 458 | 440 | ||
| @@ -492,17 +474,15 @@ namespace WixToolset.Core.WindowsInstaller | |||
| 492 | private void UpdateTransformSummaryInformationTable(Table summaryInfoTable, TransformFlags validationFlags) | 474 | private void UpdateTransformSummaryInformationTable(Table summaryInfoTable, TransformFlags validationFlags) |
| 493 | { | 475 | { |
| 494 | // calculate the minimum version of MSI required to process the transform | 476 | // calculate the minimum version of MSI required to process the transform |
| 495 | int targetMin; | 477 | var minimumVersion = 100; |
| 496 | int updatedMin; | ||
| 497 | int minimumVersion = 100; | ||
| 498 | 478 | ||
| 499 | if (Int32.TryParse(this.transformSummaryInfo.TargetMinimumVersion, out targetMin) && Int32.TryParse(this.transformSummaryInfo.UpdatedMinimumVersion, out updatedMin)) | 479 | if (Int32.TryParse(this.transformSummaryInfo.TargetMinimumVersion, out var targetMin) && Int32.TryParse(this.transformSummaryInfo.UpdatedMinimumVersion, out var updatedMin)) |
| 500 | { | 480 | { |
| 501 | minimumVersion = Math.Max(targetMin, updatedMin); | 481 | minimumVersion = Math.Max(targetMin, updatedMin); |
| 502 | } | 482 | } |
| 503 | 483 | ||
| 504 | Hashtable summaryRows = new Hashtable(summaryInfoTable.Rows.Count); | 484 | var summaryRows = new Hashtable(summaryInfoTable.Rows.Count); |
| 505 | foreach (Row row in summaryInfoTable.Rows) | 485 | foreach (var row in summaryInfoTable.Rows) |
| 506 | { | 486 | { |
| 507 | summaryRows[row[0]] = row; | 487 | summaryRows[row[0]] = row; |
| 508 | 488 | ||
| @@ -535,35 +515,35 @@ namespace WixToolset.Core.WindowsInstaller | |||
| 535 | 515 | ||
| 536 | if (!summaryRows.Contains((int)SummaryInformation.Transform.TargetPlatformAndLanguage)) | 516 | if (!summaryRows.Contains((int)SummaryInformation.Transform.TargetPlatformAndLanguage)) |
| 537 | { | 517 | { |
| 538 | Row summaryRow = summaryInfoTable.CreateRow(null); | 518 | var summaryRow = summaryInfoTable.CreateRow(null); |
| 539 | summaryRow[0] = (int)SummaryInformation.Transform.TargetPlatformAndLanguage; | 519 | summaryRow[0] = (int)SummaryInformation.Transform.TargetPlatformAndLanguage; |
| 540 | summaryRow[1] = this.transformSummaryInfo.TargetPlatformAndLanguage; | 520 | summaryRow[1] = this.transformSummaryInfo.TargetPlatformAndLanguage; |
| 541 | } | 521 | } |
| 542 | 522 | ||
| 543 | if (!summaryRows.Contains((int)SummaryInformation.Transform.UpdatedPlatformAndLanguage)) | 523 | if (!summaryRows.Contains((int)SummaryInformation.Transform.UpdatedPlatformAndLanguage)) |
| 544 | { | 524 | { |
| 545 | Row summaryRow = summaryInfoTable.CreateRow(null); | 525 | var summaryRow = summaryInfoTable.CreateRow(null); |
| 546 | summaryRow[0] = (int)SummaryInformation.Transform.UpdatedPlatformAndLanguage; | 526 | summaryRow[0] = (int)SummaryInformation.Transform.UpdatedPlatformAndLanguage; |
| 547 | summaryRow[1] = this.transformSummaryInfo.UpdatedPlatformAndLanguage; | 527 | summaryRow[1] = this.transformSummaryInfo.UpdatedPlatformAndLanguage; |
| 548 | } | 528 | } |
| 549 | 529 | ||
| 550 | if (!summaryRows.Contains((int)SummaryInformation.Transform.ValidationFlags)) | 530 | if (!summaryRows.Contains((int)SummaryInformation.Transform.ValidationFlags)) |
| 551 | { | 531 | { |
| 552 | Row summaryRow = summaryInfoTable.CreateRow(null); | 532 | var summaryRow = summaryInfoTable.CreateRow(null); |
| 553 | summaryRow[0] = (int)SummaryInformation.Transform.ValidationFlags; | 533 | summaryRow[0] = (int)SummaryInformation.Transform.ValidationFlags; |
| 554 | summaryRow[1] = ((int)validationFlags).ToString(CultureInfo.InvariantCulture); | 534 | summaryRow[1] = ((int)validationFlags).ToString(CultureInfo.InvariantCulture); |
| 555 | } | 535 | } |
| 556 | 536 | ||
| 557 | if (!summaryRows.Contains((int)SummaryInformation.Transform.InstallerRequirement)) | 537 | if (!summaryRows.Contains((int)SummaryInformation.Transform.InstallerRequirement)) |
| 558 | { | 538 | { |
| 559 | Row summaryRow = summaryInfoTable.CreateRow(null); | 539 | var summaryRow = summaryInfoTable.CreateRow(null); |
| 560 | summaryRow[0] = (int)SummaryInformation.Transform.InstallerRequirement; | 540 | summaryRow[0] = (int)SummaryInformation.Transform.InstallerRequirement; |
| 561 | summaryRow[1] = minimumVersion.ToString(CultureInfo.InvariantCulture); | 541 | summaryRow[1] = minimumVersion.ToString(CultureInfo.InvariantCulture); |
| 562 | } | 542 | } |
| 563 | 543 | ||
| 564 | if (!summaryRows.Contains((int)SummaryInformation.Transform.Security)) | 544 | if (!summaryRows.Contains((int)SummaryInformation.Transform.Security)) |
| 565 | { | 545 | { |
| 566 | Row summaryRow = summaryInfoTable.CreateRow(null); | 546 | var summaryRow = summaryInfoTable.CreateRow(null); |
| 567 | summaryRow[0] = (int)SummaryInformation.Transform.Security; | 547 | summaryRow[0] = (int)SummaryInformation.Transform.Security; |
| 568 | summaryRow[1] = "4"; | 548 | summaryRow[1] = "4"; |
| 569 | } | 549 | } |
| @@ -606,5 +586,3 @@ namespace WixToolset.Core.WindowsInstaller | |||
| 606 | } | 586 | } |
| 607 | } | 587 | } |
| 608 | } | 588 | } |
| 609 | |||
| 610 | #endif | ||
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/MsiBackend.cs b/src/wix/WixToolset.Core.WindowsInstaller/MsiBackend.cs index 33aa7a74..628ad8de 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/MsiBackend.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/MsiBackend.cs | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | 2 | ||
| 3 | namespace WixToolset.Core.WindowsInstaller | 3 | namespace WixToolset.Core.WindowsInstaller |
| 4 | { | 4 | { |
| 5 | using System; | ||
| 5 | using WixToolset.Core.WindowsInstaller.Bind; | 6 | using WixToolset.Core.WindowsInstaller.Bind; |
| 6 | using WixToolset.Core.WindowsInstaller.Decompile; | 7 | using WixToolset.Core.WindowsInstaller.Decompile; |
| 7 | using WixToolset.Core.WindowsInstaller.Unbind; | 8 | using WixToolset.Core.WindowsInstaller.Unbind; |
| @@ -71,8 +72,7 @@ namespace WixToolset.Core.WindowsInstaller | |||
| 71 | 72 | ||
| 72 | public Intermediate Unbind(IUnbindContext context) | 73 | public Intermediate Unbind(IUnbindContext context) |
| 73 | { | 74 | { |
| 74 | var command = new UnbindMsiOrMsmCommand(context); | 75 | throw new NotImplementedException(); |
| 75 | return command.Execute(); | ||
| 76 | } | 76 | } |
| 77 | } | 77 | } |
| 78 | } | 78 | } |
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/MsmBackend.cs b/src/wix/WixToolset.Core.WindowsInstaller/MsmBackend.cs index 02ea5f45..01e3c6d8 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/MsmBackend.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/MsmBackend.cs | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | 2 | ||
| 3 | namespace WixToolset.Core.WindowsInstaller | 3 | namespace WixToolset.Core.WindowsInstaller |
| 4 | { | 4 | { |
| 5 | using System; | ||
| 5 | using WixToolset.Core.WindowsInstaller.Bind; | 6 | using WixToolset.Core.WindowsInstaller.Bind; |
| 6 | using WixToolset.Core.WindowsInstaller.Decompile; | 7 | using WixToolset.Core.WindowsInstaller.Decompile; |
| 7 | using WixToolset.Core.WindowsInstaller.Unbind; | 8 | using WixToolset.Core.WindowsInstaller.Unbind; |
| @@ -67,8 +68,7 @@ namespace WixToolset.Core.WindowsInstaller | |||
| 67 | 68 | ||
| 68 | public Intermediate Unbind(IUnbindContext context) | 69 | public Intermediate Unbind(IUnbindContext context) |
| 69 | { | 70 | { |
| 70 | var command = new UnbindMsiOrMsmCommand(context); | 71 | throw new NotImplementedException(); |
| 71 | return command.Execute(); | ||
| 72 | } | 72 | } |
| 73 | } | 73 | } |
| 74 | } | 74 | } |
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/MspBackend.cs b/src/wix/WixToolset.Core.WindowsInstaller/MspBackend.cs index d1f5eb99..398fc780 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/MspBackend.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/MspBackend.cs | |||
| @@ -4,13 +4,7 @@ namespace WixToolset.Core.WindowsInstaller | |||
| 4 | { | 4 | { |
| 5 | using System; | 5 | using System; |
| 6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
| 7 | using System.IO; | ||
| 8 | using System.Linq; | ||
| 9 | using WixToolset.Core.WindowsInstaller.Bind; | 7 | using WixToolset.Core.WindowsInstaller.Bind; |
| 10 | using WixToolset.Core.Native.Msi; | ||
| 11 | using WixToolset.Core.WindowsInstaller.Unbind; | ||
| 12 | using WixToolset.Data; | ||
| 13 | using WixToolset.Data.Symbols; | ||
| 14 | using WixToolset.Data.WindowsInstaller; | 8 | using WixToolset.Data.WindowsInstaller; |
| 15 | using WixToolset.Extensibility; | 9 | using WixToolset.Extensibility; |
| 16 | using WixToolset.Extensibility.Data; | 10 | using WixToolset.Extensibility.Data; |
| @@ -74,9 +68,9 @@ namespace WixToolset.Core.WindowsInstaller | |||
| 74 | throw new NotImplementedException(); | 68 | throw new NotImplementedException(); |
| 75 | } | 69 | } |
| 76 | 70 | ||
| 71 | #if TODO_PATCHING | ||
| 77 | public Intermediate Unbind(IUnbindContext context) | 72 | public Intermediate Unbind(IUnbindContext context) |
| 78 | { | 73 | { |
| 79 | #if TODO_PATCHING | ||
| 80 | Output patch; | 74 | Output patch; |
| 81 | 75 | ||
| 82 | // patch files are essentially database files (use a special flag to let the API know its a patch file) | 76 | // patch files are essentially database files (use a special flag to let the API know its a patch file) |
| @@ -156,8 +150,7 @@ namespace WixToolset.Core.WindowsInstaller | |||
| 156 | } | 150 | } |
| 157 | 151 | ||
| 158 | return patch; | 152 | return patch; |
| 159 | #endif | ||
| 160 | throw new NotImplementedException(); | ||
| 161 | } | 153 | } |
| 154 | #endif | ||
| 162 | } | 155 | } |
| 163 | } | 156 | } |
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/MstBackend.cs b/src/wix/WixToolset.Core.WindowsInstaller/MstBackend.cs deleted file mode 100644 index 8ce75265..00000000 --- a/src/wix/WixToolset.Core.WindowsInstaller/MstBackend.cs +++ /dev/null | |||
| @@ -1,39 +0,0 @@ | |||
| 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | ||
| 2 | |||
| 3 | namespace WixToolset.Core.WindowsInstaller | ||
| 4 | { | ||
| 5 | using System; | ||
| 6 | using WixToolset.Core.WindowsInstaller.Unbind; | ||
| 7 | using WixToolset.Data; | ||
| 8 | using WixToolset.Extensibility; | ||
| 9 | using WixToolset.Extensibility.Data; | ||
| 10 | |||
| 11 | internal class MstBackend : IBackend | ||
| 12 | { | ||
| 13 | public IBindResult Bind(IBindContext context) | ||
| 14 | { | ||
| 15 | #if TODO_PATCHING | ||
| 16 | var command = new BindTransformCommand(); | ||
| 17 | command.Extensions = context.Extensions; | ||
| 18 | command.TempFilesLocation = context.IntermediateFolder; | ||
| 19 | command.Transform = context.IntermediateRepresentation; | ||
| 20 | command.OutputPath = context.OutputPath; | ||
| 21 | command.Execute(); | ||
| 22 | |||
| 23 | return new BindResult(Array.Empty<FileTransfer>(), Array.Empty<string>()); | ||
| 24 | #endif | ||
| 25 | throw new NotImplementedException(); | ||
| 26 | } | ||
| 27 | |||
| 28 | public IDecompileResult Decompile(IDecompileContext context) | ||
| 29 | { | ||
| 30 | throw new NotImplementedException(); | ||
| 31 | } | ||
| 32 | |||
| 33 | public Intermediate Unbind(IUnbindContext context) | ||
| 34 | { | ||
| 35 | var command = new UnbindMsiOrMsmCommand(context); | ||
| 36 | return command.Execute(); | ||
| 37 | } | ||
| 38 | } | ||
| 39 | } | ||
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Unbind/UnbindMsiOrMsmCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Unbind/UnbindMsiOrMsmCommand.cs index 75ee6307..82015cf2 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Unbind/UnbindMsiOrMsmCommand.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Unbind/UnbindMsiOrMsmCommand.cs | |||
| @@ -4,52 +4,80 @@ namespace WixToolset.Core.WindowsInstaller.Unbind | |||
| 4 | { | 4 | { |
| 5 | using System; | 5 | using System; |
| 6 | using System.ComponentModel; | 6 | using System.ComponentModel; |
| 7 | using WixToolset.Core.Native.Msi; | ||
| 7 | using WixToolset.Data; | 8 | using WixToolset.Data; |
| 9 | using WixToolset.Data.WindowsInstaller; | ||
| 8 | using WixToolset.Extensibility.Data; | 10 | using WixToolset.Extensibility.Data; |
| 9 | using WixToolset.Core.Native.Msi; | 11 | using WixToolset.Extensibility.Services; |
| 10 | 12 | ||
| 11 | internal class UnbindMsiOrMsmCommand | 13 | internal class UnbindMsiOrMsmCommand |
| 12 | { | 14 | { |
| 15 | public UnbindMsiOrMsmCommand(IMessaging messaging, IBackendHelper backendHelper, string databasePath, string exportBasePath, string intermediateFolder, bool adminImage, bool suppressDemodularization, bool suppressExtractCabinets) | ||
| 16 | { | ||
| 17 | this.Messaging = messaging; | ||
| 18 | this.BackendHelper = backendHelper; | ||
| 19 | this.DatabasePath = databasePath; | ||
| 20 | this.ExportBasePath = exportBasePath; | ||
| 21 | this.IntermediateFolder = intermediateFolder; | ||
| 22 | this.IsAdminImage = adminImage; | ||
| 23 | this.SuppressDemodularization = suppressDemodularization; | ||
| 24 | this.SuppressExtractCabinets = suppressExtractCabinets; | ||
| 25 | } | ||
| 26 | |||
| 13 | public UnbindMsiOrMsmCommand(IUnbindContext context) | 27 | public UnbindMsiOrMsmCommand(IUnbindContext context) |
| 14 | { | 28 | { |
| 15 | this.Context = context; | 29 | this.Messaging = context.ServiceProvider.GetService<IMessaging>(); |
| 30 | this.DatabasePath = context.InputFilePath; | ||
| 31 | this.ExportBasePath = context.ExportBasePath; | ||
| 32 | this.IntermediateFolder = context.IntermediateFolder; | ||
| 33 | this.IsAdminImage = context.IsAdminImage; | ||
| 34 | this.SuppressDemodularization = context.SuppressDemodularization; | ||
| 16 | } | 35 | } |
| 17 | 36 | ||
| 18 | public IUnbindContext Context { get; } | 37 | private IMessaging Messaging { get; } |
| 19 | 38 | ||
| 20 | public Intermediate Execute() | 39 | private IBackendHelper BackendHelper { get; } |
| 21 | { | 40 | |
| 22 | #if TODO_PATCHING | 41 | private string DatabasePath { get; } |
| 23 | Output output; | 42 | |
| 43 | private string ExportBasePath { get; } | ||
| 24 | 44 | ||
| 45 | private string IntermediateFolder { get; } | ||
| 46 | |||
| 47 | private bool IsAdminImage { get; } | ||
| 48 | |||
| 49 | private bool SuppressDemodularization { get; } | ||
| 50 | |||
| 51 | private bool SuppressExtractCabinets { get; } | ||
| 52 | |||
| 53 | public WindowsInstallerData Execute() | ||
| 54 | { | ||
| 25 | try | 55 | try |
| 26 | { | 56 | { |
| 27 | using (Database database = new Database(this.Context.InputFilePath, OpenDatabase.ReadOnly)) | 57 | using (var database = new Database(this.DatabasePath, OpenDatabase.ReadOnly)) |
| 28 | { | 58 | { |
| 29 | var unbindCommand = new UnbindDatabaseCommand(this.Context.Messaging, database, this.Context.InputFilePath, OutputType.Product, this.Context.ExportBasePath, this.Context.IntermediateFolder, this.Context.IsAdminImage, this.Context.SuppressDemodularization, skipSummaryInfo: false); | 59 | var unbindCommand = new UnbindDatabaseCommand(this.Messaging, this.BackendHelper, database, this.DatabasePath, OutputType.Product, this.ExportBasePath, this.IntermediateFolder, this.IsAdminImage, this.SuppressDemodularization, skipSummaryInfo: false); |
| 30 | output = unbindCommand.Execute(); | 60 | var data = unbindCommand.Execute(); |
| 31 | 61 | ||
| 32 | // extract the files from the cabinets | 62 | // extract the files from the cabinets |
| 33 | if (!String.IsNullOrEmpty(this.Context.ExportBasePath) && !this.Context.SuppressExtractCabinets) | 63 | if (!String.IsNullOrEmpty(this.ExportBasePath) && !this.SuppressExtractCabinets) |
| 34 | { | 64 | { |
| 35 | var extractCommand = new ExtractCabinetsCommand(output, database, this.Context.InputFilePath, this.Context.ExportBasePath, this.Context.IntermediateFolder); | 65 | var extractCommand = new ExtractCabinetsCommand(data, database, this.DatabasePath, this.ExportBasePath, this.IntermediateFolder); |
| 36 | extractCommand.Execute(); | 66 | extractCommand.Execute(); |
| 37 | } | 67 | } |
| 68 | |||
| 69 | return data; | ||
| 38 | } | 70 | } |
| 39 | } | 71 | } |
| 40 | catch (Win32Exception e) | 72 | catch (Win32Exception e) |
| 41 | { | 73 | { |
| 42 | if (0x6E == e.NativeErrorCode) // ERROR_OPEN_FAILED | 74 | if (0x6E == e.NativeErrorCode) // ERROR_OPEN_FAILED |
| 43 | { | 75 | { |
| 44 | throw new WixException(WixErrors.OpenDatabaseFailed(this.Context.InputFilePath)); | 76 | //throw new WixException(WixErrors.OpenDatabaseFailed(this.DatabasePath)); |
| 45 | } | 77 | } |
| 46 | 78 | ||
| 47 | throw; | 79 | throw; |
| 48 | } | 80 | } |
| 49 | |||
| 50 | return output; | ||
| 51 | #endif | ||
| 52 | throw new NotImplementedException(); | ||
| 53 | } | 81 | } |
| 54 | } | 82 | } |
| 55 | } | 83 | } |
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Unbind/UnbindTranformCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Unbind/UnbindTransformCommand.cs index f40aed4e..ea40fa9f 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Unbind/UnbindTranformCommand.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Unbind/UnbindTransformCommand.cs | |||
| @@ -41,7 +41,7 @@ namespace WixToolset.Core.WindowsInstaller.Unbind | |||
| 41 | private TableDefinitionCollection TableDefinitions { get; } | 41 | private TableDefinitionCollection TableDefinitions { get; } |
| 42 | 42 | ||
| 43 | private string EmptyFile { get; set; } | 43 | private string EmptyFile { get; set; } |
| 44 | 44 | ||
| 45 | public WindowsInstallerData Execute() | 45 | public WindowsInstallerData Execute() |
| 46 | { | 46 | { |
| 47 | var transform = new WindowsInstallerData(new SourceLineNumber(this.TransformFile)); | 47 | var transform = new WindowsInstallerData(new SourceLineNumber(this.TransformFile)); |
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/WindowsInstallerBackendErrors.cs b/src/wix/WixToolset.Core.WindowsInstaller/WindowsInstallerBackendErrors.cs index 0c15ad05..2efb06f1 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/WindowsInstallerBackendErrors.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/WindowsInstallerBackendErrors.cs | |||
| @@ -2,14 +2,17 @@ | |||
| 2 | 2 | ||
| 3 | namespace WixToolset.Core.WindowsInstaller | 3 | namespace WixToolset.Core.WindowsInstaller |
| 4 | { | 4 | { |
| 5 | using System; | ||
| 5 | using WixToolset.Data; | 6 | using WixToolset.Data; |
| 6 | 7 | ||
| 7 | internal static class WindowsInstallerBackendErrors | 8 | internal static class WindowsInstallerBackendErrors |
| 8 | { | 9 | { |
| 9 | //public static Message ReplaceThisWithTheFirstError(SourceLineNumber sourceLineNumbers) | 10 | public static Message CannotLoadWixoutAsTransform(SourceLineNumber sourceLineNumbers, Exception exception) |
| 10 | //{ | 11 | { |
| 11 | // return Message(sourceLineNumbers, Ids.ReplaceThisWithTheFirstError, "format string", arg1, arg2); | 12 | var additionalDetail = exception == null ? String.Empty : ", detail: " + exception.Message; |
| 12 | //} | 13 | |
| 14 | return Message(sourceLineNumbers, Ids.CannotLoadWixoutAsTransform, "Could not load wixout file as a transform{1}", additionalDetail); | ||
| 15 | } | ||
| 13 | 16 | ||
| 14 | private static Message Message(SourceLineNumber sourceLineNumber, Ids id, string format, params object[] args) | 17 | private static Message Message(SourceLineNumber sourceLineNumber, Ids id, string format, params object[] args) |
| 15 | { | 18 | { |
| @@ -18,7 +21,7 @@ namespace WixToolset.Core.WindowsInstaller | |||
| 18 | 21 | ||
| 19 | public enum Ids | 22 | public enum Ids |
| 20 | { | 23 | { |
| 21 | // ReplaceThisWithTheFirstError = 7500, | 24 | CannotLoadWixoutAsTransform = 7500, |
| 22 | } // last available is 7999. 8000 is BurnBackendErrors. | 25 | } // last available is 7999. 8000 is BurnBackendErrors. |
| 23 | } | 26 | } |
| 24 | } | 27 | } |
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/WindowsInstallerBackendFactory.cs b/src/wix/WixToolset.Core.WindowsInstaller/WindowsInstallerBackendFactory.cs index f72acb21..d14743e9 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/WindowsInstallerBackendFactory.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/WindowsInstallerBackendFactory.cs | |||
| @@ -37,11 +37,6 @@ namespace WixToolset.Core.WindowsInstaller | |||
| 37 | //case "patchcreation": | 37 | //case "patchcreation": |
| 38 | //case ".pcp": | 38 | //case ".pcp": |
| 39 | // return new PatchCreationBackend(); | 39 | // return new PatchCreationBackend(); |
| 40 | |||
| 41 | case "transform": | ||
| 42 | case ".mst": | ||
| 43 | backend = new MstBackend(); | ||
| 44 | return true; | ||
| 45 | } | 40 | } |
| 46 | 41 | ||
| 47 | backend = null; | 42 | backend = null; |
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/Language/Package.en-us.wxl b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/Language/Package.en-us.wxl index f7453566..d3844e39 100644 --- a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/Language/Package.en-us.wxl +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/Language/Package.en-us.wxl | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | <?xml version="1.0" encoding="utf-8"?> | 1 | <?xml version="1.0" encoding="utf-8"?> |
| 2 | <WixLocalization xmlns="http://wixtoolset.org/schemas/v4/wxl" Culture="en-US"> | 2 | <WixLocalization xmlns="http://wixtoolset.org/schemas/v4/wxl" Culture="en-US"> |
| 3 | 3 | ||
| 4 | <String Id="DowngradeError">A newer version of [ProductName] is already installed.</String> | 4 | <String Id="DowngradeError">A newer version en-us of [ProductName] is already installed.</String> |
| 5 | <String Id="FeatureTitle">MsiPackage</String> | 5 | <String Id="FeatureTitle">MsiPackage en-us</String> |
| 6 | 6 | ||
| 7 | </WixLocalization> | 7 | </WixLocalization> |
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/Language/Package.ja-jp.wxl b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/Language/Package.ja-jp.wxl index ef287da7..48a339d3 100644 --- a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/Language/Package.ja-jp.wxl +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/Language/Package.ja-jp.wxl | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | <?xml version="1.0" encoding="utf-8"?> | 1 | <?xml version="1.0" encoding="utf-8"?> |
| 2 | <WixLocalization xmlns="http://wixtoolset.org/schemas/v4/wxl" Culture="ja-JP"> | 2 | <WixLocalization xmlns="http://wixtoolset.org/schemas/v4/wxl" Culture="ja-JP"> |
| 3 | 3 | ||
| 4 | <String Id="DowngradeError">A newer version of [ProductName] is already installed.</String> | 4 | <String Id="DowngradeError">A newer version ja-jp of [ProductName] is already installed.</String> |
| 5 | <String Id="FeatureTitle">MsiPackage</String> | 5 | <String Id="FeatureTitle">MsiPackage ja-jp</String> |
| 6 | 6 | ||
| 7 | </WixLocalization> | 7 | </WixLocalization> |
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TransformFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/TransformFixture.cs new file mode 100644 index 00000000..bdbf5c26 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TransformFixture.cs | |||
| @@ -0,0 +1,143 @@ | |||
| 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | ||
| 2 | |||
| 3 | namespace WixToolsetTest.CoreIntegration | ||
| 4 | { | ||
| 5 | using System.IO; | ||
| 6 | using System.Linq; | ||
| 7 | using WixBuildTools.TestSupport; | ||
| 8 | using WixToolset.Core.TestPackage; | ||
| 9 | using WixToolset.Data.WindowsInstaller; | ||
| 10 | using Xunit; | ||
| 11 | |||
| 12 | public class TransformFixture | ||
| 13 | { | ||
| 14 | [Fact] | ||
| 15 | public void CanBuildTransformFromEnuToJpn() | ||
| 16 | { | ||
| 17 | var folder = TestData.Get(@"TestData", "Language"); | ||
| 18 | |||
| 19 | using (var fs = new DisposableFileSystem()) | ||
| 20 | { | ||
| 21 | var baseFolder = fs.GetFolder(); | ||
| 22 | var enuMsiPath = Path.Combine(baseFolder, @"bin\enu.msi"); | ||
| 23 | var jpnMsiPath = Path.Combine(baseFolder, @"bin\jpn.msi"); | ||
| 24 | var mstPath = Path.Combine(baseFolder, @"bin\test.mst"); | ||
| 25 | |||
| 26 | var result = WixRunner.Execute(new[] | ||
| 27 | { | ||
| 28 | "build", | ||
| 29 | Path.Combine(folder, "Package.wxs"), | ||
| 30 | "-loc", Path.Combine(folder, "Package.en-us.wxl"), | ||
| 31 | "-bindpath", Path.Combine(folder, "data"), | ||
| 32 | "-intermediateFolder", Path.Combine(baseFolder, "obj"), | ||
| 33 | "-o", enuMsiPath | ||
| 34 | }); | ||
| 35 | result.AssertSuccess(); | ||
| 36 | |||
| 37 | |||
| 38 | result = WixRunner.Execute(new[] | ||
| 39 | { | ||
| 40 | "build", | ||
| 41 | Path.Combine(folder, "Package.wxs"), | ||
| 42 | "-loc", Path.Combine(folder, "Package.ja-jp.wxl"), | ||
| 43 | "-bindpath", Path.Combine(folder, "data"), | ||
| 44 | "-intermediateFolder", Path.Combine(baseFolder, "obj"), | ||
| 45 | "-o", jpnMsiPath | ||
| 46 | }); | ||
| 47 | result.AssertSuccess(); | ||
| 48 | |||
| 49 | result = WixRunner.Execute(new[] | ||
| 50 | { | ||
| 51 | "msi", "transform", | ||
| 52 | "-intermediateFolder", Path.Combine(baseFolder, "obj"), | ||
| 53 | "-serr", "f", | ||
| 54 | "-o", mstPath, | ||
| 55 | enuMsiPath, | ||
| 56 | jpnMsiPath | ||
| 57 | }); | ||
| 58 | result.AssertSuccess(); | ||
| 59 | |||
| 60 | Assert.True(File.Exists(mstPath)); | ||
| 61 | } | ||
| 62 | } | ||
| 63 | |||
| 64 | [Fact] | ||
| 65 | public void CanBuildWixoutTransform() | ||
| 66 | { | ||
| 67 | var folder = TestData.Get(@"TestData", "Language"); | ||
| 68 | |||
| 69 | using (var fs = new DisposableFileSystem()) | ||
| 70 | { | ||
| 71 | var baseFolder = fs.GetFolder(); | ||
| 72 | var enuMsiPath = Path.Combine(baseFolder, @"bin\enu.msi"); | ||
| 73 | var jpnMsiPath = Path.Combine(baseFolder, @"bin\jpn.msi"); | ||
| 74 | var wixmstPath = Path.Combine(baseFolder, @"bin\test.wixmst"); | ||
| 75 | var mstPath = Path.Combine(baseFolder, @"bin\test.mst"); | ||
| 76 | |||
| 77 | var result = WixRunner.Execute(new[] | ||
| 78 | { | ||
| 79 | "build", | ||
| 80 | Path.Combine(folder, "Package.wxs"), | ||
| 81 | "-loc", Path.Combine(folder, "Package.en-us.wxl"), | ||
| 82 | "-bindpath", Path.Combine(folder, "data"), | ||
| 83 | "-intermediateFolder", Path.Combine(baseFolder, "obj"), | ||
| 84 | "-o", enuMsiPath | ||
| 85 | }); | ||
| 86 | result.AssertSuccess(); | ||
| 87 | |||
| 88 | result = WixRunner.Execute(new[] | ||
| 89 | { | ||
| 90 | "build", | ||
| 91 | Path.Combine(folder, "Package.wxs"), | ||
| 92 | "-loc", Path.Combine(folder, "Package.ja-jp.wxl"), | ||
| 93 | "-bindpath", Path.Combine(folder, "data"), | ||
| 94 | "-intermediateFolder", Path.Combine(baseFolder, "obj"), | ||
| 95 | "-o", jpnMsiPath | ||
| 96 | }); | ||
| 97 | result.AssertSuccess(); | ||
| 98 | |||
| 99 | result = WixRunner.Execute(new[] | ||
| 100 | { | ||
| 101 | "msi", "transform", | ||
| 102 | "-intermediateFolder", Path.Combine(baseFolder, "obj"), | ||
| 103 | "-serr", "f", | ||
| 104 | "-xo", | ||
| 105 | "-o", wixmstPath, | ||
| 106 | enuMsiPath, | ||
| 107 | jpnMsiPath | ||
| 108 | }); | ||
| 109 | result.AssertSuccess(); | ||
| 110 | |||
| 111 | var wixmst = WindowsInstallerData.Load(wixmstPath); | ||
| 112 | var rows = wixmst.Tables.SelectMany(t => t.Rows).Where(r => r.Operation == RowOperation.Modify).ToDictionary(r => r.GetPrimaryKey()); | ||
| 113 | |||
| 114 | WixAssert.CompareLineByLine(new[] | ||
| 115 | { | ||
| 116 | "NOT WIX_DOWNGRADE_DETECTED", | ||
| 117 | "ProductCode", | ||
| 118 | "ProductFeature", | ||
| 119 | "ProductLanguage" | ||
| 120 | }, rows.Keys.OrderBy(s => s).ToArray()); | ||
| 121 | |||
| 122 | Assert.True(rows.TryGetValue("ProductFeature", out var productFeatureRow)); | ||
| 123 | Assert.Equal("MsiPackage ja-jp", productFeatureRow.FieldAsString(2)); | ||
| 124 | |||
| 125 | Assert.True(rows.TryGetValue("ProductLanguage", out var productLanguageRow)); | ||
| 126 | Assert.Equal("1041", productLanguageRow.FieldAsString(1)); | ||
| 127 | |||
| 128 | Assert.False(File.Exists(mstPath)); | ||
| 129 | |||
| 130 | result = WixRunner.Execute(new[] | ||
| 131 | { | ||
| 132 | "msi", "transform", | ||
| 133 | "-intermediateFolder", Path.Combine(baseFolder, "obj"), | ||
| 134 | "-o", mstPath, | ||
| 135 | wixmstPath | ||
| 136 | }); | ||
| 137 | result.AssertSuccess(); | ||
| 138 | |||
| 139 | Assert.True(File.Exists(mstPath)); | ||
| 140 | } | ||
| 141 | } | ||
| 142 | } | ||
| 143 | } | ||
