Skip to content
Open
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
6 changes: 6 additions & 0 deletions src/dotnet-install.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -819,6 +819,12 @@ function Test-User-Write-Access([string]$InstallDir) {
function Is-Dotnet-Package-Installed([string]$InstallRoot, [string]$RelativePathToPackage, [string]$SpecificVersion) {
Say-Invocation $MyInvocation

# The Windows Desktop runtime package does not include the dotnet host.
if ($RelativePathToPackage.Replace('\', '/') -ne 'shared/Microsoft.WindowsDesktop.App' -and
-not (Test-Path (Join-Path -Path $InstallRoot -ChildPath 'dotnet.exe') -PathType Leaf)) {
return $false
}

$DotnetPackagePath = Join-Path -Path $InstallRoot -ChildPath $RelativePathToPackage | Join-Path -ChildPath $SpecificVersion
Say-Verbose "Is-Dotnet-Package-Installed: DotnetPackagePath=$DotnetPackagePath"
return Test-Path $DotnetPackagePath -PathType Container
Expand Down
2 changes: 1 addition & 1 deletion src/dotnet-install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -581,7 +581,7 @@ is_dotnet_package_installed() {
local dotnet_package_path="$(combine_paths "$(combine_paths "$install_root" "$relative_path_to_package")" "$specific_version")"
say_verbose "is_dotnet_package_installed: dotnet_package_path=$dotnet_package_path"

if [ -d "$dotnet_package_path" ]; then
if [ -d "$dotnet_package_path" ] && [ -f "$(combine_paths "$install_root" "dotnet")" ]; then
return 0
else
return 1
Expand Down
139 changes: 139 additions & 0 deletions tests/Install-Scripts.Test/PackageDetectionTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
// Copyright (c) Microsoft. All rights reserved.

using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using Xunit;

namespace Microsoft.DotNet.InstallationScript.Tests
{
public class PackageDetectionTests : IDisposable
{
private const string Version = "10.0.100";
private static readonly bool IsWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
private readonly string _testDir = Path.Combine(Path.GetTempPath(), nameof(PackageDetectionTests), Path.GetRandomFileName());

public PackageDetectionTests()
{
Directory.CreateDirectory(_testDir);
}

public void Dispose() => Directory.Delete(_testDir, recursive: true);

[Theory]
[InlineData("sdk", "missing", false)]
[InlineData("sdk", "file", true)]
[InlineData("sdk", "directory", false)]
[InlineData("shared/Microsoft.NETCore.App", "missing", false)]
[InlineData("shared/Microsoft.NETCore.App", "file", true)]
[InlineData("shared/Microsoft.NETCore.App", "directory", false)]
[InlineData("shared/Microsoft.AspNetCore.App", "missing", false)]
[InlineData("shared/Microsoft.AspNetCore.App", "file", true)]
[InlineData("shared/Microsoft.AspNetCore.App", "directory", false)]
public void InstalledPackageRequiresDotnetHost(string relativePath, string hostKind, bool expected)
{
Directory.CreateDirectory(Path.Combine(_testDir, relativePath, Version));
string hostPath = Path.Combine(_testDir, IsWindows ? "dotnet.exe" : "dotnet");
if (hostKind == "file")
{
File.WriteAllText(hostPath, "host");
}
else if (hostKind == "directory")
{
Directory.CreateDirectory(hostPath);
}

Assert.Equal(expected, IsPackageInstalled(relativePath));
}

[Fact]
public void DotnetHostWithoutPackageIsNotInstalled()
{
File.WriteAllText(Path.Combine(_testDir, IsWindows ? "dotnet.exe" : "dotnet"), "host");

Assert.False(IsPackageInstalled("sdk"));
}

[Fact]
public void WindowsDesktopRuntimeDoesNotRequireDotnetHost()
{
Assert.SkipUnless(IsWindows, "The Windows Desktop runtime is Windows-only.");
const string relativePath = "shared/Microsoft.WindowsDesktop.App";
Directory.CreateDirectory(Path.Combine(_testDir, relativePath, Version));

Assert.True(IsPackageInstalled(relativePath));
}

private bool IsPackageInstalled(string relativePath)
{
string? repoRoot = AppContext.BaseDirectory;
while (repoRoot != null &&
!Directory.Exists(Path.Combine(repoRoot, ".git")) &&
!File.Exists(Path.Combine(repoRoot, ".git")))
{
repoRoot = Directory.GetParent(repoRoot)?.FullName;
}
Assert.NotNull(repoRoot);

string extension = IsWindows ? "ps1" : "sh";
string source = File.ReadAllText(Path.Combine(repoRoot, "src", "dotnet-install." + extension));
string script;
if (IsWindows)
{
script = "param($InstallRoot, $RelativePath, $Version)\n" +
"$ErrorActionPreference = 'Stop'\n" +
"function Say-Invocation($invocation) {}\n" +
"function Say-Verbose($message) {}\n" +
ExtractFunction(source, @"function Is-Dotnet-Package-Installed\(") + "\n" +
"Is-Dotnet-Package-Installed $InstallRoot $RelativePath $Version\n";
}
else
{
script = "set -eu\ninvocation=':'\nsay_verbose() { :; }\n";
foreach (string name in new[] { "remove_trailing_slash", "remove_beginning_slash", "combine_paths", "is_dotnet_package_installed" })
{
script += ExtractFunction(source, name + @"\(\)") + "\n";
}
script += "if is_dotnet_package_installed \"$1\" \"$2\" \"$3\"; then echo True; else echo False; fi\n";
}

string scriptPath = Path.Combine(_testDir, "detect-package." + extension);
File.WriteAllText(scriptPath, script.Replace("\r\n", "\n"));
var startInfo = new ProcessStartInfo(IsWindows ? "powershell" : "/bin/bash")
{
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
};
if (IsWindows)
{
foreach (string argument in new[] { "-NoProfile", "-NoLogo", "-ExecutionPolicy", "Bypass", "-File" })
{
startInfo.ArgumentList.Add(argument);
}
}
foreach (string argument in new[] { scriptPath, _testDir, relativePath, Version })
{
startInfo.ArgumentList.Add(argument);
}

using var process = new Process { StartInfo = startInfo };
process.Start();
string stdout = process.StandardOutput.ReadToEnd();
string stderr = process.StandardError.ReadToEnd();
process.WaitForExit();
Assert.True(process.ExitCode == 0, $"StdOut: {stdout}\nStdErr: {stderr}");
return bool.Parse(stdout.Trim());
}

private static string ExtractFunction(string source, string declaration)
{
var match = Regex.Match(source, "(?ms)^" + declaration + ".+?^}");
Assert.True(match.Success, $"Could not find function matching '{declaration}'.");
return match.Value;
}
}
}