diff options
| author | Rob Mensching <rob@firegiant.com> | 2020-01-24 15:27:20 -0800 |
|---|---|---|
| committer | Rob Mensching <rob@firegiant.com> | 2020-02-05 16:15:47 -0800 |
| commit | 6ff680e386b1543ad1a58d1b1d465ce8aa20bc7d (patch) | |
| tree | c717333cd10d5592e59dfb898b391275bba1f389 /src/WixToolset.Core.WindowsInstaller/Bind/PatchTransform.cs | |
| parent | 6e2e67ab55c75f4655397588c0dcc64f50d22f92 (diff) | |
| download | wix-6ff680e386b1543ad1a58d1b1d465ce8aa20bc7d.tar.gz wix-6ff680e386b1543ad1a58d1b1d465ce8aa20bc7d.tar.bz2 wix-6ff680e386b1543ad1a58d1b1d465ce8aa20bc7d.zip | |
Start on new patch infrastructure
Diffstat (limited to 'src/WixToolset.Core.WindowsInstaller/Bind/PatchTransform.cs')
| -rw-r--r-- | src/WixToolset.Core.WindowsInstaller/Bind/PatchTransform.cs | 246 |
1 files changed, 246 insertions, 0 deletions
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/PatchTransform.cs b/src/WixToolset.Core.WindowsInstaller/Bind/PatchTransform.cs new file mode 100644 index 00000000..5ada29de --- /dev/null +++ b/src/WixToolset.Core.WindowsInstaller/Bind/PatchTransform.cs | |||
| @@ -0,0 +1,246 @@ | |||
| 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; | ||
| 7 | using System.Globalization; | ||
| 8 | using System.Text; | ||
| 9 | using System.Text.RegularExpressions; | ||
| 10 | using WixToolset.Data; | ||
| 11 | using WixToolset.Data.WindowsInstaller; | ||
| 12 | using WixToolset.Extensibility; | ||
| 13 | |||
| 14 | internal class PatchTransform | ||
| 15 | { | ||
| 16 | public PatchTransform(string baseline, WindowsInstallerData transform) | ||
| 17 | { | ||
| 18 | this.Baseline = baseline; | ||
| 19 | this.Transform = transform; | ||
| 20 | } | ||
| 21 | |||
| 22 | public string Baseline { get; } | ||
| 23 | |||
| 24 | public WindowsInstallerData Transform { get; } | ||
| 25 | |||
| 26 | /// <summary> | ||
| 27 | /// Validates that the differences in the transform are valid for patch transforms. | ||
| 28 | /// </summary> | ||
| 29 | public void Validate() | ||
| 30 | { | ||
| 31 | #if TODO_PATCHING | ||
| 32 | // Changing the ProdocutCode in a patch transform is not recommended. | ||
| 33 | Table propertyTable = this.Transform.Tables["Property"]; | ||
| 34 | if (null != propertyTable) | ||
| 35 | { | ||
| 36 | foreach (Row row in propertyTable.Rows) | ||
| 37 | { | ||
| 38 | // Only interested in modified rows; fast check. | ||
| 39 | if (RowOperation.Modify == row.Operation) | ||
| 40 | { | ||
| 41 | if (0 == String.CompareOrdinal("ProductCode", (string)row[0])) | ||
| 42 | { | ||
| 43 | this.OnMessage(WixWarnings.MajorUpgradePatchNotRecommended()); | ||
| 44 | } | ||
| 45 | } | ||
| 46 | } | ||
| 47 | } | ||
| 48 | |||
| 49 | // If there is nothing in the component table we can return early because the remaining checks are component based. | ||
| 50 | Table componentTable = this.Transform.Tables["Component"]; | ||
| 51 | if (null == componentTable) | ||
| 52 | { | ||
| 53 | return; | ||
| 54 | } | ||
| 55 | |||
| 56 | // Index Feature table row operations | ||
| 57 | Table featureTable = this.Transform.Tables["Feature"]; | ||
| 58 | Table featureComponentsTable = this.Transform.Tables["FeatureComponents"]; | ||
| 59 | Hashtable featureOps = null; | ||
| 60 | if (null != featureTable) | ||
| 61 | { | ||
| 62 | int capacity = featureTable.Rows.Count; | ||
| 63 | featureOps = new Hashtable(capacity); | ||
| 64 | |||
| 65 | foreach (Row row in featureTable.Rows) | ||
| 66 | { | ||
| 67 | featureOps[(string)row[0]] = row.Operation; | ||
| 68 | } | ||
| 69 | } | ||
| 70 | else | ||
| 71 | { | ||
| 72 | featureOps = new Hashtable(); | ||
| 73 | } | ||
| 74 | |||
| 75 | // Index Component table and check for keypath modifications | ||
| 76 | Hashtable deletedComponent = new Hashtable(); | ||
| 77 | Hashtable componentKeyPath = new Hashtable(); | ||
| 78 | foreach (Row row in componentTable.Rows) | ||
| 79 | { | ||
| 80 | string id = row.Fields[0].Data.ToString(); | ||
| 81 | string keypath = (null == row.Fields[5].Data) ? String.Empty : row.Fields[5].Data.ToString(); | ||
| 82 | |||
| 83 | componentKeyPath.Add(id, keypath); | ||
| 84 | if (RowOperation.Delete == row.Operation) | ||
| 85 | { | ||
| 86 | deletedComponent.Add(id, row); | ||
| 87 | } | ||
| 88 | else if (RowOperation.Modify == row.Operation) | ||
| 89 | { | ||
| 90 | if (row.Fields[1].Modified) | ||
| 91 | { | ||
| 92 | // Changing the guid of a component is equal to deleting the old one and adding a new one. | ||
| 93 | deletedComponent.Add(id, row); | ||
| 94 | } | ||
| 95 | |||
| 96 | // If the keypath is modified its an error | ||
| 97 | if (row.Fields[5].Modified) | ||
| 98 | { | ||
| 99 | this.OnMessage(WixErrors.InvalidKeypathChange(row.SourceLineNumbers, id, this.transformPath)); | ||
| 100 | } | ||
| 101 | } | ||
| 102 | } | ||
| 103 | |||
| 104 | // Verify changes in the file table | ||
| 105 | Table fileTable = this.Transform.Tables["File"]; | ||
| 106 | if (null != fileTable) | ||
| 107 | { | ||
| 108 | Hashtable componentWithChangedKeyPath = new Hashtable(); | ||
| 109 | foreach (Row row in fileTable.Rows) | ||
| 110 | { | ||
| 111 | if (RowOperation.None != row.Operation) | ||
| 112 | { | ||
| 113 | string fileId = row.Fields[0].Data.ToString(); | ||
| 114 | string componentId = row.Fields[1].Data.ToString(); | ||
| 115 | |||
| 116 | // If this file is the keypath of a component | ||
| 117 | if (String.Equals((string)componentKeyPath[componentId], fileId, StringComparison.Ordinal)) | ||
| 118 | { | ||
| 119 | if (row.Fields[2].Modified) | ||
| 120 | { | ||
| 121 | // You cant change the filename of a file that is the keypath of a component. | ||
| 122 | this.OnMessage(WixErrors.InvalidKeypathChange(row.SourceLineNumbers, componentId, this.transformPath)); | ||
| 123 | } | ||
| 124 | |||
| 125 | if (!componentWithChangedKeyPath.ContainsKey(componentId)) | ||
| 126 | { | ||
| 127 | componentWithChangedKeyPath.Add(componentId, fileId); | ||
| 128 | } | ||
| 129 | } | ||
| 130 | |||
| 131 | if (RowOperation.Delete == row.Operation) | ||
| 132 | { | ||
| 133 | // If the file is removed from a component that is not deleted. | ||
| 134 | if (!deletedComponent.ContainsKey(componentId)) | ||
| 135 | { | ||
| 136 | bool foundRemoveFileEntry = false; | ||
| 137 | string filename = Common.GetName((string)row[2], false, true); | ||
| 138 | |||
| 139 | Table removeFileTable = this.Transform.Tables["RemoveFile"]; | ||
| 140 | if (null != removeFileTable) | ||
| 141 | { | ||
| 142 | foreach (Row removeFileRow in removeFileTable.Rows) | ||
| 143 | { | ||
| 144 | if (RowOperation.Delete == removeFileRow.Operation) | ||
| 145 | { | ||
| 146 | continue; | ||
| 147 | } | ||
| 148 | |||
| 149 | if (componentId == (string)removeFileRow[1]) | ||
| 150 | { | ||
| 151 | // Check if there is a RemoveFile entry for this file | ||
| 152 | if (null != removeFileRow[2]) | ||
| 153 | { | ||
| 154 | string removeFileName = Common.GetName((string)removeFileRow[2], false, true); | ||
| 155 | |||
| 156 | // Convert the MSI format for a wildcard string to Regex format. | ||
| 157 | removeFileName = removeFileName.Replace('.', '|').Replace('?', '.').Replace("*", ".*").Replace("|", "\\."); | ||
| 158 | |||
| 159 | Regex regex = new Regex(removeFileName, RegexOptions.CultureInvariant | RegexOptions.IgnoreCase); | ||
| 160 | if (regex.IsMatch(filename)) | ||
| 161 | { | ||
| 162 | foundRemoveFileEntry = true; | ||
| 163 | break; | ||
| 164 | } | ||
| 165 | } | ||
| 166 | } | ||
| 167 | } | ||
| 168 | } | ||
| 169 | |||
| 170 | if (!foundRemoveFileEntry) | ||
| 171 | { | ||
| 172 | this.OnMessage(WixWarnings.InvalidRemoveFile(row.SourceLineNumbers, fileId, componentId)); | ||
| 173 | } | ||
| 174 | } | ||
| 175 | } | ||
| 176 | } | ||
| 177 | } | ||
| 178 | } | ||
| 179 | |||
| 180 | if (0 < deletedComponent.Count) | ||
| 181 | { | ||
| 182 | // Index FeatureComponents table. | ||
| 183 | Hashtable featureComponents = new Hashtable(); | ||
| 184 | |||
| 185 | if (null != featureComponentsTable) | ||
| 186 | { | ||
| 187 | foreach (Row row in featureComponentsTable.Rows) | ||
| 188 | { | ||
| 189 | ArrayList features; | ||
| 190 | string componentId = row.Fields[1].Data.ToString(); | ||
| 191 | |||
| 192 | if (featureComponents.Contains(componentId)) | ||
| 193 | { | ||
| 194 | features = (ArrayList)featureComponents[componentId]; | ||
| 195 | } | ||
| 196 | else | ||
| 197 | { | ||
| 198 | features = new ArrayList(); | ||
| 199 | featureComponents.Add(componentId, features); | ||
| 200 | } | ||
| 201 | features.Add(row.Fields[0].Data.ToString()); | ||
| 202 | } | ||
| 203 | } | ||
| 204 | |||
| 205 | // Check to make sure if a component was deleted, the feature was too. | ||
| 206 | foreach (DictionaryEntry entry in deletedComponent) | ||
| 207 | { | ||
| 208 | if (featureComponents.Contains(entry.Key.ToString())) | ||
| 209 | { | ||
| 210 | ArrayList features = (ArrayList)featureComponents[entry.Key.ToString()]; | ||
| 211 | foreach (string featureId in features) | ||
| 212 | { | ||
| 213 | if (!featureOps.ContainsKey(featureId) || RowOperation.Delete != (RowOperation)featureOps[featureId]) | ||
| 214 | { | ||
| 215 | // The feature was not deleted. | ||
| 216 | this.OnMessage(WixErrors.InvalidRemoveComponent(((Row)entry.Value).SourceLineNumbers, entry.Key.ToString(), featureId, this.transformPath)); | ||
| 217 | } | ||
| 218 | } | ||
| 219 | } | ||
| 220 | } | ||
| 221 | } | ||
| 222 | |||
| 223 | // Warn if new components are added to existing features | ||
| 224 | if (null != featureComponentsTable) | ||
| 225 | { | ||
| 226 | foreach (Row row in featureComponentsTable.Rows) | ||
| 227 | { | ||
| 228 | if (RowOperation.Add == row.Operation) | ||
| 229 | { | ||
| 230 | // Check if the feature is in the Feature table | ||
| 231 | string feature_ = (string)row[0]; | ||
| 232 | string component_ = (string)row[1]; | ||
| 233 | |||
| 234 | // Features may not be present if not referenced | ||
| 235 | if (!featureOps.ContainsKey(feature_) || RowOperation.Add != (RowOperation)featureOps[feature_]) | ||
| 236 | { | ||
| 237 | this.OnMessage(WixWarnings.NewComponentAddedToExistingFeature(row.SourceLineNumbers, component_, feature_, this.transformPath)); | ||
| 238 | } | ||
| 239 | } | ||
| 240 | } | ||
| 241 | } | ||
| 242 | #endif | ||
| 243 | throw new NotImplementedException(); | ||
| 244 | } | ||
| 245 | } | ||
| 246 | } | ||
