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 /src | |
| 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.
Diffstat (limited to 'src')
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. | |||
