private static FrameworkInformation GetFrameworkInformation(DirectoryInfo directory, NuGetFramework targetFramework, string referenceAssembliesPath)
        {
            var frameworkInfo = new FrameworkInformation();

            frameworkInfo.Exists      = true;
            frameworkInfo.Path        = directory.FullName;
            frameworkInfo.SearchPaths = new[] {
                frameworkInfo.Path,
                Path.Combine(frameworkInfo.Path, "Facades")
            };

            PopulateFromRedistList(directory, targetFramework, referenceAssembliesPath, frameworkInfo);
            if (string.IsNullOrEmpty(frameworkInfo.Name))
            {
                frameworkInfo.Name = SynthesizeFrameworkFriendlyName(targetFramework);
            }
            return(frameworkInfo);
        }
        private static void PopulateFromRedistList(DirectoryInfo directory, NuGetFramework targetFramework, string referenceAssembliesPath, FrameworkInformation frameworkInfo)
        {
            // The redist list contains the list of assemblies for this target framework
            string redistList = Path.Combine(directory.FullName, "RedistList", "FrameworkList.xml");

            if (File.Exists(redistList))
            {
                frameworkInfo.RedistListPath = redistList;

                using (var stream = File.OpenRead(redistList))
                {
                    var frameworkList = XDocument.Load(stream);

                    // Remember the original search paths, because we might need them later
                    var originalSearchPaths = frameworkInfo.SearchPaths;

                    // There are some frameworks, that "inherit" from a base framework, like
                    // e.g. .NET 4.0.3, and MonoAndroid.
                    var includeFrameworkVersion = frameworkList.Root.Attribute("IncludeFramework")?.Value;
                    if (includeFrameworkVersion != null)
                    {
                        // Get the NuGetFramework identifier for the framework to include
                        var includeFramework = NuGetFramework.Parse($"{targetFramework.Framework}, Version={includeFrameworkVersion}");

                        // Recursively call the code to get the framework information
                        var includeFrameworkInfo = GetFrameworkInformation(includeFramework, referenceAssembliesPath);

                        // Append the search paths of the included framework
                        frameworkInfo.SearchPaths = frameworkInfo.SearchPaths.Concat(includeFrameworkInfo.SearchPaths).ToArray();

                        // Add the assemblies of the included framework
                        foreach (var assemblyEntry in includeFrameworkInfo.Assemblies)
                        {
                            frameworkInfo.Assemblies[assemblyEntry.Key] = assemblyEntry.Value;
                        }
                    }

                    // On mono, the RedistList.xml has an entry pointing to the TargetFrameworkDirectory
                    // It basically uses the GAC as the reference assemblies for all .NET framework
                    // profiles
                    var targetFrameworkDirectory = frameworkList.Root.Attribute("TargetFrameworkDirectory")?.Value;

                    IEnumerable <string> populateFromPaths;
                    if (!string.IsNullOrEmpty(targetFrameworkDirectory))
                    {
                        // For some odd reason, the paths are actually listed as \ so normalize them here
                        targetFrameworkDirectory = targetFrameworkDirectory.Replace('\\', Path.DirectorySeparatorChar);

                        // The specified path is the relative path from the RedistList.xml itself
                        var resovledPath = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(redistList), targetFrameworkDirectory));

                        // Update the path to the framework
                        frameworkInfo.Path = resovledPath;

                        populateFromPaths = new List <string>
                        {
                            resovledPath,
                            Path.Combine(resovledPath, "Facades")
                        };
                    }
                    else
                    {
                        var emptyFileElements = true;
                        foreach (var e in frameworkList.Root.Elements())
                        {
                            // Remember that we had at least one framework assembly
                            emptyFileElements = false;

                            var assemblyName = e.Attribute("AssemblyName").Value;
                            var version      = e.Attribute("Version")?.Value;

                            var entry = new AssemblyEntry();
                            entry.Version = version != null?Version.Parse(version) : null;

                            frameworkInfo.Assemblies[assemblyName] = entry;
                        }

                        if (emptyFileElements)
                        {
                            // When we haven't found any file elements, we probably processed a
                            // Mono/Xamarin FrameworkList.xml. That means, that we have to
                            // populate the assembly list from the files.
                            populateFromPaths = originalSearchPaths;
                        }
                        else
                        {
                            populateFromPaths = null;
                        }
                    }

                    // Do we need to populate from search paths?
                    if (populateFromPaths != null)
                    {
                        foreach (var populateFromPath in populateFromPaths)
                        {
                            PopulateAssemblies(frameworkInfo.Assemblies, populateFromPath);
                        }
                    }

                    var nameAttribute = frameworkList.Root.Attribute("Name");

                    frameworkInfo.Name = nameAttribute == null ? null : nameAttribute.Value;
                }
            }
        }
        private static FrameworkInformation GetLegacyFrameworkInformation(NuGetFramework targetFramework, string referenceAssembliesPath)
        {
            var frameworkInfo = new FrameworkInformation();

            // Always grab .NET 2.0 data
            var searchPaths = new List <string>();
            var net20Dir    = Path.Combine(Environment.GetEnvironmentVariable("WINDIR"), "Microsoft.NET", "Framework", "v2.0.50727");

            if (!Directory.Exists(net20Dir))
            {
                return(null);
            }

            // Grab reference assemblies first, if present for this framework
            if (targetFramework.Version.Major == 3)
            {
                // Most specific first (i.e. 3.5)
                if (targetFramework.Version.Minor == 5)
                {
                    var refAsms35Dir = Path.Combine(referenceAssembliesPath, "v3.5");
                    if (!string.IsNullOrEmpty(targetFramework.Profile))
                    {
                        // The 3.5 Client Profile assemblies ARE in .NETFramework... it's weird.
                        refAsms35Dir = Path.Combine(referenceAssembliesPath, ".NETFramework", "v3.5", "Profile", targetFramework.Profile);
                    }
                    if (Directory.Exists(refAsms35Dir))
                    {
                        searchPaths.Add(refAsms35Dir);
                    }
                }

                // Always search the 3.0 reference assemblies
                if (string.IsNullOrEmpty(targetFramework.Profile))
                {
                    // a) 3.0 didn't have profiles
                    // b) When using a profile, we don't want to fall back to 3.0 or 2.0
                    var refAsms30Dir = Path.Combine(referenceAssembliesPath, "v3.0");
                    if (Directory.Exists(refAsms30Dir))
                    {
                        searchPaths.Add(refAsms30Dir);
                    }
                }
            }

            // .NET 2.0 reference assemblies go last (but only if there's no profile in the TFM)
            if (string.IsNullOrEmpty(targetFramework.Profile))
            {
                searchPaths.Add(net20Dir);
            }

            frameworkInfo.Exists      = true;
            frameworkInfo.Path        = searchPaths.First();
            frameworkInfo.SearchPaths = searchPaths;

            // Load the redist list in reverse order (most general -> most specific)
            for (int i = searchPaths.Count - 1; i >= 0; i--)
            {
                var dir = new DirectoryInfo(searchPaths[i]);
                if (dir.Exists)
                {
                    PopulateFromRedistList(dir, targetFramework, referenceAssembliesPath, frameworkInfo);
                }
            }

            if (string.IsNullOrEmpty(frameworkInfo.Name))
            {
                frameworkInfo.Name = SynthesizeFrameworkFriendlyName(targetFramework);
            }
            return(frameworkInfo);
        }