File: RestoreCommand\RequestFactory\RestoreArgs.cs
Web Access
Project: src\src\nuget-client\src\NuGet.Core\NuGet.Commands\NuGet.Commands.csproj (NuGet.Commands)
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

#nullable disable

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using NuGet.Common;
using NuGet.Configuration;
using NuGet.Packaging;
using NuGet.ProjectModel;
using NuGet.Protocol;
using NuGet.Protocol.Core.Types;

namespace NuGet.Commands
{
    public class RestoreArgs
    {
        public string ConfigFile { get; set; }

        public IMachineWideSettings MachineWideSettings { get; set; }

        public string GlobalPackagesFolder { get; set; }

        public bool DisableParallel { get; set; }

        public bool AllowNoOp { get; set; }

        public HashSet<string> Runtimes { get; set; } = new HashSet<string>(StringComparer.Ordinal);

        public HashSet<string> FallbackRuntimes { get; set; } = new HashSet<string>(StringComparer.Ordinal);

        public List<string> Inputs { get; set; } = new List<string>();

        public SourceCacheContext CacheContext { get; set; }

        public ILogger Log { get; set; }

        /// <summary>
        /// Sources to use for restore. This is not used if SourceRepositories contains the 
        /// already built SourceRepository objects.
        /// </summary>
        public List<string> Sources { get; set; } = new List<string>();

        public CachingSourceProvider CachingSourceProvider { get; set; }

        public List<IRestoreRequestProvider> RequestProviders { get; set; } = new List<IRestoreRequestProvider>();

        public List<IPreLoadedRestoreRequestProvider> PreLoadedRequestProviders { get; set; } = new List<IPreLoadedRestoreRequestProvider>();

        public PackageSaveMode PackageSaveMode { get; set; } = PackageSaveMode.Defaultv3;

        public bool? ValidateRuntimeAssets { get; set; }

        public bool HideWarningsAndErrors { get; set; } = false;

        public Guid ParentId { get; set; }

        public bool IsRestoreOriginalAction { get; set; } = true;

        public bool RestoreForceEvaluate { get; set; }

        /// <summary>
        /// Messages that should be written to the assets file, in addition to any messages generated during the restore.
        /// </summary>
        public IReadOnlyList<IAssetsLogMessage> AdditionalMessages { get; set; }

        public IRestoreProgressReporter ProgressReporter { get; set; }

        // Cache directory -> ISettings
        private ConcurrentDictionary<string, ISettings> _settingsCache
            = new ConcurrentDictionary<string, ISettings>(StringComparer.Ordinal);

        // ISettings.Root -> SourceRepositories
        private ConcurrentDictionary<string, List<SourceRepository>> _sourcesCache
            = new ConcurrentDictionary<string, List<SourceRepository>>(StringComparer.Ordinal);

        public ISettings GetSettings(string projectDirectory)
        {
            if (string.IsNullOrEmpty(ConfigFile))
            {
                return _settingsCache.GetOrAdd(projectDirectory, (dir) =>
                {
                    return Settings.LoadDefaultSettings(dir,
                        configFileName: null,
                        machineWideSettings: MachineWideSettings);
                });
            }
            else
            {
                var configFileFullPath = Path.GetFullPath(ConfigFile);
                var directory = Path.GetDirectoryName(configFileFullPath);
                var configFileName = Path.GetFileName(configFileFullPath);

                return _settingsCache.GetOrAdd(directory, (dir) =>
                {
                    return Settings.LoadSpecificSettings(dir,
                        configFileName: configFileName);
                });
            }
        }

        public string GetEffectiveGlobalPackagesFolder(string rootDirectory, ISettings settings)
        {
            if (!string.IsNullOrEmpty(GlobalPackagesFolder))
            {
                // Resolve as relative to the CWD
                return Path.GetFullPath(GlobalPackagesFolder);
            }

            // Load from environment, nuget.config or default location, and resolve relative paths
            // to the project root.
            var globalPath = SettingsUtility.GetGlobalPackagesFolder(settings);
            return Path.GetFullPath(Path.Combine(rootDirectory, globalPath));
        }

        public IReadOnlyList<string> GetEffectiveFallbackPackageFolders(ISettings settings)
        {
            return SettingsUtility.GetFallbackPackageFolders(settings);
        }

