diff --git a/src/chocolatey.tests/infrastructure.app/services/FilesServiceSpecs.cs b/src/chocolatey.tests/infrastructure.app/services/FilesServiceSpecs.cs index dd8bf96c41..5f4b471d9b 100644 --- a/src/chocolatey.tests/infrastructure.app/services/FilesServiceSpecs.cs +++ b/src/chocolatey.tests/infrastructure.app/services/FilesServiceSpecs.cs @@ -192,9 +192,15 @@ public void should_not_call_get_files() } [Fact] - public void should_return_null() + public void should_return_a_non_null_object() { - result.ShouldBeNull(); + result.ShouldNotBeNull(); + } + + [Fact] + public void should_return_empty_package_files() + { + result.Files.ShouldBeEmpty(); } } diff --git a/src/chocolatey.tests/infrastructure.app/services/NugetServiceSpecs.cs b/src/chocolatey.tests/infrastructure.app/services/NugetServiceSpecs.cs index e15e31af5f..1f89ade817 100644 --- a/src/chocolatey.tests/infrastructure.app/services/NugetServiceSpecs.cs +++ b/src/chocolatey.tests/infrastructure.app/services/NugetServiceSpecs.cs @@ -21,6 +21,7 @@ namespace chocolatey.tests.infrastructure.app.services using System.Linq; using Moq; using NuGet; + using chocolatey.infrastructure.app.configuration; using chocolatey.infrastructure.app.domain; using chocolatey.infrastructure.app.services; using IFileSystem = chocolatey.infrastructure.filesystem.IFileSystem; @@ -48,6 +49,70 @@ public override void Context() } } + public class when_NugetService_backs_up_changed_files : NugetServiceSpecsBase + { + private Action because; + private ChocolateyPackageInformation packageInfo; + private const string filePath = "c:\\tests"; + private PackageFiles packageFiles; + private readonly ChocolateyConfiguration config = new ChocolateyConfiguration(); + + public override void Context() + { + base.Context(); + package.Setup(x => x.Id).Returns("bob"); + packageInfo = new ChocolateyPackageInformation(package.Object); + packageInfo.FilesSnapshot = new PackageFiles(); + packageFiles = new PackageFiles(); + fileSystem.Setup(x => x.directory_exists(It.IsAny())).Returns(true); + } + + public override void Because() + { + because = () => service.backup_changed_files(filePath, config, packageInfo); + } + + [Fact] + public void should_ignore_an_unchanged_file() + { + Context(); + + var packageFile = new PackageFile { Path = filePath, Checksum = "1234" }; + packageFiles.Files.Add(packageFile); + packageInfo.FilesSnapshot = packageFiles; + + var fileSystemFiles = new List() { filePath }; + fileSystem.Setup(x => x.get_files(It.IsAny(), It.IsAny(), SearchOption.AllDirectories)).Returns(fileSystemFiles); + filesService.Setup(x => x.capture_package_files(It.IsAny(),config)).Returns(packageFiles); + + because(); + + fileSystem.Verify(x => x.copy_file(It.IsAny(),It.IsAny(),It.IsAny()),Times.Never); + } + + [Fact] + public void should_backup_a_changed_file() + { + Context(); + + var packageFile = new PackageFile { Path = filePath, Checksum = "1234" }; + packageFiles.Files.Add(packageFile); + packageInfo.FilesSnapshot = packageFiles; + + var packageFileWithUpdatedChecksum = new PackageFile { Path = filePath, Checksum = "4321" }; + + var fileSystemFiles = new List() { filePath }; + fileSystem.Setup(x => x.get_files(It.IsAny(), It.IsAny(), SearchOption.AllDirectories)).Returns(fileSystemFiles); + var updatedPackageFiles = new PackageFiles(); + updatedPackageFiles.Files = new List{packageFileWithUpdatedChecksum}; + filesService.Setup(x => x.capture_package_files(It.IsAny(), config)).Returns(updatedPackageFiles); + + because(); + + fileSystem.Verify(x => x.copy_file(It.IsAny(), It.IsAny(), It.IsAny()), Times.Once); + } + } + public class when_NugetService_removes_installation_files_on_uninstall : NugetServiceSpecsBase { private Action because; @@ -63,7 +128,6 @@ public override void Context() packageInfo.FilesSnapshot = new PackageFiles(); packageFiles = new List(); fileSystem.Setup(x => x.directory_exists(It.IsAny())).Returns(true); - } public override void Because() @@ -80,11 +144,9 @@ public void should_do_nothing_if_the_directory_no_longer_exists() var packageFile = new PackageFile { Path = filePath, Checksum = "1234" }; packageFiles.Add(packageFile); - packageInfo.FilesSnapshot.Files = packageFiles.ToList(); var fileSystemFiles = new List() { filePath }; - fileSystem.Setup(x => x.get_files(It.IsAny(), It.IsAny(), SearchOption.AllDirectories)).Returns(fileSystemFiles); filesService.Setup(x => x.get_package_file(It.IsAny())).Returns(packageFile); @@ -101,14 +163,10 @@ public void should_remove_an_unchanged_file() var packageFile = new PackageFile { Path = filePath, Checksum = "1234" }; packageFiles.Add(packageFile); - packageInfo.FilesSnapshot.Files = packageFiles.ToList(); var fileSystemFiles = new List() { filePath }; - - fileSystem.Setup(x => x.get_files(It.IsAny(), It.IsAny(), SearchOption.AllDirectories)).Returns(fileSystemFiles); - filesService.Setup(x => x.get_package_file(It.IsAny())).Returns(packageFile); because(); @@ -124,14 +182,10 @@ public void should_not_delete_a_changed_file() var packageFile = new PackageFile { Path = filePath, Checksum = "1234" }; var packageFileWithUpdatedChecksum = new PackageFile { Path = filePath, Checksum = "4321" }; packageFiles.Add(packageFile); - packageInfo.FilesSnapshot.Files = packageFiles.ToList(); var fileSystemFiles = new List() { filePath }; - - fileSystem.Setup(x => x.get_files(It.IsAny(), It.IsAny(), SearchOption.AllDirectories)).Returns(fileSystemFiles); - filesService.Setup(x => x.get_package_file(It.IsAny())).Returns(packageFileWithUpdatedChecksum); because(); diff --git a/src/chocolatey/infrastructure.app/services/FilesService.cs b/src/chocolatey/infrastructure.app/services/FilesService.cs index 462e7246af..86099c88d8 100644 --- a/src/chocolatey/infrastructure.app/services/FilesService.cs +++ b/src/chocolatey/infrastructure.app/services/FilesService.cs @@ -56,7 +56,7 @@ public void save_to_file(PackageFiles snapshot, string filePath) public PackageFiles capture_package_files(PackageResult packageResult, ChocolateyConfiguration config) { - if (packageResult == null) return null; + if (packageResult == null) return new PackageFiles(); var installDirectory = packageResult.InstallLocation; if (installDirectory.is_equal_to(ApplicationParameters.InstallLocation) || installDirectory.is_equal_to(ApplicationParameters.PackagesLocation)) @@ -72,15 +72,15 @@ public PackageFiles capture_package_files(PackageResult packageResult, Chocolate public PackageFiles capture_package_files(string directory, ChocolateyConfiguration config) { + var packageFiles = new PackageFiles(); + if (directory.is_equal_to(ApplicationParameters.InstallLocation) || directory.is_equal_to(ApplicationParameters.PackagesLocation)) { var logMessage = "Install location is not specific enough, cannot capture files:{0} Erroneous install location captured as '{1}'".format_with(Environment.NewLine, directory); this.Log().Error(logMessage); - return null; + return packageFiles; } - - var packageFiles = new PackageFiles(); - + this.Log().Debug(() => "Capturing package files in '{0}'".format_with(directory)); //gather all files in the folder var files = _fileSystem.get_files(directory, pattern: "*.*", option: SearchOption.AllDirectories); diff --git a/src/chocolatey/infrastructure.app/services/NugetService.cs b/src/chocolatey/infrastructure.app/services/NugetService.cs index ffb71c025f..d19bef25ed 100644 --- a/src/chocolatey/infrastructure.app/services/NugetService.cs +++ b/src/chocolatey/infrastructure.app/services/NugetService.cs @@ -317,7 +317,7 @@ public ConcurrentDictionary install_run(ChocolateyConfigu var forcedResult = packageInstalls.GetOrAdd(packageName, new PackageResult(installedPackage, _fileSystem.combine_paths(ApplicationParameters.PackagesLocation, installedPackage.Id))); forcedResult.Messages.Add(new ResultMessage(ResultType.Note, "Backing up and removing old version")); - backup_existing_version(config, installedPackage); + backup_existing_version(config, installedPackage, _packageInfoService.get_package_information(installedPackage)); try { @@ -580,7 +580,7 @@ packages as of version 1.0.0. That is what the install command is for. version == null ? null : version.ToString())) { rename_legacy_package_version(config, installedPackage, pkgInfo); - backup_existing_version(config, installedPackage); + backup_existing_version(config, installedPackage, pkgInfo); if (config.Force && (installedPackage.Version == availablePackage.Version)) { FaultTolerance.try_catch_with_logging_exception( @@ -627,7 +627,7 @@ public void rename_legacy_package_version(ChocolateyConfiguration config, IPacka } } - public void backup_existing_version(ChocolateyConfiguration config, IPackage installedPackage) + public void backup_existing_version(ChocolateyConfiguration config, IPackage installedPackage, ChocolateyPackageInformation packageInfo) { _fileSystem.create_directory_if_not_exists(ApplicationParameters.PackageBackupLocation); @@ -672,7 +672,7 @@ public void backup_existing_version(ChocolateyConfiguration config, IPackage ins } } - backup_configuration_files(pkgInstallPath, installedPackage.Version.to_string()); + backup_changed_files(pkgInstallPath, config, packageInfo); if (errored) { @@ -685,16 +685,41 @@ process locking the folder or files. Please make sure nothing is } } - private void backup_configuration_files(string packageInstallPath, string version) + public void backup_changed_files(string packageInstallPath, ChocolateyConfiguration config, ChocolateyPackageInformation packageInfo) { - var configFiles = _fileSystem.get_files(packageInstallPath, ApplicationParameters.ConfigFileExtensions, SearchOption.AllDirectories); - foreach (var file in configFiles.or_empty_list_if_null()) + if (packageInfo == null || packageInfo.Package == null) return; + + var version = packageInfo.Package.Version.to_string(); + + if (packageInfo.FilesSnapshot == null || packageInfo.FilesSnapshot.Files.Count == 0) { - var backupName = "{0}.{1}".format_with(_fileSystem.get_file_name(file), version); + var configFiles = _fileSystem.get_files(packageInstallPath, ApplicationParameters.ConfigFileExtensions, SearchOption.AllDirectories); + foreach (var file in configFiles.or_empty_list_if_null()) + { + var backupName = "{0}.{1}".format_with(_fileSystem.get_file_name(file), version); - FaultTolerance.try_catch_with_logging_exception( - () => _fileSystem.copy_file(file, _fileSystem.combine_paths(_fileSystem.get_directory_name(file), backupName), overwriteExisting: true), - "Error backing up configuration file"); + FaultTolerance.try_catch_with_logging_exception( + () => _fileSystem.copy_file(file, _fileSystem.combine_paths(_fileSystem.get_directory_name(file), backupName), overwriteExisting: true), + "Error backing up configuration file"); + } + } + else + { + var currentFiles = _filesService.capture_package_files(packageInstallPath, config); + foreach (var currentFile in currentFiles.Files.or_empty_list_if_null()) + { + var installedFile = packageInfo.FilesSnapshot.Files.FirstOrDefault(x => x.Path.is_equal_to(currentFile.Path)); + if (installedFile != null) + { + if (!currentFile.Checksum.is_equal_to(installedFile.Checksum)) + { + var backupName = "{0}.{1}".format_with(_fileSystem.get_file_name(currentFile.Path), version); + FaultTolerance.try_catch_with_logging_exception( + () => _fileSystem.copy_file(currentFile.Path, _fileSystem.combine_paths(_fileSystem.get_directory_name(currentFile.Path), backupName), overwriteExisting: true), + "Error backing up changed file"); + } + } + } } } @@ -862,7 +887,7 @@ public ConcurrentDictionary uninstall_run(ChocolateyConfi version == null ? null : version.ToString())) { rename_legacy_package_version(config, packageVersion, pkgInfo); - backup_existing_version(config, packageVersion); + backup_existing_version(config, packageVersion, pkgInfo); packageManager.UninstallPackage(packageVersion, forceRemove: config.Force, removeDependencies: config.ForceDependencies); ensure_nupkg_is_removed(packageVersion, pkgInfo); remove_installation_files(packageVersion, pkgInfo);