PureLiveModelFactory linting cleanup
This commit is contained in:
@@ -1,33 +0,0 @@
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.ModelsBuilder.Embedded.BackOffice;
|
||||
using Umbraco.Web.Features;
|
||||
|
||||
namespace Umbraco.ModelsBuilder.Embedded.Compose
|
||||
{
|
||||
// TODO: This needs to die, see TODO in ModelsBuilderComposer. This is also no longer used in this netcore
|
||||
// codebase. Potentially this could be changed to ext methods if necessary that could be used by end users who will
|
||||
// install the community MB package to disable any built in MB stuff.
|
||||
|
||||
/// <summary>
|
||||
/// Special component used for when MB is disabled with the legacy MB is detected
|
||||
/// </summary>
|
||||
public sealed class DisabledModelsBuilderComponent : IComponent
|
||||
{
|
||||
private readonly UmbracoFeatures _features;
|
||||
|
||||
public DisabledModelsBuilderComponent(UmbracoFeatures features)
|
||||
{
|
||||
_features = features;
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
//disable the embedded dashboard controller
|
||||
_features.Disabled.Controllers.Add<ModelsBuilderDashboardController>();
|
||||
}
|
||||
|
||||
public void Terminate()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
@@ -9,15 +9,15 @@ using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Configuration.Models;
|
||||
using Umbraco.Core.Hosting;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
using Umbraco.ModelsBuilder.Embedded.Building;
|
||||
using File = System.IO.File;
|
||||
using Umbraco.Core.Configuration.Models;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Umbraco.ModelsBuilder.Embedded
|
||||
{
|
||||
@@ -30,21 +30,21 @@ namespace Umbraco.ModelsBuilder.Embedded
|
||||
private readonly IProfilingLogger _profilingLogger;
|
||||
private readonly ILogger<PureLiveModelFactory> _logger;
|
||||
private readonly FileSystemWatcher _watcher;
|
||||
private int _ver, _skipver;
|
||||
private int _ver;
|
||||
private int _skipver;
|
||||
private readonly int _debugLevel;
|
||||
private RoslynCompiler _roslynCompiler;
|
||||
private UmbracoAssemblyLoadContext _currentAssemblyLoadContext;
|
||||
private readonly Lazy<UmbracoServices> _umbracoServices; // fixme: this is because of circular refs :(
|
||||
private UmbracoServices UmbracoServices => _umbracoServices.Value;
|
||||
|
||||
private static readonly Regex AssemblyVersionRegex = new Regex("AssemblyVersion\\(\"[0-9]+.[0-9]+.[0-9]+.[0-9]+\"\\)", RegexOptions.Compiled);
|
||||
private static readonly string[] OurFiles = { "models.hash", "models.generated.cs", "all.generated.cs", "all.dll.path", "models.err", "Compiled" };
|
||||
|
||||
private static readonly Regex s_assemblyVersionRegex = new Regex("AssemblyVersion\\(\"[0-9]+.[0-9]+.[0-9]+.[0-9]+\"\\)", RegexOptions.Compiled);
|
||||
private static readonly string[] s_ourFiles = { "models.hash", "models.generated.cs", "all.generated.cs", "all.dll.path", "models.err", "Compiled" };
|
||||
private readonly ModelsBuilderSettings _config;
|
||||
private readonly IHostingEnvironment _hostingEnvironment;
|
||||
private readonly IApplicationShutdownRegistry _hostingLifetime;
|
||||
private readonly ModelsGenerationError _errors;
|
||||
private readonly IPublishedValueFallback _publishedValueFallback;
|
||||
private static readonly Regex s_usingRegex = new Regex("^using(.*);", RegexOptions.Compiled | RegexOptions.Multiline);
|
||||
private static readonly Regex s_aattrRegex = new Regex("^\\[assembly:(.*)\\]", RegexOptions.Compiled | RegexOptions.Multiline);
|
||||
|
||||
public PureLiveModelFactory(
|
||||
Lazy<UmbracoServices> umbracoServices,
|
||||
@@ -65,11 +65,16 @@ namespace Umbraco.ModelsBuilder.Embedded
|
||||
_errors = new ModelsGenerationError(config, _hostingEnvironment);
|
||||
_ver = 1; // zero is for when we had no version
|
||||
_skipver = -1; // nothing to skip
|
||||
if (!hostingEnvironment.IsHosted) return;
|
||||
if (!hostingEnvironment.IsHosted)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var modelsDirectory = _config.ModelsDirectoryAbsolute(_hostingEnvironment);
|
||||
if (!Directory.Exists(modelsDirectory))
|
||||
{
|
||||
Directory.CreateDirectory(modelsDirectory);
|
||||
}
|
||||
|
||||
// BEWARE! if the watcher is not properly released then for some reason the
|
||||
// BuildManager will start confusing types - using a 'registered object' here
|
||||
@@ -83,11 +88,29 @@ namespace Umbraco.ModelsBuilder.Embedded
|
||||
_debugLevel = _config.DebugLevel;
|
||||
}
|
||||
|
||||
#region ILivePublishedModelFactory
|
||||
private UmbracoServices UmbracoServices => _umbracoServices.Value;
|
||||
|
||||
/// <inheritdoc />
|
||||
public object SyncRoot { get; } = new object();
|
||||
|
||||
// gets the RoslynCompiler
|
||||
private RoslynCompiler RoslynCompiler
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_roslynCompiler != null)
|
||||
{
|
||||
return _roslynCompiler;
|
||||
}
|
||||
|
||||
_roslynCompiler = new RoslynCompiler(System.Runtime.Loader.AssemblyLoadContext.All.SelectMany(x => x.Assemblies));
|
||||
return _roslynCompiler;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Enabled => _config.Enable;
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Refresh()
|
||||
{
|
||||
@@ -95,16 +118,14 @@ namespace Umbraco.ModelsBuilder.Embedded
|
||||
EnsureModels();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IPublishedModelFactory
|
||||
|
||||
public IPublishedElement CreateModel(IPublishedElement element)
|
||||
{
|
||||
// get models, rebuilding them if needed
|
||||
var infos = EnsureModels()?.ModelInfos;
|
||||
Dictionary<string, ModelInfo> infos = EnsureModels()?.ModelInfos;
|
||||
if (infos == null)
|
||||
{
|
||||
return element;
|
||||
}
|
||||
|
||||
// be case-insensitive
|
||||
var contentTypeAlias = element.ContentType.Alias;
|
||||
@@ -120,7 +141,7 @@ namespace Umbraco.ModelsBuilder.Embedded
|
||||
// NOT when building models
|
||||
public Type MapModelType(Type type)
|
||||
{
|
||||
var infos = EnsureModels();
|
||||
Infos infos = EnsureModels();
|
||||
return ModelType.Map(type, infos.ModelTypeMap);
|
||||
}
|
||||
|
||||
@@ -128,34 +149,39 @@ namespace Umbraco.ModelsBuilder.Embedded
|
||||
// NOT when building models
|
||||
public IList CreateModelList(string alias)
|
||||
{
|
||||
var infos = EnsureModels();
|
||||
Infos infos = EnsureModels();
|
||||
|
||||
// fail fast
|
||||
if (infos == null)
|
||||
{
|
||||
return new List<IPublishedElement>();
|
||||
}
|
||||
|
||||
if (!infos.ModelInfos.TryGetValue(alias, out var modelInfo))
|
||||
if (!infos.ModelInfos.TryGetValue(alias, out ModelInfo modelInfo))
|
||||
{
|
||||
return new List<IPublishedElement>();
|
||||
}
|
||||
|
||||
var ctor = modelInfo.ListCtor;
|
||||
if (ctor != null) return ctor();
|
||||
Func<IList> ctor = modelInfo.ListCtor;
|
||||
if (ctor != null)
|
||||
{
|
||||
return ctor();
|
||||
}
|
||||
|
||||
var listType = typeof(List<>).MakeGenericType(modelInfo.ModelType);
|
||||
Type listType = typeof(List<>).MakeGenericType(modelInfo.ModelType);
|
||||
ctor = modelInfo.ListCtor = ReflectionUtilities.EmitConstructor<Func<IList>>(declaring: listType);
|
||||
return ctor();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Enabled => _config.Enable;
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Reset()
|
||||
{
|
||||
if (_config.Enable)
|
||||
{
|
||||
ResetModels();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Compilation
|
||||
// deadlock note
|
||||
@@ -229,30 +255,30 @@ namespace Umbraco.ModelsBuilder.Embedded
|
||||
|
||||
var modelsDirectory = _config.ModelsDirectoryAbsolute(_hostingEnvironment);
|
||||
if (!Directory.Exists(modelsDirectory))
|
||||
{
|
||||
Directory.CreateDirectory(modelsDirectory);
|
||||
}
|
||||
|
||||
// clear stuff
|
||||
var modelsHashFile = Path.Combine(modelsDirectory, "models.hash");
|
||||
var dllPathFile = Path.Combine(modelsDirectory, "all.dll.path");
|
||||
|
||||
if (File.Exists(dllPathFile)) File.Delete(dllPathFile);
|
||||
if (File.Exists(modelsHashFile)) File.Delete(modelsHashFile);
|
||||
if (File.Exists(dllPathFile))
|
||||
{
|
||||
File.Delete(dllPathFile);
|
||||
}
|
||||
|
||||
if (File.Exists(modelsHashFile))
|
||||
{
|
||||
File.Delete(modelsHashFile);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_locker.IsWriteLockHeld)
|
||||
{
|
||||
_locker.ExitWriteLock();
|
||||
}
|
||||
}
|
||||
|
||||
// gets the RoslynCompiler
|
||||
private RoslynCompiler RoslynCompiler
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_roslynCompiler != null) return _roslynCompiler;
|
||||
_roslynCompiler = new RoslynCompiler(System.Runtime.Loader.AssemblyLoadContext.All.SelectMany(x => x.Assemblies));
|
||||
return _roslynCompiler;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -260,31 +286,42 @@ namespace Umbraco.ModelsBuilder.Embedded
|
||||
internal Infos EnsureModels()
|
||||
{
|
||||
if (_debugLevel > 0)
|
||||
{
|
||||
_logger.LogDebug("Ensuring models.");
|
||||
}
|
||||
|
||||
// don't use an upgradeable lock here because only 1 thread at a time could enter it
|
||||
try
|
||||
{
|
||||
_locker.EnterReadLock();
|
||||
if (_hasModels)
|
||||
{
|
||||
return _infos;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_locker.IsReadLockHeld)
|
||||
{
|
||||
_locker.ExitReadLock();
|
||||
}
|
||||
}
|
||||
|
||||
var roslynLocked = false;
|
||||
try
|
||||
{
|
||||
// TODO: DO NOT LOCK ON RoslynCompiler
|
||||
|
||||
// always take the BuildManager lock *before* taking the _locker lock
|
||||
// to avoid possible deadlock situations (see notes above)
|
||||
Monitor.Enter(RoslynCompiler, ref roslynLocked);
|
||||
|
||||
_locker.EnterUpgradeableReadLock();
|
||||
|
||||
if (_hasModels) return _infos;
|
||||
if (_hasModels)
|
||||
{
|
||||
return _infos;
|
||||
}
|
||||
|
||||
_locker.EnterWriteLock();
|
||||
|
||||
@@ -296,14 +333,13 @@ namespace Umbraco.ModelsBuilder.Embedded
|
||||
{
|
||||
try
|
||||
{
|
||||
var assembly = GetModelsAssembly(_pendingRebuild);
|
||||
Assembly assembly = GetModelsAssembly(_pendingRebuild);
|
||||
|
||||
// the one below can be used to simulate an issue with BuildManager, ie it will register
|
||||
// the models with the factory but NOT with the BuildManager, which will not recompile views.
|
||||
// this is for U4-8043 which is an obvious issue but I cannot replicate
|
||||
//_modelsAssembly = _modelsAssembly ?? assembly;
|
||||
|
||||
var types = assembly.ExportedTypes.Where(x => x.Inherits<PublishedContentModel>() || x.Inherits<PublishedElementModel>());
|
||||
// _modelsAssembly = _modelsAssembly ?? assembly;
|
||||
IEnumerable<Type> types = assembly.ExportedTypes.Where(x => x.Inherits<PublishedContentModel>() || x.Inherits<PublishedElementModel>());
|
||||
_infos = RegisterModels(types);
|
||||
_errors.Clear();
|
||||
}
|
||||
@@ -330,18 +366,26 @@ namespace Umbraco.ModelsBuilder.Embedded
|
||||
finally
|
||||
{
|
||||
if (_locker.IsWriteLockHeld)
|
||||
{
|
||||
_locker.ExitWriteLock();
|
||||
}
|
||||
|
||||
if (_locker.IsUpgradeableReadLockHeld)
|
||||
{
|
||||
_locker.ExitUpgradeableReadLock();
|
||||
}
|
||||
|
||||
if (roslynLocked)
|
||||
{
|
||||
Monitor.Exit(RoslynCompiler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Assembly ReloadAssembly(string pathToAssembly)
|
||||
{
|
||||
// If there's a current AssemblyLoadContext, unload it before creating a new one.
|
||||
if(!(_currentAssemblyLoadContext is null))
|
||||
if (!(_currentAssemblyLoadContext is null))
|
||||
{
|
||||
_currentAssemblyLoadContext.Unload();
|
||||
GC.Collect();
|
||||
@@ -364,9 +408,11 @@ namespace Umbraco.ModelsBuilder.Embedded
|
||||
{
|
||||
var modelsDirectory = _config.ModelsDirectoryAbsolute(_hostingEnvironment);
|
||||
if (!Directory.Exists(modelsDirectory))
|
||||
{
|
||||
Directory.CreateDirectory(modelsDirectory);
|
||||
}
|
||||
|
||||
var typeModels = UmbracoServices.GetAllTypes();
|
||||
IList<TypeModel> typeModels = UmbracoServices.GetAllTypes();
|
||||
var currentHash = TypeModelHasher.Hash(typeModels);
|
||||
var modelsHashFile = Path.Combine(modelsDirectory, "models.hash");
|
||||
var modelsSrcFile = Path.Combine(modelsDirectory, "models.generated.cs");
|
||||
@@ -375,7 +421,6 @@ namespace Umbraco.ModelsBuilder.Embedded
|
||||
|
||||
// caching the generated models speeds up booting
|
||||
// currentHash hashes both the types & the user's partials
|
||||
|
||||
if (!forceRebuild)
|
||||
{
|
||||
_logger.LogDebug("Looking for cached models.");
|
||||
@@ -415,7 +460,7 @@ namespace Umbraco.ModelsBuilder.Embedded
|
||||
{
|
||||
assembly = ReloadAssembly(dllPath);
|
||||
|
||||
var attr = assembly.GetCustomAttribute<ModelsBuilderAssemblyAttribute>();
|
||||
ModelsBuilderAssemblyAttribute attr = assembly.GetCustomAttribute<ModelsBuilderAssemblyAttribute>();
|
||||
if (attr != null && attr.PureLive && attr.SourceHash == currentHash)
|
||||
{
|
||||
// if we were to resume at that revision, then _ver would keep increasing
|
||||
@@ -431,17 +476,23 @@ namespace Umbraco.ModelsBuilder.Embedded
|
||||
_logger.LogDebug("Cached models dll cannot be loaded (invalid assembly).");
|
||||
}
|
||||
else if (!File.Exists(dllPath))
|
||||
{
|
||||
_logger.LogDebug("Cached models dll does not exist.");
|
||||
}
|
||||
else if (File.Exists(dllPath + ".delete"))
|
||||
{
|
||||
_logger.LogDebug("Cached models dll is marked for deletion.");
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogDebug("Cached models dll cannot be loaded (why?).");
|
||||
}
|
||||
}
|
||||
|
||||
// must reset the version in the file else it would keep growing
|
||||
// loading cached modules only happens when the app restarts
|
||||
var text = File.ReadAllText(projFile);
|
||||
var match = AssemblyVersionRegex.Match(text);
|
||||
Match match = s_assemblyVersionRegex.Match(text);
|
||||
if (match.Success)
|
||||
{
|
||||
text = text.Replace(match.Value, "AssemblyVersion(\"0.0.0." + _ver + "\")");
|
||||
@@ -478,8 +529,9 @@ namespace Umbraco.ModelsBuilder.Embedded
|
||||
// AssemblyVersion is so that we have a different version for each rebuild
|
||||
var ver = _ver == _skipver ? ++_ver : _ver;
|
||||
_ver++;
|
||||
code = code.Replace("//ASSATTR", $@"[assembly:ModelsBuilderAssembly(PureLive = true, SourceHash = ""{currentHash}"")]
|
||||
[assembly:System.Reflection.AssemblyVersion(""0.0.0.{ver}"")]");
|
||||
string mbAssemblyDirective = $@"[assembly:ModelsBuilderAssembly(PureLive = true, SourceHash = ""{currentHash}"")]
|
||||
[assembly:System.Reflection.AssemblyVersion(""0.0.0.{ver}"")]";
|
||||
code = code.Replace("//ASSATTR", mbAssemblyDirective);
|
||||
File.WriteAllText(modelsSrcFile, code);
|
||||
|
||||
// generate proj, save
|
||||
@@ -515,21 +567,20 @@ namespace Umbraco.ModelsBuilder.Embedded
|
||||
if (File.Exists(dllPathFile))
|
||||
{
|
||||
var dllPath = File.ReadAllText(dllPathFile);
|
||||
var dirInfo = new DirectoryInfo(dllPath).Parent;
|
||||
var files = dirInfo.GetFiles().Where(f => f.FullName != dllPath);
|
||||
foreach(var file in files)
|
||||
DirectoryInfo dirInfo = new DirectoryInfo(dllPath).Parent;
|
||||
IEnumerable<FileInfo> files = dirInfo.GetFiles().Where(f => f.FullName != dllPath);
|
||||
foreach (FileInfo file in files)
|
||||
{
|
||||
try
|
||||
{
|
||||
File.Delete(file.FullName);
|
||||
}
|
||||
catch(UnauthorizedAccessException)
|
||||
catch (UnauthorizedAccessException)
|
||||
{
|
||||
// The file is in use, we'll try again next time...
|
||||
// This shouldn't happen anymore.
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -537,7 +588,10 @@ namespace Umbraco.ModelsBuilder.Embedded
|
||||
{
|
||||
var dirInfo = new DirectoryInfo(Path.Combine(_config.ModelsDirectoryAbsolute(_hostingEnvironment), "Compiled"));
|
||||
if (!dirInfo.Exists)
|
||||
{
|
||||
Directory.CreateDirectory(dirInfo.FullName);
|
||||
}
|
||||
|
||||
return Path.Combine(dirInfo.FullName, $"generated.cs{currentHash}.dll");
|
||||
}
|
||||
|
||||
@@ -551,51 +605,69 @@ namespace Umbraco.ModelsBuilder.Embedded
|
||||
// useful to have the source around for debugging.
|
||||
try
|
||||
{
|
||||
if (File.Exists(dllPathFile)) File.Delete(dllPathFile);
|
||||
if (File.Exists(modelsHashFile)) File.Delete(modelsHashFile);
|
||||
if (File.Exists(projFile)) File.SetLastWriteTime(projFile, DateTime.Now);
|
||||
if (File.Exists(dllPathFile))
|
||||
{
|
||||
File.Delete(dllPathFile);
|
||||
}
|
||||
|
||||
if (File.Exists(modelsHashFile))
|
||||
{
|
||||
File.Delete(modelsHashFile);
|
||||
}
|
||||
|
||||
if (File.Exists(projFile))
|
||||
{
|
||||
File.SetLastWriteTime(projFile, DateTime.Now);
|
||||
}
|
||||
}
|
||||
catch { /* enough */ }
|
||||
}
|
||||
|
||||
private static Infos RegisterModels(IEnumerable<Type> types)
|
||||
{
|
||||
var ctorArgTypes = new[] { typeof(IPublishedElement), typeof(IPublishedValueFallback) };
|
||||
Type[] ctorArgTypes = new[] { typeof(IPublishedElement), typeof(IPublishedValueFallback) };
|
||||
var modelInfos = new Dictionary<string, ModelInfo>(StringComparer.InvariantCultureIgnoreCase);
|
||||
var map = new Dictionary<string, Type>();
|
||||
|
||||
foreach (var type in types)
|
||||
foreach (Type type in types)
|
||||
{
|
||||
ConstructorInfo constructor = null;
|
||||
Type parameterType = null;
|
||||
|
||||
foreach (var ctor in type.GetConstructors())
|
||||
foreach (ConstructorInfo ctor in type.GetConstructors())
|
||||
{
|
||||
var parms = ctor.GetParameters();
|
||||
ParameterInfo[] parms = ctor.GetParameters();
|
||||
if (parms.Length == 2 && typeof(IPublishedElement).IsAssignableFrom(parms[0].ParameterType) && typeof(IPublishedValueFallback).IsAssignableFrom(parms[1].ParameterType))
|
||||
{
|
||||
if (constructor != null)
|
||||
{
|
||||
throw new InvalidOperationException($"Type {type.FullName} has more than one public constructor with one argument of type, or implementing, IPropertySet.");
|
||||
}
|
||||
|
||||
constructor = ctor;
|
||||
parameterType = parms[0].ParameterType;
|
||||
}
|
||||
}
|
||||
|
||||
if (constructor == null)
|
||||
{
|
||||
throw new InvalidOperationException($"Type {type.FullName} is missing a public constructor with one argument of type, or implementing, IPropertySet.");
|
||||
}
|
||||
|
||||
var attribute = type.GetCustomAttribute<PublishedModelAttribute>(false);
|
||||
PublishedModelAttribute attribute = type.GetCustomAttribute<PublishedModelAttribute>(false);
|
||||
var typeName = attribute == null ? type.Name : attribute.ContentTypeAlias;
|
||||
|
||||
if (modelInfos.TryGetValue(typeName, out var modelInfo))
|
||||
{
|
||||
throw new InvalidOperationException($"Both types {type.FullName} and {modelInfo.ModelType.FullName} want to be a model type for content type with alias \"{typeName}\".");
|
||||
}
|
||||
|
||||
// TODO: use Core's ReflectionUtilities.EmitCtor !!
|
||||
// Yes .. DynamicMethod is uber slow
|
||||
// TODO: But perhaps https://docs.microsoft.com/en-us/dotnet/api/system.reflection.emit.constructorbuilder?view=netcore-3.1 is better still?
|
||||
// See CtorInvokeBenchmarks
|
||||
var meth = new DynamicMethod(string.Empty, typeof(IPublishedElement), ctorArgTypes, type.Module, true);
|
||||
var gen = meth.GetILGenerator();
|
||||
ILGenerator gen = meth.GetILGenerator();
|
||||
gen.Emit(OpCodes.Ldarg_0);
|
||||
gen.Emit(OpCodes.Ldarg_1);
|
||||
gen.Emit(OpCodes.Newobj, constructor);
|
||||
@@ -613,10 +685,14 @@ namespace Umbraco.ModelsBuilder.Embedded
|
||||
{
|
||||
var modelsDirectory = _config.ModelsDirectoryAbsolute(_hostingEnvironment);
|
||||
if (!Directory.Exists(modelsDirectory))
|
||||
{
|
||||
Directory.CreateDirectory(modelsDirectory);
|
||||
}
|
||||
|
||||
foreach (var file in Directory.GetFiles(modelsDirectory, "*.generated.cs"))
|
||||
{
|
||||
File.Delete(file);
|
||||
}
|
||||
|
||||
var builder = new TextBuilder(_config, typeModels);
|
||||
|
||||
@@ -627,9 +703,6 @@ namespace Umbraco.ModelsBuilder.Embedded
|
||||
return code;
|
||||
}
|
||||
|
||||
private static readonly Regex UsingRegex = new Regex("^using(.*);", RegexOptions.Compiled | RegexOptions.Multiline);
|
||||
private static readonly Regex AattrRegex = new Regex("^\\[assembly:(.*)\\]", RegexOptions.Compiled | RegexOptions.Multiline);
|
||||
|
||||
private static string GenerateModelsProj(IDictionary<string, string> files)
|
||||
{
|
||||
// ideally we would generate a CSPROJ file but then we'd need a BuildProvider for csproj
|
||||
@@ -637,21 +710,25 @@ namespace Umbraco.ModelsBuilder.Embedded
|
||||
|
||||
// group all 'using' at the top of the file (else fails)
|
||||
var usings = new List<string>();
|
||||
foreach (var k in files.Keys.ToList())
|
||||
files[k] = UsingRegex.Replace(files[k], m =>
|
||||
foreach (string k in files.Keys.ToList())
|
||||
{
|
||||
files[k] = s_usingRegex.Replace(files[k], m =>
|
||||
{
|
||||
usings.Add(m.Groups[1].Value);
|
||||
return string.Empty;
|
||||
});
|
||||
}
|
||||
|
||||
// group all '[assembly:...]' at the top of the file (else fails)
|
||||
var aattrs = new List<string>();
|
||||
foreach (var k in files.Keys.ToList())
|
||||
files[k] = AattrRegex.Replace(files[k], m =>
|
||||
foreach (string k in files.Keys.ToList())
|
||||
{
|
||||
files[k] = s_aattrRegex.Replace(files[k], m =>
|
||||
{
|
||||
aattrs.Add(m.Groups[1].Value);
|
||||
return string.Empty;
|
||||
});
|
||||
}
|
||||
|
||||
var text = new StringBuilder();
|
||||
foreach (var u in usings.Distinct())
|
||||
@@ -660,14 +737,16 @@ namespace Umbraco.ModelsBuilder.Embedded
|
||||
text.Append(u);
|
||||
text.Append(";\r\n");
|
||||
}
|
||||
|
||||
foreach (var a in aattrs)
|
||||
{
|
||||
text.Append("[assembly:");
|
||||
text.Append(a);
|
||||
text.Append("]\r\n");
|
||||
}
|
||||
|
||||
text.Append("\r\n\r\n");
|
||||
foreach (var f in files)
|
||||
foreach (KeyValuePair<string, string> f in files)
|
||||
{
|
||||
text.Append("// FILE: ");
|
||||
text.Append(f.Key);
|
||||
@@ -675,29 +754,12 @@ namespace Umbraco.ModelsBuilder.Embedded
|
||||
text.Append(f.Value);
|
||||
text.Append("\r\n\r\n\r\n");
|
||||
}
|
||||
|
||||
text.Append("// EOF\r\n");
|
||||
|
||||
return text.ToString();
|
||||
}
|
||||
|
||||
internal class Infos
|
||||
{
|
||||
public Dictionary<string, Type> ModelTypeMap { get; set; }
|
||||
public Dictionary<string, ModelInfo> ModelInfos { get; set; }
|
||||
}
|
||||
|
||||
internal class ModelInfo
|
||||
{
|
||||
public Type ParameterType { get; set; }
|
||||
public Func<IPublishedElement, IPublishedValueFallback, IPublishedElement> Ctor { get; set; }
|
||||
public Type ModelType { get; set; }
|
||||
public Func<IList> ListCtor { get; set; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Watching
|
||||
|
||||
private void WatcherOnChanged(object sender, FileSystemEventArgs args)
|
||||
{
|
||||
var changed = args.Name;
|
||||
@@ -715,7 +777,7 @@ namespace Umbraco.ModelsBuilder.Embedded
|
||||
//}
|
||||
|
||||
// always ignore our own file changes
|
||||
if (OurFiles.Contains(changed))
|
||||
if (s_ourFiles.Contains(changed))
|
||||
return;
|
||||
|
||||
_logger.LogInformation("Detected files changes.");
|
||||
@@ -731,6 +793,24 @@ namespace Umbraco.ModelsBuilder.Embedded
|
||||
_hostingLifetime.UnregisterObject(this);
|
||||
}
|
||||
|
||||
internal class Infos
|
||||
{
|
||||
public Dictionary<string, Type> ModelTypeMap { get; set; }
|
||||
|
||||
public Dictionary<string, ModelInfo> ModelInfos { get; set; }
|
||||
}
|
||||
|
||||
internal class ModelInfo
|
||||
{
|
||||
public Type ParameterType { get; set; }
|
||||
|
||||
public Func<IPublishedElement, IPublishedValueFallback, IPublishedElement> Ctor { get; set; }
|
||||
|
||||
public Type ModelType { get; set; }
|
||||
|
||||
public Func<IList> ListCtor { get; set; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace Umbraco.Web.Common.Localization
|
||||
return NullProviderCultureResult;
|
||||
}
|
||||
|
||||
lock(_locker)
|
||||
lock (_locker)
|
||||
{
|
||||
// We need to dynamically change the supported cultures since we won't ever know what languages are used since
|
||||
// they are dynamic within Umbraco.
|
||||
|
||||
Reference in New Issue
Block a user