Refactor extension folder harvesting

Use composition over inheritance. This will be useful later to
improve performance of module/theme manifest harvesting.

--HG--
branch : 1.x
rename : src/Orchard/Environment/Extensions/Folders/ExtensionFolders.cs => src/Orchard/Environment/Extensions/Folders/ExtensionHarvester.cs
This commit is contained in:
Renaud Paquay
2011-05-30 14:17:06 -07:00
parent 48a48e4cfe
commit 3ca3234bbf
13 changed files with 70 additions and 52 deletions

View File

@@ -125,7 +125,7 @@ Features:
public IEnumerable<ExtensionDescriptor> AvailableExtensions() {
foreach (var e in Manifests) {
string name = e.Key;
yield return ExtensionFolders.GetDescriptorForExtension("~/", name, DefaultExtensionTypes.Module, Manifests[name]);
yield return ExtensionHarvester.GetDescriptorForExtension("~/", name, DefaultExtensionTypes.Module, Manifests[name]);
}
}
}

View File

@@ -62,7 +62,8 @@ namespace Orchard.Tests.Modules.Recipes.Services {
}
var builder = new ContainerBuilder();
_folders = new ModuleFolders(new[] { _tempFolderName }, new StubCacheManager(), new StubWebSiteFolder());
var harvester = new ExtensionHarvester(new StubCacheManager(), new StubWebSiteFolder());
_folders = new ModuleFolders(new[] { _tempFolderName }, harvester);
builder.RegisterType<RecipeManager>().As<IRecipeManager>();
builder.RegisterType<RecipeHarvester>().As<IRecipeHarvester>();
builder.RegisterType<RecipeStepExecutor>().As<IRecipeStepExecutor>();

View File

@@ -92,7 +92,7 @@ namespace Orchard.Tests.DataMigration {
public IEnumerable<ExtensionDescriptor> AvailableExtensions() {
foreach (var e in Manifests) {
string name = e.Key;
yield return ExtensionFolders.GetDescriptorForExtension("~/", name, DefaultExtensionTypes.Module, Manifests[name]);
yield return ExtensionHarvester.GetDescriptorForExtension("~/", name, DefaultExtensionTypes.Module, Manifests[name]);
}
}
}

View File

