From 3f2831e94969e8df814d3b2921efca23da618689 Mon Sep 17 00:00:00 2001 From: Rob Reynolds Date: Sat, 28 May 2016 12:57:35 -0500 Subject: [PATCH] (GH-198) Remove existing pending packages If any packages are in a pending state, it means the install did not complete successfully, so those packages should not actually be considered "installed". Those pending packages should be removed with a warning. --- src/chocolatey/chocolatey.csproj | 1 + .../registration/ContainerBinding.cs | 14 +++++ .../tasks/RemovePendingPackagesTask.cs | 63 +++++++++++++++++++ 3 files changed, 78 insertions(+) create mode 100644 src/chocolatey/infrastructure.app/tasks/RemovePendingPackagesTask.cs diff --git a/src/chocolatey/chocolatey.csproj b/src/chocolatey/chocolatey.csproj index d29685d021..7980d6ce1f 100644 --- a/src/chocolatey/chocolatey.csproj +++ b/src/chocolatey/chocolatey.csproj @@ -99,6 +99,7 @@ + diff --git a/src/chocolatey/infrastructure.app/registration/ContainerBinding.cs b/src/chocolatey/infrastructure.app/registration/ContainerBinding.cs index 7f0f6494f9..74e98b69d1 100644 --- a/src/chocolatey/infrastructure.app/registration/ContainerBinding.cs +++ b/src/chocolatey/infrastructure.app/registration/ContainerBinding.cs @@ -17,6 +17,7 @@ namespace chocolatey.infrastructure.app.registration { using System.Collections.Generic; using infrastructure.events; + using infrastructure.tasks; using NuGet; using SimpleInjector; using adapters; @@ -28,6 +29,7 @@ namespace chocolatey.infrastructure.app.registration using infrastructure.services; using nuget; using services; + using tasks; using CryptoHashProvider = cryptography.CryptoHashProvider; using IFileSystem = filesystem.IFileSystem; using IHashProvider = cryptography.IHashProvider; @@ -111,6 +113,18 @@ public void RegisterComponents(Container container) container.Register(Lifestyle.Singleton); EventManager.initialize_with(container.GetInstance); + container.Register>( + () => + { + var list = new List + { + new RemovePendingPackagesTask(container.GetInstance()) + }; + + return list.AsReadOnly(); + }, + Lifestyle.Singleton); + container.Register(Lifestyle.Singleton); } } diff --git a/src/chocolatey/infrastructure.app/tasks/RemovePendingPackagesTask.cs b/src/chocolatey/infrastructure.app/tasks/RemovePendingPackagesTask.cs new file mode 100644 index 0000000000..e68b2454f4 --- /dev/null +++ b/src/chocolatey/infrastructure.app/tasks/RemovePendingPackagesTask.cs @@ -0,0 +1,63 @@ +// Copyright © 2011 - Present RealDimensions Software, LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace chocolatey.infrastructure.app.tasks +{ + using System; + using System.IO; + using System.Linq; + using events; + using filesystem; + using infrastructure.events; + using infrastructure.tasks; + using logging; + using tolerance; + + public class RemovePendingPackagesTask : ITask + { + private readonly IFileSystem _fileSystem; + private IDisposable _subscription; + + public RemovePendingPackagesTask(IFileSystem fileSystem) + { + _fileSystem = fileSystem; + } + + public void initialize() + { + _subscription = EventManager.subscribe(handle_message, null, null); + this.Log().Debug(ChocolateyLoggers.Verbose, () => "{0} is now ready and waiting for {1}.".format_with(GetType().Name, typeof(PreRunMessage).Name)); + } + + public void shutdown() + { + if (_subscription != null) _subscription.Dispose(); + } + + private void handle_message(PreRunMessage message) + { + this.Log().Debug(ChocolateyLoggers.Verbose, "[Pending] Removing all pending packages that should not be considered installed..."); + + var pendingFiles = _fileSystem.get_files(ApplicationParameters.PackagesLocation, ApplicationParameters.PackagePendingFileName, SearchOption.AllDirectories).ToList(); + foreach (var pendingFile in pendingFiles.or_empty_list_if_null()) + { + var packageFolder = _fileSystem.get_directory_name(pendingFile); + this.Log().Warn("[Pending] Removing incomplete install for '{0}'".format_with(_fileSystem.get_directory_info_for(packageFolder).Name)); + + FaultTolerance.retry(2, () => _fileSystem.delete_directory_if_exists(packageFolder, recursive: true, overrideAttributes: true, isSilent: true), 500, isSilent: true); + } + } + } +}