public void InstallWorkloadManifest(ManifestId manifestId, ManifestVersion manifestVersion, SdkFeatureBand sdkFeatureBand, DirectoryPath?offlineCache = null) { try { Log?.LogMessage($"Installing manifest, {nameof(manifestId)}: {manifestId}, {nameof(manifestVersion)}: {manifestVersion}, {nameof(sdkFeatureBand)}: {sdkFeatureBand}"); // Resolve the package ID for the manifest payload package string msiPackageId = WorkloadManifestUpdater.GetManifestPackageId(sdkFeatureBand, manifestId).ToString(); string msiPackageVersion = $"{manifestVersion}"; Log?.LogMessage($"Resolving {manifestId} ({manifestVersion}) to {msiPackageId}.{msiPackageVersion}."); // Retrieve the payload from the MSI package cache. MsiPayload msiPayload = GetCachedMsiPayload(msiPackageId, msiPackageVersion); VerifyPackage(msiPayload); } catch (Exception e) { LogException(e); throw; } }
public void InstallWorkloadManifest(ManifestId manifestId, ManifestVersion manifestVersion, SdkFeatureBand sdkFeatureBand, DirectoryPath?offlineCache = null, bool isRollback = false) { try { ReportPendingReboot(); // Rolling back a manifest update after a successful install is essentially a downgrade, which is blocked so we have to // treat it as a special case and is different from the install failing and rolling that back, though depending where the install // failed, it may have removed the old product already. Log?.LogMessage($"Installing manifest: Id: {manifestId}, version: {manifestVersion}, feature band: {sdkFeatureBand}, rollback: {isRollback}."); // Resolve the package ID for the manifest payload package string msiPackageId = WorkloadManifestUpdater.GetManifestPackageId(sdkFeatureBand, manifestId, InstallType.Msi).ToString(); string msiPackageVersion = $"{manifestVersion}"; Log?.LogMessage($"Resolving {manifestId} ({manifestVersion}) to {msiPackageId} ({msiPackageVersion})."); // Retrieve the payload from the MSI package cache. MsiPayload msi = GetCachedMsiPayload(msiPackageId, msiPackageVersion, offlineCache); VerifyPackage(msi); DetectState state = DetectPackage(msi.ProductCode, out Version installedVersion); InstallAction plannedAction = PlanPackage(msi, state, InstallAction.Install, installedVersion, out IEnumerable <string> relatedProducts); // If we've detected a downgrade, it's possible we might be doing a rollback after the manifests were updated, // but another error occurred. In this case we need to try and uninstall the upgrade and then install the lower // version of the MSI. The downgrade can also be a deliberate rollback. if (plannedAction == InstallAction.Downgrade && isRollback && state == DetectState.Absent) { Log?.LogMessage($"Rolling back manifest update."); // The provider keys for manifest packages are stable across feature bands so we retain dependents during upgrades. DependencyProvider depProvider = new DependencyProvider(msi.Manifest.ProviderKeyName); // Try and remove the SDK dependency, but ignore any remaining dependencies since // we want to force the removal of the old version. The remaining dependencies and the provider // key won't be removed. UpdateDependent(InstallRequestType.RemoveDependent, msi.Manifest.ProviderKeyName, _dependent); // Since we don't have records for manifests, we need to try and retrieve the ProductCode of // the newer MSI that's installed that we want to remove using its dependency provider. string productCode = depProvider.ProductCode; if (string.IsNullOrWhiteSpace(productCode)) { // We don't know the MSI package that wrote this provider key, so if the ProductCode is missing // we can't do anything else. Log?.LogMessage($"Failed to retrieve the ProductCode for provider: {depProvider.ProviderKeyName}."); return; } Log?.LogMessage($"Found ProductCode {productCode} registered against provider, {depProvider.ProviderKeyName}."); // This is a best effort. If for some reason the manifest installers were fixed, for example, manually // adding additional upgrade paths to work around previous faulty authoring, we may have multiple related // products. The best we can do is to check for at least one match and remove it and then try the rollback. if (!relatedProducts.Contains(productCode, StringComparer.OrdinalIgnoreCase)) { Log?.LogMessage($"Cannot rollback manifest. ProductCode does not match any detected related products."); return; } string logFile = GetMsiLogName(productCode, InstallAction.Uninstall); uint error = UninstallMsi(productCode, logFile, ignoreDependencies: true); ExitOnError(error, "Failed to uninstall manifest package."); // Detect the package again and fall through to the original execution. If that fails, then there's nothing // we could have done. Log?.LogMessage("Replanning manifest package."); state = DetectPackage(msi, out Version _); plannedAction = PlanPackage(msi, state, InstallAction.Install, installedVersion, out IEnumerable <string> _); } ExecutePackage(msi, plannedAction); // Update the reference count against the MSI. UpdateDependent(InstallRequestType.AddDependent, msi.Manifest.ProviderKeyName, _dependent); } catch (Exception e) { LogException(e); throw; } }
public void InstallWorkloadManifest(ManifestId manifestId, ManifestVersion manifestVersion, SdkFeatureBand sdkFeatureBand, DirectoryPath?offlineCache = null, bool isRollback = false) { string packagePath = null; string tempExtractionDir = null; string tempBackupDir = null; string rootInstallDir = WorkloadFileBasedInstall.IsUserLocal(_dotnetDir, sdkFeatureBand.ToString()) ? _userProfileDir : _dotnetDir; var manifestPath = Path.Combine(rootInstallDir, "sdk-manifests", sdkFeatureBand.ToString(), manifestId.ToString()); _reporter.WriteLine(string.Format(LocalizableStrings.InstallingWorkloadManifest, manifestId, manifestVersion)); try { TransactionalAction.Run( action: () => { if (offlineCache == null || !offlineCache.HasValue) { packagePath = _nugetPackageDownloader.DownloadPackageAsync(WorkloadManifestUpdater.GetManifestPackageId(sdkFeatureBand, manifestId), new NuGetVersion(manifestVersion.ToString()), _packageSourceLocation).GetAwaiter().GetResult(); } else { packagePath = Path.Combine(offlineCache.Value.Value, $"{WorkloadManifestUpdater.GetManifestPackageId(sdkFeatureBand, manifestId)}.{manifestVersion}.nupkg"); if (!File.Exists(packagePath)) { throw new Exception(string.Format(LocalizableStrings.CacheMissingPackage, WorkloadManifestUpdater.GetManifestPackageId(sdkFeatureBand, manifestId), manifestVersion, offlineCache)); } } tempExtractionDir = Path.Combine(_tempPackagesDir.Value, $"{manifestId}-{manifestVersion}-extracted"); Directory.CreateDirectory(tempExtractionDir); var manifestFiles = _nugetPackageDownloader.ExtractPackageAsync(packagePath, new DirectoryPath(tempExtractionDir)).GetAwaiter().GetResult(); if (Directory.Exists(manifestPath) && Directory.GetFileSystemEntries(manifestPath).Any()) { // Backup existing manifest data for roll back purposes tempBackupDir = Path.Combine(_tempPackagesDir.Value, $"{manifestId}-{manifestVersion}-backup"); if (Directory.Exists(tempBackupDir)) { Directory.Delete(tempBackupDir, true); } FileAccessRetrier.RetryOnMoveAccessFailure(() => DirectoryPath.MoveDirectory(manifestPath, tempBackupDir)); } Directory.CreateDirectory(Path.GetDirectoryName(manifestPath)); FileAccessRetrier.RetryOnMoveAccessFailure(() => DirectoryPath.MoveDirectory(Path.Combine(tempExtractionDir, "data"), manifestPath)); }, rollback: () => { if (!string.IsNullOrEmpty(tempBackupDir) && Directory.Exists(tempBackupDir)) { FileAccessRetrier.RetryOnMoveAccessFailure(() => DirectoryPath.MoveDirectory(tempBackupDir, manifestPath)); } }); // Delete leftover dirs and files if (!string.IsNullOrEmpty(packagePath) && File.Exists(packagePath) && (offlineCache == null || !offlineCache.HasValue)) { File.Delete(packagePath); } var versionDir = Path.GetDirectoryName(packagePath); if (Directory.Exists(versionDir) && !Directory.GetFileSystemEntries(versionDir).Any()) { Directory.Delete(versionDir); var idDir = Path.GetDirectoryName(versionDir); if (Directory.Exists(idDir) && !Directory.GetFileSystemEntries(idDir).Any()) { Directory.Delete(idDir); } } if (!string.IsNullOrEmpty(tempExtractionDir) && Directory.Exists(tempExtractionDir)) { Directory.Delete(tempExtractionDir, true); } if (!string.IsNullOrEmpty(tempBackupDir) && Directory.Exists(tempBackupDir)) { Directory.Delete(tempBackupDir, true); } } catch (Exception e) { throw new Exception(string.Format(LocalizableStrings.FailedToInstallWorkloadManifest, manifestId, manifestVersion, e.Message)); } }
public void InstallWorkloadManifest(ManifestId manifestId, ManifestVersion manifestVersion, SdkFeatureBand sdkFeatureBand) { string packagePath = null; string tempExtractionDir = null; string tempBackupDir = null; var manifestPath = Path.Combine(_dotnetDir, "sdk-manifests", sdkFeatureBand.ToString(), manifestId.ToString()); _reporter.WriteLine(string.Format(LocalizableStrings.InstallingWorkloadManifest, manifestId, manifestVersion)); try { TransactionalAction.Run( action: () => { packagePath = _nugetPackageDownloader.DownloadPackageAsync(WorkloadManifestUpdater.GetManifestPackageId(sdkFeatureBand, manifestId), new NuGetVersion(manifestVersion.ToString())).Result; tempExtractionDir = Path.Combine(_tempPackagesDir.Value, $"{manifestId}-{manifestVersion}-extracted"); Directory.CreateDirectory(tempExtractionDir); var manifestFiles = _nugetPackageDownloader.ExtractPackageAsync(packagePath, new DirectoryPath(tempExtractionDir)).Result; if (Directory.Exists(manifestPath) && Directory.GetFileSystemEntries(manifestPath).Any()) { // Backup existing manifest data for roll back purposes tempBackupDir = Path.Combine(_tempPackagesDir.Value, $"{manifestId}-{manifestVersion}-backup"); if (Directory.Exists(tempBackupDir)) { Directory.Delete(tempBackupDir, true); } FileAccessRetrier.RetryOnMoveAccessFailure(() => Directory.Move(manifestPath, tempBackupDir)); } Directory.CreateDirectory(Path.GetDirectoryName(manifestPath)); FileAccessRetrier.RetryOnMoveAccessFailure(() => Directory.Move(Path.Combine(tempExtractionDir, "data"), manifestPath)); }, rollback: () => { if (!string.IsNullOrEmpty(tempBackupDir) && Directory.Exists(tempBackupDir)) { FileAccessRetrier.RetryOnMoveAccessFailure(() => Directory.Move(tempBackupDir, manifestPath)); } }); // Delete leftover dirs and files if (!string.IsNullOrEmpty(packagePath) && File.Exists(packagePath)) { File.Delete(packagePath); } var versionDir = Path.GetDirectoryName(packagePath); if (Directory.Exists(versionDir) && !Directory.GetFileSystemEntries(versionDir).Any()) { Directory.Delete(versionDir); var idDir = Path.GetDirectoryName(versionDir); if (Directory.Exists(idDir) && !Directory.GetFileSystemEntries(idDir).Any()) { Directory.Delete(idDir); } } if (!string.IsNullOrEmpty(tempExtractionDir) && Directory.Exists(tempExtractionDir)) { Directory.Delete(tempExtractionDir, true); } if (!string.IsNullOrEmpty(tempBackupDir) && Directory.Exists(tempBackupDir)) { Directory.Delete(tempBackupDir, true); } } catch (Exception e) { throw new Exception(string.Format(LocalizableStrings.FailedToInstallWorkloadManifest, manifestId, manifestVersion, e.Message)); } }