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
117 changes: 0 additions & 117 deletions src/Tasks/Common/ProcessTaskEnvironmentDriver.cs

This file was deleted.

17 changes: 9 additions & 8 deletions src/Tasks/Common/TaskEnvironmentDefaults.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,24 @@
// Provides a default TaskEnvironment for single-threaded MSBuild execution.
// When MSBuild supports IMultiThreadableTask, it sets TaskEnvironment directly.
// This fallback ensures tasks work with older MSBuild versions that do not set it.
//
// Delegates to MSBuild's public TaskEnvironment.Fallback API
// (see https://github.com/dotnet/msbuild/pull/13462) so we no longer carry our
// own polyfill driver implementation.

#if NETFRAMEWORK

using System;

namespace Microsoft.Build.Framework
{
internal static class TaskEnvironmentDefaults
{
/// <summary>
/// Creates a default TaskEnvironment backed by the current process environment.
/// Uses Environment.CurrentDirectory as the project directory, which in single-threaded
/// MSBuild is set to the project directory before task execution.
/// Returns the MSBuild-provided fallback TaskEnvironment, which is backed by the
/// current process environment and uses Environment.CurrentDirectory as the project
/// directory.
/// </summary>
internal static TaskEnvironment Create() =>
new TaskEnvironment(new ProcessTaskEnvironmentDriver(Environment.CurrentDirectory));
internal static TaskEnvironment Create() => TaskEnvironment.Fallback;

Check failure on line 23 in src/Tasks/Common/TaskEnvironmentDefaults.cs

View check run for this annotation

Azure Pipelines / dotnet-sdk-public-ci (Build TestBuild: linux (arm64))

src/Tasks/Common/TaskEnvironmentDefaults.cs#L23

src/Tasks/Common/TaskEnvironmentDefaults.cs(23,69): error CS0117: (NETCORE_ENGINEERING_TELEMETRY=Build) 'TaskEnvironment' does not contain a definition for 'Fallback'

Check failure on line 23 in src/Tasks/Common/TaskEnvironmentDefaults.cs

View check run for this annotation

Azure Pipelines / dotnet-sdk-public-ci (Build TestBuild: linux (x64))

src/Tasks/Common/TaskEnvironmentDefaults.cs#L23

src/Tasks/Common/TaskEnvironmentDefaults.cs(23,69): error CS0117: (NETCORE_ENGINEERING_TELEMETRY=Build) 'TaskEnvironment' does not contain a definition for 'Fallback'

Check failure on line 23 in src/Tasks/Common/TaskEnvironmentDefaults.cs

View check run for this annotation

Azure Pipelines / dotnet-sdk-public-ci (Build TestBuild: macOS (x64))

src/Tasks/Common/TaskEnvironmentDefaults.cs#L23

src/Tasks/Common/TaskEnvironmentDefaults.cs(23,69): error CS0117: (NETCORE_ENGINEERING_TELEMETRY=Build) 'TaskEnvironment' does not contain a definition for 'Fallback'

Check failure on line 23 in src/Tasks/Common/TaskEnvironmentDefaults.cs

View check run for this annotation

Azure Pipelines / dotnet-sdk-public-ci (Build TestBuild: macOS (arm64))

src/Tasks/Common/TaskEnvironmentDefaults.cs#L23

src/Tasks/Common/TaskEnvironmentDefaults.cs(23,69): error CS0117: (NETCORE_ENGINEERING_TELEMETRY=Build) 'TaskEnvironment' does not contain a definition for 'Fallback'

Check failure on line 23 in src/Tasks/Common/TaskEnvironmentDefaults.cs

View check run for this annotation

Azure Pipelines / dotnet-sdk-public-ci (Build AoT: macOS (x64))

src/Tasks/Common/TaskEnvironmentDefaults.cs#L23

src/Tasks/Common/TaskEnvironmentDefaults.cs(23,69): error CS0117: (NETCORE_ENGINEERING_TELEMETRY=Build) 'TaskEnvironment' does not contain a definition for 'Fallback'

Check failure on line 23 in src/Tasks/Common/TaskEnvironmentDefaults.cs

View check run for this annotation

Azure Pipelines / dotnet-sdk-public-ci

src/Tasks/Common/TaskEnvironmentDefaults.cs#L23

src/Tasks/Common/TaskEnvironmentDefaults.cs(23,69): error CS0117: (NETCORE_ENGINEERING_TELEMETRY=Build) 'TaskEnvironment' does not contain a definition for 'Fallback'

Check failure on line 23 in src/Tasks/Common/TaskEnvironmentDefaults.cs

View check run for this annotation

Azure Pipelines / dotnet-sdk-public-ci

src/Tasks/Common/TaskEnvironmentDefaults.cs#L23

src/Tasks/Common/TaskEnvironmentDefaults.cs(23,69): error CS0117: (NETCORE_ENGINEERING_TELEMETRY=Build) 'TaskEnvironment' does not contain a definition for 'Fallback'

Check failure on line 23 in src/Tasks/Common/TaskEnvironmentDefaults.cs

View check run for this annotation

Azure Pipelines / dotnet-sdk-public-ci

src/Tasks/Common/TaskEnvironmentDefaults.cs#L23

src/Tasks/Common/TaskEnvironmentDefaults.cs(23,69): error CS0117: (NETCORE_ENGINEERING_TELEMETRY=Build) 'TaskEnvironment' does not contain a definition for 'Fallback'

Check failure on line 23 in src/Tasks/Common/TaskEnvironmentDefaults.cs

View check run for this annotation

Azure Pipelines / dotnet-sdk-public-ci

src/Tasks/Common/TaskEnvironmentDefaults.cs#L23

src/Tasks/Common/TaskEnvironmentDefaults.cs(23,69): error CS0117: (NETCORE_ENGINEERING_TELEMETRY=Build) 'TaskEnvironment' does not contain a definition for 'Fallback'
}
}

