Skip to content

Commit f6ddd3f

Browse files
authored
[dotnet] Re-pack Selenium Manager as native dependency (#16048)
To automatically exclude unnecessary Selenium Manager binaries if runtime platform is known via "RuntimeIdentifier" build property. New paths in the package: - runtimes/win/native/selenium-manager.exe - runtimes/linux/native/selenium-manager - runtimes/osx/native/selenium-manager
1 parent cafa762 commit f6ddd3f

File tree

11 files changed

+181
-121
lines changed

11 files changed

+181
-121
lines changed

dotnet/src/webdriver/BUILD.bazel

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -162,21 +162,21 @@ csharp_library(
162162
)
163163

164164
copy_file(
165-
name = "readme",
166-
src = "//dotnet/src/webdriver/assets:README.md",
165+
name = "assets-nuget-readme",
166+
src = "//dotnet/src/webdriver/assets:nuget/README.md",
167167
out = "README.md",
168168
)
169169

170170
copy_file(
171-
name = "props",
172-
src = "//dotnet/src/webdriver/assets:Selenium.WebDriver.targets",
171+
name = "assets-nuget-build-netstandard20-targets",
172+
src = "//dotnet/src/webdriver/assets:nuget/build/netstandard2.0/Selenium.WebDriver.targets",
173173
out = "Selenium.WebDriver.targets",
174174
)
175175

176176
copy_file(
177-
name = "transitive-props",
178-
src = "//dotnet/src/webdriver/assets:Selenium.WebDriver.targets",
179-
out = "transitive.Selenium.WebDriver.targets",
177+
name = "assets-nuget-buildtransitive-netstandard20-targets",
178+
src = "//dotnet/src/webdriver/assets:nuget/buildTransitive/netstandard2.0/Selenium.WebDriver.targets",
179+
out = "transitiveSelenium.WebDriver.targets",
180180
)
181181

182182
copy_file(
@@ -207,9 +207,9 @@ nuget_pack(
207207
"//common/manager:selenium-manager-linux": "manager/linux/selenium-manager",
208208
"//common/manager:selenium-manager-macos": "manager/macos/selenium-manager",
209209
"//common/manager:selenium-manager-windows": "manager/windows/selenium-manager.exe",
210-
":readme": "README.md",
211-
":props": "build/Selenium.WebDriver.targets",
212-
":transitive-props": "buildTransitive/Selenium.WebDriver.targets",
210+
":assets-nuget-readme": "README.md",
211+
":assets-nuget-build-netstandard20-targets": "build/netstandard2.0/Selenium.WebDriver.targets",
212+
":assets-nuget-buildtransitive-netstandard20-targets": "buildTransitive/netstandard2.0/Selenium.WebDriver.targets",
213213
},
214214
id = "Selenium.WebDriver",
215215
libs = {
@@ -233,9 +233,9 @@ nuget_pack(
233233
"//common/manager:selenium-manager-linux": "manager/linux/selenium-manager",
234234
"//common/manager:selenium-manager-macos": "manager/macos/selenium-manager",
235235
"//common/manager:selenium-manager-windows": "manager/windows/selenium-manager.exe",
236-
":readme": "README.md",
237-
":props": "build/Selenium.WebDriver.StrongNamed.targets",
238-
":transitive-props": "buildTransitive/Selenium.WebDriver.StrongNamed.targets",
236+
":assets-nuget-readme": "README.md",
237+
":assets-nuget-build-netstandard20-targets": "build/netstandard2.0/Selenium.WebDriver.StrongNamed.targets",
238+
":assets-nuget-buildtransitive-netstandard20-targets": "buildTransitive/netstandard2.0/Selenium.WebDriver.StrongNamed.targets",
239239
},
240240
id = "Selenium.WebDriver.StrongNamed",
241241
libs = {

dotnet/src/webdriver/Selenium.WebDriver.StrongNamed.nuspec

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,12 @@
4343
<file src="lib/net8.0/WebDriver.StrongNamed.pdb" target="lib/net8.0/WebDriver.StrongNamed.pdb" />
4444
<file src="lib/net8.0/WebDriver.StrongNamed.xml" target="lib/net8.0/WebDriver.StrongNamed.xml" />
4545

46-
<file src="build/Selenium.WebDriver.StrongNamed.targets" target="build/Selenium.WebDriver.StrongNamed.targets"/>
47-
<file src="buildTransitive/Selenium.WebDriver.StrongNamed.targets" target="buildTransitive/Selenium.WebDriver.StrongNamed.targets"/>
46+
<file src="build/netstandard2.0/Selenium.WebDriver.StrongNamed.targets" target="build/netstandard2.0/Selenium.WebDriver.StrongNamed.targets"/>
47+
<file src="buildTransitive/netstandard2.0/Selenium.WebDriver.StrongNamed.targets" target="buildTransitive/netstandard2.0/Selenium.WebDriver.StrongNamed.targets"/>
4848

49-
<file src="manager/linux/selenium-manager" target="manager/linux/selenium-manager" />
50-
<file src="manager/macos/selenium-manager" target="manager/macos/selenium-manager" />
51-
<file src="manager/windows/selenium-manager.exe" target="manager/windows/selenium-manager.exe" />
49+
<file src="manager/linux/selenium-manager" target="runtimes/linux/native/selenium-manager" />
50+
<file src="manager/macos/selenium-manager" target="runtimes/osx/native/selenium-manager" />
51+
<file src="manager/windows/selenium-manager.exe" target="runtimes/win/native/selenium-manager.exe" />
5252

5353
<file src="icon.png" />
5454
<file src="README.md" />

dotnet/src/webdriver/Selenium.WebDriver.csproj

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@
4343
<GenerateDocumentationFile>true</GenerateDocumentationFile>
4444
</PropertyGroup>
4545

46+
<PropertyGroup>
47+
<BaseSeleniumManagerPath>$(MSBuildThisFileDirectory)..\..\..\bazel-bin\dotnet\src\webdriver\manager</BaseSeleniumManagerPath>
48+
</PropertyGroup>
49+
4650
<!--TODO when AOT is ready https://github.com/SeleniumHQ/selenium/issues/14480-->
4751
<!--<PropertyGroup Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net8.0'))">
4852
<IsAotCompatible>true</IsAotCompatible>
@@ -56,29 +60,25 @@
5660
<PackageReference Include="System.Text.Json" Version="8.0.5" />
5761
</ItemGroup>
5862

59-
<PropertyGroup>
60-
<BaseImagePath>..\..\..\bazel-bin\dotnet\src\webdriver\images</BaseImagePath>
61-
</PropertyGroup>
62-
6363
<ItemGroup>
64-
<None Include="assets\Selenium.WebDriver.targets" Pack="true" PackagePath="build\" />
65-
<None Include="assets\Selenium.WebDriver.targets" Pack="true" PackagePath="buildTransitive\" />
66-
67-
<None Include="$(BaseImagePath)\selenium_logo_small.png" Pack="true" PackagePath="logo.png" Visible="false" />
68-
69-
<None Include="$(BaseSeleniumManagerPath)\linux\selenium-manager" Pack="true" PackagePath="manager\linux" Visible="false" />
70-
<None Include="$(BaseSeleniumManagerPath)\macos\selenium-manager" Pack="true" PackagePath="manager\macos" Visible="false" />
71-
<None Include="$(BaseSeleniumManagerPath)\windows\selenium-manager.exe" Pack="true" PackagePath="manager\windows" Visible="false" />
64+
<None Include="assets\nuget\build\netstandard2.0\Selenium.WebDriver.targets" Pack="true" PackagePath="build\netstandard2.0\" />
65+
<None Include="assets\nuget\buildTransitive\netstandard2.0\Selenium.WebDriver.targets" Pack="true" PackagePath="buildTransitive\netstandard2.0\" />
7266
</ItemGroup>
7367

7468
<Target Name="GenerateSeleniumManagerBinaries" BeforeTargets="BeforeBuild">
7569
<Exec Command="bazel build //dotnet/src/webdriver:manager-linux //dotnet/src/webdriver:manager-windows //dotnet/src/webdriver:manager-macos" WorkingDirectory="../../.." />
76-
77-
<PropertyGroup>
78-
<BaseSeleniumManagerPath>..\..\..\bazel-bin\dotnet\src\webdriver\manager</BaseSeleniumManagerPath>
79-
</PropertyGroup>
8070
</Target>
8171

72+
<ItemGroup>
73+
<None Include="$(BaseSeleniumManagerPath)\linux\selenium-manager" Pack="true" PackagePath="runtimes\linux\native\" Visible="false" CopyToOutputDirectory="PreserveNewest" Link="runtimes\linux\native\selenium-manager" />
74+
<None Include="$(BaseSeleniumManagerPath)\macos\selenium-manager" Pack="true" PackagePath="runtimes\osx\native\" Visible="false" CopyToOutputDirectory="PreserveNewest" Link="runtimes\osx\native\selenium-manager" />
75+
<None Include="$(BaseSeleniumManagerPath)\windows\selenium-manager.exe" Pack="true" PackagePath="runtimes\win\native\" Visible="false" CopyToOutputDirectory="PreserveNewest" Link="runtimes\win\native\selenium-manager.exe" />
76+
</ItemGroup>
77+
78+
<ItemGroup>
79+
<None Include="..\..\..\common\images\selenium_logo_small.png" Pack="true" PackagePath="logo.png" Visible="false" />
80+
</ItemGroup>
81+
8282
<Target Name="GenerateAtoms" BeforeTargets="BeforeBuild">
8383
<Exec Command="bazel build //javascript/webdriver/atoms:get-attribute.js //javascript/atoms/fragments:is-displayed.js //javascript/atoms/fragments:find-elements.js" WorkingDirectory="../../.." />
8484

@@ -114,4 +114,4 @@
114114
</ItemGroup>
115115
</Target>
116116

117-
</Project>
117+
</Project>

dotnet/src/webdriver/Selenium.WebDriver.nuspec

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,12 @@
4343
<file src="lib/net8.0/WebDriver.pdb" target="lib/net8.0/WebDriver.pdb" />
4444
<file src="lib/net8.0/WebDriver.xml" target="lib/net8.0/WebDriver.xml" />
4545

46-
<file src="build/Selenium.WebDriver.targets" target="build/Selenium.WebDriver.targets"/>
47-
<file src="buildTransitive/Selenium.WebDriver.targets" target="buildTransitive/Selenium.WebDriver.targets"/>
46+
<file src="build/netstandard2.0/Selenium.WebDriver.targets" target="build/netstandard2.0/Selenium.WebDriver.targets"/>
47+
<file src="buildTransitive/netstandard2.0/Selenium.WebDriver.targets" target="buildTransitive/netstandard2.0/Selenium.WebDriver.targets"/>
4848

49-
<file src="manager/linux/selenium-manager" target="manager/linux/selenium-manager" />
50-
<file src="manager/macos/selenium-manager" target="manager/macos/selenium-manager" />
51-
<file src="manager/windows/selenium-manager.exe" target="manager/windows/selenium-manager.exe" />
49+
<file src="manager/linux/selenium-manager" target="runtimes/linux/native/selenium-manager" />
50+
<file src="manager/macos/selenium-manager" target="runtimes/osx/native/selenium-manager" />
51+
<file src="manager/windows/selenium-manager.exe" target="runtimes/win/native/selenium-manager.exe" />
5252

5353
<file src="icon.png" />
5454
<file src="README.md" />

dotnet/src/webdriver/SeleniumManager.cs

Lines changed: 105 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
using System.Collections.Generic;
2323
using System.Diagnostics;
2424
using System.IO;
25+
using System.Linq;
2526
using System.Runtime.InteropServices;
2627
using System.Text;
2728
using System.Text.Json;
@@ -41,56 +42,120 @@ public static class SeleniumManager
4142

4243
private static readonly ILogger _logger = Log.GetLogger(typeof(SeleniumManager));
4344

45+
// This logic to find Selenium Manager binary is complex and strange.
46+
// As soon as Selenium Manager will be real native library (dll ,so, dynlib),
47+
// we will be able to use it directly from the .NET bindings, and this logic will be removed.
4448
private static readonly Lazy<string> _lazyBinaryFullPath = new(() =>
4549
{
4650
string? binaryFullPath = Environment.GetEnvironmentVariable("SE_MANAGER_PATH");
47-
if (binaryFullPath == null)
48-
{
49-
SupportedPlatform? platform = null;
5051

51-
#if NET8_0_OR_GREATER
52-
if (OperatingSystem.IsWindows())
53-
{
54-
platform = SupportedPlatform.Windows;
55-
}
56-
else if (OperatingSystem.IsLinux() || OperatingSystem.IsFreeBSD())
57-
{
58-
platform = SupportedPlatform.Linux;
59-
}
60-
else if (OperatingSystem.IsMacOS() || OperatingSystem.IsMacCatalyst())
52+
if (binaryFullPath is not null)
53+
{
54+
if (!File.Exists(binaryFullPath))
6155
{
62-
platform = SupportedPlatform.MacOS;
56+
throw new FileNotFoundException($"Unable to locate provided Selenium Manager binary at '{binaryFullPath}'.");
6357
}
58+
59+
return binaryFullPath;
60+
}
61+
62+
SupportedPlatform? platform = null;
63+
64+
#if NET8_0_OR_GREATER
65+
if (OperatingSystem.IsWindows())
66+
{
67+
platform = SupportedPlatform.Windows;
68+
}
69+
else if (OperatingSystem.IsLinux() || OperatingSystem.IsFreeBSD())
70+
{
71+
platform = SupportedPlatform.Linux;
72+
}
73+
else if (OperatingSystem.IsMacOS() || OperatingSystem.IsMacCatalyst())
74+
{
75+
platform = SupportedPlatform.MacOS;
76+
}
6477
#else
65-
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
66-
{
67-
platform = SupportedPlatform.Windows;
68-
}
69-
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
70-
{
71-
platform = SupportedPlatform.Linux;
72-
}
73-
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
74-
{
75-
platform = SupportedPlatform.MacOS;
76-
}
78+
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
79+
{
80+
platform = SupportedPlatform.Windows;
81+
}
82+
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
83+
{
84+
platform = SupportedPlatform.Linux;
85+
}
86+
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
87+
{
88+
platform = SupportedPlatform.MacOS;
89+
}
7790
#endif
7891

79-
var currentDirectory = AppContext.BaseDirectory;
92+
var seleniumManagerFileName = platform switch
93+
{
94+
SupportedPlatform.Windows => "selenium-manager.exe",
95+
SupportedPlatform.Linux => "selenium-manager",
96+
SupportedPlatform.MacOS => "selenium-manager",
97+
_ => throw new PlatformNotSupportedException(
98+
$"Selenium Manager doesn't support your runtime platform: {RuntimeInformation.OSDescription}"),
99+
};
100+
101+
var baseDirectory = AppContext.BaseDirectory;
80102

81-
binaryFullPath = platform switch
103+
List<string> probingPaths = [];
104+
105+
if (baseDirectory is not null)
106+
{
107+
probingPaths.Add(Path.Combine(baseDirectory, seleniumManagerFileName));
108+
109+
switch (platform)
82110
{
83-
SupportedPlatform.Windows => Path.Combine(currentDirectory, "selenium-manager", "windows", "selenium-manager.exe"),
84-
SupportedPlatform.Linux => Path.Combine(currentDirectory, "selenium-manager", "linux", "selenium-manager"),
85-
SupportedPlatform.MacOS => Path.Combine(currentDirectory, "selenium-manager", "macos", "selenium-manager"),
86-
_ => throw new PlatformNotSupportedException(
87-
$"Selenium Manager doesn't support your runtime platform: {RuntimeInformation.OSDescription}"),
88-
};
111+
case SupportedPlatform.Windows:
112+
probingPaths.Add(Path.Combine(baseDirectory, "runtimes", "win", "native", seleniumManagerFileName));
113+
break;
114+
case SupportedPlatform.Linux:
115+
probingPaths.Add(Path.Combine(baseDirectory, "runtimes", "linux", "native", seleniumManagerFileName));
116+
break;
117+
case SupportedPlatform.MacOS:
118+
probingPaths.Add(Path.Combine(baseDirectory, "runtimes", "osx", "native", seleniumManagerFileName));
119+
break;
120+
}
89121
}
90122

91-
if (!File.Exists(binaryFullPath))
123+
// Supporting .NET5+ applications deployed as bundled applications (single file or AOT).
124+
// In this case bootstrapper extracts the native libraries into a temporary directory.
125+
// Most interesting build properties: "IncludeNativeLibrariesForSelfExtract" and "IncludeAllContentForSelfExtract".
126+
var nativeDllSearchDirectories = AppContext.GetData("NATIVE_DLL_SEARCH_DIRECTORIES")?.ToString();
127+
128+
if (nativeDllSearchDirectories is not null)
92129
{
93-
throw new WebDriverException($"Unable to locate or obtain Selenium Manager binary at {binaryFullPath}");
130+
probingPaths.AddRange(nativeDllSearchDirectories.Split(new char[] { Path.PathSeparator }, StringSplitOptions.RemoveEmptyEntries).Select(path => Path.Combine(path, seleniumManagerFileName)));
131+
}
132+
133+
// Covering the case when the application is hosted by another application, most likely
134+
// we can find Selenium Manager in the assembly location, because "AppContext.BaseDirectory"
135+
// might return the path of the host application.
136+
var assemblyDirectory = Path.GetDirectoryName(typeof(SeleniumManager).Assembly.Location);
137+
138+
if (assemblyDirectory is not null)
139+
{
140+
probingPaths.Add(Path.Combine(assemblyDirectory, seleniumManagerFileName));
141+
}
142+
143+
probingPaths = [.. probingPaths.Distinct()];
144+
145+
binaryFullPath = probingPaths.FirstOrDefault(File.Exists);
146+
147+
if (binaryFullPath is null)
148+
{
149+
var messageBuilder = new StringBuilder();
150+
messageBuilder.AppendFormat("Selenium Manager binary '{0}' was not found in the following paths:", seleniumManagerFileName);
151+
152+
foreach (var probingPath in probingPaths)
153+
{
154+
messageBuilder.AppendLine();
155+
messageBuilder.AppendFormat(" - {0}", probingPath);
156+
}
157+
158+
throw new FileNotFoundException(messageBuilder.ToString());
94159
}
95160

96161
return binaryFullPath;
@@ -113,7 +178,7 @@ public static Dictionary<string, string> BinaryPaths(string arguments)
113178
argsBuilder.Append(" --debug");
114179
}
115180

116-
var smCommandResult = RunCommand(_lazyBinaryFullPath.Value, argsBuilder.ToString());
181+
var smCommandResult = RunCommand(argsBuilder.ToString());
117182
Dictionary<string, string> binaryPaths = new()
118183
{
119184
{ BrowserPathKey, smCommandResult.BrowserPath },
@@ -132,12 +197,11 @@ public static Dictionary<string, string> BinaryPaths(string arguments)
132197
/// <summary>
133198
/// Executes a process with the given arguments.
134199
/// </summary>
135-
/// <param name="fileName">The path to the Selenium Manager.</param>
136200
/// <param name="arguments">The switches to be used by Selenium Manager.</param>
137201
/// <returns>
138202
/// the standard output of the execution.
139203
/// </returns>
140-
private static ResultResponse RunCommand(string fileName, string arguments)
204+
private static ResultResponse RunCommand(string arguments)
141205
{
142206
Process process = new Process();
143207
process.StartInfo.FileName = _lazyBinaryFullPath.Value;
@@ -171,7 +235,7 @@ private static ResultResponse RunCommand(string fileName, string arguments)
171235
{
172236
// We do not log any warnings coming from Selenium Manager like the other bindings, as we don't have any logging in the .NET bindings
173237

174-
var exceptionMessageBuilder = new StringBuilder($"Selenium Manager process exited abnormally with {process.ExitCode} code: {fileName} {arguments}");
238+
var exceptionMessageBuilder = new StringBuilder($"Selenium Manager process exited abnormally with {process.ExitCode} code: {process.StartInfo.FileName} {arguments}");
175239

176240
if (!string.IsNullOrWhiteSpace(errorOutputBuilder.ToString()))
177241
{
@@ -194,7 +258,7 @@ private static ResultResponse RunCommand(string fileName, string arguments)
194258
}
195259
catch (Exception ex)
196260
{
197-
throw new WebDriverException($"Error starting process: {fileName} {arguments}", ex);
261+
throw new WebDriverException($"Error starting process: {process.StartInfo.FileName} {arguments}", ex);
198262
}
199263
finally
200264
{
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
exports_files([
2-
"README.md",
3-
"Selenium.WebDriver.targets",
2+
"nuget/README.md",
3+
"nuget/build/netstandard2.0/Selenium.WebDriver.targets",
4+
"nuget/buildTransitive/netstandard2.0/Selenium.WebDriver.targets",
45
])

dotnet/src/webdriver/assets/Selenium.WebDriver.targets

Lines changed: 0 additions & 31 deletions
This file was deleted.
File renamed without changes.

0 commit comments

Comments
 (0)