예제 #1
0
        private PluginPackageManager(DirectoryPath pluginDirPath,
                                     DirectoryPath pluginHomeDirPath,
                                     DirectoryPath packageDirPath,
                                     NuGetInstalledPluginRepository <TMeta> packageCache,
                                     Func <ISettings, NuGet.SourceRepositoryProvider> providerCreator =
                                     null)
        {
            var settings = Settings.LoadDefaultSettings(packageDirPath.FullPath, null, new NuGetMachineWideSettings());

            _currentFramework  = GetCurrentFramework();
            SourceRepositories = providerCreator?.Invoke(settings) ?? new NuGet.SourceRepositoryProvider(settings);
            PluginRepo         = packageCache;

            var localRepo = SourceRepositories.CreateRepository(
                new PackageSource(packageDirPath.FullPath, "Local", true),
                FeedType.FileSystemPackagesConfig);

            Solution = new NuGetPluginSolution <TMeta>(
                pluginDirPath, pluginHomeDirPath, packageDirPath,
                PluginRepo,
                SourceRepositories,
                settings,
                _currentFramework
                );
        }
예제 #2
0
        public async ValueTask <IReadOnlyCollection <SourceRepository> > GetRepositoriesAsync(
            IReadOnlyCollection <PackageSourceContextInfo> packageSourceContextInfos,
            CancellationToken cancellationToken)
        {
            if (_repositories == null)
            {
                _repositories = await SourceRepositories.GetValueAsync();
            }

            Dictionary <string, SourceRepository>?sourceRepositories = _repositories.ToDictionary(repository => repository.PackageSource.Name, _ => _);
            var matchingSourceRepositories = new List <SourceRepository>(capacity: packageSourceContextInfos.Count);

            foreach (PackageSourceContextInfo packageSource in packageSourceContextInfos)
            {
                if (sourceRepositories.TryGetValue(packageSource.Name, out SourceRepository sourceRepository))
                {
                    matchingSourceRepositories.Add(sourceRepository);
                }
            }

            return(matchingSourceRepositories);
        }
        /// <summary>
        /// Install a NuGet package. Returns all newly installed packages.
        /// </summary>
        public async Task <IReadOnlyCollection <InteractivePackage> > InstallPackageAsync(
            InteractivePackage package,
            SourceRepository sourceRepository,
            CancellationToken cancellationToken)
        {
            if (package == null)
            {
                throw new ArgumentNullException(nameof(package));
            }
            if (!package.Identity.HasVersion)
            {
                throw new ArgumentException("PackageIdentity.Version must be set");
            }

            // TODO: File upstream issue about exception if primary source repo is offline.
            //       Shouldn't secondary source repos kick in? Our current work around is to
            //       pass the source repo from search to install, but that's not perfect.
            sourceRepository = sourceRepository ?? SourceRepositories [0];

            project.ResetInstallationContext();

            // Just need to apply one fixup here
            if (PackageIdComparer.Equals(package.Identity.Id, FixedXamarinFormsPackageIdentity.Id) &&
                package.Identity.Version != FixedXamarinFormsPackageIdentity.Version)
            {
                Log.Warning(
                    TAG,
                    $"Replacing requested Xamarin.Forms version {package.Identity.Version} with " +
                    $"required version {FixedXamarinFormsPackageIdentity.Version}.");
                package = package.WithVersion(
                    FixedXamarinFormsPackageIdentity.Version,
                    overwriteRange: true);
            }

            if (PackageIdComparer.Equals(package.Identity.Id, IntegrationPackageId))
            {
                Log.Warning(TAG, $"Refusing to add integration NuGet package {IntegrationPackageId}.");
                return(Array.Empty <InteractivePackage> ());
            }

            var resolutionContext = new ResolutionContext(
                DependencyBehavior.Lowest, // IDEs only use Highest if upgrading
                includePrelease: true,
                includeUnlisted: true,
                versionConstraints: VersionConstraints.None);

            // Although there is a single repo associated with the package being installed,
            // dependency resolution will also look into the secondary sources. In some cases,
            // this can greatly slow down installation. For the primary case of searching for
            // packages in nuget.org, prevent the package manager from using secondary sources
            // for resolution.
            //
            // It is important to pass an empty enumerable, because if we pass null, the package
            // manager will determine secondary sources based on the NuGet configuration.
            var secondarySources =
                sourceRepository == SourceRepositories [0]
                ? Enumerable.Empty <SourceRepository> ()
                : SourceRepositories.Where(r => r != sourceRepository).ToArray();

            // There does not appear to be a way to hook into or override functionality of the
            // NuGetPackageManager or PackageResolver classes. In order to mess with package
            // resolution, we need to either write a lot of code, proxy the sources, or intercede
            // via preview installation actions.
            //
            // Here we do the latter, though it is not the best general-purpose approach. It works
            // fine for replacing one single package that we know a LOT about. If that package's
            // dependencies continually changed, we'd be better off with another approach.
            var previewInstallActions = await packageManager.PreviewInstallPackageAsync(
                project,
                package.Identity,
                resolutionContext,
                projectContext,
                sourceRepository,
                secondarySources,
                cancellationToken);

            var installActions = new List <NuGetProjectAction> ();

            foreach (var action in previewInstallActions)
            {
                // If the installed package has a dependency on Xamarin.Forms, make sure the version
                // that gets installed is our preferred version. Force it to install from the primary
                // source repository, because we can't assume that version is available everywhere.
                //
                // TODO: Consider adding a search or something to see if we can use the specified source
                //       instead. Could be handy if nuget.org is down or the user is offline and using
                //       a local repo.
                if (action.PackageIdentity.Id == FixedXamarinFormsPackageIdentity.Id)
                {
                    installActions.Add(NuGetProjectAction.CreateInstallProjectAction(
                                           FixedXamarinFormsPackageIdentity,
                                           SourceRepositories [0],
                                           action.Project));
                }
                else
                {
                    installActions.Add(action);
                }
            }

            // We follow the modern behavior of .NET Core and do not actually install packages anywhere.
            // Instead, we ultimately reference them out of the user's global package cache (by default,
            // ~/.nuget/packages). Our NuGetProject implementation simply collects package assembly
            // references (and potentially other necessary files) and populates them back into the
            // InteractiveInstallationContext.
            using (var sourceCacheContext = new SourceCacheContext())
                await packageManager.ExecuteNuGetProjectActionsAsync(
                    project,
                    installActions,
                    projectContext,
                    sourceCacheContext,
                    cancellationToken);

            // Identify which packages were not already noted as installed, or have been upgraded now
            var newlyInstalledPackages = new List <InteractivePackage> ();

            foreach (var newPackage in project.InstallationContext.InstalledPackages)
            {
                InteractivePackage finalNewPackage;
                var foundInstalledMatch = installedPackages.TryGetValue(
                    newPackage,
                    out finalNewPackage);

                if (!foundInstalledMatch ||
                    newPackage.Identity.Version > finalNewPackage.Identity.Version)
                {
                    // Make sure we have a reference to a matching explicit InteractivePackage if it
                    // exists, so that we can persist the original SupportedVersionRange
                    if (!foundInstalledMatch)
                    {
                        finalNewPackage = PackageIdComparer.Equals(package, newPackage)
                            ? package
                            : newPackage;
                    }

                    finalNewPackage = newPackage
                                      .WithIsExplicit(finalNewPackage.IsExplicit)
                                      .WithSupportedVersionRange(finalNewPackage.SupportedVersionRange);

                    newlyInstalledPackages.Add(finalNewPackage);
                    installedPackages = installedPackages
                                        .Remove(finalNewPackage)
                                        .Add(finalNewPackage);
                    UpdateInstalledPackages();
                }
            }

            return(newlyInstalledPackages);
        }
예제 #4
0
 public string GetTooltip()
 {
     return(SourceRepositories.Count() == 1
         ? GetTooltip(SourceRepositories.First().PackageSource)
         : string.Join("; ", PackageSources));
 }
예제 #5
0
        /// <summary>
        /// Removes the specified package source.
        /// </summary>
        /// <param name="repositoryUri">The package source to remove.</param>
        /// <returns>Whether the package source was found and removed or not.</returns>
        public bool RemoveRepository(string repositoryUri)
        {
            var sr = SourceRepositories.Keys.FirstOrDefault(sr => sr.Name == repositoryUri);

            return(sr != null && SourceRepositories.TryRemove(sr, out _));
        }
예제 #6
0
 /// <summary>
 ///   Adds the specified package source. Sources added this way will be searched before any
 ///   global sources.
 /// </summary>
 /// <param name="repository">The package source to add.</param>
 public SourceRepository AddRepository(string repository) => SourceRepositories.CreateRepository(repository);