From 10c0baabf43697d1d8f7dba48cae592b2548dd26 Mon Sep 17 00:00:00 2001 From: Lombiq Date: Tue, 27 Jan 2015 18:33:09 +0100 Subject: [PATCH] Implementing proper package uninstall process with features being disabled and uninstalled, then the package being removed. --- .../Orchard.Packaging.csproj | 1 + .../Services/PackageManager.cs | 38 ++++++++- .../Services/PackageUninstallHandler.cs | 84 +++++++++++++++++++ 3 files changed, 121 insertions(+), 2 deletions(-) create mode 100644 src/Orchard.Web/Modules/Orchard.Packaging/Services/PackageUninstallHandler.cs diff --git a/src/Orchard.Web/Modules/Orchard.Packaging/Orchard.Packaging.csproj b/src/Orchard.Web/Modules/Orchard.Packaging/Orchard.Packaging.csproj index 41fb44184..50846ff2a 100644 --- a/src/Orchard.Web/Modules/Orchard.Packaging/Orchard.Packaging.csproj +++ b/src/Orchard.Web/Modules/Orchard.Packaging/Orchard.Packaging.csproj @@ -110,6 +110,7 @@ + diff --git a/src/Orchard.Web/Modules/Orchard.Packaging/Services/PackageManager.cs b/src/Orchard.Web/Modules/Orchard.Packaging/Services/PackageManager.cs index 60d3e44cc..03f0bfa41 100644 --- a/src/Orchard.Web/Modules/Orchard.Packaging/Services/PackageManager.cs +++ b/src/Orchard.Web/Modules/Orchard.Packaging/Services/PackageManager.cs @@ -5,6 +5,8 @@ using NuGet; using Orchard.Environment.Extensions; using Orchard.Environment.Extensions.Folders; using Orchard.Environment.Extensions.Models; +using Orchard.Environment.Features; +using Orchard.Environment.State; using Orchard.Localization; using Orchard.Packaging.Models; @@ -14,14 +16,23 @@ namespace Orchard.Packaging.Services { private readonly IExtensionManager _extensionManager; private readonly IPackageBuilder _packageBuilder; private readonly IPackageInstaller _packageInstaller; + private readonly IShellStateManager _shellStateManager; + private readonly IFeatureManager _featureManager; + private readonly IPackageUninstallHandler _packageUninstallHandler; public PackageManager( IExtensionManager extensionManager, IPackageBuilder packageBuilder, - IPackageInstaller packageInstaller) { + IPackageInstaller packageInstaller, + IShellStateManager shellStateManager, + IFeatureManager featureManager, + IPackageUninstallHandler packageUninstallHandler) { _extensionManager = extensionManager; _packageBuilder = packageBuilder; _packageInstaller = packageInstaller; + _shellStateManager = shellStateManager; + _featureManager = featureManager; + _packageUninstallHandler = packageUninstallHandler; T = NullLocalizer.Instance; } @@ -69,7 +80,30 @@ namespace Orchard.Packaging.Services { } public void Uninstall(string packageId, string applicationPath) { - _packageInstaller.Uninstall(packageId, applicationPath); + var extensionToUninstall = _extensionManager.AvailableExtensions() + .FirstOrDefault(extension => PackageBuilder.BuildPackageId(extension.Id, extension.ExtensionType) == packageId); + + if (extensionToUninstall == null) { + throw new OrchardException(T("There is no extension that has the package ID \"{0}\".", packageId)); + } + + var featureIdsToUninstall = extensionToUninstall.Features.Select(feature => feature.Id); + var shellState = _shellStateManager.GetShellState(); + var featureStates = shellState.Features.Where(featureState => featureIdsToUninstall.Contains(featureState.Name)); + + // This means that no feature from this extension wasn enabled yet, can be uninstalled directly. + if (!featureStates.Any()) { + _packageUninstallHandler.QueuePackageUninstall(packageId); + } + else { + _featureManager.DisableFeatures(extensionToUninstall.Features.Select(feature => feature.Id), true); + + // Installed state can't be deduced from the shell state changes like for enabled state, so have to + // set that explicitly. + foreach (var featureState in featureStates) { + _shellStateManager.UpdateInstalledState(featureState, Environment.State.Models.ShellFeatureState.State.Falling); + } + } } #endregion diff --git a/src/Orchard.Web/Modules/Orchard.Packaging/Services/PackageUninstallHandler.cs b/src/Orchard.Web/Modules/Orchard.Packaging/Services/PackageUninstallHandler.cs new file mode 100644 index 000000000..77fb61a7e --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Packaging/Services/PackageUninstallHandler.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using Orchard.Environment; +using Orchard.Environment.Configuration; +using Orchard.Environment.Descriptor; +using Orchard.Environment.Extensions.Models; +using Orchard.Environment.State; +using Orchard.Events; + +namespace Orchard.Packaging.Services { + public interface IPackageUninstallHandler : IEventHandler { + /// + /// Queues a package to be uninstalled after the request is processed. + /// + /// The textual ID of the package. + void QueuePackageUninstall(string packageId); + + /// + /// Uninstalls the given package from the system. + /// + /// The textual ID of the package. + void UninstallPackage(string packageId); + } + + public class PackageUninstallHandler : IFeatureEventHandler, IPackageUninstallHandler { + private readonly ShellSettings _shellSettings; + private readonly IShellDescriptorManager _shellDescriptorManager; + private readonly IProcessingEngine _processingEngine; + private readonly IHostEnvironment _hostEnvironment; + private readonly IPackageInstaller _packageInstaller; + + public PackageUninstallHandler( + ShellSettings shellSettings, + IShellDescriptorManager shellDescriptorManager, + IProcessingEngine processingEngine, + IHostEnvironment hostEnvironment, + IPackageInstaller packageInstaller) { + _shellSettings = shellSettings; + _shellDescriptorManager = shellDescriptorManager; + _processingEngine = processingEngine; + _hostEnvironment = hostEnvironment; + _packageInstaller = packageInstaller; + } + + public void Installing(Feature feature) { + } + + public void Installed(Feature feature) { + } + + public void Enabling(Feature feature) { + } + + public void Enabled(Feature feature) { + } + + public void Disabling(Feature feature) { + } + + public void Disabled(Feature feature) { + } + + public void Uninstalling(Feature feature) { + } + + public void Uninstalled(Feature feature) { + QueuePackageUninstall(PackageBuilder.BuildPackageId(feature.Descriptor.Extension.Id, feature.Descriptor.Extension.ExtensionType)); + } + + public void QueuePackageUninstall(string packageId) { + _processingEngine.AddTask( + _shellSettings, + _shellDescriptorManager.GetShellDescriptor(), + "IPackageUninstallHandler.UninstallPackage", + new Dictionary { { "packageId", packageId } }); + } + + public void UninstallPackage(string packageId) { + _packageInstaller.Uninstall(packageId, _hostEnvironment.MapPath("~/")); + } + } +} \ No newline at end of file