main
cs 171 lines 8.07 KB
Raw
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.Collections.Generic;
7 using System.Linq;
8 using WixToolset.Data;
9 using WixToolset.Data.WindowsInstaller;
10 using WixToolset.Data.WindowsInstaller.Rows;
11 using WixToolset.Extensibility.Data;
12 using WixToolset.Extensibility.Services;
13
14 internal class GetFileFacadesFromTransforms
15 {
16 public GetFileFacadesFromTransforms(IMessaging messaging, IWindowsInstallerBackendHelper backendHelper, FileSystemManager fileSystemManager, IEnumerable<SubStorage> subStorages)
17 {
18 this.Messaging = messaging;
19 this.BackendHelper = backendHelper;
20 this.FileSystemManager = fileSystemManager;
21 this.SubStorages = subStorages;
22 }
23
24 private IMessaging Messaging { get; }
25
26 private IWindowsInstallerBackendHelper BackendHelper { get; }
27
28 private FileSystemManager FileSystemManager { get; }
29
30 private IEnumerable<SubStorage> SubStorages { get; }
31
32 public List<IFileFacade> FileFacades { get; private set; }
33
34 public void Execute()
35 {
36 var allFileRows = new List<IFileFacade>();
37
38 var patchMediaFileRows = new Dictionary<int, RowDictionary<FileRow>>();
39
40 // Index paired transforms by name without their "#" prefix.
41 var pairedTransforms = this.SubStorages.Where(s => s.Name.StartsWith(PatchConstants.PairedPatchTransformPrefix)).ToDictionary(s => s.Name, s => s.Data);
42
43 // Enumerate through main transforms.
44 foreach (var substorage in this.SubStorages.Where(s => !s.Name.StartsWith(PatchConstants.PairedPatchTransformPrefix)))
45 {
46 var mainTransform = substorage.Data;
47 var mainFileTable = mainTransform.Tables["File"];
48
49 if (null == mainFileTable)
50 {
51 continue;
52 }
53
54 // Index File table of pairedTransform
55 var pairedTransform = pairedTransforms[PatchConstants.PairedPatchTransformPrefix + substorage.Name];
56 var pairedFileRows = new RowDictionary<FileRow>(pairedTransform.Tables["File"]);
57
58 foreach (var mainFileRow in mainFileTable.Rows.Where(f => f.Operation != RowOperation.Delete).Cast<FileRow>())
59 {
60 var mainFileId = mainFileRow.File;
61
62 // We need compare the underlying files and include all file changes.
63 var objectField = (ObjectField)mainFileRow.Fields[9];
64 var pairedFileRow = pairedFileRows.Get(mainFileId);
65
66 // If the file is new, we always need to add it to the patch.
67 if (mainFileRow.Operation == RowOperation.Add)
68 {
69 if (null != pairedFileRow) // RowOperation.Add
70 {
71 // Always patch-added, but never non-compressed.
72 pairedFileRow.Attributes |= WindowsInstallerConstants.MsidbFileAttributesPatchAdded;
73 pairedFileRow.Attributes &= ~WindowsInstallerConstants.MsidbFileAttributesNoncompressed;
74 pairedFileRow.Fields[6].Modified = true;
75 pairedFileRow.Operation = RowOperation.Add;
76 }
77 }
78 else
79 {
80 // If PreviousData doesn't exist, target and upgrade layout point to the same location. No need to compare.
81 if (null == objectField.PreviousData)
82 {
83 if (mainFileRow.Operation == RowOperation.None)
84 {
85 continue;
86 }
87 }
88 else
89 {
90 if (
91 #if TODO_PATCHING_DELTA
92 (0 == (PatchAttributeType.Ignore & mainWixFileRow.PatchAttributes)) &&
93 #endif
94 !this.FileSystemManager.CompareFiles(objectField.PreviousData, objectField.Data.ToString()))
95 {
96 // If the file is different, we need to mark the mainFileRow and pairedFileRow as modified.
97 mainFileRow.Operation = RowOperation.Modify;
98 if (null != pairedFileRow)
99 {
100 // Always patch-added, but never non-compressed.
101 pairedFileRow.Attributes |= WindowsInstallerConstants.MsidbFileAttributesPatchAdded;
102 pairedFileRow.Attributes &= ~WindowsInstallerConstants.MsidbFileAttributesNoncompressed;
103 pairedFileRow.Fields[6].Modified = true;
104 pairedFileRow.Operation = RowOperation.Modify;
105 }
106 }
107 else
108 {
109 // The File is same. We need mark all the attributes as unchanged.
110 mainFileRow.Operation = RowOperation.None;
111 foreach (var field in mainFileRow.Fields)
112 {
113 field.Modified = false;
114 }
115
116 if (null != pairedFileRow)
117 {
118 pairedFileRow.Attributes &= ~WindowsInstallerConstants.MsidbFileAttributesPatchAdded;
119 pairedFileRow.Fields[6].Modified = false;
120 pairedFileRow.Operation = RowOperation.None;
121 }
122 continue;
123 }
124 }
125 }
126
127 // index patch files by diskId+fileId
128 var diskId = mainFileRow.DiskId;
129
130 if (!patchMediaFileRows.TryGetValue(diskId, out var mediaFileRows))
131 {
132 mediaFileRows = new RowDictionary<FileRow>();
133 patchMediaFileRows.Add(diskId, mediaFileRows);
134 }
135
136 if (!mediaFileRows.TryGetValue(mainFileId, out var patchFileRow))
137 {
138 patchFileRow = (FileRow)mainFileRow.TableDefinition.CreateRow(mainFileRow.SourceLineNumbers);
139 mainFileRow.CopyTo(patchFileRow);
140
141 mediaFileRows.Add(patchFileRow);
142
143 #if TODO_PATCHING_DELTA
144 // TODO: should we be passing along delta information to the file facade? Probably, right?
145 #endif
146 var fileFacade = this.BackendHelper.CreateFileFacade(patchFileRow);
147
148 allFileRows.Add(fileFacade);
149 }
150 else
151 {
152 // TODO: confirm the rest of data is identical?
153
154 // make sure Source is same. Otherwise we are silently ignoring a file.
155 if (0 != String.Compare(patchFileRow.Source, mainFileRow.Source, StringComparison.OrdinalIgnoreCase))
156 {
157 this.Messaging.Write(ErrorMessages.SameFileIdDifferentSource(mainFileRow.SourceLineNumbers, mainFileId, patchFileRow.Source, mainFileRow.Source));
158 }
159
160 #if TODO_PATCHING_DELTA
161 // capture the previous file versions (and associated data) from this targeted instance of the baseline into the current filerow.
162 patchFileRow.AppendPreviousDataFrom(mainFileRow);
163 #endif
164 }
165 }
166 }
167
168 this.FileFacades = allFileRows;
169 }
170 }
171 }