Skip to content

Commit

Permalink
(chocolatey#1054) Ensure backups & beforeModify for dependencies
Browse files Browse the repository at this point in the history
Previously we only ran backups and beforeModify scripts on the target
package(s) and not their dependencies.

This change should ensure we are _always_ running backups on any
existing packages from a NuGet source before we try to modify them in
any way. Additionally, this should ensure we can run the beforeModify
scripts for ALL dependencies of the target package(s).
  • Loading branch information
vexx32 committed Feb 27, 2023
1 parent 2e7ceca commit 5a3bb05
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -606,7 +606,8 @@ public virtual ConcurrentDictionary<string, PackageResult> install_run(Chocolate
action = (packageResult) => handle_package_result(packageResult, packageConfig, CommandNameType.install);
}

var results = perform_source_runner_function(packageConfig, r => r.install_run(packageConfig, action));
var beforeModifyAction = new Action<PackageResult>(packageResult => before_package_modify(packageResult, config));
var results = perform_source_runner_function(packageConfig, r => r.install_run(packageConfig, action, beforeModifyAction));

foreach (var result in results)
{
Expand Down
109 changes: 70 additions & 39 deletions src/chocolatey/infrastructure.app/services/NugetService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ namespace chocolatey.infrastructure.app.services
using System.Net;
using adapters;
using chocolatey.infrastructure.app.utility;
using chocolatey.infrastructure.configuration;
using commandline;
using configuration;
using domain;
Expand Down Expand Up @@ -444,6 +445,7 @@ public virtual ConcurrentDictionary<string, PackageResult> install_run(Chocolate
if (continueAction != null) continueAction.Invoke(packageResult);
},
uninstallSuccessAction: null,
beforeModifyAction: get_before_modify_handler(config, beforeModifyAction),
addUninstallHandler: true);

config.start_backup();
Expand Down Expand Up @@ -630,6 +632,7 @@ public virtual ConcurrentDictionary<string, PackageResult> upgrade_run(Chocolate
if (continueAction != null) continueAction.Invoke(packageResult);
},
uninstallSuccessAction: null,
beforeModifyAction: get_before_modify_handler(config, beforeUpgradeAction),
addUninstallHandler: false);

