public static List GetMSBuildOutputFiles()

in src/NuGet.Core/NuGet.Commands/RestoreCommand/Utility/BuildAssetsUtils.cs [434:718]


        public static List<MSBuildOutputFile> GetMSBuildOutputFiles(PackageSpec project,
            LockFile assetsFile,
            IEnumerable<RestoreTargetGraph> targetGraphs,
            IReadOnlyList<NuGetv3LocalRepository> repositories,
            RestoreRequest request,
            string assetsFilePath,
            bool restoreSuccess,
            ILogger log)
        {
            // Generate file names
            var targetsPath = GetMSBuildFilePath(project, TargetsExtension);
            var propsPath = GetMSBuildFilePath(project, PropsExtension);

            // Targets files contain a macro for the repository root. If only the user package folder was used
            // allow a replacement. If fallback folders were used the macro cannot be applied.
            // Do not use macros for fallback folders. Use only the first repository which is the user folder.
            var repositoryRoot = repositories[0].RepositoryRoot;

            // Invalid msbuild projects should write out an msbuild error target
            if (!targetGraphs.Any())
            {
                return GenerateMultiTargetFailureFiles(
                    targetsPath,
                    propsPath,
                    request.ProjectStyle);
            }

            // Add additional conditionals for multi targeting
            var multiTargetingFromMetadata = (request.Project.RestoreMetadata?.CrossTargeting == true);

            var isMultiTargeting = multiTargetingFromMetadata
                || request.Project.TargetFrameworks.Count > 1;

            // MultiTargeting imports are shared between TFMs, to avoid
            // duplicate import warnings only add each once.
            var multiTargetingImportsAdded = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

            var packagesWithTools = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
            for (int i = 0; i < assetsFile.Libraries.Count; ++i)
            {
                var library = assetsFile.Libraries[i];
                if (library.HasTools)
                {
                    packagesWithTools.Add(library.Name);
                }
            }

            // ItemGroups for each file.
            var props = new List<MSBuildRestoreItemGroup>();
            var targets = new List<MSBuildRestoreItemGroup>();
            foreach (var target in assetsFile.Targets)
            {
                // Skip runtime graphs, msbuild targets may not come from RID specific packages.
                if (!string.IsNullOrEmpty(target.RuntimeIdentifier))
                {
                    continue;
                }

                var ridlessTarget = target;

                var frameworkConditions = string.Format(
                        CultureInfo.InvariantCulture,
                        TargetFrameworkCondition,
                        GetMatchingFrameworkStrings(project, ridlessTarget.TargetFramework));

                // Find matching target in the original target graphs.
                RestoreTargetGraph targetGraph = null;
                foreach (RestoreTargetGraph graph in targetGraphs)
                {
                    if (string.IsNullOrEmpty(graph.RuntimeIdentifier) && ridlessTarget.TargetFramework == graph.Framework)
                    {
                        targetGraph = graph;
                        break;
                    }
                }

                // Sort by dependency order, child package assets should appear higher in the
                // msbuild targets and props files so that parents can depend on them.
                var sortedGraph = TopologicalSortUtility.SortPackagesByDependencyOrder(ConvertToPackageDependencyInfo(targetGraph.Flattened));

                // Filter out to packages only, exclude projects.
                var packageType = new HashSet<string>(
                    targetGraph.Flattened.Where(e => e.Key.Type == LibraryType.Package)
                        .Select(e => e.Key.Name),
                    StringComparer.OrdinalIgnoreCase);

                // Package -> PackageInfo
                // PackageInfo is kept lazy to avoid hitting the disk for packages
                // with no relevant assets.
                List<KeyValuePair<LockFileTargetLibrary, Lazy<LocalPackageSourceInfo>>> sortedPackages = new List<KeyValuePair<LockFileTargetLibrary, Lazy<LocalPackageSourceInfo>>>(sortedGraph.Count);

                foreach (PackageDependencyInfo sortedPkg in sortedGraph.NoAllocEnumerate())
                {
                    if (packageType.Contains(sortedPkg.Id))
                    {
                        foreach (LockFileTargetLibrary assetsPkg in ridlessTarget.Libraries.NoAllocEnumerate())
                        {
                            if (sortedPkg.Id.Equals(assetsPkg.Name, StringComparison.OrdinalIgnoreCase) && sortedPkg.Version == assetsPkg.Version)
                            {
                                var packageSourceInfo = new Lazy<LocalPackageSourceInfo>(() =>
                                                            NuGetv3LocalRepositoryUtility.GetPackage(
                                                                repositories,
                                                                sortedPkg.Id,
                                                                sortedPkg.Version));
                                sortedPackages.Add(new KeyValuePair<LockFileTargetLibrary, Lazy<LocalPackageSourceInfo>>(assetsPkg, packageSourceInfo));
                                break;
                            }
                        }
                    }
                }

                // build/ {packageId}.targets
                var buildTargetsGroup = GenerateBuildGroup(repositoryRoot, sortedPackages, TargetsExtension);
                targets.AddRange(GenerateGroupsWithConditions(buildTargetsGroup, isMultiTargeting, frameworkConditions));

                // props/ {packageId}.props
                MSBuildRestoreItemGroup buildPropsGroup = GenerateBuildGroup(repositoryRoot, sortedPackages, PropsExtension);
                props.AddRange(GenerateGroupsWithConditions(buildPropsGroup, isMultiTargeting, frameworkConditions));

                // Create an empty PropertyGroup for package properties
                var packagePathsPropertyGroup = MSBuildRestoreItemGroup.Create("PropertyGroup", 1000);
                if (isMultiTargeting)
                {
                    packagePathsPropertyGroup.Conditions.Add(frameworkConditions);
                }

                IEnumerable<string> packageIdsToCreatePropertiesFor = null;
                foreach (var projectGraph in targetGraph.Graphs)
                {
                    HashSet<string> packageSet = null;
                    foreach (var i in projectGraph.Item.Data.Dependencies)
                    {
                        // Packages with GeneratePathProperty=true
                        if (i.GeneratePathProperty)
                        {
                            packageSet ??= new HashSet<string>(StringComparer.OrdinalIgnoreCase);
                            packageSet.Add(i.Name);
                        }
                    }

                    packageIdsToCreatePropertiesFor = packageSet ?? Enumerable.Empty<string>();
                    break;
                }

                // Find the packages with matching IDs in the list of sorted packages, filtering out ones that there was no match for or that don't exist
                foreach (var sortedPackage in sortedPackages)
                {
                    var pkg = sortedPackage.Value;
                    if (pkg?.Value?.Package != null && (packagesWithTools.Contains(pkg.Value.Package.Id) || packageIdsToCreatePropertiesFor.Contains(pkg.Value.Package.Id)) && pkg.Exists())
                    {
                        // Get the property
                        packagePathsPropertyGroup.Items.Add(GeneratePackagePathProperty(pkg.Value.Package));
                    }
                }

                // Don't bother adding the PropertyGroup if there were no properties added
                if (packagePathsPropertyGroup.Items.Count > 0)
                {
                    props.Add(packagePathsPropertyGroup);
                }

                if (isMultiTargeting)
                {
                    // buildMultiTargeting/ {packageId}.targets
                    var buildCrossTargetsGroup = GenerateMultiTargetingGroup(repositoryRoot, sortedPackages, multiTargetingImportsAdded, TargetsExtension);
                    targets.AddRange(GenerateGroupsWithConditions(buildCrossTargetsGroup, isMultiTargeting, CrossTargetingCondition));

                    // buildMultiTargeting/ {packageId}.props
                    var buildCrossPropsGroup = GenerateMultiTargetingGroup(repositoryRoot, sortedPackages, multiTargetingImportsAdded, PropsExtension);
                    props.AddRange(GenerateGroupsWithConditions(buildCrossPropsGroup, isMultiTargeting, CrossTargetingCondition));
                }

                // Write out contentFiles only for XPlat PackageReference projects.
                if (request.ProjectStyle != ProjectStyle.ProjectJson
                    && request.Project.RestoreMetadata?.SkipContentFileWrite != true)
                {
                    // Create a group for every package, with the nearest from each of allLanguages
                    foreach (var pkg in sortedPackages)
                    {
                        var lockContentFiles = new List<LockFileContentFile>(pkg.Key.ContentFiles.Count);
                        foreach (var contentFile in pkg.Key.ContentFiles.NoAllocEnumerate())
                        {
                            if (pkg.Value.Exists())
                            {
                                lockContentFiles.Add(contentFile);
                            }
                        }

                        lockContentFiles.Sort(static (x, y) => StringComparer.Ordinal.Compare(x.Path, y.Path));

                        var currentItems = new List<(LockFileTargetLibrary, LockFileContentFile, string)>(lockContentFiles.Count);
                        foreach (var e in lockContentFiles)
                        {
                            var tuple = ValueTuple.Create(item1: pkg.Key, item2: e, item3: GetPathWithMacros(pkg.Value.GetAbsolutePath(e), repositoryRoot));
                            currentItems.Add(tuple);
                        }

                        foreach (var group in GetLanguageGroups(currentItems))
                        {
                            foreach (var item in GenerateGroupsWithConditions(group, isMultiTargeting, frameworkConditions))
                            {
                                props.Add(item);
                            }
                        }
                    }
                }
            }

            // Add exclude all condition to all groups
            foreach (var group in props)
            {
                group.Conditions.Add(ExcludeAllCondition);
            }

            foreach (var target in targets)
            {
                target.Conditions.Add(ExcludeAllCondition);
            }

            // Create XML, these may be null if the file should be deleted/not written out.
            var propsXML = GenerateMSBuildFile(props, request.ProjectStyle);
            var targetsXML = GenerateMSBuildFile(targets, request.ProjectStyle);

            // Return all files to write out or delete.
            var files = new List<MSBuildOutputFile>(capacity: 2)
            {
                new MSBuildOutputFile(propsPath, propsXML),
                new MSBuildOutputFile(targetsPath, targetsXML)
            };

            var packageFolders = repositories.Select(e => e.RepositoryRoot);

            AddNuGetPropertiesToFirstImport(files, packageFolders, repositoryRoot, request.ProjectStyle, assetsFilePath, restoreSuccess);

            return files;

            static MSBuildRestoreItemGroup GenerateBuildGroup(string repositoryRoot, List<KeyValuePair<LockFileTargetLibrary, Lazy<LocalPackageSourceInfo>>> sortedPackages, string extension)
            {
                var buildGroup = new MSBuildRestoreItemGroup();
                buildGroup.RootName = MSBuildRestoreItemGroup.ImportGroup;
                buildGroup.Position = 2;

                foreach (var pkg in sortedPackages)
                {
                    if (pkg.Value.Exists())
                    {
                        foreach (LockFileItem lockFileItem in pkg.Key.Build.WithExtension(extension))
                        {
                            var absolutePath = pkg.Value.GetAbsolutePath(lockFileItem);
                            var pathWithMacros = GetPathWithMacros(absolutePath, repositoryRoot);
                            var import = GenerateImport(pathWithMacros);
                            buildGroup.Items.Add(import);
                        }
                    }
                }

                return buildGroup;
            }

            static MSBuildRestoreItemGroup GenerateMultiTargetingGroup(string repositoryRoot, List<KeyValuePair<LockFileTargetLibrary, Lazy<LocalPackageSourceInfo>>> sortedPackages, HashSet<string> multiTargetingImportsAdded, string extension)
            {
                var buildCrossTargetsGroup = new MSBuildRestoreItemGroup();
                buildCrossTargetsGroup.RootName = MSBuildRestoreItemGroup.ImportGroup;
                buildCrossTargetsGroup.Position = 0;

                foreach (var pkg in sortedPackages)
                {
                    if (pkg.Value.Exists())
                    {
                        foreach (var e in pkg.Key.BuildMultiTargeting.WithExtension(extension))
                        {
                            var path = pkg.Value.GetAbsolutePath(e);
                            if (multiTargetingImportsAdded.Add(path))
                            {
                                var pathWithMacros = GetPathWithMacros(path, repositoryRoot);
                                var import = GenerateImport(pathWithMacros);
                                buildCrossTargetsGroup.Items.Add(import);
                            }
                        }
                    }
                }

                return buildCrossTargetsGroup;
            }
        }