Skip to content

Fix single file publish #2088

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Feb 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,7 @@
<PackageReference Include="Microsoft.AspNetCore" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.2.0" />
</ItemGroup>
<Target Name="testCertCheck" BeforeTargets="BeforeBuild" Condition="!Exists('testCert.cer')" >
<Error Text="Follow https://github.com/hardkoded/puppeteer-sharp/blob/master/CONTRIBUTING.md#getting-setup to setup a development certificate." />
</Target>
</Project>
9 changes: 9 additions & 0 deletions lib/PuppeteerSharp.Tests.SingleFileDeployment/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using PuppeteerSharp;

Console.WriteLine($"AppDomain.BaseDirectory: {AppContext.BaseDirectory}");
using var browserFetcher = new BrowserFetcher();
await browserFetcher.DownloadAsync();
await using var browser = await Puppeteer.LaunchAsync(new LaunchOptions { Headless = true });
await using var page = await browser.NewPageAsync();
await page.GoToAsync("http://www.google.com");
await page.ScreenshotAsync("google.jpg");
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<LangVersion>10</LangVersion>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\PuppeteerSharp\PuppeteerSharp.csproj" />
</ItemGroup>

</Project>
18 changes: 18 additions & 0 deletions lib/PuppeteerSharp.Tests/Attributes/SkipNonWindowsFact.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System.Runtime.InteropServices;
using Xunit;

namespace PuppeteerSharp.Tests.Attributes
{
internal class SkipNonWindowsFact : FactAttribute
{
public SkipNonWindowsFact()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
return;
}

Skip = "Test will only run on windows.";
}
}
}
8 changes: 4 additions & 4 deletions lib/PuppeteerSharp.Tests/JSHandleTests/ClickTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,12 @@ await Page.ExposeFunctionAsync("reportClick", (int x, int y) =>
await TestUtils.ShortWaitForCollectionToHaveAtLeastNElementsAsync(clicks, 2);

// margin + middle point offset
Assert.Equal(clicks[0].X, 45 + 60);
Assert.Equal(clicks[0].Y, 45 + 30);
Assert.Equal(45 + 60, clicks[0].X);
Assert.Equal(45 + 30, clicks[0].Y);

// margin + offset
Assert.Equal(clicks[1].X, 30 + 10);
Assert.Equal(clicks[1].Y, 30 + 15);
Assert.Equal(30 + 10, clicks[1].X);
Assert.Equal(30 + 15, clicks[1].Y);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
using System.Diagnostics;
using System.IO;
using System.Threading.Tasks;
using PuppeteerSharp.Tests.Attributes;
using Xunit;

namespace PuppeteerSharp.Tests.SingleFileDeployment
{
public class PublishSingleFileTests
{
[SkipNonWindowsFact]
public void ShouldWork()
{
var tempPath = Path.GetTempPath();
var actualFilePath = Path.Combine(tempPath, $"google.jpg");
var actualWindowsBinary = DotnetPublishSingleFile("PuppeteerSharp.Tests.SingleFileDeployment");

DeleteIfExists(actualFilePath);

using var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = actualWindowsBinary,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true,
WorkingDirectory = tempPath
}
};

process.Start();
var outputResult = GetStreamOutput(process.StandardOutput);
var errorResult = GetStreamOutput(process.StandardError);
var isExited = process.WaitForExit(80000);

if (!isExited)
{
process.Kill();
}

Assert.True(isExited);

Assert.True(File.Exists(actualFilePath), $"StdOut: {outputResult}\nStdErr: {errorResult}\n");
}

private static string GetStreamOutput(StreamReader stream)
{
var outputReadTask = Task.Run(() => stream.ReadToEnd());

return outputReadTask.Result;
}

private static string DotnetPublishSingleFile(string projectName)
{
var absolutePath = Path.GetFullPath(Path.Combine("../../../../", projectName));
var expectedBinaryPath = Path.Combine(absolutePath, $"publish/{projectName}.exe");

DeleteIfExists(expectedBinaryPath);

using var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "dotnet",
Arguments = $"publish {absolutePath} --configuration Release -p:PublishSingleFile=true --self-contained false --use-current-runtime -o ./publish",
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true,
WorkingDirectory = absolutePath
}
};
process.Start();