var configIgnoreDependencies = config.IgnoreDependencies;
Expand Down Expand Up @@ -680,7 +683,7 @@ public virtual ConcurrentDictionary<string, PackageResult> upgrade_run(Chocolate
}
else
{
var installResults = install_run(config, continueAction);
var installResults = install_run(config, continueAction, beforeUpgradeAction);
foreach (var result in installResults)
{
packageInstalls.GetOrAdd(result.Key, result.Value);
Expand Down Expand Up @@ -845,17 +848,6 @@ public virtual ConcurrentDictionary<string, PackageResult> upgrade_run(Chocolate
packageName,
version == null ? null : version.ToString()))
{
if (beforeUpgradeAction != null)
{
var currentPackageResult = new PackageResult(installedPackage, get_install_directory(config, installedPackage));
beforeUpgradeAction(currentPackageResult);
}

remove_rollback_directory_if_exists(packageName);
ensure_package_files_have_compatible_attributes(config, installedPackage, pkgInfo);
rename_legacy_package_version(config, installedPackage, pkgInfo);
backup_existing_version(config, installedPackage, pkgInfo);
remove_shim_directors(config, installedPackage, pkgInfo);
if (config.Force && (installedPackage.Version == availablePackage.Version))
{
FaultTolerance.try_catch_with_logging_exception(
Expand All @@ -871,6 +863,7 @@ public virtual ConcurrentDictionary<string, PackageResult> upgrade_run(Chocolate
{
packageManager.UpdatePackage(availablePackage, updateDependencies: !config.IgnoreDependencies, allowPrereleaseVersions: config.Prerelease);
}

remove_nuget_cache_for_package(availablePackage);
}
}
Expand Down Expand Up @@ -910,6 +903,7 @@ public virtual ConcurrentDictionary<string, PackageResult> get_outdated(Chocolat
_packageDownloader,
installSuccessAction: null,
uninstallSuccessAction: null,
beforeModifyAction: null,
addUninstallHandler: false);

var repository = packageManager.SourceRepository;
Expand Down Expand Up @@ -1104,7 +1098,7 @@ public virtual void backup_existing_version(ChocolateyConfiguration config, IPac
var errored = false;
try
{
_fileSystem.move_directory(pkgInstallPath, backupLocation);
_fileSystem.copy_directory(pkgInstallPath, backupLocation, overwriteExisting: true);
}
catch (Exception ex)
{
Expand All @@ -1115,8 +1109,6 @@ public virtual void backup_existing_version(ChocolateyConfiguration config, IPac
{
try
{
_fileSystem.copy_directory(backupLocation, pkgInstallPath, overwriteExisting: true);

remove_packaging_files_prior_to_upgrade(pkgInstallPath, config.CommandName);
}
catch (Exception ex)
Expand Down Expand Up @@ -1287,14 +1279,18 @@ public virtual ConcurrentDictionary<string, PackageResult> uninstall_run(Chocola
var packageUninstalls = new ConcurrentDictionary<string, PackageResult>(StringComparer.InvariantCultureIgnoreCase);

SemanticVersion version = config.Version != null ? new SemanticVersion(config.Version) : null;
var packageManager = NugetCommon.GetPackageManager(config, _nugetLogger, _packageDownloader,
installSuccessAction: null,
uninstallSuccessAction: (e) =>
{
var pkg = e.Package;
"chocolatey".Log().Info(ChocolateyLoggers.Important, " {0} has been successfully uninstalled.".format_with(pkg.Id));
},
addUninstallHandler: true);
var packageManager = NugetCommon.GetPackageManager(
config,
_nugetLogger,
_packageDownloader,
installSuccessAction: null,
uninstallSuccessAction: (e) =>
{
var pkg = e.Package;
"chocolatey".Log().Info(ChocolateyLoggers.Important, " {0} has been successfully uninstalled.".format_with(pkg.Id));
},
beforeModifyAction: get_before_modify_handler(config, beforeUninstallAction),
addUninstallHandler: true);

var loopCount = 0;
packageManager.PackageUninstalling += (s, e) =>
Expand Down Expand Up @@ -1326,8 +1322,8 @@ public virtual ConcurrentDictionary<string, PackageResult> uninstall_run(Chocola
}

// is this the latest version, have you passed --sxs, or is this a side-by-side install? This is the only way you get through to the continue action.
var latestVersion = packageManager.LocalRepository.FindPackage(e.Package.Id);
var pkgInfo = _packageInfoService.get_package_information(e.Package);
var latestVersion = packageManager.LocalRepository.FindPackage(pkg.Id);
var pkgInfo = _packageInfoService.get_package_information(pkg);
if (latestVersion.Version == pkg.Version || config.AllowMultipleVersions || (pkgInfo != null && pkgInfo.IsSideBySide))
{
packageResult.Messages.Add(new ResultMessage(ResultType.Debug, ApplicationParameters.Messages.ContinueChocolateyAction));
Expand All @@ -1337,6 +1333,10 @@ public virtual ConcurrentDictionary<string, PackageResult> uninstall_run(Chocola
{
//todo: #2578 allow cleaning of pkgstore files
}

ensure_nupkg_is_removed(pkg, pkgInfo);
remove_installation_files(pkg, pkgInfo);
remove_cache_for_package(config, pkg);
};

// if we are uninstalling a package and not forcing dependencies,
Expand Down Expand Up @@ -1495,21 +1495,7 @@ public virtual ConcurrentDictionary<string, PackageResult> uninstall_run(Chocola
packageVersion.Id, packageVersion.Version.to_string())
)
{
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)));
var currentPackageResult = new PackageResult(packageVersion, get_install_directory(config, packageVersion));
beforeUninstallAction(currentPackageResult);
}
ensure_package_files_have_compatible_attributes(config, packageVersion, pkgInfo);
rename_legacy_package_version(config, packageVersion, pkgInfo);
remove_rollback_directory_if_exists(packageName);
backup_existing_version(config, packageVersion, pkgInfo);
packageManager.UninstallPackage(packageVersion.Id.to_lower(), forceRemove: config.Force, removeDependencies: config.ForceDependencies, version: packageVersion.Version);
ensure_nupkg_is_removed(packageVersion, pkgInfo);
remove_installation_files(packageVersion, pkgInfo);
remove_cache_for_package(config, packageVersion);
}
}
catch (Exception ex)
Expand Down Expand Up @@ -1543,6 +1529,51 @@ public virtual ConcurrentDictionary<string, PackageResult> uninstall_run(Chocola
return packageUninstalls;
}

/// <summary>
/// Gets a handler action which can be passed into the IPackageManager as the beforeModifyAction,
/// based on a given beforeModifyAction for a package (typically a beforeModify script run action).
/// </summary>
/// <param name="config">The current configuration.</param>
/// <param name="beforeModifyAction">
/// An action to take on a PackageResult object, typically an invocation of a beforeModify powershell script.
/// This action will NOT be invoked if the package is not already installed, so it is safe to pass in the action
/// even for install_run cases, where it may be needed in the case that dependencies need to be updated during
/// the installation of the new package.
/// </param>
/// <returns></returns>
Action<PackageOperationEventArgs> get_before_modify_handler(ChocolateyConfiguration config, Action<PackageResult> beforeModifyAction)
{
void handler(PackageOperationEventArgs args)
{
var installDirectory = get_install_directory(config, args.Package);

if (installDirectory != 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}'", args.Package.Id);

var packageToModify = new PackageResult(args.Package, installDirectory);
beforeModifyAction(packageToModify);
}

var packageInformation = _packageInfoService.get_package_information(args.Package);

"chocolatey".Log().Debug("Backing up package files for '{0}'", args.Package.Id);

ensure_package_files_have_compatible_attributes(config, args.Package, packageInformation);
rename_legacy_package_version(config, args.Package, packageInformation);
remove_rollback_directory_if_exists(args.Package.Id);
backup_existing_version(config, args.Package, packageInformation);
remove_shim_directors(config, args.Package, packageInformation);
}
}

return handler;
}


/// <summary>
/// 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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ public void list(ChocolateyConfiguration configuration)
new PackageDownloader(),
installSuccessAction: null,
uninstallSuccessAction: null,
beforeModifyAction: null,
addUninstallHandler: false);

var templateDirList = _fileSystem.get_directories(ApplicationParameters.TemplatesLocation).ToList();
Expand Down

0 comments on commit 5a3bb05

Please sign in to comment.