Esempio n. 1
0
        public async Task <IEnumerable <PackageIdentity> > ResolveAsync(PackageIdentity package, NuGetFramework targetFramework, bool includePrelease = true, bool ignoreMissingPackages = true)
        {
            DependencyBehavior dependencyBehavior = DependencyBehavior.Lowest;

            //gathered dependencies
            var availabePackageStorage = new HashSet <SourcePackageDependencyInfo>(PackageIdentityComparer.Default);

            //gathering resource from available sources
            var getDependencyResourcesTasks = repositories.Select(repo => repo.GetResourceAsync <DependencyInfoResource>());

            var dependencyResources = (await getDependencyResourcesTasks.WhenAllOrException()).Where(x => x.IsSuccess && x.Result != null)
                                      .Select(x => x.Result).ToArray();

            var dependencyInfoResources = new DependencyInfoResourceCollection(dependencyResources);

            //recursively collect all dependencies
            dependencyBehavior = await ResolveDependenciesRecursivelyAsync(package, targetFramework, dependencyInfoResources, NullSourceCacheContext.Instance,
                                                                           availabePackageStorage, ignoreMissingPackages, default);

            return(availabePackageStorage.ToList());
        }
Esempio n. 2
0
        public async Task UninstallAsync(PackageIdentity package, IExtensibleProject project, IEnumerable <PackageReference> installedPackageReferences,
                                         CancellationToken cancellationToken = default)
        {
            List <string> failedEntries = null;
            ICollection <PackageIdentity> uninstalledPackages;

            var targetFramework = FrameworkParser.TryParseFrameworkName(project.Framework, _frameworkNameProvider);

#if NET5_0_OR_GREATER
            var reducer      = new FrameworkReducer();
            var mostSpecific = reducer.ReduceUpwards(project.SupportedPlatforms).FirstOrDefault();
            targetFramework = mostSpecific;
#endif

            var projectConfig         = _nuGetProjectConfigurationProvider.GetProjectConfig(project);
            var uninstallationContext = new UninstallationContext(false, false);

            _nugetLogger.LogInformation($"Uninstall package {package}, Target framework: {targetFramework}");

            if (projectConfig is null)
            {
                _nugetLogger.LogWarning($"Project {project.Name} doesn't implement any configuration for own packages");
            }

            using (var cacheContext = new SourceCacheContext()
            {
                NoCache = false,
                DirectDownload = false,
            })
            {
                var dependencyInfoResource = await project.AsSourceRepository(_sourceRepositoryProvider)
                                             .GetResourceAsync <DependencyInfoResource>(cancellationToken);

                var dependencyInfoResourceCollection = new DependencyInfoResourceCollection(dependencyInfoResource);

                var resolverContext = await ResolveDependenciesAsync(package, targetFramework, PackageIdentity.Comparer, dependencyInfoResourceCollection, cacheContext, project, true, cancellationToken);

                var packageReferences = installedPackageReferences.ToList();

                if (uninstallationContext.RemoveDependencies)
                {
                    uninstalledPackages = await GetPackagesCanBeUninstalledAsync(resolverContext.AvailablePackages, packageReferences.Select(x => x.PackageIdentity));
                }
                else
                {
                    uninstalledPackages = new List <PackageIdentity>()
                    {
                        package
                    };
                }
            }

            try
            {
                foreach (var removedPackage in uninstalledPackages)
                {
                    if (removedPackage.Version is null)
                    {
                        _nugetLogger.LogWarning($"Skip package {removedPackage.Id} uninstall. Check your package.config for references of this packages");
                        continue;
                    }

                    var folderProject = new FolderNuGetProject(project.ContentPath);

                    if (folderProject.PackageExists(removedPackage))
                    {
                        _directoryService.ForceDeleteDirectory(_fileService, folderProject.GetInstalledPath(removedPackage), out failedEntries);
                    }

                    if (projectConfig is null)
                    {
                        continue;
                    }

                    var result = await projectConfig.UninstallPackageAsync(removedPackage, _nuGetProjectContextProvider.GetProjectContext(FileConflictAction.PromptUser), cancellationToken);

                    if (!result)
                    {
                        _nugetLogger.LogError($"Saving package configuration failed in project {project} when installing package {package}");
                    }
                }
            }
            catch (IOException ex)
            {
                Log.Error(ex);
                _nugetLogger.LogError("Package files cannot be complete deleted by unexpected error (may be directory in use by another process?");
            }
            finally
            {
                LogHelper.LogUnclearedPaths(failedEntries, Log);
            }
        }
