diff options
author | Bob Arnson <bob@firegiant.com> | 2023-10-13 18:16:08 -0400 |
---|---|---|
committer | Bob Arnson <github@bobs.org> | 2024-02-26 09:18:20 -0500 |
commit | 6067839ba180f2f4bcd5eac67f839f68f513ccd2 (patch) | |
tree | f371b51c9435fe031314a882f1b68b2348ee8450 | |
parent | 4f1209d8e795ddeb4c639c96081bcfebbfa8e1e2 (diff) | |
download | wix-6067839ba180f2f4bcd5eac67f839f68f513ccd2.tar.gz wix-6067839ba180f2f4bcd5eac67f839f68f513ccd2.tar.bz2 wix-6067839ba180f2f4bcd5eac67f839f68f513ccd2.zip |
Add `Files` file harvesting.
Implements https://github.com/wixtoolset/issues/issues/7857.
Like [naked files](https://github.com/wixtoolset/issues/issues/7696),
`Files` elements can appear where `Component` elements do in WiX v4. The
optimizer enumerates files and directories, generating single-file
components as it goes. MSBuild-like wildcards (including `**`) are
supported. `Excludes` child elements lets you exclude files that would
otherwise be captured by wildcards.
40 files changed, 1146 insertions, 9 deletions
diff --git a/src/api/wix/WixToolset.Data/ErrorMessages.cs b/src/api/wix/WixToolset.Data/ErrorMessages.cs index 79b835cd..d604e94f 100644 --- a/src/api/wix/WixToolset.Data/ErrorMessages.cs +++ b/src/api/wix/WixToolset.Data/ErrorMessages.cs | |||
@@ -368,6 +368,11 @@ namespace WixToolset.Data | |||
368 | return Message(sourceLineNumbers, Ids.ExpectedAttribute, "The {0}/@{1} attribute was not found; it is required unless the attribute {2} has a value of '{3}'.", elementName, attributeName, otherAttributeName, otherAttributeValue, otherAttributeValueUnless); | 368 | return Message(sourceLineNumbers, Ids.ExpectedAttribute, "The {0}/@{1} attribute was not found; it is required unless the attribute {2} has a value of '{3}'.", elementName, attributeName, otherAttributeName, otherAttributeValue, otherAttributeValueUnless); |
369 | } | 369 | } |
370 | 370 | ||
371 | public static Message ExpectedAttributeInElementOrParent(SourceLineNumber sourceLineNumbers, string elementName, string attributeName) | ||
372 | { | ||
373 | return Message(sourceLineNumbers, Ids.ExpectedAttributeInElementOrParent, "The {0}/@{1} attribute was not found or empty; it is required unless it is specified in the parent element.", elementName, attributeName); | ||
374 | } | ||
375 | |||
371 | public static Message ExpectedAttributeInElementOrParent(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string parentElementName) | 376 | public static Message ExpectedAttributeInElementOrParent(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string parentElementName) |
372 | { | 377 | { |
373 | return Message(sourceLineNumbers, Ids.ExpectedAttributeInElementOrParent, "The {0}/@{1} attribute was not found or empty; it is required, or it can be specified in the parent {2} element.", elementName, attributeName, parentElementName); | 378 | return Message(sourceLineNumbers, Ids.ExpectedAttributeInElementOrParent, "The {0}/@{1} attribute was not found or empty; it is required, or it can be specified in the parent {2} element.", elementName, attributeName, parentElementName); |
diff --git a/src/api/wix/WixToolset.Data/Symbols/HarvestFilesSymbol.cs b/src/api/wix/WixToolset.Data/Symbols/HarvestFilesSymbol.cs new file mode 100644 index 00000000..a3123fc1 --- /dev/null +++ b/src/api/wix/WixToolset.Data/Symbols/HarvestFilesSymbol.cs | |||
@@ -0,0 +1,84 @@ | |||
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.Data | ||
4 | { | ||
5 | using WixToolset.Data.Symbols; | ||
6 | |||
7 | public static partial class SymbolDefinitions | ||
8 | { | ||
9 | public static readonly IntermediateSymbolDefinition HarvestFiles = new IntermediateSymbolDefinition( | ||
10 | SymbolDefinitionType.HarvestFiles, | ||
11 | new[] | ||
12 | { | ||
13 | new IntermediateFieldDefinition(nameof(HarvestFilesSymbolFields.DirectoryRef), IntermediateFieldType.String), | ||
14 | new IntermediateFieldDefinition(nameof(HarvestFilesSymbolFields.Inclusions), IntermediateFieldType.String), | ||
15 | new IntermediateFieldDefinition(nameof(HarvestFilesSymbolFields.Exclusions), IntermediateFieldType.String), | ||
16 | new IntermediateFieldDefinition(nameof(HarvestFilesSymbolFields.ComplexReferenceParentType), IntermediateFieldType.String), | ||
17 | new IntermediateFieldDefinition(nameof(HarvestFilesSymbolFields.ParentId), IntermediateFieldType.String), | ||
18 | new IntermediateFieldDefinition(nameof(HarvestFilesSymbolFields.SourcePath), IntermediateFieldType.String), | ||
19 | }, | ||
20 | typeof(HarvestFilesSymbol)); | ||
21 | } | ||
22 | } | ||
23 | |||
24 | namespace WixToolset.Data.Symbols | ||
25 | { | ||
26 | public enum HarvestFilesSymbolFields | ||
27 | { | ||
28 | DirectoryRef, | ||
29 | Inclusions, | ||
30 | Exclusions, | ||
31 | ComplexReferenceParentType, | ||
32 | ParentId, | ||
33 | SourcePath, | ||
34 | } | ||
35 | |||
36 | public class HarvestFilesSymbol : IntermediateSymbol | ||
37 | { | ||
38 | public HarvestFilesSymbol() : base(SymbolDefinitions.HarvestFiles, null, null) | ||
39 | { | ||
40 | } | ||
41 | |||
42 | public HarvestFilesSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(SymbolDefinitions.HarvestFiles, sourceLineNumber, id) | ||
43 | { | ||
44 | } | ||
45 | |||
46 | public IntermediateField this[HarvestFilesSymbolFields index] => this.Fields[(int)index]; | ||
47 | |||
48 | public string DirectoryRef | ||
49 | { | ||
50 | get => (string)this.Fields[(int)HarvestFilesSymbolFields.DirectoryRef]; | ||
51 | set => this.Set((int)HarvestFilesSymbolFields.DirectoryRef, value); | ||
52 | } | ||
53 | |||
54 | public string Inclusions | ||
55 | { | ||
56 | get => (string)this.Fields[(int)HarvestFilesSymbolFields.Inclusions]; | ||
57 | set => this.Set((int)HarvestFilesSymbolFields.Inclusions, value); | ||
58 | } | ||
59 | |||
60 | public string Exclusions | ||
61 | { | ||
62 | get => (string)this.Fields[(int)HarvestFilesSymbolFields.Exclusions]; | ||
63 | set => this.Set((int)HarvestFilesSymbolFields.Exclusions, value); | ||
64 | } | ||
65 | |||
66 | public string ComplexReferenceParentType | ||
67 | { | ||
68 | get => (string)this.Fields[(int)HarvestFilesSymbolFields.ComplexReferenceParentType]; | ||
69 | set => this.Set((int)HarvestFilesSymbolFields.ComplexReferenceParentType, value); | ||
70 | } | ||
71 | |||
72 | public string ParentId | ||
73 | { | ||
74 | get => (string)this.Fields[(int)HarvestFilesSymbolFields.ParentId]; | ||
75 | set => this.Set((int)HarvestFilesSymbolFields.ParentId, value); | ||
76 | } | ||
77 | |||
78 | public string SourcePath | ||
79 | { | ||
80 | get => (string)this.Fields[(int)HarvestFilesSymbolFields.SourcePath]; | ||
81 | set => this.Set((int)HarvestFilesSymbolFields.SourcePath, value); | ||
82 | } | ||
83 | } | ||
84 | } | ||
diff --git a/src/api/wix/WixToolset.Data/Symbols/SymbolDefinitions.cs b/src/api/wix/WixToolset.Data/Symbols/SymbolDefinitions.cs index 3b545a71..67c00431 100644 --- a/src/api/wix/WixToolset.Data/Symbols/SymbolDefinitions.cs +++ b/src/api/wix/WixToolset.Data/Symbols/SymbolDefinitions.cs | |||
@@ -40,6 +40,7 @@ namespace WixToolset.Data | |||
40 | FeatureComponents, | 40 | FeatureComponents, |
41 | File, | 41 | File, |
42 | FileSFPCatalog, | 42 | FileSFPCatalog, |
43 | HarvestFiles, | ||
43 | Icon, | 44 | Icon, |
44 | ImageFamilies, | 45 | ImageFamilies, |
45 | IniFile, | 46 | IniFile, |
diff --git a/src/api/wix/WixToolset.Extensibility/Services/IParseHelper.cs b/src/api/wix/WixToolset.Extensibility/Services/IParseHelper.cs index 3c20c14b..e7856c7c 100644 --- a/src/api/wix/WixToolset.Extensibility/Services/IParseHelper.cs +++ b/src/api/wix/WixToolset.Extensibility/Services/IParseHelper.cs | |||
@@ -11,7 +11,7 @@ namespace WixToolset.Extensibility.Services | |||
11 | using WixToolset.Extensibility.Data; | 11 | using WixToolset.Extensibility.Data; |
12 | 12 | ||
13 | /// <summary> | 13 | /// <summary> |
14 | /// Interface provided to help compiler extensions parse. | 14 | /// Interface provided to help compiler and optimizer extensions parse. |
15 | /// </summary> | 15 | /// </summary> |
16 | public interface IParseHelper | 16 | public interface IParseHelper |
17 | { | 17 | { |
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Bind/CreateWindowsInstallerDataFromIRCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Bind/CreateWindowsInstallerDataFromIRCommand.cs index 5c2c40d1..cd366883 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Bind/CreateWindowsInstallerDataFromIRCommand.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Bind/CreateWindowsInstallerDataFromIRCommand.cs | |||
@@ -234,6 +234,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
234 | break; | 234 | break; |
235 | 235 | ||
236 | // Symbols used internally and are not added to the output. | 236 | // Symbols used internally and are not added to the output. |
237 | case SymbolDefinitionType.HarvestFiles: | ||
237 | case SymbolDefinitionType.WixBuildInfo: | 238 | case SymbolDefinitionType.WixBuildInfo: |
238 | case SymbolDefinitionType.WixBindUpdatedFiles: | 239 | case SymbolDefinitionType.WixBindUpdatedFiles: |
239 | case SymbolDefinitionType.WixComponentGroup: | 240 | case SymbolDefinitionType.WixComponentGroup: |
diff --git a/src/wix/WixToolset.Core/CommandLine/BuildCommand.cs b/src/wix/WixToolset.Core/CommandLine/BuildCommand.cs index b0cd174a..cc0de13a 100644 --- a/src/wix/WixToolset.Core/CommandLine/BuildCommand.cs +++ b/src/wix/WixToolset.Core/CommandLine/BuildCommand.cs | |||
@@ -125,12 +125,8 @@ namespace WixToolset.Core.CommandLine | |||
125 | { | 125 | { |
126 | using (new IntermediateFieldContext("wix.link")) | 126 | using (new IntermediateFieldContext("wix.link")) |
127 | { | 127 | { |
128 | var wixipl = inputsOutputs.Wixipls.SingleOrDefault(); | 128 | var wixipl = inputsOutputs.Wixipls.SingleOrDefault() |
129 | 129 | ?? this.LinkPhase(wixobjs, inputsOutputs, creator, cancellationToken); | |
130 | if (wixipl == null) | ||
131 | { | ||
132 | wixipl = this.LinkPhase(wixobjs, inputsOutputs, creator, cancellationToken); | ||
133 | } | ||
134 | 130 | ||
135 | if (!this.Messaging.EncounteredError) | 131 | if (!this.Messaging.EncounteredError) |
136 | { | 132 | { |
diff --git a/src/wix/WixToolset.Core/Compiler.cs b/src/wix/WixToolset.Core/Compiler.cs index bafe2c19..a98d4574 100644 --- a/src/wix/WixToolset.Core/Compiler.cs +++ b/src/wix/WixToolset.Core/Compiler.cs | |||
@@ -2655,6 +2655,9 @@ namespace WixToolset.Core | |||
2655 | case "File": | 2655 | case "File": |
2656 | this.ParseNakedFileElement(child, ComplexReferenceParentType.ComponentGroup, id.Id, directoryId, source); | 2656 | this.ParseNakedFileElement(child, ComplexReferenceParentType.ComponentGroup, id.Id, directoryId, source); |
2657 | break; | 2657 | break; |
2658 | case "Files": | ||
2659 | this.ParseFilesElement(child, ComplexReferenceParentType.ComponentGroup, id.Id, directoryId, source); | ||
2660 | break; | ||
2658 | default: | 2661 | default: |
2659 | this.Core.UnexpectedElement(node, child); | 2662 | this.Core.UnexpectedElement(node, child); |
2660 | break; | 2663 | break; |
@@ -3106,7 +3109,7 @@ namespace WixToolset.Core | |||
3106 | this.Core.AddSymbol(new MoveFileSymbol(sourceLineNumbers, id) | 3109 | this.Core.AddSymbol(new MoveFileSymbol(sourceLineNumbers, id) |
3107 | { | 3110 | { |
3108 | ComponentRef = componentId, | 3111 | ComponentRef = componentId, |
3109 | SourceName = sourceName, | 3112 | SourceName = sourceName, |
3110 | DestinationName = destinationName, | 3113 | DestinationName = destinationName, |
3111 | DestinationShortName = destinationShortName, | 3114 | DestinationShortName = destinationShortName, |
3112 | SourceFolder = sourceDirectory ?? sourceProperty, | 3115 | SourceFolder = sourceDirectory ?? sourceProperty, |
@@ -3881,6 +3884,9 @@ namespace WixToolset.Core | |||
3881 | case "File": | 3884 | case "File": |
3882 | this.ParseNakedFileElement(child, ComplexReferenceParentType.Unknown, null, id.Id, fileSource); | 3885 | this.ParseNakedFileElement(child, ComplexReferenceParentType.Unknown, null, id.Id, fileSource); |
3883 | break; | 3886 | break; |
3887 | case "Files": | ||
3888 | this.ParseFilesElement(child, ComplexReferenceParentType.Unknown, null, id.Id, fileSource); | ||
3889 | break; | ||
3884 | case "Merge": | 3890 | case "Merge": |
3885 | this.ParseMergeElement(child, id.Id, diskId); | 3891 | this.ParseMergeElement(child, id.Id, diskId); |
3886 | break; | 3892 | break; |
@@ -3996,6 +4002,9 @@ namespace WixToolset.Core | |||
3996 | case "File": | 4002 | case "File": |
3997 | this.ParseNakedFileElement(child, ComplexReferenceParentType.Unknown, null, id, fileSource); | 4003 | this.ParseNakedFileElement(child, ComplexReferenceParentType.Unknown, null, id, fileSource); |
3998 | break; | 4004 | break; |
4005 | case "Files": | ||
4006 | this.ParseFilesElement(child, ComplexReferenceParentType.Unknown, null, id, fileSource); | ||
4007 | break; | ||
3999 | case "Merge": | 4008 | case "Merge": |
4000 | this.ParseMergeElement(child, id, diskId); | 4009 | this.ParseMergeElement(child, id, diskId); |
4001 | break; | 4010 | break; |
@@ -4436,6 +4445,9 @@ namespace WixToolset.Core | |||
4436 | case "File": | 4445 | case "File": |
4437 | this.ParseNakedFileElement(child, ComplexReferenceParentType.Feature, id.Id, null, null); | 4446 | this.ParseNakedFileElement(child, ComplexReferenceParentType.Feature, id.Id, null, null); |
4438 | break; | 4447 | break; |
4448 | case "Files": | ||
4449 | this.ParseFilesElement(child, ComplexReferenceParentType.Feature, id.Id, null, null); | ||
4450 | break; | ||
4439 | case "Level": | 4451 | case "Level": |
4440 | this.ParseLevelElement(child, id.Id); | 4452 | this.ParseLevelElement(child, id.Id); |
4441 | break; | 4453 | break; |
@@ -4579,6 +4591,9 @@ namespace WixToolset.Core | |||
4579 | case "File": | 4591 | case "File": |
4580 | this.ParseNakedFileElement(child, ComplexReferenceParentType.Feature, id, null, null); | 4592 | this.ParseNakedFileElement(child, ComplexReferenceParentType.Feature, id, null, null); |
4581 | break; | 4593 | break; |
4594 | case "Files": | ||
4595 | this.ParseFilesElement(child, ComplexReferenceParentType.Feature, id, null, null); | ||
4596 | break; | ||
4582 | case "MergeRef": | 4597 | case "MergeRef": |
4583 | this.ParseMergeRefElement(child, ComplexReferenceParentType.Feature, id); | 4598 | this.ParseMergeRefElement(child, ComplexReferenceParentType.Feature, id); |
4584 | break; | 4599 | break; |
@@ -4667,6 +4682,9 @@ namespace WixToolset.Core | |||
4667 | case "File": | 4682 | case "File": |
4668 | this.ParseNakedFileElement(child, ComplexReferenceParentType.FeatureGroup, id.Id, null, null); | 4683 | this.ParseNakedFileElement(child, ComplexReferenceParentType.FeatureGroup, id.Id, null, null); |
4669 | break; | 4684 | break; |
4685 | case "Files": | ||
4686 | this.ParseFilesElement(child, ComplexReferenceParentType.Feature, id.Id, null, null); | ||
4687 | break; | ||
4670 | case "MergeRef": | 4688 | case "MergeRef": |
4671 | this.ParseMergeRefElement(child, ComplexReferenceParentType.FeatureGroup, id.Id); | 4689 | this.ParseMergeRefElement(child, ComplexReferenceParentType.FeatureGroup, id.Id); |
4672 | break; | 4690 | break; |
@@ -5678,6 +5696,129 @@ namespace WixToolset.Core | |||
5678 | } | 5696 | } |
5679 | 5697 | ||
5680 | /// <summary> | 5698 | /// <summary> |
5699 | /// Parses a `Files` element. | ||
5700 | /// </summary> | ||
5701 | /// <param name="node">Files element to parse.</param> | ||
5702 | /// <param name="parentType">Type of complex reference parent. Will be Unknown if there is no parent.</param> | ||
5703 | /// <param name="parentId">Optional identifier for primary parent.</param> | ||
5704 | /// <param name="directoryId">Ancestor's directory id.</param> | ||
5705 | /// <param name="sourcePath">Default source path of parent directory.</param> | ||
5706 | private void ParseFilesElement(XElement node, ComplexReferenceParentType parentType, string parentId, string directoryId, string sourcePath) | ||
5707 | { | ||
5708 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
5709 | var win64 = this.Context.IsCurrentPlatform64Bit; | ||
5710 | string subdirectory = null; | ||
5711 | var inclusions = new List<string>(); | ||
5712 | var exclusions = new List<string>(); | ||
5713 | |||
5714 | foreach (var attrib in node.Attributes()) | ||
5715 | { | ||
5716 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
5717 | { | ||
5718 | switch (attrib.Name.LocalName) | ||
5719 | { | ||
5720 | case "Directory": | ||
5721 | directoryId = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
5722 | this.Core.CreateSimpleReference(sourceLineNumbers, SymbolDefinitions.Directory, directoryId); | ||
5723 | break; | ||
5724 | case "Subdirectory": | ||
5725 | subdirectory = this.Core.GetAttributeLongFilename(sourceLineNumbers, attrib, allowRelative: true); | ||
5726 | break; | ||
5727 | case "Include": | ||
5728 | inclusions.AddRange(this.Core.GetAttributeValue(sourceLineNumbers, attrib).Split(';')); | ||
5729 | break; | ||
5730 | default: | ||
5731 | this.Core.UnexpectedAttribute(node, attrib); | ||
5732 | break; | ||
5733 | } | ||
5734 | } | ||
5735 | else | ||
5736 | { | ||
5737 | var context = new Dictionary<string, string>() { { "Win64", win64.ToString() } }; | ||
5738 | this.Core.ParseExtensionAttribute(node, attrib, context); | ||
5739 | } | ||
5740 | } | ||
5741 | |||
5742 | foreach (var child in node.Elements()) | ||
5743 | { | ||
5744 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
5745 | { | ||
5746 | switch (child.Name.LocalName) | ||
5747 | { | ||
5748 | case "Exclude": | ||
5749 | this.ParseFilesExcludeElement(child, exclusions); | ||
5750 | break; | ||
5751 | default: | ||
5752 | this.Core.UnexpectedElement(node, child); | ||
5753 | break; | ||
5754 | } | ||
5755 | } | ||
5756 | else | ||
5757 | { | ||
5758 | var context = new Dictionary<string, string>() { { "Win64", win64.ToString() } }; | ||
5759 | this.Core.ParseExtensionElement(node, child, context); | ||
5760 | } | ||
5761 | } | ||
5762 | |||
5763 | if (String.IsNullOrEmpty(directoryId)) | ||
5764 | { | ||
5765 | directoryId = "INSTALLFOLDER"; | ||
5766 | this.Core.CreateSimpleReference(sourceLineNumbers, SymbolDefinitions.Directory, directoryId); | ||
5767 | } | ||
5768 | else if (!String.IsNullOrEmpty(subdirectory)) | ||
5769 | { | ||
5770 | directoryId = this.HandleSubdirectory(sourceLineNumbers, node, directoryId, subdirectory, "Directory", "Subdirectory"); | ||
5771 | } | ||
5772 | |||
5773 | if (!inclusions.Any()) | ||
5774 | { | ||
5775 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Include")); | ||
5776 | } | ||
5777 | |||
5778 | var inclusionsAsString = String.Join(";", inclusions); | ||
5779 | var exclusionsAsString = String.Join(";", exclusions); | ||
5780 | |||
5781 | var id = this.Core.CreateIdentifier("hvf", directoryId, inclusionsAsString, exclusionsAsString); | ||
5782 | |||
5783 | this.Core.AddSymbol(new HarvestFilesSymbol(sourceLineNumbers, id) | ||
5784 | { | ||
5785 | DirectoryRef = directoryId, | ||
5786 | Inclusions = inclusionsAsString, | ||
5787 | Exclusions = exclusionsAsString, | ||
5788 | ComplexReferenceParentType = parentType.ToString(), | ||
5789 | ParentId = parentId, | ||
5790 | SourcePath = sourcePath, | ||
5791 | }); | ||
5792 | } | ||
5793 | |||
5794 | private void ParseFilesExcludeElement(XElement node, IList<string> paths) | ||
5795 | { | ||
5796 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
5797 | |||
5798 | foreach (var attrib in node.Attributes()) | ||
5799 | { | ||
5800 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
5801 | { | ||
5802 | switch (attrib.Name.LocalName) | ||
5803 | { | ||
5804 | case "Files": | ||
5805 | paths.Add(this.Core.GetAttributeValue(sourceLineNumbers, attrib)); | ||
5806 | break; | ||
5807 | default: | ||
5808 | this.Core.UnexpectedAttribute(node, attrib); | ||
5809 | break; | ||
5810 | } | ||
5811 | } | ||
5812 | else | ||
5813 | { | ||
5814 | this.Core.ParseExtensionAttribute(node, attrib); | ||
5815 | } | ||
5816 | } | ||
5817 | |||
5818 | this.Core.ParseForExtensionElements(node); | ||
5819 | } | ||
5820 | |||
5821 | /// <summary> | ||
5681 | /// Parses a file search element. | 5822 | /// Parses a file search element. |
5682 | /// </summary> | 5823 | /// </summary> |
5683 | /// <param name="node">Element to parse.</param> | 5824 | /// <param name="node">Element to parse.</param> |
@@ -5997,6 +6138,9 @@ namespace WixToolset.Core | |||
5997 | case "File": | 6138 | case "File": |
5998 | this.ParseNakedFileElement(child, ComplexReferenceParentType.Unknown, null, null, null); | 6139 | this.ParseNakedFileElement(child, ComplexReferenceParentType.Unknown, null, null, null); |
5999 | break; | 6140 | break; |
6141 | case "Files": | ||
6142 | this.ParseFilesElement(child, ComplexReferenceParentType.Unknown, null, null, null); | ||
6143 | break; | ||
6000 | case "Icon": | 6144 | case "Icon": |
6001 | this.ParseIconElement(child); | 6145 | this.ParseIconElement(child); |
6002 | break; | 6146 | break; |
@@ -7347,6 +7491,9 @@ namespace WixToolset.Core | |||
7347 | case "File": | 7491 | case "File": |
7348 | this.ParseNakedFileElement(child, ComplexReferenceParentType.Unknown, null, id, null); | 7492 | this.ParseNakedFileElement(child, ComplexReferenceParentType.Unknown, null, id, null); |
7349 | break; | 7493 | break; |
7494 | case "Files": | ||
7495 | this.ParseFilesElement(child, ComplexReferenceParentType.Unknown, null, id, null); | ||
7496 | break; | ||
7350 | case "Merge": | 7497 | case "Merge": |
7351 | this.ParseMergeElement(child, id, diskId: CompilerConstants.IntegerNotSet); | 7498 | this.ParseMergeElement(child, id, diskId: CompilerConstants.IntegerNotSet); |
7352 | break; | 7499 | break; |
diff --git a/src/wix/WixToolset.Core/Compiler_Module.cs b/src/wix/WixToolset.Core/Compiler_Module.cs index 19f57773..08f47657 100644 --- a/src/wix/WixToolset.Core/Compiler_Module.cs +++ b/src/wix/WixToolset.Core/Compiler_Module.cs | |||
@@ -178,6 +178,9 @@ namespace WixToolset.Core | |||
178 | case "File": | 178 | case "File": |
179 | this.ParseNakedFileElement(child, ComplexReferenceParentType.Module, this.activeName, null, null); | 179 | this.ParseNakedFileElement(child, ComplexReferenceParentType.Module, this.activeName, null, null); |
180 | break; | 180 | break; |
181 | case "Files": | ||
182 | this.ParseFilesElement(child, ComplexReferenceParentType.Module, this.activeName, null, null); | ||
183 | break; | ||
181 | case "Icon": | 184 | case "Icon": |
182 | this.ParseIconElement(child); | 185 | this.ParseIconElement(child); |
183 | break; | 186 | break; |
diff --git a/src/wix/WixToolset.Core/Compiler_Package.cs b/src/wix/WixToolset.Core/Compiler_Package.cs index 220a2a76..8856930a 100644 --- a/src/wix/WixToolset.Core/Compiler_Package.cs +++ b/src/wix/WixToolset.Core/Compiler_Package.cs | |||
@@ -306,6 +306,9 @@ namespace WixToolset.Core | |||
306 | case "File": | 306 | case "File": |
307 | this.ParseNakedFileElement(child, ComplexReferenceParentType.Product, productCode, null, null); | 307 | this.ParseNakedFileElement(child, ComplexReferenceParentType.Product, productCode, null, null); |
308 | break; | 308 | break; |
309 | case "Files": | ||
310 | this.ParseFilesElement(child, ComplexReferenceParentType.Unknown, null, null, null); | ||
311 | break; | ||
309 | case "Icon": | 312 | case "Icon": |
310 | this.ParseIconElement(child); | 313 | this.ParseIconElement(child); |
311 | break; | 314 | break; |
diff --git a/src/wix/WixToolset.Core/HarvestFilesCommand.cs b/src/wix/WixToolset.Core/HarvestFilesCommand.cs new file mode 100644 index 00000000..c92de516 --- /dev/null +++ b/src/wix/WixToolset.Core/HarvestFilesCommand.cs | |||
@@ -0,0 +1,248 @@ | |||
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 | ||
4 | { | ||
5 | using System; | ||
6 | using System.Collections.Generic; | ||
7 | using System.IO; | ||
8 | using System.Linq; | ||
9 | using WixToolset.Data; | ||
10 | using WixToolset.Data.Symbols; | ||
11 | using WixToolset.Extensibility.Data; | ||
12 | using WixToolset.Extensibility.Services; | ||
13 | |||
14 | internal class HarvestFilesCommand | ||
15 | { | ||
16 | private const string BindPathOpenString = "!(bindpath."; | ||
17 | |||
18 | public HarvestFilesCommand(IOptimizeContext context) | ||
19 | { | ||
20 | this.Context = context; | ||
21 | this.Messaging = this.Context.ServiceProvider.GetService<IMessaging>(); | ||
22 | this.ParseHelper = this.Context.ServiceProvider.GetService<IParseHelper>(); | ||
23 | } | ||
24 | |||
25 | public IOptimizeContext Context { get; } | ||
26 | |||
27 | public IMessaging Messaging { get; } | ||
28 | |||
29 | public IParseHelper ParseHelper { get; } | ||
30 | |||
31 | internal void Execute() | ||
32 | { | ||
33 | var harvestedFiles = new HashSet<string>(); | ||
34 | |||
35 | foreach (var section in this.Context.Intermediates.SelectMany(i => i.Sections)) | ||
36 | { | ||
37 | foreach (var harvestFiles in section.Symbols.OfType<HarvestFilesSymbol>().ToList()) | ||
38 | { | ||
39 | this.HarvestFiles(harvestFiles, section, harvestedFiles); | ||
40 | } | ||
41 | } | ||
42 | } | ||
43 | |||
44 | private void HarvestFiles(HarvestFilesSymbol harvestFile, IntermediateSection section, ISet<string> harvestedFiles) | ||
45 | { | ||
46 | var unusedSectionCachedInlinedDirectoryIds = new Dictionary<string, string>(); | ||
47 | |||
48 | var directoryId = harvestFile.DirectoryRef; | ||
49 | |||
50 | var inclusions = harvestFile.Inclusions.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries); | ||
51 | var exclusions = harvestFile.Exclusions.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries); | ||
52 | |||
53 | var comparer = new WildcardFileComparer(); | ||
54 | |||
55 | var resolvedFiles = Enumerable.Empty<WildcardFile>(); | ||
56 | |||
57 | try | ||
58 | { | ||
59 | var included = this.GetWildcardFiles(harvestFile, inclusions); | ||
60 | var excluded = this.GetWildcardFiles(harvestFile, exclusions); | ||
61 | |||
62 | resolvedFiles = included.Except(excluded, comparer).ToList(); | ||
63 | |||
64 | if (!resolvedFiles.Any()) | ||
65 | { | ||
66 | this.Messaging.Write(OptimizerWarnings.ZeroFilesHarvested(harvestFile.SourceLineNumbers)); | ||
67 | } | ||
68 | } | ||
69 | catch (DirectoryNotFoundException e) | ||
70 | { | ||
71 | this.Messaging.Write(OptimizerWarnings.ExpectedDirectory(harvestFile.SourceLineNumbers, e.Message)); | ||
72 | |||
73 | return; | ||
74 | } | ||
75 | |||
76 | foreach (var fileByRecursiveDir in resolvedFiles.GroupBy(resolvedFile => resolvedFile.RecursiveDir, resolvedFile => resolvedFile.Path)) | ||
77 | { | ||
78 | var recursiveDir = fileByRecursiveDir.Key; | ||
79 | |||
80 | if (!String.IsNullOrEmpty(recursiveDir)) | ||
81 | { | ||
82 | directoryId = this.ParseHelper.CreateDirectoryReferenceFromInlineSyntax(section, harvestFile.SourceLineNumbers, attribute: null, directoryId, recursiveDir, unusedSectionCachedInlinedDirectoryIds); | ||
83 | } | ||
84 | |||
85 | foreach (var file in fileByRecursiveDir) | ||
86 | { | ||
87 | if (harvestedFiles.Add(file)) | ||
88 | { | ||
89 | var name = Path.GetFileName(file); | ||
90 | |||
91 | var id = this.ParseHelper.CreateIdentifier("fls", directoryId, name); | ||
92 | |||
93 | section.AddSymbol(new FileSymbol(harvestFile.SourceLineNumbers, id) | ||
94 | { | ||
95 | ComponentRef = id.Id, | ||
96 | Name = name, | ||
97 | Attributes = FileSymbolAttributes.None | FileSymbolAttributes.Vital, | ||
98 | DirectoryRef = directoryId, | ||
99 | Source = new IntermediateFieldPathValue { Path = file }, | ||
100 | }); | ||
101 | |||
102 | section.AddSymbol(new ComponentSymbol(harvestFile.SourceLineNumbers, id) | ||
103 | { | ||
104 | ComponentId = "*", | ||
105 | DirectoryRef = directoryId, | ||
106 | Location = ComponentLocation.LocalOnly, | ||
107 | KeyPath = id.Id, | ||
108 | KeyPathType = ComponentKeyPathType.File, | ||
109 | Win64 = this.Context.Platform == Platform.ARM64 || this.Context.Platform == Platform.X64, | ||
110 | }); | ||
111 | |||
112 | if (Enum.TryParse<ComplexReferenceParentType>(harvestFile.ComplexReferenceParentType, out var parentType) | ||
113 | && ComplexReferenceParentType.Unknown != parentType && null != harvestFile.ParentId) | ||
114 | { | ||
115 | // If the parent was provided, add a complex reference to that, and, if | ||
116 | // the Files is under a feature, then mark the complex reference primary. | ||
117 | this.ParseHelper.CreateComplexReference(section, harvestFile.SourceLineNumbers, parentType, harvestFile.ParentId, null, ComplexReferenceChildType.Component, id.Id, ComplexReferenceParentType.Feature == parentType); | ||
118 | } | ||
119 | } | ||
120 | else | ||
121 | { | ||
122 | this.Messaging.Write(OptimizerWarnings.SkippingDuplicateFile(harvestFile.SourceLineNumbers, file)); | ||
123 | } | ||
124 | } | ||
125 | } | ||
126 | } | ||
127 | |||
128 | private IEnumerable<WildcardFile> GetWildcardFiles(HarvestFilesSymbol harvestFile, IEnumerable<string> patterns) | ||
129 | { | ||
130 | var sourceLineNumbers = harvestFile.SourceLineNumbers; | ||
131 | var sourcePath = harvestFile.SourcePath; | ||
132 | |||
133 | var files = new List<WildcardFile>(); | ||
134 | |||
135 | foreach (var pattern in patterns) | ||
136 | { | ||
137 | // Resolve bind paths, if any, which might result in multiple directories. | ||
138 | foreach (var path in this.ResolveBindPaths(sourceLineNumbers, pattern)) | ||
139 | { | ||
140 | var sourceDirectory = String.IsNullOrEmpty(sourcePath) ? Path.GetDirectoryName(sourceLineNumbers.FileName) : sourcePath; | ||
141 | var recursive = path.IndexOf("**") >= 0; | ||
142 | var filePortion = Path.GetFileName(path); | ||
143 | var directoryPortion = Path.GetDirectoryName(path); | ||
144 | |||
145 | if (directoryPortion?.EndsWith(@"\**") == true) | ||
146 | { | ||
147 | directoryPortion = directoryPortion.Substring(0, directoryPortion.Length - 3); | ||
148 | } | ||
149 | |||
150 | var recursiveDirOffset = directoryPortion.Length + 1; | ||
151 | |||
152 | if (directoryPortion is null || directoryPortion.Length == 0 || directoryPortion == "**") | ||
153 | { | ||
154 | directoryPortion = sourceDirectory; | ||
155 | recursiveDirOffset = sourceDirectory.Length + 1; | ||
156 | |||
157 | } | ||
158 | else if (!Path.IsPathRooted(directoryPortion)) | ||
159 | { | ||
160 | directoryPortion = Path.Combine(sourceDirectory, directoryPortion); | ||
161 | recursiveDirOffset = sourceDirectory.Length + 1; | ||
162 | } | ||
163 | |||
164 | var foundFiles = Directory.EnumerateFiles(directoryPortion, filePortion, recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly); | ||
165 | |||
166 | foreach (var foundFile in foundFiles) | ||
167 | { | ||
168 | var recursiveDir = Path.GetDirectoryName(foundFile.Substring(recursiveDirOffset)); | ||
169 | files.Add(new WildcardFile() | ||
170 | { | ||
171 | RecursiveDir = recursiveDir, | ||
172 | Path = foundFile, | ||
173 | }); | ||
174 | } | ||
175 | } | ||
176 | } | ||
177 | |||
178 | return files; | ||
179 | } | ||
180 | |||
181 | private IEnumerable<string> ResolveBindPaths(SourceLineNumber sourceLineNumbers, string source) | ||
182 | { | ||
183 | var resultingDirectories = new List<string>(); | ||
184 | |||
185 | var bindName = String.Empty; | ||
186 | var path = source; | ||
187 | |||
188 | if (source.StartsWith(BindPathOpenString, StringComparison.Ordinal)) | ||
189 | { | ||
190 | var closeParen = source.IndexOf(')', BindPathOpenString.Length); | ||
191 | |||
192 | if (-1 != closeParen) | ||
193 | { | ||
194 | bindName = source.Substring(BindPathOpenString.Length, closeParen - BindPathOpenString.Length); | ||
195 | path = source.Substring(BindPathOpenString.Length + bindName.Length + 1); // +1 for the closing brace. | ||
196 | path = path.TrimStart('\\'); // remove starting '\\' char so the path doesn't look rooted. | ||
197 | } | ||
198 | } | ||
199 | |||
200 | if (String.IsNullOrEmpty(bindName)) | ||
201 | { | ||
202 | resultingDirectories.Add(path); | ||
203 | } | ||
204 | else | ||
205 | { | ||
206 | var foundBindPath = false; | ||
207 | |||
208 | foreach (var bindPath in this.Context.BindPaths) | ||
209 | { | ||
210 | if (bindName.Equals(bindPath.Name, StringComparison.OrdinalIgnoreCase)) | ||
211 | { | ||
212 | var resolved = Path.Combine(bindPath.Path, path); | ||
213 | resultingDirectories.Add(resolved); | ||
214 | |||
215 | foundBindPath = true; | ||
216 | } | ||
217 | } | ||
218 | |||
219 | if (!foundBindPath) | ||
220 | { | ||
221 | this.Messaging.Write(OptimizerWarnings.ExpectedDirectory(sourceLineNumbers, source)); | ||
222 | } | ||
223 | } | ||
224 | |||
225 | return resultingDirectories; | ||
226 | } | ||
227 | |||
228 | private class WildcardFile | ||
229 | { | ||
230 | public string RecursiveDir { get; set; } | ||
231 | |||
232 | public string Path { get; set; } | ||
233 | } | ||
234 | |||
235 | private class WildcardFileComparer : IEqualityComparer<WildcardFile> | ||
236 | { | ||
237 | public bool Equals(WildcardFile x, WildcardFile y) | ||
238 | { | ||
239 | return x?.Path == y?.Path; | ||
240 | } | ||
241 | |||
242 | public int GetHashCode(WildcardFile obj) | ||
243 | { | ||
244 | return obj?.Path?.GetHashCode() ?? 0; | ||
245 | } | ||
246 | } | ||
247 | } | ||
248 | } | ||
diff --git a/src/wix/WixToolset.Core/Optimizer.cs b/src/wix/WixToolset.Core/Optimizer.cs index 5864121e..33f757a3 100644 --- a/src/wix/WixToolset.Core/Optimizer.cs +++ b/src/wix/WixToolset.Core/Optimizer.cs | |||
@@ -25,7 +25,10 @@ namespace WixToolset.Core | |||
25 | extension.PreOptimize(context); | 25 | extension.PreOptimize(context); |
26 | } | 26 | } |
27 | 27 | ||
28 | // TODO: Fill with useful optimization features. | 28 | { |
29 | var command = new HarvestFilesCommand(context); | ||
30 | command.Execute(); | ||
31 | } | ||
29 | 32 | ||
30 | foreach (var extension in context.Extensions) | 33 | foreach (var extension in context.Extensions) |
31 | { | 34 | { |
diff --git a/src/wix/WixToolset.Core/OptimizerWarnings.cs b/src/wix/WixToolset.Core/OptimizerWarnings.cs new file mode 100644 index 00000000..784dc587 --- /dev/null +++ b/src/wix/WixToolset.Core/OptimizerWarnings.cs | |||
@@ -0,0 +1,36 @@ | |||
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 | ||
4 | { | ||
5 | using WixToolset.Data; | ||
6 | |||
7 | internal static class OptimizerWarnings | ||
8 | { | ||
9 | public static Message ZeroFilesHarvested(SourceLineNumber sourceLineNumbers) | ||
10 | { | ||
11 | return Message(sourceLineNumbers, Ids.ZeroFilesHarvested, "Files inclusions and exclusions resulted in zero files harvested. Unless that is expected, you should verify your Files paths, inclusions, and exclusions for accuracy."); | ||
12 | } | ||
13 | |||
14 | public static Message ExpectedDirectory(SourceLineNumber sourceLineNumbers, string harvestDirectory) | ||
15 | { | ||
16 | return Message(sourceLineNumbers, Ids.ExpectedDirectory, "Missing directory for harvesting files: {0}", harvestDirectory); | ||
17 | } | ||
18 | |||
19 | public static Message SkippingDuplicateFile(SourceLineNumber sourceLineNumbers, string duplicateFile) | ||
20 | { | ||
21 | return Message(sourceLineNumbers, Ids.SkippingDuplicateFile, "Skipping file that has already been harvested: {0}", duplicateFile); | ||
22 | } | ||
23 | |||
24 | private static Message Message(SourceLineNumber sourceLineNumber, Ids id, string format, params object[] args) | ||
25 | { | ||
26 | return new Message(sourceLineNumber, MessageLevel.Warning, (int)id, format, args); | ||
27 | } | ||
28 | |||
29 | public enum Ids | ||
30 | { | ||
31 | ZeroFilesHarvested = 8600, | ||
32 | ExpectedDirectory = 8601, | ||
33 | SkippingDuplicateFile = 8602, | ||
34 | } | ||
35 | } | ||
36 | } | ||
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/HarvestFilesFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/HarvestFilesFixture.cs new file mode 100644 index 00000000..c9e7fb14 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/HarvestFilesFixture.cs | |||
@@ -0,0 +1,320 @@ | |||
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 WixToolsetTest.CoreIntegration | ||
4 | { | ||
5 | using System.Data; | ||
6 | using System.IO; | ||
7 | using System.Linq; | ||
8 | using WixInternal.Core.TestPackage; | ||
9 | using WixInternal.TestSupport; | ||
10 | using Xunit; | ||
11 | |||
12 | public class HarvestFilesFixture | ||
13 | { | ||
14 | [Fact] | ||
15 | public void MustIncludeSomeFiles() | ||
16 | { | ||
17 | var messages = BuildAndQueryComponentAndFileTables("BadAuthoring.wxs", isPackage: true, 10); | ||
18 | Assert.Equal(new[] | ||
19 | { | ||
20 | "10", | ||
21 | }, messages); | ||
22 | } | ||
23 | |||
24 | [Fact] | ||
25 | public void ZeroFilesHarvestedIsAWarning() | ||
26 | { | ||
27 | var messages = BuildAndQueryComponentAndFileTables("ZeroFiles.wxs", isPackage: true, 8600); | ||
28 | Assert.Equal(new[] | ||
29 | { | ||
30 | "8600", | ||
31 | }, messages); | ||
32 | } | ||
33 | |||
34 | [Fact] | ||
35 | public void MissingHarvestDirectoryIsAWarning() | ||
36 | { | ||
37 | var messages = BuildAndQueryComponentAndFileTables("BadDirectory.wxs", isPackage: true, 8601); | ||
38 | Assert.Equal(new[] | ||
39 | { | ||
40 | "8601", | ||
41 | "8601", | ||
42 | }, messages); | ||
43 | } | ||
44 | |||
45 | [Fact] | ||
46 | public void DuplicateFilesSomethingSomething() | ||
47 | { | ||
48 | var messages = BuildAndQueryComponentAndFileTables("DuplicateFiles.wxs", isPackage: true, 8602); | ||
49 | Assert.Equal(new[] | ||
50 | { | ||
51 | "8602", | ||
52 | "8602", | ||
53 | "8602", | ||
54 | "8602", | ||
55 | }, messages); | ||
56 | } | ||
57 | |||
58 | [Fact] | ||
59 | public void CanHarvestFilesInComponentGroup() | ||
60 | { | ||
61 | BuildQueryAssertFiles("ComponentGroup.wxs", new[] | ||
62 | { | ||
63 | "FileName.Extension", | ||
64 | "test20.txt", | ||
65 | "test21.txt", | ||
66 | "test3.txt", | ||
67 | "test4.txt", | ||
68 | }); | ||
69 | } | ||
70 | |||
71 | [Fact] | ||
72 | public void CanHarvestFilesInDirectory() | ||
73 | { | ||
74 | BuildQueryAssertFiles("Directory.wxs", new[] | ||
75 | { | ||
76 | "test10.txt", | ||
77 | "test120.txt", | ||
78 | "test2.txt", | ||
79 | "test3.txt", | ||
80 | "test4.txt", | ||
81 | }); | ||
82 | } | ||
83 | |||
84 | [Fact] | ||
85 | public void CanHarvestFilesInDirectoryRef() | ||
86 | { | ||
87 | BuildQueryAssertFiles("DirectoryRef.wxs", new[] | ||
88 | { | ||
89 | "notatest.txt", | ||
90 | "pleasedontincludeme.dat", | ||
91 | "test1.txt", | ||
92 | "test120.txt", | ||
93 | "test2.txt", | ||
94 | "test20.txt", | ||
95 | "test21.txt", | ||
96 | "test3.txt", | ||
97 | "test4.txt", | ||
98 | }); | ||
99 | } | ||
100 | |||
101 | [Fact] | ||
102 | public void CanHarvestFilesInFeature() | ||
103 | { | ||
104 | var rows = BuildAndQueryComponentAndFileTables("Feature.wxs"); | ||
105 | |||
106 | AssertFileComponentIds(3, rows); | ||
107 | } | ||
108 | |||
109 | [Fact] | ||
110 | public void CanHarvestFilesInFeatureGroup() | ||
111 | { | ||
112 | BuildQueryAssertFiles("FeatureGroup.wxs", new[] | ||
113 | { | ||
114 | "FileName.Extension", | ||
115 | "notatest.txt", | ||
116 | "pleasedontincludeme.dat", | ||
117 | "test1.txt", | ||
118 | "test2.txt", | ||
119 | "test20.txt", | ||
120 | "test21.txt", | ||
121 | "test3.txt", | ||
122 | "test4.txt", | ||
123 | }); | ||
124 | } | ||
125 | |||
126 | [Fact] | ||
127 | public void CanHarvestFilesInFeatureRef() | ||
128 | { | ||
129 | BuildQueryAssertFiles("FeatureRef.wxs", new[] | ||
130 | { | ||
131 | "FileName.Extension", | ||
132 | "notatest.txt", | ||
133 | "pleasedontincludeme.dat", | ||
134 | "test1.txt", | ||
135 | "test2.txt", | ||
136 | "test20.txt", | ||
137 | "test21.txt", | ||
138 | "test3.txt", | ||
139 | "test4.txt", | ||
140 | }); | ||
141 | } | ||
142 | |||
143 | [Fact] | ||
144 | public void CanHarvestFilesInFragments() | ||
145 | { | ||
146 | BuildQueryAssertFiles("Fragment.wxs", new[] | ||
147 | { | ||
148 | "notatest.txt", | ||
149 | "test1.txt", | ||
150 | "test2.txt", | ||
151 | "test3.txt", | ||
152 | "test4.txt", | ||
153 | }); | ||
154 | } | ||
155 | |||
156 | [Fact] | ||
157 | public void CanHarvestFilesInModules() | ||
158 | { | ||
159 | BuildQueryAssertFiles("Module.wxs", new[] | ||
160 | { | ||
161 | "notatest.txt", | ||
162 | "test1.txt", | ||
163 | "test2.txt", | ||
164 | "test3.txt", | ||
165 | "test4.txt", | ||
166 | }, isPackage: false); | ||
167 | } | ||
168 | |||
169 | [Fact] | ||
170 | public void CanHarvestFilesWithBindPaths() | ||
171 | { | ||
172 | BuildQueryAssertFiles("BindPaths.wxs", new[] | ||
173 | { | ||
174 | "FileName.Extension", | ||
175 | "test1.txt", | ||
176 | "test10.txt", | ||
177 | "test120.txt", | ||
178 | "test2.txt", | ||
179 | "test20.txt", | ||
180 | "test21.txt", | ||
181 | "test3.txt", | ||
182 | "test4.txt", | ||
183 | }); | ||
184 | } | ||
185 | |||
186 | [Fact] | ||
187 | public void HarvestedFilesUnderPackageWithAuthoredFeatureAreOrphaned() | ||
188 | { | ||
189 | var messages = BuildAndQueryComponentAndFileTables("PackageWithoutDefaultFeature.wxs", isPackage: true, 267); | ||
190 | Assert.Equal(new[] | ||
191 | { | ||
192 | "267", | ||
193 | "267", | ||
194 | "267", | ||
195 | "267", | ||
196 | }, messages); | ||
197 | } | ||
198 | |||
199 | [Fact] | ||
200 | public void CanHarvestFilesInStandardDirectory() | ||
201 | { | ||
202 | BuildQueryAssertFiles("StandardDirectory.wxs", new[] | ||
203 | { | ||
204 | "FileName.Extension", | ||
205 | "notatest.txt", | ||
206 | "pleasedontincludeme.dat", | ||
207 | "test1.txt", | ||
208 | "test10.txt", | ||
209 | "test120.txt", | ||
210 | "test2.txt", | ||
211 | "test20.txt", | ||
212 | "test21.txt", | ||
213 | "test3.txt", | ||
214 | "test4.txt", | ||
215 | }); | ||
216 | } | ||
217 | |||
218 | [Fact] | ||
219 | public void CanHarvestFilesInFiveLines() | ||
220 | { | ||
221 | BuildQueryAssertFiles("PackageFiveLiner.wxs", new[] | ||
222 | { | ||
223 | "FileName.Extension", | ||
224 | "notatest.txt", | ||
225 | "pleasedontincludeme.dat", | ||
226 | "test20.txt", | ||
227 | "test21.txt", | ||
228 | "test3.txt", | ||
229 | "test4.txt", | ||
230 | }); | ||
231 | } | ||
232 | |||
233 | private static void BuildQueryAssertFiles(string file, string[] expectedFileNames, bool isPackage = true, int? exitCode = null) | ||
234 | { | ||
235 | var rows = BuildAndQueryComponentAndFileTables(file, isPackage, exitCode); | ||
236 | |||
237 | var fileNames = AssertFileComponentIds(expectedFileNames.Length, rows); | ||
238 | |||
239 | Assert.Equal(expectedFileNames, fileNames); | ||
240 | } | ||
241 | |||
242 | private static string[] BuildAndQueryComponentAndFileTables(string file, bool isPackage = true, int? exitCode = null) | ||
243 | { | ||
244 | var folder = TestData.Get("TestData", "HarvestFiles"); | ||
245 | |||
246 | using (var fs = new DisposableFileSystem()) | ||
247 | { | ||
248 | var baseFolder = fs.GetFolder(); | ||
249 | var intermediateFolder = Path.Combine(baseFolder, "obj"); | ||
250 | var binFolder = Path.Combine(baseFolder, "bin"); | ||
251 | var msiPath = Path.Combine(binFolder, isPackage ? "test.msi" : "test.msm"); | ||
252 | |||
253 | var arguments = new[] | ||
254 | { | ||
255 | "build", | ||
256 | Path.Combine(folder, file), | ||
257 | "-intermediateFolder", intermediateFolder, | ||
258 | "-bindpath", folder, | ||
259 | "-bindpath", @$"ToBeHarvested={folder}\files1", | ||
260 | "-bindpath", @$"ToBeHarvested={folder}\files2", | ||
261 | "-o", msiPath, | ||
262 | }; | ||
263 | |||
264 | var result = WixRunner.Execute(arguments); | ||
265 | |||
266 | if (exitCode.HasValue) | ||
267 | { | ||
268 | Assert.Equal(exitCode.Value, result.ExitCode); | ||
269 | |||
270 | return result.Messages.Select(m => m.Id.ToString()).ToArray(); | ||
271 | } | ||
272 | else | ||
273 | { | ||
274 | result.AssertSuccess(); | ||
275 | |||
276 | return Query.QueryDatabase(msiPath, new[] { "Component", "File" }) | ||
277 | .OrderBy(s => s) | ||
278 | .ToArray(); | ||
279 | } | ||
280 | } | ||
281 | } | ||
282 | |||
283 | private static string[] AssertFileComponentIds(int fileCount, string[] rows) | ||
284 | { | ||
285 | var componentRows = rows.Where(row => row.StartsWith("Component:")).ToArray(); | ||
286 | var fileRows = rows.Where(row => row.StartsWith("File:")).ToArray(); | ||
287 | |||
288 | Assert.Equal(componentRows.Length, fileRows.Length); | ||
289 | |||
290 | // Component id == Component keypath == File id | ||
291 | foreach (var componentRow in componentRows) | ||
292 | { | ||
293 | var columns = componentRow.Split(':', '\t'); | ||
294 | Assert.Equal(columns[1], columns[6]); | ||
295 | } | ||
296 | |||
297 | foreach (var fileRow in fileRows) | ||
298 | { | ||
299 | var columns = fileRow.Split(':', '\t'); | ||
300 | Assert.Equal(columns[1], columns[2]); | ||
301 | } | ||
302 | |||
303 | Assert.Equal(fileCount, componentRows.Length); | ||
304 | |||
305 | var files = fileRows.Select(row => row.Split('\t')[2]); | ||
306 | var lfns = files.Select(name => name.Split('|')); | ||
307 | |||
308 | return fileRows | ||
309 | .Select(row => row.Split('\t')[2]) | ||
310 | .Select(GetLFN) | ||
311 | .OrderBy(name => name).ToArray(); | ||
312 | |||
313 | static string GetLFN(string possibleSfnLfnPair) | ||
314 | { | ||
315 | var parts = possibleSfnLfnPair.Split('|'); | ||
316 | return parts[parts.Length - 1]; | ||
317 | } | ||
318 | } | ||
319 | } | ||
320 | } | ||
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/BadAuthoring.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/BadAuthoring.wxs new file mode 100644 index 00000000..c8f25e1d --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/BadAuthoring.wxs | |||
@@ -0,0 +1,7 @@ | |||
1 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"> | ||
2 | <Package Name="MsiPackage" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a"> | ||
3 | <ComponentGroup Id="Files"> | ||
4 | <Files /> | ||
5 | </ComponentGroup> | ||
6 | </Package> | ||
7 | </Wix> | ||
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/BadDirectory.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/BadDirectory.wxs new file mode 100644 index 00000000..88cbb3eb --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/BadDirectory.wxs | |||
@@ -0,0 +1,14 @@ | |||
1 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"> | ||
2 | <Package Name="MsiPackage" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a"> | ||
3 | <MajorUpgrade DowngradeErrorMessage="Downgrade error message." /> | ||
4 | |||
5 | <Feature Id="ProductFeature"> | ||
6 | <ComponentGroupRef Id="Files" /> | ||
7 | </Feature> | ||
8 | |||
9 | <ComponentGroup Id="Files" Directory="ProgramFilesFolder" Subdirectory="MsiPackage" Source="$(sys.SOURCEFILEDIR)files2"> | ||
10 | <Files Include="MissingDirectory\**" /> | ||
11 | <Files Include="ThisDirectoryIsAlsoMissing\**" /> | ||
12 | </ComponentGroup> | ||
13 | </Package> | ||
14 | </Wix> | ||
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/BindPaths.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/BindPaths.wxs new file mode 100644 index 00000000..b0495125 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/BindPaths.wxs | |||
@@ -0,0 +1,16 @@ | |||
1 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"> | ||
2 | <Package Name="HarvestedFiles" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a"> | ||
3 | <MajorUpgrade DowngradeErrorMessage="Downgrade error message." /> | ||
4 | |||
5 | <Feature Id="ProductFeature"> | ||
6 | <ComponentGroupRef Id="Files" /> | ||
7 | </Feature> | ||
8 | |||
9 | <ComponentGroup Id="Files" Directory="ProgramFilesFolder" Subdirectory="HarvestedFiles"> | ||
10 | <Files Include="!(bindpath.ToBeHarvested)\**"> | ||
11 | <Exclude Files="!(bindpath.ToBeHarvested)\notatest.txt" /> | ||
12 | <Exclude Files="**\pleasedontincludeme.dat" /> | ||
13 | </Files> | ||
14 | </ComponentGroup> | ||
15 | </Package> | ||
16 | </Wix> | ||
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/ComponentGroup.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/ComponentGroup.wxs new file mode 100644 index 00000000..963f40a5 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/ComponentGroup.wxs | |||
@@ -0,0 +1,16 @@ | |||
1 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"> | ||
2 | <Package Name="MsiPackage" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a"> | ||
3 | <MajorUpgrade DowngradeErrorMessage="Downgrade error message." /> | ||
4 | |||
5 | <Feature Id="ProductFeature"> | ||
6 | <ComponentGroupRef Id="Files" /> | ||
7 | </Feature> | ||
8 | |||
9 | <ComponentGroup Id="Files" Directory="ProgramFilesFolder" Subdirectory="MsiPackage" Source="$(sys.SOURCEFILEDIR)files2"> | ||
10 | <Files Include="**"> | ||
11 | <Exclude Files="notatest.txt" /> | ||
12 | <Exclude Files="files2_sub2\pleasedontincludeme.dat" /> | ||
13 | </Files> | ||
14 | </ComponentGroup> | ||
15 | </Package> | ||
16 | </Wix> | ||
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/Directory.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/Directory.wxs new file mode 100644 index 00000000..362c5da1 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/Directory.wxs | |||
@@ -0,0 +1,20 @@ | |||
1 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"> | ||
2 | <Package Name="MsiPackage" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a"> | ||
3 | <MajorUpgrade DowngradeErrorMessage="Downgrade error message." /> | ||
4 | |||
5 | <StandardDirectory Id="ProgramFilesFolder"> | ||
6 | <Directory Id="INSTALLFOLDER" Name="MsiPackage" FileSource="$(sys.SOURCEFILEDIR)"> | ||
7 | <!-- Relies on default-feature feature to include naked files in package. --> | ||
8 | <Files Include="files1\**"> | ||
9 | <Exclude Files="files1\test1.txt" /> | ||
10 | </Files> | ||
11 | |||
12 | <Files Include="files2\**"> | ||
13 | <Exclude Files="**\*.Extension" /> | ||
14 | <Exclude Files="files2\notatest.txt" /> | ||
15 | <Exclude Files="files2\files2_sub2\**" /> | ||
16 | </Files> | ||
17 | </Directory> | ||
18 | </StandardDirectory> | ||
19 | </Package> | ||
20 | </Wix> | ||
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/DirectoryRef.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/DirectoryRef.wxs new file mode 100644 index 00000000..3e475ff9 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/DirectoryRef.wxs | |||
@@ -0,0 +1,21 @@ | |||
1 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"> | ||
2 | <Package Name="MsiPackage" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a"> | ||
3 | <MajorUpgrade DowngradeErrorMessage="Downgrade error message." /> | ||
4 | |||
5 | <DirectoryRef Id="INSTALLFOLDER"> | ||
6 | <!-- Relies on default-feature feature to include naked files in package. --> | ||
7 | <Files Include="files1\**"> | ||
8 | <Exclude Files="files1\files1_sub1\*" /> | ||
9 | </Files> | ||
10 | <Files Include="files2\**"> | ||
11 | <Exclude Files="$(sys.SOURCEFILEDIR)\files2\**.extension" /> | ||
12 | </Files> | ||
13 | </DirectoryRef> | ||
14 | </Package> | ||
15 | |||
16 | <Fragment> | ||
17 | <StandardDirectory Id="ProgramFilesFolder"> | ||
18 | <Directory Id="INSTALLFOLDER" Name="MsiPackage" /> | ||
19 | </StandardDirectory> | ||
20 | </Fragment> | ||
21 | </Wix> | ||
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/DuplicateFiles.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/DuplicateFiles.wxs new file mode 100644 index 00000000..8375e0ae --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/DuplicateFiles.wxs | |||
@@ -0,0 +1,23 @@ | |||
1 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"> | ||
2 | <Package Name="MsiPackage" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a"> | ||
3 | <MajorUpgrade DowngradeErrorMessage="Downgrade error message." /> | ||
4 | |||
5 | <Feature Id="ProductFeature"> | ||
6 | <ComponentGroupRef Id="FilesA" /> | ||
7 | <ComponentGroupRef Id="FilesB" /> | ||
8 | </Feature> | ||
9 | |||
10 | </Package> | ||
11 | |||
12 | <Fragment> | ||
13 | <ComponentGroup Id="FilesA" Directory="ProgramFilesFolder" Subdirectory="MsiPackage"> | ||
14 | <Files Include="files1\**" /> | ||
15 | </ComponentGroup> | ||
16 | </Fragment> | ||
17 | |||
18 | <Fragment> | ||
19 | <ComponentGroup Id="FilesB" Directory="ProgramFilesFolder" Subdirectory="MsiPackage"> | ||
20 | <Files Include="files1\**" /> | ||
21 | </ComponentGroup> | ||
22 | </Fragment> | ||
23 | </Wix> | ||
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/Feature.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/Feature.wxs new file mode 100644 index 00000000..05152d72 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/Feature.wxs | |||
@@ -0,0 +1,25 @@ | |||
1 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"> | ||
2 | <Package Name="MsiPackage" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a"> | ||
3 | <MajorUpgrade DowngradeErrorMessage="Downgrade error message." /> | ||
4 | |||
5 | <Feature Id="ProductFeature"> | ||
6 | <Files | ||
7 | Directory="ProgramFiles6432Folder" | ||
8 | Subdirectory="Example Product" | ||
9 | Include="files1\*"> | ||
10 | <Exclude Files="files1\test1.txt" /> | ||
11 | </Files> | ||
12 | |||
13 | <!-- | ||
14 | `$(sys.SOURCEFILEDIR)` is equivalent to the above (i.e., the default), | ||
15 | but this validates that preprocessor variables are happy here. | ||
16 | --> | ||
17 | <Files | ||
18 | Directory="ProgramFiles6432Folder" | ||
19 | Subdirectory="Example Product\Assets" | ||
20 | Include="$(sys.SOURCEFILEDIR)\files2\*"> | ||
21 | <Exclude Files="$(sys.SOURCEFILEDIR)\files2\notatest.txt" /> | ||
22 | </Files> | ||
23 | </Feature> | ||
24 | </Package> | ||
25 | </Wix> | ||
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/FeatureGroup.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/FeatureGroup.wxs new file mode 100644 index 00000000..5c1b2165 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/FeatureGroup.wxs | |||
@@ -0,0 +1,25 @@ | |||
1 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"> | ||
2 | <Package Name="MsiPackage" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a"> | ||
3 | <MajorUpgrade DowngradeErrorMessage="Downgrade error message." /> | ||
4 | |||
5 | <Feature Id="ProductFeature"> | ||
6 | <FeatureGroupRef Id="ProductFeatureGroup" /> | ||
7 | </Feature> | ||
8 | </Package> | ||
9 | |||
10 | <Fragment> | ||
11 | <StandardDirectory Id="ProgramFilesFolder"> | ||
12 | <Directory Id="INSTALLFOLDER" Name="MsiPackage" /> | ||
13 | </StandardDirectory> | ||
14 | </Fragment> | ||
15 | |||
16 | <Fragment> | ||
17 | <FeatureGroup Id="ProductFeatureGroup"> | ||
18 | <Files Directory="INSTALLFOLDER" Include="files1\**"> | ||
19 | <Exclude Files="files1\files1_sub1\**" /> | ||
20 | </Files> | ||
21 | |||
22 | <Files Directory="INSTALLFOLDER" Subdirectory="assets" Include="files2\**" /> | ||
23 | </FeatureGroup> | ||
24 | </Fragment> | ||
25 | </Wix> | ||
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/FeatureRef.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/FeatureRef.wxs new file mode 100644 index 00000000..86a90e29 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/FeatureRef.wxs | |||
@@ -0,0 +1,23 @@ | |||
1 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"> | ||
2 | <Package Name="MsiPackage" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a"> | ||
3 | <MajorUpgrade DowngradeErrorMessage="Downgrade error message." /> | ||
4 | |||
5 | <FeatureRef Id="ProductFeature"> | ||
6 | <Files Directory="INSTALLFOLDER" Include="files1\**"> | ||
7 | <Exclude Files="files1\files1_sub1\**" /> | ||
8 | </Files> | ||
9 | |||
10 | <Files Directory="INSTALLFOLDER" Subdirectory="assets" Include="files2\**" /> | ||
11 | </FeatureRef> | ||
12 | </Package> | ||
13 | |||
14 | <Fragment> | ||
15 | <StandardDirectory Id="ProgramFilesFolder"> | ||
16 | <Directory Id="INSTALLFOLDER" Name="MsiPackage" /> | ||
17 | </StandardDirectory> | ||
18 | </Fragment> | ||
19 | |||
20 | <Fragment> | ||
21 | <Feature Id="ProductFeature" /> | ||
22 | </Fragment> | ||
23 | </Wix> | ||
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/Fragment.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/Fragment.wxs new file mode 100644 index 00000000..6f5053d2 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/Fragment.wxs | |||
@@ -0,0 +1,24 @@ | |||
1 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"> | ||
2 | <Package Name="MsiPackage" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a"> | ||
3 | <MajorUpgrade DowngradeErrorMessage="Downgrade error message." /> | ||
4 | |||
5 | <FeatureGroupRef Id="FeatureGroup1" /> | ||
6 | <FeatureGroupRef Id="FeatureGroup2" /> | ||
7 | </Package> | ||
8 | |||
9 | <Fragment> | ||
10 | <StandardDirectory Id="ProgramFilesFolder"> | ||
11 | <Directory Id="INSTALLFOLDER" Name="MsiPackage" /> | ||
12 | </StandardDirectory> | ||
13 | </Fragment> | ||
14 | |||
15 | <Fragment> | ||
16 | <FeatureGroup Id="FeatureGroup1" /> | ||
17 | <Files Directory="ProgramFilesFolder" Subdirectory="MsiPackage" Include="files1\*" /> | ||
18 | </Fragment> | ||
19 | |||
20 | <Fragment> | ||
21 | <FeatureGroup Id="FeatureGroup2" /> | ||
22 | <Files Directory="ProgramFilesFolder" Subdirectory="MsiPackage" Include="files2\*" /> | ||
23 | </Fragment> | ||
24 | </Wix> | ||
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/Module.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/Module.wxs new file mode 100644 index 00000000..7034aa9d --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/Module.wxs | |||
@@ -0,0 +1,6 @@ | |||
1 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"> | ||
2 | <Module Id="MergeModule" Guid="e535b765-1019-4a4f-b3ea-ae28870e6d73" Language="1033" Version="1.0.0.0"> | ||
3 | <Files Directory="ProgramFilesFolder" Subdirectory="MergeModule" Include="files1\*" /> | ||
4 | <Files Directory="ProgramFilesFolder" Subdirectory="MergeModule" Include="files2\*" /> | ||
5 | </Module> | ||
6 | </Wix> | ||
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/PackageFiveLiner.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/PackageFiveLiner.wxs new file mode 100644 index 00000000..7bf0845c --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/PackageFiveLiner.wxs | |||
@@ -0,0 +1,5 @@ | |||
1 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"> | ||
2 | <Package Name="MsiPackage" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a"> | ||
3 | <Files Include="files2\**" /> | ||
4 | </Package> | ||
5 | </Wix> | ||
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/PackageWithoutDefaultFeature.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/PackageWithoutDefaultFeature.wxs new file mode 100644 index 00000000..3157202a --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/PackageWithoutDefaultFeature.wxs | |||
@@ -0,0 +1,15 @@ | |||
1 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"> | ||
2 | <Package Name="MsiPackage" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a"> | ||
3 | <MajorUpgrade DowngradeErrorMessage="Downgrade error message." /> | ||
4 | |||
5 | <Files Directory="ProgramFilesFolder" Subdirectory="MsiPackage" Include="files1\**" /> | ||
6 | |||
7 | <Feature Id="ProductFeature"> | ||
8 | <ComponentGroupRef Id="Files" /> | ||
9 | </Feature> | ||
10 | |||
11 | <ComponentGroup Id="Files" Directory="ProgramFilesFolder" Subdirectory="MsiPackage"> | ||
12 | <Files Directory="ProgramFilesFolder" Subdirectory="MsiPackage" Include="files2\*" /> | ||
13 | </ComponentGroup> | ||
14 | </Package> | ||
15 | </Wix> | ||
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/StandardDirectory.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/StandardDirectory.wxs new file mode 100644 index 00000000..1838ed66 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/StandardDirectory.wxs | |||
@@ -0,0 +1,11 @@ | |||
1 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"> | ||
2 | <Package Name="MsiPackage" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a"> | ||
3 | <MajorUpgrade DowngradeErrorMessage="Downgrade error message." /> | ||
4 | |||
5 | <StandardDirectory Id="ProgramFiles6432Folder"> | ||
6 | <!-- Relies on default-feature feature to include naked files in package. --> | ||
7 | <Files Subdirectory="MsiPackage" Include="files1\**" /> | ||
8 | <Files Subdirectory="MsiPackage" Include="files2\**" /> | ||
9 | </StandardDirectory> | ||
10 | </Package> | ||
11 | </Wix> | ||
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/ZeroFiles.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/ZeroFiles.wxs new file mode 100644 index 00000000..e733622f --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/ZeroFiles.wxs | |||
@@ -0,0 +1,15 @@ | |||
1 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"> | ||
2 | <Package Name="MsiPackage" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a"> | ||
3 | <MajorUpgrade DowngradeErrorMessage="Downgrade error message." /> | ||
4 | |||
5 | <Feature Id="ProductFeature"> | ||
6 | <ComponentGroupRef Id="Files" /> | ||
7 | </Feature> | ||
8 | |||
9 | <ComponentGroup Id="Files" Directory="ProgramFilesFolder" Subdirectory="MsiPackage" Source="$(sys.SOURCEFILEDIR)files2"> | ||
10 | <Files Include="**"> | ||
11 | <Exclude Files="**" /> | ||
12 | </Files> | ||
13 | </ComponentGroup> | ||
14 | </Package> | ||
15 | </Wix> | ||
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/files1/files1_sub1/files1_sub2/test120.txt b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/files1/files1_sub1/files1_sub2/test120.txt new file mode 100644 index 00000000..d32727e0 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/files1/files1_sub1/files1_sub2/test120.txt | |||
@@ -0,0 +1 @@ | |||
This is test.txt. | |||
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/files1/files1_sub1/test10.txt b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/files1/files1_sub1/test10.txt new file mode 100644 index 00000000..d32727e0 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/files1/files1_sub1/test10.txt | |||
@@ -0,0 +1 @@ | |||
This is test.txt. | |||
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/files1/test1.txt b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/files1/test1.txt new file mode 100644 index 00000000..d32727e0 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/files1/test1.txt | |||
@@ -0,0 +1 @@ | |||
This is test.txt. | |||
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/files1/test2.txt b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/files1/test2.txt new file mode 100644 index 00000000..d32727e0 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/files1/test2.txt | |||
@@ -0,0 +1 @@ | |||
This is test.txt. | |||
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/files2/files2_sub2/pleasedontincludeme.dat b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/files2/files2_sub2/pleasedontincludeme.dat new file mode 100644 index 00000000..d32727e0 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/files2/files2_sub2/pleasedontincludeme.dat | |||
@@ -0,0 +1 @@ | |||
This is test.txt. | |||
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/files2/files2_sub2/test20.txt b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/files2/files2_sub2/test20.txt new file mode 100644 index 00000000..d32727e0 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/files2/files2_sub2/test20.txt | |||
@@ -0,0 +1 @@ | |||
This is test.txt. | |||
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/files2/files2_sub2/test21.txt b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/files2/files2_sub2/test21.txt new file mode 100644 index 00000000..d32727e0 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/files2/files2_sub2/test21.txt | |||
@@ -0,0 +1 @@ | |||
This is test.txt. | |||
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/files2/files2_sub3/FileName.Extension b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/files2/files2_sub3/FileName.Extension new file mode 100644 index 00000000..6f2d4e96 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/files2/files2_sub3/FileName.Extension | |||
@@ -0,0 +1,14 @@ | |||
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 WixToolsetTest.CoreIntegration.TestData.HarvestFiles.files2.files2_sub3 | ||
4 | { | ||
5 | using System; | ||
6 | using System.Collections.Generic; | ||
7 | using System.Linq; | ||
8 | using System.Text; | ||
9 | using System.Threading.Tasks; | ||
10 | |||
11 | internal class FileName | ||
12 | { | ||
13 | } | ||
14 | } | ||
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/files2/notatest.txt b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/files2/notatest.txt new file mode 100644 index 00000000..d32727e0 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/files2/notatest.txt | |||
@@ -0,0 +1 @@ | |||
This is test.txt. | |||
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/files2/test3.txt b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/files2/test3.txt new file mode 100644 index 00000000..d32727e0 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/files2/test3.txt | |||
@@ -0,0 +1 @@ | |||
This is test.txt. | |||
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/files2/test4.txt b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/files2/test4.txt new file mode 100644 index 00000000..d32727e0 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/HarvestFiles/files2/test4.txt | |||
@@ -0,0 +1 @@ | |||
This is test.txt. | |||