From 6c732af595e6e5eb10976df2496c44027ce8f955 Mon Sep 17 00:00:00 2001 From: Renaud Paquay Date: Thu, 26 May 2011 11:05:50 -0700 Subject: [PATCH] Implement dependency files storing state of modules compilation The file is similar to "dependencies.xml", except it contains file hash of all virtual path stored in the file. This is to ensure that the file content is updated when any file hash changes. This will be used in an upcoming bug fix. --HG-- branch : 1.x --- .../Extensions/ExtensionLoaderCoordinator.cs | 5 +- src/Orchard/Environment/OrchardStarter.cs | 1 + .../DefaultModuleDependenciesManager.cs | 103 ++++++++++++++++++ .../IModuleDependenciesManager.cs | 9 ++ src/Orchard/Orchard.Framework.csproj | 2 + 5 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 src/Orchard/FileSystems/Dependencies/DefaultModuleDependenciesManager.cs create mode 100644 src/Orchard/FileSystems/Dependencies/IModuleDependenciesManager.cs 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 @@ + +