/// <summary> /// Uninstall <paramref name="package"/>, while still keeping the downloaded file in the cache. /// </summary> /// <remarks>It is safe to call it concurrently be cause we operations are done using the FileLock.</remarks> /// <param name="package">Package to uninstall.</param> public async Task UninstallPackage(NugetPackage package, ProgressReport progress) { #if DEBUG var installedPackages = GetPackagesInstalled(new [] { package.Id }); Debug.Assert(installedPackages.FirstOrDefault(p => p.Equals(package)) != null); #endif using (GetLocalRepositoryLock()) { currentProgressReport = progress; try { var identity = new PackageIdentity(package.Id, package.Version.ToNuGetVersion()); // Notify that uninstallation started. var installPath = GetInstalledPath(identity.Id, identity.Version.ToPackageVersion()); if (installPath == null) { throw new InvalidOperationException($"Could not find installation path for package {identity}"); } OnPackageUninstalling(this, new PackageOperationEventArgs(new PackageName(package.Id, package.Version), installPath)); var projectContext = new EmptyNuGetProjectContext() { ActionType = NuGetActionType.Uninstall, PackageExtractionContext = new PackageExtractionContext(PackageSaveMode.Defaultv3, XmlDocFileSaveMode.Skip, null, NativeLogger), }; // Simply delete the installed package and its .nupkg installed in it. await Task.Run(() => FileSystemUtility.DeleteDirectorySafe(installPath, true, projectContext)); // Notify that uninstallation completed. OnPackageUninstalled(this, new PackageOperationEventArgs(new PackageName(package.Id, package.Version), installPath)); //currentProgressReport = progress; //try //{ // manager.UninstallPackage(package.IPackage); //} //finally //{ // currentProgressReport = null; //} if (package.Id == "Xenko" && package.Version < new PackageVersion(3, 0, 0, 0)) { UpdateTargetsHelper(); } } finally { currentProgressReport = null; } } }
private static void RunPackageInstall(string packageInstall, string arguments, ProgressReport progress) { // Run packageinstall.exe using (var process = Process.Start(new ProcessStartInfo(packageInstall, arguments) { UseShellExecute = false, CreateNoWindow = true, RedirectStandardError = true, RedirectStandardOutput = true, WorkingDirectory = Path.GetDirectoryName(packageInstall), })) { if (process == null) { throw new InvalidOperationException($"Could not start install package process [{packageInstall}] with options {arguments}"); } var errorOutput = new StringBuilder(); process.OutputDataReceived += (_, args) => { if (!string.IsNullOrEmpty(args.Data)) { var matches = powerShellProgressRegex.Match(args.Data); int percentageResult; if (matches.Success && int.TryParse(matches.Groups[1].Value, out percentageResult)) { // Report progress progress?.UpdateProgress(ProgressAction.Install, percentageResult); } else { lock (process) { errorOutput.AppendLine(args.Data); } } } }; process.ErrorDataReceived += (_, args) => { if (!string.IsNullOrEmpty(args.Data)) { // Save errors lock (process) { errorOutput.AppendLine(args.Data); } } }; // Process output and wait for exit process.BeginOutputReadLine(); process.BeginErrorReadLine(); process.WaitForExit(); // Check exit code var exitCode = process.ExitCode; if (exitCode != 0) { throw new InvalidOperationException($"Error code {exitCode} while running install package process [{packageInstall}]\n\n" + errorOutput); } } }
/// <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, IEnumerable <string> targetFrameworks, ProgressReport progress) { 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(PackageSaveMode.Defaultv3, XmlDocFileSaveMode.Skip, null, NativeLogger), }; ActivityCorrelationId.StartNew(); { var installPath = SettingsUtility.GetGlobalPackagesFolder(settings); // In case it's a package without any TFM (i.e. Visual Studio plugin), we still need to specify one if (!targetFrameworks.Any()) { targetFrameworks = new string[] { "net6.0" } } ; // Old version expects to be installed in GamePackages if (packageId == "Xenko" && version < new PackageVersion(3, 0, 0, 0) && oldRootDirectory != null) { installPath = oldRootDirectory; } var projectPath = Path.Combine("StrideLauncher.json"); var spec = new PackageSpec() { Name = Path.GetFileNameWithoutExtension(projectPath), // make sure this package never collides with a dependency FilePath = projectPath, Dependencies = new List <LibraryDependency>() { new LibraryDependency { LibraryRange = new LibraryRange(packageId, new VersionRange(version.ToNuGetVersion()), LibraryDependencyTarget.Package), } }, RestoreMetadata = new ProjectRestoreMetadata { ProjectPath = projectPath, ProjectName = Path.GetFileNameWithoutExtension(projectPath), ProjectStyle = ProjectStyle.PackageReference, ProjectUniqueName = projectPath, OutputPath = Path.Combine(Path.GetTempPath(), $"StrideLauncher-{packageId}-{version.ToString()}"), OriginalTargetFrameworks = targetFrameworks.ToList(), ConfigFilePaths = settings.GetConfigFilePaths(), PackagesPath = installPath, Sources = SettingsUtility.GetEnabledSources(settings).ToList(), FallbackFolders = SettingsUtility.GetFallbackPackageFolders(settings).ToList() }, }; foreach (var targetFramework in targetFrameworks) { spec.TargetFrameworks.Add(new TargetFrameworkInformation { FrameworkName = NuGetFramework.Parse(targetFramework) }); } using (var context = new SourceCacheContext { MaxAge = DateTimeOffset.UtcNow }) { context.IgnoreFailedSources = true; var dependencyGraphSpec = new DependencyGraphSpec(); dependencyGraphSpec.AddProject(spec); dependencyGraphSpec.AddRestore(spec.RestoreMetadata.ProjectUniqueName); IPreLoadedRestoreRequestProvider requestProvider = new DependencyGraphSpecRequestProvider(new RestoreCommandProvidersCache(), dependencyGraphSpec); var restoreArgs = new RestoreArgs { AllowNoOp = true, CacheContext = context, CachingSourceProvider = new CachingSourceProvider(new PackageSourceProvider(settings)), Log = NativeLogger, }; // Create requests from the arguments var requests = requestProvider.CreateRequests(restoreArgs).Result; foreach (var request in requests) { // Limit concurrency to avoid timeout request.Request.MaxDegreeOfConcurrency = 4; var command = new RestoreCommand(request.Request); // Act var result = await command.ExecuteAsync(); if (!result.Success) { throw new InvalidOperationException($"Could not restore package {packageId}"); } foreach (var install in result.RestoreGraphs.Last().Install) { var package = result.LockFile.Libraries.FirstOrDefault(x => x.Name == install.Library.Name && x.Version == install.Library.Version); if (package != null) { var packagePath = Path.Combine(installPath, package.Path); OnPackageInstalled(this, new PackageOperationEventArgs(new PackageName(install.Library.Name, install.Library.Version.ToPackageVersion()), packagePath)); } } } } if (packageId == "Xenko" && version < new PackageVersion(3, 0, 0, 0)) { UpdateTargetsHelper(); } } // Load the recently installed package var installedPackages = GetPackagesInstalled(new[] { packageId }); return(installedPackages.FirstOrDefault(p => p.Version == version)); } finally { currentProgressReport = null; } } }