From 4ea580b54e551b10fe22cf5fe38c45c67b08ee5d Mon Sep 17 00:00:00 2001 From: Renaud Paquay Date: Fri, 11 Jun 2010 21:21:20 -0700 Subject: [PATCH] Update dependencies storage to store state of all loaded extensions --HG-- branch : dev --- .../Extensions/Loaders/AreaExtensionLoader.cs | 20 ++++- .../Extensions/Loaders/CoreExtensionLoader.cs | 20 ++++- .../Loaders/DynamicExtensionLoader.cs | 16 +++- .../Loaders/PrecompiledExtensionLoader.cs | 19 +++-- .../Loaders/ProbingExtensionLoader.cs | 33 ++++++--- .../Loaders/ReferencedExtensionLoader.cs | 19 ++++- .../Dependencies/DefaultDependenciesFolder.cs | 74 ++++++++++++------- .../Dependencies/IDependenciesFolder.cs | 12 +-- .../WebFormsExtensionsVirtualFile.cs | 3 +- 9 files changed, 158 insertions(+), 58 deletions(-) diff --git a/src/Orchard/Environment/Extensions/Loaders/AreaExtensionLoader.cs b/src/Orchard/Environment/Extensions/Loaders/AreaExtensionLoader.cs index d58940168..e1dbd06b4 100644 --- a/src/Orchard/Environment/Extensions/Loaders/AreaExtensionLoader.cs +++ b/src/Orchard/Environment/Extensions/Loaders/AreaExtensionLoader.cs @@ -2,9 +2,19 @@ using System.Linq; using System.Reflection; using Orchard.Environment.Extensions.Models; +using Orchard.FileSystems.Dependencies; +using Orchard.FileSystems.VirtualPath; namespace Orchard.Environment.Extensions.Loaders { public class AreaExtensionLoader : IExtensionLoader { + private readonly IDependenciesFolder _dependenciesFolder; + private readonly IVirtualPathProvider _virtualPathProvider; + + public AreaExtensionLoader(IDependenciesFolder dependenciesFolder, IVirtualPathProvider virtualPathProvider) { + _dependenciesFolder = dependenciesFolder; + _virtualPathProvider = virtualPathProvider; + } + public int Order { get { return 50; } } public ExtensionProbeEntry Probe(ExtensionDescriptor descriptor) { @@ -22,13 +32,21 @@ namespace Orchard.Environment.Extensions.Loaders { public ExtensionEntry Load(ExtensionProbeEntry entry) { if (entry.Loader == this) { var assembly = Assembly.Load("Orchard.Web"); + + _dependenciesFolder.Store(new DependencyDescriptor { ModuleName = entry.Descriptor.Name, LoaderName = this.GetType().FullName}); + return new ExtensionEntry { Descriptor = entry.Descriptor, Assembly = assembly, ExportedTypes = assembly.GetExportedTypes().Where(x => IsTypeFromModule(x, entry.Descriptor)) }; } - return null; + else { + // If the extension is not loaded by us, there is no cached state + // we need to invalidate + _dependenciesFolder.Remove(entry.Descriptor.Name, this.GetType().FullName); + return null; + } } private static bool IsTypeFromModule(Type type, ExtensionDescriptor descriptor) { diff --git a/src/Orchard/Environment/Extensions/Loaders/CoreExtensionLoader.cs b/src/Orchard/Environment/Extensions/Loaders/CoreExtensionLoader.cs index fc2824e3a..ab35c9e9a 100644 --- a/src/Orchard/Environment/Extensions/Loaders/CoreExtensionLoader.cs +++ b/src/Orchard/Environment/Extensions/Loaders/CoreExtensionLoader.cs @@ -2,12 +2,22 @@ using System.Linq; using System.Reflection; using Orchard.Environment.Extensions.Models; +using Orchard.FileSystems.Dependencies; +using Orchard.FileSystems.VirtualPath; namespace Orchard.Environment.Extensions.Loaders { /// /// Load an extension by looking into specific namespaces of the "Orchard.Core" assembly /// public class CoreExtensionLoader : IExtensionLoader { + private readonly IDependenciesFolder _dependenciesFolder; + private readonly IVirtualPathProvider _virtualPathProvider; + + public CoreExtensionLoader(IDependenciesFolder dependenciesFolder, IVirtualPathProvider virtualPathProvider) { + _dependenciesFolder = dependenciesFolder; + _virtualPathProvider = virtualPathProvider; + } + public int Order { get { return 10; } } public ExtensionProbeEntry Probe(ExtensionDescriptor descriptor) { @@ -25,13 +35,21 @@ namespace Orchard.Environment.Extensions.Loaders { public ExtensionEntry Load(ExtensionProbeEntry entry) { if (entry.Loader == this) { var assembly = Assembly.Load("Orchard.Core"); + + _dependenciesFolder.Store(new DependencyDescriptor { ModuleName = entry.Descriptor.Name, LoaderName = this.GetType().FullName }); + return new ExtensionEntry { Descriptor = entry.Descriptor, Assembly = assembly, ExportedTypes = assembly.GetExportedTypes().Where(x => IsTypeFromModule(x, entry.Descriptor)) }; } - return null; + else { + // If the extension is not loaded by us, there is no cached state + // we need to invalidate + _dependenciesFolder.Remove(entry.Descriptor.Name, this.GetType().FullName); + return null; + } } private static bool IsTypeFromModule(Type type, ExtensionDescriptor descriptor) { diff --git a/src/Orchard/Environment/Extensions/Loaders/DynamicExtensionLoader.cs b/src/Orchard/Environment/Extensions/Loaders/DynamicExtensionLoader.cs index b88b14b55..0b5a5580c 100644 --- a/src/Orchard/Environment/Extensions/Loaders/DynamicExtensionLoader.cs +++ b/src/Orchard/Environment/Extensions/Loaders/DynamicExtensionLoader.cs @@ -39,7 +39,12 @@ namespace Orchard.Environment.Extensions.Loaders { if (entry.Loader == this) { var assembly = _buildManager.GetCompiledAssembly(entry.VirtualPath); - _dependenciesFolder.StoreBuildProviderAssembly(entry.Descriptor.Name, entry.VirtualPath, assembly); + _dependenciesFolder.Store(new DependencyDescriptor { + ModuleName = entry.Descriptor.Name, + LoaderName = this.GetType().FullName, + VirtualPath = entry.VirtualPath, + FileName = assembly.Location + }); return new ExtensionEntry { Descriptor = entry.Descriptor, @@ -47,7 +52,14 @@ namespace Orchard.Environment.Extensions.Loaders { ExportedTypes = assembly.GetExportedTypes(), }; } - return null; + else { + // If the extension is not loaded by us, there is some cached state we need to invalidate + // 1) The webforms views which have been compiled with ".csproj" assembly source + // 2) The modules which contains features which depend on us + //TODO + _dependenciesFolder.Remove(entry.Descriptor.Name, this.GetType().FullName); + return null; + } } } } \ No newline at end of file diff --git a/src/Orchard/Environment/Extensions/Loaders/PrecompiledExtensionLoader.cs b/src/Orchard/Environment/Extensions/Loaders/PrecompiledExtensionLoader.cs index fae9ae426..7d51dabc2 100644 --- a/src/Orchard/Environment/Extensions/Loaders/PrecompiledExtensionLoader.cs +++ b/src/Orchard/Environment/Extensions/Loaders/PrecompiledExtensionLoader.cs @@ -9,11 +9,11 @@ namespace Orchard.Environment.Extensions.Loaders { /// extension directory. /// public class PrecompiledExtensionLoader : IExtensionLoader { - private readonly IDependenciesFolder _folder; + private readonly IDependenciesFolder _dependenciesFolder; private readonly IVirtualPathProvider _virtualPathProvider; - public PrecompiledExtensionLoader(IDependenciesFolder folder, IVirtualPathProvider virtualPathProvider) { - _folder = folder; + public PrecompiledExtensionLoader(IDependenciesFolder dependenciesFolder, IVirtualPathProvider virtualPathProvider) { + _dependenciesFolder = dependenciesFolder; _virtualPathProvider = virtualPathProvider; } @@ -35,9 +35,9 @@ namespace Orchard.Environment.Extensions.Loaders { public ExtensionEntry Load(ExtensionProbeEntry entry) { if (entry.Loader == this) { - _folder.StorePrecompiledAssembly(entry.Descriptor.Name, entry.VirtualPath); + _dependenciesFolder.StorePrecompiledAssembly(entry.Descriptor.Name, entry.VirtualPath, this.GetType().FullName); - var assembly = _folder.LoadAssembly(entry.Descriptor.Name); + var assembly = _dependenciesFolder.LoadAssembly(entry.Descriptor.Name); if (assembly == null) return null; @@ -47,7 +47,14 @@ namespace Orchard.Environment.Extensions.Loaders { ExportedTypes = assembly.GetExportedTypes() }; } - return null; + else { + // If the extension is not loaded by us, there is some cached state we need to invalidate + // 1) The webforms views which have been compiled with ".csproj" assembly source + // 2) The modules which contains features which depend on us + //TODO + _dependenciesFolder.Remove(entry.Descriptor.Name, this.GetType().FullName); + return null; + } } } } \ No newline at end of file diff --git a/src/Orchard/Environment/Extensions/Loaders/ProbingExtensionLoader.cs b/src/Orchard/Environment/Extensions/Loaders/ProbingExtensionLoader.cs index f4976de74..a1dde340a 100644 --- a/src/Orchard/Environment/Extensions/Loaders/ProbingExtensionLoader.cs +++ b/src/Orchard/Environment/Extensions/Loaders/ProbingExtensionLoader.cs @@ -9,32 +9,33 @@ namespace Orchard.Environment.Extensions.Loaders { /// file can be found in the "App_Data/Dependencies" folder. /// public class ProbingExtensionLoader : IExtensionLoader { - private readonly IDependenciesFolder _folder; - private readonly IVirtualPathProvider _virtualPathProvider; + private readonly IDependenciesFolder _dependenciesFolder; - public ProbingExtensionLoader(IDependenciesFolder folder, IVirtualPathProvider virtualPathProvider) { - _folder = folder; + public ProbingExtensionLoader(IDependenciesFolder dependenciesFolder) { + _dependenciesFolder = dependenciesFolder; } public int Order { get { return 40; } } public ExtensionProbeEntry Probe(ExtensionDescriptor descriptor) { - var desc = _folder.GetDescriptor(descriptor.Name); - if (desc != null) { - return new ExtensionProbeEntry { + if (!_dependenciesFolder.HasPrecompiledAssembly(descriptor.Name)) + return null; + + var desc = _dependenciesFolder.GetDescriptor(descriptor.Name); + if (desc == null) + return null; + + return new ExtensionProbeEntry { Descriptor = descriptor, LastModificationTimeUtc = File.GetLastWriteTimeUtc(desc.FileName), Loader = this, VirtualPath = desc.VirtualPath }; - } - - return null; } public ExtensionEntry Load(ExtensionProbeEntry entry) { if (entry.Loader == this) { - var assembly = _folder.LoadAssembly(entry.Descriptor.Name); + var assembly = _dependenciesFolder.LoadAssembly(entry.Descriptor.Name); if (assembly == null) return null; @@ -44,7 +45,15 @@ namespace Orchard.Environment.Extensions.Loaders { ExportedTypes = assembly.GetExportedTypes() }; } - return null; + else { + // If the extension is not loaded by us, there is some cached state we need to invalidate + // 1) The webforms views which have been compiled with "Assembly Name=""" directive + // 2) The modules which contains features which depend on us + // 3) The binary from the App_Data directory + //TODO + _dependenciesFolder.Remove(entry.Descriptor.Name, this.GetType().FullName); + return null; + } } } } \ No newline at end of file diff --git a/src/Orchard/Environment/Extensions/Loaders/ReferencedExtensionLoader.cs b/src/Orchard/Environment/Extensions/Loaders/ReferencedExtensionLoader.cs index a25e36411..810c935f0 100644 --- a/src/Orchard/Environment/Extensions/Loaders/ReferencedExtensionLoader.cs +++ b/src/Orchard/Environment/Extensions/Loaders/ReferencedExtensionLoader.cs @@ -12,12 +12,13 @@ namespace Orchard.Environment.Extensions.Loaders { /// public class ReferencedExtensionLoader : IExtensionLoader { private readonly IDependenciesFolder _dependenciesFolder; - public int Order { get { return 20; } } public ReferencedExtensionLoader(IDependenciesFolder dependenciesFolder) { _dependenciesFolder = dependenciesFolder; } + public int Order { get { return 20; } } + public ExtensionProbeEntry Probe(ExtensionDescriptor descriptor) { if (HostingEnvironment.IsHosted == false) return null; @@ -47,7 +48,13 @@ namespace Orchard.Environment.Extensions.Loaders { .OfType() .FirstOrDefault(x => x.GetName().Name == entry.Descriptor.Name); - _dependenciesFolder.StoreReferencedAssembly(entry.Descriptor.Name); + _dependenciesFolder.Store(new DependencyDescriptor { + ModuleName = entry.Descriptor.Name, + LoaderName = this.GetType().FullName, + VirtualPath = entry.VirtualPath, + FileName = assembly.Location + }); + return new ExtensionEntry { Descriptor = entry.Descriptor, @@ -55,8 +62,12 @@ namespace Orchard.Environment.Extensions.Loaders { ExportedTypes = assembly.GetExportedTypes() }; } - - return null; + else { + // If the extension is not loaded by us, there is no cached state + // we need to invalidate + _dependenciesFolder.Remove(entry.Descriptor.Name, this.GetType().FullName); + return null; + } } } } diff --git a/src/Orchard/FileSystems/Dependencies/DefaultDependenciesFolder.cs b/src/Orchard/FileSystems/Dependencies/DefaultDependenciesFolder.cs index 462eae45a..9776db288 100644 --- a/src/Orchard/FileSystems/Dependencies/DefaultDependenciesFolder.cs +++ b/src/Orchard/FileSystems/Dependencies/DefaultDependenciesFolder.cs @@ -55,47 +55,60 @@ namespace Orchard.FileSystems.Dependencies { public bool IsCurrent { get; set; } } - public void StoreReferencedAssembly(string moduleName) { - if (Descriptors.Any(d => d.ModuleName == moduleName)) { - // Remove the moduleName from the list of assemblies in the dependency folder - var newDescriptors = Descriptors.Where(d => d.ModuleName != moduleName); + //public void StoreReferencedAssembly(string moduleName) { + // if (Descriptors.Any(d => d.ModuleName == moduleName)) { + // // Remove the moduleName from the list of assemblies in the dependency folder + // var newDescriptors = Descriptors.Where(d => d.ModuleName != moduleName); - WriteDependencies(PersistencePath, newDescriptors); - } - } + // WriteDependencies(PersistencePath, newDescriptors); + // } + //} - public void StoreBuildProviderAssembly(string moduleName, string virtualPath, Assembly assembly) { - var descriptor = new DependencyDescriptor { - ModuleName = moduleName, - IsFromBuildProvider = true, - VirtualPath = virtualPath, - FileName = assembly.Location - }; + //public void StoreBuildProviderAssembly(string moduleName, string virtualPath, Assembly assembly) { + // var descriptor = new DependencyDescriptor { + // ModuleName = moduleName, + // IsFromBuildProvider = true, + // VirtualPath = virtualPath, + // FileName = assembly.Location + // }; - StoreDepencyInformation(descriptor); + // StoreDepencyInformation(descriptor); - _webSiteFolder.WhenPathChanges(virtualPath, () => _events.ModuleChanged(moduleName)); - } + // _webSiteFolder.WhenPathChanges(virtualPath, () => _events.ModuleChanged(moduleName)); + //} - public void StorePrecompiledAssembly(string moduleName, string virtualPath) { + public void StorePrecompiledAssembly(string moduleModuleName, string virtualPath, string loaderName) { _appDataFolder.CreateDirectory(BasePath); // Only store assembly if it's more recent that what we have stored already (if anything) var assemblyFileName = _appDataFolder.MapPath(virtualPath); - if (IsNewerAssembly(moduleName, assemblyFileName)) { + if (IsNewerAssembly(moduleModuleName, assemblyFileName)) { var destinationFileName = Path.GetFileName(assemblyFileName); var destinationPath = _appDataFolder.MapPath(_appDataFolder.Combine(BasePath, destinationFileName)); File.Copy(assemblyFileName, destinationPath, true); StoreDepencyInformation(new DependencyDescriptor { - ModuleName = moduleName, - IsFromBuildProvider = false, + ModuleName = moduleModuleName, + LoaderName = loaderName, VirtualPath = virtualPath, FileName = destinationFileName }); } } + public void Remove(string moduleName, string loaderName) { + Func predicate = (d => d.ModuleName == moduleName && d.LoaderName == loaderName); + if (Descriptors.Any(predicate)) { + var newDescriptors = Descriptors.Where(e => !predicate(e)); + + WriteDependencies(PersistencePath, newDescriptors); + } + } + + public void Store(DependencyDescriptor descriptor) { + StoreDepencyInformation(descriptor); + } + public DependencyDescriptor GetDescriptor(string moduleName) { return Descriptors.SingleOrDefault(d => d.ModuleName == moduleName); } @@ -127,10 +140,10 @@ namespace Orchard.FileSystems.Dependencies { WriteDependencies(PersistencePath, dependencies); } - public Assembly LoadAssembly(string assemblyName) { + public Assembly LoadAssembly(string moduleName) { _appDataFolder.CreateDirectory(BasePath); - var dependency = Descriptors.SingleOrDefault(d => d.ModuleName == assemblyName); + var dependency = Descriptors.SingleOrDefault(d => d.ModuleName == moduleName); if (dependency == null) return null; @@ -140,6 +153,17 @@ namespace Orchard.FileSystems.Dependencies { return Assembly.Load(Path.GetFileNameWithoutExtension(dependency.FileName)); } + public bool HasPrecompiledAssembly(string moduleName) { + var dependency = Descriptors.SingleOrDefault(d => d.ModuleName == moduleName); + if (dependency == null) + return false; + + if (!_appDataFolder.FileExists(_appDataFolder.Combine(BasePath, dependency.FileName))) + return false; + + return true; + } + private IEnumerable ReadDependencies(string persistancePath) { Func ns = (name => XName.Get(name)); Func elem = (e, name) => e.Element(ns(name)).Value; @@ -156,7 +180,7 @@ namespace Orchard.FileSystems.Dependencies { ModuleName = elem(e, "ModuleName"), VirtualPath = elem(e, "VirtualPath"), FileName = elem(e, "FileName"), - IsFromBuildProvider = bool.Parse(elem(e, "IsFromBuildProvider")) + LoaderName = elem(e, "LoaderName") }) .ToList(); } @@ -170,7 +194,7 @@ namespace Orchard.FileSystems.Dependencies { var elements = dependencies.Select(d => new XElement("Dependency", new XElement(ns("ModuleName"), d.ModuleName), new XElement(ns("VirtualPath"), d.VirtualPath), - new XElement(ns("IsFromBuildProvider"), d.IsFromBuildProvider), + new XElement(ns("LoaderName"), d.LoaderName), new XElement(ns("FileName"), d.FileName))); document.Root.Add(elements); diff --git a/src/Orchard/FileSystems/Dependencies/IDependenciesFolder.cs b/src/Orchard/FileSystems/Dependencies/IDependenciesFolder.cs index 0f738cc59..6ac6ef5e2 100644 --- a/src/Orchard/FileSystems/Dependencies/IDependenciesFolder.cs +++ b/src/Orchard/FileSystems/Dependencies/IDependenciesFolder.cs @@ -1,20 +1,20 @@ using System.Reflection; using Orchard.Caching; -using Orchard.Environment; namespace Orchard.FileSystems.Dependencies { public class DependencyDescriptor { public string ModuleName { get; set; } - public bool IsFromBuildProvider { get; set; } + public string LoaderName { get; set; } public string VirtualPath { get; set; } public string FileName { get; set; } } public interface IDependenciesFolder : IVolatileProvider { - void StoreReferencedAssembly(string moduleName); - void StorePrecompiledAssembly(string moduleName, string virtualPath); - void StoreBuildProviderAssembly(string moduleName, string virtualPath, Assembly assembly); + void Store(DependencyDescriptor descriptor); + void StorePrecompiledAssembly(string moduleName, string virtualPath, string loaderName); + void Remove(string moduleName, string loaderName); DependencyDescriptor GetDescriptor(string moduleName); - Assembly LoadAssembly(string assemblyName); + bool HasPrecompiledAssembly(string moduleName); + Assembly LoadAssembly(string moduleName); } } diff --git a/src/Orchard/FileSystems/Dependencies/WebFormsExtensionsVirtualFile.cs b/src/Orchard/FileSystems/Dependencies/WebFormsExtensionsVirtualFile.cs index d6ad7be25..881b5e71e 100644 --- a/src/Orchard/FileSystems/Dependencies/WebFormsExtensionsVirtualFile.cs +++ b/src/Orchard/FileSystems/Dependencies/WebFormsExtensionsVirtualFile.cs @@ -1,5 +1,6 @@ using System.IO; using System.Web.Hosting; +using Orchard.Environment.Extensions.Loaders; namespace Orchard.FileSystems.Dependencies { public class WebFormsExtensionsVirtualFile : VirtualFile { @@ -50,7 +51,7 @@ namespace Orchard.FileSystems.Dependencies { } private string GetAssemblyDirective() { - if (_dependencyDescriptor.IsFromBuildProvider) { + if (_dependencyDescriptor.LoaderName == typeof(DynamicExtensionLoader).FullName) { return string.Format("<%@ Assembly Src=\"{0}\"%>", _dependencyDescriptor.VirtualPath); } else {