@joebigelow / wix / commits / 062d6387

Improve finding files relative to Core.Native assembly

Should fix unit testing issues when .cub files cannot be found.

Rob Mensching committed Mar 19, 2021 at 07:47 UTC 062d6387692d074f502176296f361c52026b96d5
3 files changed +84 -30
src/WixToolset.Core.Native/AssemblyExtensions.cs new
+70
@@ -0,0 +1,70 @@
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.Native
4 +{
5 + using System;
6 + using System.IO;
7 + using System.Reflection;
8 + using System.Text;
9 +
10 + internal static class AssemblyExtensions
11 + {
12 + internal static FindAssemblyRelativeFileResult FindFileRelativeToAssembly(this Assembly assembly, string relativePath, bool searchNativeDllDirectories)
13 + {
14 + // First try using the Assembly.Location. This works in almost all cases with
15 + // no side-effects.
16 + var path = Path.Combine(Path.GetDirectoryName(assembly.Location), relativePath);
17 + var possiblePaths = new StringBuilder(path);
18 +
19 + var found = File.Exists(path);
20 + if (!found)
21 + {
22 + // Fallback to the Assembly.CodeBase to handle "shadow copy" scenarios (like unit tests) but
23 + // only check codebase if it is different from the Assembly.Location path.
24 + var codebase = Path.Combine(Path.GetDirectoryName(new Uri(assembly.CodeBase).LocalPath), relativePath);
25 +
26 + if (!codebase.Equals(path, StringComparison.OrdinalIgnoreCase))
27 + {
28 + path = codebase;
29 + possiblePaths.Append(Path.PathSeparator + path);
30 +
31 + found = File.Exists(path);
32 + }
33 +
34 + if (!found && searchNativeDllDirectories && AppContext.GetData("NATIVE_DLL_SEARCH_DIRECTORIES") is string searchDirectoriesString)
35 + {
36 + // If instructed to search native DLL search directories, try to find our file there.
37 + possiblePaths.Append(Path.PathSeparator + searchDirectoriesString);
38 +
39 + var searchDirectories = searchDirectoriesString?.Split(Path.PathSeparator);
40 + foreach (var directoryPath in searchDirectories)
41 + {
42 + var possiblePath = Path.Combine(directoryPath, relativePath);
43 + if (File.Exists(possiblePath))
44 + {
45 + path = possiblePath;
46 + found = true;
47 + break;
48 + }
49 + }
50 + }
51 + }
52 +
53 + return new FindAssemblyRelativeFileResult
54 + {
55 + Found = found,
56 + Path = found ? path : null,
57 + PossiblePaths = possiblePaths.ToString()
58 + };
59 + }
60 +
61 + internal class FindAssemblyRelativeFileResult
62 + {
63 + public bool Found { get; set; }
64 +
65 + public string Path { get; set; }
66 +
67 + public string PossiblePaths { get; set; }
68 + }
69 + }
70 +}
src/WixToolset.Core.Native/WindowsInstallerValidator.cs
+10 -6
@@ -86,9 +86,6 @@ namespace WixToolset.Core.Native
86 var previousHwnd = IntPtr.Zero;
87 InstallUIHandler previousUIHandler = null;
88
89 - var baseCubePath = Path.Combine(Path.GetDirectoryName(typeof(WindowsInstallerValidator).Assembly.Location), CubesFolder);
90 - var cubeFiles = this.CubeFiles.Select(s => Path.Combine(baseCubePath, s)).ToList();
91 -
89 try
90 {
91 using (var database = new Database(this.DatabasePath, OpenDatabase.Direct))
@@ -116,11 +113,18 @@ namespace WixToolset.Core.Native
113 }
114
115 // Merge in the cube databases.
119 - foreach (var cubeFile in cubeFiles)
116 + foreach (var cubeFile in this.CubeFiles)
117 {
118 + var findCubeFile = typeof(WindowsInstallerValidator).Assembly.FindFileRelativeToAssembly(Path.Combine(CubesFolder, cubeFile), searchNativeDllDirectories: false);
119 +
120 + if (!findCubeFile.Found)
121 + {
122 + throw new WixException(ErrorMessages.CubeFileNotFound(findCubeFile.Path));
123 + }
124 +
125 try
126 {
123 - using (var cubeDatabase = new Database(cubeFile, OpenDatabase.ReadOnly))
127 + using (var cubeDatabase = new Database(findCubeFile.Path, OpenDatabase.ReadOnly))
128 {
129 try
130 {
@@ -136,7 +140,7 @@ namespace WixToolset.Core.Native
140 {
141 if (0x6E == e.NativeErrorCode) // ERROR_OPEN_FAILED
142 {
139 - throw new WixException(ErrorMessages.CubeFileNotFound(cubeFile));
143 + throw new WixException(ErrorMessages.CubeFileNotFound(findCubeFile.Path));
144 }
145
146 throw;
src/WixToolset.Core.Native/WixNativeExe.cs
+4 -24
@@ -7,7 +7,6 @@ namespace WixToolset.Core.Native
7 using System.ComponentModel;
8 using System.Diagnostics;
9 using System.IO;
10 - using System.Reflection;
10
11 internal class WixNativeExe
12 {
@@ -81,35 +80,16 @@ namespace WixToolset.Core.Native
80 {
81 if (String.IsNullOrEmpty(PathToWixNativeExe))
82 {
84 - var path = Path.Combine(Path.GetDirectoryName(new Uri(Assembly.GetExecutingAssembly().CodeBase).LocalPath), WixNativeExeFileName);
85 - var possiblePaths = path;
83 + var result = typeof(WixNativeExe).Assembly.FindFileRelativeToAssembly(WixNativeExeFileName, searchNativeDllDirectories: true);
84
87 - var found = File.Exists(path);
88 - if (!found && AppContext.GetData("NATIVE_DLL_SEARCH_DIRECTORIES") is string searchDirectoriesString)
89 - {
90 - possiblePaths = searchDirectoriesString;
91 - var separatorChar = Path.PathSeparator;
92 - var searchDirectories = searchDirectoriesString?.Split(separatorChar);
93 - foreach (var directoryPath in searchDirectories)
94 - {
95 - var possiblePath = Path.Combine(directoryPath, WixNativeExeFileName);
96 - if (File.Exists(possiblePath))
97 - {
98 - path = possiblePath;
99 - found = true;
100 - break;
101 - }
102 - }
103 - }
104 -
105 - if (!found)
85 + if (!result.Found)
86 {
87 throw new PlatformNotSupportedException(
88 $"Could not find platform specific '{WixNativeExeFileName}'",
109 - new FileNotFoundException($"Could not find internal piece of WiX Toolset from: {possiblePaths}", WixNativeExeFileName));
89 + new FileNotFoundException($"Could not find internal piece of WiX Toolset from: {result.PossiblePaths}", WixNativeExeFileName));
90 }
91
112 - PathToWixNativeExe = path;
92 + PathToWixNativeExe = result.Path;
93 }
94 }
95