<commit_before>// Copyright 2019 Maintainers of NUKE.
// Distributed under the MIT License.
// https://github.com/nuke-build/nuke/blob/master/LICENSE

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NuGet.Packaging;
using NuGet.Versioning;
using Nuke.Common.IO;
using Nuke.Common.Utilities;
using Nuke.Common.Utilities.Collections;

namespace Nuke.Common.Tooling
{
    [PublicAPI]
    public static class NuGetPackageResolver
    {
        private const int c_defaultTimeout = 2000;

        [ItemCanBeNull]
        public static async Task<string> GetLatestPackageVersion(string packageId, bool includePrereleases, int? timeout = null)
        {
            try
            {
                var url = $"https://api-v2v3search-0.nuget.org/query?q=packageid:{packageId}&prerelease={includePrereleases}";
                var response = await HttpTasks.HttpDownloadStringAsync(url, requestConfigurator: x => x.Timeout = timeout ?? c_defaultTimeout);
                var packageObject = JsonConvert.DeserializeObject<JObject>(response);
                return packageObject["data"].Single()["version"].ToString();
            }
            catch (Exception)
            {
                return null;
            }
        }

        [CanBeNull]
        public static InstalledPackage GetLocalInstalledPackage(
            string packageId,
            string packagesConfigFile,
            string version = null,
            bool resolveDependencies = false)
        {
            return GetLocalInstalledPackages(packagesConfigFile, resolveDependencies)
                .SingleOrDefaultOrError(
                    x => x.Id.EqualsOrdinalIgnoreCase(packageId) && (x.Version.ToString() == version || version == null),
                    $"Package '{packageId}' is referenced with multiple versions. Use NuGetPackageResolver and SetToolPath.");
        }

        // TODO: add HasLocalInstalledPackage() ?
        public static IEnumerable<InstalledPackage> GetLocalInstalledPackages(
            string packagesConfigFile,
            bool resolveDependencies = true)
        {
            return packagesConfigFile.EndsWithOrdinalIgnoreCase("json")
                ? GetLocalInstalledPackagesFromAssetsFile(packagesConfigFile, resolveDependencies)
                : GetLocalInstalledPackagesFromConfigFile(packagesConfigFile, resolveDependencies);
        }

        private static IEnumerable<InstalledPackage> GetLocalInstalledPackagesFromAssetsFile(
            string packagesConfigFile,
            bool resolveDependencies = true)
        {
            var assetsObject = SerializationTasks.JsonDeserializeFromFile<JObject>(packagesConfigFile);

            // ReSharper disable HeapView.BoxingAllocation
            var directReferences =
                assetsObject["project"]["frameworks"]
                    .Single().Single()["dependencies"]
                    ?.Children<JProperty>()
                    .Select(x => x.Name).ToList()
                ?? new List<string>();

            var allReferences =
                assetsObject["libraries"]
                    .Children<JProperty>()
                    .Where(x => x.Value["type"].ToString() == "package")
                    .Select(x => x.Name.Split('/'))
                    .Select(x => (PackageId: x.First(), Version: x.Last())).ToList();
            // ReSharper restore HeapView.BoxingAllocation

            foreach (var (name, version) in allReferences)
            {
                if (!resolveDependencies && !directReferences.Contains(name))
                    continue;

                yield return GetGlobalInstalledPackage(name, version, packagesConfigFile);
            }
        }

