diff options
| author | Rob Mensching <rob@firegiant.com> | 2020-07-10 23:41:25 -0700 |
|---|---|---|
| committer | Rob Mensching <rob@firegiant.com> | 2020-07-14 10:53:45 -0700 |
| commit | f4b7d3f7c0a49e70fe5d25a309387786589488a6 (patch) | |
| tree | 74162de1ece12ecd88c7c429f8f0ed155ca6b653 /src/WixToolset.Core/Compiler.cs | |
| parent | 28f41d1afec40d79459402fbed21f6c237768adb (diff) | |
| download | wix-f4b7d3f7c0a49e70fe5d25a309387786589488a6.tar.gz wix-f4b7d3f7c0a49e70fe5d25a309387786589488a6.tar.bz2 wix-f4b7d3f7c0a49e70fe5d25a309387786589488a6.zip | |
Major performance improvements to inline directory syntax parsing
Diffstat (limited to 'src/WixToolset.Core/Compiler.cs')
| -rw-r--r-- | src/WixToolset.Core/Compiler.cs | 168 |
1 files changed, 86 insertions, 82 deletions
diff --git a/src/WixToolset.Core/Compiler.cs b/src/WixToolset.Core/Compiler.cs index 3fa06f9c..c504e96f 100644 --- a/src/WixToolset.Core/Compiler.cs +++ b/src/WixToolset.Core/Compiler.cs | |||
| @@ -9,6 +9,7 @@ namespace WixToolset.Core | |||
| 9 | using System.Globalization; | 9 | using System.Globalization; |
| 10 | using System.IO; | 10 | using System.IO; |
| 11 | using System.Linq; | 11 | using System.Linq; |
| 12 | using System.Text; | ||
| 12 | using System.Xml.Linq; | 13 | using System.Xml.Linq; |
| 13 | using WixToolset.Data; | 14 | using WixToolset.Data; |
| 14 | using WixToolset.Data.Symbols; | 15 | using WixToolset.Data.Symbols; |
| @@ -25,8 +26,10 @@ namespace WixToolset.Core | |||
| 25 | private const int MinValueOfMaxCabSizeForLargeFileSplitting = 20; // 20 MB | 26 | private const int MinValueOfMaxCabSizeForLargeFileSplitting = 20; // 20 MB |
| 26 | private const int MaxValueOfMaxCabSizeForLargeFileSplitting = 2 * 1024; // 2048 MB (i.e. 2 GB) | 27 | private const int MaxValueOfMaxCabSizeForLargeFileSplitting = 2 * 1024; // 2048 MB (i.e. 2 GB) |
| 27 | 28 | ||
| 28 | private const string DefaultComponentIdPlaceholderPrefix = "WixComponentIdPlaceholder"; | 29 | private const char ComponentIdPlaceholderStart = (char)167; |
| 29 | private const string DefaultComponentIdPlaceholderWixVariablePrefix = "!(wix."; | 30 | private const char ComponentIdPlaceholderEnd = (char)167; |
| 31 | private Dictionary<string, string> componentIdPlaceholders; | ||
| 32 | |||
| 30 | // If these are true you know you are building a module or product | 33 | // If these are true you know you are building a module or product |
| 31 | // but if they are false you cannot not be sure they will not end | 34 | // but if they are false you cannot not be sure they will not end |
| 32 | // up a product or module. Use these flags carefully. | 35 | // up a product or module. Use these flags carefully. |
| @@ -36,9 +39,6 @@ namespace WixToolset.Core | |||
| 36 | private string activeName; | 39 | private string activeName; |
| 37 | private string activeLanguage; | 40 | private string activeLanguage; |
| 38 | 41 | ||
| 39 | // TODO: Implement this differently to not require the VariableResolver. | ||
| 40 | private VariableResolver componentIdPlaceholdersResolver; | ||
| 41 | |||
| 42 | /// <summary> | 42 | /// <summary> |
| 43 | /// Type of RadioButton element in a group. | 43 | /// Type of RadioButton element in a group. |
| 44 | /// </summary> | 44 | /// </summary> |
| @@ -129,7 +129,7 @@ namespace WixToolset.Core | |||
| 129 | 129 | ||
| 130 | this.Core = new CompilerCore(target, this.Messaging, parseHelper, extensionsByNamespace); | 130 | this.Core = new CompilerCore(target, this.Messaging, parseHelper, extensionsByNamespace); |
| 131 | this.Core.ShowPedanticMessages = this.ShowPedanticMessages; | 131 | this.Core.ShowPedanticMessages = this.ShowPedanticMessages; |
| 132 | this.componentIdPlaceholdersResolver = new VariableResolver(this.ServiceProvider); | 132 | this.componentIdPlaceholders = new Dictionary<string, string>(); |
| 133 | 133 | ||
| 134 | // parse the document | 134 | // parse the document |
| 135 | var source = this.Context.Source; | 135 | var source = this.Context.Source; |
| @@ -247,7 +247,7 @@ namespace WixToolset.Core | |||
| 247 | 247 | ||
| 248 | private void ResolveComponentIdPlaceholders(Intermediate target) | 248 | private void ResolveComponentIdPlaceholders(Intermediate target) |
| 249 | { | 249 | { |
| 250 | if (0 < this.componentIdPlaceholdersResolver.VariableCount) | 250 | if (0 < this.componentIdPlaceholders.Count) |
| 251 | { | 251 | { |
| 252 | foreach (var section in target.Sections) | 252 | foreach (var section in target.Sections) |
| 253 | { | 253 | { |
| @@ -255,15 +255,40 @@ namespace WixToolset.Core | |||
| 255 | { | 255 | { |
| 256 | foreach (var field in symbol.Fields) | 256 | foreach (var field in symbol.Fields) |
| 257 | { | 257 | { |
| 258 | if (field?.Type == IntermediateFieldType.String) | 258 | if (field != null && field.Type == IntermediateFieldType.String) |
| 259 | { | 259 | { |
| 260 | var data = field.AsString(); | 260 | var data = field.AsString(); |
| 261 | if (!String.IsNullOrEmpty(data)) | 261 | if (!String.IsNullOrEmpty(data)) |
| 262 | { | 262 | { |
| 263 | var resolved = this.componentIdPlaceholdersResolver.ResolveVariables(symbol.SourceLineNumbers, data, errorOnUnknown: false); | 263 | var changed = false; |
| 264 | if (resolved.UpdatedValue) | 264 | var start = data.IndexOf(ComponentIdPlaceholderStart); |
| 265 | while (start != -1) | ||
| 266 | { | ||
| 267 | var end = data.IndexOf(ComponentIdPlaceholderEnd, start + 1); | ||
| 268 | if (end == -1) | ||
| 269 | { | ||
| 270 | break; | ||
| 271 | } | ||
| 272 | |||
| 273 | var placeholderId = data.Substring(start, end - start + 1); | ||
| 274 | if (this.componentIdPlaceholders.TryGetValue(placeholderId, out var value)) | ||
| 275 | { | ||
| 276 | var sb = new StringBuilder(data); | ||
| 277 | sb.Remove(start, end - start + 1); | ||
| 278 | sb.Insert(start, value); | ||
| 279 | |||
| 280 | data = sb.ToString(); | ||
| 281 | changed = true; | ||
| 282 | |||
| 283 | end = start + value.Length; | ||
| 284 | } | ||
| 285 | |||
| 286 | start = data.IndexOf(ComponentIdPlaceholderStart, end); | ||
| 287 | } | ||
| 288 | |||
| 289 | if (changed) | ||
| 265 | { | 290 | { |
| 266 | field.Set(resolved.Value); | 291 | field.Overwrite(data); |
| 267 | } | 292 | } |
| 268 | } | 293 | } |
| 269 | } | 294 | } |
| @@ -2096,9 +2121,8 @@ namespace WixToolset.Core | |||
| 2096 | var encounteredODBCDataSource = false; | 2121 | var encounteredODBCDataSource = false; |
| 2097 | var files = 0; | 2122 | var files = 0; |
| 2098 | var guid = "*"; | 2123 | var guid = "*"; |
| 2099 | var componentIdPlaceholder = Compiler.DefaultComponentIdPlaceholderPrefix + this.componentIdPlaceholdersResolver.VariableCount; // placeholder id for defaulting Component/@Id to keypath id. | 2124 | Identifier id = null; |
| 2100 | var componentIdPlaceholderWixVariable = Compiler.DefaultComponentIdPlaceholderWixVariablePrefix + componentIdPlaceholder + ")"; | 2125 | string componentIdPlaceholder = null; |
| 2101 | var id = new Identifier(AccessModifier.Private, componentIdPlaceholderWixVariable); | ||
| 2102 | var keyFound = false; | 2126 | var keyFound = false; |
| 2103 | string keyPath = null; | 2127 | string keyPath = null; |
| 2104 | 2128 | ||
| @@ -2253,6 +2277,13 @@ namespace WixToolset.Core | |||
| 2253 | win64 = true; | 2277 | win64 = true; |
| 2254 | } | 2278 | } |
| 2255 | 2279 | ||
| 2280 | if (id == null) | ||
| 2281 | { | ||
| 2282 | // Placeholder id for defaulting Component/@Id to keypath id. | ||
| 2283 | componentIdPlaceholder = String.Concat(Compiler.ComponentIdPlaceholderStart, this.componentIdPlaceholders.Count, Compiler.ComponentIdPlaceholderEnd); | ||
| 2284 | id = new Identifier(AccessModifier.Private, componentIdPlaceholder); | ||
| 2285 | } | ||
| 2286 | |||
| 2256 | if (null == directoryId) | 2287 | if (null == directoryId) |
| 2257 | { | 2288 | { |
| 2258 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Directory")); | 2289 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Directory")); |
| @@ -2466,14 +2497,14 @@ namespace WixToolset.Core | |||
| 2466 | this.Core.Write(ErrorMessages.ImplicitComponentKeyPath(sourceLineNumbers, id.Id)); | 2497 | this.Core.Write(ErrorMessages.ImplicitComponentKeyPath(sourceLineNumbers, id.Id)); |
| 2467 | } | 2498 | } |
| 2468 | 2499 | ||
| 2469 | // if there isn't an @Id attribute value, replace the placeholder with the id of the keypath. | 2500 | // If there isn't an @Id attribute value, replace the placeholder with the id of the keypath. |
| 2470 | // either an explicit KeyPath="yes" attribute must be specified or requirements for | 2501 | // either an explicit KeyPath="yes" attribute must be specified or requirements for |
| 2471 | // generatable guid must be met. | 2502 | // generatable guid must be met. |
| 2472 | if (componentIdPlaceholderWixVariable == id.Id) | 2503 | if (componentIdPlaceholder == id.Id) |
| 2473 | { | 2504 | { |
| 2474 | if (isGeneratableGuidOk || keyFound && !String.IsNullOrEmpty(keyPath)) | 2505 | if (isGeneratableGuidOk || keyFound && !String.IsNullOrEmpty(keyPath)) |
| 2475 | { | 2506 | { |
| 2476 | this.componentIdPlaceholdersResolver.AddVariable(sourceLineNumbers, componentIdPlaceholder, keyPath, false); | 2507 | this.componentIdPlaceholders.Add(componentIdPlaceholder, keyPath); |
| 2477 | 2508 | ||
| 2478 | id = new Identifier(AccessModifier.Private, keyPath); | 2509 | id = new Identifier(AccessModifier.Private, keyPath); |
| 2479 | } | 2510 | } |
| @@ -2483,12 +2514,6 @@ namespace WixToolset.Core | |||
| 2483 | } | 2514 | } |
| 2484 | } | 2515 | } |
| 2485 | 2516 | ||
| 2486 | // If an id was not determined by now, we have to error. | ||
| 2487 | if (null == id) | ||
| 2488 | { | ||
| 2489 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
| 2490 | } | ||
| 2491 | |||
| 2492 | // finally add the Component table row | 2517 | // finally add the Component table row |
| 2493 | if (!this.Core.EncounteredError) | 2518 | if (!this.Core.EncounteredError) |
| 2494 | { | 2519 | { |
| @@ -4120,9 +4145,9 @@ namespace WixToolset.Core | |||
| 4120 | Identifier id = null; | 4145 | Identifier id = null; |
| 4121 | string componentGuidGenerationSeed = null; | 4146 | string componentGuidGenerationSeed = null; |
| 4122 | var fileSourceAttribSet = false; | 4147 | var fileSourceAttribSet = false; |
| 4123 | var nameHasValue = false; | 4148 | XAttribute nameAttribute = null; |
| 4124 | var name = "."; // default to parent directory. | 4149 | var name = "."; // default to parent directory. |
| 4125 | string[] inlineSyntax = null; | 4150 | string inlineSyntax = null; |
| 4126 | string shortName = null; | 4151 | string shortName = null; |
| 4127 | string sourceName = null; | 4152 | string sourceName = null; |
| 4128 | string shortSourceName = null; | 4153 | string shortSourceName = null; |
| @@ -4148,15 +4173,8 @@ namespace WixToolset.Core | |||
| 4148 | fileSourceAttribSet = true; | 4173 | fileSourceAttribSet = true; |
| 4149 | break; | 4174 | break; |
| 4150 | case "Name": | 4175 | case "Name": |
| 4151 | nameHasValue = true; | 4176 | name = this.Core.GetAttributeValue(sourceLineNumbers, attrib); |
| 4152 | if (attrib.Value == ".") | 4177 | nameAttribute = attrib; |
| 4153 | { | ||
| 4154 | name = attrib.Value; | ||
| 4155 | } | ||
| 4156 | else | ||
| 4157 | { | ||
| 4158 | inlineSyntax = this.Core.GetAttributeInlineDirectorySyntax(sourceLineNumbers, attrib); | ||
| 4159 | } | ||
| 4160 | break; | 4178 | break; |
| 4161 | case "ShortName": | 4179 | case "ShortName": |
| 4162 | shortName = this.Core.GetAttributeShortFilename(sourceLineNumbers, attrib, false); | 4180 | shortName = this.Core.GetAttributeShortFilename(sourceLineNumbers, attrib, false); |
| @@ -4185,37 +4203,7 @@ namespace WixToolset.Core | |||
| 4185 | } | 4203 | } |
| 4186 | } | 4204 | } |
| 4187 | 4205 | ||
| 4188 | // Create the directory rows for the inline. | 4206 | if (nameAttribute == null) |
| 4189 | if (null != inlineSyntax) | ||
| 4190 | { | ||
| 4191 | // Special case the single entry in the inline syntax since it is the most common case | ||
| 4192 | // and needs no extra processing. It's just the name of the directory. | ||
| 4193 | if (1 == inlineSyntax.Length) | ||
| 4194 | { | ||
| 4195 | name = inlineSyntax[0]; | ||
| 4196 | } | ||
| 4197 | else | ||
| 4198 | { | ||
| 4199 | var pathStartsAt = 0; | ||
| 4200 | if (inlineSyntax[0].EndsWith(":")) | ||
| 4201 | { | ||
| 4202 | parentId = inlineSyntax[0].TrimEnd(':'); | ||
| 4203 | this.Core.CreateSimpleReference(sourceLineNumbers, SymbolDefinitions.Directory, parentId); | ||
| 4204 | |||
| 4205 | pathStartsAt = 1; | ||
| 4206 | } | ||
| 4207 | |||
| 4208 | for (var i = pathStartsAt; i < inlineSyntax.Length - 1; ++i) | ||
| 4209 | { | ||
| 4210 | var inlineId = this.Core.CreateDirectoryRow(sourceLineNumbers, null, parentId, inlineSyntax[i]); | ||
| 4211 | parentId = inlineId.Id; | ||
| 4212 | } | ||
| 4213 | |||
| 4214 | name = inlineSyntax[inlineSyntax.Length - 1]; | ||
| 4215 | } | ||
| 4216 | } | ||
| 4217 | |||
| 4218 | if (!nameHasValue) | ||
| 4219 | { | 4207 | { |
| 4220 | if (!String.IsNullOrEmpty(shortName)) | 4208 | if (!String.IsNullOrEmpty(shortName)) |
| 4221 | { | 4209 | { |
| @@ -4264,39 +4252,55 @@ namespace WixToolset.Core | |||
| 4264 | } | 4252 | } |
| 4265 | } | 4253 | } |
| 4266 | 4254 | ||
| 4267 | // Update the file source path appropriately. | 4255 | // Create the directory rows for the inline. |
| 4268 | if (fileSourceAttribSet) | 4256 | if (nameAttribute != null) |
| 4269 | { | 4257 | { |
| 4270 | if (!fileSource.EndsWith(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal)) | 4258 | var lastSlash = name.LastIndexOf('\\'); |
| 4259 | if (lastSlash > 0) | ||
| 4271 | { | 4260 | { |
| 4272 | fileSource = String.Concat(fileSource, Path.DirectorySeparatorChar); | 4261 | inlineSyntax = name; |
| 4262 | name = inlineSyntax.Substring(lastSlash + 1); | ||
| 4263 | |||
| 4264 | parentId = this.Core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, nameAttribute, parentId, inlineSyntax.Substring(0, lastSlash)); | ||
| 4265 | |||
| 4266 | if (!this.Core.IsValidLongFilename(name, false, false)) | ||
| 4267 | { | ||
| 4268 | this.Messaging.Write(ErrorMessages.IllegalLongFilename(sourceLineNumbers, node.Name.LocalName, nameAttribute.Name.LocalName, nameAttribute.Value, name)); | ||
| 4269 | } | ||
| 4273 | } | 4270 | } |
| 4274 | } | 4271 | } |
| 4275 | else // add the appropriate part of this directory element to the file source. | 4272 | |
| 4273 | if (null == id) | ||
| 4276 | { | 4274 | { |
| 4277 | string append = String.IsNullOrEmpty(sourceName) ? name : sourceName; | 4275 | id = this.Core.CreateIdentifier("dir", parentId, name, shortName, sourceName, shortSourceName); |
| 4278 | 4276 | ||
| 4279 | if (!String.IsNullOrEmpty(append)) | 4277 | if (!String.IsNullOrEmpty(inlineSyntax)) |
| 4280 | { | 4278 | { |
| 4281 | fileSource = String.Concat(fileSource, append, Path.DirectorySeparatorChar); | 4279 | this.Core.AddInlineDirectoryId(inlineSyntax, id.Id); |
| 4282 | } | 4280 | } |
| 4283 | } | 4281 | } |
| 4284 | 4282 | ||
| 4285 | if (null == id) | 4283 | if ("TARGETDIR".Equals(id.Id, StringComparison.Ordinal) && !("SourceDir".Equals(name, StringComparison.Ordinal) && shortName == null && shortSourceName == null && sourceName == null)) |
| 4286 | { | 4284 | { |
| 4287 | id = this.Core.CreateIdentifier("dir", parentId, name, shortName, sourceName, shortSourceName); | 4285 | this.Core.Write(ErrorMessages.IllegalTargetDirDefaultDir(sourceLineNumbers, name)); |
| 4288 | } | 4286 | } |
| 4289 | 4287 | ||
| 4290 | // Calculate the DefaultDir for the directory row. | 4288 | // Update the file source path appropriately. |
| 4291 | var defaultDir = String.IsNullOrEmpty(shortName) ? name : String.Concat(shortName, "|", name); | 4289 | if (fileSourceAttribSet) |
| 4292 | if (!String.IsNullOrEmpty(sourceName)) | ||
| 4293 | { | 4290 | { |
| 4294 | defaultDir = String.Concat(defaultDir, ":", String.IsNullOrEmpty(shortSourceName) ? sourceName : String.Concat(shortSourceName, "|", sourceName)); | 4291 | if (!fileSource.EndsWith(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal)) |
| 4292 | { | ||
| 4293 | fileSource = String.Concat(fileSource, Path.DirectorySeparatorChar); | ||
| 4294 | } | ||
| 4295 | } | 4295 | } |
| 4296 | 4296 | else // add the appropriate part of this directory element to the file source. | |
| 4297 | if ("TARGETDIR".Equals(id.Id, StringComparison.Ordinal) && !"SourceDir".Equals(defaultDir, StringComparison.Ordinal)) | ||
| 4298 | { | 4297 | { |
| 4299 | this.Core.Write(ErrorMessages.IllegalTargetDirDefaultDir(sourceLineNumbers, defaultDir)); | 4298 | string append = String.IsNullOrEmpty(sourceName) ? name : sourceName; |
| 4299 | |||
| 4300 | if (!String.IsNullOrEmpty(append)) | ||
| 4301 | { | ||
| 4302 | fileSource = String.Concat(fileSource, append, Path.DirectorySeparatorChar); | ||
| 4303 | } | ||
| 4300 | } | 4304 | } |
| 4301 | 4305 | ||
| 4302 | foreach (var child in node.Elements()) | 4306 | foreach (var child in node.Elements()) |
