diff options
Diffstat (limited to 'src')
56 files changed, 1508 insertions, 1676 deletions
diff --git a/src/api/wix/WixToolset.Data/ErrorMessages.cs b/src/api/wix/WixToolset.Data/ErrorMessages.cs index 40378a2e..77ce73aa 100644 --- a/src/api/wix/WixToolset.Data/ErrorMessages.cs +++ b/src/api/wix/WixToolset.Data/ErrorMessages.cs | |||
@@ -651,7 +651,8 @@ namespace WixToolset.Data | |||
651 | public static Message FileNotFound(SourceLineNumber sourceLineNumbers, string file, string fileType, IEnumerable<string> checkedPaths) | 651 | public static Message FileNotFound(SourceLineNumber sourceLineNumbers, string file, string fileType, IEnumerable<string> checkedPaths) |
652 | { | 652 | { |
653 | var combinedCheckedPaths = String.Join(", ", checkedPaths); | 653 | var combinedCheckedPaths = String.Join(", ", checkedPaths); |
654 | return Message(sourceLineNumbers, Ids.FileNotFound, "The system cannot find the file '{0}' with type '{1}'. The following paths were checked: {2}", file, fileType, combinedCheckedPaths); | 654 | var withType = String.IsNullOrEmpty(fileType) ? String.Empty : $" with type '{fileType}'"; |
655 | return Message(sourceLineNumbers, Ids.FileNotFound, "The system cannot find the file '{0}'{1}. The following paths were checked: {2}", file, withType, combinedCheckedPaths); | ||
655 | } | 656 | } |
656 | 657 | ||
657 | public static Message FileOrDirectoryPathRequired(string parameter) | 658 | public static Message FileOrDirectoryPathRequired(string parameter) |
diff --git a/src/api/wix/WixToolset.Data/Symbols/WixPatchBaselineSymbol.cs b/src/api/wix/WixToolset.Data/Symbols/WixPatchBaselineSymbol.cs index d7295424..cbf51e2e 100644 --- a/src/api/wix/WixToolset.Data/Symbols/WixPatchBaselineSymbol.cs +++ b/src/api/wix/WixToolset.Data/Symbols/WixPatchBaselineSymbol.cs | |||
@@ -14,7 +14,6 @@ namespace WixToolset.Data | |||
14 | new IntermediateFieldDefinition(nameof(WixPatchBaselineSymbolFields.ValidationFlags), IntermediateFieldType.Number), | 14 | new IntermediateFieldDefinition(nameof(WixPatchBaselineSymbolFields.ValidationFlags), IntermediateFieldType.Number), |
15 | new IntermediateFieldDefinition(nameof(WixPatchBaselineSymbolFields.BaselineFile), IntermediateFieldType.Path), | 15 | new IntermediateFieldDefinition(nameof(WixPatchBaselineSymbolFields.BaselineFile), IntermediateFieldType.Path), |
16 | new IntermediateFieldDefinition(nameof(WixPatchBaselineSymbolFields.UpdateFile), IntermediateFieldType.Path), | 16 | new IntermediateFieldDefinition(nameof(WixPatchBaselineSymbolFields.UpdateFile), IntermediateFieldType.Path), |
17 | new IntermediateFieldDefinition(nameof(WixPatchBaselineSymbolFields.TransformFile), IntermediateFieldType.Path), | ||
18 | }, | 17 | }, |
19 | typeof(WixPatchBaselineSymbol)); | 18 | typeof(WixPatchBaselineSymbol)); |
20 | } | 19 | } |
@@ -28,7 +27,6 @@ namespace WixToolset.Data.Symbols | |||
28 | ValidationFlags, | 27 | ValidationFlags, |
29 | BaselineFile, | 28 | BaselineFile, |
30 | UpdateFile, | 29 | UpdateFile, |
31 | TransformFile, | ||
32 | } | 30 | } |
33 | 31 | ||
34 | public class WixPatchBaselineSymbol : IntermediateSymbol | 32 | public class WixPatchBaselineSymbol : IntermediateSymbol |
@@ -66,11 +64,5 @@ namespace WixToolset.Data.Symbols | |||
66 | get => this.Fields[(int)WixPatchBaselineSymbolFields.UpdateFile].AsPath(); | 64 | get => this.Fields[(int)WixPatchBaselineSymbolFields.UpdateFile].AsPath(); |
67 | set => this.Set((int)WixPatchBaselineSymbolFields.UpdateFile, value); | 65 | set => this.Set((int)WixPatchBaselineSymbolFields.UpdateFile, value); |
68 | } | 66 | } |
69 | |||
70 | public IntermediateFieldPathValue TransformFile | ||
71 | { | ||
72 | get => this.Fields[(int)WixPatchBaselineSymbolFields.TransformFile].AsPath(); | ||
73 | set => this.Set((int)WixPatchBaselineSymbolFields.TransformFile, value); | ||
74 | } | ||
75 | } | 67 | } |
76 | } | 68 | } |
diff --git a/src/api/wix/WixToolset.Extensibility/Data/IBindContext.cs b/src/api/wix/WixToolset.Extensibility/Data/IBindContext.cs index 671da292..9d663c65 100644 --- a/src/api/wix/WixToolset.Extensibility/Data/IBindContext.cs +++ b/src/api/wix/WixToolset.Extensibility/Data/IBindContext.cs | |||
@@ -18,6 +18,11 @@ namespace WixToolset.Extensibility.Data | |||
18 | IServiceProvider ServiceProvider { get; } | 18 | IServiceProvider ServiceProvider { get; } |
19 | 19 | ||
20 | /// <summary> | 20 | /// <summary> |
21 | /// Bind paths used during resolution. | ||
22 | /// </summary> | ||
23 | IReadOnlyCollection<IBindPath> BindPaths { get; set; } | ||
24 | |||
25 | /// <summary> | ||
21 | /// Counnt of threads to use in cabbing. | 26 | /// Counnt of threads to use in cabbing. |
22 | /// </summary> | 27 | /// </summary> |
23 | int CabbingThreadCount { get; set; } | 28 | int CabbingThreadCount { get; set; } |
diff --git a/src/api/wix/WixToolset.Extensibility/Data/IFileFacade.cs b/src/api/wix/WixToolset.Extensibility/Data/IFileFacade.cs index fea00d4e..8a9e3fee 100644 --- a/src/api/wix/WixToolset.Extensibility/Data/IFileFacade.cs +++ b/src/api/wix/WixToolset.Extensibility/Data/IFileFacade.cs | |||
@@ -5,34 +5,13 @@ namespace WixToolset.Extensibility.Data | |||
5 | using System.Collections.Generic; | 5 | using System.Collections.Generic; |
6 | using WixToolset.Data; | 6 | using WixToolset.Data; |
7 | using WixToolset.Data.Symbols; | 7 | using WixToolset.Data.Symbols; |
8 | using WixToolset.Data.WindowsInstaller.Rows; | ||
9 | 8 | ||
10 | /// <summary> | 9 | /// <summary> |
11 | /// Interface that provides a common facade over <c>FileSymbol</c> and <c>FileRow</c>. | 10 | /// Interface that provides a common facade over file information. |
12 | /// </summary> | 11 | /// </summary> |
13 | public interface IFileFacade | 12 | public interface IFileFacade |
14 | { | 13 | { |
15 | /// <summary> | 14 | /// <summary> |
16 | /// Reference to assembly application for this file. | ||
17 | /// </summary> | ||
18 | string AssemblyApplicationFileRef { get; } | ||
19 | |||
20 | /// <summary> | ||
21 | /// Reference to assembly manifest for this file. | ||
22 | /// </summary> | ||
23 | string AssemblyManifestFileRef { get; } | ||
24 | |||
25 | /// <summary> | ||
26 | /// List of assembly name values in the file. | ||
27 | /// </summary> | ||
28 | List<MsiAssemblyNameSymbol> AssemblyNames { get; set; } | ||
29 | |||
30 | /// <summary> | ||
31 | /// Optionally indicates what sort of assembly the file is. | ||
32 | /// </summary> | ||
33 | AssemblyType? AssemblyType { get; } | ||
34 | |||
35 | /// <summary> | ||
36 | /// Component containing the file. | 15 | /// Component containing the file. |
37 | /// </summary> | 16 | /// </summary> |
38 | string ComponentRef { get; } | 17 | string ComponentRef { get; } |
@@ -58,21 +37,6 @@ namespace WixToolset.Extensibility.Data | |||
58 | int FileSize { get; set; } | 37 | int FileSize { get; set; } |
59 | 38 | ||
60 | /// <summary> | 39 | /// <summary> |
61 | /// Indicates whether the file came from a merge module. | ||
62 | /// </summary> | ||
63 | bool FromModule { get; } | ||
64 | |||
65 | /// <summary> | ||
66 | /// Indicates whether the file came from a transform. | ||
67 | /// </summary> | ||
68 | bool FromTransform { get; } | ||
69 | |||
70 | /// <summary> | ||
71 | /// Hash symbol of the file. | ||
72 | /// </summary> | ||
73 | MsiFileHashSymbol Hash { get; set; } | ||
74 | |||
75 | /// <summary> | ||
76 | /// Underlying identifier of the file. | 40 | /// Underlying identifier of the file. |
77 | /// </summary> | 41 | /// </summary> |
78 | Identifier Identifier { get; } | 42 | Identifier Identifier { get; } |
@@ -118,9 +82,13 @@ namespace WixToolset.Extensibility.Data | |||
118 | string Version { get; set; } | 82 | string Version { get; set; } |
119 | 83 | ||
120 | /// <summary> | 84 | /// <summary> |
121 | /// Gets the underlying <c>FileRow</c> if one is present. | 85 | /// Calculated hash of the file. |
86 | /// </summary> | ||
87 | MsiFileHashSymbol MsiFileHashSymbol { get; set; } | ||
88 | |||
89 | /// <summary> | ||
90 | /// Assembly names found in the file. | ||
122 | /// </summary> | 91 | /// </summary> |
123 | /// <returns><c>FileRow</c> if one is present, otherwise throws.</returns> | 92 | ICollection<MsiAssemblyNameSymbol> AssemblyNameSymbols { get; } |
124 | FileRow GetFileRow(); | ||
125 | } | 93 | } |
126 | } | 94 | } |
diff --git a/src/api/wix/WixToolset.Extensibility/Data/IWindowsInstallerDecompileContext.cs b/src/api/wix/WixToolset.Extensibility/Data/IWindowsInstallerDecompileContext.cs index 27d30a5a..7b974942 100644 --- a/src/api/wix/WixToolset.Extensibility/Data/IWindowsInstallerDecompileContext.cs +++ b/src/api/wix/WixToolset.Extensibility/Data/IWindowsInstallerDecompileContext.cs | |||
@@ -63,11 +63,6 @@ namespace WixToolset.Extensibility.Data | |||
63 | string IntermediateFolder { get; set; } | 63 | string IntermediateFolder { get; set; } |
64 | 64 | ||
65 | /// <summary> | 65 | /// <summary> |
66 | /// Gets or sets whether the decompiler admin image. | ||
67 | /// </summary> | ||
68 | bool IsAdminImage { get; set; } | ||
69 | |||
70 | /// <summary> | ||
71 | /// Gets or sets where to output the result. | 66 | /// Gets or sets where to output the result. |
72 | /// </summary> | 67 | /// </summary> |
73 | string OutputPath { get; set; } | 68 | string OutputPath { get; set; } |
diff --git a/src/api/wix/WixToolset.Extensibility/Services/IBackendHelper.cs b/src/api/wix/WixToolset.Extensibility/Services/IBackendHelper.cs index eff42b99..8bb1b2d6 100644 --- a/src/api/wix/WixToolset.Extensibility/Services/IBackendHelper.cs +++ b/src/api/wix/WixToolset.Extensibility/Services/IBackendHelper.cs | |||
@@ -5,8 +5,6 @@ namespace WixToolset.Extensibility.Services | |||
5 | using System; | 5 | using System; |
6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
7 | using WixToolset.Data; | 7 | using WixToolset.Data; |
8 | using WixToolset.Data.Symbols; | ||
9 | using WixToolset.Data.WindowsInstaller.Rows; | ||
10 | using WixToolset.Extensibility.Data; | 8 | using WixToolset.Extensibility.Data; |
11 | 9 | ||
12 | /// <summary> | 10 | /// <summary> |
@@ -15,28 +13,6 @@ namespace WixToolset.Extensibility.Services | |||
15 | public interface IBackendHelper : ILayoutServices | 13 | public interface IBackendHelper : ILayoutServices |
16 | { | 14 | { |
17 | /// <summary> | 15 | /// <summary> |
18 | /// Creates a file facade from a <c>FileSymbol</c> and possible <c>AssemblySymbol</c>. | ||
19 | /// </summary> | ||
20 | /// <param name="file"><c>FileSymbol</c> backing the facade.</param> | ||
21 | /// <param name="assembly"><c>AssemblySymbol</c> backing the facade.</param> | ||
22 | /// <returns></returns> | ||
23 | IFileFacade CreateFileFacade(FileSymbol file, AssemblySymbol assembly); | ||
24 | |||
25 | /// <summary> | ||
26 | /// Creates a file facade from a File row. | ||
27 | /// </summary> | ||
28 | /// <param name="fileRow"><c>FileRow</c> </param> | ||
29 | /// <returns>New <c>IFileFacade</c>.</returns> | ||
30 | IFileFacade CreateFileFacade(FileRow fileRow); | ||
31 | |||
32 | /// <summary> | ||
33 | /// Creates a file facade from a Merge Module's File symbol. | ||
34 | /// </summary> | ||
35 | /// <param name="fileSymbol"><c>FileSymbol</c> created from a Merge Module.</param> | ||
36 | /// <returns>New <c>IFileFacade</c>.</returns> | ||
37 | IFileFacade CreateFileFacadeFromMergeModule(FileSymbol fileSymbol); | ||
38 | |||
39 | /// <summary> | ||
40 | /// Creates a MSI compatible GUID. | 16 | /// Creates a MSI compatible GUID. |
41 | /// </summary> | 17 | /// </summary> |
42 | /// <returns>Creates an uppercase GUID with braces.</returns> | 18 | /// <returns>Creates an uppercase GUID with braces.</returns> |
diff --git a/src/api/wix/WixToolset.Extensibility/Services/IFileResolver.cs b/src/api/wix/WixToolset.Extensibility/Services/IFileResolver.cs new file mode 100644 index 00000000..2804cc28 --- /dev/null +++ b/src/api/wix/WixToolset.Extensibility/Services/IFileResolver.cs | |||
@@ -0,0 +1,38 @@ | |||
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.Extensibility.Services | ||
4 | { | ||
5 | using System.Collections.Generic; | ||
6 | using WixToolset.Data; | ||
7 | using WixToolset.Extensibility.Data; | ||
8 | |||
9 | /// <summary> | ||
10 | /// Interface to resolve file paths using extensions and bind paths. | ||
11 | /// </summary> | ||
12 | public interface IFileResolver | ||
13 | { | ||
14 | /// <summary> | ||
15 | /// Resolves the source path of a file using binder extensions. | ||
16 | /// </summary> | ||
17 | /// <param name="source">Original source value.</param> | ||
18 | /// <param name="librarianExtensions">Extensions used to resolve the file path.</param> | ||
19 | /// <param name="bindPaths">Collection of bind paths for the binding stage.</param> | ||
20 | /// <param name="sourceLineNumbers">Optional source line of source file being resolved.</param> | ||
21 | /// <param name="symbolDefinition">Optional type of source file being resolved.</param> | ||
22 | /// <returns>Should return a valid path for the stream to be imported.</returns> | ||
23 | string ResolveFile(string source, IEnumerable<ILibrarianExtension> librarianExtensions, IEnumerable<IBindPath> bindPaths, SourceLineNumber sourceLineNumbers, IntermediateSymbolDefinition symbolDefinition); | ||
24 | |||
25 | /// <summary> | ||
26 | /// Resolves the source path of a file using binder extensions. | ||
27 | /// </summary> | ||
28 | /// <param name="source">Original source value.</param> | ||
29 | /// <param name="resolverExtensions">Extensions used to resolve the file path.</param> | ||
30 | /// <param name="bindPaths">Collection of bind paths for the binding stage.</param> | ||
31 | /// <param name="bindStage">The binding stage used to determine what collection of bind paths will be used</param> | ||
32 | /// <param name="sourceLineNumbers">Optional source line of source file being resolved.</param> | ||
33 | /// <param name="symbolDefinition">Optional type of source file being resolved.</param> | ||
34 | /// <param name="alreadyCheckedPaths">Optional collection of paths already checked.</param> | ||
35 | /// <returns>Should return a valid path for the stream to be imported.</returns> | ||
36 | string ResolveFile(string source, IEnumerable<IResolverExtension> resolverExtensions, IEnumerable<IBindPath> bindPaths, BindStage bindStage, SourceLineNumber sourceLineNumbers, IntermediateSymbolDefinition symbolDefinition, IEnumerable<string> alreadyCheckedPaths = null); | ||
37 | } | ||
38 | } | ||
diff --git a/src/api/wix/WixToolset.Extensibility/Services/IWindowsInstallerBackendHelper.cs b/src/api/wix/WixToolset.Extensibility/Services/IWindowsInstallerBackendHelper.cs index 81325131..2216e957 100644 --- a/src/api/wix/WixToolset.Extensibility/Services/IWindowsInstallerBackendHelper.cs +++ b/src/api/wix/WixToolset.Extensibility/Services/IWindowsInstallerBackendHelper.cs | |||
@@ -3,7 +3,10 @@ | |||
3 | namespace WixToolset.Extensibility.Services | 3 | namespace WixToolset.Extensibility.Services |
4 | { | 4 | { |
5 | using WixToolset.Data; | 5 | using WixToolset.Data; |
6 | using WixToolset.Data.Symbols; | ||
6 | using WixToolset.Data.WindowsInstaller; | 7 | using WixToolset.Data.WindowsInstaller; |
8 | using WixToolset.Data.WindowsInstaller.Rows; | ||
9 | using WixToolset.Extensibility.Data; | ||
7 | 10 | ||
8 | /// <summary> | 11 | /// <summary> |
9 | /// Interface provided to help Windows Installer backend extensions. | 12 | /// Interface provided to help Windows Installer backend extensions. |
@@ -11,6 +14,20 @@ namespace WixToolset.Extensibility.Services | |||
11 | public interface IWindowsInstallerBackendHelper : IBackendHelper | 14 | public interface IWindowsInstallerBackendHelper : IBackendHelper |
12 | { | 15 | { |
13 | /// <summary> | 16 | /// <summary> |
17 | /// Creates a file facade from a <c>FileSymbol</c>. | ||
18 | /// </summary> | ||
19 | /// <param name="file"><c>FileSymbol</c> backing the facade.</param> | ||
20 | /// <returns></returns> | ||
21 | IFileFacade CreateFileFacade(FileSymbol file); | ||
22 | |||
23 | /// <summary> | ||
24 | /// Creates a file facade from a File row. | ||
25 | /// </summary> | ||
26 | /// <param name="fileRow"><c>FileRow</c></param> | ||
27 | /// <returns>New <c>IFileFacade</c>.</returns> | ||
28 | IFileFacade CreateFileFacade(FileRow fileRow); | ||
29 | |||
30 | /// <summary> | ||
14 | /// Creates a <see cref="Row"/> in the specified table. | 31 | /// Creates a <see cref="Row"/> in the specified table. |
15 | /// </summary> | 32 | /// </summary> |
16 | /// <param name="section">Parent section.</param> | 33 | /// <param name="section">Parent section.</param> |
diff --git a/src/wix/WixToolset.Core.Burn/ExtensibilityServices/BurnBackendHelper.cs b/src/wix/WixToolset.Core.Burn/ExtensibilityServices/BurnBackendHelper.cs index 93e7fc20..f2b3587d 100644 --- a/src/wix/WixToolset.Core.Burn/ExtensibilityServices/BurnBackendHelper.cs +++ b/src/wix/WixToolset.Core.Burn/ExtensibilityServices/BurnBackendHelper.cs | |||
@@ -35,21 +35,6 @@ namespace WixToolset.Core.Burn.ExtensibilityServices | |||
35 | 35 | ||
36 | #region IBackendHelper interfaces | 36 | #region IBackendHelper interfaces |
37 | 37 | ||
38 | public IFileFacade CreateFileFacade(FileSymbol file, AssemblySymbol assembly) | ||
39 | { | ||
40 | return this.backendHelper.CreateFileFacade(file, assembly); | ||
41 | } | ||
42 | |||
43 | public IFileFacade CreateFileFacade(FileRow fileRow) | ||
44 | { | ||
45 | return this.backendHelper.CreateFileFacade(fileRow); | ||
46 | } | ||
47 | |||
48 | public IFileFacade CreateFileFacadeFromMergeModule(FileSymbol fileSymbol) | ||
49 | { | ||
50 | return this.backendHelper.CreateFileFacadeFromMergeModule(fileSymbol); | ||
51 | } | ||
52 | |||
53 | public IFileTransfer CreateFileTransfer(string source, string destination, bool move, SourceLineNumber sourceLineNumbers = null) | 38 | public IFileTransfer CreateFileTransfer(string source, string destination, bool move, SourceLineNumber sourceLineNumbers = null) |
54 | { | 39 | { |
55 | return this.backendHelper.CreateFileTransfer(source, destination, move, sourceLineNumbers); | 40 | return this.backendHelper.CreateFileTransfer(source, destination, move, sourceLineNumbers); |
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Bind/AddCreateFoldersCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Bind/AddCreateFoldersCommand.cs index c4fddb3e..44b66cea 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Bind/AddCreateFoldersCommand.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Bind/AddCreateFoldersCommand.cs | |||
@@ -35,4 +35,4 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
35 | } | 35 | } |
36 | } | 36 | } |
37 | } | 37 | } |
38 | } \ No newline at end of file | 38 | } |
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Bind/AttachPatchTransformsCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Bind/AttachPatchTransformsCommand.cs index 66078d8d..6d37fdc2 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Bind/AttachPatchTransformsCommand.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Bind/AttachPatchTransformsCommand.cs | |||
@@ -145,8 +145,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
145 | var mediaSymbol = patchMediaByDiskId[baselineSymbol.DiskId]; | 145 | var mediaSymbol = patchMediaByDiskId[baselineSymbol.DiskId]; |
146 | 146 | ||
147 | // Ensure that files are sequenced after the last file in any transform. | 147 | // Ensure that files are sequenced after the last file in any transform. |
148 | var transformMediaTable = mainTransform.Transform.Tables["Media"]; | 148 | if (mainTransform.Transform.Tables.TryGetTable("Media", out var transformMediaTable)) |
149 | if (null != transformMediaTable && 0 < transformMediaTable.Rows.Count) | ||
150 | { | 149 | { |
151 | foreach (MediaRow transformMediaRow in transformMediaTable.Rows) | 150 | foreach (MediaRow transformMediaRow in transformMediaTable.Rows) |
152 | { | 151 | { |
@@ -370,16 +369,13 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
370 | { | 369 | { |
371 | if (transform.TryGetTable(tableName, out var table)) | 370 | if (transform.TryGetTable(tableName, out var table)) |
372 | { | 371 | { |
373 | foreach (var row in table.Rows) | 372 | foreach (var row in table.Rows.Where(r => r.Operation == RowOperation.Add)) |
374 | { | 373 | { |
375 | if (row.Operation == RowOperation.Add) | 374 | success = false; |
376 | { | ||
377 | success = false; | ||
378 | 375 | ||
379 | var primaryKey = row.GetPrimaryKey('/') ?? String.Empty; | 376 | var primaryKey = row.GetPrimaryKey('/') ?? String.Empty; |
380 | 377 | ||
381 | this.Messaging.Write(ErrorMessages.NewRowAddedInTable(row.SourceLineNumbers, productCode, table.Name, primaryKey)); | 378 | this.Messaging.Write(ErrorMessages.NewRowAddedInTable(row.SourceLineNumbers, productCode, table.Name, primaryKey)); |
382 | } | ||
383 | } | 379 | } |
384 | } | 380 | } |
385 | } | 381 | } |
@@ -925,7 +921,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
925 | for (var i = 0; i < propertyTable.Rows.Count; ++i) | 921 | for (var i = 0; i < propertyTable.Rows.Count; ++i) |
926 | { | 922 | { |
927 | var propertyRow = propertyTable.Rows[i]; | 923 | var propertyRow = propertyTable.Rows[i]; |
928 | var property = (string)propertyRow[0]; | 924 | var property = propertyRow.FieldAsString(0); |
929 | 925 | ||
930 | if ("ProductCode" == property) | 926 | if ("ProductCode" == property) |
931 | { | 927 | { |
@@ -1173,10 +1169,15 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
1173 | { | 1169 | { |
1174 | var pairedFileTable = pairedTransform.EnsureTable(mainFileTable.Definition); | 1170 | var pairedFileTable = pairedTransform.EnsureTable(mainFileTable.Definition); |
1175 | 1171 | ||
1176 | foreach (FileRow mainFileRow in mainFileTable.Rows) | 1172 | foreach (var mainFileRow in mainFileTable.Rows.Cast<FileRow>()) |
1177 | { | 1173 | { |
1178 | // Set File.Sequence to non null to satisfy transform bind. | 1174 | // Set File.Sequence to non null to satisfy transform bind and suppress any |
1175 | // change to File.Sequence to avoid bloat. | ||
1179 | mainFileRow.Sequence = 1; | 1176 | mainFileRow.Sequence = 1; |
1177 | mainFileRow.Fields[7].Modified = false; | ||
1178 | |||
1179 | // Override authored media to the media provided in the patch. | ||
1180 | mainFileRow.DiskId = mediaSymbol.DiskId; | ||
1180 | 1181 | ||
1181 | // Delete's don't need rows in the paired transform. | 1182 | // Delete's don't need rows in the paired transform. |
1182 | if (mainFileRow.Operation == RowOperation.Delete) | 1183 | if (mainFileRow.Operation == RowOperation.Delete) |
@@ -1188,13 +1189,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
1188 | pairedFileRow.Operation = RowOperation.Modify; | 1189 | pairedFileRow.Operation = RowOperation.Modify; |
1189 | mainFileRow.CopyTo(pairedFileRow); | 1190 | mainFileRow.CopyTo(pairedFileRow); |
1190 | 1191 | ||
1191 | // Override authored media for patch bind. | 1192 | // Force modified File rows to appear in the transform. |
1192 | mainFileRow.DiskId = mediaSymbol.DiskId; | ||
1193 | |||
1194 | // Suppress any change to File.Sequence to avoid bloat. | ||
1195 | mainFileRow.Fields[7].Modified = false; | ||
1196 | |||
1197 | // Force File row to appear in the transform. | ||
1198 | switch (mainFileRow.Operation) | 1193 | switch (mainFileRow.Operation) |
1199 | { | 1194 | { |
1200 | case RowOperation.Modify: | 1195 | case RowOperation.Modify: |
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs index b849aea5..41559f8b 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs | |||
@@ -21,7 +21,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
21 | // As outlined in RFC 4122, this is our namespace for generating name-based (version 3) UUIDs. | 21 | // As outlined in RFC 4122, this is our namespace for generating name-based (version 3) UUIDs. |
22 | internal static readonly Guid WixComponentGuidNamespace = new Guid("{3064E5C6-FB63-4FE9-AC49-E446A792EFA5}"); | 22 | internal static readonly Guid WixComponentGuidNamespace = new Guid("{3064E5C6-FB63-4FE9-AC49-E446A792EFA5}"); |
23 | 23 | ||
24 | public BindDatabaseCommand(IBindContext context, IEnumerable<IWindowsInstallerBackendBinderExtension> backendExtension, IEnumerable<SubStorage> subStorages = null) | 24 | public BindDatabaseCommand(IBindContext context, IEnumerable<IWindowsInstallerBackendBinderExtension> backendExtension, IEnumerable<SubStorage> patchSubStorages = null) |
25 | { | 25 | { |
26 | this.ServiceProvider = context.ServiceProvider; | 26 | this.ServiceProvider = context.ServiceProvider; |
27 | 27 | ||
@@ -47,7 +47,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
47 | this.ResolvedLcid = context.ResolvedLcid; | 47 | this.ResolvedLcid = context.ResolvedLcid; |
48 | this.SuppressLayout = context.SuppressLayout; | 48 | this.SuppressLayout = context.SuppressLayout; |
49 | 49 | ||
50 | this.SubStorages = subStorages; | 50 | this.PatchSubStorages = patchSubStorages; |
51 | 51 | ||
52 | this.BackendExtensions = backendExtension; | 52 | this.BackendExtensions = backendExtension; |
53 | } | 53 | } |
@@ -76,7 +76,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
76 | 76 | ||
77 | private IEnumerable<IWindowsInstallerBackendBinderExtension> BackendExtensions { get; } | 77 | private IEnumerable<IWindowsInstallerBackendBinderExtension> BackendExtensions { get; } |
78 | 78 | ||
79 | private IEnumerable<SubStorage> SubStorages { get; } | 79 | private IEnumerable<SubStorage> PatchSubStorages { get; } |
80 | 80 | ||
81 | private Intermediate Intermediate { get; } | 81 | private Intermediate Intermediate { get; } |
82 | 82 | ||
@@ -180,35 +180,42 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
180 | command.Execute(); | 180 | command.Execute(); |
181 | } | 181 | } |
182 | 182 | ||
183 | #if TODO_PATCHING | 183 | // Add missing CreateFolder symbols to null-keypath components. |
184 | ////if (OutputType.Patch == this.Output.Type) | 184 | { |
185 | ////{ | 185 | var command = new AddCreateFoldersCommand(section); |
186 | //// foreach (SubStorage substorage in this.Output.SubStorages) | 186 | command.Execute(); |
187 | //// { | 187 | } |
188 | //// Output transform = substorage.Data; | ||
189 | |||
190 | //// ResolveFieldsCommand command = new ResolveFieldsCommand(); | ||
191 | //// command.Tables = transform.Tables; | ||
192 | //// command.FilesWithEmbeddedFiles = filesWithEmbeddedFiles; | ||
193 | //// command.FileManagerCore = this.FileManagerCore; | ||
194 | //// command.FileManagers = this.FileManagers; | ||
195 | //// command.SupportDelayedResolution = false; | ||
196 | //// command.TempFilesLocation = this.TempFilesLocation; | ||
197 | //// command.WixVariableResolver = this.WixVariableResolver; | ||
198 | //// command.Execute(); | ||
199 | |||
200 | //// this.MergeUnrealTables(transform.Tables); | ||
201 | //// } | ||
202 | ////} | ||
203 | #endif | ||
204 | 188 | ||
205 | if (this.Messaging.EncounteredError) | 189 | if (this.Messaging.EncounteredError) |
206 | { | 190 | { |
207 | return null; | 191 | return null; |
208 | } | 192 | } |
209 | 193 | ||
210 | this.Intermediate.UpdateLevel(Data.WindowsInstaller.IntermediateLevels.FullyBound); | 194 | // Process dependency references. |
211 | this.Messaging.Write(VerboseMessages.UpdatingFileInformation()); | 195 | if (SectionType.Product == section.Type || SectionType.Module == section.Type) |
196 | { | ||
197 | var dependencyRefs = section.Symbols.OfType<WixDependencyRefSymbol>().ToList(); | ||
198 | |||
199 | if (dependencyRefs.Any()) | ||
200 | { | ||
201 | var command = new ProcessDependencyReferencesCommand(this.WindowsInstallerBackendHelper, section, dependencyRefs); | ||
202 | command.Execute(); | ||
203 | } | ||
204 | } | ||
205 | |||
206 | // Process SoftwareTags in MSI packages. | ||
207 | if (SectionType.Product == section.Type) | ||
208 | { | ||
209 | var softwareTags = section.Symbols.OfType<WixPackageTagSymbol>().ToList(); | ||
210 | |||
211 | if (softwareTags.Any()) | ||
212 | { | ||
213 | var command = new ProcessPackageSoftwareTagsCommand(section, this.WindowsInstallerBackendHelper, softwareTags, this.IntermediateFolder); | ||
214 | command.Execute(); | ||
215 | |||
216 | trackedFiles.AddRange(command.TrackedFiles); | ||
217 | } | ||
218 | } | ||
212 | 219 | ||
213 | // Extract files that come from binary .wixlibs and WixExtensions (this does not extract files from merge modules). | 220 | // Extract files that come from binary .wixlibs and WixExtensions (this does not extract files from merge modules). |
214 | { | 221 | { |
@@ -217,21 +224,33 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
217 | trackedFiles.AddRange(extractedFiles); | 224 | trackedFiles.AddRange(extractedFiles); |
218 | } | 225 | } |
219 | 226 | ||
227 | // Update symbols that reference text files on disk. Some of those files may have come from .wixlibs and WixExtensions | ||
228 | // extracted above. | ||
229 | { | ||
230 | var command = new UpdateFromTextFilesCommand(this.Messaging, section); | ||
231 | command.Execute(); | ||
232 | } | ||
233 | |||
234 | this.Intermediate.UpdateLevel(Data.WindowsInstaller.IntermediateLevels.FullyBound); | ||
235 | this.Messaging.Write(VerboseMessages.UpdatingFileInformation()); | ||
236 | |||
220 | // This must occur after all variables and source paths have been resolved. | 237 | // This must occur after all variables and source paths have been resolved. |
221 | List<IFileFacade> fileFacades; | 238 | List<IFileFacade> allFileFacades; |
222 | if (SectionType.Patch == section.Type) | 239 | List<IFileFacade> fileFacadesFromIntermediate; |
240 | List<IFileFacade> fileFacadesFromModule = null; | ||
241 | if (section.Type == SectionType.Patch) | ||
223 | { | 242 | { |
224 | var command = new GetFileFacadesFromTransforms(this.Messaging, this.WindowsInstallerBackendHelper, this.FileSystemManager, this.SubStorages); | 243 | var command = new GetFileFacadesFromTransforms(this.Messaging, this.WindowsInstallerBackendHelper, this.FileSystemManager, this.PatchSubStorages); |
225 | command.Execute(); | 244 | command.Execute(); |
226 | 245 | ||
227 | fileFacades = command.FileFacades; | 246 | allFileFacades = fileFacadesFromIntermediate = command.FileFacades; |
228 | } | 247 | } |
229 | else | 248 | else |
230 | { | 249 | { |
231 | var command = new GetFileFacadesCommand(section, this.WindowsInstallerBackendHelper); | 250 | var command = new GetFileFacadesCommand(section, this.WindowsInstallerBackendHelper); |
232 | command.Execute(); | 251 | command.Execute(); |
233 | 252 | ||
234 | fileFacades = command.FileFacades; | 253 | allFileFacades = fileFacadesFromIntermediate = command.FileFacades; |
235 | } | 254 | } |
236 | 255 | ||
237 | // Retrieve file information from merge modules. | 256 | // Retrieve file information from merge modules. |
@@ -243,10 +262,11 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
243 | { | 262 | { |
244 | containsMergeModules = true; | 263 | containsMergeModules = true; |
245 | 264 | ||
246 | var command = new ExtractMergeModuleFilesCommand(this.Messaging, this.WindowsInstallerBackendHelper, wixMergeSymbols, fileFacades, installerVersion, this.IntermediateFolder, this.SuppressLayout); | 265 | var command = new ExtractMergeModuleFilesCommand(this.Messaging, this.WindowsInstallerBackendHelper, wixMergeSymbols, fileFacadesFromIntermediate, installerVersion, this.IntermediateFolder, this.SuppressLayout); |
247 | command.Execute(); | 266 | command.Execute(); |
248 | 267 | ||
249 | fileFacades.AddRange(command.MergeModulesFileFacades); | 268 | fileFacadesFromModule = new List<IFileFacade>(command.MergeModulesFileFacades); |
269 | allFileFacades.AddRange(fileFacadesFromModule); | ||
250 | trackedFiles.AddRange(command.TrackedFiles); | 270 | trackedFiles.AddRange(command.TrackedFiles); |
251 | } | 271 | } |
252 | } | 272 | } |
@@ -257,23 +277,9 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
257 | return null; | 277 | return null; |
258 | } | 278 | } |
259 | 279 | ||
260 | // Process SoftwareTags in MSI packages. | ||
261 | if (SectionType.Product == section.Type) | ||
262 | { | ||
263 | var softwareTags = section.Symbols.OfType<WixPackageTagSymbol>().ToList(); | ||
264 | |||
265 | if (softwareTags.Any()) | ||
266 | { | ||
267 | var command = new ProcessPackageSoftwareTagsCommand(section, this.WindowsInstallerBackendHelper, softwareTags, this.IntermediateFolder); | ||
268 | command.Execute(); | ||
269 | |||
270 | trackedFiles.AddRange(command.TrackedFiles); | ||
271 | } | ||
272 | } | ||
273 | |||
274 | // Gather information about files that do not come from merge modules. | 280 | // Gather information about files that do not come from merge modules. |
275 | { | 281 | { |
276 | var command = new UpdateFileFacadesCommand(this.Messaging, section, fileFacades, fileFacades.Where(f => !f.FromModule), variableCache, overwriteHash: true); | 282 | var command = new UpdateFileFacadesCommand(this.Messaging, section, allFileFacades, fileFacadesFromIntermediate, variableCache, overwriteHash: true); |
277 | command.Execute(); | 283 | command.Execute(); |
278 | } | 284 | } |
279 | 285 | ||
@@ -289,18 +295,6 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
289 | this.WindowsInstallerBackendHelper.ResolveDelayedFields(this.DelayedFields, variableCache); | 295 | this.WindowsInstallerBackendHelper.ResolveDelayedFields(this.DelayedFields, variableCache); |
290 | } | 296 | } |
291 | 297 | ||
292 | // Update symbols that reference text files on disk. | ||
293 | { | ||
294 | var command = new UpdateFromTextFilesCommand(this.Messaging, section); | ||
295 | command.Execute(); | ||
296 | } | ||
297 | |||
298 | // Add missing CreateFolder symbols to null-keypath components. | ||
299 | { | ||
300 | var command = new AddCreateFoldersCommand(section); | ||
301 | command.Execute(); | ||
302 | } | ||
303 | |||
304 | // Now that delayed fields are processed, fixup the package version (if needed) and validate it | 298 | // Now that delayed fields are processed, fixup the package version (if needed) and validate it |
305 | // which will short circuit duplicate errors later if the ProductVersion is invalid. | 299 | // which will short circuit duplicate errors later if the ProductVersion is invalid. |
306 | if (SectionType.Product == section.Type) | 300 | if (SectionType.Product == section.Type) |
@@ -308,18 +302,6 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
308 | this.ProcessProductVersion(packageSymbol, section, validate: true); | 302 | this.ProcessProductVersion(packageSymbol, section, validate: true); |
309 | } | 303 | } |
310 | 304 | ||
311 | // Process dependency references. | ||
312 | if (SectionType.Product == section.Type || SectionType.Module == section.Type) | ||
313 | { | ||
314 | var dependencyRefs = section.Symbols.OfType<WixDependencyRefSymbol>().ToList(); | ||
315 | |||
316 | if (dependencyRefs.Any()) | ||
317 | { | ||
318 | var command = new ProcessDependencyReferencesCommand(this.WindowsInstallerBackendHelper, section, dependencyRefs); | ||
319 | command.Execute(); | ||
320 | } | ||
321 | } | ||
322 | |||
323 | // If there are any backend extensions, give them the opportunity to process | 305 | // If there are any backend extensions, give them the opportunity to process |
324 | // the section now that the fields have all be resolved. | 306 | // the section now that the fields have all be resolved. |
325 | // | 307 | // |
@@ -339,9 +321,9 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
339 | 321 | ||
340 | if (reresolvedFiles.Any()) | 322 | if (reresolvedFiles.Any()) |
341 | { | 323 | { |
342 | var updatedFacades = reresolvedFiles.Select(f => fileFacades.First(ff => ff.Id == f.Id?.Id)); | 324 | var updatedFacades = reresolvedFiles.Select(f => allFileFacades.First(ff => ff.Id == f.Id?.Id)); |
343 | 325 | ||
344 | var command = new UpdateFileFacadesCommand(this.Messaging, section, fileFacades, updatedFacades, variableCache, overwriteHash: false); | 326 | var command = new UpdateFileFacadesCommand(this.Messaging, section, allFileFacades, updatedFacades, variableCache, overwriteHash: false); |
345 | command.Execute(); | 327 | command.Execute(); |
346 | } | 328 | } |
347 | } | 329 | } |
@@ -363,28 +345,22 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
363 | } | 345 | } |
364 | } | 346 | } |
365 | 347 | ||
366 | // Set generated component guids and validate all guids. | ||
367 | { | ||
368 | var command = new FinalizeComponentGuids(this.Messaging, this.WindowsInstallerBackendHelper, this.PathResolver, section, platform); | ||
369 | command.Execute(); | ||
370 | } | ||
371 | |||
372 | // Assign files to media and update file sequences. | 348 | // Assign files to media and update file sequences. |
373 | Dictionary<MediaSymbol, IEnumerable<IFileFacade>> filesByCabinetMedia; | 349 | Dictionary<MediaSymbol, IEnumerable<IFileFacade>> filesByCabinetMedia; |
374 | IEnumerable<IFileFacade> uncompressedFiles; | 350 | IEnumerable<IFileFacade> uncompressedFiles; |
375 | { | 351 | { |
376 | var order = new OptimizeFileFacadesOrderCommand(this.WindowsInstallerBackendHelper, this.PathResolver, section, platform, fileFacades); | 352 | var order = new OptimizeFileFacadesOrderCommand(this.WindowsInstallerBackendHelper, this.PathResolver, section, platform, allFileFacades); |
377 | order.Execute(); | 353 | order.Execute(); |
378 | 354 | ||
379 | fileFacades = order.FileFacades; | 355 | allFileFacades = order.FileFacades; |
380 | 356 | ||
381 | var assign = new AssignMediaCommand(section, this.Messaging, fileFacades, compressed); | 357 | var assign = new AssignMediaCommand(section, this.Messaging, allFileFacades, compressed); |
382 | assign.Execute(); | 358 | assign.Execute(); |
383 | 359 | ||
384 | filesByCabinetMedia = assign.FileFacadesByCabinetMedia; | 360 | filesByCabinetMedia = assign.FileFacadesByCabinetMedia; |
385 | uncompressedFiles = assign.UncompressedFileFacades; | 361 | uncompressedFiles = assign.UncompressedFileFacades; |
386 | 362 | ||
387 | var update = new UpdateMediaSequencesCommand(section, fileFacades); | 363 | var update = new UpdateMediaSequencesCommand(section, allFileFacades); |
388 | update.Execute(); | 364 | update.Execute(); |
389 | } | 365 | } |
390 | 366 | ||
@@ -394,6 +370,24 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
394 | return null; | 370 | return null; |
395 | } | 371 | } |
396 | 372 | ||
373 | // Copy updated file facade data back into the transforms or symbols as appropriate. | ||
374 | if (section.Type == SectionType.Patch) | ||
375 | { | ||
376 | var command = new UpdateTransformsWithFileFacades(this.Messaging, section, this.PatchSubStorages, tableDefinitions, allFileFacades); | ||
377 | command.Execute(); | ||
378 | } | ||
379 | else | ||
380 | { | ||
381 | var command = new UpdateSymbolsWithFileFacadesCommand(section, allFileFacades); | ||
382 | command.Execute(); | ||
383 | } | ||
384 | |||
385 | // Set generated component guids and validate all guids. | ||
386 | { | ||
387 | var command = new FinalizeComponentGuids(this.Messaging, this.WindowsInstallerBackendHelper, this.PathResolver, section, platform); | ||
388 | command.Execute(); | ||
389 | } | ||
390 | |||
397 | // Time to create the WindowsInstallerData object. Try to put as much above here as possible, updating the IR is better. | 391 | // Time to create the WindowsInstallerData object. Try to put as much above here as possible, updating the IR is better. |
398 | WindowsInstallerData data; | 392 | WindowsInstallerData data; |
399 | { | 393 | { |
@@ -412,9 +406,19 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
412 | var unsuppress = new AddBackSuppressedSequenceTablesCommand(data, tableDefinitions); | 406 | var unsuppress = new AddBackSuppressedSequenceTablesCommand(data, tableDefinitions); |
413 | suppressedTableNames = unsuppress.Execute(); | 407 | suppressedTableNames = unsuppress.Execute(); |
414 | } | 408 | } |
409 | else if (data.Type == OutputType.Product) // we can create instance transforms since Component Guids and Outputs are created. | ||
410 | { | ||
411 | var command = new CreateInstanceTransformsCommand(section, data, tableDefinitions, this.WindowsInstallerBackendHelper); | ||
412 | command.Execute(); | ||
413 | |||
414 | foreach (var storage in command.SubStorages) | ||
415 | { | ||
416 | data.SubStorages.Add(storage); | ||
417 | } | ||
418 | } | ||
415 | else if (data.Type == OutputType.Patch) | 419 | else if (data.Type == OutputType.Patch) |
416 | { | 420 | { |
417 | foreach (var storage in this.SubStorages) | 421 | foreach (var storage in this.PatchSubStorages) |
418 | { | 422 | { |
419 | data.SubStorages.Add(storage); | 423 | data.SubStorages.Add(storage); |
420 | } | 424 | } |
@@ -426,13 +430,9 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
426 | return null; | 430 | return null; |
427 | } | 431 | } |
428 | 432 | ||
429 | // Ensure the intermediate folder is created since delta patches will be | 433 | if (section.Type == SectionType.Patch && this.DeltaBinaryPatch) |
430 | // created there. | ||
431 | Directory.CreateDirectory(this.IntermediateFolder); | ||
432 | |||
433 | if (SectionType.Patch == section.Type && this.DeltaBinaryPatch) | ||
434 | { | 434 | { |
435 | var command = new CreateDeltaPatchesCommand(fileFacades, this.IntermediateFolder, section.Symbols.OfType<WixPatchSymbol>().FirstOrDefault()); | 435 | var command = new CreateDeltaPatchesCommand(allFileFacades, this.IntermediateFolder, section.Symbols.OfType<WixPatchSymbol>().FirstOrDefault()); |
436 | command.Execute(); | 436 | command.Execute(); |
437 | } | 437 | } |
438 | 438 | ||
@@ -454,19 +454,6 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
454 | return null; | 454 | return null; |
455 | } | 455 | } |
456 | 456 | ||
457 | // We can create instance transforms since Component Guids and Outputs are created. | ||
458 | if (data.Type == OutputType.Product) | ||
459 | { | ||
460 | var command = new CreateInstanceTransformsCommand(section, data, tableDefinitions, this.WindowsInstallerBackendHelper); | ||
461 | command.Execute(); | ||
462 | } | ||
463 | else if (data.Type == OutputType.Patch) | ||
464 | { | ||
465 | // Copy output data back into the transforms. | ||
466 | var command = new UpdateTransformsWithFileFacades(this.Messaging, data, this.SubStorages, tableDefinitions, fileFacades); | ||
467 | command.Execute(); | ||
468 | } | ||
469 | |||
470 | // Generate database file. | 457 | // Generate database file. |
471 | { | 458 | { |
472 | this.Messaging.Write(VerboseMessages.GeneratingDatabase()); | 459 | this.Messaging.Write(VerboseMessages.GeneratingDatabase()); |
@@ -491,7 +478,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
491 | { | 478 | { |
492 | this.Messaging.Write(VerboseMessages.MergingModules()); | 479 | this.Messaging.Write(VerboseMessages.MergingModules()); |
493 | 480 | ||
494 | var command = new MergeModulesCommand(this.Messaging, this.WindowsInstallerBackendHelper, fileFacades, section, suppressedTableNames, this.OutputPath, this.IntermediateFolder); | 481 | var command = new MergeModulesCommand(this.Messaging, this.WindowsInstallerBackendHelper, fileFacadesFromModule, section, suppressedTableNames, this.OutputPath, this.IntermediateFolder); |
495 | command.Execute(); | 482 | command.Execute(); |
496 | 483 | ||
497 | trackedFiles.AddRange(command.TrackedFiles); | 484 | trackedFiles.AddRange(command.TrackedFiles); |
@@ -518,7 +505,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
518 | var fi = new FileInfo(this.OutputPath); | 505 | var fi = new FileInfo(this.OutputPath); |
519 | if (fi.Length > Int32.MaxValue) | 506 | if (fi.Length > Int32.MaxValue) |
520 | { | 507 | { |
521 | this.Messaging.Write(WarningMessages.WindowsInstallerFileTooLarge(null, this.OutputPath, "MSI")); | 508 | this.Messaging.Write(WarningMessages.WindowsInstallerFileTooLarge(null, this.OutputPath, data.Type.ToString())); |
522 | } | 509 | } |
523 | } | 510 | } |
524 | catch | 511 | catch |
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Bind/CabinetBuilder.cs b/src/wix/WixToolset.Core.WindowsInstaller/Bind/CabinetBuilder.cs index 9acbe475..93aad0a6 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Bind/CabinetBuilder.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Bind/CabinetBuilder.cs | |||
@@ -169,18 +169,24 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
169 | } | 169 | } |
170 | } | 170 | } |
171 | 171 | ||
172 | // create the cabinet file | 172 | // Calculate the files to be compressed into the cabinet. |
173 | var cabinetPath = Path.GetFullPath(cabinetWorkItem.CabinetFile); | 173 | var compressFiles = new List<CabinetCompressFile>(); |
174 | |||
175 | foreach (var facade in cabinetWorkItem.FileFacades.OrderBy(f => f.Sequence)) | ||
176 | { | ||
177 | var modularizedId = facade.Id + cabinetWorkItem.ModularizationSuffix; | ||
174 | 178 | ||
175 | var files = cabinetWorkItem.FileFacades | 179 | var compressFile = cabinetWorkItem.HashesByFileId.TryGetValue(facade.Id, out var hash) ? |
176 | .OrderBy(f => f.Sequence) | 180 | new CabinetCompressFile(facade.SourcePath, modularizedId, hash.HashPart1, hash.HashPart2, hash.HashPart3, hash.HashPart4) : |
177 | .Select(facade => facade.Hash == null ? | 181 | new CabinetCompressFile(facade.SourcePath, modularizedId); |
178 | new CabinetCompressFile(facade.SourcePath, facade.Id + cabinetWorkItem.ModularizationSuffix) : | ||
179 | new CabinetCompressFile(facade.SourcePath, facade.Id + cabinetWorkItem.ModularizationSuffix, facade.Hash.HashPart1, facade.Hash.HashPart2, facade.Hash.HashPart3, facade.Hash.HashPart4)) | ||
180 | .ToList(); | ||
181 | 182 | ||
183 | compressFiles.Add(compressFile); | ||
184 | } | ||
185 | |||
186 | // create the cabinet file | ||
187 | var cabinetPath = Path.GetFullPath(cabinetWorkItem.CabinetFile); | ||
182 | var cab = new Cabinet(cabinetPath); | 188 | var cab = new Cabinet(cabinetPath); |
183 | var created = cab.Compress(files, cabinetWorkItem.CompressionLevel, maxCabinetSize, cabinetWorkItem.MaxThreshold); | 189 | var created = cab.Compress(compressFiles, cabinetWorkItem.CompressionLevel, maxCabinetSize, cabinetWorkItem.MaxThreshold); |
184 | 190 | ||
185 | // Best effort check to see if the cabinet is too large for the Windows Installer. | 191 | // Best effort check to see if the cabinet is too large for the Windows Installer. |
186 | try | 192 | try |
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Bind/CabinetWorkItem.cs b/src/wix/WixToolset.Core.WindowsInstaller/Bind/CabinetWorkItem.cs index 12332c80..d9bc7a7e 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Bind/CabinetWorkItem.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Bind/CabinetWorkItem.cs | |||
@@ -4,6 +4,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
4 | { | 4 | { |
5 | using System.Collections.Generic; | 5 | using System.Collections.Generic; |
6 | using WixToolset.Data; | 6 | using WixToolset.Data; |
7 | using WixToolset.Data.Symbols; | ||
7 | using WixToolset.Extensibility.Data; | 8 | using WixToolset.Extensibility.Data; |
8 | 9 | ||
9 | /// <summary> | 10 | /// <summary> |
@@ -17,11 +18,12 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
17 | /// <param name="sourceLineNumber">Source line number that requires the cabinet creation.</param> | 18 | /// <param name="sourceLineNumber">Source line number that requires the cabinet creation.</param> |
18 | /// <param name="diskId"></param> | 19 | /// <param name="diskId"></param> |
19 | /// <param name="fileFacades">The collection of files in this cabinet.</param> | 20 | /// <param name="fileFacades">The collection of files in this cabinet.</param> |
21 | /// <param name="hashesByFileId">The hashes for unversioned files.</param> | ||
20 | /// <param name="cabinetFile">The cabinet file.</param> | 22 | /// <param name="cabinetFile">The cabinet file.</param> |
21 | /// <param name="maxThreshold">Maximum threshold for each cabinet.</param> | 23 | /// <param name="maxThreshold">Maximum threshold for each cabinet.</param> |
22 | /// <param name="compressionLevel">The compression level of the cabinet.</param> | 24 | /// <param name="compressionLevel">The compression level of the cabinet.</param> |
23 | /// <param name="modularizationSuffix">Modularization suffix used when building a Merge Module.</param> | 25 | /// <param name="modularizationSuffix">Modularization suffix used when building a Merge Module.</param> |
24 | public CabinetWorkItem(SourceLineNumber sourceLineNumber, int diskId, string cabinetFile, IEnumerable<IFileFacade> fileFacades, int maxThreshold, CompressionLevel compressionLevel, string modularizationSuffix) | 26 | public CabinetWorkItem(SourceLineNumber sourceLineNumber, int diskId, string cabinetFile, IEnumerable<IFileFacade> fileFacades, Dictionary<string, MsiFileHashSymbol> hashesByFileId, int maxThreshold, CompressionLevel compressionLevel, string modularizationSuffix) |
25 | { | 27 | { |
26 | this.SourceLineNumber = sourceLineNumber; | 28 | this.SourceLineNumber = sourceLineNumber; |
27 | this.DiskId = diskId; | 29 | this.DiskId = diskId; |
@@ -29,6 +31,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
29 | this.CompressionLevel = compressionLevel; | 31 | this.CompressionLevel = compressionLevel; |
30 | this.ModularizationSuffix = modularizationSuffix; | 32 | this.ModularizationSuffix = modularizationSuffix; |
31 | this.FileFacades = fileFacades; | 33 | this.FileFacades = fileFacades; |
34 | this.HashesByFileId = hashesByFileId; | ||
32 | this.MaxThreshold = maxThreshold; | 35 | this.MaxThreshold = maxThreshold; |
33 | } | 36 | } |
34 | 37 | ||
@@ -66,6 +69,11 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
66 | public IEnumerable<IFileFacade> FileFacades { get; } | 69 | public IEnumerable<IFileFacade> FileFacades { get; } |
67 | 70 | ||
68 | /// <summary> | 71 | /// <summary> |
72 | /// The hashes for unversioned files. | ||
73 | /// </summary> | ||
74 | public Dictionary<string, MsiFileHashSymbol> HashesByFileId { get; } | ||
75 | |||
76 | /// <summary> | ||
69 | /// Gets the max threshold. | 77 | /// Gets the max threshold. |
70 | /// </summary> | 78 | /// </summary> |
71 | /// <value>The maximum threshold for a folder in a cabinet.</value> | 79 | /// <value>The maximum threshold for a folder in a cabinet.</value> |
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Bind/CreateCabinetsCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Bind/CreateCabinetsCommand.cs index 6ed107d5..1ed2ba79 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Bind/CreateCabinetsCommand.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Bind/CreateCabinetsCommand.cs | |||
@@ -95,6 +95,8 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
95 | 95 | ||
96 | var cabinetBuilder = new CabinetBuilder(this.Messaging, this.CabbingThreadCount, maximumCabinetSizeForLargeFileSplitting, maximumUncompressedMediaSize); | 96 | var cabinetBuilder = new CabinetBuilder(this.Messaging, this.CabbingThreadCount, maximumCabinetSizeForLargeFileSplitting, maximumUncompressedMediaSize); |
97 | 97 | ||
98 | var hashesByFileId = this.Section.Symbols.OfType<MsiFileHashSymbol>().ToDictionary(s => s.Id.Id); | ||
99 | |||
98 | foreach (var entry in this.FileFacadesByCabinet) | 100 | foreach (var entry in this.FileFacadesByCabinet) |
99 | { | 101 | { |
100 | var mediaSymbol = entry.Key; | 102 | var mediaSymbol = entry.Key; |
@@ -102,7 +104,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
102 | var compressionLevel = mediaSymbol.CompressionLevel ?? this.DefaultCompressionLevel ?? CompressionLevel.Medium; | 104 | var compressionLevel = mediaSymbol.CompressionLevel ?? this.DefaultCompressionLevel ?? CompressionLevel.Medium; |
103 | var cabinetDir = this.ResolveMedia(mediaSymbol, mediaSymbol.Layout, this.LayoutDirectory); | 105 | var cabinetDir = this.ResolveMedia(mediaSymbol, mediaSymbol.Layout, this.LayoutDirectory); |
104 | 106 | ||
105 | var cabinetWorkItem = this.CreateCabinetWorkItem(this.Data, cabinetDir, mediaSymbol, compressionLevel, files); | 107 | var cabinetWorkItem = this.CreateCabinetWorkItem(this.Data, cabinetDir, mediaSymbol, compressionLevel, files, hashesByFileId); |
106 | if (null != cabinetWorkItem) | 108 | if (null != cabinetWorkItem) |
107 | { | 109 | { |
108 | cabinetBuilder.Enqueue(cabinetWorkItem); | 110 | cabinetBuilder.Enqueue(cabinetWorkItem); |
@@ -140,16 +142,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
140 | return cabbingThreadCount; | 142 | return cabbingThreadCount; |
141 | } | 143 | } |
142 | 144 | ||
143 | /// <summary> | 145 | private CabinetWorkItem CreateCabinetWorkItem(WindowsInstallerData data, string cabinetDir, MediaSymbol mediaSymbol, CompressionLevel compressionLevel, IEnumerable<IFileFacade> fileFacades, Dictionary<string, MsiFileHashSymbol> hashesByFileId) |
144 | /// Creates a work item to create a cabinet. | ||
145 | /// </summary> | ||
146 | /// <param name="data">Windows Installer data for the current database.</param> | ||
147 | /// <param name="cabinetDir">Directory to create cabinet in.</param> | ||
148 | /// <param name="mediaSymbol">Media symbol containing information about the cabinet.</param> | ||
149 | /// <param name="compressionLevel">Desired compression level.</param> | ||
150 | /// <param name="fileFacades">Collection of files in this cabinet.</param> | ||
151 | /// <returns>created CabinetWorkItem object</returns> | ||
152 | private CabinetWorkItem CreateCabinetWorkItem(WindowsInstallerData data, string cabinetDir, MediaSymbol mediaSymbol, CompressionLevel compressionLevel, IEnumerable<IFileFacade> fileFacades) | ||
153 | { | 146 | { |
154 | CabinetWorkItem cabinetWorkItem = null; | 147 | CabinetWorkItem cabinetWorkItem = null; |
155 | 148 | ||
@@ -171,7 +164,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
171 | if (CabinetBuildOption.BuildAndCopy == resolvedCabinet.BuildOption || CabinetBuildOption.BuildAndMove == resolvedCabinet.BuildOption) | 164 | if (CabinetBuildOption.BuildAndCopy == resolvedCabinet.BuildOption || CabinetBuildOption.BuildAndMove == resolvedCabinet.BuildOption) |
172 | { | 165 | { |
173 | // Default to the threshold for best smartcabbing (makes smallest cabinet). | 166 | // Default to the threshold for best smartcabbing (makes smallest cabinet). |
174 | cabinetWorkItem = new CabinetWorkItem(mediaSymbol.SourceLineNumbers, mediaSymbol.DiskId, resolvedCabinet.Path, fileFacades, maxThreshold: 0, compressionLevel: compressionLevel, modularizationSuffix: this.ModularizationSuffix); | 167 | cabinetWorkItem = new CabinetWorkItem(mediaSymbol.SourceLineNumbers, mediaSymbol.DiskId, resolvedCabinet.Path, fileFacades, hashesByFileId, maxThreshold: 0, compressionLevel: compressionLevel, modularizationSuffix: this.ModularizationSuffix); |
175 | } | 168 | } |
176 | else // reuse the cabinet from the cabinet cache. | 169 | else // reuse the cabinet from the cabinet cache. |
177 | { | 170 | { |
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Bind/CreateInstanceTransformsCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Bind/CreateInstanceTransformsCommand.cs index d0e25571..1d480250 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Bind/CreateInstanceTransformsCommand.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Bind/CreateInstanceTransformsCommand.cs | |||
@@ -30,8 +30,12 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
30 | 30 | ||
31 | private IBackendHelper BackendHelper { get; } | 31 | private IBackendHelper BackendHelper { get; } |
32 | 32 | ||
33 | public void Execute() | 33 | public IReadOnlyCollection<SubStorage> SubStorages { get; private set; } |
34 | |||
35 | public IReadOnlyCollection<SubStorage> Execute() | ||
34 | { | 36 | { |
37 | var subStorages = new List<SubStorage>(); | ||
38 | |||
35 | // Create and add substorages for instance transforms. | 39 | // Create and add substorages for instance transforms. |
36 | var wixInstanceTransformsSymbols = this.Section.Symbols.OfType<WixInstanceTransformsSymbol>(); | 40 | var wixInstanceTransformsSymbols = this.Section.Symbols.OfType<WixInstanceTransformsSymbol>(); |
37 | 41 | ||
@@ -252,9 +256,11 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
252 | summaryRow[1] = "4"; | 256 | summaryRow[1] = "4"; |
253 | } | 257 | } |
254 | 258 | ||
255 | this.Output.SubStorages.Add(new SubStorage(instanceId, instanceTransform)); | 259 | subStorages.Add(new SubStorage(instanceId, instanceTransform)); |
256 | } | 260 | } |
257 | } | 261 | } |
262 | |||
263 | return this.SubStorages = subStorages; | ||
258 | } | 264 | } |
259 | } | 265 | } |
260 | } | 266 | } |
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Bind/CreatePatchTransformsCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Bind/CreatePatchTransformsCommand.cs index 5c993f63..6d5bff69 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Bind/CreatePatchTransformsCommand.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Bind/CreatePatchTransformsCommand.cs | |||
@@ -6,31 +6,44 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
7 | using System.IO; | 7 | using System.IO; |
8 | using System.Linq; | 8 | using System.Linq; |
9 | using WixToolset.Core.Native.Msi; | ||
10 | using WixToolset.Core.WindowsInstaller.Unbind; | 9 | using WixToolset.Core.WindowsInstaller.Unbind; |
11 | using WixToolset.Data; | 10 | using WixToolset.Data; |
12 | using WixToolset.Data.Symbols; | 11 | using WixToolset.Data.Symbols; |
13 | using WixToolset.Data.WindowsInstaller; | 12 | using WixToolset.Data.WindowsInstaller; |
13 | using WixToolset.Extensibility; | ||
14 | using WixToolset.Extensibility.Data; | ||
14 | using WixToolset.Extensibility.Services; | 15 | using WixToolset.Extensibility.Services; |
15 | 16 | ||
16 | internal class CreatePatchTransformsCommand | 17 | internal class CreatePatchTransformsCommand |
17 | { | 18 | { |
18 | public CreatePatchTransformsCommand(IMessaging messaging, IBackendHelper backendHelper, Intermediate intermediate, string intermediateFolder) | 19 | public CreatePatchTransformsCommand(IMessaging messaging, IBackendHelper backendHelper, IPathResolver pathResolver, IFileResolver fileResolver, IReadOnlyCollection<IResolverExtension> resolverExtensions, Intermediate intermediate, string intermediateFolder, IReadOnlyCollection<IBindPath> bindPaths) |
19 | { | 20 | { |
20 | this.Messaging = messaging; | 21 | this.Messaging = messaging; |
21 | this.BackendHelper = backendHelper; | 22 | this.BackendHelper = backendHelper; |
23 | this.PathResolver = pathResolver; | ||
24 | this.FileResolver = fileResolver; | ||
25 | this.ResolverExtensions = resolverExtensions; | ||
22 | this.Intermediate = intermediate; | 26 | this.Intermediate = intermediate; |
23 | this.IntermediateFolder = intermediateFolder; | 27 | this.IntermediateFolder = intermediateFolder; |
28 | this.BindPaths = bindPaths; | ||
24 | } | 29 | } |
25 | 30 | ||
26 | private IMessaging Messaging { get; } | 31 | private IMessaging Messaging { get; } |
27 | 32 | ||
28 | private IBackendHelper BackendHelper { get; } | 33 | private IBackendHelper BackendHelper { get; } |
29 | 34 | ||
35 | private IPathResolver PathResolver { get; } | ||
36 | |||
37 | private IFileResolver FileResolver { get; } | ||
38 | |||
39 | private IReadOnlyCollection<IResolverExtension> ResolverExtensions { get; } | ||
40 | |||
30 | private Intermediate Intermediate { get; } | 41 | private Intermediate Intermediate { get; } |
31 | 42 | ||
32 | private string IntermediateFolder { get; } | 43 | private string IntermediateFolder { get; } |
33 | 44 | ||
45 | private IReadOnlyCollection<IBindPath> BindPaths { get; } | ||
46 | |||
34 | public IEnumerable<PatchTransform> PatchTransforms { get; private set; } | 47 | public IEnumerable<PatchTransform> PatchTransforms { get; private set; } |
35 | 48 | ||
36 | public IEnumerable<PatchTransform> Execute() | 49 | public IEnumerable<PatchTransform> Execute() |
@@ -41,23 +54,11 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
41 | 54 | ||
42 | foreach (var symbol in symbols) | 55 | foreach (var symbol in symbols) |
43 | { | 56 | { |
44 | WindowsInstallerData transform; | 57 | var targetData = this.GetWindowsInstallerData(symbol.BaselineFile.Path, BindStage.Target); |
45 | 58 | var updatedData = this.GetWindowsInstallerData(symbol.UpdateFile.Path, BindStage.Updated); | |
46 | if (symbol.TransformFile is null) | ||
47 | { | ||
48 | var baselineData = this.GetData(symbol.BaselineFile.Path); | ||
49 | var updateData = this.GetData(symbol.UpdateFile.Path); | ||
50 | 59 | ||
51 | var command = new GenerateTransformCommand(this.Messaging, baselineData, updateData, preserveUnchangedRows: true, showPedanticMessages: false); | 60 | var command = new GenerateTransformCommand(this.Messaging, targetData, updatedData, preserveUnchangedRows: true, showPedanticMessages: false); |
52 | transform = command.Execute(); | 61 | var transform = command.Execute(); |
53 | } | ||
54 | else | ||
55 | { | ||
56 | var exportBasePath = Path.Combine(this.IntermediateFolder, "_trans"); // TODO: come up with a better path. | ||
57 | |||
58 | var command = new UnbindTransformCommand(this.Messaging, this.BackendHelper, symbol.TransformFile.Path, exportBasePath, this.IntermediateFolder); | ||
59 | transform = command.Execute(); | ||
60 | } | ||
61 | 62 | ||
62 | patchTransforms.Add(new PatchTransform(symbol.Id.Id, transform)); | 63 | patchTransforms.Add(new PatchTransform(symbol.Id.Id, transform)); |
63 | } | 64 | } |
@@ -67,26 +68,61 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
67 | return this.PatchTransforms; | 68 | return this.PatchTransforms; |
68 | } | 69 | } |
69 | 70 | ||
70 | private WindowsInstallerData GetData(string path) | 71 | private WindowsInstallerData GetWindowsInstallerData(string path, BindStage stage) |
71 | { | 72 | { |
72 | var ext = Path.GetExtension(path); | 73 | if (DataLoader.TryLoadWindowsInstallerData(path, true, out var data)) |
73 | |||
74 | if (".msi".Equals(ext, StringComparison.OrdinalIgnoreCase)) | ||
75 | { | 74 | { |
76 | using (var database = new Database(path, OpenDatabase.ReadOnly)) | 75 | // Re-resolve file paths only when loading from .wixpdb. |
77 | { | 76 | this.ReResolveWindowsInstallerData(data, stage); |
78 | var exportBasePath = Path.Combine(this.IntermediateFolder, "_msi"); // TODO: come up with a better path. | 77 | } |
78 | else | ||
79 | { | ||
80 | var stageFolder = $"_{stage.ToString().ToLowerInvariant()}_msi"; | ||
81 | var exportBasePath = Path.Combine(this.IntermediateFolder, stageFolder); | ||
82 | var extractFilesFolder = Path.Combine(exportBasePath, "File"); | ||
83 | |||
84 | var command = new UnbindDatabaseCommand(this.Messaging, this.BackendHelper, this.PathResolver, path, OutputType.Product, exportBasePath, extractFilesFolder, this.IntermediateFolder, enableDemodularization: false, skipSummaryInfo: false); | ||
85 | data = command.Execute(); | ||
86 | } | ||
79 | 87 | ||
80 | var isAdminImage = false; // TODO: need a better way to set this | 88 | return data; |
89 | } | ||
81 | 90 | ||
82 | var command = new UnbindDatabaseCommand(this.Messaging, this.BackendHelper, database, path, OutputType.Product, exportBasePath, this.IntermediateFolder, isAdminImage, suppressDemodularization: true, skipSummaryInfo: true); | 91 | private void ReResolveWindowsInstallerData(WindowsInstallerData data, BindStage stage) |
83 | return command.Execute(); | 92 | { |
84 | } | 93 | var bindPaths = this.BindPaths.Where(b => b.Stage == stage).ToList(); |
94 | |||
95 | if (bindPaths.Count == 0) | ||
96 | { | ||
97 | return; | ||
85 | } | 98 | } |
86 | else // assume .wixpdb (or .wixout) | 99 | |
100 | foreach (var table in data.Tables) | ||
87 | { | 101 | { |
88 | var data = WindowsInstallerData.Load(path, true); | 102 | foreach (var row in table.Rows) |
89 | return data; | 103 | { |
104 | foreach (var field in row.Fields.Where(f => f.Column.Type == ColumnType.Object)) | ||
105 | { | ||
106 | if (field.PreviousData != null) | ||
107 | { | ||
108 | try | ||
109 | { | ||
110 | var originalPath = field.AsString(); | ||
111 | |||
112 | var resolvedPath = this.FileResolver.ResolveFile(field.PreviousData, this.ResolverExtensions, bindPaths, stage, row.SourceLineNumbers, null); | ||
113 | |||
114 | if (!String.Equals(originalPath, resolvedPath, StringComparison.OrdinalIgnoreCase)) | ||
115 | { | ||
116 | field.Data = resolvedPath; | ||
117 | } | ||
118 | } | ||
119 | catch (WixException e) | ||
120 | { | ||
121 | this.Messaging.Write(e.Error); | ||
122 | } | ||
123 | } | ||
124 | } | ||
125 | } | ||
90 | } | 126 | } |
91 | } | 127 | } |
92 | } | 128 | } |
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Bind/CreateWindowsInstallerDataFromIRCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Bind/CreateWindowsInstallerDataFromIRCommand.cs index 60317cd9..4d99ff40 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Bind/CreateWindowsInstallerDataFromIRCommand.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Bind/CreateWindowsInstallerDataFromIRCommand.cs | |||
@@ -662,10 +662,13 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
662 | row.FileSize = symbol.FileSize; | 662 | row.FileSize = symbol.FileSize; |
663 | row.Version = symbol.Version; | 663 | row.Version = symbol.Version; |
664 | row.Language = symbol.Language; | 664 | row.Language = symbol.Language; |
665 | row.DiskId = symbol.DiskId ?? 1; // TODO: is 1 the correct thing to default here | ||
666 | row.Sequence = symbol.Sequence; | 665 | row.Sequence = symbol.Sequence; |
666 | row.DiskId = symbol.DiskId ?? throw new InvalidDataException("FileSymbol.DiskId should have been initialized before creating WindowsInstallerData from IntermediateRepresentation."); | ||
667 | row.Source = symbol.Source.Path; | 667 | row.Source = symbol.Source.Path; |
668 | 668 | ||
669 | var previousSourceField = symbol.Fields[(int)FileSymbolFields.Source]?.PreviousValue; | ||
670 | row.PreviousSource = previousSourceField?.AsPath().Path; | ||
671 | |||
669 | var attributes = (symbol.Attributes & FileSymbolAttributes.Checksum) == FileSymbolAttributes.Checksum ? WindowsInstallerConstants.MsidbFileAttributesChecksum : 0; | 672 | var attributes = (symbol.Attributes & FileSymbolAttributes.Checksum) == FileSymbolAttributes.Checksum ? WindowsInstallerConstants.MsidbFileAttributesChecksum : 0; |
670 | attributes |= (symbol.Attributes & FileSymbolAttributes.Compressed) == FileSymbolAttributes.Compressed ? WindowsInstallerConstants.MsidbFileAttributesCompressed : 0; | 673 | attributes |= (symbol.Attributes & FileSymbolAttributes.Compressed) == FileSymbolAttributes.Compressed ? WindowsInstallerConstants.MsidbFileAttributesCompressed : 0; |
671 | attributes |= (symbol.Attributes & FileSymbolAttributes.Uncompressed) == FileSymbolAttributes.Uncompressed ? WindowsInstallerConstants.MsidbFileAttributesNoncompressed : 0; | 674 | attributes |= (symbol.Attributes & FileSymbolAttributes.Uncompressed) == FileSymbolAttributes.Uncompressed ? WindowsInstallerConstants.MsidbFileAttributesNoncompressed : 0; |
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Bind/DataLoader.cs b/src/wix/WixToolset.Core.WindowsInstaller/Bind/DataLoader.cs new file mode 100644 index 00000000..6214bbdb --- /dev/null +++ b/src/wix/WixToolset.Core.WindowsInstaller/Bind/DataLoader.cs | |||
@@ -0,0 +1,49 @@ | |||
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.Bind | ||
4 | { | ||
5 | using System; | ||
6 | using System.IO; | ||
7 | using WixToolset.Data.WindowsInstaller; | ||
8 | |||
9 | internal class DataLoader | ||
10 | { | ||
11 | public static bool TryLoadWindowsInstallerData(string path, out WindowsInstallerData data) | ||
12 | { | ||
13 | return TryLoadWindowsInstallerData(path, false, out data); | ||
14 | } | ||
15 | |||
16 | public static bool TryLoadWindowsInstallerData(string path, bool suppressVersionCheck, out WindowsInstallerData data) | ||
17 | { | ||
18 | data = null; | ||
19 | |||
20 | var extension = Path.GetExtension(path); | ||
21 | |||
22 | // If the path is _not_ obviously a Windows Installer database, let's try opening it as | ||
23 | // our own data file format. | ||
24 | if (!extension.Equals(".msi", StringComparison.OrdinalIgnoreCase) && !extension.Equals(".msm", StringComparison.OrdinalIgnoreCase)) | ||
25 | { | ||
26 | (data, _) = LoadWindowsInstallerDataSafely(path, suppressVersionCheck); | ||
27 | } | ||
28 | |||
29 | return data != null; | ||
30 | } | ||
31 | |||
32 | public static (WindowsInstallerData, Exception) LoadWindowsInstallerDataSafely(string path, bool suppressVersionCheck = false) | ||
33 | { | ||
34 | WindowsInstallerData data = null; | ||
35 | Exception exception = null; | ||
36 | |||
37 | try | ||
38 | { | ||
39 | data = WindowsInstallerData.Load(path, suppressVersionCheck); | ||
40 | } | ||
41 | catch (Exception e) | ||
42 | { | ||
43 | exception = e; | ||
44 | } | ||
45 | |||
46 | return (data, exception); | ||
47 | } | ||
48 | } | ||
49 | } | ||
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Bind/ExtractMergeModuleFilesCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Bind/ExtractMergeModuleFilesCommand.cs index 06168727..94ed0afc 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Bind/ExtractMergeModuleFilesCommand.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Bind/ExtractMergeModuleFilesCommand.cs | |||
@@ -22,12 +22,12 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
22 | /// </summary> | 22 | /// </summary> |
23 | internal class ExtractMergeModuleFilesCommand | 23 | internal class ExtractMergeModuleFilesCommand |
24 | { | 24 | { |
25 | public ExtractMergeModuleFilesCommand(IMessaging messaging, IWindowsInstallerBackendHelper backendHelper, IEnumerable<WixMergeSymbol> wixMergeSymbols, IEnumerable<IFileFacade> fileFacades, int installerVersion, string intermediateFolder, bool suppressLayout) | 25 | public ExtractMergeModuleFilesCommand(IMessaging messaging, IWindowsInstallerBackendHelper backendHelper, IEnumerable<WixMergeSymbol> wixMergeSymbols, IEnumerable<IFileFacade> fileFacadesFromIntermediate, int installerVersion, string intermediateFolder, bool suppressLayout) |
26 | { | 26 | { |
27 | this.Messaging = messaging; | 27 | this.Messaging = messaging; |
28 | this.BackendHelper = backendHelper; | 28 | this.BackendHelper = backendHelper; |
29 | this.WixMergeSymbols = wixMergeSymbols; | 29 | this.WixMergeSymbols = wixMergeSymbols; |
30 | this.FileFacades = fileFacades; | 30 | this.FileFacadesFromIntermediate = fileFacadesFromIntermediate; |
31 | this.OutputInstallerVersion = installerVersion; | 31 | this.OutputInstallerVersion = installerVersion; |
32 | this.IntermediateFolder = intermediateFolder; | 32 | this.IntermediateFolder = intermediateFolder; |
33 | this.SuppressLayout = suppressLayout; | 33 | this.SuppressLayout = suppressLayout; |
@@ -39,7 +39,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
39 | 39 | ||
40 | private IEnumerable<WixMergeSymbol> WixMergeSymbols { get; } | 40 | private IEnumerable<WixMergeSymbol> WixMergeSymbols { get; } |
41 | 41 | ||
42 | private IEnumerable<IFileFacade> FileFacades { get; } | 42 | private IEnumerable<IFileFacade> FileFacadesFromIntermediate { get; } |
43 | 43 | ||
44 | private int OutputInstallerVersion { get; } | 44 | private int OutputInstallerVersion { get; } |
45 | 45 | ||
@@ -65,7 +65,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
65 | // Now since Merge Modules are already slow and generally less desirable than .wixlibs we'll let | 65 | // Now since Merge Modules are already slow and generally less desirable than .wixlibs we'll let |
66 | // this case be slightly more expensive because the cost of maintaining an indexed file row collection | 66 | // this case be slightly more expensive because the cost of maintaining an indexed file row collection |
67 | // is a lot more costly for the common cases. | 67 | // is a lot more costly for the common cases. |
68 | var indexedFileFacades = this.FileFacades.ToDictionary(f => f.Id, StringComparer.Ordinal); | 68 | var indexedFileFacades = this.FileFacadesFromIntermediate.ToDictionary(f => f.Id, StringComparer.Ordinal); |
69 | 69 | ||
70 | foreach (var wixMergeRow in this.WixMergeSymbols) | 70 | foreach (var wixMergeRow in this.WixMergeSymbols) |
71 | { | 71 | { |
@@ -115,7 +115,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
115 | fileSymbol.DiskId = wixMergeRow.DiskId; | 115 | fileSymbol.DiskId = wixMergeRow.DiskId; |
116 | fileSymbol.Source = new IntermediateFieldPathValue { Path = Path.Combine(this.IntermediateFolder, wixMergeRow.Id.Id, record[1]) }; | 116 | fileSymbol.Source = new IntermediateFieldPathValue { Path = Path.Combine(this.IntermediateFolder, wixMergeRow.Id.Id, record[1]) }; |
117 | 117 | ||
118 | var mergeModuleFileFacade = this.BackendHelper.CreateFileFacadeFromMergeModule(fileSymbol); | 118 | var mergeModuleFileFacade = this.BackendHelper.CreateFileFacade(fileSymbol); |
119 | 119 | ||
120 | // If case-sensitive collision with another merge module or a user-authored file identifier. | 120 | // If case-sensitive collision with another merge module or a user-authored file identifier. |
121 | if (indexedFileFacades.TryGetValue(mergeModuleFileFacade.Id, out var collidingFacade)) | 121 | if (indexedFileFacades.TryGetValue(mergeModuleFileFacade.Id, out var collidingFacade)) |
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Bind/GenerateTransformCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Bind/GenerateTransformCommand.cs index 575065bb..92a0e11f 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Bind/GenerateTransformCommand.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Bind/GenerateTransformCommand.cs | |||
@@ -16,7 +16,7 @@ namespace WixToolset.Core.WindowsInstaller | |||
16 | /// </summary> | 16 | /// </summary> |
17 | internal class GenerateTransformCommand | 17 | internal class GenerateTransformCommand |
18 | { | 18 | { |
19 | private const char sectionDelimiter = '/'; | 19 | private const char SectionDelimiter = '/'; |
20 | private readonly IMessaging messaging; | 20 | private readonly IMessaging messaging; |
21 | private SummaryInformationStreams transformSummaryInfo; | 21 | private SummaryInformationStreams transformSummaryInfo; |
22 | 22 | ||
@@ -38,22 +38,10 @@ namespace WixToolset.Core.WindowsInstaller | |||
38 | 38 | ||
39 | private TransformFlags ValidationFlags { get; } | 39 | private TransformFlags ValidationFlags { get; } |
40 | 40 | ||
41 | /// <summary> | ||
42 | /// Gets or sets the option to show pedantic messages. | ||
43 | /// </summary> | ||
44 | /// <value>The option to show pedantic messages.</value> | ||
45 | private bool ShowPedanticMessages { get; } | 41 | private bool ShowPedanticMessages { get; } |
46 | 42 | ||
47 | /// <summary> | ||
48 | /// Gets or sets the option to suppress keeping special rows. | ||
49 | /// </summary> | ||
50 | /// <value>The option to suppress keeping special rows.</value> | ||
51 | private bool SuppressKeepingSpecialRows { get; } | 43 | private bool SuppressKeepingSpecialRows { get; } |
52 | 44 | ||
53 | /// <summary> | ||
54 | /// Gets or sets the flag to determine if all rows, even unchanged ones will be persisted in the output. | ||
55 | /// </summary> | ||
56 | /// <value>The option to keep all rows including unchanged rows.</value> | ||
57 | private bool PreserveUnchangedRows { get; } | 45 | private bool PreserveUnchangedRows { get; } |
58 | 46 | ||
59 | public WindowsInstallerData Transform { get; private set; } | 47 | public WindowsInstallerData Transform { get; private set; } |
@@ -124,7 +112,7 @@ namespace WixToolset.Core.WindowsInstaller | |||
124 | foreach (var updatedRow in updatedTable.Rows) | 112 | foreach (var updatedRow in updatedTable.Rows) |
125 | { | 113 | { |
126 | updatedRow.Operation = RowOperation.Add; | 114 | updatedRow.Operation = RowOperation.Add; |
127 | updatedRow.SectionId = sectionDelimiter + updatedRow.SectionId; | 115 | updatedRow.SectionId = SectionDelimiter + updatedRow.SectionId; |
128 | addedTable.Rows.Add(updatedRow); | 116 | addedTable.Rows.Add(updatedRow); |
129 | } | 117 | } |
130 | } | 118 | } |
@@ -152,27 +140,8 @@ namespace WixToolset.Core.WindowsInstaller | |||
152 | 140 | ||
153 | if (null != primaryKey) | 141 | if (null != primaryKey) |
154 | { | 142 | { |
155 | if (index.TryGetValue(primaryKey, out var collisionRow)) | 143 | if (index.ContainsKey(primaryKey)) |
156 | { | 144 | { |
157 | #if TODO_PATCH // This case doesn't seem like it can happen any longer. | ||
158 | // Overriding WixActionRows have a primary key defined and take precedence in the index. | ||
159 | if (row is WixActionRow actionRow) | ||
160 | { | ||
161 | // If the current row is not overridable, see if the indexed row is. | ||
162 | if (!actionRow.Overridable) | ||
163 | { | ||
164 | if (collisionRow is WixActionRow indexedRow && indexedRow.Overridable) | ||
165 | { | ||
166 | // The indexed key is overridable and should be replaced. | ||
167 | index[primaryKey] = actionRow; | ||
168 | } | ||
169 | } | ||
170 | |||
171 | // If we got this far, the row does not need to be indexed. | ||
172 | return; | ||
173 | } | ||
174 | #endif | ||
175 | |||
176 | if (this.ShowPedanticMessages) | 145 | if (this.ShowPedanticMessages) |
177 | { | 146 | { |
178 | this.messaging.Write(ErrorMessages.DuplicatePrimaryKey(row.SourceLineNumbers, primaryKey, row.Table.Name)); | 147 | this.messaging.Write(ErrorMessages.DuplicatePrimaryKey(row.SourceLineNumbers, primaryKey, row.Table.Name)); |
@@ -208,7 +177,7 @@ namespace WixToolset.Core.WindowsInstaller | |||
208 | else if (null == updatedRow) | 177 | else if (null == updatedRow) |
209 | { | 178 | { |
210 | targetRow.Operation = RowOperation.Delete; | 179 | targetRow.Operation = RowOperation.Delete; |
211 | targetRow.SectionId += sectionDelimiter; | 180 | targetRow.SectionId += SectionDelimiter; |
212 | 181 | ||
213 | comparedRow = targetRow; | 182 | comparedRow = targetRow; |
214 | keepRow = true; | 183 | keepRow = true; |
@@ -219,10 +188,10 @@ namespace WixToolset.Core.WindowsInstaller | |||
219 | updatedRow.Operation = RowOperation.None; | 188 | updatedRow.Operation = RowOperation.None; |
220 | if (!this.SuppressKeepingSpecialRows && "_SummaryInformation" == targetTable.Name) | 189 | if (!this.SuppressKeepingSpecialRows && "_SummaryInformation" == targetTable.Name) |
221 | { | 190 | { |
222 | // ignore rows that shouldn't be in a transform | 191 | // Include only summary information rows that are allowed in a transform. |
223 | if (Enum.IsDefined(typeof(SummaryInformation.Transform), (int)updatedRow[0])) | 192 | if (Enum.IsDefined(typeof(SummaryInformation.Transform), (int)updatedRow[0])) |
224 | { | 193 | { |
225 | updatedRow.SectionId = targetRow.SectionId + sectionDelimiter + updatedRow.SectionId; | 194 | updatedRow.SectionId = targetRow.SectionId + SectionDelimiter + updatedRow.SectionId; |
226 | comparedRow = updatedRow; | 195 | comparedRow = updatedRow; |
227 | keepRow = true; | 196 | keepRow = true; |
228 | } | 197 | } |
@@ -273,14 +242,14 @@ namespace WixToolset.Core.WindowsInstaller | |||
273 | updatedObjectField.PreviousEmbeddedFileIndex = targetObjectField.EmbeddedFileIndex; | 242 | updatedObjectField.PreviousEmbeddedFileIndex = targetObjectField.EmbeddedFileIndex; |
274 | updatedObjectField.PreviousBaseUri = targetObjectField.BaseUri; | 243 | updatedObjectField.PreviousBaseUri = targetObjectField.BaseUri; |
275 | 244 | ||
276 | // always keep a copy of the previous data even if they are identical | 245 | // Always keep a copy of the previous data even if they are identical. |
277 | // This makes diff.wixmst clean and easier to control patch logic | 246 | // This makes diff data clean and easier to control in patch logic. |
278 | updatedObjectField.PreviousData = (string)targetObjectField.Data; | 247 | updatedObjectField.PreviousData = (string)targetObjectField.Data; |
279 | 248 | ||
280 | // always remember the unresolved data for target build | 249 | // Always remember the unresolved data for target build. |
281 | updatedObjectField.UnresolvedPreviousData = targetObjectField.UnresolvedData; | 250 | updatedObjectField.UnresolvedPreviousData = targetObjectField.UnresolvedData; |
282 | 251 | ||
283 | // keep rows containing object fields so the files can be compared in the binder | 252 | // Keep rows containing object fields so the files can be compared later. |
284 | keepRow = !this.SuppressKeepingSpecialRows; | 253 | keepRow = !this.SuppressKeepingSpecialRows; |
285 | } | 254 | } |
286 | else | 255 | else |
@@ -305,7 +274,7 @@ namespace WixToolset.Core.WindowsInstaller | |||
305 | if (keepRow) | 274 | if (keepRow) |
306 | { | 275 | { |
307 | comparedRow = updatedRow; | 276 | comparedRow = updatedRow; |
308 | comparedRow.SectionId = targetRow.SectionId + sectionDelimiter + updatedRow.SectionId; | 277 | comparedRow.SectionId = targetRow.SectionId + SectionDelimiter + updatedRow.SectionId; |
309 | } | 278 | } |
310 | } | 279 | } |
311 | } | 280 | } |
@@ -333,9 +302,6 @@ namespace WixToolset.Core.WindowsInstaller | |||
333 | } | 302 | } |
334 | else // possibly modified table. | 303 | else // possibly modified table. |
335 | { | 304 | { |
336 | var updatedPrimaryKeys = new Dictionary<string, Row>(); | ||
337 | var targetPrimaryKeys = new Dictionary<string, Row>(); | ||
338 | |||
339 | // compare the table definitions | 305 | // compare the table definitions |
340 | if (0 != targetTable.Definition.CompareTo(updatedTable.Definition)) | 306 | if (0 != targetTable.Definition.CompareTo(updatedTable.Definition)) |
341 | { | 307 | { |
@@ -344,6 +310,9 @@ namespace WixToolset.Core.WindowsInstaller | |||
344 | } | 310 | } |
345 | else | 311 | else |
346 | { | 312 | { |
313 | var updatedPrimaryKeys = new Dictionary<string, Row>(); | ||
314 | var targetPrimaryKeys = new Dictionary<string, Row>(); | ||
315 | |||
347 | this.IndexPrimaryKeys(targetTable, targetPrimaryKeys, updatedTable, updatedPrimaryKeys); | 316 | this.IndexPrimaryKeys(targetTable, targetPrimaryKeys, updatedTable, updatedPrimaryKeys); |
348 | 317 | ||
349 | // diff the target and updated rows | 318 | // diff the target and updated rows |
@@ -371,7 +340,7 @@ namespace WixToolset.Core.WindowsInstaller | |||
371 | var updatedRow = updatedPrimaryKeyEntry.Value; | 340 | var updatedRow = updatedPrimaryKeyEntry.Value; |
372 | 341 | ||
373 | updatedRow.Operation = RowOperation.Add; | 342 | updatedRow.Operation = RowOperation.Add; |
374 | updatedRow.SectionId = sectionDelimiter + updatedRow.SectionId; | 343 | updatedRow.SectionId = SectionDelimiter + updatedRow.SectionId; |
375 | rows.Add(updatedRow); | 344 | rows.Add(updatedRow); |
376 | } | 345 | } |
377 | } | 346 | } |
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Bind/GetFileFacadesCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Bind/GetFileFacadesCommand.cs index 949d5e18..fa072293 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Bind/GetFileFacadesCommand.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Bind/GetFileFacadesCommand.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; |
@@ -29,20 +27,17 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
29 | { | 27 | { |
30 | var facades = new List<IFileFacade>(); | 28 | var facades = new List<IFileFacade>(); |
31 | 29 | ||
32 | var assemblyFile = this.Section.Symbols.OfType<AssemblySymbol>().ToDictionary(t => t.Id.Id); | ||
33 | #if TODO_PATCHING_DELTA | 30 | #if TODO_PATCHING_DELTA |
34 | //var deltaPatchFiles = this.Section.Symbols.OfType<WixDeltaPatchFileSymbol>().ToDictionary(t => t.Id.Id); | 31 | //var deltaPatchFiles = this.Section.Symbols.OfType<WixDeltaPatchFileSymbol>().ToDictionary(t => t.Id.Id); |
35 | #endif | 32 | #endif |
36 | 33 | ||
37 | foreach (var file in this.Section.Symbols.OfType<FileSymbol>()) | 34 | foreach (var file in this.Section.Symbols.OfType<FileSymbol>()) |
38 | { | 35 | { |
39 | assemblyFile.TryGetValue(file.Id.Id, out var assembly); | ||
40 | |||
41 | #if TODO_PATCHING_DELTA | 36 | #if TODO_PATCHING_DELTA |
42 | //deltaPatchFiles.TryGetValue(file.Id.Id, out var deltaPatchFile); | 37 | //deltaPatchFiles.TryGetValue(file.Id.Id, out var deltaPatchFile); |
43 | // TODO: should we be passing along delta information to the file facade? Probably, right? | 38 | // TODO: should we be passing along delta information to the file facade? Probably, right? |
44 | #endif | 39 | #endif |
45 | var fileFacade = this.BackendHelper.CreateFileFacade(file, assembly); | 40 | var fileFacade = this.BackendHelper.CreateFileFacade(file); |
46 | 41 | ||
47 | facades.Add(fileFacade); | 42 | facades.Add(fileFacade); |
48 | } | 43 | } |
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Bind/GetFileFacadesFromTransforms.cs b/src/wix/WixToolset.Core.WindowsInstaller/Bind/GetFileFacadesFromTransforms.cs index 441038ec..7c71e238 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Bind/GetFileFacadesFromTransforms.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Bind/GetFileFacadesFromTransforms.cs | |||
@@ -37,8 +37,6 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
37 | 37 | ||
38 | var patchMediaFileRows = new Dictionary<int, RowDictionary<FileRow>>(); | 38 | var patchMediaFileRows = new Dictionary<int, RowDictionary<FileRow>>(); |
39 | 39 | ||
40 | //var patchActualFileTable = this.Output.EnsureTable(this.TableDefinitions["File"]); | ||
41 | |||
42 | // Index paired transforms by name without their "#" prefix. | 40 | // Index paired transforms by name without their "#" prefix. |
43 | var pairedTransforms = this.SubStorages.Where(s => s.Name.StartsWith(PatchConstants.PairedPatchTransformPrefix)).ToDictionary(s => s.Name, s => s.Data); | 41 | var pairedTransforms = this.SubStorages.Where(s => s.Name.StartsWith(PatchConstants.PairedPatchTransformPrefix)).ToDictionary(s => s.Name, s => s.Data); |
44 | 42 | ||
@@ -57,7 +55,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
57 | var pairedTransform = pairedTransforms[PatchConstants.PairedPatchTransformPrefix + substorage.Name]; | 55 | var pairedTransform = pairedTransforms[PatchConstants.PairedPatchTransformPrefix + substorage.Name]; |
58 | var pairedFileRows = new RowDictionary<FileRow>(pairedTransform.Tables["File"]); | 56 | var pairedFileRows = new RowDictionary<FileRow>(pairedTransform.Tables["File"]); |
59 | 57 | ||
60 | foreach (FileRow mainFileRow in mainFileTable.Rows.Where(f => f.Operation != RowOperation.Delete)) | 58 | foreach (var mainFileRow in mainFileTable.Rows.Where(f => f.Operation != RowOperation.Delete).Cast<FileRow>()) |
61 | { | 59 | { |
62 | var mainFileId = mainFileRow.File; | 60 | var mainFileId = mainFileRow.File; |
63 | 61 | ||
@@ -89,8 +87,10 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
89 | } | 87 | } |
90 | else | 88 | else |
91 | { | 89 | { |
92 | // TODO: should this entire condition be placed in the binder file manager? | 90 | if ( |
93 | if (/*(0 == (PatchAttributeType.Ignore & mainWixFileRow.PatchAttributes)) &&*/ | 91 | #if TODO_PATCHING_DELTA |
92 | (0 == (PatchAttributeType.Ignore & mainWixFileRow.PatchAttributes)) && | ||
93 | #endif | ||
94 | !this.FileSystemManager.CompareFiles(objectField.PreviousData, objectField.Data.ToString())) | 94 | !this.FileSystemManager.CompareFiles(objectField.PreviousData, objectField.Data.ToString())) |
95 | { | 95 | { |
96 | // If the file is different, we need to mark the mainFileRow and pairedFileRow as modified. | 96 | // If the file is different, we need to mark the mainFileRow and pairedFileRow as modified. |
@@ -133,11 +133,8 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
133 | patchMediaFileRows.Add(diskId, mediaFileRows); | 133 | patchMediaFileRows.Add(diskId, mediaFileRows); |
134 | } | 134 | } |
135 | 135 | ||
136 | var patchFileRow = mediaFileRows.Get(mainFileId); | 136 | if (!mediaFileRows.TryGetValue(mainFileId, out var patchFileRow)) |
137 | |||
138 | if (null == patchFileRow) | ||
139 | { | 137 | { |
140 | //patchFileRow = (FileRow)patchFileTable.CreateRow(mainFileRow.SourceLineNumbers); | ||
141 | patchFileRow = (FileRow)mainFileRow.TableDefinition.CreateRow(mainFileRow.SourceLineNumbers); | 138 | patchFileRow = (FileRow)mainFileRow.TableDefinition.CreateRow(mainFileRow.SourceLineNumbers); |
142 | mainFileRow.CopyTo(patchFileRow); | 139 | mainFileRow.CopyTo(patchFileRow); |
143 | 140 | ||
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Bind/MergeModulesCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Bind/MergeModulesCommand.cs index 7e6a7de0..5f21f496 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Bind/MergeModulesCommand.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Bind/MergeModulesCommand.cs | |||
@@ -10,7 +10,6 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
10 | using System.Runtime.InteropServices; | 10 | using System.Runtime.InteropServices; |
11 | using System.Text; | 11 | using System.Text; |
12 | using System.Threading; | 12 | using System.Threading; |
13 | using WixToolset.Core.Native; | ||
14 | using WixToolset.Core.Native.Msi; | 13 | using WixToolset.Core.Native.Msi; |
15 | using WixToolset.Core.Native.Msm; | 14 | using WixToolset.Core.Native.Msm; |
16 | using WixToolset.Data; | 15 | using WixToolset.Data; |
@@ -24,11 +23,11 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
24 | /// </summary> | 23 | /// </summary> |
25 | internal class MergeModulesCommand | 24 | internal class MergeModulesCommand |
26 | { | 25 | { |
27 | public MergeModulesCommand(IMessaging messaging, IBackendHelper backendHelper, IEnumerable<IFileFacade> fileFacades, IntermediateSection section, IEnumerable<string> suppressedTableNames, string outputPath, string intermediateFolder) | 26 | public MergeModulesCommand(IMessaging messaging, IBackendHelper backendHelper, IEnumerable<IFileFacade> fileFacadesFromModule, IntermediateSection section, IEnumerable<string> suppressedTableNames, string outputPath, string intermediateFolder) |
28 | { | 27 | { |
29 | this.Messaging = messaging; | 28 | this.Messaging = messaging; |
30 | this.BackendHelper = backendHelper; | 29 | this.BackendHelper = backendHelper; |
31 | this.FileFacades = fileFacades; | 30 | this.FileFacadesFromModule = fileFacadesFromModule; |
32 | this.Section = section; | 31 | this.Section = section; |
33 | this.SuppressedTableNames = suppressedTableNames ?? Array.Empty<string>(); | 32 | this.SuppressedTableNames = suppressedTableNames ?? Array.Empty<string>(); |
34 | this.OutputPath = outputPath; | 33 | this.OutputPath = outputPath; |
@@ -39,7 +38,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
39 | 38 | ||
40 | private IBackendHelper BackendHelper { get; } | 39 | private IBackendHelper BackendHelper { get; } |
41 | 40 | ||
42 | private IEnumerable<IFileFacade> FileFacades { get; } | 41 | private IEnumerable<IFileFacade> FileFacadesFromModule { get; } |
43 | 42 | ||
44 | private IntermediateSection Section { get; } | 43 | private IntermediateSection Section { get; } |
45 | 44 | ||
@@ -280,13 +279,8 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
280 | this.Messaging.Write(VerboseMessages.ResequencingMergeModuleFiles()); | 279 | this.Messaging.Write(VerboseMessages.ResequencingMergeModuleFiles()); |
281 | using (var view = db.OpenView("SELECT `Sequence`, `Attributes` FROM `File` WHERE `File`=?")) | 280 | using (var view = db.OpenView("SELECT `Sequence`, `Attributes` FROM `File` WHERE `File`=?")) |
282 | { | 281 | { |
283 | foreach (var file in this.FileFacades) | 282 | foreach (var file in this.FileFacadesFromModule) |
284 | { | 283 | { |
285 | if (!file.FromModule) | ||
286 | { | ||
287 | continue; | ||
288 | } | ||
289 | |||
290 | using (var record = new Record(1)) | 284 | using (var record = new Record(1)) |
291 | { | 285 | { |
292 | record.SetString(1, file.Id); | 286 | record.SetString(1, file.Id); |
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Bind/ProcessPropertiesCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Bind/ProcessPropertiesCommand.cs index 217609be..1f09a267 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Bind/ProcessPropertiesCommand.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Bind/ProcessPropertiesCommand.cs | |||
@@ -47,28 +47,6 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
47 | if ("ProductCode" == propertySymbol.Id.Id && "*".Equals(propertySymbol.Value, StringComparison.Ordinal)) | 47 | if ("ProductCode" == propertySymbol.Id.Id && "*".Equals(propertySymbol.Value, StringComparison.Ordinal)) |
48 | { | 48 | { |
49 | propertySymbol.Value = this.BackendHelper.CreateGuid(); | 49 | propertySymbol.Value = this.BackendHelper.CreateGuid(); |
50 | |||
51 | #if TODO_PATCHING // Is this still necessary? | ||
52 | // Update the target ProductCode in any instance transforms. | ||
53 | foreach (SubStorage subStorage in this.Output.SubStorages) | ||
54 | { | ||
55 | Output subStorageOutput = subStorage.Data; | ||
56 | if (OutputType.Transform != subStorageOutput.Type) | ||
57 | { | ||
58 | continue; | ||
59 | } | ||
60 | |||
61 | Table instanceSummaryInformationTable = subStorageOutput.Tables["_SummaryInformation"]; | ||
62 | foreach (Row row in instanceSummaryInformationTable.Rows) | ||
63 | { | ||
64 | if ((int)SummaryInformation.Transform.ProductCodes == row.FieldAsInteger(0)) | ||
65 | { | ||
66 | row[1] = row.FieldAsString(1).Replace("*", propertyRow.Value); | ||
67 | break; | ||
68 | } | ||
69 | } | ||
70 | } | ||
71 | #endif | ||
72 | } | 50 | } |
73 | else if ("ProductLanguage" == propertySymbol.Id.Id) | 51 | else if ("ProductLanguage" == propertySymbol.Id.Id) |
74 | { | 52 | { |
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs index 8043ffa8..f2f8e126 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs | |||
@@ -19,11 +19,11 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
19 | /// </summary> | 19 | /// </summary> |
20 | internal class UpdateFileFacadesCommand | 20 | internal class UpdateFileFacadesCommand |
21 | { | 21 | { |
22 | public UpdateFileFacadesCommand(IMessaging messaging, IntermediateSection section, IEnumerable<IFileFacade> fileFacades, IEnumerable<IFileFacade> updateFileFacades, IDictionary<string, string> variableCache, bool overwriteHash) | 22 | public UpdateFileFacadesCommand(IMessaging messaging, IntermediateSection section, IEnumerable<IFileFacade> allFileFacades, IEnumerable<IFileFacade> updateFileFacades, IDictionary<string, string> variableCache, bool overwriteHash) |
23 | { | 23 | { |
24 | this.Messaging = messaging; | 24 | this.Messaging = messaging; |
25 | this.Section = section; | 25 | this.Section = section; |
26 | this.FileFacades = fileFacades; | 26 | this.AllFileFacades = allFileFacades; |
27 | this.UpdateFileFacades = updateFileFacades; | 27 | this.UpdateFileFacades = updateFileFacades; |
28 | this.VariableCache = variableCache; | 28 | this.VariableCache = variableCache; |
29 | this.OverwriteHash = overwriteHash; | 29 | this.OverwriteHash = overwriteHash; |
@@ -33,7 +33,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
33 | 33 | ||
34 | private IntermediateSection Section { get; } | 34 | private IntermediateSection Section { get; } |
35 | 35 | ||
36 | private IEnumerable<IFileFacade> FileFacades { get; } | 36 | private IEnumerable<IFileFacade> AllFileFacades { get; } |
37 | 37 | ||
38 | private IEnumerable<IFileFacade> UpdateFileFacades { get; } | 38 | private IEnumerable<IFileFacade> UpdateFileFacades { get; } |
39 | 39 | ||
@@ -43,15 +43,16 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
43 | 43 | ||
44 | public void Execute() | 44 | public void Execute() |
45 | { | 45 | { |
46 | var assemblySymbols = this.Section.Symbols.OfType<AssemblySymbol>().ToDictionary(t => t.Id.Id); | ||
46 | var assemblyNameSymbols = this.Section.Symbols.OfType<MsiAssemblyNameSymbol>().ToDictionary(t => t.Id.Id); | 47 | var assemblyNameSymbols = this.Section.Symbols.OfType<MsiAssemblyNameSymbol>().ToDictionary(t => t.Id.Id); |
47 | 48 | ||
48 | foreach (var file in this.UpdateFileFacades.Where(f => f.SourcePath != null)) | 49 | foreach (var file in this.UpdateFileFacades.Where(f => f.SourcePath != null)) |
49 | { | 50 | { |
50 | this.UpdateFileFacade(file, assemblyNameSymbols); | 51 | this.UpdateFileFacade(file, assemblySymbols, assemblyNameSymbols); |
51 | } | 52 | } |
52 | } | 53 | } |
53 | 54 | ||
54 | private void UpdateFileFacade(IFileFacade facade, Dictionary<string, MsiAssemblyNameSymbol> assemblyNameSymbols) | 55 | private void UpdateFileFacade(IFileFacade facade, Dictionary<string, AssemblySymbol> assemblySymbols, Dictionary<string, MsiAssemblyNameSymbol> assemblyNameSymbols) |
55 | { | 56 | { |
56 | FileInfo fileInfo = null; | 57 | FileInfo fileInfo = null; |
57 | try | 58 | try |
@@ -124,7 +125,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
124 | // | 125 | // |
125 | // Also, if we do not find a matching file identifier then the user provided a default version and is providing a version | 126 | // Also, if we do not find a matching file identifier then the user provided a default version and is providing a version |
126 | // for unversioned file. That's allowed but generally a dangerous thing to do so let's point that out to the user. | 127 | // for unversioned file. That's allowed but generally a dangerous thing to do so let's point that out to the user. |
127 | if (!this.FileFacades.Any(r => facade.Version.Equals(r.Id, StringComparison.Ordinal))) | 128 | if (!this.AllFileFacades.Any(r => facade.Version.Equals(r.Id, StringComparison.Ordinal))) |
128 | { | 129 | { |
129 | this.Messaging.Write(WarningMessages.DefaultVersionUsedForUnversionedFile(facade.SourceLineNumber, facade.Version, facade.Id)); | 130 | this.Messaging.Write(WarningMessages.DefaultVersionUsedForUnversionedFile(facade.SourceLineNumber, facade.Version, facade.Id)); |
130 | } | 131 | } |
@@ -153,16 +154,15 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
153 | } | 154 | } |
154 | } | 155 | } |
155 | 156 | ||
156 | if (null == facade.Hash) | 157 | // Remember the hash symbol for use later. |
158 | facade.MsiFileHashSymbol = new MsiFileHashSymbol(facade.SourceLineNumber, facade.Identifier) | ||
157 | { | 159 | { |
158 | facade.Hash = this.Section.AddSymbol(new MsiFileHashSymbol(facade.SourceLineNumber, facade.Identifier)); | 160 | Options = 0, |
159 | } | 161 | HashPart1 = hash[0], |
160 | 162 | HashPart2 = hash[1], | |
161 | facade.Hash.Options = 0; | 163 | HashPart3 = hash[2], |
162 | facade.Hash.HashPart1 = hash[0]; | 164 | HashPart4 = hash[3], |
163 | facade.Hash.HashPart2 = hash[1]; | 165 | }; |
164 | facade.Hash.HashPart3 = hash[2]; | ||
165 | facade.Hash.HashPart4 = hash[3]; | ||
166 | } | 166 | } |
167 | } | 167 | } |
168 | else // update the file row with the version and language information. | 168 | else // update the file row with the version and language information. |
@@ -173,7 +173,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
173 | { | 173 | { |
174 | facade.Version = version; | 174 | facade.Version = version; |
175 | } | 175 | } |
176 | else if (!this.FileFacades.Any(r => facade.Version.Equals(r.Id, StringComparison.Ordinal))) // this looks expensive, but see explanation below. | 176 | else if (!this.AllFileFacades.Any(r => facade.Version.Equals(r.Id, StringComparison.Ordinal))) // this looks expensive, but see explanation below. |
177 | { | 177 | { |
178 | // The user provided a default version for the file row so we looked for a companion file (a file row with Id matching | 178 | // The user provided a default version for the file row so we looked for a companion file (a file row with Id matching |
179 | // the version value). We didn't find it so, we will override the default version they provided with the actual | 179 | // the version value). We didn't find it so, we will override the default version they provided with the actual |
@@ -204,108 +204,104 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
204 | this.VariableCache[$"filelanguage.{facade.Id}"] = facade.Language ?? String.Empty; | 204 | this.VariableCache[$"filelanguage.{facade.Id}"] = facade.Language ?? String.Empty; |
205 | } | 205 | } |
206 | 206 | ||
207 | // If this is a CLR assembly, load the assembly and get the assembly name information | 207 | // If there is an assembly for this file. |
208 | if (AssemblyType.DotNetAssembly == facade.AssemblyType) | 208 | if (assemblySymbols.TryGetValue(facade.Id, out var assemblySymbol)) |
209 | { | 209 | { |
210 | try | 210 | // If this is a CLR assembly, load the assembly and get the assembly name information |
211 | if (AssemblyType.DotNetAssembly == assemblySymbol.Type) | ||
211 | { | 212 | { |
212 | var assemblyName = AssemblyNameReader.ReadAssembly(facade.SourceLineNumber, fileInfo.FullName, version); | 213 | try |
214 | { | ||
215 | var assemblyName = AssemblyNameReader.ReadAssembly(facade.SourceLineNumber, fileInfo.FullName, version); | ||
213 | 216 | ||
214 | this.SetMsiAssemblyName(assemblyNameSymbols, facade, "name", assemblyName.Name); | 217 | this.SetMsiAssemblyName(assemblyNameSymbols, facade, assemblySymbol, "name", assemblyName.Name); |
215 | this.SetMsiAssemblyName(assemblyNameSymbols, facade, "culture", assemblyName.Culture); | 218 | this.SetMsiAssemblyName(assemblyNameSymbols, facade, assemblySymbol, "culture", assemblyName.Culture); |
216 | this.SetMsiAssemblyName(assemblyNameSymbols, facade, "version", assemblyName.Version); | 219 | this.SetMsiAssemblyName(assemblyNameSymbols, facade, assemblySymbol, "version", assemblyName.Version); |
217 | 220 | ||
218 | if (!String.IsNullOrEmpty(assemblyName.Architecture)) | 221 | if (!String.IsNullOrEmpty(assemblyName.Architecture)) |
219 | { | 222 | { |
220 | this.SetMsiAssemblyName(assemblyNameSymbols, facade, "processorArchitecture", assemblyName.Architecture); | 223 | this.SetMsiAssemblyName(assemblyNameSymbols, facade, assemblySymbol, "processorArchitecture", assemblyName.Architecture); |
221 | } | 224 | } |
222 | // TODO: WiX v3 seemed to do this but not clear it should actually be done. | 225 | // TODO: WiX v3 seemed to do this but not clear it should actually be done. |
223 | //else if (!String.IsNullOrEmpty(file.WixFile.ProcessorArchitecture)) | 226 | //else if (!String.IsNullOrEmpty(file.WixFile.ProcessorArchitecture)) |
224 | //{ | 227 | //{ |
225 | // this.SetMsiAssemblyName(assemblyNameSymbols, file, "processorArchitecture", file.WixFile.ProcessorArchitecture); | 228 | // this.SetMsiAssemblyName(assemblyNameSymbols, file, "processorArchitecture", file.WixFile.ProcessorArchitecture); |
226 | //} | 229 | //} |
227 | 230 | ||
228 | if (assemblyName.StrongNamedSigned) | 231 | if (assemblyName.StrongNamedSigned) |
229 | { | 232 | { |
230 | this.SetMsiAssemblyName(assemblyNameSymbols, facade, "publicKeyToken", assemblyName.PublicKeyToken); | 233 | this.SetMsiAssemblyName(assemblyNameSymbols, facade, assemblySymbol, "publicKeyToken", assemblyName.PublicKeyToken); |
231 | } | 234 | } |
232 | else if (facade.AssemblyApplicationFileRef == null) | 235 | else if (assemblySymbol.ApplicationFileRef == null) |
233 | { | 236 | { |
234 | throw new WixException(ErrorMessages.GacAssemblyNoStrongName(facade.SourceLineNumber, fileInfo.FullName, facade.ComponentRef)); | 237 | throw new WixException(ErrorMessages.GacAssemblyNoStrongName(facade.SourceLineNumber, fileInfo.FullName, facade.ComponentRef)); |
235 | } | 238 | } |
236 | 239 | ||
237 | if (!String.IsNullOrEmpty(assemblyName.FileVersion)) | 240 | if (!String.IsNullOrEmpty(assemblyName.FileVersion)) |
238 | { | 241 | { |
239 | this.SetMsiAssemblyName(assemblyNameSymbols, facade, "fileVersion", assemblyName.FileVersion); | 242 | this.SetMsiAssemblyName(assemblyNameSymbols, facade, assemblySymbol, "fileVersion", assemblyName.FileVersion); |
240 | } | 243 | } |
241 | 244 | ||
242 | // add the assembly name to the information cache | 245 | // add the assembly name to the information cache |
243 | if (null != this.VariableCache) | 246 | if (null != this.VariableCache) |
247 | { | ||
248 | this.VariableCache[$"assemblyfullname.{facade.Id}"] = assemblyName.GetFullName(); | ||
249 | } | ||
250 | } | ||
251 | catch (WixException e) | ||
244 | { | 252 | { |
245 | this.VariableCache[$"assemblyfullname.{facade.Id}"] = assemblyName.GetFullName(); | 253 | this.Messaging.Write(e.Error); |
246 | } | 254 | } |
247 | } | 255 | } |
248 | catch (WixException e) | 256 | else if (AssemblyType.Win32Assembly == assemblySymbol.Type) |
249 | { | ||
250 | this.Messaging.Write(e.Error); | ||
251 | } | ||
252 | } | ||
253 | else if (AssemblyType.Win32Assembly == facade.AssemblyType) | ||
254 | { | ||
255 | // TODO: Consider passing in the this.FileFacades as an indexed collection instead of searching through | ||
256 | // all files like this. Even though this is a rare case it looks like we might be able to index the | ||
257 | // file earlier. | ||
258 | var fileManifest = this.FileFacades.FirstOrDefault(r => r.Id.Equals(facade.AssemblyManifestFileRef, StringComparison.Ordinal)); | ||
259 | if (null == fileManifest) | ||
260 | { | ||
261 | this.Messaging.Write(ErrorMessages.MissingManifestForWin32Assembly(facade.SourceLineNumber, facade.Id, facade.AssemblyManifestFileRef)); | ||
262 | } | ||
263 | |||
264 | try | ||
265 | { | 257 | { |
266 | var assemblyName = AssemblyNameReader.ReadAssemblyManifest(facade.SourceLineNumber, fileManifest.SourcePath); | 258 | // TODO: Consider passing in the this.AllFileFacades as an indexed collection instead of searching through |
267 | 259 | // all files like this. Even though this is a rare case it looks like we might be able to index the | |
268 | if (!String.IsNullOrEmpty(assemblyName.Name)) | 260 | // file earlier. |
261 | var fileManifest = this.AllFileFacades.FirstOrDefault(r => r.Id.Equals(assemblySymbol.ManifestFileRef, StringComparison.Ordinal)); | ||
262 | if (null == fileManifest) | ||
269 | { | 263 | { |
270 | this.SetMsiAssemblyName(assemblyNameSymbols, facade, "name", assemblyName.Name); | 264 | this.Messaging.Write(ErrorMessages.MissingManifestForWin32Assembly(facade.SourceLineNumber, facade.Id, assemblySymbol.ManifestFileRef)); |
271 | } | 265 | } |
272 | 266 | ||
273 | if (!String.IsNullOrEmpty(assemblyName.Version)) | 267 | try |
274 | { | 268 | { |
275 | this.SetMsiAssemblyName(assemblyNameSymbols, facade, "version", assemblyName.Version); | 269 | var assemblyName = AssemblyNameReader.ReadAssemblyManifest(facade.SourceLineNumber, fileManifest.SourcePath); |
276 | } | ||
277 | 270 | ||
278 | if (!String.IsNullOrEmpty(assemblyName.Type)) | 271 | if (!String.IsNullOrEmpty(assemblyName.Name)) |
279 | { | 272 | { |
280 | this.SetMsiAssemblyName(assemblyNameSymbols, facade, "type", assemblyName.Type); | 273 | this.SetMsiAssemblyName(assemblyNameSymbols, facade, assemblySymbol, "name", assemblyName.Name); |
281 | } | 274 | } |
282 | 275 | ||
283 | if (!String.IsNullOrEmpty(assemblyName.Architecture)) | 276 | if (!String.IsNullOrEmpty(assemblyName.Version)) |
284 | { | 277 | { |
285 | this.SetMsiAssemblyName(assemblyNameSymbols, facade, "processorArchitecture", assemblyName.Architecture); | 278 | this.SetMsiAssemblyName(assemblyNameSymbols, facade, assemblySymbol, "version", assemblyName.Version); |
286 | } | 279 | } |
280 | |||
281 | if (!String.IsNullOrEmpty(assemblyName.Type)) | ||
282 | { | ||
283 | this.SetMsiAssemblyName(assemblyNameSymbols, facade, assemblySymbol, "type", assemblyName.Type); | ||
284 | } | ||
285 | |||
286 | if (!String.IsNullOrEmpty(assemblyName.Architecture)) | ||
287 | { | ||
288 | this.SetMsiAssemblyName(assemblyNameSymbols, facade, assemblySymbol, "processorArchitecture", assemblyName.Architecture); | ||
289 | } | ||
287 | 290 | ||
288 | if (!String.IsNullOrEmpty(assemblyName.PublicKeyToken)) | 291 | if (!String.IsNullOrEmpty(assemblyName.PublicKeyToken)) |
292 | { | ||
293 | this.SetMsiAssemblyName(assemblyNameSymbols, facade, assemblySymbol, "publicKeyToken", assemblyName.PublicKeyToken); | ||
294 | } | ||
295 | } | ||
296 | catch (WixException e) | ||
289 | { | 297 | { |
290 | this.SetMsiAssemblyName(assemblyNameSymbols, facade, "publicKeyToken", assemblyName.PublicKeyToken); | 298 | this.Messaging.Write(e.Error); |
291 | } | 299 | } |
292 | } | 300 | } |
293 | catch (WixException e) | ||
294 | { | ||
295 | this.Messaging.Write(e.Error); | ||
296 | } | ||
297 | } | 301 | } |
298 | } | 302 | } |
299 | 303 | ||
300 | /// <summary> | 304 | private void SetMsiAssemblyName(Dictionary<string, MsiAssemblyNameSymbol> assemblyNameSymbols, IFileFacade facade, AssemblySymbol assemblySymbol, string name, string value) |
301 | /// Set an MsiAssemblyName row. If it was directly authored, override the value, otherwise | ||
302 | /// create a new row. | ||
303 | /// </summary> | ||
304 | /// <param name="assemblyNameSymbols">MsiAssemblyName table.</param> | ||
305 | /// <param name="facade">FileFacade containing the assembly read for the MsiAssemblyName row.</param> | ||
306 | /// <param name="name">MsiAssemblyName name.</param> | ||
307 | /// <param name="value">MsiAssemblyName value.</param> | ||
308 | private void SetMsiAssemblyName(Dictionary<string, MsiAssemblyNameSymbol> assemblyNameSymbols, IFileFacade facade, string name, string value) | ||
309 | { | 305 | { |
310 | // check for null value (this can occur when grabbing the file version from an assembly without one) | 306 | // check for null value (this can occur when grabbing the file version from an assembly without one) |
311 | if (String.IsNullOrEmpty(value)) | 307 | if (String.IsNullOrEmpty(value)) |
@@ -315,36 +311,32 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
315 | else | 311 | else |
316 | { | 312 | { |
317 | // if the assembly will be GAC'd and the name in the file table doesn't match the name in the MsiAssemblyName table, error because the install will fail. | 313 | // if the assembly will be GAC'd and the name in the file table doesn't match the name in the MsiAssemblyName table, error because the install will fail. |
318 | if ("name" == name && AssemblyType.DotNetAssembly == facade.AssemblyType && | 314 | if ("name" == name && AssemblyType.DotNetAssembly == assemblySymbol.Type && |
319 | String.IsNullOrEmpty(facade.AssemblyApplicationFileRef) && | 315 | String.IsNullOrEmpty(assemblySymbol.ApplicationFileRef) && |
320 | !String.Equals(Path.GetFileNameWithoutExtension(facade.FileName), value, StringComparison.OrdinalIgnoreCase)) | 316 | !String.Equals(Path.GetFileNameWithoutExtension(facade.FileName), value, StringComparison.OrdinalIgnoreCase)) |
321 | { | 317 | { |
322 | this.Messaging.Write(ErrorMessages.GACAssemblyIdentityWarning(facade.SourceLineNumber, Path.GetFileNameWithoutExtension(facade.FileName), value)); | 318 | this.Messaging.Write(ErrorMessages.GACAssemblyIdentityWarning(facade.SourceLineNumber, Path.GetFileNameWithoutExtension(facade.FileName), value)); |
323 | } | 319 | } |
324 | 320 | ||
325 | // override directly authored value | 321 | // Override directly authored value, otherwise remember the gathered information on the facade for use later. |
326 | var lookup = String.Concat(facade.ComponentRef, "/", name); | 322 | var lookup = String.Concat(facade.ComponentRef, "/", name); |
327 | if (!assemblyNameSymbols.TryGetValue(lookup, out var assemblyNameSymbol)) | 323 | if (assemblyNameSymbols.TryGetValue(lookup, out var assemblyNameSymbol)) |
328 | { | 324 | { |
329 | assemblyNameSymbol = this.Section.AddSymbol(new MsiAssemblyNameSymbol(facade.SourceLineNumber, new Identifier(AccessModifier.Section, facade.ComponentRef, name)) | 325 | assemblyNameSymbol.Value = value; |
326 | } | ||
327 | else | ||
328 | { | ||
329 | assemblyNameSymbol = new MsiAssemblyNameSymbol(assemblySymbol.SourceLineNumbers, new Identifier(AccessModifier.Section, facade.ComponentRef, name)) | ||
330 | { | 330 | { |
331 | ComponentRef = facade.ComponentRef, | 331 | ComponentRef = facade.ComponentRef, |
332 | Name = name, | 332 | Name = name, |
333 | Value = value, | 333 | Value = value, |
334 | }); | 334 | }; |
335 | |||
336 | if (null == facade.AssemblyNames) | ||
337 | { | ||
338 | facade.AssemblyNames = new List<MsiAssemblyNameSymbol>(); | ||
339 | } | ||
340 | |||
341 | facade.AssemblyNames.Add(assemblyNameSymbol); | ||
342 | 335 | ||
336 | facade.AssemblyNameSymbols.Add(assemblyNameSymbol); | ||
343 | assemblyNameSymbols.Add(assemblyNameSymbol.Id.Id, assemblyNameSymbol); | 337 | assemblyNameSymbols.Add(assemblyNameSymbol.Id.Id, assemblyNameSymbol); |
344 | } | 338 | } |
345 | 339 | ||
346 | assemblyNameSymbol.Value = value; | ||
347 | |||
348 | if (this.VariableCache != null) | 340 | if (this.VariableCache != null) |
349 | { | 341 | { |
350 | var key = String.Format(CultureInfo.InvariantCulture, "assembly{0}.{1}", name, facade.Id).ToLowerInvariant(); | 342 | var key = String.Format(CultureInfo.InvariantCulture, "assembly{0}.{1}", name, facade.Id).ToLowerInvariant(); |
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Bind/UpdateSymbolsWithFileFacadesCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Bind/UpdateSymbolsWithFileFacadesCommand.cs new file mode 100644 index 00000000..4b332363 --- /dev/null +++ b/src/wix/WixToolset.Core.WindowsInstaller/Bind/UpdateSymbolsWithFileFacadesCommand.cs | |||
@@ -0,0 +1,73 @@ | |||
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.Bind | ||
4 | { | ||
5 | using System.Collections.Generic; | ||
6 | using System.Linq; | ||
7 | using WixToolset.Data; | ||
8 | using WixToolset.Data.Symbols; | ||
9 | using WixToolset.Extensibility.Data; | ||
10 | using WixToolset.Extensibility.Services; | ||
11 | |||
12 | internal class UpdateSymbolsWithFileFacadesCommand | ||
13 | { | ||
14 | private readonly IntermediateSection section; | ||
15 | private readonly List<IFileFacade> allFileFacades; | ||
16 | |||
17 | public UpdateSymbolsWithFileFacadesCommand(IntermediateSection section, List<IFileFacade> allFileFacades) | ||
18 | { | ||
19 | this.section = section; | ||
20 | this.allFileFacades = allFileFacades; | ||
21 | } | ||
22 | |||
23 | public void Execute() | ||
24 | { | ||
25 | var fileSymbolsById = this.section.Symbols.OfType<FileSymbol>().ToDictionary(f => f.Id.Id); | ||
26 | |||
27 | foreach (var facade in this.allFileFacades) | ||
28 | { | ||
29 | if (fileSymbolsById.TryGetValue(facade.Id, out var fileSymbol)) | ||
30 | { | ||
31 | // Only update the file symbol if the facade value changed | ||
32 | if (fileSymbol.DiskId != facade.DiskId) | ||
33 | { | ||
34 | fileSymbol.DiskId = facade.DiskId; | ||
35 | } | ||
36 | |||
37 | if (fileSymbol.FileSize != facade.FileSize) | ||
38 | { | ||
39 | fileSymbol.FileSize = facade.FileSize; | ||
40 | } | ||
41 | |||
42 | if (fileSymbol.Language != facade.Language) | ||
43 | { | ||
44 | fileSymbol.Language = facade.Language; | ||
45 | } | ||
46 | |||
47 | if (fileSymbol.Sequence != facade.Sequence) | ||
48 | { | ||
49 | fileSymbol.Sequence = facade.Sequence; | ||
50 | } | ||
51 | |||
52 | if (fileSymbol.Version != facade.Version) | ||
53 | { | ||
54 | fileSymbol.Version = facade.Version; | ||
55 | } | ||
56 | } | ||
57 | |||
58 | if (facade.MsiFileHashSymbol != null) | ||
59 | { | ||
60 | this.section.AddSymbol(facade.MsiFileHashSymbol); | ||
61 | } | ||
62 | |||
63 | if (facade.AssemblyNameSymbols != null) | ||
64 | { | ||
65 | foreach (var assemblyNameSymbol in facade.AssemblyNameSymbols) | ||
66 | { | ||
67 | this.section.AddSymbol(assemblyNameSymbol); | ||
68 | } | ||
69 | } | ||
70 | } | ||
71 | } | ||
72 | } | ||
73 | } | ||
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Bind/UpdateTransformsWithFileFacades.cs b/src/wix/WixToolset.Core.WindowsInstaller/Bind/UpdateTransformsWithFileFacades.cs index ed865450..7b6c21ef 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Bind/UpdateTransformsWithFileFacades.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Bind/UpdateTransformsWithFileFacades.cs | |||
@@ -4,6 +4,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
7 | using System.IO; | ||
7 | using System.Linq; | 8 | using System.Linq; |
8 | using WixToolset.Data; | 9 | using WixToolset.Data; |
9 | using WixToolset.Data.Symbols; | 10 | using WixToolset.Data.Symbols; |
@@ -14,10 +15,10 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
14 | 15 | ||
15 | internal class UpdateTransformsWithFileFacades | 16 | internal class UpdateTransformsWithFileFacades |
16 | { | 17 | { |
17 | public UpdateTransformsWithFileFacades(IMessaging messaging, WindowsInstallerData output, IEnumerable<SubStorage> subStorages, TableDefinitionCollection tableDefinitions, IEnumerable<IFileFacade> fileFacades) | 18 | public UpdateTransformsWithFileFacades(IMessaging messaging, IntermediateSection section, IEnumerable<SubStorage> subStorages, TableDefinitionCollection tableDefinitions, IEnumerable<IFileFacade> fileFacades) |
18 | { | 19 | { |
19 | this.Messaging = messaging; | 20 | this.Messaging = messaging; |
20 | this.Output = output; | 21 | this.Section = section; |
21 | this.SubStorages = subStorages; | 22 | this.SubStorages = subStorages; |
22 | this.TableDefinitions = tableDefinitions; | 23 | this.TableDefinitions = tableDefinitions; |
23 | this.FileFacades = fileFacades; | 24 | this.FileFacades = fileFacades; |
@@ -25,7 +26,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
25 | 26 | ||
26 | private IMessaging Messaging { get; } | 27 | private IMessaging Messaging { get; } |
27 | 28 | ||
28 | private WindowsInstallerData Output { get; } | 29 | private IntermediateSection Section { get; } |
29 | 30 | ||
30 | private IEnumerable<SubStorage> SubStorages { get; } | 31 | private IEnumerable<SubStorage> SubStorages { get; } |
31 | 32 | ||
@@ -35,190 +36,97 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
35 | 36 | ||
36 | public void Execute() | 37 | public void Execute() |
37 | { | 38 | { |
38 | var fileFacadesByDiskId = new Dictionary<int, Dictionary<string, IFileFacade>>(); | 39 | var fileFacadesByDiskId = this.IndexFileFacadesByDiskId(); |
39 | |||
40 | // Index patch file facades by diskId+fileId. | ||
41 | foreach (var facade in this.FileFacades) | ||
42 | { | ||
43 | if (!fileFacadesByDiskId.TryGetValue(facade.DiskId, out var mediaFacades)) | ||
44 | { | ||
45 | mediaFacades = new Dictionary<string, IFileFacade>(); | ||
46 | fileFacadesByDiskId.Add(facade.DiskId, mediaFacades); | ||
47 | } | ||
48 | |||
49 | mediaFacades.Add(facade.Id, facade); | ||
50 | } | ||
51 | 40 | ||
52 | var patchMediaRows = new RowDictionary<MediaRow>(this.Output.Tables["Media"]); | 41 | var mediaSymbolsByDiskId = this.Section.Symbols.OfType<MediaSymbol>().ToDictionary(m => m.DiskId); |
53 | 42 | ||
54 | // Index paired transforms by name without the "#" prefix. | 43 | // Index paired transforms by name without the "#" prefix. |
55 | var pairedTransforms = this.SubStorages.Where(s => s.Name.StartsWith(PatchConstants.PairedPatchTransformPrefix)).ToDictionary(s => s.Name, s => s.Data); | 44 | var pairedTransforms = this.SubStorages.Where(s => s.Name.StartsWith(PatchConstants.PairedPatchTransformPrefix)).ToDictionary(s => s.Name, s => s.Data); |
56 | 45 | ||
57 | // Copy File bind data into substorages | ||
58 | foreach (var substorage in this.SubStorages.Where(s => !s.Name.StartsWith(PatchConstants.PairedPatchTransformPrefix))) | 46 | foreach (var substorage in this.SubStorages.Where(s => !s.Name.StartsWith(PatchConstants.PairedPatchTransformPrefix))) |
59 | { | 47 | { |
60 | var mainTransform = substorage.Data; | 48 | var mainTransform = substorage.Data; |
61 | 49 | ||
62 | var mainMsiFileHashIndex = new RowDictionary<Row>(mainTransform.Tables["MsiFileHash"]); | ||
63 | |||
64 | var pairedTransform = pairedTransforms[PatchConstants.PairedPatchTransformPrefix + substorage.Name]; | 50 | var pairedTransform = pairedTransforms[PatchConstants.PairedPatchTransformPrefix + substorage.Name]; |
65 | 51 | ||
66 | // Copy Media.LastSequence. | 52 | // Update the Media.LastSequence in the paired transforms. |
67 | var pairedMediaTable = pairedTransform.Tables["Media"]; | 53 | foreach (var pairedMediaRow in pairedTransform.Tables["Media"].Rows.Cast<MediaRow>()) |
68 | foreach (MediaRow pairedMediaRow in pairedMediaTable.Rows) | ||
69 | { | 54 | { |
70 | var patchMediaRow = patchMediaRows.Get(pairedMediaRow.DiskId); | 55 | if (mediaSymbolsByDiskId.TryGetValue(pairedMediaRow.DiskId, out var mediaSymbol) && mediaSymbol.LastSequence.HasValue) |
71 | pairedMediaRow.LastSequence = patchMediaRow.LastSequence; | 56 | { |
57 | pairedMediaRow.LastSequence = mediaSymbol.LastSequence.Value; | ||
58 | } | ||
59 | else // TODO: This shouldn't be possible. | ||
60 | { | ||
61 | throw new InvalidDataException(); | ||
62 | } | ||
72 | } | 63 | } |
73 | 64 | ||
74 | // Validate file row changes for keypath-related issues | 65 | // Validate file row changes for keypath-related issues |
75 | this.ValidateFileRowChanges(mainTransform); | 66 | this.ValidateFileRowChanges(mainTransform); |
76 | 67 | ||
77 | // Index File table of pairedTransform | 68 | // Copy File bind data into transforms |
78 | var pairedFileRows = new RowDictionary<FileRow>(pairedTransform.Tables["File"]); | 69 | if (mainTransform.Tables.TryGetTable("File", out var mainFileTable)) |
79 | |||
80 | var mainFileTable = mainTransform.Tables["File"]; | ||
81 | if (null != mainFileTable) | ||
82 | { | 70 | { |
71 | // Index File table of pairedTransform | ||
72 | var pairedFileRows = new RowDictionary<FileRow>(pairedTransform.Tables["File"]); | ||
73 | |||
74 | var mainMsiFileHashIndex = new RowDictionary<Row>(mainTransform.Tables["MsiFileHash"]); | ||
75 | |||
83 | // Remove the MsiFileHash table because it will be updated later with the final file hash for each file | 76 | // Remove the MsiFileHash table because it will be updated later with the final file hash for each file |
84 | mainTransform.Tables.Remove("MsiFileHash"); | 77 | mainTransform.Tables.Remove("MsiFileHash"); |
85 | 78 | ||
86 | foreach (FileRow mainFileRow in mainFileTable.Rows) | 79 | foreach (var mainFileRow in mainFileTable.Rows.Where(r => r.Operation == RowOperation.Add || r.Operation == RowOperation.Modify).Cast<FileRow>()) |
87 | { | 80 | { |
88 | if (RowOperation.Delete == mainFileRow.Operation) | 81 | // TODO: Wasn't this indexing done at the top of this method? |
89 | { | 82 | // Index main transform files by diskId+fileId |
90 | continue; | ||
91 | } | ||
92 | else if (RowOperation.None == mainFileRow.Operation) | ||
93 | { | ||
94 | continue; | ||
95 | } | ||
96 | |||
97 | // Index patch files by diskId+fileId | ||
98 | if (!fileFacadesByDiskId.TryGetValue(mainFileRow.DiskId, out var mediaFacades)) | 83 | if (!fileFacadesByDiskId.TryGetValue(mainFileRow.DiskId, out var mediaFacades)) |
99 | { | 84 | { |
100 | mediaFacades = new Dictionary<string, IFileFacade>(); | 85 | mediaFacades = new Dictionary<string, IFileFacade>(); |
101 | fileFacadesByDiskId.Add(mainFileRow.DiskId, mediaFacades); | 86 | fileFacadesByDiskId.Add(mainFileRow.DiskId, mediaFacades); |
102 | } | 87 | } |
103 | 88 | ||
104 | // copy data from the patch back to the transform | 89 | // Copy data from the facade back to the appropriate transform. |
105 | if (mediaFacades.TryGetValue(mainFileRow.File, out var facade)) | 90 | if (mediaFacades.TryGetValue(mainFileRow.File, out var facade)) |
106 | { | 91 | { |
107 | var patchFileRow = facade.GetFileRow(); | ||
108 | var pairedFileRow = pairedFileRows.Get(mainFileRow.File); | 92 | var pairedFileRow = pairedFileRows.Get(mainFileRow.File); |
109 | 93 | ||
110 | for (var i = 0; i < patchFileRow.Fields.Length; i++) | 94 | TryModifyField(mainFileRow, 3, facade.FileSize); |
111 | { | 95 | |
112 | var patchValue = patchFileRow.FieldAsString(i) ?? String.Empty; | 96 | TryModifyField(mainFileRow, 4, facade.Version); |
113 | var mainValue = mainFileRow.FieldAsString(i) ?? String.Empty; | 97 | |
98 | TryModifyField(mainFileRow, 5, facade.Language); | ||
114 | 99 | ||
115 | if (1 == i) | ||
116 | { | ||
117 | // File.Component_ changes should not come from the shared file rows | ||
118 | // that contain the file information as each individual transform might | ||
119 | // have different changes (or no changes at all). | ||
120 | } | ||
121 | else if (6 == i) // File.Attributes should not changed for binary deltas | ||
122 | { | ||
123 | #if TODO_PATCHING_DELTA | ||
124 | if (null != patchFileRow.Patch) | ||
125 | { | ||
126 | // File.Attribute should not change for binary deltas | ||
127 | pairedFileRow.Attributes = mainFileRow.Attributes; | ||
128 | mainFileRow.Fields[i].Modified = false; | ||
129 | } | ||
130 | #endif | ||
131 | } | ||
132 | else if (7 == i) // File.Sequence is updated in pairedTransform, not mainTransform | ||
133 | { | ||
134 | // file sequence is updated in Patch table instead of File table for delta patches | ||
135 | #if TODO_PATCHING_DELTA | 100 | #if TODO_PATCHING_DELTA |
136 | if (null != patchFileRow.Patch) | 101 | // File.Attribute should not change for binary deltas, otherwise copy File Attributes from main transform row. |
137 | { | 102 | if (null != facade.Patch) |
138 | pairedFileRow.Fields[i].Modified = false; | ||
139 | } | ||
140 | else | ||
141 | #endif | 103 | #endif |
142 | { | 104 | { |
143 | pairedFileRow[i] = patchFileRow[i]; | 105 | TryModifyField(pairedFileRow, 6, mainFileRow.Attributes); |
144 | pairedFileRow.Fields[i].Modified = true; | 106 | mainFileRow.Fields[6].Modified = false; |
145 | } | ||
146 | mainFileRow.Fields[i].Modified = false; | ||
147 | } | ||
148 | else if (patchValue != mainValue) | ||
149 | { | ||
150 | mainFileRow[i] = patchFileRow[i]; | ||
151 | mainFileRow.Fields[i].Modified = true; | ||
152 | if (mainFileRow.Operation == RowOperation.None) | ||
153 | { | ||
154 | mainFileRow.Operation = RowOperation.Modify; | ||
155 | } | ||
156 | } | ||
157 | } | 107 | } |
158 | 108 | ||
159 | // Copy MsiFileHash row for this File. | 109 | #if TODO_PATCHING_DELTA |
160 | if (!mainMsiFileHashIndex.TryGetValue(patchFileRow.File, out var patchHashRow)) | 110 | // File.Sequence is updated in Patch table instead of File table for delta patches |
111 | if (null != facade.Patch) | ||
161 | { | 112 | { |
162 | //patchHashRow = patchFileRow.Hash; | 113 | pairedFileRow.Fields[7].Modified = false; |
163 | throw new NotImplementedException(); | ||
164 | } | 114 | } |
165 | 115 | else | |
166 | if (null != patchHashRow) | 116 | #endif |
167 | { | 117 | { |
168 | var mainHashTable = mainTransform.EnsureTable(this.TableDefinitions["MsiFileHash"]); | 118 | // File.Sequence is updated in pairedTransform, not mainTransform. |
169 | var mainHashRow = mainHashTable.CreateRow(mainFileRow.SourceLineNumbers); | 119 | TryModifyField(pairedFileRow, 7, facade.Sequence); |
170 | for (var i = 0; i < patchHashRow.Fields.Length; i++) | ||
171 | { | ||
172 | mainHashRow[i] = patchHashRow[i]; | ||
173 | if (i > 1) | ||
174 | { | ||
175 | // assume all hash fields have been modified | ||
176 | mainHashRow.Fields[i].Modified = true; | ||
177 | } | ||
178 | } | ||
179 | |||
180 | // assume the MsiFileHash operation follows the File one | ||
181 | mainHashRow.Operation = mainFileRow.Operation; | ||
182 | } | 120 | } |
121 | mainFileRow.Fields[7].Modified = false; | ||
183 | 122 | ||
184 | // copy MsiAssemblyName rows for this File | 123 | this.ProcessMsiFileHash(mainTransform, mainFileRow, facade.MsiFileHashSymbol, mainMsiFileHashIndex); |
185 | #if TODO_PATCHING | ||
186 | List<Row> patchAssemblyNameRows = patchFileRow.AssemblyNames; | ||
187 | if (null != patchAssemblyNameRows) | ||
188 | { | ||
189 | var mainAssemblyNameTable = mainTransform.EnsureTable(this.TableDefinitions["MsiAssemblyName"]); | ||
190 | foreach (var patchAssemblyNameRow in patchAssemblyNameRows) | ||
191 | { | ||
192 | // Copy if there isn't an identical modified/added row already in the transform. | ||
193 | var foundMatchingModifiedRow = false; | ||
194 | foreach (var mainAssemblyNameRow in mainAssemblyNameTable.Rows) | ||
195 | { | ||
196 | if (RowOperation.None != mainAssemblyNameRow.Operation && mainAssemblyNameRow.GetPrimaryKey('/').Equals(patchAssemblyNameRow.GetPrimaryKey('/'))) | ||
197 | { | ||
198 | foundMatchingModifiedRow = true; | ||
199 | break; | ||
200 | } | ||
201 | } | ||
202 | 124 | ||
203 | if (!foundMatchingModifiedRow) | 125 | this.ProcessMsiAssemblyName(mainTransform, mainFileRow, facade); |
204 | { | ||
205 | var mainAssemblyNameRow = mainAssemblyNameTable.CreateRow(mainFileRow.SourceLineNumbers); | ||
206 | for (var i = 0; i < patchAssemblyNameRow.Fields.Length; i++) | ||
207 | { | ||
208 | mainAssemblyNameRow[i] = patchAssemblyNameRow[i]; | ||
209 | } | ||
210 | |||
211 | // assume value field has been modified | ||
212 | mainAssemblyNameRow.Fields[2].Modified = true; | ||
213 | mainAssemblyNameRow.Operation = mainFileRow.Operation; | ||
214 | } | ||
215 | } | ||
216 | } | ||
217 | #endif | ||
218 | 126 | ||
219 | // Add patch header for this file | ||
220 | #if TODO_PATCHING_DELTA | 127 | #if TODO_PATCHING_DELTA |
221 | if (null != patchFileRow.Patch) | 128 | // Add patch header for this file |
129 | if (null != facade.Patch) | ||
222 | { | 130 | { |
223 | // Add the PatchFiles action automatically to the AdminExecuteSequence and InstallExecuteSequence tables. | 131 | // Add the PatchFiles action automatically to the AdminExecuteSequence and InstallExecuteSequence tables. |
224 | this.AddPatchFilesActionToSequenceTable(SequenceTable.AdminExecuteSequence, mainTransform, pairedTransform, mainFileRow); | 132 | this.AddPatchFilesActionToSequenceTable(SequenceTable.AdminExecuteSequence, mainTransform, pairedTransform, mainFileRow); |
@@ -232,12 +140,12 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
232 | } | 140 | } |
233 | 141 | ||
234 | var patchRow = patchTable.CreateRow(mainFileRow.SourceLineNumbers); | 142 | var patchRow = patchTable.CreateRow(mainFileRow.SourceLineNumbers); |
235 | patchRow[0] = patchFileRow.File; | 143 | patchRow[0] = facade.File; |
236 | patchRow[1] = patchFileRow.Sequence; | 144 | patchRow[1] = facade.Sequence; |
237 | 145 | ||
238 | var patchFile = new FileInfo(patchFileRow.Source); | 146 | var patchFile = new FileInfo(facade.Source); |
239 | patchRow[2] = (int)patchFile.Length; | 147 | patchRow[2] = (int)patchFile.Length; |
240 | patchRow[3] = 0 == (PatchAttributeType.AllowIgnoreOnError & patchFileRow.PatchAttributes) ? 0 : 1; | 148 | patchRow[3] = 0 == (PatchAttributeType.AllowIgnoreOnError & facade.PatchAttributes) ? 0 : 1; |
241 | 149 | ||
242 | var streamName = patchTable.Name + "." + patchRow[0] + "." + patchRow[1]; | 150 | var streamName = patchTable.Name + "." + patchRow[0] + "." + patchRow[1]; |
243 | if (Msi.MsiInterop.MsiMaxStreamNameLength < streamName.Length) | 151 | if (Msi.MsiInterop.MsiMaxStreamNameLength < streamName.Length) |
@@ -252,13 +160,13 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
252 | 160 | ||
253 | var patchHeadersRow = patchHeadersTable.CreateRow(mainFileRow.SourceLineNumbers); | 161 | var patchHeadersRow = patchHeadersTable.CreateRow(mainFileRow.SourceLineNumbers); |
254 | patchHeadersRow[0] = streamName; | 162 | patchHeadersRow[0] = streamName; |
255 | patchHeadersRow[1] = patchFileRow.Patch; | 163 | patchHeadersRow[1] = facade.Patch; |
256 | patchRow[5] = streamName; | 164 | patchRow[5] = streamName; |
257 | patchHeadersRow.Operation = RowOperation.Add; | 165 | patchHeadersRow.Operation = RowOperation.Add; |
258 | } | 166 | } |
259 | else | 167 | else |
260 | { | 168 | { |
261 | patchRow[4] = patchFileRow.Patch; | 169 | patchRow[4] = facade.Patch; |
262 | } | 170 | } |
263 | patchRow.Operation = RowOperation.Add; | 171 | patchRow.Operation = RowOperation.Add; |
264 | } | 172 | } |
@@ -270,14 +178,89 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
270 | } | 178 | } |
271 | } | 179 | } |
272 | } | 180 | } |
181 | } | ||
182 | } | ||
183 | |||
184 | private void ProcessMsiFileHash(WindowsInstallerData transform, FileRow fileRow, MsiFileHashSymbol msiFileHashSymbol, RowDictionary<Row> msiFileHashIndex) | ||
185 | { | ||
186 | Row msiFileHashRow = null; | ||
187 | |||
188 | if (msiFileHashSymbol != null || msiFileHashIndex.TryGetValue(fileRow.File, out msiFileHashRow)) | ||
189 | { | ||
190 | var sourceLineNumbers = msiFileHashSymbol?.SourceLineNumbers ?? msiFileHashRow?.SourceLineNumbers; | ||
191 | |||
192 | var transformHashTable = transform.EnsureTable(this.TableDefinitions["MsiFileHash"]); | ||
193 | |||
194 | var transformHashRow = transformHashTable.CreateRow(sourceLineNumbers); | ||
195 | transformHashRow.Operation = fileRow.Operation; // Assume the MsiFileHash operation follows the File one. | ||
196 | |||
197 | transformHashRow[0] = fileRow.File; | ||
198 | transformHashRow[1] = msiFileHashSymbol?.Options ?? msiFileHashRow?.Fields[1].Data; | ||
199 | |||
200 | // Assume all hash fields have been modified. | ||
201 | TryModifyField(transformHashRow, 2, msiFileHashSymbol?.HashPart1 ?? msiFileHashRow?.Fields[2].Data); | ||
202 | TryModifyField(transformHashRow, 3, msiFileHashSymbol?.HashPart2 ?? msiFileHashRow?.Fields[3].Data); | ||
203 | TryModifyField(transformHashRow, 4, msiFileHashSymbol?.HashPart3 ?? msiFileHashRow?.Fields[4].Data); | ||
204 | TryModifyField(transformHashRow, 5, msiFileHashSymbol?.HashPart4 ?? msiFileHashRow?.Fields[5].Data); | ||
205 | } | ||
206 | } | ||
273 | 207 | ||
274 | this.Output.Tables.Remove("Media"); | 208 | private void ProcessMsiAssemblyName(WindowsInstallerData transform, FileRow fileRow, IFileFacade facade) |
275 | this.Output.Tables.Remove("File"); | 209 | { |
276 | this.Output.Tables.Remove("MsiFileHash"); | 210 | if (facade.AssemblyNameSymbols.Count > 0) |
277 | this.Output.Tables.Remove("MsiAssemblyName"); | 211 | { |
212 | var assemblyNameTable = transform.EnsureTable(this.TableDefinitions["MsiAssemblyName"]); | ||
213 | |||
214 | foreach (var assemblyNameSymbol in facade.AssemblyNameSymbols) | ||
215 | { | ||
216 | // Copy if there isn't an identical modified/added row already in the transform. | ||
217 | var foundMatchingModifiedRow = false; | ||
218 | foreach (var mainAssemblyNameRow in assemblyNameTable.Rows.Where(r => r.Operation != RowOperation.None)) | ||
219 | { | ||
220 | var component = mainAssemblyNameRow.FieldAsString(0); | ||
221 | var name = mainAssemblyNameRow.FieldAsString(1); | ||
222 | |||
223 | if (assemblyNameSymbol.ComponentRef == component && assemblyNameSymbol.Name == name) | ||
224 | { | ||
225 | foundMatchingModifiedRow = true; | ||
226 | break; | ||
227 | } | ||
228 | } | ||
229 | |||
230 | if (!foundMatchingModifiedRow) | ||
231 | { | ||
232 | var assemblyNameRow = assemblyNameTable.CreateRow(fileRow.SourceLineNumbers); | ||
233 | assemblyNameRow[0] = assemblyNameSymbol.ComponentRef; | ||
234 | assemblyNameRow[1] = assemblyNameSymbol.Name; | ||
235 | assemblyNameRow[2] = assemblyNameSymbol.Value; | ||
236 | |||
237 | // assume value field has been modified | ||
238 | assemblyNameRow.Fields[2].Modified = true; | ||
239 | assemblyNameRow.Operation = fileRow.Operation; | ||
240 | } | ||
241 | } | ||
278 | } | 242 | } |
279 | } | 243 | } |
280 | 244 | ||
245 | private Dictionary<int, Dictionary<string, IFileFacade>> IndexFileFacadesByDiskId() | ||
246 | { | ||
247 | var fileFacadesByDiskId = new Dictionary<int, Dictionary<string, IFileFacade>>(); | ||
248 | |||
249 | // Index patch file facades by diskId+fileId. | ||
250 | foreach (var facade in this.FileFacades) | ||
251 | { | ||
252 | if (!fileFacadesByDiskId.TryGetValue(facade.DiskId, out var mediaFacades)) | ||
253 | { | ||
254 | mediaFacades = new Dictionary<string, IFileFacade>(); | ||
255 | fileFacadesByDiskId.Add(facade.DiskId, mediaFacades); | ||
256 | } | ||
257 | |||
258 | mediaFacades.Add(facade.Id, facade); | ||
259 | } | ||
260 | |||
261 | return fileFacadesByDiskId; | ||
262 | } | ||
263 | |||
281 | /// <summary> | 264 | /// <summary> |
282 | /// Adds the PatchFiles action to the sequence table if it does not already exist. | 265 | /// Adds the PatchFiles action to the sequence table if it does not already exist. |
283 | /// </summary> | 266 | /// </summary> |
@@ -349,6 +332,24 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
349 | } | 332 | } |
350 | } | 333 | } |
351 | 334 | ||
335 | private static bool TryModifyField(Row row, int index, object value) | ||
336 | { | ||
337 | var field = row.Fields[index]; | ||
338 | |||
339 | if (field.Data != value) | ||
340 | { | ||
341 | field.Data = value; | ||
342 | field.Modified = true; | ||
343 | |||
344 | if (row.Operation == RowOperation.None) | ||
345 | { | ||
346 | row.Operation = RowOperation.Modify; | ||
347 | } | ||
348 | } | ||
349 | |||
350 | return field.Modified; | ||
351 | } | ||
352 | |||
352 | /// <summary> | 353 | /// <summary> |
353 | /// Tests sequence table for PatchFiles and associated actions | 354 | /// Tests sequence table for PatchFiles and associated actions |
354 | /// </summary> | 355 | /// </summary> |
@@ -396,33 +397,29 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
396 | return; | 397 | return; |
397 | } | 398 | } |
398 | 399 | ||
399 | var componentKeyPath = new Dictionary<string, string>(componentTable.Rows.Count); | ||
400 | |||
401 | // Index the Component table for non-directory & non-registry key paths. | 400 | // Index the Component table for non-directory & non-registry key paths. |
402 | foreach (var row in componentTable.Rows) | 401 | var componentKeyPath = new Dictionary<string, string>(); |
402 | foreach (var row in componentTable.Rows.Cast<ComponentRow>().Where(r => !r.IsRegistryKeyPath)) | ||
403 | { | 403 | { |
404 | var keyPath = row.FieldAsString(5); | 404 | var keyPath = row.KeyPath; |
405 | if (keyPath != null && 0 != (row.FieldAsInteger(3) & WindowsInstallerConstants.MsidbComponentAttributesRegistryKeyPath)) | 405 | |
406 | if (!String.IsNullOrEmpty(keyPath)) | ||
406 | { | 407 | { |
407 | componentKeyPath.Add(row.FieldAsString(0), keyPath); | 408 | componentKeyPath.Add(row.Component, keyPath); |
408 | } | 409 | } |
409 | } | 410 | } |
410 | 411 | ||
411 | var componentWithChangedKeyPath = new Dictionary<string, string>(); | 412 | var componentWithChangedKeyPath = new Dictionary<string, string>(); |
412 | var componentWithNonKeyPathChanged = new Dictionary<string, string>(); | 413 | var componentWithNonKeyPathChanged = new Dictionary<string, string>(); |
414 | |||
413 | // Verify changes in the file table, now that file diffing has occurred | 415 | // Verify changes in the file table, now that file diffing has occurred |
414 | foreach (FileRow row in fileTable.Rows) | 416 | foreach (var row in fileTable.Rows.Cast<FileRow>().Where(r => r.Operation == RowOperation.Modify)) |
415 | { | 417 | { |
416 | if (RowOperation.Modify != row.Operation) | 418 | var fileId = row.File; |
417 | { | 419 | var componentId = row.Component; |
418 | continue; | ||
419 | } | ||
420 | |||
421 | var fileId = row.FieldAsString(0); | ||
422 | var componentId = row.FieldAsString(1); | ||
423 | 420 | ||
424 | // If this file is the keypath of a component | 421 | // If this file is the keypath of a component |
425 | if (componentKeyPath.ContainsValue(fileId)) | 422 | if (componentKeyPath.ContainsValue(componentId)) |
426 | { | 423 | { |
427 | if (!componentWithChangedKeyPath.ContainsKey(componentId)) | 424 | if (!componentWithChangedKeyPath.ContainsKey(componentId)) |
428 | { | 425 | { |
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/CommandLine/TransformSubcommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/CommandLine/TransformSubcommand.cs index 727e20b2..68cb6554 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/CommandLine/TransformSubcommand.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/CommandLine/TransformSubcommand.cs | |||
@@ -21,6 +21,7 @@ namespace WixToolset.Core.WindowsInstaller.CommandLine | |||
21 | { | 21 | { |
22 | this.Messaging = serviceProvider.GetService<IMessaging>(); | 22 | this.Messaging = serviceProvider.GetService<IMessaging>(); |
23 | this.BackendHelper = serviceProvider.GetService<IBackendHelper>(); | 23 | this.BackendHelper = serviceProvider.GetService<IBackendHelper>(); |
24 | this.PathResolver = serviceProvider.GetService<IPathResolver>(); | ||
24 | this.ExtensionManager = serviceProvider.GetService<IExtensionManager>(); | 25 | this.ExtensionManager = serviceProvider.GetService<IExtensionManager>(); |
25 | } | 26 | } |
26 | 27 | ||
@@ -28,6 +29,8 @@ namespace WixToolset.Core.WindowsInstaller.CommandLine | |||
28 | 29 | ||
29 | private IBackendHelper BackendHelper { get; } | 30 | private IBackendHelper BackendHelper { get; } |
30 | 31 | ||
32 | private IPathResolver PathResolver { get; } | ||
33 | |||
31 | private IExtensionManager ExtensionManager { get; } | 34 | private IExtensionManager ExtensionManager { get; } |
32 | 35 | ||
33 | private string OutputPath { get; set; } | 36 | private string OutputPath { get; set; } |
@@ -40,8 +43,6 @@ namespace WixToolset.Core.WindowsInstaller.CommandLine | |||
40 | 43 | ||
41 | private string IntermediateFolder { get; set; } | 44 | private string IntermediateFolder { get; set; } |
42 | 45 | ||
43 | private bool IsAdminImage { get; set; } | ||
44 | |||
45 | private bool PreserveUnchangedRows { get; set; } | 46 | private bool PreserveUnchangedRows { get; set; } |
46 | 47 | ||
47 | private bool ShowPedanticMessages { get; set; } | 48 | private bool ShowPedanticMessages { get; set; } |
@@ -133,10 +134,6 @@ namespace WixToolset.Core.WindowsInstaller.CommandLine | |||
133 | var parameter = argument.Substring(1); | 134 | var parameter = argument.Substring(1); |
134 | switch (parameter.ToLowerInvariant()) | 135 | switch (parameter.ToLowerInvariant()) |
135 | { | 136 | { |
136 | case "a": | ||
137 | this.IsAdminImage = true; | ||
138 | return true; | ||
139 | |||
140 | case "intermediatefolder": | 137 | case "intermediatefolder": |
141 | this.IntermediateFolder = parser.GetNextArgumentAsDirectoryOrError(argument); | 138 | this.IntermediateFolder = parser.GetNextArgumentAsDirectoryOrError(argument); |
142 | return true; | 139 | return true; |
@@ -194,15 +191,15 @@ namespace WixToolset.Core.WindowsInstaller.CommandLine | |||
194 | } | 191 | } |
195 | } | 192 | } |
196 | 193 | ||
197 | case "val": | 194 | case "t": |
198 | { | 195 | { |
199 | var val = parser.GetNextArgumentOrError(argument); | 196 | var type = parser.GetNextArgumentOrError(argument); |
200 | if (String.IsNullOrEmpty(val)) | 197 | if (String.IsNullOrEmpty(type)) |
201 | { | 198 | { |
202 | return true; | 199 | return true; |
203 | } | 200 | } |
204 | 201 | ||
205 | switch (val.ToLowerInvariant()) | 202 | switch (type.ToLowerInvariant()) |
206 | { | 203 | { |
207 | case "language": | 204 | case "language": |
208 | this.ValidationFlags |= TransformFlags.LanguageTransformDefault; | 205 | this.ValidationFlags |= TransformFlags.LanguageTransformDefault; |
@@ -216,6 +213,22 @@ namespace WixToolset.Core.WindowsInstaller.CommandLine | |||
216 | this.ValidationFlags |= TransformFlags.PatchTransformDefault; | 213 | this.ValidationFlags |= TransformFlags.PatchTransformDefault; |
217 | return true; | 214 | return true; |
218 | 215 | ||
216 | default: | ||
217 | parser.ReportErrorArgument(argument, ErrorMessages.IllegalCommandLineArgumentValue(argument, type, new[] { "language", "instance", "patch" })); | ||
218 | return true; | ||
219 | } | ||
220 | } | ||
221 | |||
222 | case "val": | ||
223 | { | ||
224 | var val = parser.GetNextArgumentOrError(argument); | ||
225 | if (String.IsNullOrEmpty(val)) | ||
226 | { | ||
227 | return true; | ||
228 | } | ||
229 | |||
230 | switch (val.ToLowerInvariant()) | ||
231 | { | ||
219 | case "g": | 232 | case "g": |
220 | this.ValidationFlags |= TransformFlags.ValidateUpgradeCode; | 233 | this.ValidationFlags |= TransformFlags.ValidateUpgradeCode; |
221 | return true; | 234 | return true; |
@@ -261,7 +274,7 @@ namespace WixToolset.Core.WindowsInstaller.CommandLine | |||
261 | return true; | 274 | return true; |
262 | 275 | ||
263 | default: | 276 | default: |
264 | parser.ReportErrorArgument(argument, ErrorMessages.IllegalCommandLineArgumentValue(argument, val, new[] { "language", "instance", "patch", "g", "l", "r", "s", "t", "u", "v", "w", "x", "y", "z" })); | 277 | parser.ReportErrorArgument(argument, ErrorMessages.IllegalCommandLineArgumentValue(argument, val, new[] { "g", "l", "r", "s", "t", "u", "v", "w", "x", "y", "z" })); |
265 | return true; | 278 | return true; |
266 | } | 279 | } |
267 | } | 280 | } |
@@ -297,7 +310,7 @@ namespace WixToolset.Core.WindowsInstaller.CommandLine | |||
297 | { | 310 | { |
298 | Exception exception; | 311 | Exception exception; |
299 | 312 | ||
300 | (transform, exception) = LoadWindowsInstallerDataSafely(this.TargetPath); | 313 | (transform, exception) = DataLoader.LoadWindowsInstallerDataSafely(this.TargetPath); |
301 | 314 | ||
302 | if (transform?.Type != OutputType.Transform) | 315 | if (transform?.Type != OutputType.Transform) |
303 | { | 316 | { |
@@ -340,17 +353,9 @@ namespace WixToolset.Core.WindowsInstaller.CommandLine | |||
340 | 353 | ||
341 | private WindowsInstallerData CreateTransform() | 354 | private WindowsInstallerData CreateTransform() |
342 | { | 355 | { |
343 | if (!TryLoadWindowsInstallerData(this.TargetPath, out var targetOutput)) | 356 | var targetData = this.GetWindowsInstallerData(this.TargetPath); |
344 | { | ||
345 | var unbindCommand = new UnbindMsiOrMsmCommand(this.Messaging, this.BackendHelper, this.TargetPath, this.ExportBasePath, this.IntermediateFolder, this.IsAdminImage, suppressDemodularization: true, suppressExtractCabinets: true); | ||
346 | targetOutput = unbindCommand.Execute(); | ||
347 | } | ||
348 | 357 | ||
349 | if (!TryLoadWindowsInstallerData(this.TargetPath, out var updatedOutput)) | 358 | var updatedData = this.GetWindowsInstallerData(this.UpdatedPath); |
350 | { | ||
351 | var unbindCommand = new UnbindMsiOrMsmCommand(this.Messaging, this.BackendHelper, this.UpdatedPath, this.ExportBasePath, this.IntermediateFolder, this.IsAdminImage, suppressDemodularization: true, suppressExtractCabinets: true); | ||
352 | updatedOutput = unbindCommand.Execute(); | ||
353 | } | ||
354 | 359 | ||
355 | var differ = new Differ(this.Messaging) | 360 | var differ = new Differ(this.Messaging) |
356 | { | 361 | { |
@@ -359,7 +364,7 @@ namespace WixToolset.Core.WindowsInstaller.CommandLine | |||
359 | SuppressKeepingSpecialRows = this.SuppressKeepingSpecialRows | 364 | SuppressKeepingSpecialRows = this.SuppressKeepingSpecialRows |
360 | }; | 365 | }; |
361 | 366 | ||
362 | return differ.Diff(targetOutput, updatedOutput, this.ValidationFlags); | 367 | return differ.Diff(targetData, updatedData, this.ValidationFlags); |
363 | } | 368 | } |
364 | 369 | ||
365 | private TableDefinitionCollection GetTableDefinitions() | 370 | private TableDefinitionCollection GetTableDefinitions() |
@@ -370,37 +375,15 @@ namespace WixToolset.Core.WindowsInstaller.CommandLine | |||
370 | return loadTableDefinitions.Execute(); | 375 | return loadTableDefinitions.Execute(); |
371 | } | 376 | } |
372 | 377 | ||
373 | private static bool TryLoadWindowsInstallerData(string path, out WindowsInstallerData data) | 378 | private WindowsInstallerData GetWindowsInstallerData(string path) |
374 | { | 379 | { |
375 | data = null; | 380 | if (!DataLoader.TryLoadWindowsInstallerData(path, out var data)) |
376 | |||
377 | var extension = Path.GetExtension(path); | ||
378 | |||
379 | // If the path is _not_ obviously a Windows Installer database, let's try opening it as | ||
380 | // our own data file format. | ||
381 | if (!extension.Equals(".msi", StringComparison.OrdinalIgnoreCase) && !extension.Equals(".msm", StringComparison.OrdinalIgnoreCase)) | ||
382 | { | ||
383 | (data, _) = LoadWindowsInstallerDataSafely(path); | ||
384 | } | ||
385 | |||
386 | return data != null; | ||
387 | } | ||
388 | |||
389 | private static (WindowsInstallerData, Exception) LoadWindowsInstallerDataSafely(string path) | ||
390 | { | ||
391 | WindowsInstallerData data = null; | ||
392 | Exception exception = null; | ||
393 | |||
394 | try | ||
395 | { | ||
396 | data = WindowsInstallerData.Load(path); | ||
397 | } | ||
398 | catch (Exception e) | ||
399 | { | 381 | { |
400 | exception = e; | 382 | var unbindCommand = new UnbindDatabaseCommand(this.Messaging, this.BackendHelper, this.PathResolver, path, OutputType.Product, this.ExportBasePath, null, this.IntermediateFolder, enableDemodularization: false, skipSummaryInfo: false); |
383 | data = unbindCommand.Execute(); | ||
401 | } | 384 | } |
402 | 385 | ||
403 | return (data, exception); | 386 | return data; |
404 | } | 387 | } |
405 | } | 388 | } |
406 | } | 389 | } |
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Differ.cs b/src/wix/WixToolset.Core.WindowsInstaller/Differ.cs index ae9492eb..f4e4a1fc 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Differ.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Differ.cs | |||
@@ -10,7 +10,6 @@ namespace WixToolset.Core.WindowsInstaller | |||
10 | using WixToolset.Data; | 10 | using WixToolset.Data; |
11 | using WixToolset.Data.Symbols; | 11 | using WixToolset.Data.Symbols; |
12 | using WixToolset.Data.WindowsInstaller; | 12 | using WixToolset.Data.WindowsInstaller; |
13 | using WixToolset.Extensibility; | ||
14 | using WixToolset.Extensibility.Services; | 13 | using WixToolset.Extensibility.Services; |
15 | 14 | ||
16 | /// <summary> | 15 | /// <summary> |
@@ -18,7 +17,7 @@ namespace WixToolset.Core.WindowsInstaller | |||
18 | /// </summary> | 17 | /// </summary> |
19 | public sealed class Differ | 18 | public sealed class Differ |
20 | { | 19 | { |
21 | private const char sectionDelimiter = '/'; | 20 | private const char SectionDelimiter = '/'; |
22 | private readonly IMessaging messaging; | 21 | private readonly IMessaging messaging; |
23 | private SummaryInformationStreams transformSummaryInfo; | 22 | private SummaryInformationStreams transformSummaryInfo; |
24 | 23 | ||
@@ -53,24 +52,16 @@ namespace WixToolset.Core.WindowsInstaller | |||
53 | /// </summary> | 52 | /// </summary> |
54 | /// <param name="targetOutput">The target output.</param> | 53 | /// <param name="targetOutput">The target output.</param> |
55 | /// <param name="updatedOutput">The updated output.</param> | 54 | /// <param name="updatedOutput">The updated output.</param> |
56 | /// <returns>The transform.</returns> | ||
57 | public WindowsInstallerData Diff(WindowsInstallerData targetOutput, WindowsInstallerData updatedOutput) | ||
58 | { | ||
59 | return this.Diff(targetOutput, updatedOutput, 0); | ||
60 | } | ||
61 | |||
62 | /// <summary> | ||
63 | /// Creates a transform by diffing two outputs. | ||
64 | /// </summary> | ||
65 | /// <param name="targetOutput">The target output.</param> | ||
66 | /// <param name="updatedOutput">The updated output.</param> | ||
67 | /// <param name="validationFlags"></param> | 55 | /// <param name="validationFlags"></param> |
68 | /// <returns>The transform.</returns> | 56 | /// <returns>The transform.</returns> |
69 | public WindowsInstallerData Diff(WindowsInstallerData targetOutput, WindowsInstallerData updatedOutput, TransformFlags validationFlags) | 57 | public WindowsInstallerData Diff(WindowsInstallerData targetOutput, WindowsInstallerData updatedOutput, TransformFlags validationFlags) |
70 | { | 58 | { |
71 | var transform = new WindowsInstallerData(null); | 59 | var transform = new WindowsInstallerData(null) |
72 | transform.Type = OutputType.Transform; | 60 | { |
73 | transform.Codepage = updatedOutput.Codepage; | 61 | Type = OutputType.Transform, |
62 | Codepage = updatedOutput.Codepage | ||
63 | }; | ||
64 | |||
74 | this.transformSummaryInfo = new SummaryInformationStreams(); | 65 | this.transformSummaryInfo = new SummaryInformationStreams(); |
75 | 66 | ||
76 | // compare the codepages | 67 | // compare the codepages |
@@ -120,7 +111,7 @@ namespace WixToolset.Core.WindowsInstaller | |||
120 | foreach (var updatedRow in updatedTable.Rows) | 111 | foreach (var updatedRow in updatedTable.Rows) |
121 | { | 112 | { |
122 | updatedRow.Operation = RowOperation.Add; | 113 | updatedRow.Operation = RowOperation.Add; |
123 | updatedRow.SectionId = sectionDelimiter + updatedRow.SectionId; | 114 | updatedRow.SectionId = SectionDelimiter + updatedRow.SectionId; |
124 | addedTable.Rows.Add(updatedRow); | 115 | addedTable.Rows.Add(updatedRow); |
125 | } | 116 | } |
126 | } | 117 | } |
@@ -209,7 +200,7 @@ namespace WixToolset.Core.WindowsInstaller | |||
209 | else if (null == updatedRow) | 200 | else if (null == updatedRow) |
210 | { | 201 | { |
211 | operation = targetRow.Operation = RowOperation.Delete; | 202 | operation = targetRow.Operation = RowOperation.Delete; |
212 | targetRow.SectionId += sectionDelimiter; | 203 | targetRow.SectionId += SectionDelimiter; |
213 | comparedRow = targetRow; | 204 | comparedRow = targetRow; |
214 | keepRow = true; | 205 | keepRow = true; |
215 | } | 206 | } |
@@ -222,7 +213,7 @@ namespace WixToolset.Core.WindowsInstaller | |||
222 | // ignore rows that shouldn't be in a transform | 213 | // ignore rows that shouldn't be in a transform |
223 | if (Enum.IsDefined(typeof(SummaryInformation.Transform), (int)updatedRow[0])) | 214 | if (Enum.IsDefined(typeof(SummaryInformation.Transform), (int)updatedRow[0])) |
224 | { | 215 | { |
225 | updatedRow.SectionId = targetRow.SectionId + sectionDelimiter + updatedRow.SectionId; | 216 | updatedRow.SectionId = targetRow.SectionId + SectionDelimiter + updatedRow.SectionId; |
226 | comparedRow = updatedRow; | 217 | comparedRow = updatedRow; |
227 | keepRow = true; | 218 | keepRow = true; |
228 | operation = RowOperation.Modify; | 219 | operation = RowOperation.Modify; |
@@ -306,7 +297,7 @@ namespace WixToolset.Core.WindowsInstaller | |||
306 | if (keepRow) | 297 | if (keepRow) |
307 | { | 298 | { |
308 | comparedRow = updatedRow; | 299 | comparedRow = updatedRow; |
309 | comparedRow.SectionId = targetRow.SectionId + sectionDelimiter + updatedRow.SectionId; | 300 | comparedRow.SectionId = targetRow.SectionId + SectionDelimiter + updatedRow.SectionId; |
310 | } | 301 | } |
311 | } | 302 | } |
312 | } | 303 | } |
@@ -350,8 +341,9 @@ namespace WixToolset.Core.WindowsInstaller | |||
350 | // diff the target and updated rows | 341 | // diff the target and updated rows |
351 | foreach (var targetPrimaryKeyEntry in targetPrimaryKeys) | 342 | foreach (var targetPrimaryKeyEntry in targetPrimaryKeys) |
352 | { | 343 | { |
353 | var targetPrimaryKey = targetPrimaryKeyEntry.Key; | 344 | updatedPrimaryKeys.TryGetValue(targetPrimaryKeyEntry.Key, out var updatedRow); |
354 | var compared = this.CompareRows(targetTable, targetPrimaryKeyEntry.Value, updatedPrimaryKeys[targetPrimaryKey], out var _, out var keepRow); | 345 | |
346 | var compared = this.CompareRows(targetTable, targetPrimaryKeyEntry.Value, updatedRow, out var _, out var keepRow); | ||
355 | 347 | ||
356 | if (keepRow) | 348 | if (keepRow) |
357 | { | 349 | { |
@@ -369,7 +361,7 @@ namespace WixToolset.Core.WindowsInstaller | |||
369 | var updatedRow = (Row)updatedPrimaryKeyEntry.Value; | 361 | var updatedRow = (Row)updatedPrimaryKeyEntry.Value; |
370 | 362 | ||
371 | updatedRow.Operation = RowOperation.Add; | 363 | updatedRow.Operation = RowOperation.Add; |
372 | updatedRow.SectionId = sectionDelimiter + updatedRow.SectionId; | 364 | updatedRow.SectionId = SectionDelimiter + updatedRow.SectionId; |
373 | rows.Add(updatedRow); | 365 | rows.Add(updatedRow); |
374 | } | 366 | } |
375 | } | 367 | } |
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/ExtensibilityServices/FileFacade.cs b/src/wix/WixToolset.Core.WindowsInstaller/ExtensibilityServices/FileFacade.cs new file mode 100644 index 00000000..eede6e24 --- /dev/null +++ b/src/wix/WixToolset.Core.WindowsInstaller/ExtensibilityServices/FileFacade.cs | |||
@@ -0,0 +1,82 @@ | |||
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.ExtensibilityServices | ||
4 | { | ||
5 | using System.Collections.Generic; | ||
6 | using WixToolset.Data; | ||
7 | using WixToolset.Data.Symbols; | ||
8 | using WixToolset.Data.WindowsInstaller; | ||
9 | using WixToolset.Data.WindowsInstaller.Rows; | ||
10 | using WixToolset.Extensibility.Data; | ||
11 | |||
12 | internal class FileFacade : IFileFacade | ||
13 | { | ||
14 | public FileFacade(FileSymbol file) | ||
15 | { | ||
16 | this.Identifier = file.Id; | ||
17 | this.ComponentRef = file.ComponentRef; | ||
18 | this.DiskId = file.DiskId ?? 1; | ||
19 | this.FileName = file.Name; | ||
20 | this.FileSize = file.FileSize; | ||
21 | this.Language = file.Language; | ||
22 | this.PatchGroup = file.PatchGroup; | ||
23 | this.Sequence = file.Sequence; | ||
24 | this.SourceLineNumber = file.SourceLineNumbers; | ||
25 | this.SourcePath = file.Source?.Path; | ||
26 | this.Compressed = (file.Attributes & FileSymbolAttributes.Compressed) == FileSymbolAttributes.Compressed; | ||
27 | this.Uncompressed = (file.Attributes & FileSymbolAttributes.Uncompressed) == FileSymbolAttributes.Uncompressed; | ||
28 | this.Version = file.Version; | ||
29 | this.AssemblyNameSymbols = new List<MsiAssemblyNameSymbol>(); | ||
30 | } | ||
31 | |||
32 | public FileFacade(FileRow row) | ||
33 | { | ||
34 | this.Identifier = new Identifier(AccessModifier.Section, row.File); | ||
35 | this.ComponentRef = row.Component; | ||
36 | this.DiskId = row.DiskId; | ||
37 | this.FileName = row.FileName; | ||
38 | this.FileSize = row.FileSize; | ||
39 | this.Language = row.Language; | ||
40 | this.PatchGroup = null; | ||
41 | this.Sequence = row.Sequence; | ||
42 | this.SourceLineNumber = row.SourceLineNumbers; | ||
43 | this.SourcePath = row.Source; | ||
44 | this.Compressed = (row.Attributes & WindowsInstallerConstants.MsidbFileAttributesCompressed) == WindowsInstallerConstants.MsidbFileAttributesCompressed; | ||
45 | this.Uncompressed = (row.Attributes & WindowsInstallerConstants.MsidbFileAttributesNoncompressed) == WindowsInstallerConstants.MsidbFileAttributesNoncompressed; | ||
46 | this.Version = row.Version; | ||
47 | this.AssemblyNameSymbols = new List<MsiAssemblyNameSymbol>(); | ||
48 | } | ||
49 | |||
50 | public string Id => this.Identifier.Id; | ||
51 | |||
52 | public Identifier Identifier { get; } | ||
53 | |||
54 | public string ComponentRef { get; } | ||
55 | |||
56 | public int DiskId { get; set; } | ||
57 | |||
58 | public string FileName { get; } | ||
59 | |||
60 | public int FileSize { get; set; } | ||
61 | |||
62 | public string Language { get; set; } | ||
63 | |||
64 | public int? PatchGroup { get; } | ||
65 | |||
66 | public int Sequence { get; set; } | ||
67 | |||
68 | public SourceLineNumber SourceLineNumber { get; } | ||
69 | |||
70 | public string SourcePath { get; } | ||
71 | |||
72 | public bool Compressed { get; } | ||
73 | |||
74 | public bool Uncompressed { get; } | ||
75 | |||
76 | public string Version { get; set; } | ||
77 | |||
78 | public MsiFileHashSymbol MsiFileHashSymbol { get; set; } | ||
79 | |||
80 | public ICollection<MsiAssemblyNameSymbol> AssemblyNameSymbols { get; } | ||
81 | } | ||
82 | } | ||
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/ExtensibilityServices/WindowsInstallerBackendHelper.cs b/src/wix/WixToolset.Core.WindowsInstaller/ExtensibilityServices/WindowsInstallerBackendHelper.cs index ad738321..f372af82 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/ExtensibilityServices/WindowsInstallerBackendHelper.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/ExtensibilityServices/WindowsInstallerBackendHelper.cs | |||
@@ -23,19 +23,14 @@ namespace WixToolset.Core.WindowsInstaller.ExtensibilityServices | |||
23 | 23 | ||
24 | #region IBackendHelper interfaces | 24 | #region IBackendHelper interfaces |
25 | 25 | ||
26 | public IFileFacade CreateFileFacade(FileSymbol file, AssemblySymbol assembly) | 26 | public IFileFacade CreateFileFacade(FileSymbol file) |
27 | { | 27 | { |
28 | return this.backendHelper.CreateFileFacade(file, assembly); | 28 | return new FileFacade(file); |
29 | } | 29 | } |
30 | 30 | ||
31 | public IFileFacade CreateFileFacade(FileRow fileRow) | 31 | public IFileFacade CreateFileFacade(FileRow fileRow) |
32 | { | 32 | { |
33 | return this.backendHelper.CreateFileFacade(fileRow); | 33 | return new FileFacade(fileRow); |
34 | } | ||
35 | |||
36 | public IFileFacade CreateFileFacadeFromMergeModule(FileSymbol fileSymbol) | ||
37 | { | ||
38 | return this.backendHelper.CreateFileFacadeFromMergeModule(fileSymbol); | ||
39 | } | 34 | } |
40 | 35 | ||
41 | public IFileTransfer CreateFileTransfer(string source, string destination, bool move, SourceLineNumber sourceLineNumbers = null) | 36 | public IFileTransfer CreateFileTransfer(string source, string destination, bool move, SourceLineNumber sourceLineNumbers = null) |
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/MsiBackend.cs b/src/wix/WixToolset.Core.WindowsInstaller/MsiBackend.cs index f73791aa..27bb282b 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/MsiBackend.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/MsiBackend.cs | |||
@@ -2,11 +2,7 @@ | |||
2 | 2 | ||
3 | namespace WixToolset.Core.WindowsInstaller | 3 | namespace WixToolset.Core.WindowsInstaller |
4 | { | 4 | { |
5 | using System; | ||
6 | using WixToolset.Core.WindowsInstaller.Bind; | 5 | using WixToolset.Core.WindowsInstaller.Bind; |
7 | using WixToolset.Core.WindowsInstaller.Decompile; | ||
8 | using WixToolset.Core.WindowsInstaller.Unbind; | ||
9 | using WixToolset.Data; | ||
10 | using WixToolset.Extensibility; | 6 | using WixToolset.Extensibility; |
11 | using WixToolset.Extensibility.Data; | 7 | using WixToolset.Extensibility.Data; |
12 | using WixToolset.Extensibility.Services; | 8 | using WixToolset.Extensibility.Services; |
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/MspBackend.cs b/src/wix/WixToolset.Core.WindowsInstaller/MspBackend.cs index 38a4ab34..bccdd3d4 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/MspBackend.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/MspBackend.cs | |||
@@ -2,7 +2,6 @@ | |||
2 | 2 | ||
3 | namespace WixToolset.Core.WindowsInstaller | 3 | namespace WixToolset.Core.WindowsInstaller |
4 | { | 4 | { |
5 | using System; | ||
6 | using System.Collections.Generic; | 5 | using System.Collections.Generic; |
7 | using WixToolset.Core.WindowsInstaller.Bind; | 6 | using WixToolset.Core.WindowsInstaller.Bind; |
8 | using WixToolset.Data.WindowsInstaller; | 7 | using WixToolset.Data.WindowsInstaller; |
@@ -18,8 +17,14 @@ namespace WixToolset.Core.WindowsInstaller | |||
18 | 17 | ||
19 | var backendHelper = context.ServiceProvider.GetService<IBackendHelper>(); | 18 | var backendHelper = context.ServiceProvider.GetService<IBackendHelper>(); |
20 | 19 | ||
20 | var pathResolver = context.ServiceProvider.GetService<IPathResolver>(); | ||
21 | |||
22 | var fileResolver = context.ServiceProvider.GetService<IFileResolver>(); | ||
23 | |||
21 | var extensionManager = context.ServiceProvider.GetService<IExtensionManager>(); | 24 | var extensionManager = context.ServiceProvider.GetService<IExtensionManager>(); |
22 | 25 | ||
26 | var resolveExtensions = extensionManager.GetServices<IResolverExtension>(); | ||
27 | |||
23 | var backendExtensions = extensionManager.GetServices<IWindowsInstallerBackendBinderExtension>(); | 28 | var backendExtensions = extensionManager.GetServices<IWindowsInstallerBackendBinderExtension>(); |
24 | 29 | ||
25 | foreach (var extension in backendExtensions) | 30 | foreach (var extension in backendExtensions) |
@@ -30,7 +35,7 @@ namespace WixToolset.Core.WindowsInstaller | |||
30 | // Create transforms named in patch transforms. | 35 | // Create transforms named in patch transforms. |
31 | IEnumerable<PatchTransform> patchTransforms; | 36 | IEnumerable<PatchTransform> patchTransforms; |
32 | { | 37 | { |
33 | var command = new CreatePatchTransformsCommand(messaging, backendHelper, context.IntermediateRepresentation, context.IntermediateFolder); | 38 | var command = new CreatePatchTransformsCommand(messaging, backendHelper, pathResolver, fileResolver, resolveExtensions, context.IntermediateRepresentation, context.IntermediateFolder, context.BindPaths); |
34 | patchTransforms = command.Execute(); | 39 | patchTransforms = command.Execute(); |
35 | } | 40 | } |
36 | 41 | ||
@@ -42,7 +47,7 @@ namespace WixToolset.Core.WindowsInstaller | |||
42 | } | 47 | } |
43 | 48 | ||
44 | // Create WindowsInstallerData with patch metdata and transforms as sub-storages | 49 | // Create WindowsInstallerData with patch metdata and transforms as sub-storages |
45 | // Create MSP from WindowsInstallerData | 50 | // and create MSP from that WindowsInstallerData. |
46 | IBindResult result = null; | 51 | IBindResult result = null; |
47 | try | 52 | try |
48 | { | 53 | { |
@@ -62,90 +67,5 @@ namespace WixToolset.Core.WindowsInstaller | |||
62 | throw; | 67 | throw; |
63 | } | 68 | } |
64 | } | 69 | } |
65 | |||
66 | #if TODO_PATCHING | ||
67 | public Intermediate Unbind(IUnbindContext context) | ||
68 | { | ||
69 | Output patch; | ||
70 | |||
71 | // patch files are essentially database files (use a special flag to let the API know its a patch file) | ||
72 | try | ||
73 | { | ||
74 | using (Database database = new Database(context.InputFilePath, OpenDatabase.ReadOnly | OpenDatabase.OpenPatchFile)) | ||
75 | { | ||
76 | var unbindCommand = new UnbindDatabaseCommand(context.Messaging, database, context.InputFilePath, OutputType.Patch, context.ExportBasePath, context.IntermediateFolder, context.IsAdminImage, context.SuppressDemodularization, skipSummaryInfo: false); | ||
77 | patch = unbindCommand.Execute(); | ||
78 | } | ||
79 | } | ||
80 | catch (Win32Exception e) | ||
81 | { | ||
82 | if (0x6E == e.NativeErrorCode) // ERROR_OPEN_FAILED | ||
83 | { | ||
84 | throw new WixException(WixErrors.OpenDatabaseFailed(context.InputFilePath)); | ||
85 | } | ||
86 | |||
87 | throw; | ||
88 | } | ||
89 | |||
90 | // retrieve the transforms (they are in substorages) | ||
91 | using (Storage storage = Storage.Open(context.InputFilePath, StorageMode.Read | StorageMode.ShareDenyWrite)) | ||
92 | { | ||
93 | Table summaryInformationTable = patch.Tables["_SummaryInformation"]; | ||
94 | foreach (Row row in summaryInformationTable.Rows) | ||
95 | { | ||
96 | if (8 == (int)row[0]) // PID_LASTAUTHOR | ||
97 | { | ||
98 | string value = (string)row[1]; | ||
99 | |||
100 | foreach (string decoratedSubStorageName in value.Split(';')) | ||
101 | { | ||
102 | string subStorageName = decoratedSubStorageName.Substring(1); | ||
103 | string transformFile = Path.Combine(context.IntermediateFolder, String.Concat("Transform", Path.DirectorySeparatorChar, subStorageName, ".mst")); | ||
104 | |||
105 | // ensure the parent directory exists | ||
106 | Directory.CreateDirectory(Path.GetDirectoryName(transformFile)); | ||
107 | |||
108 | // copy the substorage to a new storage for the transform file | ||
109 | using (Storage subStorage = storage.OpenStorage(subStorageName)) | ||
110 | { | ||
111 | using (Storage transformStorage = Storage.CreateDocFile(transformFile, StorageMode.ReadWrite | StorageMode.ShareExclusive | StorageMode.Create)) | ||
112 | { | ||
113 | subStorage.CopyTo(transformStorage); | ||
114 | } | ||
115 | } | ||
116 | |||
117 | // unbind the transform | ||
118 | var unbindCommand= new UnbindTransformCommand(context.Messaging, transformFile, (null == context.ExportBasePath ? null : Path.Combine(context.ExportBasePath, subStorageName)), context.IntermediateFolder); | ||
119 | var transform = unbindCommand.Execute(); | ||
120 | |||
121 | patch.SubStorages.Add(new SubStorage(subStorageName, transform)); | ||
122 | } | ||
123 | |||
124 | break; | ||
125 | } | ||
126 | } | ||
127 | } | ||
128 | |||
129 | // extract the files from the cabinets | ||
130 | // TODO: use per-transform export paths for support of multi-product patches | ||
131 | if (null != context.ExportBasePath && !context.SuppressExtractCabinets) | ||
132 | { | ||
133 | using (Database database = new Database(context.InputFilePath, OpenDatabase.ReadOnly | OpenDatabase.OpenPatchFile)) | ||
134 | { | ||
135 | foreach (SubStorage subStorage in patch.SubStorages) | ||
136 | { | ||
137 | // only patch transforms should carry files | ||
138 | if (subStorage.Name.StartsWith("#", StringComparison.Ordinal)) | ||
139 | { | ||
140 | var extractCommand = new ExtractCabinetsCommand(subStorage.Data, database, context.InputFilePath, context.ExportBasePath, context.IntermediateFolder); | ||
141 | extractCommand.Execute(); | ||
142 | } | ||
143 | } | ||
144 | } | ||
145 | } | ||
146 | |||
147 | return patch; | ||
148 | } | ||
149 | #endif | ||
150 | } | 70 | } |
151 | } | 71 | } |
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Unbind/ExtractCabinetsCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Unbind/ExtractCabinetsCommand.cs index 8f52bed9..9aa6f3d4 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Unbind/ExtractCabinetsCommand.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Unbind/ExtractCabinetsCommand.cs | |||
@@ -3,7 +3,6 @@ | |||
3 | namespace WixToolset.Core.WindowsInstaller.Unbind | 3 | namespace WixToolset.Core.WindowsInstaller.Unbind |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections; | ||
7 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
8 | using System.Globalization; | 7 | using System.Globalization; |
9 | using System.IO; | 8 | using System.IO; |
@@ -26,7 +25,7 @@ namespace WixToolset.Core.WindowsInstaller.Unbind | |||
26 | this.TreatOutputAsModule = treatOutputAsModule; | 25 | this.TreatOutputAsModule = treatOutputAsModule; |
27 | } | 26 | } |
28 | 27 | ||
29 | public string[] ExtractedFiles { get; private set; } | 28 | public Dictionary<string, MediaRow> ExtractedFileIdsWithMediaRow { get; private set; } |
30 | 29 | ||
31 | private WindowsInstallerData Output { get; } | 30 | private WindowsInstallerData Output { get; } |
32 | 31 | ||
@@ -42,47 +41,51 @@ namespace WixToolset.Core.WindowsInstaller.Unbind | |||
42 | 41 | ||
43 | public void Execute() | 42 | public void Execute() |
44 | { | 43 | { |
44 | var extractedFileIdsWithMediaRow = new Dictionary<string, MediaRow>(); | ||
45 | var databaseBasePath = Path.GetDirectoryName(this.InputFilePath); | 45 | var databaseBasePath = Path.GetDirectoryName(this.InputFilePath); |
46 | var cabinetFiles = new List<string>(); | 46 | |
47 | var embeddedCabinets = new SortedList(); | 47 | var cabinetPathsWithMediaRow = new Dictionary<string, MediaRow>(); |
48 | var embeddedCabinetNamesByDiskId = new SortedDictionary<int, string>(); | ||
49 | var embeddedCabinetRowsByDiskId = new SortedDictionary<int, MediaRow>(); | ||
48 | 50 | ||
49 | // index all of the cabinet files | 51 | // index all of the cabinet files |
50 | if (OutputType.Module == this.Output.Type || this.TreatOutputAsModule) | 52 | if (OutputType.Module == this.Output.Type || this.TreatOutputAsModule) |
51 | { | 53 | { |
52 | embeddedCabinets.Add(0, "MergeModule.CABinet"); | 54 | embeddedCabinetNamesByDiskId.Add(0, "MergeModule.CABinet"); |
53 | } | 55 | } |
54 | else if (null != this.Output.Tables["Media"]) | 56 | else if (this.Output.Tables.TryGetTable("Media", out var mediaTable)) |
55 | { | 57 | { |
56 | foreach (MediaRow mediaRow in this.Output.Tables["Media"].Rows) | 58 | foreach (var mediaRow in mediaTable.Rows.Cast<MediaRow>().Where(r => !String.IsNullOrEmpty(r.Cabinet))) |
57 | { | 59 | { |
58 | if (null != mediaRow.Cabinet) | 60 | if (OutputType.Product == this.Output.Type || |
61 | (OutputType.Transform == this.Output.Type && RowOperation.Add == mediaRow.Operation)) | ||
59 | { | 62 | { |
60 | if (OutputType.Product == this.Output.Type || | 63 | if (mediaRow.Cabinet.StartsWith("#", StringComparison.Ordinal)) |
61 | (OutputType.Transform == this.Output.Type && RowOperation.Add == mediaRow.Operation)) | ||
62 | { | 64 | { |
63 | if (mediaRow.Cabinet.StartsWith("#", StringComparison.Ordinal)) | 65 | embeddedCabinetNamesByDiskId.Add(mediaRow.DiskId, mediaRow.Cabinet.Substring(1)); |
64 | { | 66 | embeddedCabinetRowsByDiskId.Add(mediaRow.DiskId, mediaRow); |
65 | embeddedCabinets.Add(mediaRow.DiskId, mediaRow.Cabinet.Substring(1)); | 67 | } |
66 | } | 68 | else |
67 | else | 69 | { |
68 | { | 70 | cabinetPathsWithMediaRow.Add(Path.Combine(databaseBasePath, mediaRow.Cabinet), mediaRow); |
69 | cabinetFiles.Add(Path.Combine(databaseBasePath, mediaRow.Cabinet)); | ||
70 | } | ||
71 | } | 71 | } |
72 | } | 72 | } |
73 | } | 73 | } |
74 | } | 74 | } |
75 | 75 | ||
76 | // extract the embedded cabinet files from the database | 76 | // Extract any embedded cabinet files from the database. |
77 | if (0 < embeddedCabinets.Count) | 77 | if (0 < embeddedCabinetRowsByDiskId.Count) |
78 | { | 78 | { |
79 | using (var streamsView = this.Database.OpenView("SELECT `Data` FROM `_Streams` WHERE `Name` = ?")) | 79 | using (var streamsView = this.Database.OpenView("SELECT `Data` FROM `_Streams` WHERE `Name` = ?")) |
80 | { | 80 | { |
81 | foreach (int diskId in embeddedCabinets.Keys) | 81 | foreach (var diskIdWithCabinetName in embeddedCabinetNamesByDiskId) |
82 | { | 82 | { |
83 | var diskId = diskIdWithCabinetName.Key; | ||
84 | var cabinetName = diskIdWithCabinetName.Value; | ||
85 | |||
83 | using (var record = new Record(1)) | 86 | using (var record = new Record(1)) |
84 | { | 87 | { |
85 | record.SetString(1, (string)embeddedCabinets[diskId]); | 88 | record.SetString(1, cabinetName); |
86 | streamsView.Execute(record); | 89 | streamsView.Execute(record); |
87 | } | 90 | } |
88 | 91 | ||
@@ -92,15 +95,15 @@ namespace WixToolset.Core.WindowsInstaller.Unbind | |||
92 | { | 95 | { |
93 | // since the cabinets are stored in case-sensitive streams inside the msi, but the file system is not (typically) case-sensitive, | 96 | // since the cabinets are stored in case-sensitive streams inside the msi, but the file system is not (typically) case-sensitive, |
94 | // embedded cabinets must be extracted to a canonical file name (like their diskid) to ensure extraction will always work | 97 | // embedded cabinets must be extracted to a canonical file name (like their diskid) to ensure extraction will always work |
95 | var cabinetFile = Path.Combine(this.IntermediateFolder, String.Concat("Media", Path.DirectorySeparatorChar, diskId.ToString(CultureInfo.InvariantCulture), ".cab")); | 98 | var cabinetPath = Path.Combine(this.IntermediateFolder, "Media", diskId.ToString(CultureInfo.InvariantCulture), ".cab"); |
96 | 99 | ||
97 | // ensure the parent directory exists | 100 | // ensure the parent directory exists |
98 | Directory.CreateDirectory(Path.GetDirectoryName(cabinetFile)); | 101 | Directory.CreateDirectory(Path.GetDirectoryName(cabinetPath)); |
99 | 102 | ||
100 | using (var fs = File.Create(cabinetFile)) | 103 | using (var fs = File.Create(cabinetPath)) |
101 | { | 104 | { |
102 | int bytesRead; | 105 | int bytesRead; |
103 | var buffer = new byte[512]; | 106 | var buffer = new byte[4096]; |
104 | 107 | ||
105 | while (0 != (bytesRead = record.GetStream(1, buffer, buffer.Length))) | 108 | while (0 != (bytesRead = record.GetStream(1, buffer, buffer.Length))) |
106 | { | 109 | { |
@@ -108,7 +111,8 @@ namespace WixToolset.Core.WindowsInstaller.Unbind | |||
108 | } | 111 | } |
109 | } | 112 | } |
110 | 113 | ||
111 | cabinetFiles.Add(cabinetFile); | 114 | embeddedCabinetRowsByDiskId.TryGetValue(diskId, out var cabinetMediaRow); |
115 | cabinetPathsWithMediaRow.Add(cabinetPath, cabinetMediaRow); | ||
112 | } | 116 | } |
113 | else | 117 | else |
114 | { | 118 | { |
@@ -119,29 +123,34 @@ namespace WixToolset.Core.WindowsInstaller.Unbind | |||
119 | } | 123 | } |
120 | } | 124 | } |
121 | 125 | ||
122 | // extract the cabinet files | 126 | // Extract files from any available cabinets. |
123 | if (0 < cabinetFiles.Count) | 127 | if (0 < cabinetPathsWithMediaRow.Count) |
124 | { | 128 | { |
125 | // ensure the directory exists or extraction will fail | ||
126 | Directory.CreateDirectory(this.ExportBasePath); | 129 | Directory.CreateDirectory(this.ExportBasePath); |
127 | 130 | ||
128 | foreach (var cabinetFile in cabinetFiles) | 131 | foreach (var cabinetPathWithMediaRow in cabinetPathsWithMediaRow) |
129 | { | 132 | { |
133 | var cabinetPath = cabinetPathWithMediaRow.Key; | ||
134 | var cabinetMediaRow = cabinetPathWithMediaRow.Value; | ||
135 | |||
130 | try | 136 | try |
131 | { | 137 | { |
132 | var cabinet = new Cabinet(cabinetFile); | 138 | var cabinet = new Cabinet(cabinetPath); |
133 | this.ExtractedFiles = cabinet.Extract(this.ExportBasePath).ToArray(); | 139 | var cabinetFilesExtracted = cabinet.Extract(this.ExportBasePath); |
140 | |||
141 | foreach (var extractedFile in cabinetFilesExtracted) | ||
142 | { | ||
143 | extractedFileIdsWithMediaRow.Add(extractedFile, cabinetMediaRow); | ||
144 | } | ||
134 | } | 145 | } |
135 | catch (FileNotFoundException) | 146 | catch (FileNotFoundException) |
136 | { | 147 | { |
137 | throw new WixException(ErrorMessages.FileNotFound(new SourceLineNumber(this.InputFilePath), cabinetFile)); | 148 | throw new WixException(ErrorMessages.FileNotFound(new SourceLineNumber(this.InputFilePath), cabinetPath)); |
138 | } | 149 | } |
139 | } | 150 | } |
140 | } | 151 | } |
141 | else | 152 | |
142 | { | 153 | this.ExtractedFileIdsWithMediaRow = extractedFileIdsWithMediaRow; |
143 | this.ExtractedFiles = new string[0]; | ||
144 | } | ||
145 | } | 154 | } |
146 | } | 155 | } |
147 | } | 156 | } |
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Unbind/UnbindDatabaseCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Unbind/UnbindDatabaseCommand.cs index c1fb7f12..7bbbbd76 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Unbind/UnbindDatabaseCommand.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Unbind/UnbindDatabaseCommand.cs | |||
@@ -5,29 +5,35 @@ namespace WixToolset.Core.WindowsInstaller.Unbind | |||
5 | using System; | 5 | using System; |
6 | using System.Collections; | 6 | using System.Collections; |
7 | using System.Collections.Generic; | 7 | using System.Collections.Generic; |
8 | using System.ComponentModel; | ||
8 | using System.Globalization; | 9 | using System.Globalization; |
9 | using System.IO; | 10 | using System.IO; |
11 | using System.Linq; | ||
10 | using System.Text.RegularExpressions; | 12 | using System.Text.RegularExpressions; |
11 | using WixToolset.Core.Native.Msi; | 13 | using WixToolset.Core.Native.Msi; |
12 | using WixToolset.Data; | 14 | using WixToolset.Data; |
13 | using WixToolset.Data.WindowsInstaller; | 15 | using WixToolset.Data.WindowsInstaller; |
16 | using WixToolset.Data.WindowsInstaller.Rows; | ||
17 | using WixToolset.Extensibility.Data; | ||
14 | using WixToolset.Extensibility.Services; | 18 | using WixToolset.Extensibility.Services; |
15 | 19 | ||
16 | internal class UnbindDatabaseCommand | 20 | internal class UnbindDatabaseCommand |
17 | { | 21 | { |
18 | private List<string> exportedFiles; | 22 | private static readonly Regex Modularization = new Regex(@"\.[0-9A-Fa-f]{8}_[0-9A-Fa-f]{4}_[0-9A-Fa-f]{4}_[0-9A-Fa-f]{4}_[0-9A-Fa-f]{12}"); |
19 | 23 | ||
20 | public UnbindDatabaseCommand(IMessaging messaging, IBackendHelper backendHelper, Database database, string databasePath, OutputType outputType, string exportBasePath, string intermediateFolder, bool isAdminImage, bool suppressDemodularization, bool skipSummaryInfo) | 24 | private int sectionCount; |
25 | |||
26 | public UnbindDatabaseCommand(IMessaging messaging, IBackendHelper backendHelper, IPathResolver pathResolver, string databasePath, OutputType outputType, string exportBasePath, string extractFilesFolder, string intermediateFolder, bool enableDemodularization, bool skipSummaryInfo) | ||
21 | { | 27 | { |
22 | this.Messaging = messaging; | 28 | this.Messaging = messaging; |
23 | this.BackendHelper = backendHelper; | 29 | this.BackendHelper = backendHelper; |
24 | this.Database = database; | 30 | this.PathResolver = pathResolver; |
25 | this.DatabasePath = databasePath; | 31 | this.DatabasePath = databasePath; |
26 | this.OutputType = outputType; | 32 | this.OutputType = outputType; |
27 | this.ExportBasePath = exportBasePath; | 33 | this.ExportBasePath = exportBasePath; |
34 | this.ExtractFilesFolder = extractFilesFolder; | ||
28 | this.IntermediateFolder = intermediateFolder; | 35 | this.IntermediateFolder = intermediateFolder; |
29 | this.IsAdminImage = isAdminImage; | 36 | this.EnableDemodularization = enableDemodularization; |
30 | this.SuppressDemodularization = suppressDemodularization; | ||
31 | this.SkipSummaryInfo = skipSummaryInfo; | 37 | this.SkipSummaryInfo = skipSummaryInfo; |
32 | 38 | ||
33 | this.TableDefinitions = new TableDefinitionCollection(WindowsInstallerTableDefinitions.All); | 39 | this.TableDefinitions = new TableDefinitionCollection(WindowsInstallerTableDefinitions.All); |
@@ -37,7 +43,9 @@ namespace WixToolset.Core.WindowsInstaller.Unbind | |||
37 | 43 | ||
38 | public IBackendHelper BackendHelper { get; } | 44 | public IBackendHelper BackendHelper { get; } |
39 | 45 | ||
40 | public Database Database { get; } | 46 | private IPathResolver PathResolver { get; } |
47 | |||
48 | private Database Database { get; set; } | ||
41 | 49 | ||
42 | public string DatabasePath { get; } | 50 | public string DatabasePath { get; } |
43 | 51 | ||
@@ -45,73 +53,91 @@ namespace WixToolset.Core.WindowsInstaller.Unbind | |||
45 | 53 | ||
46 | public string ExportBasePath { get; } | 54 | public string ExportBasePath { get; } |
47 | 55 | ||
48 | public string IntermediateFolder { get; } | 56 | public string ExtractFilesFolder { get; } |
49 | 57 | ||
50 | public bool IsAdminImage { get; } | 58 | public string IntermediateFolder { get; } |
51 | 59 | ||
52 | public bool SuppressDemodularization { get; } | 60 | public bool EnableDemodularization { get; } |
53 | 61 | ||
54 | public bool SkipSummaryInfo { get; } | 62 | public bool SkipSummaryInfo { get; } |
55 | 63 | ||
56 | public TableDefinitionCollection TableDefinitions { get; } | 64 | public TableDefinitionCollection TableDefinitions { get; } |
57 | 65 | ||
58 | public IEnumerable<string> ExportedFiles => this.exportedFiles; | 66 | public bool AdminImage { get; private set; } |
59 | 67 | ||
60 | private int SectionCount { get; set; } | 68 | public IEnumerable<string> ExportedFiles { get; private set; } |
61 | 69 | ||
62 | public WindowsInstallerData Execute() | 70 | public WindowsInstallerData Execute() |
63 | { | 71 | { |
64 | this.exportedFiles = new List<string>(); | 72 | var adminImage = false; |
73 | var exportedFiles = new List<string>(); | ||
65 | 74 | ||
66 | string modularizationGuid = null; | 75 | var output = new WindowsInstallerData(new SourceLineNumber(this.DatabasePath)) |
67 | var output = new WindowsInstallerData(new SourceLineNumber(this.DatabasePath)); | 76 | { |
68 | View validationView = null; | 77 | Type = this.OutputType |
78 | }; | ||
79 | |||
80 | try | ||
81 | { | ||
82 | using (var database = new Database(this.DatabasePath, OpenDatabase.ReadOnly)) | ||
83 | { | ||
84 | this.Database = database; | ||
69 | 85 | ||
70 | // set the output type | 86 | Directory.CreateDirectory(this.IntermediateFolder); |
71 | output.Type = this.OutputType; | ||
72 | 87 | ||
73 | Directory.CreateDirectory(this.IntermediateFolder); | 88 | output.Codepage = this.GetCodePage(); |
74 | 89 | ||
75 | // get the codepage | 90 | var modularizationGuid = this.ProcessTables(output, exportedFiles); |
76 | this.Database.Export("_ForceCodepage", this.IntermediateFolder, "_ForceCodepage.idt"); | ||
77 | using (var sr = File.OpenText(Path.Combine(this.IntermediateFolder, "_ForceCodepage.idt"))) | ||
78 | { | ||
79 | string line; | ||
80 | 91 | ||
81 | while (null != (line = sr.ReadLine())) | 92 | var summaryInfo = this.ProcessSummaryInfo(output, modularizationGuid); |
82 | { | ||
83 | var data = line.Split('\t'); | ||
84 | 93 | ||
85 | if (2 == data.Length) | 94 | this.UpdateUnrealFileColumns(this.DatabasePath, output, summaryInfo, exportedFiles); |
86 | { | 95 | |
87 | output.Codepage = Convert.ToInt32(data[0], CultureInfo.InvariantCulture); | 96 | this.GenerateSectionIds(output); |
88 | } | ||
89 | } | 97 | } |
90 | } | 98 | } |
91 | 99 | catch (Win32Exception e) | |
92 | // get the summary information table if it exists; it won't if unbinding a transform | ||
93 | if (!this.SkipSummaryInfo) | ||
94 | { | 100 | { |
95 | using (var summaryInformation = new SummaryInformation(this.Database)) | 101 | if (0x6E == e.NativeErrorCode) // ERROR_OPEN_FAILED |
96 | { | 102 | { |
97 | var table = new Table(this.TableDefinitions["_SummaryInformation"]); | 103 | throw new WixException(ErrorMessages.OpenDatabaseFailed(this.DatabasePath)); |
104 | } | ||
98 | 105 | ||
99 | for (var i = 1; 19 >= i; i++) | 106 | throw; |
100 | { | 107 | } |
101 | var value = summaryInformation.GetProperty(i); | ||
102 | 108 | ||
103 | if (0 < value.Length) | 109 | this.AdminImage = adminImage; |
104 | { | 110 | this.ExportedFiles = exportedFiles; |
105 | var row = table.CreateRow(output.SourceLineNumbers); | ||
106 | row[0] = i; | ||
107 | row[1] = value; | ||
108 | } | ||
109 | } | ||
110 | 111 | ||
111 | output.Tables.Add(table); | 112 | return output; |
113 | } | ||
114 | |||
115 | private int GetCodePage() | ||
116 | { | ||
117 | var codepage = 0; | ||
118 | |||
119 | this.Database.Export("_ForceCodepage", this.IntermediateFolder, "_ForceCodepage.idt"); | ||
120 | |||
121 | var lines = File.ReadAllLines(Path.Combine(this.IntermediateFolder, "_ForceCodepage.idt")); | ||
122 | |||
123 | if (lines.Length == 3) | ||
124 | { | ||
125 | var data = lines[2].Split('\t'); | ||
126 | |||
127 | if (2 == data.Length) | ||
128 | { | ||
129 | codepage = Convert.ToInt32(data[0], CultureInfo.InvariantCulture); | ||
112 | } | 130 | } |
113 | } | 131 | } |
114 | 132 | ||
133 | return codepage; | ||
134 | } | ||
135 | |||
136 | private string ProcessTables(WindowsInstallerData output, List<string> exportedFiles) | ||
137 | { | ||
138 | View validationView = null; | ||
139 | string modularizationGuid = null; | ||
140 | |||
115 | try | 141 | try |
116 | { | 142 | { |
117 | // open a view on the validation table if it exists | 143 | // open a view on the validation table if it exists |
@@ -127,7 +153,7 @@ namespace WixToolset.Core.WindowsInstaller.Unbind | |||
127 | { | 153 | { |
128 | var tableName = tableRecord.GetString(1); | 154 | var tableName = tableRecord.GetString(1); |
129 | 155 | ||
130 | using (var tableView = this.Database.OpenExecuteView(String.Format(CultureInfo.InvariantCulture, "SELECT * FROM `{0}`", tableName))) | 156 | using (var tableView = this.Database.OpenExecuteView($"SELECT * FROM `{tableName}`")) |
131 | { | 157 | { |
132 | var tableDefinition = this.GetTableDefinition(tableName, tableView, validationView); | 158 | var tableDefinition = this.GetTableDefinition(tableName, tableView, validationView); |
133 | var table = new Table(tableDefinition); | 159 | var table = new Table(tableDefinition); |
@@ -154,16 +180,8 @@ namespace WixToolset.Core.WindowsInstaller.Unbind | |||
154 | switch (row.Fields[i].Column.Type) | 180 | switch (row.Fields[i].Column.Type) |
155 | { | 181 | { |
156 | case ColumnType.Number: | 182 | case ColumnType.Number: |
157 | var success = false; | ||
158 | var intValue = rowRecord.GetInteger(i + 1); | 183 | var intValue = rowRecord.GetInteger(i + 1); |
159 | if (row.Fields[i].Column.IsLocalizable) | 184 | var success = row.Fields[i].Column.IsLocalizable ? row.BestEffortSetField(i, Convert.ToString(intValue, CultureInfo.InvariantCulture)) : row.BestEffortSetField(i, intValue); |
160 | { | ||
161 | success = row.BestEffortSetField(i, Convert.ToString(intValue, CultureInfo.InvariantCulture)); | ||
162 | } | ||
163 | else | ||
164 | { | ||
165 | success = row.BestEffortSetField(i, intValue); | ||
166 | } | ||
167 | 185 | ||
168 | if (!success) | 186 | if (!success) |
169 | { | 187 | { |
@@ -171,20 +189,18 @@ namespace WixToolset.Core.WindowsInstaller.Unbind | |||
171 | } | 189 | } |
172 | break; | 190 | break; |
173 | case ColumnType.Object: | 191 | case ColumnType.Object: |
174 | var sourceFile = "FILE NOT EXPORTED"; | 192 | var source = "FILE NOT EXPORTED"; |
175 | 193 | ||
176 | if (null != this.ExportBasePath) | 194 | if (null != this.ExportBasePath) |
177 | { | 195 | { |
178 | var relativeSourceFile = Path.Combine(tableName, row.GetPrimaryKey('.')); | 196 | source = Path.Combine(this.ExportBasePath, tableName, row.GetPrimaryKey('.')); |
179 | sourceFile = Path.Combine(this.ExportBasePath, relativeSourceFile); | ||
180 | 197 | ||
181 | // ensure the parent directory exists | 198 | Directory.CreateDirectory(Path.Combine(this.ExportBasePath, tableName)); |
182 | System.IO.Directory.CreateDirectory(Path.Combine(this.ExportBasePath, tableName)); | ||
183 | 199 | ||
184 | using (var fs = System.IO.File.Create(sourceFile)) | 200 | using (var fs = File.Create(source)) |
185 | { | 201 | { |
186 | int bytesRead; | 202 | int bytesRead; |
187 | var buffer = new byte[512]; | 203 | var buffer = new byte[4096]; |
188 | 204 | ||
189 | while (0 != (bytesRead = rowRecord.GetStream(i + 1, buffer, buffer.Length))) | 205 | while (0 != (bytesRead = rowRecord.GetStream(i + 1, buffer, buffer.Length))) |
190 | { | 206 | { |
@@ -192,10 +208,10 @@ namespace WixToolset.Core.WindowsInstaller.Unbind | |||
192 | } | 208 | } |
193 | } | 209 | } |
194 | 210 | ||
195 | this.exportedFiles.Add(sourceFile); | 211 | exportedFiles.Add(source); |
196 | } | 212 | } |
197 | 213 | ||
198 | row[i] = sourceFile; | 214 | row[i] = source; |
199 | break; | 215 | break; |
200 | default: | 216 | default: |
201 | var value = rowRecord.GetString(i + 1); | 217 | var value = rowRecord.GetString(i + 1); |
@@ -203,27 +219,26 @@ namespace WixToolset.Core.WindowsInstaller.Unbind | |||
203 | switch (row.Fields[i].Column.Category) | 219 | switch (row.Fields[i].Column.Category) |
204 | { | 220 | { |
205 | case ColumnCategory.Guid: | 221 | case ColumnCategory.Guid: |
206 | value = value.ToUpper(CultureInfo.InvariantCulture); | 222 | value = value.ToUpperInvariant(); |
207 | break; | 223 | break; |
208 | } | 224 | } |
209 | 225 | ||
210 | // de-modularize | 226 | // De-modularize |
211 | if (!this.SuppressDemodularization && OutputType.Module == output.Type && ColumnModularizeType.None != row.Fields[i].Column.ModularizeType) | 227 | if (this.EnableDemodularization && OutputType.Module == output.Type && ColumnModularizeType.None != row.Fields[i].Column.ModularizeType) |
212 | { | 228 | { |
213 | var modularization = new Regex(@"\.[0-9A-Fa-f]{8}_[0-9A-Fa-f]{4}_[0-9A-Fa-f]{4}_[0-9A-Fa-f]{4}_[0-9A-Fa-f]{12}"); | ||
214 | |||
215 | if (null == modularizationGuid) | 229 | if (null == modularizationGuid) |
216 | { | 230 | { |
217 | var match = modularization.Match(value); | 231 | var match = Modularization.Match(value); |
218 | if (match.Success) | 232 | if (match.Success) |
219 | { | 233 | { |
220 | modularizationGuid = String.Concat('{', match.Value.Substring(1).Replace('_', '-'), '}'); | 234 | modularizationGuid = String.Concat('{', match.Value.Substring(1).Replace('_', '-'), '}'); |
221 | } | 235 | } |
222 | } | 236 | } |
223 | 237 | ||
224 | value = modularization.Replace(value, String.Empty); | 238 | value = Modularization.Replace(value, String.Empty); |
225 | } | 239 | } |
226 | 240 | ||
241 | #if TODO_MOVE_TO_DECOMPILER | ||
227 | // escape "$(" for the preprocessor | 242 | // escape "$(" for the preprocessor |
228 | value = value.Replace("$(", "$$("); | 243 | value = value.Replace("$(", "$$("); |
229 | 244 | ||
@@ -234,6 +249,7 @@ namespace WixToolset.Core.WindowsInstaller.Unbind | |||
234 | //{ | 249 | //{ |
235 | // value = value.Insert(matches[j].Index, "!"); | 250 | // value = value.Insert(matches[j].Index, "!"); |
236 | //} | 251 | //} |
252 | #endif | ||
237 | 253 | ||
238 | row[i] = value; | 254 | row[i] = value; |
239 | break; | 255 | break; |
@@ -249,33 +265,54 @@ namespace WixToolset.Core.WindowsInstaller.Unbind | |||
249 | } | 265 | } |
250 | finally | 266 | finally |
251 | { | 267 | { |
252 | if (null != validationView) | 268 | validationView?.Close(); |
253 | { | ||
254 | validationView.Close(); | ||
255 | } | ||
256 | } | 269 | } |
257 | 270 | ||
258 | // set the modularization guid as the PackageCode | 271 | return modularizationGuid; |
259 | if (null != modularizationGuid) | 272 | } |
260 | { | ||
261 | var table = output.Tables["_SummaryInformation"]; | ||
262 | 273 | ||
263 | foreach (var row in table.Rows) | 274 | private SummaryInformationBits ProcessSummaryInfo(WindowsInstallerData output, string modularizationGuid) |
275 | { | ||
276 | var result = new SummaryInformationBits(); | ||
277 | |||
278 | if (!this.SkipSummaryInfo) | ||
279 | { | ||
280 | using (var summaryInformation = new SummaryInformation(this.Database)) | ||
264 | { | 281 | { |
265 | if (9 == (int)row[0]) // PID_REVNUMBER | 282 | var table = new Table(this.TableDefinitions["_SummaryInformation"]); |
283 | |||
284 | for (var i = 1; 19 >= i; i++) | ||
266 | { | 285 | { |
267 | row[1] = modularizationGuid; | 286 | var value = summaryInformation.GetProperty(i); |
287 | |||
288 | // Set the modularization guid as the PackageCode, for merge modules. | ||
289 | if (i == (int)SummaryInformation.Package.PackageCode && !String.IsNullOrEmpty(modularizationGuid)) | ||
290 | { | ||
291 | var row = table.CreateRow(output.SourceLineNumbers); | ||
292 | row[0] = i; | ||
293 | row[1] = modularizationGuid; | ||
294 | } | ||
295 | else if (0 < value.Length) | ||
296 | { | ||
297 | var row = table.CreateRow(output.SourceLineNumbers); | ||
298 | row[0] = i; | ||
299 | row[1] = value; | ||
300 | |||
301 | if (i == (int)SummaryInformation.Package.FileAndElevatedFlags) | ||
302 | { | ||
303 | var wordcount = Convert.ToInt32(value, CultureInfo.InvariantCulture); | ||
304 | result.LongFilenames = (wordcount & 0x1) != 0x1; | ||
305 | result.Compressed = (wordcount & 0x2) == 0x2; | ||
306 | result.AdminImage = (wordcount & 0x4) == 0x4; | ||
307 | } | ||
308 | } | ||
268 | } | 309 | } |
269 | } | ||
270 | } | ||
271 | 310 | ||
272 | if (this.IsAdminImage) | 311 | output.Tables.Add(table); |
273 | { | 312 | } |
274 | this.GenerateWixFileTable(this.DatabasePath, output); | ||
275 | this.GenerateSectionIds(output); | ||
276 | } | 313 | } |
277 | 314 | ||
278 | return output; | 315 | return result; |
279 | } | 316 | } |
280 | 317 | ||
281 | private TableDefinition GetTableDefinition(string tableName, View tableView, View validationView) | 318 | private TableDefinition GetTableDefinition(string tableName, View tableView, View validationView) |
@@ -310,10 +347,6 @@ namespace WixToolset.Core.WindowsInstaller.Unbind | |||
310 | var columnName = columnNameRecord.GetString(i); | 347 | var columnName = columnNameRecord.GetString(i); |
311 | var idtType = columnTypeRecord.GetString(i); | 348 | var idtType = columnTypeRecord.GetString(i); |
312 | 349 | ||
313 | ColumnType columnType; | ||
314 | int length; | ||
315 | bool nullable; | ||
316 | |||
317 | var columnCategory = ColumnCategory.Unknown; | 350 | var columnCategory = ColumnCategory.Unknown; |
318 | var columnModularizeType = ColumnModularizeType.None; | 351 | var columnModularizeType = ColumnModularizeType.None; |
319 | var primary = tablePrimaryKeys.Contains(columnName); | 352 | var primary = tablePrimaryKeys.Contains(columnName); |
@@ -326,7 +359,8 @@ namespace WixToolset.Core.WindowsInstaller.Unbind | |||
326 | string description = null; | 359 | string description = null; |
327 | 360 | ||
328 | // get the column type, length, and whether its nullable | 361 | // get the column type, length, and whether its nullable |
329 | switch (Char.ToLower(idtType[0], CultureInfo.InvariantCulture)) | 362 | ColumnType columnType; |
363 | switch (Char.ToLowerInvariant(idtType[0])) | ||
330 | { | 364 | { |
331 | case 'i': | 365 | case 'i': |
332 | columnType = ColumnType.Number; | 366 | columnType = ColumnType.Number; |
@@ -345,8 +379,8 @@ namespace WixToolset.Core.WindowsInstaller.Unbind | |||
345 | columnType = ColumnType.Unknown; | 379 | columnType = ColumnType.Unknown; |
346 | break; | 380 | break; |
347 | } | 381 | } |
348 | length = Convert.ToInt32(idtType.Substring(1), CultureInfo.InvariantCulture); | 382 | var length = Convert.ToInt32(idtType.Substring(1), CultureInfo.InvariantCulture); |
349 | nullable = Char.IsUpper(idtType[0]); | 383 | var nullable = Char.IsUpper(idtType[0]); |
350 | 384 | ||
351 | // try to get validation information | 385 | // try to get validation information |
352 | if (null != validationView) | 386 | if (null != validationView) |
@@ -385,11 +419,7 @@ namespace WixToolset.Core.WindowsInstaller.Unbind | |||
385 | // convert category to ColumnCategory | 419 | // convert category to ColumnCategory |
386 | if (null != category) | 420 | if (null != category) |
387 | { | 421 | { |
388 | try | 422 | if (!Enum.TryParse(category, true, out columnCategory)) |
389 | { | ||
390 | columnCategory = (ColumnCategory)Enum.Parse(typeof(ColumnCategory), category, true); | ||
391 | } | ||
392 | catch (ArgumentException) | ||
393 | { | 423 | { |
394 | columnCategory = ColumnCategory.Unknown; | 424 | columnCategory = ColumnCategory.Unknown; |
395 | } | 425 | } |
@@ -427,67 +457,103 @@ namespace WixToolset.Core.WindowsInstaller.Unbind | |||
427 | return new TableDefinition(tableName, null, columns, false); | 457 | return new TableDefinition(tableName, null, columns, false); |
428 | } | 458 | } |
429 | 459 | ||
430 | /// <summary> | 460 | private void UpdateUnrealFileColumns(string databaseFile, WindowsInstallerData output, SummaryInformationBits summaryInformation, List<string> exportedFiles) |
431 | /// Generates the WixFile table based on a path to an admin image msi and an Output. | ||
432 | /// </summary> | ||
433 | /// <param name="databaseFile">The path to the msi database file in an admin image.</param> | ||
434 | /// <param name="output">The Output that represents the msi database.</param> | ||
435 | private void GenerateWixFileTable(string databaseFile, WindowsInstallerData output) | ||
436 | { | 461 | { |
437 | throw new NotImplementedException(); | 462 | var fileRows = output.Tables["File"]?.Rows; |
438 | #if TODO_FIX_UNBINDING_FILES | ||
439 | var adminRootPath = Path.GetDirectoryName(databaseFile); | ||
440 | 463 | ||
441 | var componentDirectoryIndex = new Hashtable(); | 464 | if (fileRows == null || fileRows.Count == 0) |
442 | var componentTable = output.Tables["Component"]; | ||
443 | foreach (var row in componentTable.Rows) | ||
444 | { | 465 | { |
445 | componentDirectoryIndex.Add(row[0], row[2]); | 466 | return; |
446 | } | 467 | } |
447 | 468 | ||
469 | this.UpdateFileRowsDiskId(output, fileRows); | ||
470 | |||
471 | this.UpdateFileRowsSource(databaseFile, output, fileRows, summaryInformation, exportedFiles); | ||
472 | } | ||
473 | |||
474 | private void UpdateFileRowsDiskId(WindowsInstallerData output, IList<Row> fileRows) | ||
475 | { | ||
476 | var mediaRows = output.Tables["Media"]?.Rows?.Cast<MediaRow>()?.OrderBy(r => r.LastSequence)?.ToList(); | ||
477 | |||
478 | var lastMediaRowIndex = 0; | ||
479 | var lastMediaRow = (mediaRows == null || mediaRows.Count == 0) ? null : mediaRows[lastMediaRowIndex]; | ||
480 | |||
481 | foreach (var fileRow in fileRows.Cast<FileRow>()?.OrderBy(r => r.Sequence)) | ||
482 | { | ||
483 | while (lastMediaRow != null && fileRow.Sequence > lastMediaRow.LastSequence) | ||
484 | { | ||
485 | ++lastMediaRowIndex; | ||
486 | |||
487 | lastMediaRow = lastMediaRowIndex < mediaRows.Count ? mediaRows[lastMediaRowIndex] : null; | ||
488 | } | ||
489 | |||
490 | fileRow.DiskId = lastMediaRow?.DiskId ?? 1; | ||
491 | } | ||
492 | } | ||
493 | |||
494 | private void UpdateFileRowsSource(string databasePath, WindowsInstallerData output, IList<Row> fileRows, SummaryInformationBits summaryInformation, List<string> exportedFiles) | ||
495 | { | ||
496 | var databaseFolder = Path.GetDirectoryName(databasePath); | ||
497 | |||
498 | var componentDirectoryIndex = output.Tables["Component"].Rows.Cast<ComponentRow>().ToDictionary(r => r.Component, r => r.Directory); | ||
499 | |||
448 | // Index full source paths for all directories | 500 | // Index full source paths for all directories |
449 | var directoryDirectoryParentIndex = new Hashtable(); | 501 | var directories = new Dictionary<string, IResolvedDirectory>(); |
450 | var directoryFullPathIndex = new Hashtable(); | 502 | |
451 | var directorySourceNameIndex = new Hashtable(); | ||
452 | var directoryTable = output.Tables["Directory"]; | 503 | var directoryTable = output.Tables["Directory"]; |
453 | foreach (var row in directoryTable.Rows) | 504 | foreach (var row in directoryTable.Rows) |
454 | { | 505 | { |
455 | directoryDirectoryParentIndex.Add(row[0], row[1]); | 506 | var sourceName = this.BackendHelper.GetMsiFileName(row.FieldAsString(2), source: true, longName: summaryInformation.LongFilenames); |
456 | if (null == row[1]) | 507 | var resolvedDirectory = this.BackendHelper.CreateResolvedDirectory(row.FieldAsString(1), sourceName); |
457 | { | 508 | |
458 | directoryFullPathIndex.Add(row[0], adminRootPath); | 509 | directories.Add(row.FieldAsString(0), resolvedDirectory); |
459 | } | ||
460 | else | ||
461 | { | ||
462 | directorySourceNameIndex.Add(row[0], GetAdminSourceName((string)row[2])); | ||
463 | } | ||
464 | } | 510 | } |
465 | 511 | ||
466 | foreach (DictionaryEntry directoryEntry in directoryDirectoryParentIndex) | 512 | if (summaryInformation.AdminImage) |
467 | { | 513 | { |
468 | if (!directoryFullPathIndex.ContainsKey(directoryEntry.Key)) | 514 | foreach (var fileRow in fileRows.Cast<FileRow>()) |
469 | { | 515 | { |
470 | this.GetAdminFullPath((string)directoryEntry.Key, directoryDirectoryParentIndex, directorySourceNameIndex, directoryFullPathIndex); | 516 | var directoryId = componentDirectoryIndex[fileRow.Component]; |
517 | var relativeFileLayoutPath = this.PathResolver.GetFileSourcePath(directories, directoryId, fileRow.FileName, compressed: false, useLongName: summaryInformation.LongFilenames); | ||
518 | |||
519 | fileRow.Source = Path.Combine(databaseFolder, relativeFileLayoutPath); | ||
471 | } | 520 | } |
472 | } | 521 | } |
473 | 522 | else | |
474 | var fileTable = output.Tables["File"]; | ||
475 | var wixFileTable = output.EnsureTable(this.TableDefinitions["WixFile"]); | ||
476 | foreach (var row in fileTable.Rows) | ||
477 | { | 523 | { |
478 | var wixFileRow = new WixFileRow(null, this.TableDefinitions["WixFile"]); | 524 | var extractedFileIds = new HashSet<string>(); |
479 | wixFileRow.File = (string)row[0]; | ||
480 | wixFileRow.Directory = (string)componentDirectoryIndex[(string)row[1]]; | ||
481 | wixFileRow.Source = Path.Combine((string)directoryFullPathIndex[wixFileRow.Directory], GetAdminSourceName((string)row[2])); | ||
482 | 525 | ||
483 | if (!File.Exists(wixFileRow.Source)) | 526 | if (!String.IsNullOrEmpty(this.ExtractFilesFolder)) |
484 | { | 527 | { |
485 | throw new WixException(ErrorMessages.WixFileNotFound(wixFileRow.Source)); | 528 | var extractCommand = new ExtractCabinetsCommand(output, this.Database, this.DatabasePath, this.ExtractFilesFolder, this.IntermediateFolder); |
529 | extractCommand.Execute(); | ||
530 | |||
531 | extractedFileIds = new HashSet<string>(extractCommand.ExtractedFileIdsWithMediaRow.Keys, StringComparer.OrdinalIgnoreCase); | ||
532 | exportedFiles.AddRange(extractedFileIds); | ||
486 | } | 533 | } |
487 | 534 | ||
488 | wixFileTable.Rows.Add(wixFileRow); | 535 | foreach (var fileRow in fileRows.Cast<FileRow>()) |
536 | { | ||
537 | var source = "FILE NOT EXPORTED"; | ||
538 | |||
539 | if (fileRow.Compressed == YesNoType.Yes || (fileRow.Compressed == YesNoType.NotSet && summaryInformation.Compressed)) | ||
540 | { | ||
541 | if (extractedFileIds.Contains(fileRow.File)) | ||
542 | { | ||
543 | source = Path.Combine(this.ExtractFilesFolder, fileRow.File); | ||
544 | } | ||
545 | } | ||
546 | else | ||
547 | { | ||
548 | var directoryId = componentDirectoryIndex[fileRow.Component]; | ||
549 | var relativeFileLayoutPath = this.PathResolver.GetFileSourcePath(directories, directoryId, fileRow.FileName, compressed: false, useLongName: summaryInformation.LongFilenames); | ||
550 | |||
551 | source = Path.Combine(databaseFolder, relativeFileLayoutPath); | ||
552 | } | ||
553 | |||
554 | fileRow.Source = source; | ||
555 | } | ||
489 | } | 556 | } |
490 | #endif | ||
491 | } | 557 | } |
492 | 558 | ||
493 | /// <summary> | 559 | /// <summary> |
@@ -620,7 +686,6 @@ namespace WixToolset.Core.WindowsInstaller.Unbind | |||
620 | { | 686 | { |
621 | switch (table.Name) | 687 | switch (table.Name) |
622 | { | 688 | { |
623 | case "WixFile": | ||
624 | case "MsiFileHash": | 689 | case "MsiFileHash": |
625 | ConnectTableToSection(table, fileSectionIdIndex, 0); | 690 | ConnectTableToSection(table, fileSectionIdIndex, 0); |
626 | break; | 691 | break; |
@@ -699,7 +764,7 @@ namespace WixToolset.Core.WindowsInstaller.Unbind | |||
699 | } | 764 | } |
700 | } | 765 | } |
701 | 766 | ||
702 | // Now pass the output to each unbinder extension to allow them to analyze the output and determine thier proper section ids. | 767 | // Now pass the output to each unbinder extension to allow them to analyze the output and determine their proper section ids. |
703 | //foreach (IUnbinderExtension extension in this.unbinderExtensions) | 768 | //foreach (IUnbinderExtension extension in this.unbinderExtensions) |
704 | //{ | 769 | //{ |
705 | // extension.GenerateSectionIds(output); | 770 | // extension.GenerateSectionIds(output); |
@@ -711,19 +776,22 @@ namespace WixToolset.Core.WindowsInstaller.Unbind | |||
711 | /// </summary> | 776 | /// </summary> |
712 | /// <param name="table">The table to add sections to.</param> | 777 | /// <param name="table">The table to add sections to.</param> |
713 | /// <param name="rowPrimaryKeyIndex">The index of the column which is used by other tables to reference this table.</param> | 778 | /// <param name="rowPrimaryKeyIndex">The index of the column which is used by other tables to reference this table.</param> |
714 | /// <returns>A Hashtable containing the tables key for each row paired with its assigned section id.</returns> | 779 | /// <returns>A dictionary containing the tables key for each row paired with its assigned section id.</returns> |
715 | private Hashtable AssignSectionIdsToTable(Table table, int rowPrimaryKeyIndex) | 780 | private Dictionary<string, string> AssignSectionIdsToTable(Table table, int rowPrimaryKeyIndex) |
716 | { | 781 | { |
717 | var hashtable = new Hashtable(); | 782 | var primaryKeyToSectionId = new Dictionary<string, string>(); |
783 | |||
718 | if (null != table) | 784 | if (null != table) |
719 | { | 785 | { |
720 | foreach (var row in table.Rows) | 786 | foreach (var row in table.Rows) |
721 | { | 787 | { |
722 | row.SectionId = this.GetNewSectionId(); | 788 | row.SectionId = this.GetNewSectionId(); |
723 | hashtable.Add(row[rowPrimaryKeyIndex], row.SectionId); | 789 | |
790 | primaryKeyToSectionId.Add(row.FieldAsString(rowPrimaryKeyIndex), row.SectionId); | ||
724 | } | 791 | } |
725 | } | 792 | } |
726 | return hashtable; | 793 | |
794 | return primaryKeyToSectionId; | ||
727 | } | 795 | } |
728 | 796 | ||
729 | /// <summary> | 797 | /// <summary> |
@@ -732,15 +800,15 @@ namespace WixToolset.Core.WindowsInstaller.Unbind | |||
732 | /// <param name="table">The table containing rows that need to be connected to sections.</param> | 800 | /// <param name="table">The table containing rows that need to be connected to sections.</param> |
733 | /// <param name="sectionIdIndex">A hashtable containing keys to map table to its section.</param> | 801 | /// <param name="sectionIdIndex">A hashtable containing keys to map table to its section.</param> |
734 | /// <param name="rowIndex">The index of the column which is used as the foreign key in to the sectionIdIndex.</param> | 802 | /// <param name="rowIndex">The index of the column which is used as the foreign key in to the sectionIdIndex.</param> |
735 | private static void ConnectTableToSection(Table table, Hashtable sectionIdIndex, int rowIndex) | 803 | private static void ConnectTableToSection(Table table, Dictionary<string, string> sectionIdIndex, int rowIndex) |
736 | { | 804 | { |
737 | if (null != table) | 805 | if (null != table) |
738 | { | 806 | { |
739 | foreach (var row in table.Rows) | 807 | foreach (var row in table.Rows) |
740 | { | 808 | { |
741 | if (sectionIdIndex.ContainsKey(row[rowIndex])) | 809 | if (sectionIdIndex.TryGetValue(row.FieldAsString(rowIndex), out var sectionId)) |
742 | { | 810 | { |
743 | row.SectionId = (string)sectionIdIndex[row[rowIndex]]; | 811 | row.SectionId = sectionId; |
744 | } | 812 | } |
745 | } | 813 | } |
746 | } | 814 | } |
@@ -750,40 +818,53 @@ namespace WixToolset.Core.WindowsInstaller.Unbind | |||
750 | /// Connects a table's rows to an already sectioned table and produces an index for other tables to connect to it. | 818 | /// Connects a table's rows to an already sectioned table and produces an index for other tables to connect to it. |
751 | /// </summary> | 819 | /// </summary> |
752 | /// <param name="table">The table containing rows that need to be connected to sections.</param> | 820 | /// <param name="table">The table containing rows that need to be connected to sections.</param> |
753 | /// <param name="sectionIdIndex">A hashtable containing keys to map table to its section.</param> | 821 | /// <param name="sectionIdIndex">A dictionary containing keys to map table to its section.</param> |
754 | /// <param name="rowIndex">The index of the column which is used as the foreign key in to the sectionIdIndex.</param> | 822 | /// <param name="rowIndex">The index of the column which is used as the foreign key in to the sectionIdIndex.</param> |
755 | /// <param name="rowPrimaryKeyIndex">The index of the column which is used by other tables to reference this table.</param> | 823 | /// <param name="rowPrimaryKeyIndex">The index of the column which is used by other tables to reference this table.</param> |
756 | /// <returns>A Hashtable containing the tables key for each row paired with its assigned section id.</returns> | 824 | /// <returns>A dictionary containing the tables key for each row paired with its assigned section id.</returns> |
757 | private static Hashtable ConnectTableToSectionAndIndex(Table table, Hashtable sectionIdIndex, int rowIndex, int rowPrimaryKeyIndex) | 825 | private static Dictionary<string, string> ConnectTableToSectionAndIndex(Table table, Dictionary<string, string> sectionIdIndex, int rowIndex, int rowPrimaryKeyIndex) |
758 | { | 826 | { |
759 | var newHashTable = new Hashtable(); | 827 | var newPrimaryKeyToSectionId = new Dictionary<string, string>(); |
828 | |||
760 | if (null != table) | 829 | if (null != table) |
761 | { | 830 | { |
762 | foreach (var row in table.Rows) | 831 | foreach (var row in table.Rows) |
763 | { | 832 | { |
764 | if (!sectionIdIndex.ContainsKey(row[rowIndex])) | 833 | var foreignKey = row.FieldAsString(rowIndex); |
834 | |||
835 | if (!sectionIdIndex.TryGetValue(foreignKey, out var sectionId)) | ||
765 | { | 836 | { |
766 | continue; | 837 | continue; |
767 | } | 838 | } |
768 | 839 | ||
769 | row.SectionId = (string)sectionIdIndex[row[rowIndex]]; | 840 | row.SectionId = sectionId; |
770 | if (null != row[rowPrimaryKeyIndex]) | 841 | |
842 | var primaryKey = row.FieldAsString(rowPrimaryKeyIndex); | ||
843 | |||
844 | if (!String.IsNullOrEmpty(primaryKey) && sectionIdIndex.ContainsKey(primaryKey)) | ||
771 | { | 845 | { |
772 | newHashTable.Add(row[rowPrimaryKeyIndex], row.SectionId); | 846 | newPrimaryKeyToSectionId.Add(primaryKey, row.SectionId); |
773 | } | 847 | } |
774 | } | 848 | } |
775 | } | 849 | } |
776 | return newHashTable; | 850 | |
851 | return newPrimaryKeyToSectionId; | ||
777 | } | 852 | } |
778 | 853 | ||
779 | /// <summary> | ||
780 | /// Creates a new section identifier to be used when adding a section to an output. | ||
781 | /// </summary> | ||
782 | /// <returns>A string representing a new section id.</returns> | ||
783 | private string GetNewSectionId() | 854 | private string GetNewSectionId() |
784 | { | 855 | { |
785 | this.SectionCount++; | 856 | this.sectionCount++; |
786 | return "wix.section." + this.SectionCount.ToString(CultureInfo.InvariantCulture); | 857 | |
858 | return "wix.section." + this.sectionCount.ToString(CultureInfo.InvariantCulture); | ||
859 | } | ||
860 | |||
861 | private class SummaryInformationBits | ||
862 | { | ||
863 | public bool AdminImage { get; set; } | ||
864 | |||
865 | public bool Compressed { get; set; } | ||
866 | |||
867 | public bool LongFilenames { get; set; } | ||
787 | } | 868 | } |
788 | } | 869 | } |
789 | } | 870 | } |
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Unbind/UnbindMsiOrMsmCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Unbind/UnbindMsiOrMsmCommand.cs deleted file mode 100644 index 8070d42d..00000000 --- a/src/wix/WixToolset.Core.WindowsInstaller/Unbind/UnbindMsiOrMsmCommand.cs +++ /dev/null | |||
@@ -1,72 +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.Unbind | ||
4 | { | ||
5 | using System; | ||
6 | using System.ComponentModel; | ||
7 | using WixToolset.Core.Native.Msi; | ||
8 | using WixToolset.Data; | ||
9 | using WixToolset.Data.WindowsInstaller; | ||
10 | using WixToolset.Extensibility.Services; | ||
11 | |||
12 | internal class UnbindMsiOrMsmCommand | ||
13 | { | ||
14 | public UnbindMsiOrMsmCommand(IMessaging messaging, IBackendHelper backendHelper, string databasePath, string exportBasePath, string intermediateFolder, bool adminImage, bool suppressDemodularization, bool suppressExtractCabinets) | ||
15 | { | ||
16 | this.Messaging = messaging; | ||
17 | this.BackendHelper = backendHelper; | ||
18 | this.DatabasePath = databasePath; | ||
19 | this.ExportBasePath = exportBasePath; | ||
20 | this.IntermediateFolder = intermediateFolder; | ||
21 | this.IsAdminImage = adminImage; | ||
22 | this.SuppressDemodularization = suppressDemodularization; | ||
23 | this.SuppressExtractCabinets = suppressExtractCabinets; | ||
24 | } | ||
25 | |||
26 | private IMessaging Messaging { get; } | ||
27 | |||
28 | private IBackendHelper BackendHelper { get; } | ||
29 | |||
30 | private string DatabasePath { get; } | ||
31 | |||
32 | private string ExportBasePath { get; } | ||
33 | |||
34 | private string IntermediateFolder { get; } | ||
35 | |||
36 | private bool IsAdminImage { get; } | ||
37 | |||
38 | private bool SuppressDemodularization { get; } | ||
39 | |||
40 | private bool SuppressExtractCabinets { get; } | ||
41 | |||
42 | public WindowsInstallerData Execute() | ||
43 | { | ||
44 | try | ||
45 | { | ||
46 | using (var database = new Database(this.DatabasePath, OpenDatabase.ReadOnly)) | ||
47 | { | ||
48 | var unbindCommand = new UnbindDatabaseCommand(this.Messaging, this.BackendHelper, database, this.DatabasePath, OutputType.Product, this.ExportBasePath, this.IntermediateFolder, this.IsAdminImage, this.SuppressDemodularization, skipSummaryInfo: false); | ||
49 | var data = unbindCommand.Execute(); | ||
50 | |||
51 | // extract the files from the cabinets | ||
52 | if (!String.IsNullOrEmpty(this.ExportBasePath) && !this.SuppressExtractCabinets) | ||
53 | { | ||
54 | var extractCommand = new ExtractCabinetsCommand(data, database, this.DatabasePath, this.ExportBasePath, this.IntermediateFolder); | ||
55 | extractCommand.Execute(); | ||
56 | } | ||
57 | |||
58 | return data; | ||
59 | } | ||
60 | } | ||
61 | catch (Win32Exception e) | ||
62 | { | ||
63 | if (0x6E == e.NativeErrorCode) // ERROR_OPEN_FAILED | ||
64 | { | ||
65 | //throw new WixException(WixErrors.OpenDatabaseFailed(this.DatabasePath)); | ||
66 | } | ||
67 | |||
68 | throw; | ||
69 | } | ||
70 | } | ||
71 | } | ||
72 | } | ||
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Unbind/UnbindTransformCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Unbind/UnbindTransformCommand.cs index 01ff1a80..bce60e40 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Unbind/UnbindTransformCommand.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Unbind/UnbindTransformCommand.cs | |||
@@ -1,5 +1,7 @@ | |||
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 TODO_KEEP_FOR_PATCH_UNBINDING_CONSIDERATION_IN_FUTURE | ||
4 | |||
3 | namespace WixToolset.Core.WindowsInstaller.Unbind | 5 | namespace WixToolset.Core.WindowsInstaller.Unbind |
4 | { | 6 | { |
5 | using System; | 7 | using System; |
@@ -17,10 +19,11 @@ namespace WixToolset.Core.WindowsInstaller.Unbind | |||
17 | 19 | ||
18 | internal class UnbindTransformCommand | 20 | internal class UnbindTransformCommand |
19 | { | 21 | { |
20 | public UnbindTransformCommand(IMessaging messaging, IBackendHelper backendHelper, string transformFile, string exportBasePath, string intermediateFolder) | 22 | public UnbindTransformCommand(IMessaging messaging, IBackendHelper backendHelper, FileSystemManager fileSystemManager, string transformFile, string exportBasePath, string intermediateFolder) |
21 | { | 23 | { |
22 | this.Messaging = messaging; | 24 | this.Messaging = messaging; |
23 | this.BackendHelper = backendHelper; | 25 | this.BackendHelper = backendHelper; |
26 | this.FileSystemManager = fileSystemManager; | ||
24 | this.TransformFile = transformFile; | 27 | this.TransformFile = transformFile; |
25 | this.ExportBasePath = exportBasePath; | 28 | this.ExportBasePath = exportBasePath; |
26 | this.IntermediateFolder = intermediateFolder; | 29 | this.IntermediateFolder = intermediateFolder; |
@@ -32,6 +35,8 @@ namespace WixToolset.Core.WindowsInstaller.Unbind | |||
32 | 35 | ||
33 | private IBackendHelper BackendHelper { get; } | 36 | private IBackendHelper BackendHelper { get; } |
34 | 37 | ||
38 | private FileSystemManager FileSystemManager { get; } | ||
39 | |||
35 | private string TransformFile { get; } | 40 | private string TransformFile { get; } |
36 | 41 | ||
37 | private string ExportBasePath { get; } | 42 | private string ExportBasePath { get; } |
@@ -90,7 +95,7 @@ namespace WixToolset.Core.WindowsInstaller.Unbind | |||
90 | msiDatabase.ApplyTransform(this.TransformFile, TransformErrorConditions.All | TransformErrorConditions.ViewTransform); | 95 | msiDatabase.ApplyTransform(this.TransformFile, TransformErrorConditions.All | TransformErrorConditions.ViewTransform); |
91 | 96 | ||
92 | // unbind the database | 97 | // unbind the database |
93 | var unbindCommand = new UnbindDatabaseCommand(this.Messaging, this.BackendHelper, msiDatabase, msiDatabaseFile, OutputType.Product, this.ExportBasePath, this.IntermediateFolder, false, false, skipSummaryInfo: true); | 98 | var unbindCommand = new UnbindDatabaseCommand(this.Messaging, this.BackendHelper, msiDatabase, msiDatabaseFile, OutputType.Product, this.ExportBasePath, this.IntermediateFolder, enableDemodularization: false, skipSummaryInfo: true); |
94 | var transformViewOutput = unbindCommand.Execute(); | 99 | var transformViewOutput = unbindCommand.Execute(); |
95 | 100 | ||
96 | // index the added and possibly modified rows (added rows may also appears as modified rows) | 101 | // index the added and possibly modified rows (added rows may also appears as modified rows) |
@@ -160,7 +165,7 @@ namespace WixToolset.Core.WindowsInstaller.Unbind | |||
160 | } | 165 | } |
161 | 166 | ||
162 | // unbind the database | 167 | // unbind the database |
163 | var unbindCommand = new UnbindDatabaseCommand(this.Messaging, this.BackendHelper, msiDatabase, msiDatabaseFile, OutputType.Product, this.ExportBasePath, this.IntermediateFolder, false, false, skipSummaryInfo: true); | 168 | var unbindCommand = new UnbindDatabaseCommand(this.Messaging, this.BackendHelper, msiDatabase, msiDatabaseFile, OutputType.Product, this.ExportBasePath, this.IntermediateFolder, enableDemodularization: false, skipSummaryInfo: true); |
164 | var output = unbindCommand.Execute(); | 169 | var output = unbindCommand.Execute(); |
165 | 170 | ||
166 | // index all the rows to easily find modified rows | 171 | // index all the rows to easily find modified rows |
@@ -302,8 +307,9 @@ namespace WixToolset.Core.WindowsInstaller.Unbind | |||
302 | 307 | ||
303 | private void GenerateDatabase(WindowsInstallerData output, string databaseFile) | 308 | private void GenerateDatabase(WindowsInstallerData output, string databaseFile) |
304 | { | 309 | { |
305 | var command = new GenerateDatabaseCommand(this.Messaging, null, null, output, databaseFile, this.TableDefinitions, this.IntermediateFolder, keepAddedColumns: true, suppressAddingValidationRows: true, useSubdirectory: false); | 310 | var command = new GenerateDatabaseCommand(this.Messaging, this.BackendHelper, this.FileSystemManager, output, databaseFile, this.TableDefinitions, this.IntermediateFolder, keepAddedColumns: true, suppressAddingValidationRows: true, useSubdirectory: false); |
306 | command.Execute(); | 311 | command.Execute(); |
307 | } | 312 | } |
308 | } | 313 | } |
309 | } | 314 | } |
315 | #endif | ||
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/WindowsInstallerDecompiler.cs b/src/wix/WixToolset.Core.WindowsInstaller/WindowsInstallerDecompiler.cs index b35e3587..c78ea93a 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/WindowsInstallerDecompiler.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/WindowsInstallerDecompiler.cs | |||
@@ -3,11 +3,9 @@ | |||
3 | namespace WixToolset.Core.WindowsInstaller | 3 | namespace WixToolset.Core.WindowsInstaller |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections.Generic; | 6 | using System.ComponentModel.Design; |
7 | using System.ComponentModel; | ||
8 | using System.IO; | 7 | using System.IO; |
9 | using System.Linq; | 8 | using System.Linq; |
10 | using WixToolset.Core.Native.Msi; | ||
11 | using WixToolset.Core.WindowsInstaller.Decompile; | 9 | using WixToolset.Core.WindowsInstaller.Decompile; |
12 | using WixToolset.Core.WindowsInstaller.Unbind; | 10 | using WixToolset.Core.WindowsInstaller.Unbind; |
13 | using WixToolset.Data; | 11 | using WixToolset.Data; |
@@ -63,56 +61,32 @@ namespace WixToolset.Core.WindowsInstaller | |||
63 | 61 | ||
64 | private IWindowsInstallerDecompileResult Execute(IWindowsInstallerDecompileContext context) | 62 | private IWindowsInstallerDecompileResult Execute(IWindowsInstallerDecompileContext context) |
65 | { | 63 | { |
66 | var result = context.ServiceProvider.GetService<IWindowsInstallerDecompileResult>(); | 64 | // Delete the directory and its files to prevent cab extraction failure due to an existing file. |
67 | 65 | if (Directory.Exists(context.ExtractFolder)) | |
68 | try | ||
69 | { | 66 | { |
70 | using (var database = new Database(context.DecompilePath, OpenDatabase.ReadOnly)) | 67 | Directory.Delete(context.ExtractFolder, true); |
71 | { | ||
72 | // Delete the directory and its files to prevent cab extraction failure due to an existing file. | ||
73 | if (Directory.Exists(context.ExtractFolder)) | ||
74 | { | ||
75 | Directory.Delete(context.ExtractFolder, true); | ||
76 | } | ||
77 | |||
78 | var backendHelper = context.ServiceProvider.GetService<IWindowsInstallerBackendHelper>(); | ||
79 | var decompilerHelper = context.ServiceProvider.GetService<IWindowsInstallerDecompilerHelper>(); | ||
80 | |||
81 | var unbindCommand = new UnbindDatabaseCommand(this.Messaging, backendHelper, database, context.DecompilePath, context.DecompileType, context.ExtractFolder, context.IntermediateFolder, context.IsAdminImage, suppressDemodularization: false, skipSummaryInfo: false); | ||
82 | var output = unbindCommand.Execute(); | ||
83 | var extractedFilePaths = new List<string>(unbindCommand.ExportedFiles); | ||
84 | |||
85 | var decompiler = new Decompiler(this.Messaging, backendHelper, decompilerHelper, context.Extensions, context.ExtensionData, context.SymbolDefinitionCreator, context.BaseSourcePath, context.SuppressCustomTables, context.SuppressDroppingEmptyTables, context.SuppressRelativeActionSequencing, context.SuppressUI, context.TreatProductAsModule); | ||
86 | result.Document = decompiler.Decompile(output); | ||
87 | |||
88 | result.Platform = GetPlatformFromOutput(output); | ||
89 | |||
90 | // extract the files from the cabinets | ||
91 | if (!String.IsNullOrEmpty(context.ExtractFolder) && !context.SuppressExtractCabinets) | ||
92 | { | ||
93 | var fileDirectory = String.IsNullOrEmpty(context.CabinetExtractFolder) ? Path.Combine(context.ExtractFolder, "File") : context.CabinetExtractFolder; | ||
94 | |||
95 | var extractCommand = new ExtractCabinetsCommand(output, database, context.DecompilePath, fileDirectory, context.IntermediateFolder, context.TreatProductAsModule); | ||
96 | extractCommand.Execute(); | ||
97 | |||
98 | extractedFilePaths.AddRange(extractCommand.ExtractedFiles); | ||
99 | result.ExtractedFilePaths = extractedFilePaths; | ||
100 | } | ||
101 | else | ||
102 | { | ||
103 | result.ExtractedFilePaths = new string[0]; | ||
104 | } | ||
105 | } | ||
106 | } | 68 | } |
107 | catch (Win32Exception e) | ||
108 | { | ||
109 | if (0x6E == e.NativeErrorCode) // ERROR_OPEN_FAILED | ||
110 | { | ||
111 | throw new WixException(ErrorMessages.OpenDatabaseFailed(context.DecompilePath)); | ||
112 | } | ||
113 | 69 | ||
114 | throw; | 70 | var backendHelper = context.ServiceProvider.GetService<IWindowsInstallerBackendHelper>(); |
115 | } | 71 | |
72 | var pathResolver = context.ServiceProvider.GetService<IPathResolver>(); | ||
73 | |||
74 | var extractFilesFolder = context.SuppressExtractCabinets || (String.IsNullOrEmpty(context.CabinetExtractFolder) && String.IsNullOrEmpty(context.ExtractFolder)) ? null : | ||
75 | String.IsNullOrEmpty(context.CabinetExtractFolder) ? Path.Combine(context.ExtractFolder, "File") : context.CabinetExtractFolder; | ||
76 | |||
77 | var outputType = context.TreatProductAsModule ? OutputType.Module : context.DecompileType; | ||
78 | var unbindCommand = new UnbindDatabaseCommand(this.Messaging, backendHelper, pathResolver, context.DecompilePath, outputType, context.ExtractFolder, extractFilesFolder, context.IntermediateFolder, enableDemodularization: true, skipSummaryInfo: false); | ||
79 | var output = unbindCommand.Execute(); | ||
80 | var extractedFilePaths = unbindCommand.ExportedFiles; | ||
81 | |||
82 | var decompilerHelper = context.ServiceProvider.GetService<IWindowsInstallerDecompilerHelper>(); | ||
83 | var decompiler = new Decompiler(this.Messaging, backendHelper, decompilerHelper, context.Extensions, context.ExtensionData, context.SymbolDefinitionCreator, context.BaseSourcePath, context.SuppressCustomTables, context.SuppressDroppingEmptyTables, context.SuppressRelativeActionSequencing, context.SuppressUI, context.TreatProductAsModule); | ||
84 | var document = decompiler.Decompile(output); | ||
85 | |||
86 | var result = context.ServiceProvider.GetService<IWindowsInstallerDecompileResult>(); | ||
87 | result.Document = document; | ||
88 | result.Platform = GetPlatformFromOutput(output); | ||
89 | result.ExtractedFilePaths = extractedFilePaths.ToList(); | ||
116 | 90 | ||
117 | return result; | 91 | return result; |
118 | } | 92 | } |
diff --git a/src/wix/WixToolset.Core/Bind/ExtractEmbeddedFiles.cs b/src/wix/WixToolset.Core/Bind/ExtractEmbeddedFiles.cs index a0798e62..025affd3 100644 --- a/src/wix/WixToolset.Core/Bind/ExtractEmbeddedFiles.cs +++ b/src/wix/WixToolset.Core/Bind/ExtractEmbeddedFiles.cs | |||
@@ -4,7 +4,6 @@ namespace WixToolset.Core.Bind | |||
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
7 | using System.Globalization; | ||
8 | using System.IO; | 7 | using System.IO; |
9 | using System.Linq; | 8 | using System.Linq; |
10 | using System.Security.Cryptography; | 9 | using System.Security.Cryptography; |
@@ -41,9 +40,9 @@ namespace WixToolset.Core.Bind | |||
41 | { | 40 | { |
42 | var localFileNameWithoutExtension = Path.GetFileNameWithoutExtension(uri.LocalPath); | 41 | var localFileNameWithoutExtension = Path.GetFileNameWithoutExtension(uri.LocalPath); |
43 | var unique = this.HashUri(uri.AbsoluteUri); | 42 | var unique = this.HashUri(uri.AbsoluteUri); |
44 | var extractedName = String.Format(CultureInfo.InvariantCulture, @"{0}_{1}\{2}", localFileNameWithoutExtension, unique, embeddedFileId); | 43 | var extractedName = String.Concat(localFileNameWithoutExtension, "_", unique); |
45 | 44 | ||
46 | extractPath = Path.GetFullPath(Path.Combine(extractFolder, extractedName)); | 45 | extractPath = Path.GetFullPath(Path.Combine(extractFolder, extractedName, embeddedFileId)); |
47 | extracts.Add(embeddedFileId, extractPath); | 46 | extracts.Add(embeddedFileId, extractPath); |
48 | } | 47 | } |
49 | 48 | ||
diff --git a/src/wix/WixToolset.Core/Bind/ResolveFieldsCommand.cs b/src/wix/WixToolset.Core/Bind/ResolveFieldsCommand.cs index 794208e5..8a5299d9 100644 --- a/src/wix/WixToolset.Core/Bind/ResolveFieldsCommand.cs +++ b/src/wix/WixToolset.Core/Bind/ResolveFieldsCommand.cs | |||
@@ -16,186 +16,121 @@ namespace WixToolset.Core.Bind | |||
16 | /// </summary> | 16 | /// </summary> |
17 | internal class ResolveFieldsCommand | 17 | internal class ResolveFieldsCommand |
18 | { | 18 | { |
19 | public IMessaging Messaging { private get; set; } | 19 | public ResolveFieldsCommand(IMessaging messaging, IFileResolver fileResolver, IVariableResolver variableResolver, IReadOnlyCollection<IBindPath> bindPaths, IReadOnlyCollection<IResolverExtension> extensions, ExtractEmbeddedFiles filesWithEmbeddedFiles, string intermediateFolder, Intermediate intermediate, bool allowUnresolvedVariables) |
20 | { | ||
21 | this.Messaging = messaging; | ||
22 | this.FileResolver = fileResolver; | ||
23 | this.VariableResolver = variableResolver; | ||
24 | this.BindPaths = bindPaths; | ||
25 | this.Extensions = extensions; | ||
26 | this.FilesWithEmbeddedFiles = filesWithEmbeddedFiles; | ||
27 | this.IntermediateFolder = intermediateFolder; | ||
28 | this.Intermediate = intermediate; | ||
29 | this.AllowUnresolvedVariables = allowUnresolvedVariables; | ||
30 | } | ||
20 | 31 | ||
21 | public bool BuildingPatch { private get; set; } | 32 | private IMessaging Messaging { get; } |
22 | 33 | ||
23 | public IVariableResolver VariableResolver { private get; set; } | 34 | private IFileResolver FileResolver { get; } |
24 | 35 | ||
25 | public IEnumerable<IBindPath> BindPaths { private get; set; } | 36 | private IVariableResolver VariableResolver { get; } |
26 | 37 | ||
27 | public IEnumerable<IResolverExtension> Extensions { private get; set; } | 38 | private IEnumerable<IBindPath> BindPaths { get; } |
28 | 39 | ||
29 | public ExtractEmbeddedFiles FilesWithEmbeddedFiles { private get; set; } | 40 | private IEnumerable<IResolverExtension> Extensions { get; } |
30 | 41 | ||
31 | public string IntermediateFolder { private get; set; } | 42 | private ExtractEmbeddedFiles FilesWithEmbeddedFiles { get; } |
32 | 43 | ||
33 | public Intermediate Intermediate { private get; set; } | 44 | private string IntermediateFolder { get; } |
34 | 45 | ||
35 | public bool SupportDelayedResolution { private get; set; } | 46 | private Intermediate Intermediate { get; } |
36 | 47 | ||
37 | public bool AllowUnresolvedVariables { private get; set; } | 48 | private bool AllowUnresolvedVariables { get; } |
38 | 49 | ||
39 | public IReadOnlyCollection<DelayedField> DelayedFields { get; private set; } | 50 | public IReadOnlyCollection<DelayedField> DelayedFields { get; private set; } |
40 | 51 | ||
41 | public void Execute() | 52 | public void Execute() |
42 | { | 53 | { |
43 | var delayedFields = this.SupportDelayedResolution ? new List<DelayedField>() : null; | 54 | var delayedFields = new List<DelayedField>(); |
44 | 55 | ||
45 | var fileResolver = new FileResolver(this.BindPaths, this.Extensions); | 56 | var bindPaths = this.BindPaths.Where(b => b.Stage == BindStage.Normal).ToList(); |
46 | 57 | ||
47 | // Build the column lookup only when needed. | 58 | // Build the column lookup only when needed. |
48 | Dictionary<string, WixCustomTableColumnSymbol> customColumnsById = null; | 59 | Dictionary<string, WixCustomTableColumnSymbol> customColumnsById = null; |
49 | 60 | ||
50 | foreach (var sections in this.Intermediate.Sections) | 61 | foreach (var symbol in this.Intermediate.Sections.SelectMany(s => s.Symbols)) |
51 | { | 62 | { |
52 | foreach (var symbol in sections.Symbols) | 63 | foreach (var field in symbol.Fields.Where(f => !f.IsNull())) |
53 | { | 64 | { |
54 | foreach (var field in symbol.Fields) | 65 | var fieldType = field.Type; |
66 | |||
67 | // Custom table cells require an extra look up to the column definition as the | ||
68 | // cell's data type is always a string (because strings can store anything) but | ||
69 | // the column definition may be more specific. | ||
70 | if (symbol.Definition.Type == SymbolDefinitionType.WixCustomTableCell) | ||
55 | { | 71 | { |
56 | if (field.IsNull()) | 72 | // We only care about the Data in a CustomTable cell. |
73 | if (field.Name != nameof(WixCustomTableCellSymbolFields.Data)) | ||
57 | { | 74 | { |
58 | continue; | 75 | continue; |
59 | } | 76 | } |
60 | 77 | ||
61 | var fieldType = field.Type; | 78 | if (customColumnsById == null) |
62 | |||
63 | // Custom table cells require an extra look up to the column definition as the | ||
64 | // cell's data type is always a string (because strings can store anything) but | ||
65 | // the column definition may be more specific. | ||
66 | if (symbol.Definition.Type == SymbolDefinitionType.WixCustomTableCell) | ||
67 | { | 79 | { |
68 | // We only care about the Data in a CustomTable cell. | 80 | customColumnsById = this.Intermediate.Sections.SelectMany(s => s.Symbols.OfType<WixCustomTableColumnSymbol>()).ToDictionary(t => t.Id.Id); |
69 | if (field.Name != nameof(WixCustomTableCellSymbolFields.Data)) | ||
70 | { | ||
71 | continue; | ||
72 | } | ||
73 | |||
74 | if (customColumnsById == null) | ||
75 | { | ||
76 | customColumnsById = this.Intermediate.Sections.SelectMany(s => s.Symbols.OfType<WixCustomTableColumnSymbol>()).ToDictionary(t => t.Id.Id); | ||
77 | } | ||
78 | |||
79 | if (customColumnsById.TryGetValue(symbol.Fields[(int)WixCustomTableCellSymbolFields.TableRef].AsString() + "/" + symbol.Fields[(int)WixCustomTableCellSymbolFields.ColumnRef].AsString(), out var customColumn)) | ||
80 | { | ||
81 | fieldType = customColumn.Type; | ||
82 | } | ||
83 | } | 81 | } |
84 | 82 | ||
85 | // Check to make sure we're in a scenario where we can handle variable resolution. | 83 | if (customColumnsById.TryGetValue(symbol.Fields[(int)WixCustomTableCellSymbolFields.TableRef].AsString() + "/" + symbol.Fields[(int)WixCustomTableCellSymbolFields.ColumnRef].AsString(), out var customColumn)) |
86 | if (null != delayedFields) | ||
87 | { | 84 | { |
88 | // resolve localization and wix variables | 85 | fieldType = customColumn.Type; |
89 | if (fieldType == IntermediateFieldType.String) | ||
90 | { | ||
91 | var original = field.AsString(); | ||
92 | if (!String.IsNullOrEmpty(original)) | ||
93 | { | ||
94 | var resolution = this.VariableResolver.ResolveVariables(symbol.SourceLineNumbers, original, !this.AllowUnresolvedVariables); | ||
95 | if (resolution.UpdatedValue) | ||
96 | { | ||
97 | field.Set(resolution.Value); | ||
98 | } | ||
99 | |||
100 | if (resolution.DelayedResolve) | ||
101 | { | ||
102 | delayedFields.Add(new DelayedField(symbol, field)); | ||
103 | } | ||
104 | } | ||
105 | } | ||
106 | } | ||
107 | |||
108 | // Move to next symbol if we've hit an error resolving variables. | ||
109 | if (this.Messaging.EncounteredError) // TODO: make this error handling more specific to just the failure to resolve variables in this field. | ||
110 | { | ||
111 | continue; | ||
112 | } | 86 | } |
87 | } | ||
113 | 88 | ||
114 | // Resolve file paths | 89 | // Check to make sure we're in a scenario where we can handle variable resolution. |
115 | if (fieldType == IntermediateFieldType.Path) | 90 | if (null != delayedFields) |
91 | { | ||
92 | // resolve localization and wix variables | ||
93 | if (fieldType == IntermediateFieldType.String) | ||
116 | { | 94 | { |
117 | this.ResolvePathField(fileResolver, symbol, field); | 95 | var original = field.AsString(); |
118 | 96 | if (!String.IsNullOrEmpty(original)) | |
119 | #if TODO_PATCHING | ||
120 | if (null != objectField.PreviousData) | ||
121 | { | 97 | { |
122 | objectField.PreviousData = this.BindVariableResolver.ResolveVariables(symbol.SourceLineNumbers, objectField.PreviousData, false, out isDefault); | 98 | var resolution = this.VariableResolver.ResolveVariables(symbol.SourceLineNumbers, original, !this.AllowUnresolvedVariables); |
123 | 99 | if (resolution.UpdatedValue) | |
124 | if (!Messaging.Instance.EncounteredError) // TODO: make this error handling more specific to just the failure to resolve variables in this field. | ||
125 | { | 100 | { |
126 | // file is compressed in a cabinet (and not modified above) | 101 | field.Set(resolution.Value); |
127 | if (objectField.PreviousEmbeddedFileIndex.HasValue && isDefault) | 102 | } |
128 | { | ||
129 | // when loading transforms from disk, PreviousBaseUri may not have been set | ||
130 | if (null == objectField.PreviousBaseUri) | ||
131 | { | ||
132 | objectField.PreviousBaseUri = objectField.BaseUri; | ||
133 | } | ||
134 | |||
135 | string extractPath = this.FilesWithEmbeddedFiles.AddEmbeddedFileIndex(objectField.PreviousBaseUri, objectField.PreviousEmbeddedFileIndex.Value, this.IntermediateFolder); | ||
136 | |||
137 | // set the path to the file once its extracted from the cabinet | ||
138 | objectField.PreviousData = extractPath; | ||
139 | } | ||
140 | else if (null != objectField.PreviousData) // non-compressed file (or localized value) | ||
141 | { | ||
142 | try | ||
143 | { | ||
144 | if (!fileResolver.RebaseTarget && !fileResolver.RebaseUpdated) | ||
145 | { | ||
146 | // resolve the path to the file | ||
147 | objectField.PreviousData = fileResolver.ResolveFile((string)objectField.PreviousData, symbol.Definition.Name, symbol.SourceLineNumbers, BindStage.Normal); | ||
148 | } | ||
149 | else | ||
150 | { | ||
151 | if (fileResolver.RebaseTarget) | ||
152 | { | ||
153 | // if -bt is used, it come here | ||
154 | // Try to use the original unresolved source from either target build or update build | ||
155 | // If both target and updated are of old wixpdb, it behaves the same as today, no re-base logic here | ||
156 | // If target is old version and updated is new version, it uses unresolved path from updated build | ||
157 | // If both target and updated are of new versions, it uses unresolved path from target build | ||
158 | if (null != objectField.UnresolvedPreviousData || null != objectField.UnresolvedData) | ||
159 | { | ||
160 | objectField.PreviousData = objectField.UnresolvedPreviousData ?? objectField.UnresolvedData; | ||
161 | } | ||
162 | } | ||
163 | |||
164 | // resolve the path to the file | ||
165 | objectField.PreviousData = fileResolver.ResolveFile((string)objectField.PreviousData, symbol.Definition.Name, symbol.SourceLineNumbers, BindStage.Target); | ||
166 | 103 | ||
167 | } | 104 | if (resolution.DelayedResolve) |
168 | } | 105 | { |
169 | catch (WixFileNotFoundException) | 106 | delayedFields.Add(new DelayedField(symbol, field)); |
170 | { | ||
171 | // display the error with source line information | ||
172 | Messaging.Instance.Write(WixErrors.FileNotFound(symbol.SourceLineNumbers, (string)objectField.PreviousData)); | ||
173 | } | ||
174 | } | ||
175 | } | 107 | } |
176 | } | 108 | } |
177 | #endif | ||
178 | } | 109 | } |
179 | } | 110 | } |
111 | |||
112 | // Move to next symbol if we've hit an error resolving variables. | ||
113 | if (this.Messaging.EncounteredError) // TODO: make this error handling more specific to just the failure to resolve variables in this field. | ||
114 | { | ||
115 | continue; | ||
116 | } | ||
117 | |||
118 | // Resolve file paths | ||
119 | if (fieldType == IntermediateFieldType.Path) | ||
120 | { | ||
121 | this.ResolvePathField(this.FileResolver, bindPaths, symbol, field); | ||
122 | } | ||
180 | } | 123 | } |
181 | } | 124 | } |
182 | 125 | ||
183 | this.DelayedFields = delayedFields; | 126 | this.DelayedFields = delayedFields; |
184 | } | 127 | } |
185 | 128 | ||
186 | private void ResolvePathField(FileResolver fileResolver, IntermediateSymbol symbol, IntermediateField field) | 129 | private void ResolvePathField(IFileResolver fileResolver, IEnumerable<IBindPath> bindPaths, IntermediateSymbol symbol, IntermediateField field) |
187 | { | 130 | { |
188 | var fieldValue = field.AsPath(); | 131 | var fieldValue = field.AsPath(); |
189 | var originalFieldPath = fieldValue.Path; | 132 | var originalFieldPath = fieldValue.Path; |
190 | 133 | ||
191 | #if TODO_PATCHING | ||
192 | // Skip file resolution if the file is to be deleted. | ||
193 | if (RowOperation.Delete == symbol.Operation) | ||
194 | { | ||
195 | continue; | ||
196 | } | ||
197 | #endif | ||
198 | |||
199 | // If the file is embedded and if the previous value has a bind variable in the path | 134 | // If the file is embedded and if the previous value has a bind variable in the path |
200 | // which gets modified by resolving the previous value again then switch to that newly | 135 | // which gets modified by resolving the previous value again then switch to that newly |
201 | // resolved path instead of using the embedded file. | 136 | // resolved path instead of using the embedded file. |
@@ -221,45 +156,7 @@ namespace WixToolset.Core.Bind | |||
221 | { | 156 | { |
222 | try | 157 | try |
223 | { | 158 | { |
224 | var resolvedPath = fieldValue.Path; | 159 | var resolvedPath = fileResolver.ResolveFile(fieldValue.Path, this.Extensions, bindPaths, BindStage.Normal, symbol.SourceLineNumbers, symbol.Definition); |
225 | |||
226 | if (!this.BuildingPatch) // Normal binding for non-Patch scenario such as link (light.exe) | ||
227 | { | ||
228 | #if TODO_PATCHING | ||
229 | // keep a copy of the un-resolved data for future replay. This will be saved into wixpdb file | ||
230 | if (null == objectField.UnresolvedData) | ||
231 | { | ||
232 | objectField.UnresolvedData = (string)objectField.Data; | ||
233 | } | ||
234 | #endif | ||
235 | resolvedPath = fileResolver.ResolveFile(fieldValue.Path, symbol.Definition, symbol.SourceLineNumbers, BindStage.Normal); | ||
236 | } | ||
237 | else if (!fileResolver.RebaseTarget && !fileResolver.RebaseUpdated) // Normal binding for Patch Scenario (normal patch, no re-basing logic) | ||
238 | { | ||
239 | resolvedPath = fileResolver.ResolveFile(fieldValue.Path, symbol.Definition, symbol.SourceLineNumbers, BindStage.Normal); | ||
240 | } | ||
241 | #if TODO_PATCHING | ||
242 | else // Re-base binding path scenario caused by pyro.exe -bt -bu | ||
243 | { | ||
244 | // by default, use the resolved Data for file lookup | ||
245 | string filePathToResolve = (string)objectField.Data; | ||
246 | |||
247 | // if -bu is used in pyro command, this condition holds true and the tool | ||
248 | // will use pre-resolved source for new wixpdb file | ||
249 | if (fileResolver.RebaseUpdated) | ||
250 | { | ||
251 | // try to use the unResolved Source if it exists. | ||
252 | // New version of wixpdb file keeps a copy of pre-resolved Source. i.e. !(bindpath.test)\foo.dll | ||
253 | // Old version of winpdb file does not contain this attribute and the value is null. | ||
254 | if (null != objectField.UnresolvedData) | ||
255 | { | ||
256 | filePathToResolve = objectField.UnresolvedData; | ||
257 | } | ||
258 | } | ||
259 | |||
260 | objectField.Data = fileResolver.ResolveFile(filePathToResolve, symbol.Definition.Name, symbol.SourceLineNumbers, BindStage.Updated); | ||
261 | } | ||
262 | #endif | ||
263 | 160 | ||
264 | if (!String.Equals(originalFieldPath, resolvedPath, StringComparison.OrdinalIgnoreCase)) | 161 | if (!String.Equals(originalFieldPath, resolvedPath, StringComparison.OrdinalIgnoreCase)) |
265 | { | 162 | { |
diff --git a/src/wix/WixToolset.Core/BindContext.cs b/src/wix/WixToolset.Core/BindContext.cs index 9dd6aa46..1c1f7528 100644 --- a/src/wix/WixToolset.Core/BindContext.cs +++ b/src/wix/WixToolset.Core/BindContext.cs | |||
@@ -18,7 +18,7 @@ namespace WixToolset.Core | |||
18 | 18 | ||
19 | public IServiceProvider ServiceProvider { get; } | 19 | public IServiceProvider ServiceProvider { get; } |
20 | 20 | ||
21 | public IReadOnlyCollection<BindPath> BindPaths { get; set; } | 21 | public IReadOnlyCollection<IBindPath> BindPaths { get; set; } |
22 | 22 | ||
23 | public string BurnStubPath { get; set; } | 23 | public string BurnStubPath { get; set; } |
24 | 24 | ||
diff --git a/src/wix/WixToolset.Core/CommandLine/BuildCommand.cs b/src/wix/WixToolset.Core/CommandLine/BuildCommand.cs index dc4e0a6d..34520fc0 100644 --- a/src/wix/WixToolset.Core/CommandLine/BuildCommand.cs +++ b/src/wix/WixToolset.Core/CommandLine/BuildCommand.cs | |||
@@ -48,7 +48,9 @@ namespace WixToolset.Core.CommandLine | |||
48 | { | 48 | { |
49 | new CommandLineHelpSwitch("-arch", "Set the architecture of the output."), | 49 | new CommandLineHelpSwitch("-arch", "Set the architecture of the output."), |
50 | new CommandLineHelpSwitch("-bindfiles", "-bf", "Bind files into an output .wixlib. Ignored if not building a .wixlib."), | 50 | new CommandLineHelpSwitch("-bindfiles", "-bf", "Bind files into an output .wixlib. Ignored if not building a .wixlib."), |
51 | new CommandLineHelpSwitch("-bindpath", "Bind path to search for content files."), | 51 | new CommandLineHelpSwitch("-bindpath", "-b", "Bind path to search for content files."), |
52 | new CommandLineHelpSwitch("-bindpath:target", "-bt", "Bind path to search for target package's content files. Only used when building a patch."), | ||
53 | new CommandLineHelpSwitch("-bindpath:update", "-bu", "Bind path to search for update package's content files. Only used when building a patch."), | ||
52 | new CommandLineHelpSwitch("-cabcache", "-cc", "Set a folder to cache cabinets across builds."), | 54 | new CommandLineHelpSwitch("-cabcache", "-cc", "Set a folder to cache cabinets across builds."), |
53 | new CommandLineHelpSwitch("-culture", "Adds a culture to filter localization files."), | 55 | new CommandLineHelpSwitch("-culture", "Adds a culture to filter localization files."), |
54 | new CommandLineHelpSwitch("-define", "-d", "Sets a preprocessor variable."), | 56 | new CommandLineHelpSwitch("-define", "-d", "Sets a preprocessor variable."), |
@@ -292,6 +294,7 @@ namespace WixToolset.Core.CommandLine | |||
292 | { | 294 | { |
293 | { | 295 | { |
294 | var context = this.ServiceProvider.GetService<IBindContext>(); | 296 | var context = this.ServiceProvider.GetService<IBindContext>(); |
297 | context.BindPaths = bindPaths; | ||
295 | //context.CabbingThreadCount = this.CabbingThreadCount; | 298 | //context.CabbingThreadCount = this.CabbingThreadCount; |
296 | context.CabCachePath = cabCachePath; | 299 | context.CabCachePath = cabCachePath; |
297 | context.ResolvedCodepage = resolveResult.Codepage; | 300 | context.ResolvedCodepage = resolveResult.Codepage; |
@@ -534,11 +537,25 @@ namespace WixToolset.Core.CommandLine | |||
534 | this.BindFiles = true; | 537 | this.BindFiles = true; |
535 | return true; | 538 | return true; |
536 | 539 | ||
540 | case "b": | ||
537 | case "bindpath": | 541 | case "bindpath": |
542 | case "bt": | ||
543 | case "bindpath:target": | ||
544 | case "bu": | ||
545 | case "bindpath:update": | ||
538 | { | 546 | { |
539 | var value = parser.GetNextArgumentOrError(arg); | 547 | var value = parser.GetNextArgumentOrError(arg); |
540 | if (value != null && this.TryParseBindPath(value, out var bindPath)) | 548 | if (value != null && this.TryParseBindPath(arg, value, out var bindPath)) |
541 | { | 549 | { |
550 | if (parameter == "bt" || parameter.EndsWith("target")) | ||
551 | { | ||
552 | bindPath.Stage = BindStage.Target; | ||
553 | } | ||
554 | else if (parameter == "bu" || parameter.EndsWith("update")) | ||
555 | { | ||
556 | bindPath.Stage = BindStage.Updated; | ||
557 | } | ||
558 | |||
542 | this.BindPaths.Add(bindPath); | 559 | this.BindPaths.Add(bindPath); |
543 | } | 560 | } |
544 | return true; | 561 | return true; |
@@ -830,7 +847,7 @@ namespace WixToolset.Core.CommandLine | |||
830 | return new InputsAndOutputs(codePaths, localizationPaths, libraryPaths, wixipls, outputPath, outputType, pdbPath, this.PdbType); | 847 | return new InputsAndOutputs(codePaths, localizationPaths, libraryPaths, wixipls, outputPath, outputType, pdbPath, this.PdbType); |
831 | } | 848 | } |
832 | 849 | ||
833 | private bool TryParseBindPath(string bindPath, out IBindPath bp) | 850 | private bool TryParseBindPath(string argument, string bindPath, out IBindPath bp) |
834 | { | 851 | { |
835 | var namedPath = bindPath.Split(BindPathSplit, 2); | 852 | var namedPath = bindPath.Split(BindPathSplit, 2); |
836 | 853 | ||
@@ -848,7 +865,7 @@ namespace WixToolset.Core.CommandLine | |||
848 | 865 | ||
849 | if (File.Exists(bp.Path)) | 866 | if (File.Exists(bp.Path)) |
850 | { | 867 | { |
851 | this.Messaging.Write(ErrorMessages.ExpectedDirectoryGotFile("-bindpath", bp.Path)); | 868 | this.Messaging.Write(ErrorMessages.ExpectedDirectoryGotFile(argument, bp.Path)); |
852 | return false; | 869 | return false; |
853 | } | 870 | } |
854 | 871 | ||
diff --git a/src/wix/WixToolset.Core/Compiler.cs b/src/wix/WixToolset.Core/Compiler.cs index d04ae491..8f1ae7fb 100644 --- a/src/wix/WixToolset.Core/Compiler.cs +++ b/src/wix/WixToolset.Core/Compiler.cs | |||
@@ -7706,7 +7706,6 @@ namespace WixToolset.Core | |||
7706 | var validationFlags = TransformFlags.PatchTransformDefault; | 7706 | var validationFlags = TransformFlags.PatchTransformDefault; |
7707 | string baselineFile = null; | 7707 | string baselineFile = null; |
7708 | string updateFile = null; | 7708 | string updateFile = null; |
7709 | string transformFile = null; | ||
7710 | 7709 | ||
7711 | foreach (var attrib in node.Attributes()) | 7710 | foreach (var attrib in node.Attributes()) |
7712 | { | 7711 | { |
@@ -7726,9 +7725,6 @@ namespace WixToolset.Core | |||
7726 | case "UpdateFile": | 7725 | case "UpdateFile": |
7727 | updateFile = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | 7726 | updateFile = this.Core.GetAttributeValue(sourceLineNumbers, attrib); |
7728 | break; | 7727 | break; |
7729 | case "TransformFile": | ||
7730 | transformFile = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
7731 | break; | ||
7732 | default: | 7728 | default: |
7733 | this.Core.UnexpectedAttribute(node, attrib); | 7729 | this.Core.UnexpectedAttribute(node, attrib); |
7734 | break; | 7730 | break; |
@@ -7746,26 +7742,14 @@ namespace WixToolset.Core | |||
7746 | id = Identifier.Invalid; | 7742 | id = Identifier.Invalid; |
7747 | } | 7743 | } |
7748 | 7744 | ||
7749 | if (!String.IsNullOrEmpty(baselineFile) || !String.IsNullOrEmpty(updateFile)) | 7745 | if (String.IsNullOrEmpty(baselineFile)) |
7750 | { | 7746 | { |
7751 | if (String.IsNullOrEmpty(baselineFile)) | 7747 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "BaselineFile")); |
7752 | { | ||
7753 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "BaselineFile", "UpdateFile")); | ||
7754 | } | ||
7755 | |||
7756 | if (String.IsNullOrEmpty(updateFile)) | ||
7757 | { | ||
7758 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "UpdateFile", "BaselineFile")); | ||
7759 | } | ||
7760 | |||
7761 | if (!String.IsNullOrEmpty(transformFile)) | ||
7762 | { | ||
7763 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "TransformFile", !String.IsNullOrEmpty(baselineFile) ? "BaselineFile" : "UpdateFile")); | ||
7764 | } | ||
7765 | } | 7748 | } |
7766 | else if (String.IsNullOrEmpty(transformFile)) | 7749 | |
7750 | if (String.IsNullOrEmpty(updateFile)) | ||
7767 | { | 7751 | { |
7768 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "BaselineFile", "TransformFile", true)); | 7752 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "UpdateFile")); |
7769 | } | 7753 | } |
7770 | 7754 | ||
7771 | foreach (var child in node.Elements()) | 7755 | foreach (var child in node.Elements()) |
@@ -7805,7 +7789,6 @@ namespace WixToolset.Core | |||
7805 | ValidationFlags = validationFlags, | 7789 | ValidationFlags = validationFlags, |
7806 | BaselineFile = new IntermediateFieldPathValue { Path = baselineFile }, | 7790 | BaselineFile = new IntermediateFieldPathValue { Path = baselineFile }, |
7807 | UpdateFile = new IntermediateFieldPathValue { Path = updateFile }, | 7791 | UpdateFile = new IntermediateFieldPathValue { Path = updateFile }, |
7808 | TransformFile = new IntermediateFieldPathValue { Path = transformFile }, | ||
7809 | }); | 7792 | }); |
7810 | } | 7793 | } |
7811 | } | 7794 | } |
diff --git a/src/wix/WixToolset.Core/ExtensibilityServices/BackendHelper.cs b/src/wix/WixToolset.Core/ExtensibilityServices/BackendHelper.cs index 20a47637..4a5cc607 100644 --- a/src/wix/WixToolset.Core/ExtensibilityServices/BackendHelper.cs +++ b/src/wix/WixToolset.Core/ExtensibilityServices/BackendHelper.cs | |||
@@ -6,8 +6,6 @@ namespace WixToolset.Core.ExtensibilityServices | |||
6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
7 | using WixToolset.Core.Bind; | 7 | using WixToolset.Core.Bind; |
8 | using WixToolset.Data; | 8 | using WixToolset.Data; |
9 | using WixToolset.Data.Symbols; | ||
10 | using WixToolset.Data.WindowsInstaller.Rows; | ||
11 | using WixToolset.Extensibility.Data; | 9 | using WixToolset.Extensibility.Data; |
12 | using WixToolset.Extensibility.Services; | 10 | using WixToolset.Extensibility.Services; |
13 | 11 | ||
@@ -17,21 +15,6 @@ namespace WixToolset.Core.ExtensibilityServices | |||
17 | { | 15 | { |
18 | } | 16 | } |
19 | 17 | ||
20 | public IFileFacade CreateFileFacade(FileSymbol file, AssemblySymbol assembly) | ||
21 | { | ||
22 | return new FileFacade(file, assembly); | ||
23 | } | ||
24 | |||
25 | public IFileFacade CreateFileFacade(FileRow fileRow) | ||
26 | { | ||
27 | return new FileFacade(fileRow); | ||
28 | } | ||
29 | |||
30 | public IFileFacade CreateFileFacadeFromMergeModule(FileSymbol fileSymbol) | ||
31 | { | ||
32 | return new FileFacade(true, fileSymbol); | ||
33 | } | ||
34 | |||
35 | public string CreateGuid() | 18 | public string CreateGuid() |
36 | { | 19 | { |
37 | return Common.GenerateGuid(); | 20 | return Common.GenerateGuid(); |
diff --git a/src/wix/WixToolset.Core/ExtensibilityServices/FileFacade.cs b/src/wix/WixToolset.Core/ExtensibilityServices/FileFacade.cs deleted file mode 100644 index 65043658..00000000 --- a/src/wix/WixToolset.Core/ExtensibilityServices/FileFacade.cs +++ /dev/null | |||
@@ -1,175 +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.ExtensibilityServices | ||
4 | { | ||
5 | using System; | ||
6 | using System.Collections.Generic; | ||
7 | using WixToolset.Data; | ||
8 | using WixToolset.Data.Symbols; | ||
9 | using WixToolset.Data.WindowsInstaller; | ||
10 | using WixToolset.Data.WindowsInstaller.Rows; | ||
11 | using WixToolset.Extensibility.Data; | ||
12 | |||
13 | internal class FileFacade : IFileFacade | ||
14 | { | ||
15 | public FileFacade(FileSymbol file, AssemblySymbol assembly) | ||
16 | { | ||
17 | this.FileSymbol = file; | ||
18 | this.AssemblySymbol = assembly; | ||
19 | |||
20 | this.Identifier = file.Id; | ||
21 | this.ComponentRef = file.ComponentRef; | ||
22 | } | ||
23 | |||
24 | public FileFacade(bool fromModule, FileSymbol file) | ||
25 | { | ||
26 | this.FromModule = fromModule; | ||
27 | this.FileSymbol = file; | ||
28 | |||
29 | this.Identifier = file.Id; | ||
30 | this.ComponentRef = file.ComponentRef; | ||
31 | } | ||
32 | |||
33 | public FileFacade(FileRow row) | ||
34 | { | ||
35 | this.FromTransform = true; | ||
36 | this.FileRow = row; | ||
37 | |||
38 | this.Identifier = new Identifier(AccessModifier.Section, row.File); | ||
39 | this.ComponentRef = row.Component; | ||
40 | } | ||
41 | |||
42 | public bool FromModule { get; } | ||
43 | |||
44 | public bool FromTransform { get; } | ||
45 | |||
46 | private FileRow FileRow { get; } | ||
47 | |||
48 | private FileSymbol FileSymbol { get; } | ||
49 | |||
50 | private AssemblySymbol AssemblySymbol { get; } | ||
51 | |||
52 | public string Id => this.Identifier.Id; | ||
53 | |||
54 | public Identifier Identifier { get; } | ||
55 | |||
56 | public string ComponentRef { get; } | ||
57 | |||
58 | public int DiskId | ||
59 | { | ||
60 | get => this.FileRow == null ? this.FileSymbol.DiskId ?? 1 : this.FileRow.DiskId; | ||
61 | set | ||
62 | { | ||
63 | if (this.FileRow == null) | ||
64 | { | ||
65 | this.FileSymbol.DiskId = value; | ||
66 | } | ||
67 | else | ||
68 | { | ||
69 | this.FileRow.DiskId = value; | ||
70 | } | ||
71 | } | ||
72 | } | ||
73 | |||
74 | public string FileName => this.FileRow == null ? this.FileSymbol.Name : this.FileRow.FileName; | ||
75 | |||
76 | public int FileSize | ||
77 | { | ||
78 | get => this.FileRow == null ? this.FileSymbol.FileSize : this.FileRow.FileSize; | ||
79 | set | ||
80 | { | ||
81 | if (this.FileRow == null) | ||
82 | { | ||
83 | this.FileSymbol.FileSize = value; | ||
84 | } | ||
85 | else | ||
86 | { | ||
87 | this.FileRow.FileSize = value; | ||
88 | } | ||
89 | } | ||
90 | } | ||
91 | |||
92 | public string Language | ||
93 | { | ||
94 | get => this.FileRow == null ? this.FileSymbol.Language : this.FileRow.Language; | ||
95 | set | ||
96 | { | ||
97 | if (this.FileRow == null) | ||
98 | { | ||
99 | this.FileSymbol.Language = value; | ||
100 | } | ||
101 | else | ||
102 | { | ||
103 | this.FileRow.Language = value; | ||
104 | } | ||
105 | } | ||
106 | } | ||
107 | |||
108 | public int? PatchGroup => this.FileRow == null ? this.FileSymbol.PatchGroup : null; | ||
109 | |||
110 | public int Sequence | ||
111 | { | ||
112 | get => this.FileRow == null ? this.FileSymbol.Sequence : this.FileRow.Sequence; | ||
113 | set | ||
114 | { | ||
115 | if (this.FileRow == null) | ||
116 | { | ||
117 | this.FileSymbol.Sequence = value; | ||
118 | } | ||
119 | else | ||
120 | { | ||
121 | this.FileRow.Sequence = value; | ||
122 | } | ||
123 | } | ||
124 | } | ||
125 | |||
126 | public SourceLineNumber SourceLineNumber => this.FileRow == null ? this.FileSymbol.SourceLineNumbers : this.FileRow.SourceLineNumbers; | ||
127 | |||
128 | public string SourcePath => this.FileRow == null ? this.FileSymbol.Source?.Path : this.FileRow.Source; | ||
129 | |||
130 | public bool Compressed => this.FileRow == null ? (this.FileSymbol.Attributes & FileSymbolAttributes.Compressed) == FileSymbolAttributes.Compressed : (this.FileRow.Attributes & WindowsInstallerConstants.MsidbFileAttributesCompressed) == WindowsInstallerConstants.MsidbFileAttributesCompressed; | ||
131 | |||
132 | public bool Uncompressed => this.FileRow == null ? (this.FileSymbol.Attributes & FileSymbolAttributes.Uncompressed) == FileSymbolAttributes.Uncompressed : (this.FileRow.Attributes & WindowsInstallerConstants.MsidbFileAttributesNoncompressed) == WindowsInstallerConstants.MsidbFileAttributesNoncompressed; | ||
133 | |||
134 | public string Version | ||
135 | { | ||
136 | get => this.FileRow == null ? this.FileSymbol.Version : this.FileRow.Version; | ||
137 | set | ||
138 | { | ||
139 | if (this.FileRow == null) | ||
140 | { | ||
141 | this.FileSymbol.Version = value; | ||
142 | } | ||
143 | else | ||
144 | { | ||
145 | this.FileRow.Version = value; | ||
146 | } | ||
147 | } | ||
148 | } | ||
149 | |||
150 | public AssemblyType? AssemblyType => this.FileRow == null ? this.AssemblySymbol?.Type : null; | ||
151 | |||
152 | public string AssemblyApplicationFileRef => this.FileRow == null ? this.AssemblySymbol?.ApplicationFileRef : throw new NotImplementedException(); | ||
153 | |||
154 | public string AssemblyManifestFileRef => this.FileRow == null ? this.AssemblySymbol?.ManifestFileRef : throw new NotImplementedException(); | ||
155 | |||
156 | /// <summary> | ||
157 | /// Gets the set of MsiAssemblyName rows created for this file. | ||
158 | /// </summary> | ||
159 | /// <value>RowCollection of MsiAssemblyName table.</value> | ||
160 | public List<MsiAssemblyNameSymbol> AssemblyNames { get; set; } | ||
161 | |||
162 | /// <summary> | ||
163 | /// Gets or sets the MsiFileHash row for this file. | ||
164 | /// </summary> | ||
165 | public MsiFileHashSymbol Hash { get; set; } | ||
166 | |||
167 | /// <summary> | ||
168 | /// Allows direct access to the underlying FileRow as requried for patching. | ||
169 | /// </summary> | ||
170 | public FileRow GetFileRow() | ||
171 | { | ||
172 | return this.FileRow ?? throw new NotImplementedException(); | ||
173 | } | ||
174 | } | ||
175 | } | ||
diff --git a/src/wix/WixToolset.Core/Bind/FileResolver.cs b/src/wix/WixToolset.Core/ExtensibilityServices/FileResolver.cs index eb878239..8f08e75e 100644 --- a/src/wix/WixToolset.Core/Bind/FileResolver.cs +++ b/src/wix/WixToolset.Core/ExtensibilityServices/FileResolver.cs | |||
@@ -1,51 +1,24 @@ | |||
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 | namespace WixToolset.Core.Bind | 3 | namespace WixToolset.Core.ExtensibilityServices |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
7 | using System.IO; | 7 | using System.IO; |
8 | using System.Linq; | ||
9 | using WixToolset.Data; | 8 | using WixToolset.Data; |
10 | using WixToolset.Extensibility; | 9 | using WixToolset.Extensibility; |
11 | using WixToolset.Extensibility.Data; | 10 | using WixToolset.Extensibility.Data; |
11 | using WixToolset.Extensibility.Services; | ||
12 | 12 | ||
13 | internal class FileResolver | 13 | internal class FileResolver : IFileResolver |
14 | { | 14 | { |
15 | private const string BindPathOpenString = "!(bindpath."; | 15 | private const string BindPathOpenString = "!(bindpath."; |
16 | 16 | ||
17 | private FileResolver(IEnumerable<IBindPath> bindPaths) | 17 | public string ResolveFile(string source, IEnumerable<ILibrarianExtension> librarianExtensions, IEnumerable<IBindPath> bindPaths, SourceLineNumber sourceLineNumbers, IntermediateSymbolDefinition symbolDefinition) |
18 | { | ||
19 | this.BindPaths = (bindPaths ?? Array.Empty<IBindPath>()).ToLookup(b => b.Stage); | ||
20 | this.RebaseTarget = this.BindPaths[BindStage.Target].Any(); | ||
21 | this.RebaseUpdated = this.BindPaths[BindStage.Updated].Any(); | ||
22 | } | ||
23 | |||
24 | public FileResolver(IEnumerable<IBindPath> bindPaths, IEnumerable<IResolverExtension> extensions) : this(bindPaths) | ||
25 | { | ||
26 | this.ResolverExtensions = extensions ?? Array.Empty<IResolverExtension>(); | ||
27 | } | ||
28 | |||
29 | public FileResolver(IEnumerable<IBindPath> bindPaths, IEnumerable<ILibrarianExtension> extensions) : this(bindPaths) | ||
30 | { | ||
31 | this.LibrarianExtensions = extensions ?? Array.Empty<ILibrarianExtension>(); | ||
32 | } | ||
33 | |||
34 | private ILookup<BindStage, IBindPath> BindPaths { get; } | ||
35 | |||
36 | public bool RebaseTarget { get; } | ||
37 | |||
38 | public bool RebaseUpdated { get; } | ||
39 | |||
40 | private IEnumerable<IResolverExtension> ResolverExtensions { get; } | ||
41 | |||
42 | private IEnumerable<ILibrarianExtension> LibrarianExtensions { get; } | ||
43 | |||
44 | public string Resolve(SourceLineNumber sourceLineNumbers, IntermediateSymbolDefinition symbolDefinition, string source) | ||
45 | { | 18 | { |
46 | var checkedPaths = new List<string>(); | 19 | var checkedPaths = new List<string>(); |
47 | 20 | ||
48 | foreach (var extension in this.LibrarianExtensions) | 21 | foreach (var extension in librarianExtensions) |
49 | { | 22 | { |
50 | var resolved = extension.ResolveFile(sourceLineNumbers, symbolDefinition, source); | 23 | var resolved = extension.ResolveFile(sourceLineNumbers, symbolDefinition, source); |
51 | 24 | ||
@@ -60,19 +33,10 @@ namespace WixToolset.Core.Bind | |||
60 | } | 33 | } |
61 | } | 34 | } |
62 | 35 | ||
63 | return this.MustResolveUsingBindPaths(source, symbolDefinition, sourceLineNumbers, BindStage.Normal, checkedPaths); | 36 | return this.MustResolveUsingBindPaths(source, symbolDefinition, sourceLineNumbers, bindPaths, checkedPaths); |
64 | } | 37 | } |
65 | 38 | ||
66 | /// <summary> | 39 | public string ResolveFile(string source, IEnumerable<IResolverExtension> resolverExtensions, IEnumerable<IBindPath> bindPaths, BindStage bindStage, SourceLineNumber sourceLineNumbers, IntermediateSymbolDefinition symbolDefinition, IEnumerable<string> alreadyCheckedPaths = null) |
67 | /// Resolves the source path of a file using binder extensions. | ||
68 | /// </summary> | ||
69 | /// <param name="source">Original source value.</param> | ||
70 | /// <param name="symbolDefinition">Optional type of source file being resolved.</param> | ||
71 | /// <param name="sourceLineNumbers">Optional source line of source file being resolved.</param> | ||
72 | /// <param name="bindStage">The binding stage used to determine what collection of bind paths will be used</param> | ||
73 | /// <param name="alreadyCheckedPaths">Optional collection of paths already checked.</param> | ||
74 | /// <returns>Should return a valid path for the stream to be imported.</returns> | ||
75 | public string ResolveFile(string source, IntermediateSymbolDefinition symbolDefinition, SourceLineNumber sourceLineNumbers, BindStage bindStage, IEnumerable<string> alreadyCheckedPaths = null) | ||
76 | { | 40 | { |
77 | var checkedPaths = new List<string>(); | 41 | var checkedPaths = new List<string>(); |
78 | 42 | ||
@@ -81,7 +45,7 @@ namespace WixToolset.Core.Bind | |||
81 | checkedPaths.AddRange(alreadyCheckedPaths); | 45 | checkedPaths.AddRange(alreadyCheckedPaths); |
82 | } | 46 | } |
83 | 47 | ||
84 | foreach (var extension in this.ResolverExtensions) | 48 | foreach (var extension in resolverExtensions) |
85 | { | 49 | { |
86 | var resolved = extension.ResolveFile(source, symbolDefinition, sourceLineNumbers, bindStage); | 50 | var resolved = extension.ResolveFile(source, symbolDefinition, sourceLineNumbers, bindStage); |
87 | 51 | ||
@@ -96,10 +60,10 @@ namespace WixToolset.Core.Bind | |||
96 | } | 60 | } |
97 | } | 61 | } |
98 | 62 | ||
99 | return this.MustResolveUsingBindPaths(source, symbolDefinition, sourceLineNumbers, bindStage, checkedPaths); | 63 | return this.MustResolveUsingBindPaths(source, symbolDefinition, sourceLineNumbers, bindPaths, checkedPaths); |
100 | } | 64 | } |
101 | 65 | ||
102 | private string MustResolveUsingBindPaths(string source, IntermediateSymbolDefinition symbolDefinition, SourceLineNumber sourceLineNumbers, BindStage bindStage, List<string> checkedPaths) | 66 | private string MustResolveUsingBindPaths(string source, IntermediateSymbolDefinition symbolDefinition, SourceLineNumber sourceLineNumbers, IEnumerable<IBindPath> bindPaths, List<string> checkedPaths) |
103 | { | 67 | { |
104 | string resolved = null; | 68 | string resolved = null; |
105 | 69 | ||
@@ -135,8 +99,6 @@ namespace WixToolset.Core.Bind | |||
135 | pathWithoutSourceDir = path.Substring(10); | 99 | pathWithoutSourceDir = path.Substring(10); |
136 | } | 100 | } |
137 | 101 | ||
138 | var bindPaths = this.BindPaths[bindStage]; | ||
139 | |||
140 | foreach (var bindPath in bindPaths) | 102 | foreach (var bindPath in bindPaths) |
141 | { | 103 | { |
142 | if (String.IsNullOrEmpty(bindName)) | 104 | if (String.IsNullOrEmpty(bindName)) |
@@ -145,36 +107,18 @@ namespace WixToolset.Core.Bind | |||
145 | { | 107 | { |
146 | if (!String.IsNullOrEmpty(pathWithoutSourceDir)) | 108 | if (!String.IsNullOrEmpty(pathWithoutSourceDir)) |
147 | { | 109 | { |
148 | var filePath = Path.Combine(bindPath.Path, pathWithoutSourceDir); | 110 | resolved = ResolveWithBindPath(bindPath.Path, pathWithoutSourceDir, checkedPaths); |
149 | |||
150 | checkedPaths.Add(filePath); | ||
151 | if (CheckFileExists(filePath)) | ||
152 | { | ||
153 | resolved = filePath; | ||
154 | } | ||
155 | } | 111 | } |
156 | 112 | ||
157 | if (String.IsNullOrEmpty(resolved)) | 113 | if (String.IsNullOrEmpty(resolved)) |
158 | { | 114 | { |
159 | var filePath = Path.Combine(bindPath.Path, path); | 115 | resolved = ResolveWithBindPath(bindPath.Path, path, checkedPaths); |
160 | |||
161 | checkedPaths.Add(filePath); | ||
162 | if (CheckFileExists(filePath)) | ||
163 | { | ||
164 | resolved = filePath; | ||
165 | } | ||
166 | } | 116 | } |
167 | } | 117 | } |
168 | } | 118 | } |
169 | else if (bindName.Equals(bindPath.Name, StringComparison.OrdinalIgnoreCase)) | 119 | else if (bindName.Equals(bindPath.Name, StringComparison.OrdinalIgnoreCase)) |
170 | { | 120 | { |
171 | var filePath = Path.Combine(bindPath.Path, path); | 121 | resolved = ResolveWithBindPath(bindPath.Path, path, checkedPaths); |
172 | |||
173 | checkedPaths.Add(filePath); | ||
174 | if (CheckFileExists(filePath)) | ||
175 | { | ||
176 | resolved = filePath; | ||
177 | } | ||
178 | } | 122 | } |
179 | 123 | ||
180 | if (!String.IsNullOrEmpty(resolved)) | 124 | if (!String.IsNullOrEmpty(resolved)) |
@@ -186,12 +130,26 @@ namespace WixToolset.Core.Bind | |||
186 | 130 | ||
187 | if (null == resolved) | 131 | if (null == resolved) |
188 | { | 132 | { |
189 | throw new WixException(ErrorMessages.FileNotFound(sourceLineNumbers, source, symbolDefinition.Name, checkedPaths)); | 133 | throw new WixException(ErrorMessages.FileNotFound(sourceLineNumbers, source, symbolDefinition?.Name, checkedPaths)); |
190 | } | 134 | } |
191 | 135 | ||
192 | return resolved; | 136 | return resolved; |
193 | } | 137 | } |
194 | 138 | ||
139 | private static string ResolveWithBindPath(string bindPath, string relativePath, List<string> checkedPaths) | ||
140 | { | ||
141 | var filePath = Path.Combine(bindPath, relativePath); | ||
142 | |||
143 | checkedPaths.Add(filePath); | ||
144 | |||
145 | if (CheckFileExists(filePath)) | ||
146 | { | ||
147 | return filePath; | ||
148 | } | ||
149 | |||
150 | return null; | ||
151 | } | ||
152 | |||
195 | private static bool CheckFileExists(string path) | 153 | private static bool CheckFileExists(string path) |
196 | { | 154 | { |
197 | try | 155 | try |
diff --git a/src/wix/WixToolset.Core/Librarian.cs b/src/wix/WixToolset.Core/Librarian.cs index 2762fb33..968dd946 100644 --- a/src/wix/WixToolset.Core/Librarian.cs +++ b/src/wix/WixToolset.Core/Librarian.cs | |||
@@ -5,7 +5,6 @@ namespace WixToolset.Core | |||
5 | using System; | 5 | using System; |
6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
7 | using System.Linq; | 7 | using System.Linq; |
8 | using WixToolset.Core.Bind; | ||
9 | using WixToolset.Core.Link; | 8 | using WixToolset.Core.Link; |
10 | using WixToolset.Data; | 9 | using WixToolset.Data; |
11 | using WixToolset.Extensibility.Data; | 10 | using WixToolset.Extensibility.Data; |
@@ -21,6 +20,7 @@ namespace WixToolset.Core | |||
21 | this.ServiceProvider = serviceProvider; | 20 | this.ServiceProvider = serviceProvider; |
22 | 21 | ||
23 | this.Messaging = this.ServiceProvider.GetService<IMessaging>(); | 22 | this.Messaging = this.ServiceProvider.GetService<IMessaging>(); |
23 | this.FileResolver = this.ServiceProvider.GetService<IFileResolver>(); | ||
24 | this.LayoutServices = this.ServiceProvider.GetService<ILayoutServices>(); | 24 | this.LayoutServices = this.ServiceProvider.GetService<ILayoutServices>(); |
25 | } | 25 | } |
26 | 26 | ||
@@ -28,6 +28,8 @@ namespace WixToolset.Core | |||
28 | 28 | ||
29 | private IMessaging Messaging { get; } | 29 | private IMessaging Messaging { get; } |
30 | 30 | ||
31 | private IFileResolver FileResolver { get; } | ||
32 | |||
31 | private ILayoutServices LayoutServices { get; } | 33 | private ILayoutServices LayoutServices { get; } |
32 | 34 | ||
33 | /// <summary> | 35 | /// <summary> |
@@ -97,7 +99,7 @@ namespace WixToolset.Core | |||
97 | { | 99 | { |
98 | var variableResolver = this.ServiceProvider.GetService<IVariableResolver>(); | 100 | var variableResolver = this.ServiceProvider.GetService<IVariableResolver>(); |
99 | 101 | ||
100 | var fileResolver = new FileResolver(context.BindPaths, context.Extensions); | 102 | var bindPaths = context.BindPaths.Where(b => b.Stage == BindStage.Normal).ToList(); |
101 | 103 | ||
102 | foreach (var symbol in sections.SelectMany(s => s.Symbols)) | 104 | foreach (var symbol in sections.SelectMany(s => s.Symbols)) |
103 | { | 105 | { |
@@ -109,7 +111,7 @@ namespace WixToolset.Core | |||
109 | { | 111 | { |
110 | var resolution = variableResolver.ResolveVariables(symbol.SourceLineNumbers, pathField.Path); | 112 | var resolution = variableResolver.ResolveVariables(symbol.SourceLineNumbers, pathField.Path); |
111 | 113 | ||
112 | var file = fileResolver.Resolve(symbol.SourceLineNumbers, symbol.Definition, resolution.Value); | 114 | var file = this.FileResolver.ResolveFile(resolution.Value, context.Extensions, bindPaths, symbol.SourceLineNumbers, symbol.Definition); |
113 | 115 | ||
114 | if (!String.IsNullOrEmpty(file)) | 116 | if (!String.IsNullOrEmpty(file)) |
115 | { | 117 | { |
diff --git a/src/wix/WixToolset.Core/Resolver.cs b/src/wix/WixToolset.Core/Resolver.cs index e93f8e1b..f7aa6ff9 100644 --- a/src/wix/WixToolset.Core/Resolver.cs +++ b/src/wix/WixToolset.Core/Resolver.cs | |||
@@ -23,12 +23,16 @@ namespace WixToolset.Core | |||
23 | this.ServiceProvider = serviceProvider; | 23 | this.ServiceProvider = serviceProvider; |
24 | 24 | ||
25 | this.Messaging = serviceProvider.GetService<IMessaging>(); | 25 | this.Messaging = serviceProvider.GetService<IMessaging>(); |
26 | |||
27 | this.FileResolver = serviceProvider.GetService<IFileResolver>(); | ||
26 | } | 28 | } |
27 | 29 | ||
28 | private IServiceProvider ServiceProvider { get; } | 30 | private IServiceProvider ServiceProvider { get; } |
29 | 31 | ||
30 | private IMessaging Messaging { get; } | 32 | private IMessaging Messaging { get; } |
31 | 33 | ||
34 | private IFileResolver FileResolver { get; } | ||
35 | |||
32 | public IResolveResult Resolve(IResolveContext context) | 36 | public IResolveResult Resolve(IResolveContext context) |
33 | { | 37 | { |
34 | foreach (var extension in context.Extensions) | 38 | foreach (var extension in context.Extensions) |
@@ -45,7 +49,7 @@ namespace WixToolset.Core | |||
45 | 49 | ||
46 | this.LocalizeUI(variableResolver, context.IntermediateRepresentation); | 50 | this.LocalizeUI(variableResolver, context.IntermediateRepresentation); |
47 | 51 | ||
48 | resolveResult = this.DoResolve(context, variableResolver); | 52 | resolveResult = this.ResolveFields(context, variableResolver); |
49 | 53 | ||
50 | var primaryLocalization = filteredLocalizations.FirstOrDefault(); | 54 | var primaryLocalization = filteredLocalizations.FirstOrDefault(); |
51 | 55 | ||
@@ -71,49 +75,18 @@ namespace WixToolset.Core | |||
71 | return resolveResult; | 75 | return resolveResult; |
72 | } | 76 | } |
73 | 77 | ||
74 | private ResolveResult DoResolve(IResolveContext context, IVariableResolver variableResolver) | 78 | private ResolveResult ResolveFields(IResolveContext context, IVariableResolver variableResolver) |
75 | { | 79 | { |
76 | var buildingPatch = context.IntermediateRepresentation.Sections.Any(s => s.Type == SectionType.Patch); | ||
77 | |||
78 | var filesWithEmbeddedFiles = new ExtractEmbeddedFiles(); | 80 | var filesWithEmbeddedFiles = new ExtractEmbeddedFiles(); |
79 | 81 | ||
80 | IReadOnlyCollection<DelayedField> delayedFields; | 82 | IReadOnlyCollection<DelayedField> delayedFields; |
81 | { | 83 | { |
82 | var command = new ResolveFieldsCommand(); | 84 | var command = new ResolveFieldsCommand(this.Messaging, this.FileResolver, variableResolver, context.BindPaths, context.Extensions, filesWithEmbeddedFiles, context.IntermediateFolder, context.IntermediateRepresentation, context.AllowUnresolvedVariables); |
83 | command.Messaging = this.Messaging; | ||
84 | command.BuildingPatch = buildingPatch; | ||
85 | command.VariableResolver = variableResolver; | ||
86 | command.BindPaths = context.BindPaths; | ||
87 | command.Extensions = context.Extensions; | ||
88 | command.FilesWithEmbeddedFiles = filesWithEmbeddedFiles; | ||
89 | command.IntermediateFolder = context.IntermediateFolder; | ||
90 | command.Intermediate = context.IntermediateRepresentation; | ||
91 | command.SupportDelayedResolution = true; | ||
92 | command.AllowUnresolvedVariables = context.AllowUnresolvedVariables; | ||
93 | command.Execute(); | 85 | command.Execute(); |
94 | 86 | ||
95 | delayedFields = command.DelayedFields; | 87 | delayedFields = command.DelayedFields; |
96 | } | 88 | } |
97 | 89 | ||
98 | #if TODO_PATCHING | ||
99 | if (context.IntermediateRepresentation.SubStorages != null) | ||
100 | { | ||
101 | foreach (SubStorage transform in context.IntermediateRepresentation.SubStorages) | ||
102 | { | ||
103 | var command = new ResolveFieldsCommand(); | ||
104 | command.BuildingPatch = buildingPatch; | ||
105 | command.BindVariableResolver = context.WixVariableResolver; | ||
106 | command.BindPaths = context.BindPaths; | ||
107 | command.Extensions = context.Extensions; | ||
108 | command.FilesWithEmbeddedFiles = filesWithEmbeddedFiles; | ||
109 | command.IntermediateFolder = context.IntermediateFolder; | ||
110 | command.Intermediate = context.IntermediateRepresentation; | ||
111 | command.SupportDelayedResolution = false; | ||
112 | command.Execute(); | ||
113 | } | ||
114 | } | ||
115 | #endif | ||
116 | |||
117 | var expectedEmbeddedFiles = filesWithEmbeddedFiles.GetExpectedEmbeddedFiles(); | 90 | var expectedEmbeddedFiles = filesWithEmbeddedFiles.GetExpectedEmbeddedFiles(); |
118 | 91 | ||
119 | context.IntermediateRepresentation.UpdateLevel(IntermediateLevels.Resolved); | 92 | context.IntermediateRepresentation.UpdateLevel(IntermediateLevels.Resolved); |
diff --git a/src/wix/WixToolset.Core/WixToolsetServiceProvider.cs b/src/wix/WixToolset.Core/WixToolsetServiceProvider.cs index fa6b369d..5620bcd2 100644 --- a/src/wix/WixToolset.Core/WixToolsetServiceProvider.cs +++ b/src/wix/WixToolset.Core/WixToolsetServiceProvider.cs | |||
@@ -27,6 +27,7 @@ namespace WixToolset.Core | |||
27 | this.AddService((provider, singletons) => AddSingleton<ILayoutServices>(singletons, new LayoutServices(provider))); | 27 | this.AddService((provider, singletons) => AddSingleton<ILayoutServices>(singletons, new LayoutServices(provider))); |
28 | this.AddService((provider, singletons) => AddSingleton<IBackendHelper>(singletons, new BackendHelper(provider))); | 28 | this.AddService((provider, singletons) => AddSingleton<IBackendHelper>(singletons, new BackendHelper(provider))); |
29 | this.AddService((provider, singletons) => AddSingleton<IPathResolver>(singletons, new PathResolver())); | 29 | this.AddService((provider, singletons) => AddSingleton<IPathResolver>(singletons, new PathResolver())); |
30 | this.AddService((provider, singletons) => AddSingleton<IFileResolver>(singletons, new FileResolver())); | ||
30 | this.AddService((provider, singletons) => AddSingleton<IFileSystem>(singletons, new FileSystem())); | 31 | this.AddService((provider, singletons) => AddSingleton<IFileSystem>(singletons, new FileSystem())); |
31 | this.AddService((provider, singletons) => AddSingleton<IWixBranding>(singletons, new WixBranding())); | 32 | this.AddService((provider, singletons) => AddSingleton<IWixBranding>(singletons, new WixBranding())); |
32 | 33 | ||
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/PatchFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/PatchFixture.cs index a8aff8d8..c330fd02 100644 --- a/src/wix/test/WixToolsetTest.CoreIntegration/PatchFixture.cs +++ b/src/wix/test/WixToolsetTest.CoreIntegration/PatchFixture.cs | |||
@@ -5,6 +5,7 @@ namespace WixToolsetTest.CoreIntegration | |||
5 | using System; | 5 | using System; |
6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
7 | using System.ComponentModel; | 7 | using System.ComponentModel; |
8 | using System.Diagnostics; | ||
8 | using System.IO; | 9 | using System.IO; |
9 | using System.Linq; | 10 | using System.Linq; |
10 | using System.Runtime.InteropServices; | 11 | using System.Runtime.InteropServices; |
@@ -22,8 +23,11 @@ namespace WixToolsetTest.CoreIntegration | |||
22 | public class PatchFixture : IDisposable | 23 | public class PatchFixture : IDisposable |
23 | { | 24 | { |
24 | private static readonly XNamespace PatchNamespace = "http://www.microsoft.com/msi/patch_applicability.xsd"; | 25 | private static readonly XNamespace PatchNamespace = "http://www.microsoft.com/msi/patch_applicability.xsd"; |
26 | private static readonly XName TargetProductCodeName = PatchNamespace + "TargetProductCode"; | ||
27 | |||
25 | private readonly DisposableFileSystem tempFileSystem; | 28 | private readonly DisposableFileSystem tempFileSystem; |
26 | private readonly string tempBaseFolder; | 29 | private readonly string tempBaseFolder; |
30 | private readonly string templateSourceFolder; | ||
27 | private readonly string templateBaselinePdb; | 31 | private readonly string templateBaselinePdb; |
28 | private readonly string templateUpdatePdb; | 32 | private readonly string templateUpdatePdb; |
29 | private readonly string templateUpdateNoFilesChangedPdb; | 33 | private readonly string templateUpdateNoFilesChangedPdb; |
@@ -33,14 +37,14 @@ namespace WixToolsetTest.CoreIntegration | |||
33 | this.tempFileSystem = new DisposableFileSystem(); | 37 | this.tempFileSystem = new DisposableFileSystem(); |
34 | this.tempBaseFolder = this.tempFileSystem.GetFolder(); | 38 | this.tempBaseFolder = this.tempFileSystem.GetFolder(); |
35 | 39 | ||
36 | var templateSourceFolder = TestData.Get(@"TestData", "PatchTemplatePackage"); | 40 | this.templateSourceFolder = TestData.Get(@"TestData", "PatchTemplatePackage"); |
37 | var tempFolderBaseline = Path.Combine(this.tempBaseFolder, "PatchTemplatePackage", "baseline"); | 41 | var tempFolderBaseline = Path.Combine(this.tempBaseFolder, "PatchTemplatePackage", "baseline"); |
38 | var tempFolderUpdate = Path.Combine(this.tempBaseFolder, "PatchTemplatePackage", "update"); | 42 | var tempFolderUpdate = Path.Combine(this.tempBaseFolder, "PatchTemplatePackage", "update"); |
39 | var tempFolderUpdateNoFileChanges = Path.Combine(this.tempBaseFolder, "PatchTemplatePackage", "updatewithoutfilechanges"); | 43 | var tempFolderUpdateNoFileChanges = Path.Combine(this.tempBaseFolder, "PatchTemplatePackage", "updatewithoutfilechanges"); |
40 | 44 | ||
41 | this.templateBaselinePdb = BuildMsi("Baseline.msi", templateSourceFolder, tempFolderBaseline, "1.0.0", "1.0.0", "1.0.0", new[] { Path.Combine(templateSourceFolder, ".baseline-data") }); | 45 | this.templateBaselinePdb = BuildMsi("Baseline.msi", this.templateSourceFolder, tempFolderBaseline, "1.0.0", "1.0.0", "1.0.0", new[] { Path.Combine(this.templateSourceFolder, ".baseline-data") }); |
42 | this.templateUpdatePdb = BuildMsi("Update.msi", templateSourceFolder, tempFolderUpdate, "1.0.1", "1.0.1", "1.0.1", new[] { Path.Combine(templateSourceFolder, ".update-data") }); | 46 | this.templateUpdatePdb = BuildMsi("Update.msi", this.templateSourceFolder, tempFolderUpdate, "1.0.1", "1.0.1", "1.0.1", new[] { Path.Combine(this.templateSourceFolder, ".update-data") }); |
43 | this.templateUpdateNoFilesChangedPdb = BuildMsi("Update.msi", templateSourceFolder, tempFolderUpdateNoFileChanges, "1.0.1", "1.0.1", "1.0.1", new[] { Path.Combine(templateSourceFolder, ".baseline-data") }); | 47 | this.templateUpdateNoFilesChangedPdb = BuildMsi("Update.msi", this.templateSourceFolder, tempFolderUpdateNoFileChanges, "1.0.1", "1.0.1", "1.0.1", new[] { Path.Combine(this.templateSourceFolder, ".baseline-data") }); |
44 | } | 48 | } |
45 | 49 | ||
46 | public void Dispose() | 50 | public void Dispose() |
@@ -49,7 +53,7 @@ namespace WixToolsetTest.CoreIntegration | |||
49 | } | 53 | } |
50 | 54 | ||
51 | [Fact] | 55 | [Fact] |
52 | public void CanBuildSimplePatch() | 56 | public void CanBuildSimplePatchUsingWixpdbs() |
53 | { | 57 | { |
54 | var folder = TestData.Get(@"TestData", "PatchSingle"); | 58 | var folder = TestData.Get(@"TestData", "PatchSingle"); |
55 | 59 | ||
@@ -66,14 +70,13 @@ namespace WixToolsetTest.CoreIntegration | |||
66 | Assert.True(File.Exists(update1Pdb)); | 70 | Assert.True(File.Exists(update1Pdb)); |
67 | 71 | ||
68 | var doc = GetExtractPatchXml(patchPath); | 72 | var doc = GetExtractPatchXml(patchPath); |
69 | WixAssert.StringEqual("{7D326855-E790-4A94-8611-5351F8321FCA}", doc.Root.Element(PatchNamespace + "TargetProductCode").Value); | 73 | WixAssert.StringEqual("{7D326855-E790-4A94-8611-5351F8321FCA}", doc.Root.Element(TargetProductCodeName).Value); |
70 | 74 | ||
71 | var names = Query.GetSubStorageNames(patchPath); | 75 | var names = Query.GetSubStorageNames(patchPath); |
72 | WixAssert.CompareLineByLine(new[] { "#RTM.1", "RTM.1" }, names); | 76 | WixAssert.CompareLineByLine(new[] { "#RTM.1", "RTM.1" }, names); |
73 | 77 | ||
74 | var cab = Path.Combine(tempFolder, "foo.cab"); | 78 | var cab = Path.Combine(tempFolder, "foo.cab"); |
75 | Query.ExtractStream(patchPath, "foo.cab", cab); | 79 | Query.ExtractStream(patchPath, "foo.cab", cab); |
76 | Assert.True(File.Exists(cab)); | ||
77 | 80 | ||
78 | var files = Query.GetCabinetFiles(cab); | 81 | var files = Query.GetCabinetFiles(cab); |
79 | WixAssert.CompareLineByLine(new[] { "a.txt", "b.txt" }, files.Select(f => f.Name).ToArray()); | 82 | WixAssert.CompareLineByLine(new[] { "a.txt", "b.txt" }, files.Select(f => f.Name).ToArray()); |
@@ -81,7 +84,37 @@ namespace WixToolsetTest.CoreIntegration | |||
81 | } | 84 | } |
82 | 85 | ||
83 | [Fact] | 86 | [Fact] |
84 | public void CanBuildSimplePatchWithFileChanges() | 87 | public void CanBuildSimplePatchWithFileChangesUsingMsi() |
88 | { | ||
89 | var sourceFolder = TestData.Get(@"TestData", "PatchWithFileChangesUsingMsi"); | ||
90 | |||
91 | using (var fs = new DisposableFileSystem()) | ||
92 | { | ||
93 | var baseFolder = fs.GetFolder(); | ||
94 | var tempFolderPatch = Path.Combine(baseFolder, "patch"); | ||
95 | |||
96 | var patchPdb = BuildMsp("Patch1.msp", sourceFolder, tempFolderPatch, "1.0.1", bindpaths: new[] { Path.GetDirectoryName(this.templateBaselinePdb), Path.GetDirectoryName(this.templateUpdatePdb) }); | ||
97 | var patchPath = Path.ChangeExtension(patchPdb, ".msp"); | ||
98 | |||
99 | var doc = GetExtractPatchXml(patchPath); | ||
100 | WixAssert.StringEqual("{11111111-2222-3333-4444-555555555555}", doc.Root.Element(TargetProductCodeName).Value); | ||
101 | |||
102 | var names = Query.GetSubStorageNames(patchPath); | ||
103 | WixAssert.CompareLineByLine(new[] { "#RTM.1", "RTM.1" }, names); | ||
104 | |||
105 | var cab = Path.Combine(baseFolder, "foo.cab"); | ||
106 | Query.ExtractStream(patchPath, "foo.cab", cab); | ||
107 | |||
108 | var files = Query.GetCabinetFiles(cab); | ||
109 | var file = files.Single(); | ||
110 | WixAssert.StringEqual("a.txt", file.Name); | ||
111 | var contents = file.OpenText().ReadToEnd(); | ||
112 | WixAssert.StringEqual("This is A v1.0.1 from the '.update-data' folder in 'PatchTemplatePackage'.\r\n\r\nLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.\r\n", contents); | ||
113 | } | ||
114 | } | ||
115 | |||
116 | [Fact] | ||
117 | public void CanBuildSimplePatchWithFileChangesUsingWixpdb() | ||
85 | { | 118 | { |
86 | var sourceFolder = TestData.Get(@"TestData", "PatchWithFileChanges"); | 119 | var sourceFolder = TestData.Get(@"TestData", "PatchWithFileChanges"); |
87 | 120 | ||
@@ -94,7 +127,7 @@ namespace WixToolsetTest.CoreIntegration | |||
94 | var patchPath = Path.ChangeExtension(patchPdb, ".msp"); | 127 | var patchPath = Path.ChangeExtension(patchPdb, ".msp"); |
95 | 128 | ||
96 | var doc = GetExtractPatchXml(patchPath); | 129 | var doc = GetExtractPatchXml(patchPath); |
97 | WixAssert.StringEqual("{11111111-2222-3333-4444-555555555555}", doc.Root.Element(PatchNamespace + "TargetProductCode").Value); | 130 | WixAssert.StringEqual("{11111111-2222-3333-4444-555555555555}", doc.Root.Element(TargetProductCodeName).Value); |
98 | 131 | ||
99 | var names = Query.GetSubStorageNames(patchPath); | 132 | var names = Query.GetSubStorageNames(patchPath); |
100 | WixAssert.CompareLineByLine(new[] { "#RTM.1", "RTM.1" }, names); | 133 | WixAssert.CompareLineByLine(new[] { "#RTM.1", "RTM.1" }, names); |
@@ -106,11 +139,73 @@ namespace WixToolsetTest.CoreIntegration | |||
106 | var file = files.Single(); | 139 | var file = files.Single(); |
107 | WixAssert.StringEqual("a.txt", file.Name); | 140 | WixAssert.StringEqual("a.txt", file.Name); |
108 | var contents = file.OpenText().ReadToEnd(); | 141 | var contents = file.OpenText().ReadToEnd(); |
109 | WixAssert.StringEqual("This is A v1.0.1\r\n", contents); | 142 | WixAssert.StringEqual("This is A v1.0.1 from the '.update-data' folder in 'PatchTemplatePackage'.\r\n\r\nLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.\r\n", contents); |
110 | } | 143 | } |
111 | } | 144 | } |
112 | 145 | ||
113 | [Fact] | 146 | [Fact] |
147 | public void CanBuildSimplePatchWithFileChangesUsingWixpdbAndAlternativeUpdatedSourceFolder() | ||
148 | { | ||
149 | var sourceFolder = TestData.Get(@"TestData", "PatchWithFileChanges"); | ||
150 | |||
151 | using (var fs = new DisposableFileSystem()) | ||
152 | { | ||
153 | var baseFolder = fs.GetFolder(); | ||
154 | var tempFolderPatch = Path.Combine(baseFolder, "patch"); | ||
155 | |||
156 | var patchPdb = BuildMsp("Patch1.msp", sourceFolder, tempFolderPatch, "1.0.1", bindpaths: new[] { Path.GetDirectoryName(this.templateBaselinePdb), Path.GetDirectoryName(this.templateUpdatePdb) }, updateBindpaths: new[] { Path.Combine(this.templateSourceFolder, ".update-data-alternative") }); | ||
157 | var patchPath = Path.ChangeExtension(patchPdb, ".msp"); | ||
158 | |||
159 | var doc = GetExtractPatchXml(patchPath); | ||
160 | WixAssert.StringEqual("{11111111-2222-3333-4444-555555555555}", doc.Root.Element(TargetProductCodeName).Value); | ||
161 | |||
162 | var names = Query.GetSubStorageNames(patchPath); | ||
163 | WixAssert.CompareLineByLine(new[] { "#RTM.1", "RTM.1" }, names); | ||
164 | |||
165 | var cab = Path.Combine(baseFolder, "foo.cab"); | ||
166 | Query.ExtractStream(patchPath, "foo.cab", cab); | ||
167 | |||
168 | var files = Query.GetCabinetFiles(cab); | ||
169 | var file = files.Single(); | ||
170 | WixAssert.StringEqual("a.txt", file.Name); | ||
171 | var contents = file.OpenText().ReadToEnd(); | ||
172 | WixAssert.StringEqual("This is A v1.0.1 from the '.update-data-alternative' folder in 'PatchTemplatePackage'.\r\n\r\nDiam quis enim lobortis scelerisque fermentum dui faucibus in ornare.\r\n", contents); | ||
173 | } | ||
174 | } | ||
175 | |||
176 | [Fact] | ||
177 | public void CanBuildPatchFromAdminImage() | ||
178 | { | ||
179 | var sourceFolder = TestData.Get(@"TestData", "PatchUsingAdminImages"); | ||
180 | |||
181 | var baseFolder = this.tempFileSystem.GetFolder(); | ||
182 | var tempFolderPatch = Path.Combine(baseFolder, "patch"); | ||
183 | var adminBaselineFolder = Path.Combine(baseFolder, "admin-baseline"); | ||
184 | var adminUpdateFolder = Path.Combine(baseFolder, "admin-update"); | ||
185 | |||
186 | CreateAdminImage(this.templateBaselinePdb, adminBaselineFolder); | ||
187 | CreateAdminImage(this.templateUpdatePdb, adminUpdateFolder); | ||
188 | |||
189 | var patchPdb = BuildMsp("Patch1.msp", sourceFolder, tempFolderPatch, "1.0.1", bindpaths: new[] { adminBaselineFolder, adminUpdateFolder }); | ||
190 | var patchPath = Path.ChangeExtension(patchPdb, ".msp"); | ||
191 | |||
192 | var doc = GetExtractPatchXml(patchPath); | ||
193 | WixAssert.StringEqual("{11111111-2222-3333-4444-555555555555}", doc.Root.Element(TargetProductCodeName).Value); | ||
194 | |||
195 | var names = Query.GetSubStorageNames(patchPath); | ||
196 | WixAssert.CompareLineByLine(new[] { "#RTM.1", "RTM.1" }, names); | ||
197 | |||
198 | var cab = Path.Combine(baseFolder, "foo.cab"); | ||
199 | Query.ExtractStream(patchPath, "foo.cab", cab); | ||
200 | |||
201 | var files = Query.GetCabinetFiles(cab); | ||
202 | var file = files.Single(); | ||
203 | WixAssert.StringEqual("a.txt", file.Name); | ||
204 | var contents = file.OpenText().ReadToEnd(); | ||
205 | WixAssert.StringEqual("This is A v1.0.1 from the '.update-data' folder in 'PatchTemplatePackage'.\r\n\r\nLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.\r\n", contents); | ||
206 | } | ||
207 | |||
208 | [Fact] | ||
114 | public void CanBuildSimplePatchWithNoFileChanges() | 209 | public void CanBuildSimplePatchWithNoFileChanges() |
115 | { | 210 | { |
116 | var folder = TestData.Get(@"TestData", "PatchNoFileChanges"); | 211 | var folder = TestData.Get(@"TestData", "PatchNoFileChanges"); |
@@ -123,14 +218,13 @@ namespace WixToolsetTest.CoreIntegration | |||
123 | var patchPath = Path.ChangeExtension(patchPdb, ".msp"); | 218 | var patchPath = Path.ChangeExtension(patchPdb, ".msp"); |
124 | 219 | ||
125 | var doc = GetExtractPatchXml(patchPath); | 220 | var doc = GetExtractPatchXml(patchPath); |
126 | WixAssert.StringEqual("{11111111-2222-3333-4444-555555555555}", doc.Root.Element(PatchNamespace + "TargetProductCode").Value); | 221 | WixAssert.StringEqual("{11111111-2222-3333-4444-555555555555}", doc.Root.Element(TargetProductCodeName).Value); |
127 | 222 | ||
128 | var names = Query.GetSubStorageNames(patchPath); | 223 | var names = Query.GetSubStorageNames(patchPath); |
129 | WixAssert.CompareLineByLine(new[] { "#RTM.1", "RTM.1" }, names); | 224 | WixAssert.CompareLineByLine(new[] { "#RTM.1", "RTM.1" }, names); |
130 | 225 | ||
131 | var cab = Path.Combine(tempFolder, "foo.cab"); | 226 | var cab = Path.Combine(tempFolder, "foo.cab"); |
132 | Query.ExtractStream(patchPath, "foo.cab", cab); | 227 | Query.ExtractStream(patchPath, "foo.cab", cab); |
133 | Assert.True(File.Exists(cab)); | ||
134 | 228 | ||
135 | var files = Query.GetCabinetFiles(cab); | 229 | var files = Query.GetCabinetFiles(cab); |
136 | Assert.Empty(files); | 230 | Assert.Empty(files); |
@@ -155,14 +249,13 @@ namespace WixToolsetTest.CoreIntegration | |||
155 | var patchPath = Path.ChangeExtension(patchPdb, ".msp"); | 249 | var patchPath = Path.ChangeExtension(patchPdb, ".msp"); |
156 | 250 | ||
157 | var doc = GetExtractPatchXml(patchPath); | 251 | var doc = GetExtractPatchXml(patchPath); |
158 | WixAssert.StringEqual("{7D326855-E790-4A94-8611-5351F8321FCA}", doc.Root.Element(PatchNamespace + "TargetProductCode").Value); | 252 | WixAssert.StringEqual("{7D326855-E790-4A94-8611-5351F8321FCA}", doc.Root.Element(TargetProductCodeName).Value); |
159 | 253 | ||
160 | var names = Query.GetSubStorageNames(patchPath); | 254 | var names = Query.GetSubStorageNames(patchPath); |
161 | WixAssert.CompareLineByLine(new[] { "#RTM.1", "RTM.1" }, names); | 255 | WixAssert.CompareLineByLine(new[] { "#RTM.1", "RTM.1" }, names); |
162 | 256 | ||
163 | var cab = Path.Combine(baseFolder, "foo.cab"); | 257 | var cab = Path.Combine(baseFolder, "foo.cab"); |
164 | Query.ExtractStream(patchPath, "foo.cab", cab); | 258 | Query.ExtractStream(patchPath, "foo.cab", cab); |
165 | Assert.True(File.Exists(cab)); | ||
166 | 259 | ||
167 | var files = Query.GetCabinetFiles(cab); | 260 | var files = Query.GetCabinetFiles(cab); |
168 | var file = files.Single(); | 261 | var file = files.Single(); |
@@ -197,7 +290,7 @@ namespace WixToolsetTest.CoreIntegration | |||
197 | var patchPath = Path.ChangeExtension(patchPdb, ".msp"); | 290 | var patchPath = Path.ChangeExtension(patchPdb, ".msp"); |
198 | 291 | ||
199 | var doc = GetExtractPatchXml(patchPath); | 292 | var doc = GetExtractPatchXml(patchPath); |
200 | WixAssert.StringEqual("{11111111-2222-3333-4444-555555555555}", doc.Root.Element(PatchNamespace + "TargetProductCode").Value); | 293 | WixAssert.StringEqual("{11111111-2222-3333-4444-555555555555}", doc.Root.Element(TargetProductCodeName).Value); |
201 | 294 | ||
202 | var names = Query.GetSubStorageNames(patchPath); | 295 | var names = Query.GetSubStorageNames(patchPath); |
203 | WixAssert.CompareLineByLine(new[] { "#ThisBaseLineIdIsTooLongAndGe.1", "ThisBaseLineIdIsTooLongAndGe.1" }, names); | 296 | WixAssert.CompareLineByLine(new[] { "#ThisBaseLineIdIsTooLongAndGe.1", "ThisBaseLineIdIsTooLongAndGe.1" }, names); |
@@ -217,12 +310,12 @@ namespace WixToolsetTest.CoreIntegration | |||
217 | var tempFolderPatch = Path.Combine(baseFolder, "patch"); | 310 | var tempFolderPatch = Path.Combine(baseFolder, "patch"); |
218 | 311 | ||
219 | var baselinePdb = BuildMsi("Baseline.msi", sourceFolder, tempFolderBaseline, "1.0.0", "1.0.0", "1.0.0"); | 312 | var baselinePdb = BuildMsi("Baseline.msi", sourceFolder, tempFolderBaseline, "1.0.0", "1.0.0", "1.0.0"); |
220 | var update1Pdb = BuildMsi("Update.msi", sourceFolder, tempFolderUpdate, "1.0.1", "1.0.1", "1.0.1"); | 313 | var updatePdb = BuildMsi("Update.msi", sourceFolder, tempFolderUpdate, "1.0.1", "1.0.1", "1.0.1"); |
221 | var patchPdb = BuildMsp("Patch1.msp", sourceFolder, tempFolderPatch, "1.0.1", bindpaths: new[] { Path.GetDirectoryName(baselinePdb), Path.GetDirectoryName(update1Pdb) }, hasNoFiles: true); | 314 | var patchPdb = BuildMsp("Patch1.msp", sourceFolder, tempFolderPatch, "1.0.1", bindpaths: new[] { Path.GetDirectoryName(baselinePdb), Path.GetDirectoryName(updatePdb) }, hasNoFiles: true); |
222 | var patchPath = Path.ChangeExtension(patchPdb, ".msp"); | 315 | var patchPath = Path.ChangeExtension(patchPdb, ".msp"); |
223 | 316 | ||
224 | Assert.True(File.Exists(baselinePdb)); | 317 | var doc = GetExtractPatchXml(patchPath); |
225 | Assert.True(File.Exists(update1Pdb)); | 318 | WixAssert.StringEqual("{7C871EC1-1F89-4850-A6A9-D7A4C21769F6}", doc.Root.Element(TargetProductCodeName).Value); |
226 | } | 319 | } |
227 | } | 320 | } |
228 | 321 | ||
@@ -317,7 +410,28 @@ namespace WixToolsetTest.CoreIntegration | |||
317 | return Path.ChangeExtension(outputPath, ".wixpdb"); | 410 | return Path.ChangeExtension(outputPath, ".wixpdb"); |
318 | } | 411 | } |
319 | 412 | ||
320 | private static string BuildMsp(string outputName, string sourceFolder, string baseFolder, string defineV, IEnumerable<string> bindpaths = null, bool hasNoFiles = false, bool warningsAsErrors = true) | 413 | private static string BuildMst(string transformName, string baseFolder, string templateBaselinePdb, string templateUpdatePdb) |
414 | { | ||
415 | var outputPath = Path.Combine(baseFolder, transformName); | ||
416 | |||
417 | var args = new List<string> | ||
418 | { | ||
419 | "msi", "transform", | ||
420 | templateBaselinePdb, | ||
421 | templateUpdatePdb, | ||
422 | "-intermediateFolder", Path.Combine(baseFolder), | ||
423 | "-t", "patch", | ||
424 | "-o", outputPath, | ||
425 | }; | ||
426 | |||
427 | var result = WixRunner.Execute(args.ToArray()); | ||
428 | |||
429 | result.AssertSuccess(); | ||
430 | |||
431 | return outputPath; | ||
432 | } | ||
433 | |||
434 | private static string BuildMsp(string outputName, string sourceFolder, string baseFolder, string defineV, IEnumerable<string> bindpaths = null, IEnumerable<string> targetBindpaths = null, IEnumerable<string> updateBindpaths = null, bool hasNoFiles = false, bool warningsAsErrors = true) | ||
321 | { | 435 | { |
322 | var outputPath = Path.Combine(baseFolder, Path.Combine("bin", outputName)); | 436 | var outputPath = Path.Combine(baseFolder, Path.Combine("bin", outputName)); |
323 | 437 | ||
@@ -332,10 +446,22 @@ namespace WixToolsetTest.CoreIntegration | |||
332 | "-o", outputPath | 446 | "-o", outputPath |
333 | }; | 447 | }; |
334 | 448 | ||
335 | foreach (var additionaBindPath in bindpaths ?? Enumerable.Empty<string>()) | 449 | foreach (var additionalBindPath in bindpaths ?? Enumerable.Empty<string>()) |
336 | { | 450 | { |
337 | args.Add("-bindpath"); | 451 | args.Add("-bindpath"); |
338 | args.Add(additionaBindPath); | 452 | args.Add(additionalBindPath); |
453 | } | ||
454 | |||
455 | foreach (var targetBindPath in targetBindpaths ?? Enumerable.Empty<string>()) | ||
456 | { | ||
457 | args.Add("-bindpath:target"); | ||
458 | args.Add(targetBindPath); | ||
459 | } | ||
460 | |||
461 | foreach (var updateBindpath in updateBindpaths ?? Enumerable.Empty<string>()) | ||
462 | { | ||
463 | args.Add("-bindpath:update"); | ||
464 | args.Add(updateBindpath); | ||
339 | } | 465 | } |
340 | 466 | ||
341 | var result = WixRunner.Execute(warningsAsErrors, args.ToArray()); | 467 | var result = WixRunner.Execute(warningsAsErrors, args.ToArray()); |
@@ -365,6 +491,16 @@ namespace WixToolsetTest.CoreIntegration | |||
365 | return Path.ChangeExtension(outputPath, ".wixpdb"); | 491 | return Path.ChangeExtension(outputPath, ".wixpdb"); |
366 | } | 492 | } |
367 | 493 | ||
494 | private static void CreateAdminImage(string msiPath, string targetDir) | ||
495 | { | ||
496 | var args = $"/a {Path.ChangeExtension(msiPath, "msi")} TARGETDIR={targetDir} /qn"; | ||
497 | |||
498 | var proc = Process.Start("msiexec.exe", args); | ||
499 | proc.WaitForExit(5000); | ||
500 | |||
501 | Assert.Equal(0, proc.ExitCode); | ||
502 | } | ||
503 | |||
368 | private static XDocument GetExtractPatchXml(string path) | 504 | private static XDocument GetExtractPatchXml(string path) |
369 | { | 505 | { |
370 | var buffer = new StringBuilder(65535); | 506 | var buffer = new StringBuilder(65535); |
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/PatchTemplatePackage/.baseline-data/A.txt b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/PatchTemplatePackage/.baseline-data/A.txt index 6fd385bd..f6c69979 100644 --- a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/PatchTemplatePackage/.baseline-data/A.txt +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/PatchTemplatePackage/.baseline-data/A.txt | |||
@@ -1 +1 @@ | |||
This is A v1.0.0 | This is A v1.0.0 from the "PatchTemplatePackage\.baseline-data" folder. | ||
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/PatchTemplatePackage/.update-data-alternative/A.txt b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/PatchTemplatePackage/.update-data-alternative/A.txt new file mode 100644 index 00000000..17e8c861 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/PatchTemplatePackage/.update-data-alternative/A.txt | |||
@@ -0,0 +1,3 @@ | |||
1 | This is A v1.0.1 from the '.update-data-alternative' folder in 'PatchTemplatePackage'. | ||
2 | |||
3 | Diam quis enim lobortis scelerisque fermentum dui faucibus in ornare. | ||
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/PatchTemplatePackage/.update-data/A.txt b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/PatchTemplatePackage/.update-data/A.txt index f7ec8b4e..26832a47 100644 --- a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/PatchTemplatePackage/.update-data/A.txt +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/PatchTemplatePackage/.update-data/A.txt | |||
@@ -1 +1,3 @@ | |||
1 | This is A v1.0.1 | 1 | This is A v1.0.1 from the '.update-data' folder in 'PatchTemplatePackage'. |
2 | |||
3 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod. | ||
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/PatchUsingAdminImages/Patch.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/PatchUsingAdminImages/Patch.wxs new file mode 100644 index 00000000..f9ea1f5d --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/PatchUsingAdminImages/Patch.wxs | |||
@@ -0,0 +1,16 @@ | |||
1 | <Wix xmlns='http://wixtoolset.org/schemas/v4/wxs'> | ||
2 | <Patch | ||
3 | AllowRemoval="yes" | ||
4 | DisplayName="~Test Patch v$(V)" | ||
5 | Description="~Test Small Update Patch v$(V)" | ||
6 | MoreInfoURL="http://www.example.com/" | ||
7 | Manufacturer="Example Corporation" | ||
8 | Classification="Update"> | ||
9 | |||
10 | <Media Id="1" Cabinet="foo.cab"> | ||
11 | <PatchBaseline Id="RTM" BaselineFile="Baseline.msi" UpdateFile="Update.msi" /> | ||
12 | </Media> | ||
13 | |||
14 | <PatchFamily Id='SequenceFamily' Version='$(V)' /> | ||
15 | </Patch> | ||
16 | </Wix> | ||
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/PatchWithFileChangesUsingMsi/Patch.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/PatchWithFileChangesUsingMsi/Patch.wxs new file mode 100644 index 00000000..f9ea1f5d --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/PatchWithFileChangesUsingMsi/Patch.wxs | |||
@@ -0,0 +1,16 @@ | |||
1 | <Wix xmlns='http://wixtoolset.org/schemas/v4/wxs'> | ||
2 | <Patch | ||
3 | AllowRemoval="yes" | ||
4 | DisplayName="~Test Patch v$(V)" | ||
5 | Description="~Test Small Update Patch v$(V)" | ||
6 | MoreInfoURL="http://www.example.com/" | ||
7 | Manufacturer="Example Corporation" | ||
8 | Classification="Update"> | ||
9 | |||
10 | <Media Id="1" Cabinet="foo.cab"> | ||
11 | <PatchBaseline Id="RTM" BaselineFile="Baseline.msi" UpdateFile="Update.msi" /> | ||
12 | </Media> | ||
13 | |||
14 | <PatchFamily Id='SequenceFamily' Version='$(V)' /> | ||
15 | </Patch> | ||
16 | </Wix> | ||