|
// 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 Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using NuGet.Frameworks;
namespace Microsoft.NET.Build.Tasks
{
public class ResolveAppHosts : TaskBase
{
public string TargetFrameworkIdentifier { get; set; }
public string TargetFrameworkVersion { get; set; }
public string TargetingPackRoot { get; set; }
public string AppHostRuntimeIdentifier { get; set; }
public string[] OtherRuntimeIdentifiers { get; set; }
public string RuntimeFrameworkVersion { get; set; }
public ITaskItem[] PackAsToolShimRuntimeIdentifiers { get; set; } = Array.Empty<ITaskItem>();
/// <summary>
/// The file name of Apphost asset.
/// </summary>
[Required]
public string DotNetAppHostExecutableNameWithoutExtension { get; set; }
[Required]
public string DotNetSingleFileHostExecutableNameWithoutExtension { get; set; }
/// <summary>
/// The file name of comhost asset.
/// </summary>
[Required]
public string DotNetComHostLibraryNameWithoutExtension { get; set; }
/// <summary>
/// The file name of ijwhost asset.
/// </summary>
[Required]
public string DotNetIjwHostLibraryNameWithoutExtension { get; set; }
[Required]
public string RuntimeGraphPath { get; set; }
public ITaskItem[] KnownAppHostPacks { get; set; }
public bool NuGetRestoreSupported { get; set; } = true;
public string NetCoreTargetingPackRoot { get; set; }
public bool EnableAppHostPackDownload { get; set; } = true;
[Output]
public ITaskItem[] PackagesToDownload { get; set; }
// There should only be one AppHost item, but we use an item here so we can attach metadata to it
// (ie the apphost pack name and version, and the relative path to the apphost inside of it so
// we can resolve the full path later)
[Output]
public ITaskItem[] AppHost { get; set; }
[Output]
public ITaskItem[] SingleFileHost { get; set; }
[Output]
public ITaskItem[] ComHost { get; set; }
[Output]
public ITaskItem[] IjwHost { get; set; }
[Output]
public ITaskItem[] PackAsToolShimAppHostPacks { get; set; }
protected override void ExecuteCore()
{
var normalizedTargetFrameworkVersion = ProcessFrameworkReferences.NormalizeVersion(new Version(TargetFrameworkVersion));
var knownAppHostPacksForTargetFramework = KnownAppHostPacks
.Where(appHostPack =>
{
var packTargetFramework = NuGetFramework.Parse(appHostPack.GetMetadata("TargetFramework"));
return packTargetFramework.Framework.Equals(TargetFrameworkIdentifier, StringComparison.OrdinalIgnoreCase) &&
ProcessFrameworkReferences.NormalizeVersion(packTargetFramework.Version) == normalizedTargetFrameworkVersion;
})
.ToList();
if (knownAppHostPacksForTargetFramework.Count > 1)
{
throw new InvalidOperationException("Multiple KnownAppHostPack items applied to the specified target framework, which is not supposed to happen");
}
if (knownAppHostPacksForTargetFramework.Count == 0)
{
return;
}
var packagesToDownload = new Dictionary<string, string>();
if (!string.IsNullOrEmpty(AppHostRuntimeIdentifier))
{
var appHostItem = GetHostItem(
AppHostRuntimeIdentifier,
knownAppHostPacksForTargetFramework,
packagesToDownload,
DotNetAppHostExecutableNameWithoutExtension,
"AppHost",
isExecutable: true,
errorIfNotFound: true);
if (appHostItem != null)
{
AppHost = new ITaskItem[] { appHostItem };
}
var singlefileHostItem = GetHostItem(
AppHostRuntimeIdentifier,
knownAppHostPacksForTargetFramework,
packagesToDownload,
DotNetSingleFileHostExecutableNameWithoutExtension,
"SingleFileHost",
isExecutable: true,
errorIfNotFound: true);
if (singlefileHostItem != null)
{
SingleFileHost = new ITaskItem[] { singlefileHostItem };
}
var comHostItem = GetHostItem(
AppHostRuntimeIdentifier,
knownAppHostPacksForTargetFramework,
packagesToDownload,
DotNetComHostLibraryNameWithoutExtension,
"ComHost",
isExecutable: false,
errorIfNotFound: true);
if (comHostItem != null)
{
ComHost = new ITaskItem[] { comHostItem };
}
var ijwHostItem = GetHostItem(
AppHostRuntimeIdentifier,
knownAppHostPacksForTargetFramework,
packagesToDownload,
DotNetIjwHostLibraryNameWithoutExtension,
"IjwHost",
isExecutable: false,
errorIfNotFound: true);
if (ijwHostItem != null)
{
IjwHost = new ITaskItem[] { ijwHostItem };
}
}
if (PackAsToolShimRuntimeIdentifiers.Length > 0)
{
var packAsToolShimAppHostPacks = new List<ITaskItem>();
foreach (var runtimeIdentifier in PackAsToolShimRuntimeIdentifiers)
{
var appHostItem = GetHostItem(
runtimeIdentifier.ItemSpec,
knownAppHostPacksForTargetFramework,
packagesToDownload,
DotNetAppHostExecutableNameWithoutExtension,
"AppHost",
isExecutable: true,
errorIfNotFound: true);
if (appHostItem != null)
{
packAsToolShimAppHostPacks.Add(appHostItem);
}
}
PackAsToolShimAppHostPacks = packAsToolShimAppHostPacks.ToArray();
}
if (OtherRuntimeIdentifiers != null)
{
foreach (var otherRuntimeIdentifier in OtherRuntimeIdentifiers)
{
// The 'any' RID represents a platform-agnostic platform. As such, it has no
// apphost pack associated with it.
if (otherRuntimeIdentifier == "any")
{
continue;
}
// Download any apphost packages for other runtime identifiers.
// This allows you to specify the list of RIDs in RuntimeIdentifiers and only restore once,
// and then build for each RuntimeIdentifier without restoring separately.
// We discard the return value, and pass in some bogus data that won't be used, because
// we won't use the assets from the apphost pack in this build.
GetHostItem(otherRuntimeIdentifier,
knownAppHostPacksForTargetFramework,
packagesToDownload,
hostNameWithoutExtension: "unused",
itemName: "unused",
isExecutable: true,
errorIfNotFound: false);
}
}
if (packagesToDownload.Any())
{
PackagesToDownload = packagesToDownload.Select(ToPackageDownload).ToArray();
}
}
private ITaskItem ToPackageDownload(KeyValuePair<string, string> packageInformation)
{
var item = new TaskItem(packageInformation.Key);
item.SetMetadata(MetadataKeys.Version, packageInformation.Value);
return item;
}
private ITaskItem GetHostItem(string runtimeIdentifier,
List<ITaskItem> knownAppHostPacksForTargetFramework,
IDictionary<string, string> packagesToDownload,
string hostNameWithoutExtension,
string itemName,
bool isExecutable,
bool errorIfNotFound)
{
var selectedAppHostPack = knownAppHostPacksForTargetFramework.Single();
string appHostRuntimeIdentifiers = selectedAppHostPack.GetMetadata("AppHostRuntimeIdentifiers");
string appHostPackPattern = selectedAppHostPack.GetMetadata("AppHostPackNamePattern");
string appHostPackVersion = selectedAppHostPack.GetMetadata("AppHostPackVersion");
string runtimeIdentifiersToExclude = selectedAppHostPack.GetMetadata(MetadataKeys.ExcludedRuntimeIdentifiers);
if (!string.IsNullOrEmpty(RuntimeFrameworkVersion))
{
appHostPackVersion = RuntimeFrameworkVersion;
}
string bestAppHostRuntimeIdentifier = NuGetUtils.GetBestMatchingRidWithExclusion(
new RuntimeGraphCache(this).GetRuntimeGraph(RuntimeGraphPath),
runtimeIdentifier,
runtimeIdentifiersToExclude.Split(';'),
appHostRuntimeIdentifiers.Split(';'),
out bool wasInGraph);
if (bestAppHostRuntimeIdentifier == null)
{
if (wasInGraph)
{
// NETSDK1084: There was no app host for available for the specified RuntimeIdentifier '{0}'.
if (errorIfNotFound)
{
Log.LogError(Strings.NoAppHostAvailable, runtimeIdentifier);
}
else
{
Log.LogMessage(Strings.NoAppHostAvailable, runtimeIdentifier);
}
}
else
{
// NETSDK1083: The specified RuntimeIdentifier '{0}' is not recognized.
if (errorIfNotFound)
{
Log.LogError(Strings.RuntimeIdentifierNotRecognized, runtimeIdentifier);
}
else
{
Log.LogMessage(Strings.RuntimeIdentifierNotRecognized, runtimeIdentifier);
}
}
return null;
}
else
{
string hostPackName = appHostPackPattern.Replace("**RID**", bestAppHostRuntimeIdentifier);
string hostRelativePathInPackage = Path.Combine("runtimes", bestAppHostRuntimeIdentifier, "native",
hostNameWithoutExtension + (isExecutable ? ExecutableExtension.ForRuntimeIdentifier(bestAppHostRuntimeIdentifier) : ".dll"));
TaskItem appHostItem = new(itemName);
string appHostPackPath = null;
if (!string.IsNullOrEmpty(TargetingPackRoot))
{
appHostPackPath = Path.Combine(TargetingPackRoot, hostPackName, appHostPackVersion);
}
if (appHostPackPath != null && Directory.Exists(appHostPackPath))
{
// Use AppHost from packs folder
appHostItem.SetMetadata(MetadataKeys.PackageDirectory, appHostPackPath);
appHostItem.SetMetadata(MetadataKeys.Path, Path.Combine(appHostPackPath, hostRelativePathInPackage));
}
else if (EnableAppHostPackDownload)
{
// C++/CLI does not support package download && dedup error
if (!NuGetRestoreSupported && !packagesToDownload.ContainsKey(hostPackName))
{
Log.LogError(
Strings.TargetingApphostPackMissingCannotRestore,
"Apphost",
$"{NetCoreTargetingPackRoot}\\{hostPackName}",
selectedAppHostPack.GetMetadata("TargetFramework") ?? "",
hostPackName,
appHostPackVersion
);
}
// use the first one added
if (!packagesToDownload.ContainsKey(hostPackName))
{
packagesToDownload.Add(hostPackName, appHostPackVersion);
}
appHostItem.SetMetadata(MetadataKeys.NuGetPackageId, hostPackName);
appHostItem.SetMetadata(MetadataKeys.NuGetPackageVersion, appHostPackVersion);
}
appHostItem.SetMetadata(MetadataKeys.PathInPackage, hostRelativePathInPackage);
appHostItem.SetMetadata(MetadataKeys.RuntimeIdentifier, runtimeIdentifier);
return appHostItem;
}
}
}
}
|