diff --git a/src/Orchard/Environment/Features/FeatureManager.cs b/src/Orchard/Environment/Features/FeatureManager.cs index fb2db8a77..8c788386d 100644 --- a/src/Orchard/Environment/Features/FeatureManager.cs +++ b/src/Orchard/Environment/Features/FeatureManager.cs @@ -107,12 +107,8 @@ namespace Orchard.Environment.Features { ShellDescriptor shellDescriptor = _shellDescriptorManager.GetShellDescriptor(); List enabledFeatures = shellDescriptor.Features.ToList(); - IDictionary availableFeatures = GetAvailableFeatures() - .ToDictionary(featureDescriptor => featureDescriptor, - featureDescriptor => enabledFeatures.FirstOrDefault(shellFeature => shellFeature.Name.Equals(featureDescriptor.Id)) != null); - IEnumerable featuresToDisable = featureIds - .Select(featureId => DisableFeature(featureId, availableFeatures, force)).ToList() + .Select(featureId => DisableFeature(featureId, force)).ToList() .SelectMany(ies => ies.Select(s => s)); if (featuresToDisable.Any()) { @@ -130,6 +126,30 @@ namespace Orchard.Environment.Features { return featuresToDisable; } + /// + /// Lists all enabled features that depend on a given feature. + /// + /// ID of the feature to check. + /// An enumeration with dependent feature IDs. + public IEnumerable GetDependentFeatures(string featureId) { + var getEnabledDependants = + new Func, IDictionary>( + (currentFeatureId, fs) => fs + .Where(f => f.Value && f.Key.Dependencies != null && f.Key.Dependencies + .Select(s => s.ToLowerInvariant()) + .Contains(currentFeatureId.ToLowerInvariant())) + .ToDictionary(f => f.Key, f => f.Value)); + + ShellDescriptor shellDescriptor = _shellDescriptorManager.GetShellDescriptor(); + List enabledFeatures = shellDescriptor.Features.ToList(); + + IDictionary availableFeatures = GetAvailableFeatures() + .ToDictionary(featureDescriptor => featureDescriptor, + featureDescriptor => enabledFeatures.FirstOrDefault(shellFeature => shellFeature.Name.Equals(featureDescriptor.Id)) != null); + + return GetAffectedFeatures(featureId, availableFeatures, getEnabledDependants); + } + /// /// Enables a feature. /// @@ -179,16 +199,11 @@ namespace Orchard.Environment.Features { /// Disables a feature. /// /// The ID of the feature to be enabled. - /// /// Boolean parameter indicating if the feature should enable it's dependencies if required or fail otherwise. /// An enumeration of the disabled features. - private IEnumerable DisableFeature(string featureId, IDictionary availableFeatures, bool force) { - var getEnabledDependants = - new Func, IDictionary>( - (currentFeatureId, fs) => fs.Where(f => f.Value && f.Key.Dependencies != null && f.Key.Dependencies.Select(s => s.ToLowerInvariant()).Contains(currentFeatureId.ToLowerInvariant())) - .ToDictionary(f => f.Key, f => f.Value)); + private IEnumerable DisableFeature(string featureId, bool force) { + IEnumerable featuresToDisable = GetDependentFeatures(featureId); - IEnumerable featuresToDisable = GetAffectedFeatures(featureId, availableFeatures, getEnabledDependants); if (featuresToDisable.Count() > 1 && !force) { Logger.Warning("Additional features need to be disabled."); if (FeatureDependencyNotification != null) { @@ -201,11 +216,21 @@ namespace Orchard.Environment.Features { return featuresToDisable; } - private static IEnumerable GetAffectedFeatures(string featureId, IDictionary features, Func, IDictionary> getAffectedDependencies) { - var dependencies = new List { featureId }; + private static IEnumerable GetAffectedFeatures( + string featureId, IDictionary features, + Func, IDictionary> getAffectedDependencies) { - foreach (KeyValuePair dependency in getAffectedDependencies(featureId, features)) { - dependencies.AddRange(GetAffectedFeatures(dependency.Key.Id, features, getAffectedDependencies)); + var dependencies = new HashSet(StringComparer.OrdinalIgnoreCase) { featureId }; + var stack = new Stack>(); + + stack.Push(getAffectedDependencies(featureId, features)); + + while (stack.Any()) { + var next = stack.Pop(); + foreach (var dependency in next.Where(dependency => !dependencies.Contains(dependency.Key.Id))) { + dependencies.Add(dependency.Key.Id); + stack.Push(getAffectedDependencies(dependency.Key.Id, features)); + } } return dependencies; diff --git a/src/Orchard/Environment/Features/IFeatureManager.cs b/src/Orchard/Environment/Features/IFeatureManager.cs index 60561022a..962d09f2f 100644 --- a/src/Orchard/Environment/Features/IFeatureManager.cs +++ b/src/Orchard/Environment/Features/IFeatureManager.cs @@ -48,5 +48,12 @@ namespace Orchard.Environment.Features { /// Boolean parameter indicating if the feature should disable the features which depend on it if required or fail otherwise. /// An enumeration with the disabled feature IDs. IEnumerable DisableFeatures(IEnumerable featureIds, bool force); + + /// + /// Lists all enabled features that depend on a given feature. + /// + /// ID of the feature to check. + /// An enumeration with dependent feature IDs. + IEnumerable GetDependentFeatures(string featureId); } } \ No newline at end of file