mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2026-02-09 09:16:41 +08:00
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
This commit is contained in:
@@ -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...");
|
||||
|
||||
|
||||
@@ -60,6 +60,7 @@ namespace Orchard.Environment {
|
||||
RegisterVolatileProvider<DefaultLockFileManager, ILockFileManager>(builder);
|
||||
RegisterVolatileProvider<Clock, IClock>(builder);
|
||||
RegisterVolatileProvider<DefaultDependenciesFolder, IDependenciesFolder>(builder);
|
||||
RegisterVolatileProvider<DefaultModuleDependenciesManager, IModuleDependenciesManager>(builder);
|
||||
RegisterVolatileProvider<DefaultAssemblyProbingFolder, IAssemblyProbingFolder>(builder);
|
||||
RegisterVolatileProvider<DefaultVirtualPathMonitor, IVirtualPathMonitor>(builder);
|
||||
RegisterVolatileProvider<DefaultVirtualPathProvider, IVirtualPathProvider>(builder);
|
||||
|
||||
@@ -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 {
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
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<DependencyDescriptor> 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<string> 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<DependencyDescriptor> dependencies) {
|
||||
Func<string, XName> 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; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using System.Collections.Generic;
|
||||
using Orchard.Caching;
|
||||
|
||||
namespace Orchard.FileSystems.Dependencies {
|
||||
public interface IModuleDependenciesManager : IVolatileProvider {
|
||||
void StoreDependencies(IEnumerable<DependencyDescriptor> dependencyDescriptors);
|
||||
IEnumerable<string> GetVirtualPathDependencies(DependencyDescriptor descriptor);
|
||||
}
|
||||
}
|
||||
@@ -191,6 +191,8 @@
|
||||
<Compile Include="Environment\WorkContextImplementation.cs" />
|
||||
<Compile Include="Environment\WorkContextModule.cs" />
|
||||
<Compile Include="Environment\WorkContextProperty.cs" />
|
||||
<Compile Include="FileSystems\Dependencies\IModuleDependenciesManager.cs" />
|
||||
<Compile Include="FileSystems\Dependencies\DefaultModuleDependenciesManager.cs" />
|
||||
<Compile Include="FileSystems\LockFile\ILockFile.cs" />
|
||||
<Compile Include="FileSystems\LockFile\ILockFileManager.cs" />
|
||||
<Compile Include="FileSystems\LockFile\LockFile.cs" />
|
||||
|
||||
Reference in New Issue
Block a user