Extensions are not enabled any more if they can't actually be loaded, fixes #2437

This commit is contained in:
Lombiq
2016-12-10 01:43:36 +01:00
committed by Zoltán Lehóczky
parent 80856c2d13
commit f89dfbf715
13 changed files with 133 additions and 23 deletions

View File

@@ -194,6 +194,10 @@ Features:
throw new NotImplementedException();
}
public bool LoaderIsSuitable(ExtensionDescriptor descriptor) {
throw new NotImplementedException();
}
#endregion
}

View File

@@ -114,6 +114,10 @@ namespace Orchard.Tests.Environment.Extensions {
throw new NotImplementedException();
}
public bool LoaderIsSuitable(ExtensionDescriptor descriptor) {
throw new NotImplementedException();
}
#endregion
}

View File

@@ -119,6 +119,10 @@ namespace Orchard.Tests.Environment.Extensions {
throw new NotImplementedException();
}
public bool LoaderIsSuitable(ExtensionDescriptor descriptor) {
throw new NotImplementedException();
}
#endregion
}

View File

@@ -46,8 +46,7 @@ namespace Orchard.Modules.Controllers {
IRecipeManager recipeManager,
ShellDescriptor shellDescriptor,
ShellSettings shellSettings,
IShapeFactory shapeFactory)
{
IShapeFactory shapeFactory) {
Services = services;
_extensionDisplayEventHandler = extensionDisplayEventHandlers.FirstOrDefault();
_moduleService = moduleService;
@@ -77,7 +76,7 @@ namespace Orchard.Modules.Controllers {
IEnumerable<ModuleEntry> modules = _extensionManager.AvailableExtensions()
.Where(extensionDescriptor => DefaultExtensionTypes.IsModule(extensionDescriptor.ExtensionType) &&
(string.IsNullOrEmpty(options.SearchText) || extensionDescriptor.Name.ToLowerInvariant().Contains(options.SearchText.ToLowerInvariant())))
.OrderBy(extensionDescriptor => extensionDescriptor.Name)
.Select(extensionDescriptor => new ModuleEntry { Descriptor = extensionDescriptor });
@@ -158,13 +157,13 @@ namespace Orchard.Modules.Controllers {
try {
_recipeManager.Execute(recipe);
}
catch(Exception e) {
catch (Exception e) {
Logger.Error(e, "Error while executing recipe {0} in {1}", moduleId, name);
Services.Notifier.Error(T("Recipes {0} contains unsupported module installation steps.", recipe.Name));
}
Services.Notifier.Success(T("The recipe {0} was executed successfully.", recipe.Name));
return RedirectToAction("Recipes");
}
@@ -177,15 +176,15 @@ namespace Orchard.Modules.Controllers {
IEnumerable<ModuleFeature> features = _featureManager.GetAvailableFeatures()
.Where(f => !DefaultExtensionTypes.IsTheme(f.Extension.ExtensionType))
.Select(f => new ModuleFeature {
Descriptor = f,
IsEnabled = _shellDescriptor.Features.Any(sf => sf.Name == f.Id),
IsRecentlyInstalled = _moduleService.IsRecentlyInstalled(f.Extension),
NeedsUpdate = featuresThatNeedUpdate.Contains(f.Id),
DependentFeatures = _moduleService.GetDependentFeatures(f.Id).Where(x => x.Id != f.Id).ToList()
})
Descriptor = f,
IsEnabled = _shellDescriptor.Features.Any(sf => sf.Name == f.Id),
IsRecentlyInstalled = _moduleService.IsRecentlyInstalled(f.Extension),
NeedsUpdate = featuresThatNeedUpdate.Contains(f.Id),
DependentFeatures = _moduleService.GetDependentFeatures(f.Id).Where(x => x.Id != f.Id).ToList()
})
.ToList();
return View(new FeaturesViewModel {
return View(new FeaturesViewModel {
Features = features,
IsAllowed = ExtensionIsAllowed
});
@@ -212,13 +211,13 @@ namespace Orchard.Modules.Controllers {
case FeaturesBulkAction.None:
break;
case FeaturesBulkAction.Enable:
_moduleService.EnableFeatures(disabledFeatures, force == true);
EnableFeatures(disabledFeatures, force == true);
break;
case FeaturesBulkAction.Disable:
_moduleService.DisableFeatures(enabledFeatures, force == true);
break;
case FeaturesBulkAction.Toggle:
_moduleService.EnableFeatures(disabledFeatures, force == true);
EnableFeatures(disabledFeatures, force == true);
_moduleService.DisableFeatures(enabledFeatures, force == true);
break;
case FeaturesBulkAction.Update:
@@ -250,5 +249,16 @@ namespace Orchard.Modules.Controllers {
private bool ExtensionIsAllowed(ExtensionDescriptor extensionDescriptor) {
return _shellSettings.Modules.Length == 0 || _shellSettings.Modules.Contains(extensionDescriptor.Id);
}
private void EnableFeatures(List<string> disabledFeatures, bool force) {
foreach (var feature in disabledFeatures) {
if (_featureManager.HasLoader(feature)) {
_moduleService.EnableFeatures(disabledFeatures, force);
}
else {
Services.Notifier.Error(T("No loader found for feature's (\"{0}\") exension!", feature));
}
}
}
}
}

View File

@@ -11,10 +11,12 @@ namespace Orchard.Environment.Extensions.Loaders {
public class CoreExtensionLoader : ExtensionLoaderBase {
private const string CoreAssemblyName = "Orchard.Core";
private readonly IAssemblyLoader _assemblyLoader;
private readonly IDependenciesFolder _dependenciesFolder;
public CoreExtensionLoader(IDependenciesFolder dependenciesFolder, IAssemblyLoader assemblyLoader)
public CoreExtensionLoader(IAssemblyLoader assemblyLoader, IDependenciesFolder dependenciesFolder)
: base(dependenciesFolder) {
_assemblyLoader = assemblyLoader;
_dependenciesFolder = dependenciesFolder;
Logger = NullLogger.Instance;
}
@@ -59,6 +61,15 @@ namespace Orchard.Environment.Extensions.Loaders {
};
}
public override bool LoaderIsSuitable(ExtensionDescriptor descriptor) {
var dependency = _dependenciesFolder.GetDescriptor(descriptor.Id);
if (dependency != null && dependency.LoaderName == this.Name) {
return _assemblyLoader.Load(CoreAssemblyName) != null;
}
return false;
}
private static bool IsTypeFromModule(Type type, ExtensionDescriptor descriptor) {
return (type.Namespace + ".").StartsWith(CoreAssemblyName + "." + descriptor.Id + ".");
}

View File

@@ -212,6 +212,20 @@ namespace Orchard.Environment.Extensions.Loaders {
return dependencies;
}
public override bool LoaderIsSuitable(ExtensionDescriptor descriptor) {
var dependency = _dependenciesFolder.GetDescriptor(descriptor.Id);
if (dependency != null && dependency.LoaderName == this.Name) {
var projectPath = GetProjectPath(descriptor);
if (projectPath == null) {
return false;
}
return _buildManager.GetCompiledAssembly(projectPath) != null;
}
return false;
}
private void AddDependencies(string projectPath, HashSet<string> currentSet) {
// Skip files from locations other than "~/Modules" and "~/Themes" etc.
if (string.IsNullOrEmpty(PrefixMatch(projectPath, _extensionsVirtualPathPrefixes))) {

View File

@@ -57,5 +57,7 @@ namespace Orchard.Environment.Extensions.Loaders {
public virtual IEnumerable<string> GetVirtualPathDependencies(DependencyDescriptor dependency) {
return Enumerable.Empty<string>();
}
public abstract bool LoaderIsSuitable(ExtensionDescriptor descriptor);
}
}

View File

@@ -59,5 +59,7 @@ namespace Orchard.Environment.Extensions.Loaders {
/// For example, Razor or WebForms views needs to be recompiled when a dependency of a module changes.
/// </summary>
IEnumerable<string> GetVirtualPathDependencies(DependencyDescriptor dependency);
bool LoaderIsSuitable(ExtensionDescriptor descriptor);
}
}

View File

@@ -19,6 +19,7 @@ namespace Orchard.Environment.Extensions.Loaders {
private readonly IAssemblyProbingFolder _assemblyProbingFolder;
private readonly IVirtualPathProvider _virtualPathProvider;
private readonly IVirtualPathMonitor _virtualPathMonitor;
private readonly IDependenciesFolder _dependenciesFolder;
public PrecompiledExtensionLoader(
IHostEnvironment hostEnvironment,
@@ -31,6 +32,7 @@ namespace Orchard.Environment.Extensions.Loaders {
_assemblyProbingFolder = assemblyProbingFolder;
_virtualPathProvider = virtualPathProvider;
_virtualPathMonitor = virtualPathMonitor;
_dependenciesFolder = dependenciesFolder;
Logger = NullLogger.Instance;
}
@@ -166,7 +168,7 @@ namespace Orchard.Environment.Extensions.Loaders {
Loader = this,
Name = Path.GetFileNameWithoutExtension(path),
VirtualPath = path
} )
})
.ToList();
Logger.Information("Done probing references for module '{0}'", descriptor.Id);
@@ -244,5 +246,14 @@ namespace Orchard.Environment.Extensions.Loaders {
return assemblyPath;
}
public override bool LoaderIsSuitable(ExtensionDescriptor descriptor) {
var dependency = _dependenciesFolder.GetDescriptor(descriptor.Id);
if (dependency != null && dependency.LoaderName == this.Name) {
return _assemblyProbingFolder.AssemblyExists(descriptor.Id);
}
return false;
}
}
}

View File

@@ -8,10 +8,12 @@ using Orchard.Logging;
namespace Orchard.Environment.Extensions.Loaders {
public class RawThemeExtensionLoader : ExtensionLoaderBase {
private readonly IVirtualPathProvider _virtualPathProvider;
private readonly IDependenciesFolder _dependenciesFolder;
public RawThemeExtensionLoader(IDependenciesFolder dependenciesFolder, IVirtualPathProvider virtualPathProvider)
: base(dependenciesFolder) {
_virtualPathProvider = virtualPathProvider;
_dependenciesFolder = dependenciesFolder;
Logger = NullLogger.Instance;
}
@@ -26,12 +28,12 @@ namespace Orchard.Environment.Extensions.Loaders {
return null;
// Temporary - theme without own project should be under ~/themes
if (descriptor.Location.StartsWith("~/Themes",StringComparison.InvariantCultureIgnoreCase)) {
if (descriptor.Location.StartsWith("~/Themes", StringComparison.InvariantCultureIgnoreCase)) {
string projectPath = _virtualPathProvider.Combine(descriptor.Location, descriptor.Id,
descriptor.Id + ".csproj");
// ignore themes including a .csproj in this loader
if ( _virtualPathProvider.FileExists(projectPath) ) {
if (_virtualPathProvider.FileExists(projectPath)) {
return null;
}
@@ -39,7 +41,7 @@ namespace Orchard.Environment.Extensions.Loaders {
descriptor.Id + ".dll");
// ignore themes with /bin in this loader
if ( _virtualPathProvider.FileExists(assemblyPath) )
if (_virtualPathProvider.FileExists(assemblyPath))
return null;
return new ExtensionProbeEntry {
@@ -64,5 +66,14 @@ namespace Orchard.Environment.Extensions.Loaders {
ExportedTypes = new Type[0]
};
}
public override bool LoaderIsSuitable(ExtensionDescriptor descriptor) {
var dependency = _dependenciesFolder.GetDescriptor(descriptor.Id);
if (dependency != null && dependency.LoaderName == this.Name) {
return true;
}
return false;
}
}
}

View File

@@ -13,12 +13,14 @@ namespace Orchard.Environment.Extensions.Loaders {
public class ReferencedExtensionLoader : ExtensionLoaderBase {
private readonly IVirtualPathProvider _virtualPathProvider;
private readonly IBuildManager _buildManager;
private readonly IDependenciesFolder _dependenciesFolder;
public ReferencedExtensionLoader(IDependenciesFolder dependenciesFolder, IVirtualPathProvider virtualPathProvider, IBuildManager buildManager)
: base(dependenciesFolder) {
_virtualPathProvider = virtualPathProvider;
_buildManager = buildManager;
_dependenciesFolder = dependenciesFolder;
Logger = NullLogger.Instance;
}
@@ -82,5 +84,14 @@ namespace Orchard.Environment.Extensions.Loaders {
ExportedTypes = assembly.GetExportedTypes()
};
}
public override bool LoaderIsSuitable(ExtensionDescriptor descriptor) {
var dependency = _dependenciesFolder.GetDescriptor(descriptor.Id);
if (dependency != null && dependency.LoaderName == this.Name) {
return _buildManager.GetReferencedAssembly(descriptor.Id) != null;
}
return false;
}
}
}

View File

@@ -4,7 +4,7 @@ using System.Linq;
using Orchard.Environment.Descriptor;
using Orchard.Environment.Descriptor.Models;
using Orchard.Environment.Extensions;
using Orchard.Environment.Extensions.Helpers;
using Orchard.Environment.Extensions.Loaders;
using Orchard.Environment.Extensions.Models;
using Orchard.Localization;
using Orchard.Logging;
@@ -13,6 +13,7 @@ namespace Orchard.Environment.Features {
public class FeatureManager : IFeatureManager {
private readonly IExtensionManager _extensionManager;
private readonly IShellDescriptorManager _shellDescriptorManager;
private readonly IEnumerable<IExtensionLoader> _loaders;
/// <summary>
/// Delegate to notify about feature dependencies.
@@ -21,10 +22,11 @@ namespace Orchard.Environment.Features {
public FeatureManager(
IExtensionManager extensionManager,
IShellDescriptorManager shellDescriptorManager) {
IShellDescriptorManager shellDescriptorManager,
IEnumerable<IExtensionLoader> loaders) {
_extensionManager = extensionManager;
_shellDescriptorManager = shellDescriptorManager;
_loaders = loaders;
T = NullLocalizer.Instance;
Logger = NullLogger.Instance;
}
@@ -161,6 +163,22 @@ namespace Orchard.Environment.Features {
return GetAffectedFeatures(featureId, availableFeatures, getEnabledDependants);
}
public bool HasLoader(string featureId) {
var descriptor = _extensionManager
.AvailableExtensions()
.Where(d => DefaultExtensionTypes.IsModule(d.ExtensionType) || DefaultExtensionTypes.IsTheme(d.ExtensionType))
.OrderBy(d => d.Id)
.FirstOrDefault(e => e.Id == featureId || e.Features.Select(f => f.Id).Contains(featureId));
foreach (var loader in _loaders) {
if (loader.LoaderIsSuitable(descriptor)) {
return true;
}
}
return false;
}
/// <summary>
/// Enables a feature.
/// </summary>
@@ -228,7 +246,7 @@ namespace Orchard.Environment.Features {
}
private static IEnumerable<string> GetAffectedFeatures(
string featureId, IDictionary<FeatureDescriptor, bool> features,
string featureId, IDictionary<FeatureDescriptor, bool> features,
Func<string, IDictionary<FeatureDescriptor, bool>, IDictionary<FeatureDescriptor, bool>> getAffectedDependencies) {
var dependencies = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { featureId };

View File

@@ -1,5 +1,6 @@
using System.Collections.Generic;
using Orchard.Environment.Extensions.Models;
using Orchard.Environment.Extensions;
namespace Orchard.Environment.Features {
public delegate void FeatureDependencyNotificationHandler(string messageFormat, string featureId, IEnumerable<string> featureIds);
@@ -61,5 +62,12 @@ namespace Orchard.Environment.Features {
/// <param name="featureId">ID of the feature to check.</param>
/// <returns>An enumeration with dependent feature IDs.</returns>
IEnumerable<string> GetDependentFeatures(string featureId);
/// <summary>
/// Checks whether the feature's extension has a loadee, i.e. a suitable <see cref="IExtensionLoader"/> can be found.
/// </summary>
/// <param name="featureId">ID of the feature to check.</param>
/// <returns><c>True</c> if a suitable <see cref="IExtensionLoader"/> can be found.</returns>
bool HasLoader(string featureId);
}
}