diff --git a/src/Orchard/Environment/Extensions/ExtensionLoaderCoordinator.cs b/src/Orchard/Environment/Extensions/ExtensionLoaderCoordinator.cs index 094cdbe04..f61107126 100644 --- a/src/Orchard/Environment/Extensions/ExtensionLoaderCoordinator.cs +++ b/src/Orchard/Environment/Extensions/ExtensionLoaderCoordinator.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Generic; using System.Linq; using System.Text; -using System.Web.Mvc; using Orchard.Caching; using Orchard.Environment.Extensions.Loaders; using Orchard.Environment.Extensions.Models; @@ -15,6 +14,7 @@ using Orchard.Utility; namespace Orchard.Environment.Extensions { public class ExtensionLoaderCoordinator : IExtensionLoaderCoordinator { private readonly IDependenciesFolder _dependenciesFolder; + private readonly IModuleDependenciesManager _moduleDependenciesManager; private readonly IExtensionManager _extensionManager; private readonly IVirtualPathProvider _virtualPathProvider; private readonly IVirtualPathMonitor _virtualPathMonitor; @@ -24,6 +24,7 @@ namespace Orchard.Environment.Extensions { public ExtensionLoaderCoordinator( IDependenciesFolder dependenciesFolder, + IModuleDependenciesManager moduleDependenciesManager, IExtensionManager extensionManager, IVirtualPathProvider virtualPathProvider, IVirtualPathMonitor virtualPathMonitor, @@ -32,6 +33,7 @@ namespace Orchard.Environment.Extensions { IBuildManager buildManager) { _dependenciesFolder = dependenciesFolder; + _moduleDependenciesManager = moduleDependenciesManager; _extensionManager = extensionManager; _virtualPathProvider = virtualPathProvider; _virtualPathMonitor = virtualPathMonitor; @@ -72,6 +74,7 @@ namespace Orchard.Environment.Extensions { // And finally save the new entries in the dependencies folder _dependenciesFolder.StoreDescriptors(context.NewDependencies); + _moduleDependenciesManager.StoreDependencies(context.NewDependencies); Logger.Information("Done loading extensions..."); diff --git a/src/Orchard/Environment/OrchardStarter.cs b/src/Orchard/Environment/OrchardStarter.cs index 41fd63bda..6f05683d3 100644 --- a/src/Orchard/Environment/OrchardStarter.cs +++ b/src/Orchard/Environment/OrchardStarter.cs @@ -60,6 +60,7 @@ namespace Orchard.Environment { RegisterVolatileProvider(builder); RegisterVolatileProvider(builder); RegisterVolatileProvider(builder); + RegisterVolatileProvider(builder); RegisterVolatileProvider(builder); RegisterVolatileProvider(builder); RegisterVolatileProvider(builder); diff --git a/src/Orchard/FileSystems/Dependencies/DefaultModuleDependenciesManager.cs b/src/Orchard/FileSystems/Dependencies/DefaultModuleDependenciesManager.cs new file mode 100644 index 000000000..8d80b99fa --- /dev/null +++ b/src/Orchard/FileSystems/Dependencies/DefaultModuleDependenciesManager.cs @@ -0,0 +1,103 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Xml.Linq; +using Orchard.Caching; +using Orchard.FileSystems.AppData; +using Orchard.FileSystems.VirtualPath; +using Orchard.Logging; + +namespace Orchard.FileSystems.Dependencies { + /// + /// Similar to "Dependencies.xml" file, except we also store "GetFileHash" result for every + /// VirtualPath entry. This is so that if any virtual path reference in the file changes, + /// the file stored by this component will also change. + /// + public class DefaultModuleDependenciesManager : IModuleDependenciesManager { + private readonly IAppDataFolder _appDataFolder; + private readonly IVirtualPathProvider _virtualPathProvider; + private const string BasePath = "Dependencies"; + private const string FileName = "Dependencies.ModuleCompilation.xml"; + + public DefaultModuleDependenciesManager(IAppDataFolder appDataFolder, IVirtualPathProvider virtualPathProvider) { + _appDataFolder = appDataFolder; + _virtualPathProvider = virtualPathProvider; + Logger = NullLogger.Instance; + } + + public ILogger Logger { get; set; } + + private string PersistencePath { + get { return _appDataFolder.Combine(BasePath, FileName); } + } + + public void StoreDependencies(IEnumerable dependencyDescriptors) { + var newDocument = CreateDocument(dependencyDescriptors); + var previousDocument = ReadDocument(PersistencePath); + if (CompareXmlDocuments(newDocument, previousDocument)) { + Logger.Debug("Existing document is identical to new one. Skipping save."); + return; + } + + WriteDocument(PersistencePath, newDocument); + } + + public IEnumerable GetVirtualPathDependencies(DependencyDescriptor descriptor) { + // Currently, we return the same file for every module. An improvement would be to return + // a specific file per module (this would decrease the number of recompilations needed + // when modules change on disk). + yield return _appDataFolder.GetVirtualPath(PersistencePath); + } + + private XDocument CreateDocument(IEnumerable dependencies) { + Func ns = (name => XName.Get(name)); + + var document = new XDocument(); + document.Add(new XElement(ns("Dependencies"))); + var elements = dependencies.Select(d => new XElement("Dependency", + new XElement(ns("ModuleName"), d.Name), + new XElement(ns("LoaderName"), d.LoaderName), + new XElement(ns("VirtualPath"), d.VirtualPath), + new XElement(ns("FileHash"), _virtualPathProvider.GetFileHash(d.VirtualPath)), + new XElement(ns("References"), d.References + .Select(r => new XElement(ns("Reference"), + new XElement(ns("Name"), r.Name), + new XElement(ns("LoaderName"), r.LoaderName), + new XElement(ns("VirtualPath"), r.VirtualPath), + new XElement(ns("FileHash"), _virtualPathProvider.GetFileHash(r.VirtualPath)))).ToArray()))); + + document.Root.Add(elements); + return document; + } + + private void WriteDocument(string persistancePath, XDocument document) { + using (var stream = _appDataFolder.CreateFile(persistancePath)) { + document.Save(stream, SaveOptions.None); + stream.Close(); + } + } + + private XDocument ReadDocument(string persistancePath) { + if (!_appDataFolder.FileExists(persistancePath)) + return new XDocument(); + + try { + using (var stream = _appDataFolder.OpenFile(persistancePath)) { + return XDocument.Load(stream); + } + } + catch(Exception e) { + Logger.Information(e, "Error reading file '{0}'", persistancePath); + return new XDocument(); + } + } + + private bool CompareXmlDocuments(XDocument doc1, XDocument doc2) { + return XNode.DeepEquals(doc1.Root, doc2.Root); + } + + private class InvalidationToken : IVolatileToken { + public bool IsCurrent { get; set; } + } + } +} \ No newline at end of file diff --git a/src/Orchard/FileSystems/Dependencies/IModuleDependenciesManager.cs b/src/Orchard/FileSystems/Dependencies/IModuleDependenciesManager.cs new file mode 100644 index 000000000..b183aebbe --- /dev/null +++ b/src/Orchard/FileSystems/Dependencies/IModuleDependenciesManager.cs @@ -0,0 +1,9 @@ +using System.Collections.Generic; +using Orchard.Caching; + +namespace Orchard.FileSystems.Dependencies { + public interface IModuleDependenciesManager : IVolatileProvider { + void StoreDependencies(IEnumerable dependencyDescriptors); + IEnumerable GetVirtualPathDependencies(DependencyDescriptor descriptor); + } +} \ No newline at end of file diff --git a/src/Orchard/Orchard.Framework.csproj b/src/Orchard/Orchard.Framework.csproj index 314b697ca..82efc56a2 100644 --- a/src/Orchard/Orchard.Framework.csproj +++ b/src/Orchard/Orchard.Framework.csproj @@ -191,6 +191,8 @@ + +