Esempio n. 3
0
        private async Task <Resolver.PackageResolverContext> ResolveDependenciesAsync(PackageIdentity identity, NuGetFramework targetFramework, IEqualityComparer <PackageIdentity> equalityComparer,
                                                                                      DependencyInfoResourceCollection dependencyInfoResource, SourceCacheContext cacheContext, IExtensibleProject project, bool ignoreMissingPackages = false, CancellationToken cancellationToken = default)
        {
            // The collection of already processed packages
            var packageStore      = new HashSet <SourcePackageDependencyInfo>(equalityComparer);
            var ignoredPackages   = new HashSet <PackageIdentity>();
            var downloadStack     = new Stack <SourcePackageDependencyInfo>();
            var resolvingBehavior = DependencyBehavior.Lowest;

            // get top dependency
            var dependencyInfo = await dependencyInfoResource.ResolvePackageAsync(
                identity, targetFramework, cacheContext, _nugetLogger, cancellationToken);

            if (dependencyInfo is null)
            {
                _nugetLogger.LogError($"Cannot resolve {identity} package for target framework {targetFramework}");
                return(Resolver.PackageResolverContext.Empty);
            }

            downloadStack.Push(dependencyInfo); //and add it to package store

            while (downloadStack.Count > 0)
            {
                var nextPackage = downloadStack.Pop();

                if (packageStore.Contains(nextPackage))
                {
                    continue;
                }
                else
                {
                    packageStore.Add(nextPackage);
                }

                foreach (var dependency in nextPackage.Dependencies)
                {
                    // currently we use specific version during child dependency resolving
                    // but possibly it should be configured in project
                    var dependencyIdentity = new PackageIdentity(dependency.Id, dependency.VersionRange.MinVersion);

                    var isPackageRequiresOwnDependencies = !_apiPackageRegistry.IsRegistered(dependencyIdentity.Id);
                    if (isPackageRequiresOwnDependencies)
                    {
                        // We can't determine the unknown version yet from range, but can exclude min required if it was already processed
                        if (packageStore.Contains(dependencyIdentity))
                        {
                            continue;
                        }

                        var relatedDepInfos = await dependencyInfoResource.ResolvePackagesWithVersionSatisfyRangeAsync(dependencyIdentity, dependency.VersionRange, targetFramework, cacheContext, _nugetLogger, cancellationToken);

                        foreach (var relatedDepedencyInfoResource in relatedDepInfos)
                        {
                            downloadStack.Push(relatedDepedencyInfoResource);
                        }

                        if (relatedDepInfos.Any())
                        {
                            // we found compatible (at least with target framework) packages and leave decision to Package Resolver in the future
                            continue;
                        }
                    }

                    // Determine behavior if package cannot be resolved in any way
                    if (ignoreMissingPackages)
                    {
                        if (_apiPackageRegistry.IsRegistered(dependencyIdentity.Id))
                        {
                            resolvingBehavior = DependencyBehavior.Lowest;

                            if (!packageStore.Contains(dependencyIdentity))
                            {
                                packageStore.Add(new SourcePackageDependencyInfo(dependencyIdentity.Id, dependencyIdentity.Version, Enumerable.Empty <PackageDependency>(), false, null));
                            }

                            if (ignoredPackages.Add(dependencyIdentity))
                            {
                                // Show only for top package, not much effort to see this message multiple times
                                if (nextPackage == dependencyInfo)
                                {
                                    await _nugetLogger.LogAsync(LogLevel.Information, $"The package dependency {dependencyIdentity.Id} listed as part of API and can be safely skipped");
                                }
                            }
                        }
                        else
                        {
                            resolvingBehavior = DependencyBehavior.Ignore;
                            await _nugetLogger.LogAsync(LogLevel.Warning, $"Available sources doesn't contain package {dependencyIdentity}. Package {dependencyIdentity} is missing");
                        }
                    }
                    else
                    {
                        throw new MissingPackageException($"Cannot find package {dependencyIdentity}");
                    }
                }
            }


            // Pass packages.config to resolver
            var nugetPackagesConfigProject = _nuGetProjectConfigurationProvider.GetProjectConfig(project);
            var packagesConfigReferences   = await nugetPackagesConfigProject.GetInstalledPackagesAsync(cancellationToken);

            // Construct context for package resolver
            return(GetResolverContext(identity, resolvingBehavior, packageStore, packagesConfigReferences, ignoredPackages));
        }
