/// <summary> /// Fetch, if not already downloaded, and install the package represented by /// (<paramref name="packageId"/>, <paramref name="version"/>). /// </summary> /// <remarks>It is safe to call it concurrently be cause we operations are done using the FileLock.</remarks> /// <param name="packageId">Name of package to install.</param> /// <param name="version">Version of package to install.</param> public async Task <NugetLocalPackage> InstallPackage(string packageId, PackageVersion version, ProgressReport progress) { // Xenko 2.x still installs in GamePackages var currentManager = IsPackageV2(packageId, version) ? managerV2 : manager; using (GetLocalRepositoryLock()) { currentProgressReport = progress; try { var identity = new PackageIdentity(packageId, version.ToNuGetVersion()); var resolutionContext = new ResolutionContext( DependencyBehavior.Lowest, true, true, VersionConstraints.None); var repositories = PackageSources.Select(sourceRepositoryProvider.CreateRepository).ToArray(); var projectContext = new EmptyNuGetProjectContext() { ActionType = NuGetActionType.Install, PackageExtractionContext = new PackageExtractionContext(NativeLogger), }; ActivityCorrelationId.StartNew(); { // Equivalent to: // await manager.InstallPackageAsync(manager.PackagesFolderNuGetProject, // identity, resolutionContext, projectContext, repositories, // Array.Empty<SourceRepository>(), // This is a list of secondary source respositories, probably empty // CancellationToken.None); using (var sourceCacheContext = new SourceCacheContext()) { var nuGetProject = currentManager.PackagesFolderNuGetProject; var packageIdentity = identity; var nuGetProjectContext = projectContext; var primarySources = repositories; var secondarySources = Array.Empty <SourceRepository>(); var token = CancellationToken.None; var downloadContext = new PackageDownloadContext(sourceCacheContext); // Step-1 : Call PreviewInstallPackageAsync to get all the nuGetProjectActions var nuGetProjectActions = await currentManager.PreviewInstallPackageAsync(nuGetProject, packageIdentity, resolutionContext, nuGetProjectContext, primarySources, secondarySources, token); // Notify that installations started. foreach (var operation in nuGetProjectActions) { if (operation.NuGetProjectActionType == NuGetProjectActionType.Install) { var installPath = GetInstalledPath(operation.PackageIdentity.Id, operation.PackageIdentity.Version.ToPackageVersion()); OnPackageInstalling(this, new PackageOperationEventArgs(new PackageName(operation.PackageIdentity.Id, operation.PackageIdentity.Version.ToPackageVersion()), installPath)); } } NuGetPackageManager.SetDirectInstall(packageIdentity, nuGetProjectContext); // Step-2 : Execute all the nuGetProjectActions if (IsPackageV2(packageId, version)) { await currentManager.ExecuteNuGetProjectActionsAsync( nuGetProject, nuGetProjectActions, nuGetProjectContext, downloadContext, token); } else { // Download and install package in the global cache (can't use NuGetPackageManager anymore since it is designed for V2) foreach (var operation in nuGetProjectActions) { if (operation.NuGetProjectActionType == NuGetProjectActionType.Install) { using (var downloadResult = await PackageDownloader.GetDownloadResourceResultAsync(primarySources, packageIdentity, downloadContext, InstallPath, NativeLogger, token)) { if (downloadResult.Status != DownloadResourceResultStatus.Available) { throw new InvalidOperationException($"Could not download package {packageIdentity}"); } using (var installResult = await GlobalPackagesFolderUtility.AddPackageAsync(packageIdentity, downloadResult.PackageStream, InstallPath, NativeLogger, token)) { if (installResult.Status != DownloadResourceResultStatus.Available) { throw new InvalidOperationException($"Could not install package {packageIdentity}"); } } } } } } NuGetPackageManager.ClearDirectInstall(nuGetProjectContext); // Notify that installations completed. foreach (var operation in nuGetProjectActions) { if (operation.NuGetProjectActionType == NuGetProjectActionType.Install) { var installPath = GetInstalledPath(operation.PackageIdentity.Id, operation.PackageIdentity.Version.ToPackageVersion()); OnPackageInstalled(this, new PackageOperationEventArgs(new PackageName(operation.PackageIdentity.Id, operation.PackageIdentity.Version.ToPackageVersion()), installPath)); } } } } // Load the recently installed package var installedPackages = GetPackagesInstalled(new[] { packageId }); return(installedPackages.FirstOrDefault(p => p.Version == version)); } finally { currentProgressReport = null; } } }
internal async Task UpdateSelfFromVersionAsync(string exePath, bool prerelease, NuGetVersion currentVersion, string source, CancellationToken cancellationToken) { var sourceCacheContext = new SourceCacheContext(); _console.WriteLine(LocalizedResourceManager.GetString("UpdateCommandCheckingForUpdates"), source); var sourceRepository = Repository.Factory.GetCoreV3(source); var metadataResource = await sourceRepository.GetResourceAsync <MetadataResource>(cancellationToken); var latestVersion = await metadataResource.GetLatestVersion(NuGetCommandLinePackageId, prerelease, includeUnlisted : false, sourceCacheContext, _console, cancellationToken); _console.WriteLine(LocalizedResourceManager.GetString("UpdateCommandCurrentlyRunningNuGetExe"), currentVersion); // Check to see if an update is needed if (latestVersion == null || currentVersion >= latestVersion) { _console.WriteLine(LocalizedResourceManager.GetString("UpdateCommandNuGetUpToDate")); } else { _console.WriteLine(LocalizedResourceManager.GetString("UpdateCommandUpdatingNuGet"), latestVersion); var packageIdentity = new PackageIdentity(NuGetCommandLinePackageId, latestVersion); var tempDir = Path.Combine(NuGetEnvironment.GetFolderPath(NuGetFolderPath.Temp), "updateSelf"); var nupkgPath = FileUtility.GetTempFilePath(tempDir); try { DirectoryUtility.CreateSharedDirectory(tempDir); DownloadResourceResult downloadResourceResult = await PackageDownloader.GetDownloadResourceResultAsync( sourceRepository, packageIdentity, new PackageDownloadContext(sourceCacheContext), tempDir, _console, cancellationToken); // Get the exe path and move it to a temp file (NuGet.exe.old) so we can replace the running exe with the bits we got // from the package repository IEnumerable <string> packageFiles = await downloadResourceResult.PackageReader.GetFilesAsync(CancellationToken.None); string nugetExeInPackageFilePath = packageFiles.FirstOrDefault(f => Path.GetFileName(f).Equals(NuGetExe, StringComparison.OrdinalIgnoreCase)); // If for some reason this package doesn't have NuGet.exe then we don't want to use it if (nugetExeInPackageFilePath == null) { throw new CommandException(LocalizedResourceManager.GetString("UpdateCommandUnableToLocateNuGetExe")); } string renamedPath = exePath + ".old"; FileUtility.Move(exePath, renamedPath); using (Stream fromStream = await downloadResourceResult.PackageReader.GetStreamAsync(nugetExeInPackageFilePath, cancellationToken), toStream = File.Create(exePath)) { fromStream.CopyTo(toStream); } } finally { // Delete the temporary directory try { Directory.Delete(tempDir, recursive: true); } catch { } } } _console.WriteLine(LocalizedResourceManager.GetString("UpdateCommandUpdateSuccessful")); }
public static async Task <Dictionary <PackageIdentity, PackagePreFetcherResult> > GetPackagesAsync( IEnumerable <ResolvedAction> actions, IModulesDirectory modulesDirectory, PackageDownloadContext downloadContext, ILogger logger, CancellationToken token) { var result = new Dictionary <PackageIdentity, PackagePreFetcherResult>(); var maxParallelTasks = PackageManagementConstants.DefaultMaxDegreeOfParallelism; var toDownload = new Queue <ResolvedAction>(); var seen = new HashSet <PackageIdentity>(); // Find all uninstalled packages var uninstalledPackages = new HashSet <PackageIdentity>( actions.Where(action => action.Action == ResolvedActionType.Uninstall) .Select(action => action.PackageIdentity)); // find the packages that need to be downloaded foreach (var action in actions) { if (action.Action == ResolvedActionType.Install && seen.Add(action.PackageIdentity)) { string localFile = null; // Packages that are also being uninstalled cannot come from the // packages folder since it will be gone. This is true for reinstalls. if (!uninstalledPackages.Contains(action.PackageIdentity)) { // Check the packages folder for the id and version localFile = modulesDirectory.VersionFolderPathResolver.GetPackageFilePath( action.PackageIdentity.Id, action.PackageIdentity.Version); // Verify the nupkg exists if (localFile == null || !File.Exists(localFile)) { localFile = null; } } // installPath will contain the full path of the already installed nupkg if it // exists. If the path is empty it will need to be downloaded. if (!string.IsNullOrEmpty(localFile)) { // Create a download result using the already installed package var downloadResult = new PackagePreFetcherResult(localFile, action.PackageIdentity); result.Add(action.PackageIdentity, downloadResult); } else { // Download this package toDownload.Enqueue(action); } } } // Check if any packages are not already in the packages folder if (toDownload.Any()) { var downloadResults = new List <PackagePreFetcherResult>(maxParallelTasks); while (toDownload.Count > 0) { // Throttle tasks if (downloadResults.Count == maxParallelTasks) { // Wait for a task to complete // This will not throw, exceptions are stored in the result await Task.WhenAny(downloadResults.Select(e => e.EnsureResultAsync())); // Remove all completed tasks downloadResults.RemoveAll(e => e.IsComplete); } var action = toDownload.Dequeue(); // Download the package if it does not exist in the packages folder already // Start the download task var task = Task.Run(async() => await PackageDownloader.GetDownloadResourceResultAsync( action.SourceRepository, action.PackageIdentity, downloadContext, "NO_GLOBAL_CACHE_DIRECTORY", logger, token), token); var downloadResult = new PackagePreFetcherResult( task, action.PackageIdentity, action.SourceRepository.PackageSource); downloadResults.Add(downloadResult); result.Add(action.PackageIdentity, downloadResult); } } // Do not wait for the remaining tasks to finish, these will download // in the background while other operations such as uninstall run first. return(result); }