diff --git a/src/chocolatey/infrastructure.app/services/NugetService.cs b/src/chocolatey/infrastructure.app/services/NugetService.cs index 4525d2290a..502ddb9aba 100644 --- a/src/chocolatey/infrastructure.app/services/NugetService.cs +++ b/src/chocolatey/infrastructure.app/services/NugetService.cs @@ -762,8 +762,7 @@ Version was specified as '{0}'. It is possible that version if (packageToUninstall != null) { shouldAddForcedResultMessage = true; - remove_rollback_directory_if_exists(packageRemoteMetadata.Identity.Id); - backup_existing_version(config, packageToUninstall.PackageMetadata, _packageInfoService.get_package_information(packageToUninstall.PackageMetadata)); + backup_and_before_modify(packageToUninstall, config, beforeModifyAction); packageToUninstall.InstallLocation = pathResolver.GetInstallPath(packageToUninstall.Identity); try { @@ -1371,21 +1370,11 @@ public virtual ConcurrentDictionary upgrade_run(Chocolate try { - remove_rollback_directory_if_exists(packageName); - if (packageToUninstall != null) { var oldPkgInfo = _packageInfoService.get_package_information(packageToUninstall.PackageMetadata); - if (beforeUpgradeAction != null && packageToUninstall.PackageMetadata != null) - { - beforeUpgradeAction(packageToUninstall, config); - } - - ensure_package_files_have_compatible_attributes(config, packageToUninstall.PackageMetadata, oldPkgInfo); - rename_legacy_package_version(config, packageToUninstall.PackageMetadata, oldPkgInfo); - backup_existing_version(config, packageToUninstall.PackageMetadata, oldPkgInfo); - remove_shim_directors(config, packageToUninstall.PackageMetadata, pkgInfo); + backup_and_before_modify(packageToUninstall, oldPkgInfo, config, beforeUpgradeAction); packageToUninstall.InstallLocation = pathResolver.GetInstallPath(packageToUninstall.Identity); try @@ -1817,7 +1806,11 @@ private string get_install_directory(ChocolateyConfiguration config, IPackageMet return installDirectory; } + [Obsolete("This overload is obsolete and will be removed in a future version.")] public virtual void ensure_package_files_have_compatible_attributes(ChocolateyConfiguration config, IPackageMetadata installedPackage, ChocolateyPackageInformation pkgInfo) + => ensure_package_files_have_compatible_attributes(config, installedPackage); + + protected virtual void ensure_package_files_have_compatible_attributes(ChocolateyConfiguration config, IPackageMetadata installedPackage) { var installDirectory = get_install_directory(config, installedPackage); if (!_fileSystem.directory_exists(installDirectory)) return; @@ -1825,7 +1818,11 @@ public virtual void ensure_package_files_have_compatible_attributes(ChocolateyCo _filesService.ensure_compatible_file_attributes(installDirectory, config); } + [Obsolete("This overload is obsolete and will be removed in a future version.")] public virtual void rename_legacy_package_version(ChocolateyConfiguration config, IPackageMetadata installedPackage, ChocolateyPackageInformation pkgInfo) + => normalize_package_legacy_folder_name(config, installedPackage, pkgInfo); + + protected virtual void normalize_package_legacy_folder_name(ChocolateyConfiguration config, IPackageMetadata installedPackage, ChocolateyPackageInformation pkgInfo) { if (pkgInfo != null && pkgInfo.IsSideBySide) return; @@ -1845,15 +1842,19 @@ public virtual void rename_legacy_package_version(ChocolateyConfiguration config } + [Obsolete("This overload is obsolete and will be removed in a future version.")] public virtual void backup_existing_version(ChocolateyConfiguration config, IPackageMetadata installedPackage, ChocolateyPackageInformation packageInfo) + => backup_existing_version(config, packageInfo); + + protected virtual void backup_existing_version(ChocolateyConfiguration config, ChocolateyPackageInformation packageInfo) { _fileSystem.create_directory_if_not_exists(ApplicationParameters.PackageBackupLocation); - var pkgInstallPath = get_install_directory(config, installedPackage); + var pkgInstallPath = get_install_directory(config, packageInfo.Package); if (_fileSystem.directory_exists(pkgInstallPath)) { - this.Log().Debug("Backing up existing {0} prior to operation.".format_with(installedPackage.Id)); + this.Log().Debug("Backing up existing {0} prior to operation.".format_with(packageInfo.Package.Id)); var backupLocation = pkgInstallPath.Replace(ApplicationParameters.PackagesLocation, ApplicationParameters.PackageBackupLocation); @@ -1970,7 +1971,7 @@ public virtual void backup_changed_files(string packageInstallPath, ChocolateyCo /// The configuration. /// The installed package. /// The package information. - private void remove_shim_directors(ChocolateyConfiguration config, IPackageMetadata installedPackage, ChocolateyPackageInformation pkgInfo) + private void remove_shim_directors(ChocolateyConfiguration config, IPackageMetadata installedPackage) { var pkgInstallPath = get_install_directory(config, installedPackage); @@ -2211,7 +2212,6 @@ public virtual ConcurrentDictionary uninstall_run(Chocola var pathResolver = NugetCommon.GetPathResolver(config, _fileSystem); var nugetProject = new FolderNuGetProject(ApplicationParameters.PackagesLocation, pathResolver, NuGetFramework.AnyFramework); - var pkgInfo = _packageInfoService.get_package_information(installedPackage.PackageMetadata); if (pkgInfo != null && pkgInfo.IsPinned) { @@ -2241,21 +2241,10 @@ public virtual ConcurrentDictionary uninstall_run(Chocola foreach (var packageToUninstall in packagesToUninstall) { - if (beforeUninstallAction != null) - { - // guessing this is not added so that it doesn't fail the action if an error is recorded? - //var currentPackageResult = packageUninstalls.GetOrAdd(packageName, new PackageResult(packageVersion, get_install_directory(config, packageVersion))); - beforeUninstallAction(packageToUninstall, config); - } - - var uninstallPkgInfo = _packageInfoService.get_package_information(packageToUninstall.PackageMetadata); - try { - ensure_package_files_have_compatible_attributes(config, packageToUninstall.PackageMetadata, uninstallPkgInfo); - rename_legacy_package_version(config, packageToUninstall.PackageMetadata, uninstallPkgInfo); - remove_rollback_directory_if_exists(packageName); - backup_existing_version(config, packageToUninstall.PackageMetadata, uninstallPkgInfo); + var uninstallPkgInfo = _packageInfoService.get_package_information(packageToUninstall.PackageMetadata); + backup_and_before_modify(packageToUninstall, uninstallPkgInfo, config, beforeUninstallAction); var packageResult = packageResultsToReturn.GetOrAdd(packageToUninstall.Name + "." + packageToUninstall.Version.to_string(), packageToUninstall); packageResult.InstallLocation = packageToUninstall.InstallLocation; @@ -2320,6 +2309,76 @@ public virtual ConcurrentDictionary uninstall_run(Chocola return packageResultsToReturn; } + /// + /// This method should be called before any modifications are made to a package. + /// Typically this should be called before doing an uninstall of an existing package + /// or package dependency during an install, upgrade, or uninstall operation. + /// + /// The package currently being modified. + /// The current configuration. + /// Any action to run before performing backup operations. Typically this is an invocation of the chocolateyBeforeModify script. + protected void backup_and_before_modify( + PackageResult packageResult, + ChocolateyConfiguration config, + Action beforeModifyAction) + { + var packageInformation = _packageInfoService.get_package_information(packageResult.PackageMetadata); + backup_and_before_modify(packageResult, packageInformation, config, beforeModifyAction); + } + + /// + /// This method should be called before any modifications are made to a package. + /// Typically this should be called before doing an uninstall of an existing package + /// or package dependency during an install, upgrade, or uninstall operation. + /// + /// The package currently being modified. + /// The package information for the package being modified. + /// The current configuration. + /// Any action to run before performing backup operations. Typically this is an invocation of the chocolateyBeforeModify script. + protected virtual void backup_and_before_modify( + PackageResult packageResult, + ChocolateyPackageInformation packageInformation, + ChocolateyConfiguration config, + Action beforeModifyAction) + { + try + { + if (packageResult.InstallLocation != null) + { + // If this is an already installed package we're modifying, ensure we run its beforeModify script and back it up properly. + if (beforeModifyAction != null) + { + "chocolatey".Log().Debug("Running beforeModify step for '{0}'", packageResult.PackageMetadata.Id); + beforeModifyAction(packageResult, config); + } + + "chocolatey".Log().Debug("Backing up package files for '{0}'", packageResult.PackageMetadata.Id); + + backup_existing_package_files(config, packageResult.PackageMetadata, packageInformation); + } + } + catch (Exception error) + { + "chocolatey".Log().Error("Failed to run backup or beforeModify steps for package '{0}': {1}", packageResult.PackageMetadata.Id, error.Message); + "chocolatey".Log().Trace(error.StackTrace); + } + } + + /// + /// Takes a backup of the existing package files. + /// + /// The current configuration settings + /// The metadata for the package to backup + /// The package information to backup + protected void backup_existing_package_files(ChocolateyConfiguration config, IPackageMetadata package, ChocolateyPackageInformation packageInformation) + { + remove_rollback_directory_if_exists(package.Id); + ensure_package_files_have_compatible_attributes(config, package); + normalize_package_legacy_folder_name(config, package, packageInformation); + backup_existing_version(config, packageInformation); + remove_shim_directors(config, package); + } + /// /// NuGet will happily report a package has been uninstalled, even if it doesn't always remove the nupkg. /// Ensure that the package is deleted or throw an error.