        /// <summary>
        /// Uses either Sources or Settings, and then adds Fallback sources.
        /// </summary>
        internal List<SourceRepository> GetEffectiveSources(ISettings settings, IList<PackageSource> dgSpecSources)
        {
            if (settings == null)
            {
                throw new ArgumentNullException(nameof(settings));
            }
            var values = settings.GetConfigRoots();
            if (dgSpecSources != null)
            {
                values.AddRange(dgSpecSources.Select(e => e.Source));
            }

            var cacheKey = string.Join("|", values);

            return _sourcesCache.GetOrAdd(cacheKey, (root) => GetEffectiveSourcesCore(settings, dgSpecSources));
        }

        private List<SourceRepository> GetEffectiveSourcesCore(ISettings settings, IList<PackageSource> dgSpecSources)
        {
#pragma warning disable CS0618 // Type or member is obsolete
            var packageSourceProvider = new PackageSourceProvider(settings, enablePackageSourcesChangedEvent: false);
#pragma warning restore CS0618 // Type or member is obsolete
            var packageSourcesFromProvider = packageSourceProvider.LoadPackageSources();
            var sourceObjects = new Dictionary<string, PackageSource>();
            for (var i = 0; i < dgSpecSources.Count; i++)
            {
                sourceObjects[dgSpecSources[i].Source] = dgSpecSources[i];
            }

            foreach (var sourceUri in Sources)
            {
                //DGSpecSources should always match the Sources
                if (!sourceObjects.ContainsKey(sourceUri))
                {
                    Log.LogDebug($"{sourceUri} is in the RestoreArgs Sources but not in the passed in dgSpecSources");
                    sourceObjects[sourceUri] = new PackageSource(sourceUri);
                }
            }

            // Use PackageSource objects from the provider when possible (since those will have credentials from nuget.config)
            foreach (var source in packageSourcesFromProvider)
            {
                if (source.IsEnabled && (sourceObjects.ContainsKey(source.Source)))
                {
                    sourceObjects[source.Source] = source;
                }
            }

            if (CachingSourceProvider == null)
            {
                // Create a shared caching provider if one does not exist already
                CachingSourceProvider = new CachingSourceProvider(packageSourceProvider);
            }

            return sourceObjects.Select(entry => CachingSourceProvider.CreateRepository(entry.Value)).ToList();
        }

        public void ApplyStandardProperties(RestoreRequest request)
        {
            if (request == null) throw new ArgumentNullException(nameof(request));

            if (request.ProjectStyle == ProjectStyle.PackageReference)
            {
                request.LockFilePath = Path.Combine(request.RestoreOutputPath, LockFileFormat.AssetsFileName);
            }
            else if (request.ProjectStyle != ProjectStyle.DotnetCliTool)
            {
                request.LockFilePath = ProjectJsonPathUtilities.GetLockFilePath(request.Project.FilePath);
            }

            if (request.Project.RestoreMetadata?.CacheFilePath == null)
            {
                request.Project.RestoreMetadata.CacheFilePath = NoOpRestoreUtilities.GetCacheFilePath(request);
            }

            request.MaxDegreeOfConcurrency =
                DisableParallel ? 1 : RestoreRequest.DefaultDegreeOfConcurrency;

            request.RequestedRuntimes.UnionWith(Runtimes);
            request.FallbackRuntimes.UnionWith(FallbackRuntimes);
            // Use legacy version for classic csproj.
            request.LockFileVersion = request.Project.RestoreMetadata?.UsingMicrosoftNETSdk == true ? LockFileFormat.Version : LockFileFormat.LegacyVersion;

            // Run runtime asset checks for project.json, and for other types if enabled.
            if (ValidateRuntimeAssets == null)
            {
                if (request.ProjectStyle == ProjectStyle.ProjectJson
                    || request.Project.RestoreMetadata == null)
                {
                    request.ValidateRuntimeAssets = request.ProjectStyle == ProjectStyle.ProjectJson;
                }
                else
                {
                    request.ValidateRuntimeAssets = request.Project.RestoreMetadata.ValidateRuntimeAssets;
                }
            }
            else
            {
                request.ValidateRuntimeAssets = ValidateRuntimeAssets.Value;
            }

            request.AllowNoOp = !request.CacheContext.NoCache && AllowNoOp;
            request.HideWarningsAndErrors = HideWarningsAndErrors;
            request.ParentId = ParentId;
            request.IsRestoreOriginalAction = IsRestoreOriginalAction;
            request.RestoreForceEvaluate = RestoreForceEvaluate;
        }
    }
}