diff options
7 files changed, 108 insertions, 52 deletions
diff --git a/src/wix/WixToolset.Core/Link/FindEntrySectionAndLoadSymbolsCommand.cs b/src/wix/WixToolset.Core/Link/FindEntrySectionAndLoadSymbolsCommand.cs index 908476db..496c6178 100644 --- a/src/wix/WixToolset.Core/Link/FindEntrySectionAndLoadSymbolsCommand.cs +++ b/src/wix/WixToolset.Core/Link/FindEntrySectionAndLoadSymbolsCommand.cs | |||
@@ -42,13 +42,13 @@ namespace WixToolset.Core.Link | |||
42 | /// Gets the collection of redundant symbols that should not be included | 42 | /// Gets the collection of redundant symbols that should not be included |
43 | /// in the final output. | 43 | /// in the final output. |
44 | /// </summary> | 44 | /// </summary> |
45 | public ISet<IntermediateSymbol> RedundantSymbols { get; private set; } | 45 | public ISet<IntermediateSymbol> IdenticalDirectorySymbols { get; private set; } |
46 | 46 | ||
47 | public void Execute() | 47 | public void Execute() |
48 | { | 48 | { |
49 | var symbolsByName = new Dictionary<string, SymbolWithSection>(); | 49 | var symbolsByName = new Dictionary<string, SymbolWithSection>(); |
50 | var possibleConflicts = new HashSet<SymbolWithSection>(); | 50 | var possibleConflicts = new HashSet<SymbolWithSection>(); |
51 | var redundantSymbols = new HashSet<IntermediateSymbol>(); | 51 | var identicalDirectorySymbols = new HashSet<IntermediateSymbol>(); |
52 | 52 | ||
53 | if (!Enum.TryParse(this.ExpectedOutputType.ToString(), out SectionType expectedEntrySectionType)) | 53 | if (!Enum.TryParse(this.ExpectedOutputType.ToString(), out SectionType expectedEntrySectionType)) |
54 | { | 54 | { |
@@ -76,28 +76,27 @@ namespace WixToolset.Core.Link | |||
76 | } | 76 | } |
77 | } | 77 | } |
78 | 78 | ||
79 | // Load all the symbols from the section's tables that create symbols. | 79 | // Load all the symbols from the section's tables that can be referenced (i.e. have an Id). |
80 | foreach (var symbol in section.Symbols.Where(t => t.Id != null)) | 80 | foreach (var symbol in section.Symbols.Where(t => t.Id != null)) |
81 | { | 81 | { |
82 | var symbolWithSection = new SymbolWithSection(section, symbol); | 82 | var symbolWithSection = new SymbolWithSection(section, symbol); |
83 | var fullName = symbolWithSection.GetFullName(); | ||
83 | 84 | ||
84 | if (!symbolsByName.TryGetValue(symbolWithSection.Name, out var existingSymbol)) | 85 | if (!symbolsByName.TryGetValue(fullName, out var existingSymbol)) |
85 | { | 86 | { |
86 | symbolsByName.Add(symbolWithSection.Name, symbolWithSection); | 87 | symbolsByName.Add(fullName, symbolWithSection); |
87 | } | 88 | } |
88 | else // uh-oh, duplicate symbols. | 89 | else // uh-oh, duplicate symbols. |
89 | { | 90 | { |
90 | // If the duplicate symbols are both private directories, there is a chance that they | 91 | // If the duplicate symbols are both private directories, there is a chance that they |
91 | // point to identical symbols. Identical directory symbols are redundant and will not cause | 92 | // point to identical symbols. Identical directory symbols should be treated as redundant. |
92 | // conflicts. | 93 | // and not cause conflicts. |
93 | if (AccessModifier.Section == existingSymbol.Access && AccessModifier.Section == symbolWithSection.Access && | 94 | if (AccessModifier.Section == existingSymbol.Access && AccessModifier.Section == symbolWithSection.Access && |
94 | SymbolDefinitionType.Directory == existingSymbol.Symbol.Definition.Type && existingSymbol.Symbol.IsIdentical(symbolWithSection.Symbol)) | 95 | SymbolDefinitionType.Directory == existingSymbol.Symbol.Definition.Type && existingSymbol.Symbol.IsIdentical(symbolWithSection.Symbol)) |
95 | { | 96 | { |
96 | // Ensure identical symbol's symbol is marked redundant to ensure (should the symbol be | 97 | // Ensure identical symbols are tracked to ensure that only one symbol will end up in linked intermediate. |
97 | // referenced into the final output) it will not add duplicate primary keys during | 98 | identicalDirectorySymbols.Add(existingSymbol.Symbol); |
98 | // the .IDT importing. | 99 | identicalDirectorySymbols.Add(symbolWithSection.Symbol); |
99 | existingSymbol.AddRedundant(symbolWithSection); | ||
100 | redundantSymbols.Add(symbolWithSection.Symbol); | ||
101 | } | 100 | } |
102 | else | 101 | else |
103 | { | 102 | { |
@@ -111,7 +110,7 @@ namespace WixToolset.Core.Link | |||
111 | 110 | ||
112 | this.SymbolsByName = symbolsByName; | 111 | this.SymbolsByName = symbolsByName; |
113 | this.PossibleConflicts = possibleConflicts; | 112 | this.PossibleConflicts = possibleConflicts; |
114 | this.RedundantSymbols = redundantSymbols; | 113 | this.IdenticalDirectorySymbols = identicalDirectorySymbols; |
115 | } | 114 | } |
116 | } | 115 | } |
117 | } | 116 | } |
diff --git a/src/wix/WixToolset.Core/Link/ReportConflictingSymbolsCommand.cs b/src/wix/WixToolset.Core/Link/ReportConflictingSymbolsCommand.cs index ace2e19d..3a07d366 100644 --- a/src/wix/WixToolset.Core/Link/ReportConflictingSymbolsCommand.cs +++ b/src/wix/WixToolset.Core/Link/ReportConflictingSymbolsCommand.cs | |||
@@ -40,7 +40,9 @@ namespace WixToolset.Core.Link | |||
40 | 40 | ||
41 | if (actuallyReferencedDuplicates.Any()) | 41 | if (actuallyReferencedDuplicates.Any()) |
42 | { | 42 | { |
43 | this.Messaging.Write(ErrorMessages.DuplicateSymbol(referencedDuplicate.Symbol.SourceLineNumbers, referencedDuplicate.Name)); | 43 | var fullName = referencedDuplicate.GetFullName(); |
44 | |||
45 | this.Messaging.Write(ErrorMessages.DuplicateSymbol(referencedDuplicate.Symbol.SourceLineNumbers, fullName)); | ||
44 | 46 | ||
45 | foreach (var duplicate in actuallyReferencedDuplicates) | 47 | foreach (var duplicate in actuallyReferencedDuplicates) |
46 | { | 48 | { |
diff --git a/src/wix/WixToolset.Core/Link/ResolveReferencesCommand.cs b/src/wix/WixToolset.Core/Link/ResolveReferencesCommand.cs index efb90bb8..d95d648f 100644 --- a/src/wix/WixToolset.Core/Link/ResolveReferencesCommand.cs +++ b/src/wix/WixToolset.Core/Link/ResolveReferencesCommand.cs | |||
@@ -91,15 +91,16 @@ namespace WixToolset.Core.Link | |||
91 | else // display errors for the duplicate symbols. | 91 | else // display errors for the duplicate symbols. |
92 | { | 92 | { |
93 | var accessibleSymbol = accessible[0]; | 93 | var accessibleSymbol = accessible[0]; |
94 | var accessibleFullName = accessibleSymbol.GetFullName(); | ||
94 | var referencingSourceLineNumber = wixSimpleReferenceRow.SourceLineNumbers?.ToString(); | 95 | var referencingSourceLineNumber = wixSimpleReferenceRow.SourceLineNumbers?.ToString(); |
95 | 96 | ||
96 | if (String.IsNullOrEmpty(referencingSourceLineNumber)) | 97 | if (String.IsNullOrEmpty(referencingSourceLineNumber)) |
97 | { | 98 | { |
98 | this.Messaging.Write(ErrorMessages.DuplicateSymbol(accessibleSymbol.Symbol.SourceLineNumbers, accessibleSymbol.Name)); | 99 | this.Messaging.Write(ErrorMessages.DuplicateSymbol(accessibleSymbol.Symbol.SourceLineNumbers, accessibleFullName)); |
99 | } | 100 | } |
100 | else | 101 | else |
101 | { | 102 | { |
102 | this.Messaging.Write(ErrorMessages.DuplicateSymbol(accessibleSymbol.Symbol.SourceLineNumbers, accessibleSymbol.Name, referencingSourceLineNumber)); | 103 | this.Messaging.Write(ErrorMessages.DuplicateSymbol(accessibleSymbol.Symbol.SourceLineNumbers, accessibleFullName, referencingSourceLineNumber)); |
103 | } | 104 | } |
104 | 105 | ||
105 | foreach (var accessibleDuplicate in accessible.Skip(1)) | 106 | foreach (var accessibleDuplicate in accessible.Skip(1)) |
@@ -146,14 +147,6 @@ namespace WixToolset.Core.Link | |||
146 | } | 147 | } |
147 | } | 148 | } |
148 | 149 | ||
149 | foreach (var dupe in symbolWithSection.Redundants) | ||
150 | { | ||
151 | if (this.AccessibleSymbol(referencingSection, dupe)) | ||
152 | { | ||
153 | accessibleSymbols.Add(dupe); | ||
154 | } | ||
155 | } | ||
156 | |||
157 | return accessibleSymbols; | 150 | return accessibleSymbols; |
158 | } | 151 | } |
159 | 152 | ||
diff --git a/src/wix/WixToolset.Core/Link/SymbolWithSection.cs b/src/wix/WixToolset.Core/Link/SymbolWithSection.cs index 08e01077..dbaceb28 100644 --- a/src/wix/WixToolset.Core/Link/SymbolWithSection.cs +++ b/src/wix/WixToolset.Core/Link/SymbolWithSection.cs | |||
@@ -13,7 +13,6 @@ namespace WixToolset.Core.Link | |||
13 | internal class SymbolWithSection | 13 | internal class SymbolWithSection |
14 | { | 14 | { |
15 | private HashSet<SymbolWithSection> possibleConflicts; | 15 | private HashSet<SymbolWithSection> possibleConflicts; |
16 | private HashSet<SymbolWithSection> redundants; | ||
17 | 16 | ||
18 | /// <summary> | 17 | /// <summary> |
19 | /// Creates a symbol for a symbol. | 18 | /// Creates a symbol for a symbol. |
@@ -24,7 +23,6 @@ namespace WixToolset.Core.Link | |||
24 | { | 23 | { |
25 | this.Symbol = symbol; | 24 | this.Symbol = symbol; |
26 | this.Section = section; | 25 | this.Section = section; |
27 | this.Name = String.Concat(this.Symbol.Definition.Name, ":", this.Symbol.Id.Id); | ||
28 | } | 26 | } |
29 | 27 | ||
30 | /// <summary> | 28 | /// <summary> |
@@ -34,12 +32,6 @@ namespace WixToolset.Core.Link | |||
34 | public AccessModifier Access => this.Symbol.Id.Access; | 32 | public AccessModifier Access => this.Symbol.Id.Access; |
35 | 33 | ||
36 | /// <summary> | 34 | /// <summary> |
37 | /// Gets the name of the symbol. | ||
38 | /// </summary> | ||
39 | /// <value>Name of the symbol.</value> | ||
40 | public string Name { get; } | ||
41 | |||
42 | /// <summary> | ||
43 | /// Gets the symbol for this symbol. | 35 | /// Gets the symbol for this symbol. |
44 | /// </summary> | 36 | /// </summary> |
45 | /// <value>Symbol for this symbol.</value> | 37 | /// <value>Symbol for this symbol.</value> |
@@ -57,11 +49,6 @@ namespace WixToolset.Core.Link | |||
57 | public IEnumerable<SymbolWithSection> PossiblyConflicts => this.possibleConflicts ?? Enumerable.Empty<SymbolWithSection>(); | 49 | public IEnumerable<SymbolWithSection> PossiblyConflicts => this.possibleConflicts ?? Enumerable.Empty<SymbolWithSection>(); |
58 | 50 | ||
59 | /// <summary> | 51 | /// <summary> |
60 | /// Gets any duplicates of this symbol with sections that are redundant. | ||
61 | /// </summary> | ||
62 | public IEnumerable<SymbolWithSection> Redundants => this.redundants ?? Enumerable.Empty<SymbolWithSection>(); | ||
63 | |||
64 | /// <summary> | ||
65 | /// Adds a duplicate symbol with sections that is a possible conflict. | 52 | /// Adds a duplicate symbol with sections that is a possible conflict. |
66 | /// </summary> | 53 | /// </summary> |
67 | /// <param name="symbolWithSection">Symbol with section that is a possible conflict of this symbol.</param> | 54 | /// <param name="symbolWithSection">Symbol with section that is a possible conflict of this symbol.</param> |
@@ -76,17 +63,11 @@ namespace WixToolset.Core.Link | |||
76 | } | 63 | } |
77 | 64 | ||
78 | /// <summary> | 65 | /// <summary> |
79 | /// Adds a duplicate symbol that is redundant. | 66 | /// Gets the full name of the symbol. |
80 | /// </summary> | 67 | /// </summary> |
81 | /// <param name="symbolWithSection">Symbol with section that is redundant of this symbol.</param> | 68 | public string GetFullName() |
82 | public void AddRedundant(SymbolWithSection symbolWithSection) | ||
83 | { | 69 | { |
84 | if (null == this.redundants) | 70 | return String.Concat(this.Symbol.Definition.Name, ":", this.Symbol.Id.Id); |
85 | { | ||
86 | this.redundants = new HashSet<SymbolWithSection>(); | ||
87 | } | ||
88 | |||
89 | this.redundants.Add(symbolWithSection); | ||
90 | } | 71 | } |
91 | } | 72 | } |
92 | } | 73 | } |
diff --git a/src/wix/WixToolset.Core/Linker.cs b/src/wix/WixToolset.Core/Linker.cs index a3d99039..5c021ca0 100644 --- a/src/wix/WixToolset.Core/Linker.cs +++ b/src/wix/WixToolset.Core/Linker.cs | |||
@@ -177,14 +177,20 @@ namespace WixToolset.Core | |||
177 | // metadata. | 177 | // metadata. |
178 | var resolvedSection = new IntermediateSection(find.EntrySection.Id, find.EntrySection.Type); | 178 | var resolvedSection = new IntermediateSection(find.EntrySection.Id, find.EntrySection.Type); |
179 | var references = new List<WixSimpleReferenceSymbol>(); | 179 | var references = new List<WixSimpleReferenceSymbol>(); |
180 | var identicalDirectoryIds = new HashSet<string>(StringComparer.Ordinal); | ||
180 | 181 | ||
181 | foreach (var section in sections) | 182 | foreach (var section in sections) |
182 | { | 183 | { |
183 | foreach (var symbol in section.Symbols) | 184 | foreach (var symbol in section.Symbols) |
184 | { | 185 | { |
185 | if (find.RedundantSymbols.Contains(symbol)) | 186 | // If this symbol is an identical directory, ensure we only visit |
187 | // one (and skip the other identicals with the same id). | ||
188 | if (find.IdenticalDirectorySymbols.Contains(symbol)) | ||
186 | { | 189 | { |
187 | continue; | 190 | if (!identicalDirectoryIds.Add(symbol.Id.Id)) |
191 | { | ||
192 | continue; | ||
193 | } | ||
188 | } | 194 | } |
189 | 195 | ||
190 | var copySymbol = true; // by default, copy symbols. | 196 | var copySymbol = true; // by default, copy symbols. |
@@ -351,22 +357,24 @@ namespace WixToolset.Core | |||
351 | foreach (var actionSymbol in WindowsInstallerStandard.StandardActions()) | 357 | foreach (var actionSymbol in WindowsInstallerStandard.StandardActions()) |
352 | { | 358 | { |
353 | var symbolWithSection = new SymbolWithSection(null, actionSymbol); | 359 | var symbolWithSection = new SymbolWithSection(null, actionSymbol); |
360 | var fullName = symbolWithSection.GetFullName(); | ||
354 | 361 | ||
355 | // If the action's symbol has not already been defined (i.e. overriden by the user), add it now. | 362 | // If the action's symbol has not already been defined (i.e. overriden by the user), add it now. |
356 | if (!symbolsByName.ContainsKey(symbolWithSection.Name)) | 363 | if (!symbolsByName.ContainsKey(fullName)) |
357 | { | 364 | { |
358 | symbolsByName.Add(symbolWithSection.Name, symbolWithSection); | 365 | symbolsByName.Add(fullName, symbolWithSection); |
359 | } | 366 | } |
360 | } | 367 | } |
361 | 368 | ||
362 | foreach (var directorySymbol in WindowsInstallerStandard.StandardDirectories()) | 369 | foreach (var directorySymbol in WindowsInstallerStandard.StandardDirectories()) |
363 | { | 370 | { |
364 | var symbolWithSection = new SymbolWithSection(null, directorySymbol); | 371 | var symbolWithSection = new SymbolWithSection(null, directorySymbol); |
372 | var fullName = symbolWithSection.GetFullName(); | ||
365 | 373 | ||
366 | // If the directory's symbol has not already been defined (i.e. overriden by the user), add it now. | 374 | // If the directory's symbol has not already been defined (i.e. overriden by the user), add it now. |
367 | if (!symbolsByName.ContainsKey(symbolWithSection.Name)) | 375 | if (!symbolsByName.ContainsKey(fullName)) |
368 | { | 376 | { |
369 | symbolsByName.Add(symbolWithSection.Name, symbolWithSection); | 377 | symbolsByName.Add(fullName, symbolWithSection); |
370 | } | 378 | } |
371 | } | 379 | } |
372 | } | 380 | } |
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/DirectoryFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/DirectoryFixture.cs index cacf72bd..3f4108cb 100644 --- a/src/wix/test/WixToolsetTest.CoreIntegration/DirectoryFixture.cs +++ b/src/wix/test/WixToolsetTest.CoreIntegration/DirectoryFixture.cs | |||
@@ -273,5 +273,52 @@ namespace WixToolsetTest.CoreIntegration | |||
273 | }, directoryRows.Select(r => String.Join('\t', r.FieldAsString(0), r.FieldAsString(1), r.FieldAsString(2))).ToArray()); | 273 | }, directoryRows.Select(r => String.Join('\t', r.FieldAsString(0), r.FieldAsString(1), r.FieldAsString(2))).ToArray()); |
274 | } | 274 | } |
275 | } | 275 | } |
276 | |||
277 | [Fact] | ||
278 | public void CanFindRedundantSubdirectoryInSecondSection() | ||
279 | { | ||
280 | var folder = TestData.Get(@"TestData"); | ||
281 | |||
282 | using (var fs = new DisposableFileSystem()) | ||
283 | { | ||
284 | var baseFolder = fs.GetFolder(); | ||
285 | var intermediateFolder = Path.Combine(baseFolder, "obj"); | ||
286 | var msiPath = Path.Combine(baseFolder, "bin", "test.msi"); | ||
287 | var wixpdbPath = Path.ChangeExtension(msiPath, ".wixpdb"); | ||
288 | |||
289 | var result = WixRunner.Execute(new[] | ||
290 | { | ||
291 | "build", | ||
292 | Path.Combine(folder, "Directory", "RedundantSubdirectoryInSecondSection.wxs"), | ||
293 | "-bindpath", Path.Combine(folder, "SingleFile", "data"), | ||
294 | "-intermediateFolder", intermediateFolder, | ||
295 | "-o", msiPath | ||
296 | }); | ||
297 | |||
298 | result.AssertSuccess(); | ||
299 | |||
300 | var intermediate = Intermediate.Load(wixpdbPath); | ||
301 | var section = intermediate.Sections.Single(); | ||
302 | |||
303 | var dirSymbols = section.Symbols.OfType<WixToolset.Data.Symbols.DirectorySymbol>().ToList(); | ||
304 | WixAssert.CompareLineByLine(new[] | ||
305 | { | ||
306 | @"dKO7wPCF.XLmq6KnqybHHgcBBqtU:ProgramFilesFolder:a\b\c", | ||
307 | @"ProgramFilesFolder:TARGETDIR:PFiles", | ||
308 | @"TARGETDIR::SourceDir" | ||
309 | }, dirSymbols.OrderBy(d => d.Id.Id).Select(d => d.Id.Id + ":" + d.ParentDirectoryRef + ":" + d.Name).OrderBy(s => s).ToArray()); | ||
310 | |||
311 | var data = WindowsInstallerData.Load(wixpdbPath); | ||
312 | var directoryRows = data.Tables["Directory"].Rows; | ||
313 | WixAssert.CompareLineByLine(new[] | ||
314 | { | ||
315 | @"d1nVb5_zcCwRCz7i2YXNAofGRmfc:ProgramFilesFolder:a", | ||
316 | @"dijlG.bNicFgvj1_DujiGg9EBGrQ:d1nVb5_zcCwRCz7i2YXNAofGRmfc:b", | ||
317 | @"dKO7wPCF.XLmq6KnqybHHgcBBqtU:dijlG.bNicFgvj1_DujiGg9EBGrQ:c", | ||
318 | "ProgramFilesFolder:TARGETDIR:PFiles", | ||
319 | "TARGETDIR::SourceDir" | ||
320 | }, directoryRows.Select(r => r.FieldAsString(0) + ":" + r.FieldAsString(1) + ":" + r.FieldAsString(2)).OrderBy(s => s).ToArray()); | ||
321 | } | ||
322 | } | ||
276 | } | 323 | } |
277 | } | 324 | } |
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/Directory/RedundantSubdirectoryInSecondSection.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/Directory/RedundantSubdirectoryInSecondSection.wxs new file mode 100644 index 00000000..fc73ee47 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/Directory/RedundantSubdirectoryInSecondSection.wxs | |||
@@ -0,0 +1,26 @@ | |||
1 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"> | ||
2 | <Package Name="~RedundantSubdirectories" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="12E4699F-E774-4D05-8A01-5BDD41BBA127" Compressed="no"> | ||
3 | <MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." /> | ||
4 | |||
5 | <Feature Id="ProductFeature"> | ||
6 | <!-- NotIncludeButFirst will define the subdirectory and IncludedButSecond needs the same symbols, this tests linking order --> | ||
7 | <ComponentGroupRef Id="IncludedButSecond" /> | ||
8 | </Feature> | ||
9 | </Package> | ||
10 | |||
11 | <Fragment Id="NotIncludedButFirst"> | ||
12 | <ComponentGroup Id="NotIncludedButFirst"> | ||
13 | <Component Directory="ProgramFilesFolder" Subdirectory="a\b\c"> | ||
14 | <File Name="notincluded.txt" Source="test.txt" /> | ||
15 | </Component> | ||
16 | </ComponentGroup> | ||
17 | </Fragment> | ||
18 | |||
19 | <Fragment Id="IncludedButSecond"> | ||
20 | <ComponentGroup Id="IncludedButSecond"> | ||
21 | <Component Directory="ProgramFilesFolder" Subdirectory="a\b\c"> | ||
22 | <File Name="included.txt" Source="test.txt" /> | ||
23 | </Component> | ||
24 | </ComponentGroup> | ||
25 | </Fragment> | ||
26 | </Wix> | ||