Esempio n. 4
0
        public async Task <InstallerResult> InstallAsync(
            PackageIdentity package,
            IExtensibleProject project,
            IReadOnlyList <SourceRepository> repositories,
            bool ignoreMissingPackages          = false,
            CancellationToken cancellationToken = default)
        {
            try
            {
                // Step 1. Decide what framework version used on package resolving
                // Enforce platform-specific framework for .NET 5.0

                var targetFramework = FrameworkParser.TryParseFrameworkName(project.Framework, _frameworkNameProvider);
                var reducer         = new FrameworkReducer();

#if NET5_0_OR_GREATER
                var mostSpecific = reducer.ReduceUpwards(project.SupportedPlatforms).FirstOrDefault();
                targetFramework = mostSpecific;
#endif

                _nugetLogger.LogInformation($"Installing package {package}, Target framework: {targetFramework}");

                // Prepare to step 2. Add globals if cache enabled as available repository with highest priority.
                // Note: This part falls under responsibility of RepositoryContextService but the same logic used to determine what packages are found by IPackageLoaderService
                // To not break behavior for now add here
                if (!project.NoCache)
                {
                    var repositoryList = repositories.ToList();
                    repositoryList.Insert(0, new SourceRepository(new PackageSource(DefaultNuGetFolders.GetGlobalPackagesFolder(), ".nuget"), Repository.Provider.GetCoreV3()));
                    repositories = repositoryList;
                }

                // Step 2. Build list of dependencies and determine DependencyBehavior if some packages are misssed in current feed
                Resolver.PackageResolverContext resolverContext = null;

                using (var cacheContext = new SourceCacheContext())
                {
#pragma warning disable IDISP013 // Await in using.
                    var getDependencyResourcesTasks = repositories.Select(repo => repo.GetResourceAsync <DependencyInfoResource>());
#pragma warning restore IDISP013 // Await in using.

                    var dependencyResources = (await getDependencyResourcesTasks.WhenAllOrExceptionAsync()).Where(x => x.IsSuccess && x.Result is not null)
                                              .Select(x => x.Result).ToArray();

                    var dependencyInfoResources = new DependencyInfoResourceCollection(dependencyResources);

                    resolverContext = await ResolveDependenciesAsync(package, targetFramework, PackageIdentityComparer.Default, dependencyInfoResources, cacheContext, project, ignoreMissingPackages, cancellationToken);

                    if (resolverContext is null ||
                        !(resolverContext?.AvailablePackages?.Any() ?? false))
                    {
                        var errorMessage = $"Package {package} cannot be resolved with current settings (TFM: {targetFramework}) for chosen destination";
                        _nugetLogger.LogWarning(errorMessage);
                        return(new InstallerResult(errorMessage));
                    }

                    // Step 3. Try to check is main package can be downloaded from resource
                    var mainPackageInfo = resolverContext.AvailablePackages.FirstOrDefault(p => p.Id == package.Id);

                    _nugetLogger.LogInformation($"Downloading {package}...");
                    var mainDownloadedFiles = await DownloadPackageResourceAsync(mainPackageInfo, cacheContext, cancellationToken);

                    _nugetLogger.LogInformation($"{package} download completed");

                    if (!mainDownloadedFiles.IsAvailable())
                    {
                        // Downlod failed by some reasons (probably connection issue or package goes deleted before feed updated)
                        var errorMessage = $"Current source lists package {package} but attempts to download it have failed. The source in invalid or required packages were removed while the current operation was in progress";
                        _nugetLogger.LogError(errorMessage);
                        return(new InstallerResult(errorMessage));
                    }

                    // Step 4. Check is main package compatible with target Framework
                    var canBeInstalled = await CheckCanBeInstalledAsync(project, mainDownloadedFiles.PackageReader, targetFramework, cancellationToken);

                    if (!canBeInstalled)
                    {
                        throw new IncompatiblePackageException($"Package {package} incompatible with project target platform {targetFramework}");
                    }

                    // Step 5. Build install list using NuGet Resolver and select available resources.
                    // Track packages which already installed and make sure only one version of package exists
                    var resolver = new Resolver.PackageResolver();
                    var availablePackagesToInstall = await resolver.ResolveWithVersionOverrideAsync(resolverContext, project, DependencyBehavior.Highest,
                                                                                                    (project, conflict) => _fileSystemService.CreateDeleteme(conflict.PackageIdentity.Id, project.GetInstallPath(conflict.PackageIdentity)),
                                                                                                    cancellationToken);

                    // Step 6. Download everything except main package and extract all
                    availablePackagesToInstall.Remove(mainPackageInfo);
                    _nugetLogger.LogInformation($"Downloading package dependencies...");
                    var downloadResults = await DownloadPackagesResourcesAsync(availablePackagesToInstall, cacheContext, cancellationToken);

                    downloadResults[mainPackageInfo] = mainDownloadedFiles;
                    _nugetLogger.LogInformation($"{downloadResults.Count - 1} dependencies downloaded");
                    var extractionContext = GetExtractionContext();
                    await ExtractPackagesResourcesAsync(downloadResults, project, extractionContext, cancellationToken);
                    await CheckLibAndFrameworkItemsAsync(downloadResults, targetFramework, cancellationToken);

                    return(new InstallerResult(downloadResults));
                }
            }
            catch (NuGetResolverInputException ex)
            {
                throw new IncompatiblePackageException($"Package {package} or some of it dependencies are missed for current target framework", ex);
            }
            catch (Exception ex)
            {
                Log.Error(ex);
                throw;
            }
        }