@@ -49,7 +49,8 @@ namespace Orchard.Tests.Environment.Extensions {
[Test]
public void IdsFromFoldersWithModuleTxtShouldBeListed() {
IExtensionFolders folders = new ModuleFolders(new[] { _tempFolderName }, new StubCacheManager(), new StubWebSiteFolder());
var harvester = new ExtensionHarvester(new StubCacheManager(), new StubWebSiteFolder());
IExtensionFolders folders = new ModuleFolders(new[] { _tempFolderName }, harvester);
var ids = folders.AvailableExtensions().Select(d => d.Id);
Assert.That(ids.Count(), Is.EqualTo(5));
Assert.That(ids, Has.Some.EqualTo("Sample1")); // Sample1 - obviously
@@ -61,7 +62,8 @@ namespace Orchard.Tests.Environment.Extensions {
[Test]
public void ModuleTxtShouldBeParsedAndReturnedAsYamlDocument() {
IExtensionFolders folders = new ModuleFolders(new[] { _tempFolderName }, new StubCacheManager(), new StubWebSiteFolder());
var harvester = new ExtensionHarvester(new StubCacheManager(), new StubWebSiteFolder());
IExtensionFolders folders = new ModuleFolders(new[] { _tempFolderName }, harvester);
var sample1 = folders.AvailableExtensions().Single(d => d.Id == "Sample1");
Assert.That(sample1.Id, Is.Not.Empty);
Assert.That(sample1.Author, Is.EqualTo("Bertrand Le Roy")); // Sample1
@@ -69,7 +71,8 @@ namespace Orchard.Tests.Environment.Extensions {
[Test]
public void NamesFromFoldersWithModuleTxtShouldFallBackToIdIfNotGiven() {
IExtensionFolders folders = new ModuleFolders(new[] { _tempFolderName }, new StubCacheManager(), new StubWebSiteFolder());
var harvester = new ExtensionHarvester(new StubCacheManager(), new StubWebSiteFolder());
IExtensionFolders folders = new ModuleFolders(new[] { _tempFolderName }, harvester);
var names = folders.AvailableExtensions().Select(d => d.Name);
Assert.That(names.Count(), Is.EqualTo(5));
Assert.That(names, Has.Some.EqualTo("Le plug-in français")); // Sample1
@@ -81,7 +84,8 @@ namespace Orchard.Tests.Environment.Extensions {
[Test]
public void PathsFromFoldersWithModuleTxtShouldFallBackAppropriatelyIfNotGiven() {
IExtensionFolders folders = new ModuleFolders(new[] { _tempFolderName }, new StubCacheManager(), new StubWebSiteFolder());
var harvester = new ExtensionHarvester(new StubCacheManager(), new StubWebSiteFolder());
IExtensionFolders folders = new ModuleFolders(new[] { _tempFolderName }, harvester);
var paths = folders.AvailableExtensions().Select(d => d.Path);
Assert.That(paths.Count(), Is.EqualTo(5));
Assert.That(paths, Has.Some.EqualTo("Sample1")); // Sample1 - Id, Name invalid URL segment

View File

@@ -46,7 +46,7 @@ namespace Orchard.Tests.Environment.Extensions {
public IEnumerable<ExtensionDescriptor> AvailableExtensions() {
foreach (var e in Manifests) {
string name = e.Key;
yield return ExtensionFolders.GetDescriptorForExtension("~/", name, _extensionType, Manifests[name]);
yield return ExtensionHarvester.GetDescriptorForExtension("~/", name, _extensionType, Manifests[name]);
}
}
}

View File

@@ -51,7 +51,7 @@ namespace Orchard.Tests.Environment.Extensions {
public IEnumerable<ExtensionDescriptor> AvailableExtensions() {
foreach (var e in Manifests) {
string name = e.Key;
yield return ExtensionFolders.GetDescriptorForExtension("~/", name, _extensionType, Manifests[name]);
yield return ExtensionHarvester.GetDescriptorForExtension("~/", name, _extensionType, Manifests[name]);
}
}
}

View File

@@ -78,7 +78,7 @@ namespace Orchard.Packaging.Services {
if (packageFile != null) {
string extensionId = Path.GetFileName(Path.GetDirectoryName(packageFile.Path).TrimEnd('/', '\\'));
using (StreamReader streamReader = new StreamReader(packageFile.GetStream())) {
return ExtensionFolders.GetDescriptorForExtension("", extensionId, extensionType, streamReader.ReadToEnd());
return ExtensionHarvester.GetDescriptorForExtension("", extensionId, extensionType, streamReader.ReadToEnd());
}
}

View File

@@ -10,7 +10,7 @@ using Orchard.Logging;
using Orchard.Utility.Extensions;
namespace Orchard.Environment.Extensions.Folders {
public class ExtensionFolders : IExtensionFolders {
public class ExtensionHarvester : IExtensionHarvester {
private const string NameSection = "name";
private const string PathSection = "path";
private const string DescriptionSection = "description";
@@ -29,23 +29,10 @@ namespace Orchard.Environment.Extensions.Folders {
private const string PrioritySection = "priority";
private const string FeaturesSection = "features";
private readonly IEnumerable<string> _paths;
private readonly string _manifestName;
private readonly string _extensionType;
private readonly bool _manifestIsOptional;
private readonly ICacheManager _cacheManager;
private readonly IWebSiteFolder _webSiteFolder;
protected ExtensionFolders(
IEnumerable<string> paths,
string manifestName,
bool manifestIsOptional,
ICacheManager cacheManager,
IWebSiteFolder webSiteFolder) {
_paths = paths;
_manifestName = manifestName;
_extensionType = manifestName == "Theme.txt" ? DefaultExtensionTypes.Theme : DefaultExtensionTypes.Module;
_manifestIsOptional = manifestIsOptional;
public ExtensionHarvester(ICacheManager cacheManager, IWebSiteFolder webSiteFolder) {
_cacheManager = cacheManager;
_webSiteFolder = webSiteFolder;
Logger = NullLogger.Instance;
@@ -55,24 +42,30 @@ namespace Orchard.Environment.Extensions.Folders {
public Localizer T { get; set; }
public ILogger Logger { get; set; }
public IEnumerable<ExtensionDescriptor> AvailableExtensions() {
return _paths
.SelectMany(path => _cacheManager.Get(path, ctx => {
ctx.Monitor(_webSiteFolder.WhenPathChanges(ctx.Key));
return AvailableExtensionsInFolder(ctx.Key);
}))
public IEnumerable<ExtensionDescriptor> HarvestExtensions(IEnumerable<string> paths, string extensionType, string manifestName, bool manifestIsOptional) {
return paths
.SelectMany(path => HarvestExtensions(path, extensionType, manifestName, manifestIsOptional))
.ToList();
}
private List<ExtensionDescriptor> AvailableExtensionsInFolder(string path) {
private IEnumerable<ExtensionDescriptor> HarvestExtensions(string path, string extensionType, string manifestName, bool manifestIsOptional) {
string key = string.Format("{0}-{1}-{2}", path, manifestName, extensionType);
return _cacheManager.Get(key, ctx => {
ctx.Monitor(_webSiteFolder.WhenPathChanges(path));
return AvailableExtensionsInFolder(path, extensionType, manifestName, manifestIsOptional);
});
}
private List<ExtensionDescriptor> AvailableExtensionsInFolder(string path, string extensionType, string manifestName, bool manifestIsOptional) {
Logger.Information("Start looking for extensions in '{0}'...", path);
var subfolderPaths = _webSiteFolder.ListDirectories(path);
var localList = new List<ExtensionDescriptor>();
foreach (var subfolderPath in subfolderPaths) {
var extensionId = Path.GetFileName(subfolderPath.TrimEnd('/', '\\'));
var manifestPath = Path.Combine(subfolderPath, _manifestName);
var manifestPath = Path.Combine(subfolderPath, manifestName);
try {
var descriptor = GetExtensionDescriptor(path, extensionId, manifestPath);
var descriptor = GetExtensionDescriptor(path, extensionId, extensionType, manifestPath, manifestIsOptional);
if (descriptor == null)
continue;
@@ -124,12 +117,12 @@ namespace Orchard.Environment.Extensions.Folders {
return extensionDescriptor;
}
private ExtensionDescriptor GetExtensionDescriptor(string locationPath, string extensionId, string manifestPath) {
private ExtensionDescriptor GetExtensionDescriptor(string locationPath, string extensionId, string extensionType, string manifestPath, bool manifestIsOptional) {
return _cacheManager.Get(manifestPath, context => {
context.Monitor(_webSiteFolder.WhenPathChanges(manifestPath));
var manifestText = _webSiteFolder.ReadFile(manifestPath);
if (manifestText == null) {
if (_manifestIsOptional) {
if (manifestIsOptional) {
manifestText = string.Format("Id: {0}", extensionId);
}
else {
@@ -137,14 +130,10 @@ namespace Orchard.Environment.Extensions.Folders {
}
}
return GetDescriptorForExtension(locationPath, extensionId, manifestText);
return GetDescriptorForExtension(locationPath, extensionId, extensionType, manifestText);
});
}
private ExtensionDescriptor GetDescriptorForExtension(string locationPath, string extensionId, string manifestText) {
return GetDescriptorForExtension(locationPath, extensionId, _extensionType, manifestText);
}
private static Dictionary<string, string> ParseManifest(string manifestText) {
var manifest = new Dictionary<string, string>();

View File

@@ -0,0 +1,8 @@
using System.Collections.Generic;
using Orchard.Environment.Extensions.Models;
namespace Orchard.Environment.Extensions.Folders {
public interface IExtensionHarvester {
IEnumerable<ExtensionDescriptor> HarvestExtensions(IEnumerable<string> paths, string extensionType, string manifestName, bool manifestIsOptional);
}
}

View File

@@ -1,11 +1,18 @@
using System.Collections.Generic;
using Orchard.Caching;
using Orchard.FileSystems.WebSite;
using Orchard.Environment.Extensions.Models;
namespace Orchard.Environment.Extensions.Folders {
public class ModuleFolders : ExtensionFolders {
public ModuleFolders(IEnumerable<string> paths, ICacheManager cacheManager, IWebSiteFolder webSiteFolder) :
base(paths, "Module.txt", false/*isManifestOptional*/, cacheManager, webSiteFolder) {
public class ModuleFolders : IExtensionFolders {
private readonly IEnumerable<string> _paths;
private readonly IExtensionHarvester _extensionHarvester;
public ModuleFolders(IEnumerable<string> paths, IExtensionHarvester extensionHarvester) {
_paths = paths;
_extensionHarvester = extensionHarvester;
}
public IEnumerable<ExtensionDescriptor> AvailableExtensions() {
return _extensionHarvester.HarvestExtensions(_paths, DefaultExtensionTypes.Module, "Module.txt", false/*isManifestOptional*/);
}
}
}

View File

@@ -1,11 +1,18 @@
using System.Collections.Generic;
using Orchard.Caching;
using Orchard.FileSystems.WebSite;
using Orchard.Environment.Extensions.Models;
namespace Orchard.Environment.Extensions.Folders {
public class ThemeFolders : ExtensionFolders {
public ThemeFolders(IEnumerable<string> paths, ICacheManager cacheManager, IWebSiteFolder webSiteFolder) :
base(paths, "Theme.txt", false/*manifestIsOptional*/, cacheManager, webSiteFolder) {
public class ThemeFolders : IExtensionFolders {
private readonly IEnumerable<string> _paths;
private readonly IExtensionHarvester _extensionHarvester;
public ThemeFolders(IEnumerable<string> paths, IExtensionHarvester extensionHarvester) {
_paths = paths;
_extensionHarvester = extensionHarvester;
}
public IEnumerable<ExtensionDescriptor> AvailableExtensions() {
return _extensionHarvester.HarvestExtensions(_paths, DefaultExtensionTypes.Theme, "Theme.txt", false/*isManifestOptional*/);
}
}
}

View File

@@ -81,6 +81,7 @@ namespace Orchard.Environment {
builder.RegisterType<ExtensionMonitoringCoordinator>().As<IExtensionMonitoringCoordinator>().SingleInstance();
builder.RegisterType<ExtensionManager>().As<IExtensionManager>().SingleInstance();
{
builder.RegisterType<ExtensionHarvester>().As<IExtensionHarvester>().SingleInstance();
builder.RegisterType<ModuleFolders>().As<IExtensionFolders>().SingleInstance()
.WithParameter(new NamedParameter("paths", new[] { "~/Core", "~/Modules" }));
builder.RegisterType<ThemeFolders>().As<IExtensionFolders>().SingleInstance()

View File

@@ -178,6 +178,7 @@
<Compile Include="Caching\DefaultAsyncTokenProvider.cs" />
<Compile Include="Environment\Extensions\ExtensionMonitoringCoordinator.cs" />
<Compile Include="Caching\IAsyncTokenProvider.cs" />
<Compile Include="Environment\Extensions\Folders\IExtensionHarvester.cs" />
<Compile Include="Environment\Extensions\IExtensionMonitoringCoordinator.cs" />
<Compile Include="Environment\Extensions\OrchardSuppressDependencyAttribute.cs" />
<Compile Include="Environment\Features\IFeatureManager.cs" />
@@ -710,7 +711,7 @@
<Compile Include="Events\EventsRegistrationSource.cs" />
<Compile Include="Environment\Configuration\IShellSettingsManagerEventHandler.cs" />
<Compile Include="Events\IEventBus.cs" />
<Compile Include="Environment\Extensions\Folders\ExtensionFolders.cs" />
<Compile Include="Environment\Extensions\Folders\ExtensionHarvester.cs" />
<Compile Include="Environment\Extensions\Models\Feature.cs" />
<Compile Include="Environment\Extensions\Models\FeatureDescriptor.cs" />
<Compile Include="Environment\Extensions\OrchardFeatureAttribute.cs" />