diff options
author | Rob Mensching <rob@firegiant.com> | 2022-10-14 09:34:30 -0700 |
---|---|---|
committer | Rob Mensching <rob@firegiant.com> | 2022-10-14 20:13:50 -0700 |
commit | 08f53f409020b12dffaa2aeefa943b667a4b9328 (patch) | |
tree | 42bad414ff06c19fb881c7db1b145ec1d6885521 | |
parent | 07b3d459ea0a45cbef29b98d283edafbab26462a (diff) | |
download | wix-08f53f409020b12dffaa2aeefa943b667a4b9328.tar.gz wix-08f53f409020b12dffaa2aeefa943b667a4b9328.tar.bz2 wix-08f53f409020b12dffaa2aeefa943b667a4b9328.zip |
Simplify reference resolution
WiX v3 extension loading had options that were rarely if ever used
and library paths modeled after C++. Given the new Sdk-style model
in WiX v4, we can simplify reference resolution.
Fixes 6945, 6946
8 files changed, 173 insertions, 251 deletions
diff --git a/src/internal/WixToolset.BaseBuildTasks.Sources/FileSearchHelperMethods.cs b/src/internal/WixToolset.BaseBuildTasks.Sources/FileSearchHelperMethods.cs deleted file mode 100644 index 442fedd6..00000000 --- a/src/internal/WixToolset.BaseBuildTasks.Sources/FileSearchHelperMethods.cs +++ /dev/null | |||
@@ -1,57 +0,0 @@ | |||
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.BaseBuildTasks | ||
4 | { | ||
5 | using System; | ||
6 | using System.IO; | ||
7 | |||
8 | /// <summary> | ||
9 | /// Contains helper methods on searching for files | ||
10 | /// </summary> | ||
11 | public static class FileSearchHelperMethods | ||
12 | { | ||
13 | /// <summary> | ||
14 | /// Searches for the existence of a file in multiple directories. | ||
15 | /// Search is satisfied if default file path is valid and exists. If not, | ||
16 | /// file name is extracted from default path and combined with each of the directories | ||
17 | /// looking to see if it exists. If not found, input default path is returned. | ||
18 | /// </summary> | ||
19 | /// <param name="directories">Array of directories to look in, without filenames in them</param> | ||
20 | /// <param name="defaultFullPath">Default path - to use if not found</param> | ||
21 | /// <returns>File path if file found. Empty string if not found</returns> | ||
22 | public static string SearchFilePaths(string[] directories, string defaultFullPath) | ||
23 | { | ||
24 | if (String.IsNullOrEmpty(defaultFullPath)) | ||
25 | { | ||
26 | return String.Empty; | ||
27 | } | ||
28 | |||
29 | if (File.Exists(defaultFullPath)) | ||
30 | { | ||
31 | return defaultFullPath; | ||
32 | } | ||
33 | |||
34 | if (directories == null) | ||
35 | { | ||
36 | return String.Empty; | ||
37 | } | ||
38 | |||
39 | var fileName = Path.GetFileName(defaultFullPath); | ||
40 | foreach (var currentPath in directories) | ||
41 | { | ||
42 | if (String.IsNullOrWhiteSpace(currentPath)) | ||
43 | { | ||
44 | continue; | ||
45 | } | ||
46 | |||
47 | var path = Path.Combine(currentPath, fileName); | ||
48 | if (File.Exists(path)) | ||
49 | { | ||
50 | return path; | ||
51 | } | ||
52 | } | ||
53 | |||
54 | return String.Empty; | ||
55 | } | ||
56 | } | ||
57 | } | ||
diff --git a/src/internal/WixToolset.BaseBuildTasks.Sources/WixCommandLineBuilder.cs b/src/internal/WixToolset.BaseBuildTasks.Sources/WixCommandLineBuilder.cs index 152992dd..d950bca9 100644 --- a/src/internal/WixToolset.BaseBuildTasks.Sources/WixCommandLineBuilder.cs +++ b/src/internal/WixToolset.BaseBuildTasks.Sources/WixCommandLineBuilder.cs | |||
@@ -76,79 +76,6 @@ namespace WixToolset.BaseBuildTasks | |||
76 | } | 76 | } |
77 | 77 | ||
78 | /// <summary> | 78 | /// <summary> |
79 | /// Build the extensions argument. Each extension is searched in the current folder, user defined search | ||
80 | /// directories (ReferencePath), HintPath, and under Wix Extension Directory in that order. | ||
81 | /// The order of precedence is based off of that described in Microsoft.Common.Targets's SearchPaths | ||
82 | /// property for the ResolveAssemblyReferences task. | ||
83 | /// </summary> | ||
84 | /// <param name="extensions">The list of extensions to include.</param> | ||
85 | /// <param name="wixExtensionDirectory">Evaluated default folder for Wix Extensions</param> | ||
86 | /// <param name="referencePaths">User defined reference directories to search in</param> | ||
87 | public void AppendExtensions(ITaskItem[] extensions, string wixExtensionDirectory, string [] referencePaths) | ||
88 | { | ||
89 | if (extensions == null) | ||
90 | { | ||
91 | return; | ||
92 | } | ||
93 | |||
94 | foreach (ITaskItem extension in extensions) | ||
95 | { | ||
96 | string className = extension.GetMetadata("Class"); | ||
97 | |||
98 | string fileName = Path.GetFileName(extension.ItemSpec); | ||
99 | |||
100 | if (String.IsNullOrEmpty(Path.GetExtension(fileName))) | ||
101 | { | ||
102 | fileName += ".dll"; | ||
103 | } | ||
104 | |||
105 | // First try reference paths | ||
106 | var resolvedPath = FileSearchHelperMethods.SearchFilePaths(referencePaths, fileName); | ||
107 | |||
108 | if (String.IsNullOrEmpty(resolvedPath)) | ||
109 | { | ||
110 | // Now try HintPath | ||
111 | resolvedPath = extension.GetMetadata("HintPath"); | ||
112 | |||
113 | if (!File.Exists(resolvedPath)) | ||
114 | { | ||
115 | // Now try the item itself | ||
116 | resolvedPath = extension.ItemSpec; | ||
117 | |||
118 | if (String.IsNullOrEmpty(Path.GetExtension(resolvedPath))) | ||
119 | { | ||
120 | resolvedPath += ".dll"; | ||
121 | } | ||
122 | |||
123 | if (!File.Exists(resolvedPath)) | ||
124 | { | ||
125 | if (!String.IsNullOrEmpty(wixExtensionDirectory)) | ||
126 | { | ||
127 | // Now try the extension directory | ||
128 | resolvedPath = Path.Combine(wixExtensionDirectory, Path.GetFileName(resolvedPath)); | ||
129 | } | ||
130 | |||
131 | if (!File.Exists(resolvedPath)) | ||
132 | { | ||
133 | // Extension wasn't found, just set it to the extension name passed in | ||
134 | resolvedPath = extension.ItemSpec; | ||
135 | } | ||
136 | } | ||
137 | } | ||
138 | } | ||
139 | |||
140 | if (String.IsNullOrEmpty(className)) | ||
141 | { | ||
142 | this.AppendSwitchIfNotNull("-ext ", resolvedPath); | ||
143 | } | ||
144 | else | ||
145 | { | ||
146 | this.AppendSwitchIfNotNull("-ext ", className + ", " + resolvedPath); | ||
147 | } | ||
148 | } | ||
149 | } | ||
150 | |||
151 | /// <summary> | ||
152 | /// Append arbitrary text to the command-line if specified. | 79 | /// Append arbitrary text to the command-line if specified. |
153 | /// </summary> | 80 | /// </summary> |
154 | /// <param name="textToAppend">Text to append.</param> | 81 | /// <param name="textToAppend">Text to append.</param> |
diff --git a/src/wix/WixToolset.BuildTasks/ResolveWixReferences.cs b/src/wix/WixToolset.BuildTasks/ResolveWixReferences.cs index 8d8db428..d11b0399 100644 --- a/src/wix/WixToolset.BuildTasks/ResolveWixReferences.cs +++ b/src/wix/WixToolset.BuildTasks/ResolveWixReferences.cs | |||
@@ -4,9 +4,10 @@ namespace WixToolset.BuildTasks | |||
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
7 | using Microsoft.Build.Utilities; | ||
8 | using Microsoft.Build.Framework; | ||
9 | using System.IO; | 7 | using System.IO; |
8 | using System.Linq; | ||
9 | using Microsoft.Build.Framework; | ||
10 | using Microsoft.Build.Utilities; | ||
10 | 11 | ||
11 | /// <summary> | 12 | /// <summary> |
12 | /// This task searches for paths to references using the order specified in SearchPaths. | 13 | /// This task searches for paths to references using the order specified in SearchPaths. |
@@ -15,14 +16,14 @@ namespace WixToolset.BuildTasks | |||
15 | { | 16 | { |
16 | /// <summary> | 17 | /// <summary> |
17 | /// Token value used in SearchPaths to indicate that the item's HintPath metadata should | 18 | /// Token value used in SearchPaths to indicate that the item's HintPath metadata should |
18 | /// be searched as a full file path to resolve the reference. | 19 | /// be searched as a full file path to resolve the reference. |
19 | /// Must match wix.targets, case sensitive. | 20 | /// Must match wix.targets, case sensitive. |
20 | /// </summary> | 21 | /// </summary> |
21 | private const string HintPathToken = "{HintPathFromItem}"; | 22 | private const string HintPathToken = "{HintPathFromItem}"; |
22 | 23 | ||
23 | /// <summary> | 24 | /// <summary> |
24 | /// Token value used in SearchPaths to indicate that the item's Identity should | 25 | /// Token value used in SearchPaths to indicate that the item's Identity should |
25 | /// be searched as a full file path to resolve the reference. | 26 | /// be searched as a full file path to resolve the reference. |
26 | /// Must match wix.targets, case sensitive. | 27 | /// Must match wix.targets, case sensitive. |
27 | /// </summary> | 28 | /// </summary> |
28 | private const string RawFileNameToken = "{RawFileName}"; | 29 | private const string RawFileNameToken = "{RawFileName}"; |
@@ -34,24 +35,18 @@ namespace WixToolset.BuildTasks | |||
34 | public ITaskItem[] WixReferences { get; set; } | 35 | public ITaskItem[] WixReferences { get; set; } |
35 | 36 | ||
36 | /// <summary> | 37 | /// <summary> |
37 | /// The directories or special locations that are searched to find the files | 38 | /// The directories or special locations that are searched to find the files |
38 | /// on disk that represent the references. The order in which the search paths are listed | 39 | /// on disk that represent the references. The order in which the search paths are listed |
39 | /// is important. For each reference, the list of paths is searched from left to right. | 40 | /// is important. For each reference, the list of paths is searched from left to right. |
40 | /// When a file that represents the reference is found, that search stops and the search | 41 | /// When a file that represents the reference is found, that search stops and the search |
41 | /// for the next reference starts. | 42 | /// for the next reference starts. |
42 | /// | 43 | /// |
43 | /// This parameter accepts the following types of values: | 44 | /// This parameter accepts the following types of values: |
44 | /// A directory path. | 45 | /// A directory path. |
45 | /// {HintPathFromItem}: Specifies that the task will examine the HintPath metadata | 46 | /// {HintPathFromItem}: Specifies that the task will examine the HintPath metadata |
46 | /// of the base item. | 47 | /// of the base item. |
47 | /// TODO : {CandidateAssemblyFiles}: Specifies that the task will examine the files | 48 | /// {RawFileName}: Specifies the task will consider the Include value of the item to be |
48 | /// passed in through the CandidateAssemblyFiles parameter. | 49 | /// an exact path and file name. |
49 | /// TODO : {Registry:_AssemblyFoldersBase_, _RuntimeVersion_, _AssemblyFoldersSuffix_}: | ||
50 | /// TODO : {AssemblyFolders}: Specifies the task will use the Visual Studio.NET 2003 | ||
51 | /// finding-assemblies-from-registry scheme. | ||
52 | /// TODO : {GAC}: Specifies the task will search in the GAC. | ||
53 | /// {RawFileName}: Specifies the task will consider the Include value of the item to be | ||
54 | /// an exact path and file name. | ||
55 | /// </summary> | 50 | /// </summary> |
56 | public string[] SearchPaths { get; set; } | 51 | public string[] SearchPaths { get; set; } |
57 | 52 | ||
@@ -67,22 +62,37 @@ namespace WixToolset.BuildTasks | |||
67 | public ITaskItem[] ResolvedWixReferences { get; private set; } | 62 | public ITaskItem[] ResolvedWixReferences { get; private set; } |
68 | 63 | ||
69 | /// <summary> | 64 | /// <summary> |
65 | /// Output items that contain the same metadata as input references and cannot be found. | ||
66 | /// </summary> | ||
67 | [Output] | ||
68 | public ITaskItem[] UnresolvedWixReferences { get; private set; } | ||
69 | |||
70 | /// <summary> | ||
70 | /// Resolves reference paths by searching for referenced items using the specified SearchPaths. | 71 | /// Resolves reference paths by searching for referenced items using the specified SearchPaths. |
71 | /// </summary> | 72 | /// </summary> |
72 | /// <returns>True on success, or throws an exception on failure.</returns> | 73 | /// <returns>True on success, or throws an exception on failure.</returns> |
73 | public override bool Execute() | 74 | public override bool Execute() |
74 | { | 75 | { |
75 | var resolvedReferences = new List<ITaskItem>(); | 76 | var resolvedReferences = new List<ITaskItem>(); |
77 | var unresolvedReferences = new List<ITaskItem>(); | ||
76 | var uniqueReferences = new HashSet<string>(StringComparer.OrdinalIgnoreCase); | 78 | var uniqueReferences = new HashSet<string>(StringComparer.OrdinalIgnoreCase); |
77 | 79 | ||
78 | foreach (var reference in this.WixReferences) | 80 | foreach (var reference in this.WixReferences.Where(r => !String.IsNullOrWhiteSpace(r.ItemSpec))) |
79 | { | 81 | { |
80 | var resolvedReference = ResolveWixReferences.ResolveReference(reference, this.SearchPaths, this.SearchFilenameExtensions, this.Log); | 82 | (var resolvedReference, var found) = this.ResolveReference(reference, this.SearchPaths, this.SearchFilenameExtensions); |
81 | 83 | ||
82 | if (uniqueReferences.Add(resolvedReference.ItemSpec)) | 84 | if (uniqueReferences.Add(resolvedReference.ItemSpec)) |
83 | { | 85 | { |
84 | this.Log.LogMessage(MessageImportance.Low, "Resolved path {0}", resolvedReference.ItemSpec); | 86 | if (found) |
85 | resolvedReferences.Add(resolvedReference); | 87 | { |
88 | this.Log.LogMessage(MessageImportance.Low, "Resolved path {0}", resolvedReference.ItemSpec); | ||
89 | resolvedReferences.Add(resolvedReference); | ||
90 | } | ||
91 | else | ||
92 | { | ||
93 | this.Log.LogWarning(null, "WXE0001", null, null, 0, 0, 0, 0, "Unable to find extension {0}.", resolvedReference.ItemSpec); | ||
94 | unresolvedReferences.Add(resolvedReference); | ||
95 | } | ||
86 | } | 96 | } |
87 | else | 97 | else |
88 | { | 98 | { |
@@ -91,6 +101,7 @@ namespace WixToolset.BuildTasks | |||
91 | } | 101 | } |
92 | 102 | ||
93 | this.ResolvedWixReferences = resolvedReferences.ToArray(); | 103 | this.ResolvedWixReferences = resolvedReferences.ToArray(); |
104 | this.UnresolvedWixReferences = unresolvedReferences.ToArray(); | ||
94 | return true; | 105 | return true; |
95 | } | 106 | } |
96 | 107 | ||
@@ -101,80 +112,76 @@ namespace WixToolset.BuildTasks | |||
101 | /// <param name="reference">The referenced item.</param> | 112 | /// <param name="reference">The referenced item.</param> |
102 | /// <param name="searchPaths">The paths to search.</param> | 113 | /// <param name="searchPaths">The paths to search.</param> |
103 | /// <param name="searchFilenameExtensions">Filename extensions to check.</param> | 114 | /// <param name="searchFilenameExtensions">Filename extensions to check.</param> |
104 | /// <param name="log">Logging helper.</param> | ||
105 | /// <returns>The resolved reference item, or the original reference if it could not be resolved.</returns> | 115 | /// <returns>The resolved reference item, or the original reference if it could not be resolved.</returns> |
106 | public static ITaskItem ResolveReference(ITaskItem reference, string[] searchPaths, string[] searchFilenameExtensions, TaskLoggingHelper log) | 116 | public (ITaskItem, bool) ResolveReference(ITaskItem reference, string[] searchPaths, string[] searchFilenameExtensions) |
107 | { | 117 | { |
108 | if (reference == null) | 118 | // Ensure we first check the reference without adding additional search filename extensions. |
109 | { | 119 | searchFilenameExtensions = searchFilenameExtensions == null ? new[] { String.Empty } : searchFilenameExtensions.Prepend(String.Empty).ToArray(); |
110 | throw new ArgumentNullException("reference"); | 120 | |
111 | } | 121 | // Copy all the metadata from the source |
122 | var resolvedReference = new TaskItem(reference); | ||
123 | this.Log.LogMessage(MessageImportance.Low, "WixReference: {0}", reference.ItemSpec); | ||
124 | |||
125 | var found = false; | ||
112 | 126 | ||
127 | // Nothing to search, so just resolve the original reference item. | ||
113 | if (searchPaths == null) | 128 | if (searchPaths == null) |
114 | { | 129 | { |
115 | // Nothing to search, so just return the original reference item. | 130 | if (this.ResolveFilenameExtensions(resolvedReference, resolvedReference.ItemSpec, searchFilenameExtensions)) |
116 | return reference; | 131 | { |
117 | } | 132 | found = true; |
133 | } | ||
118 | 134 | ||
119 | if (searchFilenameExtensions == null) | 135 | return (resolvedReference, found); |
120 | { | ||
121 | searchFilenameExtensions = new string[] { }; | ||
122 | } | 136 | } |
123 | 137 | ||
124 | // Copy all the metadata from the source | 138 | // Otherwise, now try to find the resolved path based on the order of precedence from search paths. |
125 | var resolvedReference = new TaskItem(reference); | ||
126 | log.LogMessage(MessageImportance.Low, "WixReference: {0}", reference.ItemSpec); | ||
127 | |||
128 | // Now find the resolved path based on our order of precedence | ||
129 | foreach (var searchPath in searchPaths) | 139 | foreach (var searchPath in searchPaths) |
130 | { | 140 | { |
131 | log.LogMessage(MessageImportance.Low, "Trying {0}", searchPath); | 141 | this.Log.LogMessage(MessageImportance.Low, "Trying {0}", searchPath); |
132 | if (searchPath.Equals(HintPathToken, StringComparison.Ordinal)) | 142 | if (HintPathToken.Equals(searchPath, StringComparison.Ordinal)) |
133 | { | 143 | { |
134 | var path = reference.GetMetadata("HintPath"); | 144 | var path = reference.GetMetadata("HintPath"); |
135 | log.LogMessage(MessageImportance.Low, "Trying path {0}", path); | 145 | if (String.IsNullOrWhiteSpace(path)) |
146 | { | ||
147 | continue; | ||
148 | } | ||
149 | |||
150 | this.Log.LogMessage(MessageImportance.Low, "Trying path {0}", path); | ||
136 | if (File.Exists(path)) | 151 | if (File.Exists(path)) |
137 | { | 152 | { |
138 | resolvedReference.ItemSpec = path; | 153 | resolvedReference.ItemSpec = path; |
154 | found = true; | ||
139 | break; | 155 | break; |
140 | } | 156 | } |
141 | } | 157 | } |
142 | else if (searchPath.Equals(RawFileNameToken, StringComparison.Ordinal)) | 158 | else if (RawFileNameToken.Equals(searchPath, StringComparison.Ordinal)) |
143 | { | 159 | { |
144 | log.LogMessage(MessageImportance.Low, "Trying path {0}", resolvedReference.ItemSpec); | 160 | if (this.ResolveFilenameExtensions(resolvedReference, resolvedReference.ItemSpec, searchFilenameExtensions)) |
145 | if (File.Exists(resolvedReference.ItemSpec)) | ||
146 | { | ||
147 | break; | ||
148 | } | ||
149 | |||
150 | if (ResolveWixReferences.ResolveFilenameExtensions(resolvedReference, | ||
151 | resolvedReference.ItemSpec, searchFilenameExtensions, log)) | ||
152 | { | 161 | { |
162 | found = true; | ||
153 | break; | 163 | break; |
154 | } | 164 | } |
155 | } | 165 | } |
156 | else | 166 | else |
157 | { | 167 | { |
158 | var path = Path.Combine(searchPath, Path.GetFileName(reference.ItemSpec)); | 168 | var path = Path.Combine(searchPath, reference.ItemSpec); |
159 | log.LogMessage(MessageImportance.Low, "Trying path {0}", path); | ||
160 | if (File.Exists(path)) | ||
161 | { | ||
162 | resolvedReference.ItemSpec = path; | ||
163 | break; | ||
164 | } | ||
165 | 169 | ||
166 | if (ResolveWixReferences.ResolveFilenameExtensions(resolvedReference, | 170 | if (this.ResolveFilenameExtensions(resolvedReference, path, searchFilenameExtensions)) |
167 | path, searchFilenameExtensions, log)) | ||
168 | { | 171 | { |
172 | found = true; | ||
169 | break; | 173 | break; |
170 | } | 174 | } |
171 | } | 175 | } |
172 | } | 176 | } |
173 | 177 | ||
174 | // Normalize the item path | 178 | if (found) |
175 | resolvedReference.ItemSpec = resolvedReference.GetMetadata("FullPath"); | 179 | { |
180 | // Normalize the item spec to the full path. | ||
181 | resolvedReference.ItemSpec = resolvedReference.GetMetadata("FullPath"); | ||
182 | } | ||
176 | 183 | ||
177 | return resolvedReference; | 184 | return (resolvedReference, found); |
178 | } | 185 | } |
179 | 186 | ||
180 | /// <summary> | 187 | /// <summary> |
@@ -183,14 +190,14 @@ namespace WixToolset.BuildTasks | |||
183 | /// <param name="reference">The reference being resolved.</param> | 190 | /// <param name="reference">The reference being resolved.</param> |
184 | /// <param name="basePath">Full filename path without extension.</param> | 191 | /// <param name="basePath">Full filename path without extension.</param> |
185 | /// <param name="filenameExtensions">Filename extensions to check.</param> | 192 | /// <param name="filenameExtensions">Filename extensions to check.</param> |
186 | /// <param name="log">Logging helper.</param> | ||
187 | /// <returns>True if the item was resolved, else false.</returns> | 193 | /// <returns>True if the item was resolved, else false.</returns> |
188 | private static bool ResolveFilenameExtensions(ITaskItem reference, string basePath, string[] filenameExtensions, TaskLoggingHelper log) | 194 | private bool ResolveFilenameExtensions(ITaskItem reference, string basePath, string[] filenameExtensions) |
189 | { | 195 | { |
190 | foreach (var filenameExtension in filenameExtensions) | 196 | foreach (var filenameExtension in filenameExtensions) |
191 | { | 197 | { |
192 | var path = basePath + filenameExtension; | 198 | var path = basePath + filenameExtension; |
193 | log.LogMessage(MessageImportance.Low, "Trying path {0}", path); | 199 | this.Log.LogMessage(MessageImportance.Low, "Trying path {0}", path); |
200 | |||
194 | if (File.Exists(path)) | 201 | if (File.Exists(path)) |
195 | { | 202 | { |
196 | reference.ItemSpec = path; | 203 | reference.ItemSpec = path; |
diff --git a/src/wix/WixToolset.BuildTasks/WixBuild.cs b/src/wix/WixToolset.BuildTasks/WixBuild.cs index 8990d0b7..923567ed 100644 --- a/src/wix/WixToolset.BuildTasks/WixBuild.cs +++ b/src/wix/WixToolset.BuildTasks/WixBuild.cs | |||
@@ -18,8 +18,6 @@ namespace WixToolset.BuildTasks | |||
18 | 18 | ||
19 | public ITaskItem[] Extensions { get; set; } | 19 | public ITaskItem[] Extensions { get; set; } |
20 | 20 | ||
21 | public string ExtensionDirectory { get; set; } | ||
22 | |||
23 | public string[] IncludeSearchPaths { get; set; } | 21 | public string[] IncludeSearchPaths { get; set; } |
24 | 22 | ||
25 | public string InstallerPlatform { get; set; } | 23 | public string InstallerPlatform { get; set; } |
@@ -45,8 +43,6 @@ namespace WixToolset.BuildTasks | |||
45 | [Required] | 43 | [Required] |
46 | public ITaskItem[] SourceFiles { get; set; } | 44 | public ITaskItem[] SourceFiles { get; set; } |
47 | 45 | ||
48 | public string[] ReferencePaths { get; set; } | ||
49 | |||
50 | public ITaskItem[] BindInputPaths { get; set; } | 46 | public ITaskItem[] BindInputPaths { get; set; } |
51 | 47 | ||
52 | public bool BindFiles { get; set; } | 48 | public bool BindFiles { get; set; } |
@@ -75,7 +71,7 @@ namespace WixToolset.BuildTasks | |||
75 | commandLineBuilder.AppendArrayIfNotNull("-culture ", this.Cultures); | 71 | commandLineBuilder.AppendArrayIfNotNull("-culture ", this.Cultures); |
76 | commandLineBuilder.AppendArrayIfNotNull("-d ", this.DefineConstants); | 72 | commandLineBuilder.AppendArrayIfNotNull("-d ", this.DefineConstants); |
77 | commandLineBuilder.AppendArrayIfNotNull("-I ", this.IncludeSearchPaths); | 73 | commandLineBuilder.AppendArrayIfNotNull("-I ", this.IncludeSearchPaths); |
78 | commandLineBuilder.AppendExtensions(this.Extensions, this.ExtensionDirectory, this.ReferencePaths); | 74 | commandLineBuilder.AppendArrayIfNotNull("-ext ", this.Extensions); |
79 | commandLineBuilder.AppendSwitchIfNotNull("-cc ", this.CabinetCachePath); | 75 | commandLineBuilder.AppendSwitchIfNotNull("-cc ", this.CabinetCachePath); |
80 | commandLineBuilder.AppendSwitchIfNotNull("-intermediatefolder ", this.IntermediateDirectory); | 76 | commandLineBuilder.AppendSwitchIfNotNull("-intermediatefolder ", this.IntermediateDirectory); |
81 | commandLineBuilder.AppendSwitchIfNotNull("-trackingfile ", this.BindTrackingFile); | 77 | commandLineBuilder.AppendSwitchIfNotNull("-trackingfile ", this.BindTrackingFile); |
diff --git a/src/wix/WixToolset.Sdk/tools/wix.targets b/src/wix/WixToolset.Sdk/tools/wix.targets index 340fb91f..6a8b6055 100644 --- a/src/wix/WixToolset.Sdk/tools/wix.targets +++ b/src/wix/WixToolset.Sdk/tools/wix.targets | |||
@@ -129,10 +129,6 @@ | |||
129 | </PropertyGroup> | 129 | </PropertyGroup> |
130 | 130 | ||
131 | <PropertyGroup> | 131 | <PropertyGroup> |
132 | <WixExtDir Condition=" '$(WixExtDir)' == ''">$(WixBinDir)</WixExtDir> | ||
133 | </PropertyGroup> | ||
134 | |||
135 | <PropertyGroup> | ||
136 | <BindTrackingFilePrefix Condition=" '$(BindTrackingFilePrefix)' == '' ">$(MSBuildProjectFile).BindTracking</BindTrackingFilePrefix> | 132 | <BindTrackingFilePrefix Condition=" '$(BindTrackingFilePrefix)' == '' ">$(MSBuildProjectFile).BindTracking</BindTrackingFilePrefix> |
137 | <BindTrackingFileExtension Condition=" '$(BindTrackingFileExtension)' == '' ">.txt</BindTrackingFileExtension> | 133 | <BindTrackingFileExtension Condition=" '$(BindTrackingFileExtension)' == '' ">.txt</BindTrackingFileExtension> |
138 | </PropertyGroup> | 134 | </PropertyGroup> |
@@ -362,10 +358,9 @@ | |||
362 | 358 | ||
363 | By default the WixLibrarySearchPaths property is set to find libraries in the following order: | 359 | By default the WixLibrarySearchPaths property is set to find libraries in the following order: |
364 | 360 | ||
365 | (1) $(ReferencePaths) - the reference paths property, which comes from the .USER file. | 361 | (1) $(ReferencePaths) - the reference paths property. |
366 | (2) The hintpath from the referenced item itself, indicated by {HintPathFromItem}. | 362 | (2) The hintpath from the referenced item itself, indicated by {HintPathFromItem}. |
367 | (3) Treat the reference's Include as if it were a real file name. | 363 | (3) Treat the reference's Include as if it were a real file name. |
368 | (4) Path specified by the WixExtDir property. | ||
369 | 364 | ||
370 | [IN] | 365 | [IN] |
371 | @(WixLibrary) - the list of .wixlib files. | 366 | @(WixLibrary) - the list of .wixlib files. |
@@ -381,39 +376,33 @@ | |||
381 | </PropertyGroup> | 376 | </PropertyGroup> |
382 | <Target | 377 | <Target |
383 | Name="ResolveWixLibraryReferences" | 378 | Name="ResolveWixLibraryReferences" |
384 | DependsOnTargets="$(ResolveWixLibraryReferencesDependsOn)"> | 379 | DependsOnTargets="$(ResolveWixLibraryReferencesDependsOn)" |
380 | Condition=" '@(WixLibrary)' != ''"> | ||
385 | 381 | ||
386 | <PropertyGroup> | 382 | <PropertyGroup> |
387 | <WixLibrarySearchPaths Condition=" '$(WixLibrarySearchPaths)' == '' ">$(ReferencePaths);{HintPathFromItem};{RawFileName};$(WixExtDir)</WixLibrarySearchPaths> | 383 | <WixLibrarySearchPaths Condition=" '$(WixLibrarySearchPaths)' == '' ">$(ReferencePaths);{HintPathFromItem};{RawFileName}</WixLibrarySearchPaths> |
388 | </PropertyGroup> | 384 | </PropertyGroup> |
389 | 385 | ||
390 | <ResolveWixReferences | 386 | <ResolveWixReferences |
391 | WixReferences="@(WixLibrary)" | 387 | WixReferences="@(WixLibrary)" |
392 | SearchPaths="$(WixLibrarySearchPaths)" | 388 | SearchPaths="$(WixLibrarySearchPaths)" |
393 | SearchFilenameExtensions=".wixlib" | 389 | SearchFilenameExtensions=".wixlib"> |
394 | Condition=" '@(WixLibrary)' != ''"> | 390 | <Output TaskParameter="ResolvedWixReferences" ItemName="_ResolvedWixLibraryPaths" /> |
395 | <Output TaskParameter="ResolvedWixReferences" ItemName="_AllResolvedWixLibraryPaths" /> | 391 | <Output TaskParameter="UnresolvedWixReferences" ItemName="_UnresolvedWixLibraryPaths" /> |
396 | </ResolveWixReferences> | 392 | </ResolveWixReferences> |
397 | |||
398 | <RemoveDuplicates Inputs="@(_AllResolvedWixLibraryPaths)"> | ||
399 | <Output TaskParameter="Filtered" ItemName="_ResolvedWixLibraryPaths" /> | ||
400 | </RemoveDuplicates> | ||
401 | </Target> | 393 | </Target> |
402 | 394 | ||
403 | <!-- | 395 | <!-- |
404 | ================================================================================================ | 396 | ================================================================================================ |
405 | ResolveWixExtensionReferences | 397 | ResolveWixExtensionReferences |
406 | 398 | ||
407 | Resolves WiX extension references to full paths. Any properties you use | 399 | Resolves WiX extension references to full paths. |
408 | to resolve paths to extensions must be defined before importing this | ||
409 | file or the extensions will be automatically resolved to $(WixExtDir). | ||
410 | 400 | ||
411 | By default the WixExtensionSearchPaths property is set to find extensions in the following order: | 401 | By default the WixExtensionSearchPaths property is set to find extensions in the following order: |
412 | 402 | ||
413 | (1) $(ReferencePaths) - the reference paths property, which comes from the .USER file. | 403 | (1) $(ReferencePaths) - the reference paths property. |
414 | (2) The hintpath from the referenced item itself, indicated by {HintPathFromItem}. | 404 | (2) The hintpath from the referenced item itself, indicated by {HintPathFromItem}. |
415 | (3) Treat the reference's Include as if it were a real file name. | 405 | (3) Treat the reference's Include as if it were a real file name. |
416 | (4) Path specified by the WixExtDir property. | ||
417 | 406 | ||
418 | [IN] | 407 | [IN] |
419 | @(WixExtension) - WixExtension item group | 408 | @(WixExtension) - WixExtension item group |
@@ -431,20 +420,16 @@ | |||
431 | Condition=" '@(WixExtension)' != ''"> | 420 | Condition=" '@(WixExtension)' != ''"> |
432 | 421 | ||
433 | <PropertyGroup> | 422 | <PropertyGroup> |
434 | <WixExtensionSearchPaths Condition=" '$(WixExtensionSearchPaths)' == '' ">$(ReferencePaths);{HintPathFromItem};{RawFileName};$(WixExtDir)</WixExtensionSearchPaths> | 423 | <WixExtensionSearchPaths Condition=" '$(WixExtensionSearchPaths)' == '' ">$(ReferencePaths);{HintPathFromItem};{RawFileName}</WixExtensionSearchPaths> |
435 | </PropertyGroup> | 424 | </PropertyGroup> |
436 | 425 | ||
437 | <ResolveWixReferences | 426 | <ResolveWixReferences |
438 | WixReferences="@(WixExtension)" | 427 | WixReferences="@(WixExtension)" |
439 | SearchPaths="$(WixExtensionSearchPaths)" | 428 | SearchPaths="$(WixExtensionSearchPaths)" |
440 | SearchFilenameExtensions=".wixext.dll"> | 429 | SearchFilenameExtensions=".wixext.dll"> |
441 | <Output TaskParameter="ResolvedWixReferences" ItemName="_AllResolvedWixExtensionPaths" /> | 430 | <Output TaskParameter="ResolvedWixReferences" ItemName="_ResolvedWixExtensionPaths" /> |
431 | <Output TaskParameter="UnresolvedWixReferences" ItemName="_UnresolvedWixExtensionPaths" /> | ||
442 | </ResolveWixReferences> | 432 | </ResolveWixReferences> |
443 | |||
444 | <!-- Remove duplicate extension items that would cause build errors --> | ||
445 | <RemoveDuplicates Inputs="@(_AllResolvedWixExtensionPaths)"> | ||
446 | <Output TaskParameter="Filtered" ItemName="_ResolvedWixExtensionPaths" /> | ||
447 | </RemoveDuplicates> | ||
448 | </Target> | 433 | </Target> |
449 | 434 | ||
450 | <!-- | 435 | <!-- |
@@ -599,7 +584,6 @@ | |||
599 | 584 | ||
600 | Cultures="%(CultureGroup.Identity)" | 585 | Cultures="%(CultureGroup.Identity)" |
601 | 586 | ||
602 | ExtensionDirectory="$(WixExtDir)" | ||
603 | Extensions="@(_ResolvedWixExtensionPaths)" | 587 | Extensions="@(_ResolvedWixExtensionPaths)" |
604 | 588 | ||
605 | IntermediateDirectory="$(IntermediateOutputPath)%(CultureGroup.OutputFolder)" | 589 | IntermediateDirectory="$(IntermediateOutputPath)%(CultureGroup.OutputFolder)" |
@@ -615,7 +599,6 @@ | |||
615 | InstallerPlatform="$(InstallerPlatform)" | 599 | InstallerPlatform="$(InstallerPlatform)" |
616 | NoLogo="true" | 600 | NoLogo="true" |
617 | Pedantic="$(Pedantic)" | 601 | Pedantic="$(Pedantic)" |
618 | ReferencePaths="$(ReferencePaths)" | ||
619 | 602 | ||
620 | BindInputPaths="@(LinkerBindInputPaths)" | 603 | BindInputPaths="@(LinkerBindInputPaths)" |
621 | BindFiles="$(BindFiles)" | 604 | BindFiles="$(BindFiles)" |
diff --git a/src/wix/test/WixToolsetTest.Sdk/MsbuildFixture.cs b/src/wix/test/WixToolsetTest.Sdk/MsbuildFixture.cs index 1201620b..c1fdd548 100644 --- a/src/wix/test/WixToolsetTest.Sdk/MsbuildFixture.cs +++ b/src/wix/test/WixToolsetTest.Sdk/MsbuildFixture.cs | |||
@@ -29,7 +29,7 @@ namespace WixToolsetTest.Sdk | |||
29 | var binFolder = Path.Combine(baseFolder, @"bin\"); | 29 | var binFolder = Path.Combine(baseFolder, @"bin\"); |
30 | var projectPath = Path.Combine(baseFolder, "SimpleBundle.wixproj"); | 30 | var projectPath = Path.Combine(baseFolder, "SimpleBundle.wixproj"); |
31 | 31 | ||
32 | var result = MsbuildUtilities.BuildProject(buildSystem, projectPath, new[] { | 32 | var result = MsbuildUtilities.BuildProject(buildSystem, projectPath, new[] { |
33 | MsbuildUtilities.GetQuotedPropertySwitch(buildSystem, "WixMSBuildProps", MsbuildFixture.WixPropsPath), | 33 | MsbuildUtilities.GetQuotedPropertySwitch(buildSystem, "WixMSBuildProps", MsbuildFixture.WixPropsPath), |
34 | "-p:SignOutput=true", | 34 | "-p:SignOutput=true", |
35 | }); | 35 | }); |
@@ -162,7 +162,7 @@ namespace WixToolsetTest.Sdk | |||
162 | var platformSwitches = result.Output.Where(line => line.Contains("-platform x86")); | 162 | var platformSwitches = result.Output.Where(line => line.Contains("-platform x86")); |
163 | Assert.Single(platformSwitches); | 163 | Assert.Single(platformSwitches); |
164 | 164 | ||
165 | var warnings = result.Output.Where(line => line.Contains(": warning")).Select(ExtractWarningFromMessage).ToArray(); | 165 | var warnings = result.Output.Where(line => line.Contains(": warning")).Select(line => ExtractWarningFromMessage(line, baseFolder)).ToArray(); |
166 | WixAssert.CompareLineByLine(new[] | 166 | WixAssert.CompareLineByLine(new[] |
167 | { | 167 | { |
168 | @"WIX1118: The variable 'Variable' with value 'DifferentValue' was previously declared with value 'Value'.", | 168 | @"WIX1118: The variable 'Variable' with value 'DifferentValue' was previously declared with value 'Value'.", |
@@ -173,7 +173,7 @@ namespace WixToolsetTest.Sdk | |||
173 | @"WIX1122: The installer database '<basefolder>\obj\x86\Release\en-US\MsiPackage.msi' has external cabs, but at least one of them is not signed. Please ensure that all external cabs are signed, if you mean to sign them. If you don't mean to sign them, there is no need to inscribe the MSI as part of your build." | 173 | @"WIX1122: The installer database '<basefolder>\obj\x86\Release\en-US\MsiPackage.msi' has external cabs, but at least one of them is not signed. Please ensure that all external cabs are signed, if you mean to sign them. If you don't mean to sign them, there is no need to inscribe the MSI as part of your build." |
174 | }, warnings); | 174 | }, warnings); |
175 | 175 | ||
176 | var testMessages = result.Output.Where(line => line.Contains("TEST:")).Select(ReplacePathsInMessage).ToArray(); | 176 | var testMessages = result.Output.Where(line => line.Contains("TEST:")).Select(line => ReplacePathsInMessage(line, baseFolder)).ToArray(); |
177 | WixAssert.CompareLineByLine(new[] | 177 | WixAssert.CompareLineByLine(new[] |
178 | { | 178 | { |
179 | @"TEST: SignCabs: <basefolder>\obj\x86\Release\en-US\cab1.cab", | 179 | @"TEST: SignCabs: <basefolder>\obj\x86\Release\en-US\cab1.cab", |
@@ -191,20 +191,6 @@ namespace WixToolsetTest.Sdk | |||
191 | @"bin\x86\Release\en-US\MsiPackage.wixpdb", | 191 | @"bin\x86\Release\en-US\MsiPackage.wixpdb", |
192 | }, paths); | 192 | }, paths); |
193 | } | 193 | } |
194 | |||
195 | string ExtractWarningFromMessage(string message) | ||
196 | { | ||
197 | const string prefix = ": warning "; | ||
198 | |||
199 | var start = message.IndexOf(prefix) + prefix.Length; | ||
200 | var end = message.LastIndexOf("["); | ||
201 | return ReplacePathsInMessage(message.Substring(start, end - start)); | ||
202 | } | ||
203 | |||
204 | string ReplacePathsInMessage(string message) | ||
205 | { | ||
206 | return message.Replace(baseFolder, "<basefolder>").Trim(); | ||
207 | } | ||
208 | } | 194 | } |
209 | 195 | ||
210 | [Theory] | 196 | [Theory] |
@@ -585,6 +571,46 @@ namespace WixToolsetTest.Sdk | |||
585 | } | 571 | } |
586 | } | 572 | } |
587 | 573 | ||
574 | |||
575 | [Theory] | ||
576 | [InlineData(BuildSystem.DotNetCoreSdk)] | ||
577 | [InlineData(BuildSystem.MSBuild)] | ||
578 | [InlineData(BuildSystem.MSBuild64)] | ||
579 | public void CanBuildWithWarningWhenExtensionIsMissing(BuildSystem buildSystem) | ||
580 | { | ||
581 | var sourceFolder = TestData.Get(@"TestData", "WixlibMissingExtension"); | ||
582 | |||
583 | using (var fs = new TestDataFolderFileSystem()) | ||
584 | { | ||
585 | fs.Initialize(sourceFolder); | ||
586 | var baseFolder = fs.BaseFolder; | ||
587 | var binFolder = Path.Combine(baseFolder, @"bin\"); | ||
588 | var projectPath = Path.Combine(baseFolder, "WixlibMissingExtension.wixproj"); | ||
589 | |||
590 | var result = MsbuildUtilities.BuildProject(buildSystem, projectPath, new[] { | ||
591 | MsbuildUtilities.GetQuotedPropertySwitch(buildSystem, "WixMSBuildProps", MsbuildFixture.WixPropsPath), | ||
592 | "-p:SignOutput=true", | ||
593 | }); | ||
594 | result.AssertSuccess(); | ||
595 | |||
596 | var warnings = result.Output.Where(line => line.Contains(": warning")).Select(line => ExtractWarningFromMessage(line, baseFolder)).ToArray(); | ||
597 | WixAssert.CompareLineByLine(new[] | ||
598 | { | ||
599 | "WXE0001: Unable to find extension DoesNotExist.wixext.dll.", | ||
600 | "WXE0001: Unable to find extension DoesNotExist.wixext.dll.", | ||
601 | }, warnings); | ||
602 | |||
603 | var paths = Directory.EnumerateFiles(binFolder, @"*.*", SearchOption.AllDirectories) | ||
604 | .Select(s => s.Substring(baseFolder.Length + 1)) | ||
605 | .OrderBy(s => s) | ||
606 | .ToArray(); | ||
607 | WixAssert.CompareLineByLine(new[] | ||
608 | { | ||
609 | @"bin\Release\WixlibMissingExtension.wixlib", | ||
610 | }, paths); | ||
611 | } | ||
612 | } | ||
613 | |||
588 | [Theory(Skip = "Depends on creating broken publish which is not supported at this time")] | 614 | [Theory(Skip = "Depends on creating broken publish which is not supported at this time")] |
589 | [InlineData(BuildSystem.DotNetCoreSdk)] | 615 | [InlineData(BuildSystem.DotNetCoreSdk)] |
590 | [InlineData(BuildSystem.MSBuild)] | 616 | [InlineData(BuildSystem.MSBuild)] |
@@ -610,5 +636,20 @@ namespace WixToolsetTest.Sdk | |||
610 | Assert.Contains(result.Output, m => m.Contains(expectedMessage)); | 636 | Assert.Contains(result.Output, m => m.Contains(expectedMessage)); |
611 | } | 637 | } |
612 | } | 638 | } |
639 | |||
640 | private static string ExtractWarningFromMessage(string message, string baseFolder) | ||
641 | { | ||
642 | const string prefix = ": warning "; | ||
643 | |||
644 | var start = message.IndexOf(prefix) + prefix.Length; | ||
645 | var end = message.LastIndexOf("["); | ||
646 | |||
647 | return ReplacePathsInMessage(message.Substring(start, end - start), baseFolder); | ||
648 | } | ||
649 | |||
650 | private static string ReplacePathsInMessage(string message, string baseFolder) | ||
651 | { | ||
652 | return message.Replace(baseFolder, "<basefolder>").Trim(); | ||
653 | } | ||
613 | } | 654 | } |
614 | } | 655 | } |
diff --git a/src/wix/test/WixToolsetTest.Sdk/TestData/WixlibMissingExtension/Library.wxs b/src/wix/test/WixToolsetTest.Sdk/TestData/WixlibMissingExtension/Library.wxs new file mode 100644 index 00000000..bcf79a1f --- /dev/null +++ b/src/wix/test/WixToolsetTest.Sdk/TestData/WixlibMissingExtension/Library.wxs | |||
@@ -0,0 +1,7 @@ | |||
1 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"> | ||
2 | <Fragment> | ||
3 | <StandardDirectory Id="ProgramFilesFolder"> | ||
4 | <Directory Id="WixLibFolder" /> | ||
5 | </StandardDirectory> | ||
6 | </Fragment> | ||
7 | </Wix> | ||
diff --git a/src/wix/test/WixToolsetTest.Sdk/TestData/WixlibMissingExtension/WixlibMissingExtension.wixproj b/src/wix/test/WixToolsetTest.Sdk/TestData/WixlibMissingExtension/WixlibMissingExtension.wixproj new file mode 100644 index 00000000..7a21c293 --- /dev/null +++ b/src/wix/test/WixToolsetTest.Sdk/TestData/WixlibMissingExtension/WixlibMissingExtension.wixproj | |||
@@ -0,0 +1,18 @@ | |||
1 | <?xml version="1.0" encoding="utf-8"?> | ||
2 | <Project> | ||
3 | <Import Project="$(WixMSBuildProps)" /> | ||
4 | |||
5 | <PropertyGroup> | ||
6 | <OutputType>Library</OutputType> | ||
7 | </PropertyGroup> | ||
8 | |||
9 | <ItemGroup> | ||
10 | <Compile Include="Library.wxs" /> | ||
11 | </ItemGroup> | ||
12 | |||
13 | <ItemGroup> | ||
14 | <WixExtension Include="DoesNotExist.wixext.dll" /> | ||
15 | </ItemGroup> | ||
16 | |||
17 | <Import Project="$(WixTargetsPath)" /> | ||
18 | </Project> | ||