        private static IEnumerable<InstalledPackage> GetLocalInstalledPackagesFromConfigFile(
            string packagesConfigFile,
            bool resolveDependencies = true)
        {
            var packageIds = XmlTasks.XmlPeek(
                    packagesConfigFile,
                    IsLegacyFile(packagesConfigFile)
                        ? ".//package/@id"
                        : ".//*[local-name() = 'PackageReference' or local-name() = 'PackageDownload']/@Include")
                .Distinct();

            var installedPackages = new HashSet<InstalledPackage>(InstalledPackage.Comparer.Instance);
            foreach (var packageId in packageIds)
            {
                // TODO: use xml namespaces
                // TODO: version as tag
                var versions = XmlTasks.XmlPeek(
                    packagesConfigFile,
                    IsLegacyFile(packagesConfigFile)
                        ? $".//package[@id='{packageId}']/@version"
                        : $".//*[local-name() = 'PackageReference' or local-name() = 'PackageDownload'][@Include='{packageId}']/@Version");

                foreach (var version in versions)
                {
                    var packageData = GetGlobalInstalledPackage(packageId, version, packagesConfigFile);
                    if (packageData == null)
                        continue;

                    installedPackages.Add(packageData);
                    yield return packageData;
                }
            }

            if (resolveDependencies && !IsLegacyFile(packagesConfigFile))
            {
                var packagesToCheck = new Queue<InstalledPackage>(installedPackages);
                while (packagesToCheck.Any())
                {
                    var packageToCheck = packagesToCheck.Dequeue();

                    foreach (var dependentPackage in GetDependentPackages(packageToCheck, packagesConfigFile))
                    {
                        if (installedPackages.Contains(dependentPackage))
                            continue;<commit_msg>Fix NuGetPackageResolver to split version identifier<commit_after>// Copyright 2019 Maintainers of NUKE.
// Distributed under the MIT License.
// https://github.com/nuke-build/nuke/blob/master/LICENSE

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NuGet.Packaging;
using NuGet.Versioning;
using Nuke.Common.IO;
using Nuke.Common.Utilities;
using Nuke.Common.Utilities.Collections;

namespace Nuke.Common.Tooling
{
    [PublicAPI]
    public static class NuGetPackageResolver
    {
        private const int c_defaultTimeout = 2000;

        [ItemCanBeNull]
        public static async Task<string> GetLatestPackageVersion(string packageId, bool includePrereleases, int? timeout = null)
        {
            try
            {
                var url = $"https://api-v2v3search-0.nuget.org/query?q=packageid:{packageId}&prerelease={includePrereleases}";
                var response = await HttpTasks.HttpDownloadStringAsync(url, requestConfigurator: x => x.Timeout = timeout ?? c_defaultTimeout);
                var packageObject = JsonConvert.DeserializeObject<JObject>(response);
                return packageObject["data"].Single()["version"].ToString();
            }
            catch (Exception)
            {
                return null;
            }
        }

        [CanBeNull]
        public static InstalledPackage GetLocalInstalledPackage(
            string packageId,
            string packagesConfigFile,
            string version = null,
            bool resolveDependencies = false)
        {
            return GetLocalInstalledPackages(packagesConfigFile, resolveDependencies)
                .SingleOrDefaultOrError(
                    x => x.Id.EqualsOrdinalIgnoreCase(packageId) && (x.Version.ToString() == version || version == null),
                    $"Package '{packageId}' is referenced with multiple versions. Use NuGetPackageResolver and SetToolPath.");
        }

        // TODO: add HasLocalInstalledPackage() ?
        public static IEnumerable<InstalledPackage> GetLocalInstalledPackages(
            string packagesConfigFile,
            bool resolveDependencies = true)
        {
            return packagesConfigFile.EndsWithOrdinalIgnoreCase("json")
                ? GetLocalInstalledPackagesFromAssetsFile(packagesConfigFile, resolveDependencies)
                : GetLocalInstalledPackagesFromConfigFile(packagesConfigFile, resolveDependencies);
        }

        private static IEnumerable<InstalledPackage> GetLocalInstalledPackagesFromAssetsFile(
            string packagesConfigFile,
            bool resolveDependencies = true)
        {
            var assetsObject = SerializationTasks.JsonDeserializeFromFile<JObject>(packagesConfigFile);

            // ReSharper disable HeapView.BoxingAllocation
            var directReferences =
                assetsObject["project"]["frameworks"]
                    .Single().Single()["dependencies"]
                    ?.Children<JProperty>()
                    .Select(x => x.Name).ToList()
                ?? new List<string>();

            var allReferences =
                assetsObject["libraries"]
                    .Children<JProperty>()
                    .Where(x => x.Value["type"].ToString() == "package")
                    .Select(x => x.Name.Split('/'))
                    .Select(x => (PackageId: x.First(), Version: x.Last())).ToList();
            // ReSharper restore HeapView.BoxingAllocation

            foreach (var (name, version) in allReferences)
            {
                if (!resolveDependencies && !directReferences.Contains(name))
                    continue;

                yield return GetGlobalInstalledPackage(name, version, packagesConfigFile);
            }
        }

        private static IEnumerable<InstalledPackage> GetLocalInstalledPackagesFromConfigFile(
            string packagesConfigFile,
            bool resolveDependencies = true)
        {
            var packageIds = XmlTasks.XmlPeek(
                    packagesConfigFile,
                    IsLegacyFile(packagesConfigFile)
                        ? ".//package/@id"
                        : ".//*[local-name() = 'PackageReference' or local-name() = 'PackageDownload']/@Include")
                .Distinct();

            var installedPackages = new HashSet<InstalledPackage>(InstalledPackage.Comparer.Instance);
            foreach (var packageId in packageIds)
            {
                // TODO: use xml namespaces
                // TODO: version as tag
                var versions = XmlTasks.XmlPeek(
                        packagesConfigFile,
                        IsLegacyFile(packagesConfigFile)
                            ? $".//package[@id='{packageId}']/@version"
                            : $".//*[local-name() = 'PackageReference' or local-name() = 'PackageDownload'][@Include='{packageId}']/@Version")
                    .SelectMany(x => x.Split(';'));

                foreach (var version in versions)
                {
                    var packageData = GetGlobalInstalledPackage(packageId, version, packagesConfigFile);
                    if (packageData == null)
                        continue;

                    installedPackages.Add(packageData);
                    yield return packageData;
                }
            }

            if (resolveDependencies && !IsLegacyFile(packagesConfigFile))
            {
                var packagesToCheck = new Queue<InstalledPackage>(installedPackages);
                while (packagesToCheck.Any())
                {
                    var packageToCheck = packagesToCheck.Dequeue();

                    foreach (var dependentPackage in GetDependentPackages(packageToCheck, packagesConfigFile))
                    {
                        if (installedPackages.Contains(dependentPackage))
                            continue;
{'fraction_non_alphanumeric': 0.09119179694066229, 'fraction_numerical': 0.0018490502605479913, 'mean_word_length': 1.931510224193151, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 38, 'https://': 4, 'lorem ipsum': 0, 'www.': 0, 'xml': 2}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '249039', 'n_tokens_mistral': 2914, 'n_tokens_neox': 2721, 'n_words': 570}