File: FrameworkListReader.cs
Web Access
Project: ..\..\..\src\Tasks\Microsoft.NET.Build.Extensions.Tasks\Microsoft.NET.Build.Extensions.Tasks.csproj (Microsoft.NET.Build.Extensions.Tasks)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Globalization;
using System.Reflection;
using Microsoft.Build.Framework;
 
namespace Microsoft.NET.Build.Tasks.ConflictResolution
{
    class FrameworkListReader
    {
        private IBuildEngine4 _buildEngine;
 
        public FrameworkListReader(IBuildEngine4 buildEngine)
        {
            _buildEngine = buildEngine;
        }
 
        public IEnumerable<ConflictItem> GetConflictItems(string frameworkListPath, Logger log)
        {
            if (frameworkListPath == null)
            {
                throw new ArgumentNullException(nameof(frameworkListPath));
            }
 
            if (!Path.IsPathRooted(frameworkListPath))
            {
                throw new BuildErrorException(Strings.FrameworkListPathNotRooted, frameworkListPath);
            }
 
 
            //  Need to include assembly name in the key here, since both Microsoft.NET.Build.Tasks and Microsoft.NET.Build.Extensions.Tasks share this code,
            //  but can't share the types of the ConflictItem objects.
            string? assemblyName = typeof(FrameworkListReader).GetTypeInfo().Assembly.FullName;
 
            string objectKey = $"{assemblyName}:{nameof(FrameworkListReader)}:{frameworkListPath}";
 
            IEnumerable<ConflictItem> result;
 
            object existingConflictItems = _buildEngine.GetRegisteredTaskObject(objectKey, RegisteredTaskObjectLifetime.AppDomain);
 
            if (existingConflictItems == null)
            {
                result = LoadConflictItems(frameworkListPath, log);
 
                _buildEngine.RegisterTaskObject(objectKey, result, RegisteredTaskObjectLifetime.AppDomain, true);
            }
            else
            {
                result = (IEnumerable<ConflictItem>)existingConflictItems;
            }
 
            return result;
        }
 
        private static IEnumerable<ConflictItem> LoadConflictItems(string frameworkListPath, Logger log)
        {
            if (!File.Exists(frameworkListPath))
            {
                //  This is not an error, as we get both the root target framework directory as well as the Facades folder passed in as TargetFrameworkDirectories.
                //  Only the root will have a RedistList\FrameworkList.xml in it
                return Enumerable.Empty<ConflictItem>();
            }
 
            var frameworkList = XDocument.Load(frameworkListPath);
            var ret = new List<ConflictItem>();
            foreach (var file in frameworkList.Root?.Elements("File") ?? [])
            {
                var type = file.Attribute("Type")?.Value;
 
                if (type?.Equals("Analyzer", StringComparison.OrdinalIgnoreCase) ?? false)
                {
                    continue;
                }
 
                var assemblyName = file.Attribute("AssemblyName")?.Value;
                var assemblyVersionString = file.Attribute("Version")?.Value;
 
                if (string.IsNullOrEmpty(assemblyName))
                {
                    string errorMessage = string.Format(CultureInfo.CurrentCulture, Strings.ErrorParsingFrameworkListInvalidValue,
                        frameworkListPath,
                        "AssemblyName",
                        assemblyName);
                    log.LogError(errorMessage);
                    return Enumerable.Empty<ConflictItem>();
                }
 
                Version? assemblyVersion;
                if (string.IsNullOrEmpty(assemblyVersionString) || !Version.TryParse(assemblyVersionString, out assemblyVersion))
                {
                    string errorMessage = string.Format(CultureInfo.CurrentCulture, Strings.ErrorParsingFrameworkListInvalidValue,
                        frameworkListPath,
                        "Version",
                        assemblyVersionString);
                    log.LogError(errorMessage);
                    return Enumerable.Empty<ConflictItem>();
                }
 
                ret.Add(new ConflictItem(assemblyName + ".dll",
                                                packageId: "TargetingPack",
                                                assemblyVersion: assemblyVersion,
                                                fileVersion: null));
            }
 
            return ret;
        }
    }
}