From d0b04bd4da5a6d0d594a86c92da5f58a1c166eab Mon Sep 17 00:00:00 2001 From: Bob Arnson Date: Sun, 2 Oct 2022 10:05:00 -0400 Subject: [PATCH 1/2] Implement default-feature feature. See WIP at https://github.com/wixtoolset/issues/issues/7581. --- .../AssignDefaultFeatureCommand.cs | 70 ++++++++++++++++++ src/wix/WixToolset.Core/Compiler.cs | 4 +- src/wix/WixToolset.Core/Compiler_Package.cs | 6 ++ src/wix/WixToolset.Core/Linker.cs | 21 ++++-- .../FeatureFixture.cs | 71 +++++++++++++++++++ .../Feature/PackageBadDefaultFeature.wxs | 27 +++++++ .../Feature/PackageDefaultFeature.wxs | 46 ++++++++++++ 7 files changed, 239 insertions(+), 6 deletions(-) create mode 100644 src/wix/WixToolset.Core/AssignDefaultFeatureCommand.cs create mode 100644 src/wix/test/WixToolsetTest.CoreIntegration/TestData/Feature/PackageBadDefaultFeature.wxs create mode 100644 src/wix/test/WixToolsetTest.CoreIntegration/TestData/Feature/PackageDefaultFeature.wxs diff --git a/src/wix/WixToolset.Core/AssignDefaultFeatureCommand.cs b/src/wix/WixToolset.Core/AssignDefaultFeatureCommand.cs new file mode 100644 index 000000000..87ab14645 --- /dev/null +++ b/src/wix/WixToolset.Core/AssignDefaultFeatureCommand.cs @@ -0,0 +1,70 @@ +// 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. + +namespace WixToolset.Core +{ + using System.Collections.Generic; + using System.Linq; + using WixToolset.Core.Link; + using WixToolset.Data; + using WixToolset.Data.Symbols; + using WixToolset.Extensibility.Services; + using static System.Collections.Specialized.BitVector32; + + internal class AssignDefaultFeatureCommand + { + private const string DefaultFeatureName = "WixDefaultFeature"; + + public AssignDefaultFeatureCommand(IMessaging messaging, IntermediateSection entrySection, IEnumerable sections, HashSet referencedComponents, Link.ConnectToFeatureCollection componentsToFeatures) + { + this.Messaging = messaging; + this.EntrySection = entrySection; + this.Sections = sections; + this.ReferencedComponents = referencedComponents; + this.ComponentsToFeatures = componentsToFeatures; + } + + public IMessaging Messaging { get; } + + public IntermediateSection EntrySection { get; } + + public IEnumerable Sections { get; } + + public HashSet ReferencedComponents { get; } + + public ConnectToFeatureCollection ComponentsToFeatures { get; } + + public void Execute() + { + var assignedComponents = false; + + foreach (var section in this.Sections) + { + foreach (var component in section.Symbols.OfType().ToList()) + { + if (!this.ReferencedComponents.Contains(component.Id.Id)) + { + assignedComponents = true; + + this.ComponentsToFeatures.Add(new ConnectToFeature(section, component.Id.Id, DefaultFeatureName, explicitPrimaryFeature: true)); + + section.AddSymbol(new FeatureComponentsSymbol + { + FeatureRef = DefaultFeatureName, + ComponentRef = component.Id.Id, + }); + } + } + } + + if (assignedComponents) + { + this.EntrySection.AddSymbol(new FeatureSymbol(null, new Identifier(AccessModifier.Global, DefaultFeatureName)) + { + Level = 1, + Display = 0, + InstallDefault = FeatureInstallDefault.Local, + }); + } + } + } +} diff --git a/src/wix/WixToolset.Core/Compiler.cs b/src/wix/WixToolset.Core/Compiler.cs index 7541969b7..25dd75e67 100644 --- a/src/wix/WixToolset.Core/Compiler.cs +++ b/src/wix/WixToolset.Core/Compiler.cs @@ -2681,7 +2681,7 @@ private void ParseComponentGroupElement(XElement node, ComplexReferenceParentTyp /// Optional language of parent (only useful for Modules). private void ParseComponentGroupRefElement(XElement node, ComplexReferenceParentType parentType, string parentId, string parentLanguage) { - Debug.Assert(ComplexReferenceParentType.ComponentGroup == parentType || ComplexReferenceParentType.FeatureGroup == parentType || ComplexReferenceParentType.Feature == parentType || ComplexReferenceParentType.Module == parentType); + Debug.Assert(ComplexReferenceParentType.ComponentGroup == parentType || ComplexReferenceParentType.FeatureGroup == parentType || ComplexReferenceParentType.Feature == parentType || ComplexReferenceParentType.Module == parentType || ComplexReferenceParentType.Product == parentType); var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); string id = null; @@ -2730,7 +2730,7 @@ private void ParseComponentGroupRefElement(XElement node, ComplexReferenceParent /// Optional language of parent (only useful for Modules). private void ParseComponentRefElement(XElement node, ComplexReferenceParentType parentType, string parentId, string parentLanguage) { - Debug.Assert(ComplexReferenceParentType.FeatureGroup == parentType || ComplexReferenceParentType.ComponentGroup == parentType || ComplexReferenceParentType.Feature == parentType || ComplexReferenceParentType.Module == parentType); + Debug.Assert(ComplexReferenceParentType.FeatureGroup == parentType || ComplexReferenceParentType.ComponentGroup == parentType || ComplexReferenceParentType.Feature == parentType || ComplexReferenceParentType.Module == parentType || ComplexReferenceParentType.Product == parentType); var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); string id = null; diff --git a/src/wix/WixToolset.Core/Compiler_Package.cs b/src/wix/WixToolset.Core/Compiler_Package.cs index c8a1ae595..2fdbe6f08 100644 --- a/src/wix/WixToolset.Core/Compiler_Package.cs +++ b/src/wix/WixToolset.Core/Compiler_Package.cs @@ -242,9 +242,15 @@ private void ParsePackageElement(XElement node) case "Component": this.ParseComponentElement(child, ComplexReferenceParentType.Unknown, null, null, CompilerConstants.IntegerNotSet, null, null); break; + case "ComponentRef": + this.ParseComponentRefElement(child, ComplexReferenceParentType.Product, null, null); + break; case "ComponentGroup": this.ParseComponentGroupElement(child, ComplexReferenceParentType.Unknown, null); break; + case "ComponentGroupRef": + this.ParseComponentGroupRefElement(child, ComplexReferenceParentType.Product, null, null); + break; case "CustomAction": this.ParseCustomActionElement(child); break; diff --git a/src/wix/WixToolset.Core/Linker.cs b/src/wix/WixToolset.Core/Linker.cs index a3d990392..21cc67347 100644 --- a/src/wix/WixToolset.Core/Linker.cs +++ b/src/wix/WixToolset.Core/Linker.cs @@ -150,14 +150,23 @@ public Intermediate Link(ILinkContext context) return null; } - // Display an error message for Components that were not referenced by a Feature. - foreach (var component in sections.SelectMany(s => s.Symbols.Where(y => y.Definition.Type == SymbolDefinitionType.Component))) + // If there are authored features, error for any referenced components that aren't assigned to a feature. + // If not, create a default feature and assign the components to it. + if (sections.SelectMany(s => s.Symbols).OfType().Any()) { - if (!referencedComponents.Contains(component.Id.Id)) + foreach (var component in sections.SelectMany(s => s.Symbols.Where(y => y.Definition.Type == SymbolDefinitionType.Component))) { - this.Messaging.Write(ErrorMessages.OrphanedComponent(component.SourceLineNumbers, component.Id.Id)); + if (!referencedComponents.Contains(component.Id.Id)) + { + this.Messaging.Write(ErrorMessages.OrphanedComponent(component.SourceLineNumbers, component.Id.Id)); + } } } + else + { + var command = new AssignDefaultFeatureCommand(this.Messaging, find.EntrySection, sections, referencedComponents, componentsToFeatures); + command.Execute(); + } // Report duplicates that would ultimately end up being primary key collisions. { @@ -532,6 +541,10 @@ private void ProcessComplexReferences(IntermediateSection resolvedSection, IEnum featuresToFeatures.Add(new ConnectToFeature(section, wixComplexReferenceRow.Child, null, wixComplexReferenceRow.IsPrimary)); break; + case ComplexReferenceChildType.Component: + case ComplexReferenceChildType.ComponentGroup: + break; + default: throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, "Unexpected complex reference child type: {0}", Enum.GetName(typeof(ComplexReferenceChildType), wixComplexReferenceRow.ChildType))); } diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/FeatureFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/FeatureFixture.cs index c6da19eb4..6121c3fcd 100644 --- a/src/wix/test/WixToolsetTest.CoreIntegration/FeatureFixture.cs +++ b/src/wix/test/WixToolsetTest.CoreIntegration/FeatureFixture.cs @@ -44,6 +44,77 @@ public void CanDetectMissingFeatureComponentMapping() } } + [Fact] + public void CanAutomaticallyCreateDefaultFeature() + { + var folder = TestData.Get(@"TestData"); + + using (var fs = new DisposableFileSystem()) + { + var baseFolder = fs.GetFolder(); + var intermediateFolder = Path.Combine(baseFolder, "obj"); + var msiPath = Path.Combine(baseFolder, @"bin\test.msi"); + + var result = WixRunner.Execute(new[] + { + "build", + Path.Combine(folder, "Feature", "PackageDefaultFeature.wxs"), + "-bindpath", Path.Combine(folder, "SingleFile", "data"), + "-intermediateFolder", intermediateFolder, + "-o", msiPath + }); + + Assert.Empty(result.Messages); + + Assert.True(File.Exists(msiPath)); + var results = Query.QueryDatabase(msiPath, new[] { "Feature", "FeatureComponents", "Shortcut" }); + WixAssert.CompareLineByLine(new[] + { + "Feature:WixDefaultFeature\t\t\t\t0\t1\t\t0", + "FeatureComponents:WixDefaultFeature\tAnotherComponentInAFragment", + "FeatureComponents:WixDefaultFeature\tComponentInAFragment", + "FeatureComponents:WixDefaultFeature\tfil6J6CHYPBCOMYclNjnqn0afimmzM", + "FeatureComponents:WixDefaultFeature\tfilcV1yrx0x8wJWj4qMzcH21jwkPko", + "FeatureComponents:WixDefaultFeature\tfilj.cb0sFWqIPHPFSKJSEEaPDuAQ4", + "Shortcut:AdvertisedShortcut\tINSTALLFOLDER\tShortcut\tAnotherComponentInAFragment\tWixDefaultFeature\t\t\t\t\t\t\t\t\t\t\t", + }, results); + } + } + + [Fact] + public void WontAutomaticallyCreateDefaultFeature() + { + var folder = TestData.Get(@"TestData"); + + using (var fs = new DisposableFileSystem()) + { + var baseFolder = fs.GetFolder(); + var intermediateFolder = Path.Combine(baseFolder, "obj"); + var msiPath = Path.Combine(baseFolder, @"bin\test.msi"); + + var result = WixRunner.Execute(new[] + { + "build", + Path.Combine(folder, "Feature", "PackageBadDefaultFeature.wxs"), + "-bindpath", Path.Combine(folder, "SingleFile", "data"), + "-intermediateFolder", intermediateFolder, + "-o", msiPath + }); + + var messages = result.Messages.Select(m => m.ToString()).ToList(); + messages.Sort(); + + WixAssert.CompareLineByLine(new[] + { + "Found orphaned Component 'fil6J6CHYPBCOMYclNjnqn0afimmzM'. If this is a Package, every Component must have at least one parent Feature. To include a Component in a Module, you must include it directly as a Component element of the Module element or indirectly via ComponentRef, ComponentGroup, or ComponentGroupRef elements.", + "Found orphaned Component 'filcV1yrx0x8wJWj4qMzcH21jwkPko'. If this is a Package, every Component must have at least one parent Feature. To include a Component in a Module, you must include it directly as a Component element of the Module element or indirectly via ComponentRef, ComponentGroup, or ComponentGroupRef elements.", + "Found orphaned Component 'filj.cb0sFWqIPHPFSKJSEEaPDuAQ4'. If this is a Package, every Component must have at least one parent Feature. To include a Component in a Module, you must include it directly as a Component element of the Module element or indirectly via ComponentRef, ComponentGroup, or ComponentGroupRef elements.", + }, messages.ToArray()); + + Assert.Equal(267, result.ExitCode); + } + } + [Fact] public void CannotBuildMsiWithTooLargeFeatureDepth() { diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/Feature/PackageBadDefaultFeature.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/Feature/PackageBadDefaultFeature.wxs new file mode 100644 index 000000000..0f8a078af --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/Feature/PackageBadDefaultFeature.wxs @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/Feature/PackageDefaultFeature.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/Feature/PackageDefaultFeature.wxs new file mode 100644 index 000000000..a855f26f9 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/Feature/PackageDefaultFeature.wxs @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 339070e20e592b8a6822daa24b599d1785ebd474 Mon Sep 17 00:00:00 2001 From: Bob Arnson Date: Sun, 10 Sep 2023 22:34:56 -0400 Subject: [PATCH 2/2] Support naked files. Implements https://github.com/wixtoolset/issues/issues/7696. `File` elements can appear where `Component` elements do in WiX v4. The compiler generates an appropriate per-file component. Naked files under `Directory`, `DirectoryRef`, `Fragment`, `StandardDirectory`, or `Package` elements are included in a package via the [default-feature feature](https://github.com/wixtoolset/issues/issues/7581). Naked files appearing under `ComponentGroup`, `Feature`, `FeatureRef`, and `FeatureGroup` generate the component and the reference to the parent element. --- src/api/wix/WixToolset.Data/ErrorMessages.cs | 5 + .../AssignDefaultFeatureCommand.cs | 1 - src/wix/WixToolset.Core/Compiler.cs | 342 ++++++++++++++---- src/wix/WixToolset.Core/Compiler_Module.cs | 3 + src/wix/WixToolset.Core/Compiler_Package.cs | 3 + src/wix/WixToolset.Core/Linker.cs | 2 +- .../NakedFileFixture.cs | 240 ++++++++++++ .../TestData/NakedFile/BadAttributes.wxs | 11 + .../TestData/NakedFile/ComponentGroup.wxs | 14 + .../TestData/NakedFile/Condition.wxs | 10 + .../TestData/NakedFile/Directory.wxs | 13 + .../TestData/NakedFile/DirectoryRef.wxs | 17 + .../TestData/NakedFile/Feature.wxs | 10 + .../TestData/NakedFile/FeatureGroup.wxs | 22 ++ .../TestData/NakedFile/FeatureRef.wxs | 20 + .../TestData/NakedFile/Fragment.wxs | 24 ++ .../TestData/NakedFile/Module.wxs | 6 + .../TestData/NakedFile/ModuleFragment.wxs | 16 + .../PackageWithoutDefaultFeature.wxs | 17 + .../TestData/NakedFile/StandardDirectory.wxs | 11 + .../NakedFile/WixlibComponentGroup.wxs | 14 + .../NakedFile/WixlibComponentGroupPackage.wxs | 6 + .../TestData/NakedFile/test.txt | 1 + .../TestData/SingleFile/PackageComponents.wxs | 5 +- 24 files changed, 732 insertions(+), 81 deletions(-) create mode 100644 src/wix/test/WixToolsetTest.CoreIntegration/NakedFileFixture.cs create mode 100644 src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/BadAttributes.wxs create mode 100644 src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/ComponentGroup.wxs create mode 100644 src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/Condition.wxs create mode 100644 src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/Directory.wxs create mode 100644 src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/DirectoryRef.wxs create mode 100644 src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/Feature.wxs create mode 100644 src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/FeatureGroup.wxs create mode 100644 src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/FeatureRef.wxs create mode 100644 src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/Fragment.wxs create mode 100644 src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/Module.wxs create mode 100644 src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/ModuleFragment.wxs create mode 100644 src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/PackageWithoutDefaultFeature.wxs create mode 100644 src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/StandardDirectory.wxs create mode 100644 src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/WixlibComponentGroup.wxs create mode 100644 src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/WixlibComponentGroupPackage.wxs create mode 100644 src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/test.txt diff --git a/src/api/wix/WixToolset.Data/ErrorMessages.cs b/src/api/wix/WixToolset.Data/ErrorMessages.cs index bc63247e0..eabb675c6 100644 --- a/src/api/wix/WixToolset.Data/ErrorMessages.cs +++ b/src/api/wix/WixToolset.Data/ErrorMessages.cs @@ -2271,6 +2271,11 @@ public static Message IllegalInnerText(SourceLineNumber sourceLineNumbers, strin return Message(sourceLineNumbers, Ids.IllegalInnerText, "The {0} element contains inner text which is obsolete. Use the {1} attribute instead.", elementName, attributeName); } + public static Message IllegalAttributeWhenNested(SourceLineNumber sourceLineNumbers, string attributeName) + { + return Message(sourceLineNumbers, Ids.IllegalAttributeWhenNested, "The File element contains an attribute '{0}' that cannot be used in a File element that is a child of a Component element.", attributeName); + } + private static Message Message(SourceLineNumber sourceLineNumber, Ids id, string format, params object[] args) { return new Message(sourceLineNumber, MessageLevel.Error, (int)id, format, args); diff --git a/src/wix/WixToolset.Core/AssignDefaultFeatureCommand.cs b/src/wix/WixToolset.Core/AssignDefaultFeatureCommand.cs index 87ab14645..549e8a4ad 100644 --- a/src/wix/WixToolset.Core/AssignDefaultFeatureCommand.cs +++ b/src/wix/WixToolset.Core/AssignDefaultFeatureCommand.cs @@ -8,7 +8,6 @@ namespace WixToolset.Core using WixToolset.Data; using WixToolset.Data.Symbols; using WixToolset.Extensibility.Services; - using static System.Collections.Specialized.BitVector32; internal class AssignDefaultFeatureCommand { diff --git a/src/wix/WixToolset.Core/Compiler.cs b/src/wix/WixToolset.Core/Compiler.cs index 25dd75e67..ff71bdfd9 100644 --- a/src/wix/WixToolset.Core/Compiler.cs +++ b/src/wix/WixToolset.Core/Compiler.cs @@ -2427,6 +2427,7 @@ private void ParseComponentElement(XElement node, ComplexReferenceParentType par keyBit = ComponentKeyPathType.File; keyPossible = possibleKeyPath.Id; break; + case PossibleKeyPathType.Directory: keyBit = ComponentKeyPathType.Directory; keyPossible = String.Empty; @@ -2581,8 +2582,8 @@ private void ParseComponentElement(XElement node, ComplexReferenceParentType par /// Parses a component group element. /// /// Element to parse. - /// - /// + /// Type of complex reference parent. Will be Unknown if there is no parent. + /// Optional identifier for primary parent. private void ParseComponentGroupElement(XElement node, ComplexReferenceParentType parentType, string parentId) { var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); @@ -2649,6 +2650,9 @@ private void ParseComponentGroupElement(XElement node, ComplexReferenceParentTyp case "Component": this.ParseComponentElement(child, ComplexReferenceParentType.ComponentGroup, id.Id, null, CompilerConstants.IntegerNotSet, directoryId, source); break; + case "File": + this.ParseNakedFileElement(child, ComplexReferenceParentType.ComponentGroup, id.Id, directoryId, source); + break; default: this.Core.UnexpectedElement(node, child); break; @@ -3867,6 +3871,9 @@ private void ParseDirectoryElement(XElement node, string parentId, int diskId, s case "Directory": this.ParseDirectoryElement(child, id.Id, diskId, fileSource); break; + case "File": + this.ParseNakedFileElement(child, ComplexReferenceParentType.Unknown, null, id.Id, fileSource); + break; case "Merge": this.ParseMergeElement(child, id.Id, diskId); break; @@ -3979,6 +3986,9 @@ private void ParseDirectoryRefElement(XElement node) case "Directory": this.ParseDirectoryElement(child, id, diskId, fileSource); break; + case "File": + this.ParseNakedFileElement(child, ComplexReferenceParentType.Unknown, null, id, fileSource); + break; case "Merge": this.ParseMergeElement(child, id, diskId); break; @@ -4416,6 +4426,9 @@ private void ParseFeatureElement(XElement node, ComplexReferenceParentType paren case "FeatureRef": this.ParseFeatureRefElement(child, ComplexReferenceParentType.Feature, id.Id); break; + case "File": + this.ParseNakedFileElement(child, ComplexReferenceParentType.Feature, id.Id, null, null); + break; case "Level": this.ParseLevelElement(child, id.Id); break; @@ -4556,6 +4569,9 @@ private void ParseFeatureRefElement(XElement node, ComplexReferenceParentType pa case "FeatureRef": this.ParseFeatureRefElement(child, ComplexReferenceParentType.Feature, id); break; + case "File": + this.ParseNakedFileElement(child, ComplexReferenceParentType.Feature, id, null, null); + break; case "MergeRef": this.ParseMergeRefElement(child, ComplexReferenceParentType.Feature, id); break; @@ -4641,6 +4657,9 @@ private void ParseFeatureGroupElement(XElement node, ComplexReferenceParentType case "FeatureRef": this.ParseFeatureRefElement(child, ComplexReferenceParentType.FeatureGroup, id.Id); break; + case "File": + this.ParseNakedFileElement(child, ComplexReferenceParentType.FeatureGroup, id.Id, null, null); + break; case "MergeRef": this.ParseMergeRefElement(child, ComplexReferenceParentType.FeatureGroup, id.Id); break; @@ -5024,9 +5043,8 @@ private void ParseExtensionElement(XElement node, string componentId, YesNoType } } - /// - /// Parses a file element. + /// Parses a File element's attributes. /// /// File element to parse. /// Parent's component id. @@ -5034,10 +5052,12 @@ private void ParseExtensionElement(XElement node, string componentId, YesNoType /// Disk id inherited from parent component. /// Default source path of parent directory. /// This will be set with the possible keyPath for the parent component. - /// true if the component is 64-bit. - /// + /// Component GUID (including `*`). + /// Whether the File element being parsed is outside a Component element. + /// Outgoing file symbol containing parsed attributes. + /// Outgoing assembly symbol containing parsed attributes. /// Yes if this element was marked as the parent component's key path, No if explicitly marked as not being a key path, or NotSet otherwise. - private YesNoType ParseFileElement(XElement node, string componentId, string directoryId, int diskId, string sourcePath, out string possibleKeyPath, bool win64Component, string componentGuid) + private YesNoType ParseFileElementAttributes(XElement node, string componentId, string directoryId, int diskId, string sourcePath, out string possibleKeyPath, string componentGuid, bool isNakedFile, out FileSymbol fileSymbol, out AssemblySymbol assemblySymbol) { var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); Identifier id = null; @@ -5078,12 +5098,25 @@ private YesNoType ParseFileElement(XElement node, string componentId, string dir var source = sourcePath; // assume we'll use the parents as the source for this file var sourceSet = false; + fileSymbol = null; + assemblySymbol = null; + foreach (var attrib in node.Attributes()) { if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) { switch (attrib.Name.LocalName) { + case "Bitness": + case "Condition": + case "Directory": + case "Subdirectory": + // Naked files handle their attributes in ParseNakedFileElement. + if (!isNakedFile) + { + this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, attrib.Name.LocalName)); + } + break; case "Id": id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); break; @@ -5324,70 +5357,6 @@ private YesNoType ParseFileElement(XElement node, string componentId, string dir } } - foreach (var child in node.Elements()) - { - if (CompilerCore.WixNamespace == child.Name.Namespace) - { - switch (child.Name.LocalName) - { - case "AppId": - this.ParseAppIdElement(child, componentId, YesNoType.NotSet, id.Id, null, null); - break; - case "AssemblyName": - this.ParseAssemblyName(child, componentId); - break; - case "Class": - this.ParseClassElement(child, componentId, YesNoType.NotSet, id.Id, null, null, null); - break; - case "CopyFile": - this.ParseCopyFileElement(child, componentId, id.Id); - break; - case "IgnoreRange": - this.ParseRangeElement(child, ref ignoreOffsets, ref ignoreLengths); - break; - case "ODBCDriver": - this.ParseODBCDriverOrTranslator(child, componentId, id.Id, SymbolDefinitionType.ODBCDriver); - break; - case "ODBCTranslator": - this.ParseODBCDriverOrTranslator(child, componentId, id.Id, SymbolDefinitionType.ODBCTranslator); - break; - case "Permission": - this.ParsePermissionElement(child, id.Id, "File"); - break; - case "PermissionEx": - this.ParsePermissionExElement(child, id.Id, "File"); - break; - case "ProtectRange": - this.ParseRangeElement(child, ref protectOffsets, ref protectLengths); - break; - case "Shortcut": - this.ParseShortcutElement(child, componentId, node.Name.LocalName, id.Id, keyPath); - break; - case "SymbolPath": - if (null != symbols) - { - symbols += ";" + this.ParseSymbolPathElement(child); - } - else - { - symbols = this.ParseSymbolPathElement(child); - } - break; - case "TypeLib": - this.ParseTypeLibElement(child, componentId, id.Id, win64Component); - break; - default: - this.Core.UnexpectedElement(node, child); - break; - } - } - else - { - var context = new Dictionary() { { "FileId", id?.Id }, { "ComponentId", componentId }, { "DirectoryId", directoryId }, { "Win64", win64Component.ToString() } }; - this.Core.ParseExtensionElement(node, child, context); - } - } - if (!this.Core.EncounteredError) { var patchAttributes = PatchAttributeType.None; @@ -5422,7 +5391,7 @@ private YesNoType ParseFileElement(XElement node, string componentId, string dir attributes |= compressed.HasValue && compressed == true ? FileSymbolAttributes.Compressed : 0; attributes |= compressed.HasValue && compressed == false ? FileSymbolAttributes.Uncompressed : 0; - this.Core.AddSymbol(new FileSymbol(sourceLineNumbers, id) + fileSymbol = new FileSymbol(sourceLineNumbers, id) { ComponentRef = componentId, Name = name, @@ -5449,11 +5418,11 @@ private YesNoType ParseFileElement(XElement node, string componentId, string dir IgnoreLengths = ignoreLengths, RetainOffsets = protectOffsets, SymbolPaths = symbols, - }); + }; if (AssemblyType.NotAnAssembly != assemblyType) { - this.Core.AddSymbol(new AssemblySymbol(sourceLineNumbers, id) + assemblySymbol = new AssemblySymbol(sourceLineNumbers, id) { ComponentRef = componentId, FeatureRef = Guid.Empty.ToString("B"), @@ -5461,7 +5430,7 @@ private YesNoType ParseFileElement(XElement node, string componentId, string dir ApplicationFileRef = assemblyApplication, Type = assemblyType, ProcessorArchitecture = procArch, - }); + }; } } @@ -5480,6 +5449,221 @@ private YesNoType ParseFileElement(XElement node, string componentId, string dir return keyPath; } + /// File element to parse. + /// The partially-parsed file symbol. + /// Whether the file is the keypath of its component. + /// true if the component is 64-bit. + private void ParseFileElementChildren(XElement node, FileSymbol fileSymbol, YesNoType keyPath, bool win64Component) + { + var directoryId = fileSymbol.DirectoryRef; + var componentId = fileSymbol.ComponentRef; + var id = fileSymbol.Id; + var ignoreOffsets = fileSymbol.IgnoreOffsets; + var ignoreLengths = fileSymbol.IgnoreLengths; + var protectOffsets = fileSymbol.RetainOffsets; + var protectLengths = fileSymbol.RetainLengths; + var symbols = fileSymbol.SymbolPaths; + + foreach (var child in node.Elements()) + { + if (CompilerCore.WixNamespace == child.Name.Namespace) + { + switch (child.Name.LocalName) + { + case "AppId": + this.ParseAppIdElement(child, componentId, YesNoType.NotSet, id.Id, null, null); + break; + case "AssemblyName": + this.ParseAssemblyName(child, componentId); + break; + case "Class": + this.ParseClassElement(child, componentId, YesNoType.NotSet, id.Id, null, null, null); + break; + case "CopyFile": + this.ParseCopyFileElement(child, componentId, id.Id); + break; + case "IgnoreRange": + this.ParseRangeElement(child, ref ignoreOffsets, ref ignoreLengths); + break; + case "ODBCDriver": + this.ParseODBCDriverOrTranslator(child, componentId, id.Id, SymbolDefinitionType.ODBCDriver); + break; + case "ODBCTranslator": + this.ParseODBCDriverOrTranslator(child, componentId, id.Id, SymbolDefinitionType.ODBCTranslator); + break; + case "Permission": + this.ParsePermissionElement(child, id.Id, "File"); + break; + case "PermissionEx": + this.ParsePermissionExElement(child, id.Id, "File"); + break; + case "ProtectRange": + this.ParseRangeElement(child, ref protectOffsets, ref protectLengths); + break; + case "Shortcut": + this.ParseShortcutElement(child, componentId, node.Name.LocalName, id.Id, keyPath); + break; + case "SymbolPath": + if (null != symbols) + { + symbols += ";" + this.ParseSymbolPathElement(child); + } + else + { + symbols = this.ParseSymbolPathElement(child); + } + break; + case "TypeLib": + this.ParseTypeLibElement(child, componentId, id.Id, win64Component); + break; + default: + this.Core.UnexpectedElement(node, child); + break; + } + } + else + { + var context = new Dictionary() { { "FileId", id?.Id }, { "ComponentId", componentId }, { "DirectoryId", directoryId }, { "Win64", win64Component.ToString() } }; + this.Core.ParseExtensionElement(node, child, context); + } + } + + fileSymbol.IgnoreOffsets = ignoreOffsets; + fileSymbol.IgnoreLengths = ignoreLengths; + fileSymbol.RetainOffsets = protectOffsets; + fileSymbol.RetainLengths = protectLengths; + fileSymbol.SymbolPaths = symbols; + } + + + /// + /// Parses a File element. + /// + /// File element to parse. + /// Parent's component id. + /// Ancestor's directory id. + /// Disk id inherited from parent component. + /// Default source path of parent directory. + /// This will be set with the possible keyPath for the parent component. + /// true if the component is 64-bit. + /// Component GUID (including `*`). + /// Yes if this element was marked as the parent component's key path, No if explicitly marked as not being a key path, or NotSet otherwise. + private YesNoType ParseFileElement(XElement node, string componentId, string directoryId, int diskId, string sourcePath, out string possibleKeyPath, bool win64Component, string componentGuid) + { + var keyPath = this.ParseFileElementAttributes(node, componentId, directoryId, diskId, sourcePath, out possibleKeyPath, componentGuid, isNakedFile: false, out var fileSymbol, out var assemblySymbol); + + if (!this.Core.EncounteredError) + { + this.Core.AddSymbol(fileSymbol); + + if (assemblySymbol != null) + { + this.Core.AddSymbol(assemblySymbol); + } + + this.ParseFileElementChildren(node, fileSymbol, keyPath, win64Component); + } + + return keyPath; + } + + /// + /// Parses a file element outside a component. + /// + /// File element to parse. + /// Type of complex reference parent. Will be Unknown if there is no parent. + /// Optional identifier for primary parent. + /// Ancestor's directory id. + /// Default source path of parent directory. + /// Yes if this element was marked as the parent component's key path, No if explicitly marked as not being a key path, or NotSet otherwise. + private void ParseNakedFileElement(XElement node, ComplexReferenceParentType parentType, string parentId, string directoryId, string sourcePath) + { + var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); + var win64 = this.Context.IsCurrentPlatform64Bit; + string condition = null; + string subdirectory = null; + + var keyPath = this.ParseFileElementAttributes(node, "TemporaryComponentId", directoryId, diskId: CompilerConstants.IntegerNotSet, sourcePath, out var _, componentGuid: "*", isNakedFile: true, out var fileSymbol, out var assemblySymbol); + + if (!this.Core.EncounteredError) + { + // Naked files have additional attributes to handle common component attributes. + foreach (var attrib in node.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Bitness": + var bitnessValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + switch (bitnessValue) + { + case "always32": + win64 = false; + break; + case "always64": + win64 = true; + break; + case "default": + case "": + break; + default: + this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, bitnessValue, "default", "always32", "always64")); + break; + } + break; + case "Condition": + condition = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "Directory": + directoryId = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + this.Core.CreateSimpleReference(sourceLineNumbers, SymbolDefinitions.Directory, directoryId); + break; + case "Subdirectory": + subdirectory = this.Core.GetAttributeLongFilename(sourceLineNumbers, attrib, allowRelative: true); + break; + } + } + } + + directoryId = this.HandleSubdirectory(sourceLineNumbers, node, directoryId, subdirectory, "Directory", "Subdirectory"); + + this.Core.AddSymbol(new ComponentSymbol(sourceLineNumbers, fileSymbol.Id) + { + ComponentId = "*", + DirectoryRef = directoryId, + Location = ComponentLocation.LocalOnly, + Condition = condition, + KeyPath = fileSymbol.Id.Id, + KeyPathType = ComponentKeyPathType.File, + DisableRegistryReflection = false, + NeverOverwrite = false, + Permanent = false, + SharedDllRefCount = false, + Shared = false, + Transitive = false, + UninstallWhenSuperseded = false, + Win64 = win64, + }); + + fileSymbol.ComponentRef = fileSymbol.Id.Id; + this.Core.AddSymbol(fileSymbol); + + if (assemblySymbol != null) + { + this.Core.AddSymbol(assemblySymbol); + } + + this.ParseFileElementChildren(node, fileSymbol, keyPath, win64); + + if (ComplexReferenceParentType.Unknown != parentType && null != parentId) // if parent was provided, add a complex reference to that. + { + // If the naked file's component is defined directly under a feature, then mark the complex reference primary. + this.Core.CreateComplexReference(sourceLineNumbers, parentType, parentId, null, ComplexReferenceChildType.Component, fileSymbol.Id.Id, ComplexReferenceParentType.Feature == parentType); + } + } + } + /// /// Parses a file search element. /// @@ -5797,6 +5981,9 @@ private void ParseFragmentElement(XElement node) case "FeatureRef": this.ParseFeatureRefElement(child, ComplexReferenceParentType.Unknown, null); break; + case "File": + this.ParseNakedFileElement(child, ComplexReferenceParentType.Unknown, null, null, null); + break; case "Icon": this.ParseIconElement(child); break; @@ -7144,6 +7331,9 @@ private void ParseStandardDirectoryElement(XElement node) case "Directory": this.ParseDirectoryElement(child, id, diskId: CompilerConstants.IntegerNotSet, fileSource: String.Empty); break; + case "File": + this.ParseNakedFileElement(child, ComplexReferenceParentType.Unknown, null, id, null); + break; case "Merge": this.ParseMergeElement(child, id, diskId: CompilerConstants.IntegerNotSet); break; @@ -7295,7 +7485,7 @@ private void ParseLevelElement(XElement node, string featureId) /// Parses a merge reference element. /// /// Element to parse. - /// Parents complex reference type. + /// Parent's complex reference type. /// Identifier for parent feature or feature group. private void ParseMergeRefElement(XElement node, ComplexReferenceParentType parentType, string parentId) { diff --git a/src/wix/WixToolset.Core/Compiler_Module.cs b/src/wix/WixToolset.Core/Compiler_Module.cs index 0a547ad72..fd75bc4d9 100644 --- a/src/wix/WixToolset.Core/Compiler_Module.cs +++ b/src/wix/WixToolset.Core/Compiler_Module.cs @@ -175,6 +175,9 @@ private void ParseModuleElement(XElement node) case "Exclusion": this.ParseExclusionElement(child); break; + case "File": + this.ParseNakedFileElement(child, ComplexReferenceParentType.Module, this.activeName, null, null); + break; case "Icon": this.ParseIconElement(child); break; diff --git a/src/wix/WixToolset.Core/Compiler_Package.cs b/src/wix/WixToolset.Core/Compiler_Package.cs index 2fdbe6f08..e679a650a 100644 --- a/src/wix/WixToolset.Core/Compiler_Package.cs +++ b/src/wix/WixToolset.Core/Compiler_Package.cs @@ -287,6 +287,9 @@ private void ParsePackageElement(XElement node) case "FeatureGroupRef": this.ParseFeatureGroupRefElement(child, ComplexReferenceParentType.Product, productCode); break; + case "File": + this.ParseNakedFileElement(child, ComplexReferenceParentType.Unknown, null, null, null); + break; case "Icon": this.ParseIconElement(child); break; diff --git a/src/wix/WixToolset.Core/Linker.cs b/src/wix/WixToolset.Core/Linker.cs index 21cc67347..4a8868a76 100644 --- a/src/wix/WixToolset.Core/Linker.cs +++ b/src/wix/WixToolset.Core/Linker.cs @@ -162,7 +162,7 @@ public Intermediate Link(ILinkContext context) } } } - else + else if (find.EntrySection.Type == SectionType.Package) { var command = new AssignDefaultFeatureCommand(this.Messaging, find.EntrySection, sections, referencedComponents, componentsToFeatures); command.Execute(); diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/NakedFileFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/NakedFileFixture.cs new file mode 100644 index 000000000..1b0f091ef --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/NakedFileFixture.cs @@ -0,0 +1,240 @@ +// 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. + +namespace WixToolsetTest.CoreIntegration +{ + using System.Data; + using System.IO; + using System.Linq; + using WixInternal.Core.TestPackage; + using WixInternal.TestSupport; + using Xunit; + + public class NakedFileFixture + { + [Fact] + public void CanBuildNakedFilesInComponentGroup() + { + var rows = BuildAndQueryComponentAndFileTables("ComponentGroup.wxs"); + + AssertFileComponentIds(2, rows); + } + + [Fact] + public void CanBuildNakedFilesInFeature() + { + var rows = BuildAndQueryComponentAndFileTables("Feature.wxs"); + + AssertFileComponentIds(2, rows); + } + + [Fact] + public void CanBuildNakedFilesInDirectory() + { + var rows = BuildAndQueryComponentAndFileTables("Directory.wxs"); + + AssertFileComponentIds(2, rows); + } + + [Fact] + public void CanBuildNakedFilesInDirectoryRef() + { + var rows = BuildAndQueryComponentAndFileTables("DirectoryRef.wxs"); + + AssertFileComponentIds(2, rows); + } + + [Fact] + public void CanBuildNakedFilesInFeatureRef() + { + var rows = BuildAndQueryComponentAndFileTables("FeatureRef.wxs"); + + AssertFileComponentIds(2, rows); + } + + [Fact] + public void CanBuildNakedFilesInFeatureGroup() + { + var rows = BuildAndQueryComponentAndFileTables("FeatureGroup.wxs"); + + AssertFileComponentIds(2, rows); + } + + [Fact] + public void CanBuildNakedFilesInFragments() + { + var rows = BuildAndQueryComponentAndFileTables("Fragment.wxs"); + + AssertFileComponentIds(2, rows); + } + + [Fact] + public void CanBuildNakedFilesInStandardDirectory() + { + var rows = BuildAndQueryComponentAndFileTables("StandardDirectory.wxs"); + + AssertFileComponentIds(2, rows); + } + + [Fact] + public void CanBuildNakedFilesInModule() + { + var rows = BuildAndQueryComponentAndFileTables("Module.wxs", isPackage: false); + + AssertFileComponentIds(2, rows); + } + + [Fact] + public void CanBuildNakedFileInModuleWithFragments() + { + var rows = BuildAndQueryComponentAndFileTables("ModuleFragment.wxs", isPackage: false); + + AssertFileComponentIds(2, rows); + } + + [Fact] + public void CanBuildNakedFilesWithConditions() + { + var rows = BuildAndQueryComponentAndFileTables("Condition.wxs"); + var componentRows = rows.Where(row => row.StartsWith("Component:")).ToArray(); + + // Coincidentally, the files' ids are the same as the component conditions. + foreach (var componentRow in componentRows) + { + var columns = componentRow.Split(':', '\t'); + Assert.Equal(columns[1], columns[5]); + } + } + + [Fact] + public void NakedFilesUnderPackageWithAuthoredFeatureAreOrphaned() + { + var messages = BuildAndQueryComponentAndFileTables("PackageWithoutDefaultFeature.wxs", isPackage: true, 267); + Assert.Equal(new[] + { + "267", + "267", + }, messages); + } + + [Fact] + public void IllegalAttributesWhenNonNakedFailTheBuild() + { + var messages = BuildAndQueryComponentAndFileTables("BadAttributes.wxs", isPackage: true, 62); + Assert.Equal(new[] + { + "62", + "62", + "62", + "62", + }, messages); + } + + [Fact] + public void CanBuildNakedFileFromWixlibComponentGroup() + { + var rows = BuildPackageWithWixlib("WixlibComponentGroup.wxs", "WixlibComponentGroupPackage.wxs"); + + AssertFileComponentIds(2, rows); + } + + private static string[] BuildPackageWithWixlib(string wixlibSourcePath, string msiSourcePath) + { + var folder = TestData.Get("TestData", "NakedFile"); + + using (var fs = new DisposableFileSystem()) + { + var baseFolder = fs.GetFolder(); + var intermediateFolder = Path.Combine(baseFolder, "obj"); + var binFolder = Path.Combine(baseFolder, "bin"); + var wixlibPath = Path.Combine(binFolder, Path.ChangeExtension(wixlibSourcePath, ".wixlib")); + + var result = WixRunner.Execute(new[] + { + "build", + Path.Combine(folder, wixlibSourcePath), + "-intermediateFolder", intermediateFolder, + "-bindpath", folder, + "-o", wixlibPath, + }); + + result.AssertSuccess(); + + var msiPath = Path.Combine(binFolder, "test.msi"); + + result = WixRunner.Execute(new[] + { + "build", + Path.Combine(folder, msiSourcePath), + wixlibPath, + "-intermediateFolder", intermediateFolder, + "-bindpath", folder, + "-o", msiPath, + }); + result.AssertSuccess(); + + return Query.QueryDatabase(msiPath, new[] { "Component", "File" }) + .OrderBy(s => s) + .ToArray(); + } + } + + private static string[] BuildAndQueryComponentAndFileTables(string file, bool isPackage = true, int? exitCode = null) + { + var folder = TestData.Get("TestData", "NakedFile"); + + using (var fs = new DisposableFileSystem()) + { + var baseFolder = fs.GetFolder(); + var intermediateFolder = Path.Combine(baseFolder, "obj"); + var binFolder = Path.Combine(baseFolder, "bin"); + var msiPath = Path.Combine(binFolder, isPackage ? "test.msi" : "test.msm"); + + var result = WixRunner.Execute(new[] + { + "build", + Path.Combine(folder, file), + "-intermediateFolder", intermediateFolder, + "-bindpath", folder, + "-o", msiPath, + }); + + if (exitCode.HasValue) + { + Assert.Equal(exitCode.Value, result.ExitCode); + + return result.Messages.Select(m => m.Id.ToString()).ToArray(); + } + else + { + result.AssertSuccess(); + + return Query.QueryDatabase(msiPath, new[] { "Component", "File" }) + .OrderBy(s => s) + .ToArray(); + } + } + } + + private static void AssertFileComponentIds(int fileCount, string[] rows) + { + var componentRows = rows.Where(row => row.StartsWith("Component:")).ToArray(); + var fileRows = rows.Where(row => row.StartsWith("File:")).ToArray(); + + Assert.Equal(fileCount, componentRows.Length); + Assert.Equal(componentRows.Length, fileRows.Length); + + // Component id == Component keypath == File id + foreach (var componentRow in componentRows) + { + var columns = componentRow.Split(':', '\t'); + Assert.Equal(columns[1], columns[6]); + } + + foreach (var fileRow in fileRows) + { + var columns = fileRow.Split(':', '\t'); + Assert.Equal(columns[1], columns[2]); + } + } + } +} diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/BadAttributes.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/BadAttributes.wxs new file mode 100644 index 000000000..269db3c07 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/BadAttributes.wxs @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/ComponentGroup.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/ComponentGroup.wxs new file mode 100644 index 000000000..69a539a98 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/ComponentGroup.wxs @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/Condition.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/Condition.wxs new file mode 100644 index 000000000..3b5dae22d --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/Condition.wxs @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/Directory.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/Directory.wxs new file mode 100644 index 000000000..85cdb0292 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/Directory.wxs @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/DirectoryRef.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/DirectoryRef.wxs new file mode 100644 index 000000000..6de50ac44 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/DirectoryRef.wxs @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/Feature.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/Feature.wxs new file mode 100644 index 000000000..d4c2daa94 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/Feature.wxs @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/FeatureGroup.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/FeatureGroup.wxs new file mode 100644 index 000000000..94fdd0de2 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/FeatureGroup.wxs @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/FeatureRef.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/FeatureRef.wxs new file mode 100644 index 000000000..c92db44b9 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/FeatureRef.wxs @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/Fragment.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/Fragment.wxs new file mode 100644 index 000000000..6518e4bae --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/Fragment.wxs @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/Module.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/Module.wxs new file mode 100644 index 000000000..c94f37200 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/Module.wxs @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/ModuleFragment.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/ModuleFragment.wxs new file mode 100644 index 000000000..a9612f93e --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/ModuleFragment.wxs @@ -0,0 +1,16 @@ + + + + + + + + + + + + diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/PackageWithoutDefaultFeature.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/PackageWithoutDefaultFeature.wxs new file mode 100644 index 000000000..0dbf20458 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/PackageWithoutDefaultFeature.wxs @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/StandardDirectory.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/StandardDirectory.wxs new file mode 100644 index 000000000..5b6bdf2f3 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/StandardDirectory.wxs @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/WixlibComponentGroup.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/WixlibComponentGroup.wxs new file mode 100644 index 000000000..047d5bf26 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/WixlibComponentGroup.wxs @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/WixlibComponentGroupPackage.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/WixlibComponentGroupPackage.wxs new file mode 100644 index 000000000..853167534 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/WixlibComponentGroupPackage.wxs @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/test.txt b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/test.txt new file mode 100644 index 000000000..d32727e04 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/NakedFile/test.txt @@ -0,0 +1 @@ +This is test.txt. diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/SingleFile/PackageComponents.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/SingleFile/PackageComponents.wxs index b8e9f59c2..488e230f3 100644 --- a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/SingleFile/PackageComponents.wxs +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/SingleFile/PackageComponents.wxs @@ -2,9 +2,8 @@ - - - + +