#endif
#endif
20 changes: 13 additions & 7 deletions src/Tasks/Microsoft.NET.Build.Tasks/ResolveAppHosts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@

namespace Microsoft.NET.Build.Tasks
{
public class ResolveAppHosts : TaskBase
[MSBuildMultiThreadableTask]
public class ResolveAppHosts : TaskBase, IMultiThreadableTask
{
public TaskEnvironment TaskEnvironment { get; set; } = null!;

public string TargetFrameworkIdentifier { get; set; }

public string TargetFrameworkVersion { get; set; }
Expand Down Expand Up @@ -287,16 +290,19 @@ private ITaskItem GetHostItem(string runtimeIdentifier,
hostNameWithoutExtension + (isExecutable ? ExecutableExtension.ForRuntimeIdentifier(bestAppHostRuntimeIdentifier) : ".dll"));

TaskItem appHostItem = new(itemName);
string appHostPackPath = null;

AbsolutePath? resolvedPackDirectory = null;

if (!string.IsNullOrEmpty(TargetingPackRoot))
{
appHostPackPath = Path.Combine(TargetingPackRoot, hostPackName, appHostPackVersion);
resolvedPackDirectory = TaskEnvironment.GetAbsolutePath(Path.Combine(TargetingPackRoot, hostPackName, appHostPackVersion));
}
if (appHostPackPath != null && Directory.Exists(appHostPackPath))

if (resolvedPackDirectory != null && Directory.Exists(resolvedPackDirectory.Value))
{
// Use AppHost from packs folder
appHostItem.SetMetadata(MetadataKeys.PackageDirectory, appHostPackPath);
appHostItem.SetMetadata(MetadataKeys.Path, Path.Combine(appHostPackPath, hostRelativePathInPackage));
// Use AppHost from packs folder. Use OriginalValue to preserve relativity in output metadata.
appHostItem.SetMetadata(MetadataKeys.PackageDirectory, resolvedPackDirectory.Value.OriginalValue);
appHostItem.SetMetadata(MetadataKeys.Path, Path.Combine(resolvedPackDirectory.Value.OriginalValue, hostRelativePathInPackage));
}
else if (EnableAppHostPackDownload)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#nullable disable

using System;
using System.Collections.Generic;
using System.IO;
using FluentAssertions;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using Xunit;

namespace Microsoft.NET.Build.Tasks.UnitTests
{
[CollectionDefinition(GivenAResolveAppHostsMultiThreading.CollectionName, DisableParallelization = true)]
public sealed class ResolveAppHostsCurrentDirectoryCollection
{
}

/// <summary>
/// Tests for ResolveAppHosts multi-threading support.
/// Verifies TaskEnvironment-based path resolution against ProjectDirectory (not process CWD)
/// and that output metadata preserves the original path form.
/// </summary>
[Collection(CollectionName)]
public class GivenAResolveAppHostsMultiThreading : IDisposable
{
internal const string CollectionName = "ResolveAppHosts current directory tests";
private const string PackName = "Microsoft.NETCore.App.Host.win-x64";
private const string PackVersion = "8.0.0";
private const string RuntimeGraphJson = "{ \"runtimes\": { \"win-x64\": { \"#import\": [] } } }";

private readonly string _testDir = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
private readonly string _decoyDir = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
private readonly string _originalCurrentDirectory = Directory.GetCurrentDirectory();

public GivenAResolveAppHostsMultiThreading()
{
Directory.CreateDirectory(_testDir);
Directory.CreateDirectory(_decoyDir);
Directory.SetCurrentDirectory(_decoyDir);
}

public void Dispose()
{
Directory.SetCurrentDirectory(_originalCurrentDirectory);
DeleteDirectory(_testDir);
DeleteDirectory(_decoyDir);
}

[Fact]
public void RelativeTargetingPackRoot_OutputMetadataRemainsRelative()
{
string relativePackRoot = "packs";
Directory.Exists(Path.Combine(_decoyDir, relativePackRoot)).Should().BeFalse(
"the process CWD must not contain the relative pack root, or CWD fallback regressions can pass");

string nativePath = Path.Combine(_testDir, relativePackRoot, PackName, PackVersion, "runtimes", "win-x64", "native");
CreateHostFiles(nativePath);

string runtimeGraphPath = Path.Combine(_testDir, "runtime.json");
File.WriteAllText(runtimeGraphPath, RuntimeGraphJson);

var task = CreateTask(
taskEnv: TaskEnvironmentHelper.CreateForTest(_testDir),
targetingPackRoot: relativePackRoot,
runtimeGraphPath: runtimeGraphPath);

task.Execute().Should().BeTrue();
Directory.GetCurrentDirectory().Should().Be(_decoyDir,
"ResolveAppHosts must not mutate process current directory");

string expectedPackDir = Path.Combine(relativePackRoot, PackName, PackVersion);
AssertRelativePackMetadata(task.AppHost, expectedPackDir, "apphost.exe");
AssertRelativePackMetadata(task.SingleFileHost, expectedPackDir, "singlefilehost.exe");
AssertRelativePackMetadata(task.ComHost, expectedPackDir, "comhost.dll");
AssertRelativePackMetadata(task.IjwHost, expectedPackDir, "ijwhost.dll");
}

private static void AssertRelativePackMetadata(ITaskItem[] hostItems, string expectedPackDir, string hostFileName)
{
hostItems.Should().NotBeNull().And.HaveCount(1);
string packageDirectory = hostItems[0].GetMetadata(MetadataKeys.PackageDirectory);
string path = hostItems[0].GetMetadata(MetadataKeys.Path);

packageDirectory.Should().Be(expectedPackDir);
Path.IsPathRooted(packageDirectory).Should().BeFalse();
path.Should().Be(Path.Combine(expectedPackDir, "runtimes", "win-x64", "native", hostFileName));
Path.IsPathRooted(path).Should().BeFalse();
}

private static ResolveAppHosts CreateTask(
TaskEnvironment taskEnv,
string targetingPackRoot,
string runtimeGraphPath)
{
var knownAppHostPacks = new ITaskItem[]
{
new TaskItem("Microsoft.NETCore.App.Host", new Dictionary<string, string>
{
{ "TargetFramework", "net8.0" },
{ "AppHostRuntimeIdentifiers", "win-x64" },
{ "AppHostPackNamePattern", "Microsoft.NETCore.App.Host.**RID**" },
{ "AppHostPackVersion", PackVersion },
{ MetadataKeys.ExcludedRuntimeIdentifiers, "" }
})
};

return new ResolveAppHosts
{
BuildEngine = new MockBuildEngine(),
TaskEnvironment = taskEnv,
TargetFrameworkIdentifier = ".NETCoreApp",
TargetFrameworkVersion = "8.0",
TargetingPackRoot = targetingPackRoot,
AppHostRuntimeIdentifier = "win-x64",
DotNetAppHostExecutableNameWithoutExtension = "apphost",
DotNetSingleFileHostExecutableNameWithoutExtension = "singlefilehost",
DotNetComHostLibraryNameWithoutExtension = "comhost",
DotNetIjwHostLibraryNameWithoutExtension = "ijwhost",
RuntimeGraphPath = runtimeGraphPath,
KnownAppHostPacks = knownAppHostPacks,
NuGetRestoreSupported = true,
EnableAppHostPackDownload = false,
};
}

private static void CreateHostFiles(string nativePath)
{
Directory.CreateDirectory(nativePath);
File.WriteAllText(Path.Combine(nativePath, "apphost.exe"), "fake apphost");
File.WriteAllText(Path.Combine(nativePath, "singlefilehost.exe"), "fake");
File.WriteAllText(Path.Combine(nativePath, "comhost.dll"), "fake");
File.WriteAllText(Path.Combine(nativePath, "ijwhost.dll"), "fake");
}

private static void DeleteDirectory(string path)
{
if (Directory.Exists(path))
{
Directory.Delete(path, recursive: true);
}
}
}
}
Loading
Loading