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 ); }
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); }
public string GetTooltip() { return(SourceRepositories.Count() == 1 ? GetTooltip(SourceRepositories.First().PackageSource) : string.Join("; ", PackageSources)); }
/// <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 _)); }
/// <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);