var outputResult = GetStreamOutput(process.StandardOutput);
var errorResult = GetStreamOutput(process.StandardError);
Assert.True(process.WaitForExit(20000));

Assert.Empty(errorResult);

Assert.True(File.Exists(expectedBinaryPath), outputResult);

return expectedBinaryPath;
}

private static void DeleteIfExists(string actualFilePath)
{
if (File.Exists(actualFilePath))
{
File.Delete(actualFilePath);
}
}
}
}
7 changes: 3 additions & 4 deletions lib/PuppeteerSharp.Tests/PuppeteerSharp.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,18 @@
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
<PackageReference Include="Mono.Posix.NETStandard" Version="1.0.0" />
<PackageReference Include="System.Net.Http" Version="4.3.4" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.4" />
<PackageReference Include="Microsoft.AspNetCore.Connections.Abstractions" Version="2.2.0" />
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="6.0.0-preview.2.21154.6" />
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="7.0.0" />
</ItemGroup>
<Import Project="../Common/SignAssembly.props" />
<ItemGroup>
<Folder Include="Issues\" />
<Folder Include="Attributes\" />
<Folder Include="ClickTests\" />
<Folder Include="KeyboardTests\" />
<Folder Include="MouseTests\" />
Expand Down
2 changes: 1 addition & 1 deletion lib/PuppeteerSharp.Tooling/PuppeteerSharp.Tooling.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<PackageReference Include="Microsoft.Extensions.Primitives" Version="5.0.0" />
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="1.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="xunit.core" Version="2.4.1" />
<PackageReference Include="xunit.core" Version="2.4.2" />
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0" />
<PackageReference Include="Mono.Posix.NETStandard" Version="1.0.0" />
</ItemGroup>
Expand Down
2 changes: 1 addition & 1 deletion lib/PuppeteerSharp.Xunit/PuppeteerSharp.Xunit.csproj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks Condition="'$(OS)' == 'Windows_NT' ">net48;net6.0</TargetFrameworks>
Expand Down
15 changes: 10 additions & 5 deletions lib/PuppeteerSharp.sln
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30404.54
# Visual Studio Version 17
VisualStudioVersion = 17.4.33205.214
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PuppeteerSharp", "PuppeteerSharp\PuppeteerSharp.csproj", "{19B9B1ED-AF6C-4DAF-8B73-401570111F88}"
EndProject
Expand All @@ -22,9 +21,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
stylecop.json = stylecop.json
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PuppeteerSharp.Xunit", "PuppeteerSharp.Xunit\PuppeteerSharp.Xunit.csproj", "{EE53767C-D321-4BCF-B372-57949F38AB40}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PuppeteerSharp.Xunit", "PuppeteerSharp.Xunit\PuppeteerSharp.Xunit.csproj", "{EE53767C-D321-4BCF-B372-57949F38AB40}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PuppeteerSharp.Tooling", "PuppeteerSharp.Tooling\PuppeteerSharp.Tooling.csproj", "{912C1F21-9306-4D6B-A487-47A8FC793E6D}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PuppeteerSharp.Tooling", "PuppeteerSharp.Tooling\PuppeteerSharp.Tooling.csproj", "{912C1F21-9306-4D6B-A487-47A8FC793E6D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PuppeteerSharp.Tests.SingleFileDeployment", "PuppeteerSharp.Tests.SingleFileDeployment\PuppeteerSharp.Tests.SingleFileDeployment.csproj", "{CB0DB076-60FE-48A1-925A-7C1BC566D3CE}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down Expand Up @@ -60,6 +61,10 @@ Global
{912C1F21-9306-4D6B-A487-47A8FC793E6D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{912C1F21-9306-4D6B-A487-47A8FC793E6D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{912C1F21-9306-4D6B-A487-47A8FC793E6D}.Release|Any CPU.Build.0 = Release|Any CPU
{CB0DB076-60FE-48A1-925A-7C1BC566D3CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CB0DB076-60FE-48A1-925A-7C1BC566D3CE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CB0DB076-60FE-48A1-925A-7C1BC566D3CE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CB0DB076-60FE-48A1-925A-7C1BC566D3CE}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
42 changes: 30 additions & 12 deletions lib/PuppeteerSharp/BrowserFetcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ public class BrowserFetcher : IBrowserFetcher
/// </summary>
public const string DefaultChromiumRevision = "1069273";

private const string PublishSingleFileLocalApplicationDataFolderName = "PuppeteerSharp";

private static readonly Dictionary<Product, string> _hosts = new Dictionary<Product, string>
{
[Product.Chrome] = "https://storage.googleapis.com",
Expand Down Expand Up @@ -127,11 +129,14 @@ public static string GetExecutablePath(Product product, Platform platform, strin
"Contents",
"MacOS",
"Chromium");

case Platform.Linux:
return Path.Combine(folderPath, GetArchiveName(product, platform, revision), "chrome");

case Platform.Win32:
case Platform.Win64:
return Path.Combine(folderPath, GetArchiveName(product, platform, revision), "chrome.exe");

default:
throw new ArgumentException("Invalid platform", nameof(platform));
}
Expand All @@ -147,11 +152,14 @@ public static string GetExecutablePath(Product product, Platform platform, strin
"Contents",
"MacOS",
"firefox");

case Platform.Linux:
return Path.Combine(folderPath, "firefox", "firefox");

case Platform.Win32:
case Platform.Win64:
return Path.Combine(folderPath, "firefox", "firefox.exe");

default:
throw new ArgumentException("Invalid platform", nameof(platform));
}
Expand Down Expand Up @@ -347,26 +355,29 @@ internal static Platform GetCurrentPlatform()

internal static string GetExecutablePath()
{
var assembly = typeof(Puppeteer).Assembly;
var assemblyName = assembly.GetName().Name + ".dll";
DirectoryInfo assemblyDirectory = new(AppContext.BaseDirectory);
if (!assemblyDirectory.Exists || !File.Exists(Path.Combine(assemblyDirectory.FullName, "PuppeteerSharp.dll")))

if (!assemblyDirectory.Exists || !File.Exists(Path.Combine(assemblyDirectory.FullName, assemblyName)))
{
string assemblyLocation;
var assembly = typeof(Puppeteer).Assembly;
#pragma warning disable SYSLIB0012 // 'Assembly.CodeBase' is obsolete: 'Assembly.CodeBase and Assembly.EscapedCodeBase are only included for .NET Framework compatibility.
if (Uri.TryCreate(assembly.CodeBase, UriKind.Absolute, out var codeBase) && codeBase.IsFile)
#pragma warning restore SYSLIB0012 // 'Assembly.CodeBase' is obsolete: 'Assembly.CodeBase and Assembly.EscapedCodeBase are only included for .NET Framework compatibility.
{
assemblyLocation = codeBase.LocalPath;
}
else
var assemblyLocation = assembly.Location;

if (string.IsNullOrEmpty(assemblyLocation))
{
assemblyLocation = assembly.Location;
var singleFilePublishFilePathForBrowserExecutables = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), PublishSingleFileLocalApplicationDataFolderName);
if (!Directory.Exists(singleFilePublishFilePathForBrowserExecutables))
{
Directory.CreateDirectory(singleFilePublishFilePathForBrowserExecutables);
}

return singleFilePublishFilePathForBrowserExecutables;
}

assemblyDirectory = new FileInfo(assemblyLocation).Directory;
}

if (!assemblyDirectory.Exists || !File.Exists(Path.Combine(assemblyDirectory.FullName, "PuppeteerSharp.dll")))
if (!assemblyDirectory.Exists || !File.Exists(Path.Combine(assemblyDirectory.FullName, assemblyName)))
{
assemblyDirectory = new DirectoryInfo(Directory.GetCurrentDirectory());
}
Expand Down Expand Up @@ -401,11 +412,14 @@ private static string GetArchiveName(Product product, Platform platform, string
{
case Platform.Linux:
return "chrome-linux";

case Platform.MacOS:
return "chrome-mac";

case Platform.Win32:
case Platform.Win64:
return int.TryParse(revision, out var revValue) && revValue > 591479 ? "chrome-win" : "chrome-win32";

default:
throw new ArgumentException("Invalid platform", nameof(platform));
}
Expand All @@ -416,12 +430,16 @@ private static string GetArchiveName(Product product, Platform platform, string
{
case Platform.Linux:
return "linux";

case Platform.MacOS:
return "mac";

case Platform.Win32:
return "win32";

case Platform.Win64:
return "win64";

default:
throw new ArgumentException("Invalid platform", nameof(platform));
}
Expand Down