Esempio n. 5
0
        private async Task <DependencyBehavior> ResolveDependenciesRecursivelyAsync(PackageIdentity identity, NuGetFramework targetFramework,
                                                                                    DependencyInfoResourceCollection dependencyInfoResource,
                                                                                    SourceCacheContext cacheContext,
                                                                                    HashSet <SourcePackageDependencyInfo> storage,
                                                                                    bool ignoreMissingPackages          = false,
                                                                                    CancellationToken cancellationToken = default)
        {
            Argument.IsNotNull(() => storage);

            HashSet <SourcePackageDependencyInfo> packageStore = storage;

            Stack <SourcePackageDependencyInfo> downloadStack = new Stack <SourcePackageDependencyInfo>();

            var resolvedBehavior = DependencyBehavior.Lowest;

            //get top dependency
            var dependencyInfo = await dependencyInfoResource.ResolvePackage(
                identity, targetFramework, cacheContext, NuGetLogger, cancellationToken);

            if (dependencyInfo == null)
            {
                Log.Error($"Cannot resolve {identity} package for target framework {targetFramework}");
                return(resolvedBehavior);
            }

            downloadStack.Push(dependencyInfo); //and add it to package store

            while (downloadStack.Count > 0)
            {
                var rootDependency = downloadStack.Pop();

                //store all new packges
                if (!packageStore.Contains(rootDependency))
                {
                    packageStore.Add(rootDependency);
                }
                else
                {
                    continue;
                }

                foreach (var dependency in rootDependency.Dependencies)
                {
                    var relatedIdentity = new PackageIdentity(dependency.Id, dependency.VersionRange.MinVersion);

                    var relatedDepInfo = await dependencyInfoResource.ResolvePackage(relatedIdentity, targetFramework, cacheContext, NuGetLogger, cancellationToken);

                    if (relatedDepInfo != null)
                    {
                        downloadStack.Push(relatedDepInfo);
                        Log.Info($"Add dependency {relatedIdentity} for package {identity}");
                        continue;
                    }

                    if (ignoreMissingPackages)
                    {
                        resolvedBehavior = DependencyBehavior.Ignore;
                        Log.Warning($"Available sources doesn't contain package {relatedIdentity}. Package {relatedIdentity} is missing");
                    }
                    else
                    {
                        throw new MissingPackageException($"Cannot find package {relatedIdentity}");
                    }
                }
            }

            return(resolvedBehavior);
        }