Moves classes/namespaces, reduces statics, reduces usages of "Current", imports some unit tests from orig MB.
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: AssemblyCompany("Umbraco")]
|
||||
[assembly: AssemblyCopyright("Copyright © Umbraco 2019")]
|
||||
@@ -20,3 +21,5 @@ using System.Resources;
|
||||
// these are FYI and changed automatically
|
||||
[assembly: AssemblyFileVersion("8.3.0")]
|
||||
[assembly: AssemblyInformationalVersion("8.3.0")]
|
||||
|
||||
[assembly: InternalsVisibleTo("Umbraco.Tests")]
|
||||
|
||||
58
src/Umbraco.ModelsBuilder/BackOffice/DashboardReport.cs
Normal file
58
src/Umbraco.ModelsBuilder/BackOffice/DashboardReport.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
using System.Text;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.ModelsBuilder.Configuration;
|
||||
using Umbraco.ModelsBuilder.Umbraco;
|
||||
|
||||
namespace Umbraco.ModelsBuilder.BackOffice
|
||||
{
|
||||
internal class DashboardReport
|
||||
{
|
||||
private readonly IModelsBuilderConfig _config;
|
||||
private readonly ModelsGenerator _modelsGenerator;
|
||||
|
||||
public DashboardReport(IModelsBuilderConfig config, ModelsGenerator modelsGenerator)
|
||||
{
|
||||
_config = config;
|
||||
_modelsGenerator = modelsGenerator;
|
||||
}
|
||||
|
||||
public bool CanGenerate() => _config.ModelsMode.SupportsExplicitGeneration();
|
||||
|
||||
public bool AreModelsOutOfDate() => OutOfDateModelsStatus.IsOutOfDate;
|
||||
|
||||
public string LastError() => _modelsGenerator.GetLastError();
|
||||
|
||||
public string Text()
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
|
||||
sb.Append("Version: ");
|
||||
sb.Append(Api.ApiVersion.Current.Version);
|
||||
sb.Append("<br /> <br />");
|
||||
|
||||
sb.Append("ModelsBuilder is enabled, with the following configuration:");
|
||||
|
||||
sb.Append("<ul>");
|
||||
|
||||
sb.Append("<li>The <strong>models factory</strong> is ");
|
||||
sb.Append(_config.EnableFactory || _config.ModelsMode == ModelsMode.PureLive
|
||||
? "enabled"
|
||||
: "not enabled. Umbraco will <em>not</em> use models");
|
||||
sb.Append(".</li>");
|
||||
|
||||
sb.Append(_config.ModelsMode != ModelsMode.Nothing
|
||||
? $"<li><strong>{_config.ModelsMode} models</strong> are enabled.</li>"
|
||||
: "<li>No models mode is specified: models will <em>not</em> be generated.</li>");
|
||||
|
||||
sb.Append($"<li>Models namespace is {_config.ModelsNamespace}.</li>");
|
||||
|
||||
sb.Append("<li>Tracking of <strong>out-of-date models</strong> is ");
|
||||
sb.Append(_config.FlagOutOfDateModels ? "enabled" : "not enabled");
|
||||
sb.Append(".</li>");
|
||||
|
||||
sb.Append("</ul>");
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,11 +9,11 @@ using System.Web.Hosting;
|
||||
using Umbraco.Core.Exceptions;
|
||||
using Umbraco.ModelsBuilder.Building;
|
||||
using Umbraco.ModelsBuilder.Configuration;
|
||||
using Umbraco.ModelsBuilder.Dashboard;
|
||||
using Umbraco.ModelsBuilder.Umbraco;
|
||||
using Umbraco.Web.Editors;
|
||||
using Umbraco.Web.WebApi.Filters;
|
||||
|
||||
namespace Umbraco.ModelsBuilder.Umbraco
|
||||
namespace Umbraco.ModelsBuilder.BackOffice
|
||||
{
|
||||
/// <summary>
|
||||
/// API controller for use in the Umbraco back office with Angular resources
|
||||
@@ -26,13 +26,16 @@ namespace Umbraco.ModelsBuilder.Umbraco
|
||||
[UmbracoApplicationAuthorize(Core.Constants.Applications.Settings)]
|
||||
public class ModelsBuilderBackOfficeController : UmbracoAuthorizedJsonController
|
||||
{
|
||||
private readonly UmbracoServices _umbracoServices;
|
||||
private readonly Config _config;
|
||||
private readonly IModelsBuilderConfig _config;
|
||||
private readonly ModelsGenerator _modelGenerator;
|
||||
private readonly DashboardReport _dashboardReport;
|
||||
|
||||
public ModelsBuilderBackOfficeController(UmbracoServices umbracoServices, Config config)
|
||||
public ModelsBuilderBackOfficeController(IModelsBuilderConfig config, ModelsGenerator modelsGenerator)
|
||||
{
|
||||
//_umbracoServices = umbracoServices;
|
||||
_config = config;
|
||||
_modelGenerator = modelsGenerator;
|
||||
_dashboardReport = new DashboardReport(config, modelsGenerator);
|
||||
}
|
||||
|
||||
// invoked by the dashboard
|
||||
@@ -51,20 +54,17 @@ namespace Umbraco.ModelsBuilder.Umbraco
|
||||
return Request.CreateResponse(HttpStatusCode.OK, result2, Configuration.Formatters.JsonFormatter);
|
||||
}
|
||||
|
||||
var modelsDirectory = config.ModelsDirectory;
|
||||
|
||||
var bin = HostingEnvironment.MapPath("~/bin");
|
||||
if (bin == null)
|
||||
throw new PanicException("bin is null.");
|
||||
|
||||
// EnableDllModels will recycle the app domain - but this request will end properly
|
||||
GenerateModels(modelsDirectory);
|
||||
|
||||
ModelsGenerationError.Clear();
|
||||
_modelGenerator.GenerateModels();
|
||||
_modelGenerator.ClearErrors();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ModelsGenerationError.Report("Failed to build models.", e);
|
||||
_modelGenerator.ReportError("Failed to build models.", e);
|
||||
}
|
||||
|
||||
return Request.CreateResponse(HttpStatusCode.OK, GetDashboardResult(), Configuration.Formatters.JsonFormatter);
|
||||
@@ -76,9 +76,9 @@ namespace Umbraco.ModelsBuilder.Umbraco
|
||||
public HttpResponseMessage GetModelsOutOfDateStatus()
|
||||
{
|
||||
var status = OutOfDateModelsStatus.IsEnabled
|
||||
? (OutOfDateModelsStatus.IsOutOfDate
|
||||
? OutOfDateModelsStatus.IsOutOfDate
|
||||
? new OutOfDateStatus { Status = OutOfDateType.OutOfDate }
|
||||
: new OutOfDateStatus { Status = OutOfDateType.Current })
|
||||
: new OutOfDateStatus { Status = OutOfDateType.Current }
|
||||
: new OutOfDateStatus { Status = OutOfDateType.Unknown };
|
||||
|
||||
return Request.CreateResponse(HttpStatusCode.OK, status, Configuration.Formatters.JsonFormatter);
|
||||
@@ -98,52 +98,13 @@ namespace Umbraco.ModelsBuilder.Umbraco
|
||||
return new Dashboard
|
||||
{
|
||||
Enable = true,
|
||||
Text = BuilderDashboardHelper.Text(),
|
||||
CanGenerate = BuilderDashboardHelper.CanGenerate(),
|
||||
OutOfDateModels = BuilderDashboardHelper.AreModelsOutOfDate(),
|
||||
LastError = BuilderDashboardHelper.LastError(),
|
||||
Text = _dashboardReport.Text(),
|
||||
CanGenerate = _dashboardReport.CanGenerate(),
|
||||
OutOfDateModels = _dashboardReport.AreModelsOutOfDate(),
|
||||
LastError = _dashboardReport.LastError(),
|
||||
};
|
||||
}
|
||||
|
||||
private void GenerateModels(string modelsDirectory)
|
||||
{
|
||||
GenerateModels(_umbracoServices, modelsDirectory, _config.ModelsNamespace);
|
||||
}
|
||||
|
||||
internal static void GenerateModels(UmbracoServices umbracoServices, string modelsDirectory, string modelsNamespace)
|
||||
{
|
||||
if (!Directory.Exists(modelsDirectory))
|
||||
Directory.CreateDirectory(modelsDirectory);
|
||||
|
||||
foreach (var file in Directory.GetFiles(modelsDirectory, "*.generated.cs"))
|
||||
File.Delete(file);
|
||||
|
||||
var typeModels = umbracoServices.GetAllTypes();
|
||||
|
||||
var builder = new TextBuilder(typeModels, modelsNamespace);
|
||||
|
||||
foreach (var typeModel in builder.GetModelsToGenerate())
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
builder.Generate(sb, typeModel);
|
||||
var filename = Path.Combine(modelsDirectory, typeModel.ClrName + ".generated.cs");
|
||||
File.WriteAllText(filename, sb.ToString());
|
||||
}
|
||||
|
||||
// the idea was to calculate the current hash and to add it as an extra file to the compilation,
|
||||
// in order to be able to detect whether a DLL is consistent with an environment - however the
|
||||
// environment *might not* contain the local partial files, and thus it could be impossible to
|
||||
// calculate the hash. So... maybe that's not a good idea after all?
|
||||
/*
|
||||
var currentHash = HashHelper.Hash(ourFiles, typeModels);
|
||||
ourFiles["models.hash.cs"] = $@"using Umbraco.ModelsBuilder;
|
||||
[assembly:ModelsBuilderAssembly(SourceHash = ""{currentHash}"")]
|
||||
";
|
||||
*/
|
||||
|
||||
OutOfDateModelsStatus.Clear();
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
internal class BuildResult
|
||||
{
|
||||
@@ -23,12 +23,11 @@ namespace Umbraco.ModelsBuilder.Building
|
||||
/// </summary>
|
||||
internal abstract class Builder
|
||||
{
|
||||
|
||||
private readonly IList<TypeModel> _typeModels;
|
||||
|
||||
protected Dictionary<string, string> ModelsMap { get; } = new Dictionary<string, string>();
|
||||
|
||||
private static Config Config => Current.Configs.ModelsBuilder();
|
||||
|
||||
// the list of assemblies that will be 'using' by default
|
||||
protected readonly IList<string> TypesUsing = new List<string>
|
||||
{
|
||||
@@ -69,27 +68,20 @@ namespace Umbraco.ModelsBuilder.Building
|
||||
/// <remarks>Includes those that are ignored.</remarks>
|
||||
internal IList<TypeModel> TypeModels => _typeModels;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Builder"/> class with a list of models to generate
|
||||
/// and the result of code parsing.
|
||||
/// </summary>
|
||||
/// <param name="typeModels">The list of models to generate.</param>
|
||||
protected Builder(IList<TypeModel> typeModels)
|
||||
: this(typeModels, null)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Builder"/> class with a list of models to generate,
|
||||
/// the result of code parsing, and a models namespace.
|
||||
/// </summary>
|
||||
/// <param name="typeModels">The list of models to generate.</param>
|
||||
/// <param name="modelsNamespace">The models namespace.</param>
|
||||
protected Builder(IList<TypeModel> typeModels, string modelsNamespace)
|
||||
protected Builder(IModelsBuilderConfig config, IList<TypeModel> typeModels)
|
||||
{
|
||||
_typeModels = typeModels ?? throw new ArgumentNullException(nameof(typeModels));
|
||||
|
||||
Config = config ?? throw new ArgumentNullException(nameof(config));
|
||||
|
||||
// can be null or empty, we'll manage
|
||||
ModelsNamespace = modelsNamespace;
|
||||
ModelsNamespace = Config.ModelsNamespace;
|
||||
|
||||
// but we want it to prepare
|
||||
Prepare();
|
||||
@@ -99,6 +91,8 @@ namespace Umbraco.ModelsBuilder.Building
|
||||
protected Builder()
|
||||
{ }
|
||||
|
||||
protected IModelsBuilderConfig Config { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Prepares generation by processing the result of code parsing.
|
||||
/// </summary>
|
||||
@@ -204,6 +198,8 @@ namespace Umbraco.ModelsBuilder.Building
|
||||
// cannot figure out is a symbol is ambiguous without Roslyn
|
||||
// so... let's say everything is ambiguous - code won't be
|
||||
// pretty but it'll work
|
||||
|
||||
// Essentially this means that a `global::` syntax will be output for the generated models
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -220,7 +216,7 @@ namespace Umbraco.ModelsBuilder.Building
|
||||
|
||||
// default
|
||||
// fixme - should NOT reference config here, should make ModelsNamespace mandatory
|
||||
return Config.ModelsNamespace;
|
||||
return string.IsNullOrWhiteSpace(Config.ModelsNamespace) ? ModelsBuilderConfig.DefaultModelsNamespace : Config.ModelsNamespace;
|
||||
}
|
||||
|
||||
protected string GetModelsBaseClassName(TypeModel type)
|
||||
|
||||
@@ -20,26 +20,14 @@ namespace Umbraco.ModelsBuilder.Building
|
||||
/// and the result of code parsing.
|
||||
/// </summary>
|
||||
/// <param name="typeModels">The list of models to generate.</param>
|
||||
public TextBuilder(IList<TypeModel> typeModels)
|
||||
: base(typeModels)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TextBuilder"/> class with a list of models to generate,
|
||||
/// the result of code parsing, and a models namespace.
|
||||
/// </summary>
|
||||
/// <param name="typeModels">The list of models to generate.</param>
|
||||
/// <param name="modelsNamespace">The models namespace.</param>
|
||||
public TextBuilder(IList<TypeModel> typeModels, string modelsNamespace)
|
||||
: base(typeModels, modelsNamespace)
|
||||
public TextBuilder(IModelsBuilderConfig config, IList<TypeModel> typeModels)
|
||||
: base(config, typeModels)
|
||||
{ }
|
||||
|
||||
// internal for unit tests only
|
||||
internal TextBuilder()
|
||||
{ }
|
||||
|
||||
private static Config Config => Current.Configs.ModelsBuilder();
|
||||
|
||||
/// <summary>
|
||||
/// Outputs a generated model to a string builder.
|
||||
/// </summary>
|
||||
@@ -354,7 +342,7 @@ namespace Umbraco.ModelsBuilder.Building
|
||||
|
||||
var mixinStaticGetterName = MixinStaticGetterName(property.ClrName);
|
||||
|
||||
if (type.StaticMixinMethods.Contains(mixinStaticGetterName)) return;
|
||||
//if (type.StaticMixinMethods.Contains(mixinStaticGetterName)) return;
|
||||
|
||||
sb.Append("\n");
|
||||
|
||||
|
||||
@@ -77,10 +77,10 @@ namespace Umbraco.ModelsBuilder.Building
|
||||
/// </summary>
|
||||
public readonly List<TypeModel> ImplementingInterfaces = new List<TypeModel>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of existing static mixin method candidates.
|
||||
/// </summary>
|
||||
public readonly List<string> StaticMixinMethods = new List<string>();
|
||||
///// <summary>
|
||||
///// Gets the list of existing static mixin method candidates.
|
||||
///// </summary>
|
||||
//public readonly List<string> StaticMixinMethods = new List<string>(); //TODO: Do we need this? it isn't used
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this model has a base class.
|
||||
|
||||
@@ -8,23 +8,25 @@ using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Core.Services.Implement;
|
||||
using Umbraco.ModelsBuilder.BackOffice;
|
||||
using Umbraco.ModelsBuilder.Configuration;
|
||||
using Umbraco.ModelsBuilder.Umbraco;
|
||||
using Umbraco.Web;
|
||||
using Umbraco.Web.JavaScript;
|
||||
using Umbraco.Web.Mvc;
|
||||
|
||||
namespace Umbraco.ModelsBuilder.Umbraco
|
||||
namespace Umbraco.ModelsBuilder.Compose
|
||||
{
|
||||
public class ModelsBuilderComponent : IComponent
|
||||
{
|
||||
private readonly UmbracoServices _umbracoServices;
|
||||
|
||||
private readonly Config _config;
|
||||
private readonly IModelsBuilderConfig _config;
|
||||
private readonly LiveModelsProvider _liveModelsProvider;
|
||||
|
||||
public ModelsBuilderComponent(UmbracoServices umbracoServices, Config config)
|
||||
public ModelsBuilderComponent(IModelsBuilderConfig config, LiveModelsProvider liveModelsProvider)
|
||||
{
|
||||
_umbracoServices = umbracoServices;
|
||||
_config = config;
|
||||
_liveModelsProvider = liveModelsProvider;
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
@@ -39,7 +41,7 @@ namespace Umbraco.ModelsBuilder.Umbraco
|
||||
|
||||
// fixme LiveModelsProvider should not be static
|
||||
if (_config.ModelsMode.IsLiveNotPure())
|
||||
LiveModelsProvider.Install(_umbracoServices);
|
||||
_liveModelsProvider.Install();
|
||||
|
||||
// fixme OutOfDateModelsStatus should not be static
|
||||
if (_config.FlagOutOfDateModels)
|
||||
@@ -105,7 +107,6 @@ namespace Umbraco.ModelsBuilder.Umbraco
|
||||
throw new InvalidOperationException("The additionalData key: ContentTypeAlias was not found");
|
||||
|
||||
foreach (var template in e.SavedEntities)
|
||||
{
|
||||
// if it is in fact a new entity (not been saved yet) and the "CreateTemplateForContentType" key
|
||||
// is found, then it means a new template is being created based on the creation of a document type
|
||||
if (!template.HasIdentity && string.IsNullOrWhiteSpace(template.Content))
|
||||
@@ -130,7 +131,6 @@ namespace Umbraco.ModelsBuilder.Umbraco
|
||||
template.Content = markup;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ContentModelBinder_ModelBindingException(object sender, ContentModelBinder.ModelBindingArgs args)
|
||||
{
|
||||
@@ -158,7 +158,6 @@ namespace Umbraco.ModelsBuilder.Umbraco
|
||||
var pureModel = modelAttr.PureLive;
|
||||
|
||||
if (sourceAttr.PureLive || modelAttr.PureLive)
|
||||
{
|
||||
if (pureSource == false || pureModel == false)
|
||||
{
|
||||
// only one is pure - report, but better not restart (loops?)
|
||||
@@ -182,4 +181,3 @@ namespace Umbraco.ModelsBuilder.Umbraco
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,9 +3,10 @@ using Umbraco.Core;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
using Umbraco.ModelsBuilder.Configuration;
|
||||
using Umbraco.ModelsBuilder.Umbraco;
|
||||
using Umbraco.Web.PublishedCache.NuCache;
|
||||
|
||||
namespace Umbraco.ModelsBuilder.Umbraco
|
||||
namespace Umbraco.ModelsBuilder.Compose
|
||||
{
|
||||
[ComposeBefore(typeof(NuCacheComposer))]
|
||||
[RuntimeLevel(MinLevel = RuntimeLevel.Run)]
|
||||
@@ -16,7 +17,9 @@ namespace Umbraco.ModelsBuilder.Umbraco
|
||||
base.Compose(composition);
|
||||
|
||||
composition.Register<UmbracoServices>(Lifetime.Singleton);
|
||||
composition.Configs.Add(() => new Config());
|
||||
composition.Configs.Add<IModelsBuilderConfig>(() => new ModelsBuilderConfig());
|
||||
composition.RegisterUnique<ModelsGenerator>();
|
||||
composition.RegisterUnique<LiveModelsProvider>();
|
||||
|
||||
if (composition.Configs.ModelsBuilder().ModelsMode == ModelsMode.PureLive)
|
||||
ComposeForLiveModels(composition);
|
||||
@@ -1,12 +1,12 @@
|
||||
using System.Web;
|
||||
using System.Web.Compilation;
|
||||
using Umbraco.ModelsBuilder.Umbraco;
|
||||
using Umbraco.ModelsBuilder.Compose;
|
||||
|
||||
[assembly: PreApplicationStartMethod(typeof(ModelsBuilderInitializer), "Initialize")]
|
||||
|
||||
namespace Umbraco.ModelsBuilder.Umbraco
|
||||
namespace Umbraco.ModelsBuilder.Compose
|
||||
{
|
||||
public static class ModelsBuilderInitializer
|
||||
internal static class ModelsBuilderInitializer
|
||||
{
|
||||
public static void Initialize()
|
||||
{
|
||||
@@ -14,7 +14,7 @@ namespace Umbraco.ModelsBuilder
|
||||
/// <remarks>Getting the models builder configuration freezes its state,
|
||||
/// and any attempt at modifying the configuration using the Setup method
|
||||
/// will be ignored.</remarks>
|
||||
public static Config ModelsBuilder(this Configs configs)
|
||||
=> configs.GetConfig<Config>();
|
||||
public static ModelsBuilderConfig ModelsBuilder(this Configs configs)
|
||||
=> configs.GetConfig<ModelsBuilderConfig>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
namespace Umbraco.ModelsBuilder.Configuration
|
||||
{
|
||||
public interface IModelsBuilderConfig
|
||||
{
|
||||
bool AcceptUnsafeModelsDirectory { get; }
|
||||
int DebugLevel { get; }
|
||||
bool EnableFactory { get; }
|
||||
bool FlagOutOfDateModels { get; }
|
||||
bool IsDebug { get; }
|
||||
string ModelsDirectory { get; }
|
||||
ModelsMode ModelsMode { get; }
|
||||
string ModelsNamespace { get; }
|
||||
}
|
||||
}
|
||||
@@ -4,29 +4,28 @@ using System.IO;
|
||||
using System.Web.Configuration;
|
||||
using System.Web.Hosting;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.IO;
|
||||
|
||||
namespace Umbraco.ModelsBuilder.Configuration
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the models builder configuration.
|
||||
/// </summary>
|
||||
public class Config
|
||||
public class ModelsBuilderConfig : IModelsBuilderConfig
|
||||
{
|
||||
internal const string DefaultModelsNamespace = "Umbraco.Web.PublishedModels";
|
||||
internal const string DefaultModelsDirectory = "~/App_Data/Models";
|
||||
public const string DefaultModelsNamespace = "Umbraco.Web.PublishedModels";
|
||||
public const string DefaultModelsDirectory = "~/App_Data/Models";
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Config"/> class.
|
||||
/// Initializes a new instance of the <see cref="ModelsBuilderConfig"/> class.
|
||||
/// </summary>
|
||||
public Config()
|
||||
public ModelsBuilderConfig()
|
||||
{
|
||||
const string prefix = "Umbraco.ModelsBuilder.";
|
||||
|
||||
// ensure defaults are initialized for tests
|
||||
ModelsNamespace = DefaultModelsNamespace;
|
||||
ModelsDirectory = HostingEnvironment.IsHosted
|
||||
? HostingEnvironment.MapPath(DefaultModelsDirectory)
|
||||
: DefaultModelsDirectory.TrimStart("~/");
|
||||
ModelsDirectory = IOHelper.MapPath("~/");
|
||||
DebugLevel = 0;
|
||||
|
||||
// mode
|
||||
@@ -69,9 +68,7 @@ namespace Umbraco.ModelsBuilder.Configuration
|
||||
value = ConfigurationManager.AppSettings[prefix + "ModelsDirectory"];
|
||||
if (!string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
var root = HostingEnvironment.IsHosted
|
||||
? HostingEnvironment.MapPath("~/")
|
||||
: Directory.GetCurrentDirectory();
|
||||
var root = IOHelper.MapPath("~/");
|
||||
if (root == null)
|
||||
throw new ConfigurationErrorsException("Could not determine root directory.");
|
||||
|
||||
@@ -95,9 +92,9 @@ namespace Umbraco.ModelsBuilder.Configuration
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Config"/> class.
|
||||
/// Initializes a new instance of the <see cref="ModelsBuilderConfig"/> class.
|
||||
/// </summary>
|
||||
public Config(
|
||||
public ModelsBuilderConfig(
|
||||
ModelsMode modelsMode = ModelsMode.Nothing,
|
||||
string modelsNamespace = null,
|
||||
bool enableFactory = true,
|
||||
@@ -8,7 +8,7 @@
|
||||
/// <summary>
|
||||
/// Do not generate models.
|
||||
/// </summary>
|
||||
Nothing = 0, // default value
|
||||
Nothing = 0, // default value //TODO: This doesn't make sense since we cannot actualy disable MB since Umbraco would die
|
||||
|
||||
/// <summary>
|
||||
/// Generate models in memory.
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
using System.Text;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.ModelsBuilder.Configuration;
|
||||
using Umbraco.ModelsBuilder.Umbraco;
|
||||
|
||||
namespace Umbraco.ModelsBuilder.Dashboard
|
||||
{
|
||||
internal static class BuilderDashboardHelper
|
||||
{
|
||||
private static Config Config => Current.Configs.ModelsBuilder();
|
||||
|
||||
public static bool CanGenerate()
|
||||
{
|
||||
return Config.ModelsMode.SupportsExplicitGeneration();
|
||||
}
|
||||
|
||||
public static bool AreModelsOutOfDate()
|
||||
{
|
||||
return OutOfDateModelsStatus.IsOutOfDate;
|
||||
}
|
||||
|
||||
public static string LastError()
|
||||
{
|
||||
return ModelsGenerationError.GetLastError();
|
||||
}
|
||||
|
||||
public static string Text()
|
||||
{
|
||||
var config = Config;
|
||||
|
||||
var sb = new StringBuilder();
|
||||
|
||||
sb.Append("Version: ");
|
||||
sb.Append(Api.ApiVersion.Current.Version);
|
||||
sb.Append("<br /> <br />");
|
||||
|
||||
sb.Append("ModelsBuilder is enabled, with the following configuration:");
|
||||
|
||||
sb.Append("<ul>");
|
||||
|
||||
sb.Append("<li>The <strong>models factory</strong> is ");
|
||||
sb.Append(config.EnableFactory || config.ModelsMode == ModelsMode.PureLive
|
||||
? "enabled"
|
||||
: "not enabled. Umbraco will <em>not</em> use models");
|
||||
sb.Append(".</li>");
|
||||
|
||||
sb.Append(config.ModelsMode != ModelsMode.Nothing
|
||||
? $"<li><strong>{config.ModelsMode} models</strong> are enabled.</li>"
|
||||
: "<li>No models mode is specified: models will <em>not</em> be generated.</li>");
|
||||
|
||||
sb.Append($"<li>Models namespace is {config.ModelsNamespace}.</li>");
|
||||
|
||||
sb.Append("<li>Tracking of <strong>out-of-date models</strong> is ");
|
||||
sb.Append(config.FlagOutOfDateModels ? "enabled" : "not enabled");
|
||||
sb.Append(".</li>");
|
||||
|
||||
sb.Append("</ul>");
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,17 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Umbraco.ModelsBuilder.Umbraco
|
||||
namespace Umbraco.ModelsBuilder
|
||||
{
|
||||
// because, of course, it's internal in Umbraco
|
||||
// see also System.Web.Util.HashCodeCombiner
|
||||
class HashCombiner
|
||||
internal class HashCombiner
|
||||
{
|
||||
private long _combinedHash = 5381L;
|
||||
|
||||
public void Add(int i)
|
||||
{
|
||||
_combinedHash = ((_combinedHash << 5) + _combinedHash) ^ i;
|
||||
_combinedHash = (_combinedHash << 5) + _combinedHash ^ i;
|
||||
}
|
||||
|
||||
public void Add(object o)
|
||||
@@ -27,7 +27,7 @@ namespace Umbraco.ModelsBuilder.Umbraco
|
||||
public void Add(string s)
|
||||
{
|
||||
if (s == null) return;
|
||||
Add((StringComparer.InvariantCulture).GetHashCode(s));
|
||||
Add(StringComparer.InvariantCulture.GetHashCode(s));
|
||||
}
|
||||
|
||||
public string GetCombinedHashCode()
|
||||
@@ -56,10 +56,11 @@
|
||||
<Compile Include="Building\TextHeaderWriter.cs" />
|
||||
<Compile Include="Building\TypeModel.cs" />
|
||||
<Compile Include="ConfigsExtensions.cs" />
|
||||
<Compile Include="Configuration\Config.cs" />
|
||||
<Compile Include="Configuration\IModelsBuilderConfig.cs" />
|
||||
<Compile Include="Configuration\ModelsBuilderConfig.cs" />
|
||||
<Compile Include="Configuration\ModelsMode.cs" />
|
||||
<Compile Include="Configuration\ModelsModeExtensions.cs" />
|
||||
<Compile Include="Dashboard\BuilderDashboardHelper.cs" />
|
||||
<Compile Include="BackOffice\DashboardReport.cs" />
|
||||
<Compile Include="ImplementPropertyTypeAttribute.cs" />
|
||||
<Compile Include="ModelsBuilderAssemblyAttribute.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
@@ -67,13 +68,15 @@
|
||||
<Compile Include="PureLiveAssemblyAttribute.cs" />
|
||||
<Compile Include="ReferencedAssemblies.cs" />
|
||||
<Compile Include="TypeExtensions.cs" />
|
||||
<Compile Include="Umbraco\HashCombiner.cs" />
|
||||
<Compile Include="Umbraco\HashHelper.cs" />
|
||||
<Compile Include="HashCombiner.cs" />
|
||||
<Compile Include="Umbraco\LiveModelsProvider.cs" />
|
||||
<Compile Include="Umbraco\ModelsBuilderBackOfficeController.cs" />
|
||||
<Compile Include="Umbraco\ModelsBuilderComponent.cs" />
|
||||
<Compile Include="Umbraco\ModelsBuilderComposer.cs" />
|
||||
<Compile Include="Umbraco\ModelsBuilderInitializer.cs" />
|
||||
<Compile Include="Umbraco\LiveModelsProviderModule.cs" />
|
||||
<Compile Include="Umbraco\ModelsGenerator.cs" />
|
||||
<Compile Include="BackOffice\ModelsBuilderBackOfficeController.cs" />
|
||||
<Compile Include="Compose\ModelsBuilderComponent.cs" />
|
||||
<Compile Include="Compose\ModelsBuilderComposer.cs" />
|
||||
<Compile Include="Umbraco\ModelsBuilderHasher.cs" />
|
||||
<Compile Include="Compose\ModelsBuilderInitializer.cs" />
|
||||
<Compile Include="Umbraco\ModelsGenerationError.cs" />
|
||||
<Compile Include="Umbraco\OutOfDateModelsStatus.cs" />
|
||||
<Compile Include="Umbraco\PublishedModelUtility.cs" />
|
||||
@@ -92,10 +95,6 @@
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Umbraco.Abstractions\Umbraco.Abstractions.csproj">
|
||||
<Project>{29aa69d9-b597-4395-8d42-43b1263c240a}</Project>
|
||||
<Name>Umbraco.Abstractions</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Umbraco.Core\Umbraco.Core.csproj">
|
||||
<Project>{31785BC3-256C-4613-B2F5-A1B0BDDED8C1}</Project>
|
||||
<Name>Umbraco.Core</Name>
|
||||
@@ -110,5 +109,8 @@
|
||||
<Version>5.2.7</Version>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Dashboard\" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
@@ -2,43 +2,46 @@
|
||||
using System.Threading;
|
||||
using System.Web;
|
||||
using System.Web.Hosting;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Exceptions;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.ModelsBuilder.Configuration;
|
||||
using Umbraco.ModelsBuilder.Umbraco;
|
||||
using Umbraco.Web.Cache;
|
||||
|
||||
// will install only if configuration says it needs to be installed
|
||||
[assembly: PreApplicationStartMethod(typeof(LiveModelsProviderModule), "Install")]
|
||||
|
||||
namespace Umbraco.ModelsBuilder.Umbraco
|
||||
{
|
||||
// supports LiveDll and LiveAppData - but not PureLive
|
||||
public sealed class LiveModelsProvider
|
||||
{
|
||||
private static UmbracoServices _umbracoServices;
|
||||
private static Mutex _mutex;
|
||||
private static int _req;
|
||||
|
||||
private static Config Config => Current.Configs.ModelsBuilder();
|
||||
private readonly ILogger _logger;
|
||||
private readonly IModelsBuilderConfig _config;
|
||||
private readonly ModelsGenerator _modelGenerator;
|
||||
|
||||
// we do not manage pure live here
|
||||
internal static bool IsEnabled => Config.ModelsMode.IsLiveNotPure();
|
||||
internal bool IsEnabled => _config.ModelsMode.IsLiveNotPure();
|
||||
|
||||
internal static void Install(UmbracoServices umbracoServices)
|
||||
public LiveModelsProvider(ILogger logger, IModelsBuilderConfig config, ModelsGenerator modelGenerator)
|
||||
{
|
||||
_logger = logger;
|
||||
_config = config ?? throw new ArgumentNullException(nameof(config));
|
||||
_modelGenerator = modelGenerator;
|
||||
}
|
||||
|
||||
internal void Install()
|
||||
{
|
||||
// just be sure
|
||||
if (!IsEnabled)
|
||||
return;
|
||||
|
||||
_umbracoServices = umbracoServices;
|
||||
|
||||
// initialize mutex
|
||||
// ApplicationId will look like "/LM/W3SVC/1/Root/AppName"
|
||||
// name is system-wide and must be less than 260 chars
|
||||
var name = HostingEnvironment.ApplicationID + "/UmbracoLiveModelsProvider";
|
||||
_mutex = new Mutex(false, name);
|
||||
|
||||
_mutex = new Mutex(false, name); //TODO: Replace this with MainDom? Seems we now have 2x implementations of almost the same thing
|
||||
|
||||
// anything changes, and we want to re-generate models.
|
||||
ContentTypeCacheRefresher.CacheUpdated += RequestModelsGeneration;
|
||||
@@ -57,14 +60,14 @@ namespace Umbraco.ModelsBuilder.Umbraco
|
||||
// need to be generated. Could be by another request. Anyway. We could
|
||||
// have collisions but... you know the risk.
|
||||
|
||||
private static void RequestModelsGeneration(object sender, EventArgs args)
|
||||
private void RequestModelsGeneration(object sender, EventArgs args)
|
||||
{
|
||||
//HttpContext.Current.Items[this] = true;
|
||||
Current.Logger.Debug<LiveModelsProvider>("Requested to generate models.");
|
||||
_logger.Debug<LiveModelsProvider>("Requested to generate models.");
|
||||
Interlocked.Exchange(ref _req, 1);
|
||||
}
|
||||
|
||||
public static void GenerateModelsIfRequested(object sender, EventArgs args)
|
||||
public void GenerateModelsIfRequested(object sender, EventArgs args)
|
||||
{
|
||||
//if (HttpContext.Current.Items[this] == null) return;
|
||||
if (Interlocked.Exchange(ref _req, 0) == 0) return;
|
||||
@@ -74,22 +77,22 @@ namespace Umbraco.ModelsBuilder.Umbraco
|
||||
|
||||
try
|
||||
{
|
||||
Current.Logger.Debug<LiveModelsProvider>("Generate models...");
|
||||
_logger.Debug<LiveModelsProvider>("Generate models...");
|
||||
const int timeout = 2*60*1000; // 2 mins
|
||||
_mutex.WaitOne(timeout); // wait until it is safe, and acquire
|
||||
Current.Logger.Info<LiveModelsProvider>("Generate models now.");
|
||||
_logger.Info<LiveModelsProvider>("Generate models now.");
|
||||
GenerateModels();
|
||||
ModelsGenerationError.Clear();
|
||||
Current.Logger.Info<LiveModelsProvider>("Generated.");
|
||||
_modelGenerator.ClearErrors();
|
||||
_logger.Info<LiveModelsProvider>("Generated.");
|
||||
}
|
||||
catch (TimeoutException)
|
||||
{
|
||||
Current.Logger.Warn<LiveModelsProvider>("Timeout, models were NOT generated.");
|
||||
_logger.Warn<LiveModelsProvider>("Timeout, models were NOT generated.");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ModelsGenerationError.Report("Failed to build Live models.", e);
|
||||
Current.Logger.Error<LiveModelsProvider>("Failed to generate models.", e);
|
||||
_modelGenerator.ReportError("Failed to build Live models.", e);
|
||||
_logger.Error<LiveModelsProvider>("Failed to generate models.", e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -97,38 +100,16 @@ namespace Umbraco.ModelsBuilder.Umbraco
|
||||
}
|
||||
}
|
||||
|
||||
private static void GenerateModels()
|
||||
private void GenerateModels()
|
||||
{
|
||||
var modelsDirectory = Config.ModelsDirectory;
|
||||
var modelsNamespace = Config.ModelsNamespace;
|
||||
|
||||
var bin = HostingEnvironment.MapPath("~/bin");
|
||||
var bin = IOHelper.MapPath("~/bin");
|
||||
if (bin == null)
|
||||
throw new PanicException("Panic: bin is null.");
|
||||
|
||||
// EnableDllModels will recycle the app domain - but this request will end properly
|
||||
ModelsBuilderBackOfficeController.GenerateModels(_umbracoServices, modelsDirectory, modelsNamespace);
|
||||
}
|
||||
_modelGenerator.GenerateModels();
|
||||
}
|
||||
|
||||
// have to do this because it's the only way to subscribe to EndRequest,
|
||||
// module is installed by assembly attribute at the top of this file
|
||||
public class LiveModelsProviderModule : IHttpModule
|
||||
{
|
||||
public void Init(HttpApplication app)
|
||||
{
|
||||
app.EndRequest += LiveModelsProvider.GenerateModelsIfRequested;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
// nothing
|
||||
}
|
||||
|
||||
public static void Install()
|
||||
{
|
||||
// always - don't read config in PreApplicationStartMethod
|
||||
HttpApplication.RegisterModule(typeof(LiveModelsProviderModule));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.Web;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.ModelsBuilder.Umbraco;
|
||||
|
||||
// will install only if configuration says it needs to be installed
|
||||
[assembly: PreApplicationStartMethod(typeof(LiveModelsProviderModule), "Install")]
|
||||
|
||||
namespace Umbraco.ModelsBuilder.Umbraco
|
||||
{
|
||||
// have to do this because it's the only way to subscribe to EndRequest,
|
||||
// module is installed by assembly attribute at the top of this file
|
||||
public class LiveModelsProviderModule : IHttpModule
|
||||
{
|
||||
private static LiveModelsProvider _liveModelsProvider;
|
||||
|
||||
public void Init(HttpApplication app)
|
||||
{
|
||||
app.EndRequest += App_EndRequest;
|
||||
}
|
||||
|
||||
private void App_EndRequest(object sender, EventArgs e)
|
||||
{
|
||||
// here we're using "Current." since we're in a module, it is possible in a round about way to inject into a module but for now we'll just use Current
|
||||
if (_liveModelsProvider == null)
|
||||
_liveModelsProvider = Current.Factory.GetInstance<LiveModelsProvider>();
|
||||
|
||||
if (_liveModelsProvider.IsEnabled)
|
||||
_liveModelsProvider.GenerateModelsIfRequested(sender, e);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
// nothing
|
||||
}
|
||||
|
||||
public static void Install()
|
||||
{
|
||||
// always - don't read config in PreApplicationStartMethod
|
||||
HttpApplication.RegisterModule(typeof(LiveModelsProviderModule));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ using Umbraco.ModelsBuilder.Building;
|
||||
|
||||
namespace Umbraco.ModelsBuilder.Umbraco
|
||||
{
|
||||
class HashHelper
|
||||
internal class ModelsBuilderHasher
|
||||
{
|
||||
public static string Hash(IEnumerable<TypeModel> typeModels)
|
||||
{
|
||||
@@ -6,11 +6,16 @@ using Umbraco.ModelsBuilder.Configuration;
|
||||
|
||||
namespace Umbraco.ModelsBuilder.Umbraco
|
||||
{
|
||||
internal static class ModelsGenerationError
|
||||
internal class ModelsGenerationError
|
||||
{
|
||||
private static Config Config => Current.Configs.ModelsBuilder();
|
||||
private readonly IModelsBuilderConfig _config;
|
||||
|
||||
public static void Clear()
|
||||
public ModelsGenerationError(IModelsBuilderConfig config)
|
||||
{
|
||||
_config = config;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
var errFile = GetErrFile();
|
||||
if (errFile == null) return;
|
||||
@@ -19,7 +24,7 @@ namespace Umbraco.ModelsBuilder.Umbraco
|
||||
File.Delete(errFile);
|
||||
}
|
||||
|
||||
public static void Report(string message, Exception e)
|
||||
public void Report(string message, Exception e)
|
||||
{
|
||||
var errFile = GetErrFile();
|
||||
if (errFile == null) return;
|
||||
@@ -35,7 +40,7 @@ namespace Umbraco.ModelsBuilder.Umbraco
|
||||
File.WriteAllText(errFile, sb.ToString());
|
||||
}
|
||||
|
||||
public static string GetLastError()
|
||||
public string GetLastError()
|
||||
{
|
||||
var errFile = GetErrFile();
|
||||
if (errFile == null) return null;
|
||||
@@ -50,9 +55,9 @@ namespace Umbraco.ModelsBuilder.Umbraco
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetErrFile()
|
||||
private string GetErrFile()
|
||||
{
|
||||
var modelsDirectory = Config.ModelsDirectory;
|
||||
var modelsDirectory = _config.ModelsDirectory;
|
||||
if (!Directory.Exists(modelsDirectory))
|
||||
return null;
|
||||
|
||||
|
||||
63
src/Umbraco.ModelsBuilder/Umbraco/ModelsGenerator.cs
Normal file
63
src/Umbraco.ModelsBuilder/Umbraco/ModelsGenerator.cs
Normal file
@@ -0,0 +1,63 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Web;
|
||||
using Umbraco.ModelsBuilder.Building;
|
||||
using Umbraco.ModelsBuilder.Configuration;
|
||||
using Umbraco.ModelsBuilder.Umbraco;
|
||||
|
||||
namespace Umbraco.ModelsBuilder.Umbraco
|
||||
{
|
||||
public class ModelsGenerator
|
||||
{
|
||||
private readonly UmbracoServices _umbracoService;
|
||||
private readonly IModelsBuilderConfig _config;
|
||||
private readonly ModelsGenerationError _errors;
|
||||
|
||||
public ModelsGenerator(UmbracoServices umbracoService, IModelsBuilderConfig config)
|
||||
{
|
||||
_umbracoService = umbracoService;
|
||||
_config = config;
|
||||
_errors = new ModelsGenerationError(config);
|
||||
}
|
||||
|
||||
internal void GenerateModels()
|
||||
{
|
||||
if (!Directory.Exists(_config.ModelsDirectory))
|
||||
Directory.CreateDirectory(_config.ModelsDirectory);
|
||||
|
||||
foreach (var file in Directory.GetFiles(_config.ModelsDirectory, "*.generated.cs"))
|
||||
File.Delete(file);
|
||||
|
||||
var typeModels = _umbracoService.GetAllTypes();
|
||||
|
||||
var builder = new TextBuilder(_config, typeModels);
|
||||
|
||||
foreach (var typeModel in builder.GetModelsToGenerate())
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
builder.Generate(sb, typeModel);
|
||||
var filename = Path.Combine(_config.ModelsDirectory, typeModel.ClrName + ".generated.cs");
|
||||
File.WriteAllText(filename, sb.ToString());
|
||||
}
|
||||
|
||||
// the idea was to calculate the current hash and to add it as an extra file to the compilation,
|
||||
// in order to be able to detect whether a DLL is consistent with an environment - however the
|
||||
// environment *might not* contain the local partial files, and thus it could be impossible to
|
||||
// calculate the hash. So... maybe that's not a good idea after all?
|
||||
/*
|
||||
var currentHash = HashHelper.Hash(ourFiles, typeModels);
|
||||
ourFiles["models.hash.cs"] = $@"using Umbraco.ModelsBuilder;
|
||||
[assembly:ModelsBuilderAssembly(SourceHash = ""{currentHash}"")]
|
||||
";
|
||||
*/
|
||||
|
||||
OutOfDateModelsStatus.Clear();
|
||||
}
|
||||
|
||||
internal void ClearErrors() => _errors.Clear();
|
||||
internal void ReportError(string message, Exception e) => _errors.Report(message, e);
|
||||
internal string GetLastError() => _errors.GetLastError();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,12 @@ namespace Umbraco.ModelsBuilder.Umbraco
|
||||
{
|
||||
public sealed class OutOfDateModelsStatus
|
||||
{
|
||||
private static Config Config => Current.Configs.ModelsBuilder();
|
||||
public OutOfDateModelsStatus()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private static ModelsBuilderConfig Config => Current.Configs.ModelsBuilder();
|
||||
|
||||
internal static void Install()
|
||||
{
|
||||
|
||||
@@ -42,13 +42,15 @@ namespace Umbraco.ModelsBuilder.Umbraco
|
||||
private const string ProjVirt = "~/App_Data/Models/all.generated.cs";
|
||||
private static readonly string[] OurFiles = { "models.hash", "models.generated.cs", "all.generated.cs", "all.dll.path", "models.err" };
|
||||
|
||||
private readonly Config _config;
|
||||
private readonly IModelsBuilderConfig _config;
|
||||
private readonly ModelsGenerator _modelGenerator;
|
||||
|
||||
public PureLiveModelFactory(Lazy<UmbracoServices> umbracoServices, IProfilingLogger logger, Config config)
|
||||
public PureLiveModelFactory(Lazy<UmbracoServices> umbracoServices, IProfilingLogger logger, IModelsBuilderConfig config, ModelsGenerator modelGenerator)
|
||||
{
|
||||
_umbracoServices = umbracoServices;
|
||||
_logger = logger;
|
||||
_config = config;
|
||||
_modelGenerator = modelGenerator;
|
||||
_ver = 1; // zero is for when we had no version
|
||||
_skipver = -1; // nothing to skip
|
||||
|
||||
@@ -292,7 +294,7 @@ namespace Umbraco.ModelsBuilder.Umbraco
|
||||
|
||||
var types = assembly.ExportedTypes.Where(x => x.Inherits<PublishedContentModel>() || x.Inherits<PublishedElementModel>());
|
||||
_infos = RegisterModels(types);
|
||||
ModelsGenerationError.Clear();
|
||||
_modelGenerator.ClearErrors();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -300,7 +302,7 @@ namespace Umbraco.ModelsBuilder.Umbraco
|
||||
{
|
||||
_logger.Error<PureLiveModelFactory>("Failed to build models.", e);
|
||||
_logger.Warn<PureLiveModelFactory>("Running without models."); // be explicit
|
||||
ModelsGenerationError.Report("Failed to build PureLive models.", e);
|
||||
_modelGenerator.ReportError("Failed to build PureLive models.", e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -333,7 +335,7 @@ namespace Umbraco.ModelsBuilder.Umbraco
|
||||
Directory.CreateDirectory(modelsDirectory);
|
||||
|
||||
var typeModels = UmbracoServices.GetAllTypes();
|
||||
var currentHash = HashHelper.Hash(typeModels);
|
||||
var currentHash = ModelsBuilderHasher.Hash(typeModels);
|
||||
var modelsHashFile = Path.Combine(modelsDirectory, "models.hash");
|
||||
var modelsSrcFile = Path.Combine(modelsDirectory, "models.generated.cs");
|
||||
var projFile = Path.Combine(modelsDirectory, "all.generated.cs");
|
||||
@@ -557,7 +559,7 @@ namespace Umbraco.ModelsBuilder.Umbraco
|
||||
foreach (var file in Directory.GetFiles(modelsDirectory, "*.generated.cs"))
|
||||
File.Delete(file);
|
||||
|
||||
var builder = new TextBuilder(typeModels, _config.ModelsNamespace);
|
||||
var builder = new TextBuilder(_config, typeModels);
|
||||
|
||||
var codeBuilder = new StringBuilder();
|
||||
builder.Generate(codeBuilder, builder.GetModelsToGenerate());
|
||||
|
||||
@@ -28,8 +28,6 @@ namespace Umbraco.ModelsBuilder.Umbraco
|
||||
_publishedContentTypeFactory = publishedContentTypeFactory;
|
||||
}
|
||||
|
||||
private static Config Config => Current.Configs.ModelsBuilder();
|
||||
|
||||
#region Services
|
||||
|
||||
public IList<TypeModel> GetAllTypes()
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace Umbraco.ModelsBuilder.Validation
|
||||
where TModel: ContentTypeSave<TProperty>
|
||||
where TProperty: PropertyTypeBasic
|
||||
{
|
||||
private static Config Config => Current.Configs.ModelsBuilder();
|
||||
private static ModelsBuilderConfig Config => Current.Configs.ModelsBuilder();
|
||||
|
||||
protected override IEnumerable<ValidationResult> Validate(TModel model)
|
||||
{
|
||||
|
||||
443
src/Umbraco.Tests/ModelsBuilder/BuilderTests.cs
Normal file
443
src/Umbraco.Tests/ModelsBuilder/BuilderTests.cs
Normal file
@@ -0,0 +1,443 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
using Umbraco.ModelsBuilder.Api;
|
||||
using Umbraco.ModelsBuilder.Building;
|
||||
using Umbraco.ModelsBuilder.Configuration;
|
||||
|
||||
namespace Umbraco.ModelsBuilder.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class BuilderTests
|
||||
{
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
Current.Reset();
|
||||
Current.UnlockConfigs();
|
||||
Current.Configs.Add(() => new ModelsBuilderConfig());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateSimpleType()
|
||||
{
|
||||
// Umbraco returns nice, pascal-cased names
|
||||
|
||||
var type1 = new TypeModel
|
||||
{
|
||||
Id = 1,
|
||||
Alias = "type1",
|
||||
ClrName = "Type1",
|
||||
ParentId = 0,
|
||||
BaseType = null,
|
||||
ItemType = TypeModel.ItemTypes.Content,
|
||||
};
|
||||
type1.Properties.Add(new PropertyModel
|
||||
{
|
||||
Alias = "prop1",
|
||||
ClrName = "Prop1",
|
||||
ModelClrType = typeof(string),
|
||||
});
|
||||
|
||||
var types = new[] { type1 };
|
||||
|
||||
var code = new Dictionary<string, string>
|
||||
{
|
||||
};
|
||||
|
||||
var builder = new TextBuilder(Mock.Of<IModelsBuilderConfig>(), types);
|
||||
var btypes = builder.TypeModels;
|
||||
|
||||
var sb = new StringBuilder();
|
||||
builder.Generate(sb, builder.GetModelsToGenerate().First());
|
||||
var gen = sb.ToString();
|
||||
|
||||
var version = ApiVersion.Current.Version;
|
||||
var expected = @"//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
//
|
||||
// Umbraco.ModelsBuilder v" + version + @"
|
||||
//
|
||||
// Changes to this file will be lost if the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq.Expressions;
|
||||
using System.Web;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
using Umbraco.Web;
|
||||
using Umbraco.ModelsBuilder;
|
||||
using Umbraco.ModelsBuilder.Umbraco;
|
||||
|
||||
namespace Umbraco.Web.PublishedModels
|
||||
{
|
||||
[PublishedModel(""type1"")]
|
||||
public partial class Type1 : PublishedContentModel
|
||||
{
|
||||
// helpers
|
||||
#pragma warning disable 0109 // new is redundant
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute(""Umbraco.ModelsBuilder"", """ + version + @""")]
|
||||
public new const string ModelTypeAlias = ""type1"";
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute(""Umbraco.ModelsBuilder"", """ + version + @""")]
|
||||
public new const PublishedItemType ModelItemType = PublishedItemType.Content;
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute(""Umbraco.ModelsBuilder"", """ + version + @""")]
|
||||
public new static IPublishedContentType GetModelContentType()
|
||||
=> PublishedModelUtility.GetModelContentType(ModelItemType, ModelTypeAlias);
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute(""Umbraco.ModelsBuilder"", """ + version + @""")]
|
||||
public static IPublishedPropertyType GetModelPropertyType<TValue>(Expression<Func<Type1, TValue>> selector)
|
||||
=> PublishedModelUtility.GetModelPropertyType(GetModelContentType(), selector);
|
||||
#pragma warning restore 0109
|
||||
|
||||
// ctor
|
||||
public Type1(IPublishedContent content)
|
||||
: base(content)
|
||||
{ }
|
||||
|
||||
// properties
|
||||
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute(""Umbraco.ModelsBuilder"", """ + version + @""")]
|
||||
[ImplementPropertyType(""prop1"")]
|
||||
public string Prop1 => this.Value<string>(""prop1"");
|
||||
}
|
||||
}
|
||||
";
|
||||
Console.WriteLine(gen);
|
||||
Assert.AreEqual(expected.ClearLf(), gen);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateSimpleType_Ambiguous_Issue()
|
||||
{
|
||||
// Umbraco returns nice, pascal-cased names
|
||||
|
||||
var type1 = new TypeModel
|
||||
{
|
||||
Id = 1,
|
||||
Alias = "type1",
|
||||
ClrName = "Type1",
|
||||
ParentId = 0,
|
||||
BaseType = null,
|
||||
ItemType = TypeModel.ItemTypes.Content,
|
||||
};
|
||||
type1.Properties.Add(new PropertyModel
|
||||
{
|
||||
Alias = "foo",
|
||||
ClrName = "Foo",
|
||||
ModelClrType = typeof(IEnumerable<>).MakeGenericType(ModelType.For("foo")),
|
||||
});
|
||||
|
||||
var type2 = new TypeModel
|
||||
{
|
||||
Id = 2,
|
||||
Alias = "foo",
|
||||
ClrName = "Foo",
|
||||
ParentId = 0,
|
||||
BaseType = null,
|
||||
ItemType = TypeModel.ItemTypes.Element,
|
||||
};
|
||||
|
||||
var types = new[] { type1, type2 };
|
||||
|
||||
var code = new Dictionary<string, string>
|
||||
{
|
||||
{ "code", @"
|
||||
namespace Umbraco.Web.PublishedModels
|
||||
{
|
||||
public partial class Foo
|
||||
{
|
||||
}
|
||||
}
|
||||
" }
|
||||
};
|
||||
|
||||
var builder = new TextBuilder(Mock.Of<IModelsBuilderConfig>(), types);
|
||||
var btypes = builder.TypeModels;
|
||||
|
||||
builder.ModelsNamespace = "Umbraco.Web.PublishedModels";
|
||||
|
||||
var sb1 = new StringBuilder();
|
||||
builder.Generate(sb1, builder.GetModelsToGenerate().Skip(1).First());
|
||||
var gen1 = sb1.ToString();
|
||||
Console.WriteLine(gen1);
|
||||
|
||||
var sb = new StringBuilder();
|
||||
builder.Generate(sb, builder.GetModelsToGenerate().First());
|
||||
var gen = sb.ToString();
|
||||
|
||||
var version = ApiVersion.Current.Version;
|
||||
var expected = @"//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
//
|
||||
// Umbraco.ModelsBuilder v" + version + @"
|
||||
//
|
||||
// Changes to this file will be lost if the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq.Expressions;
|
||||
using System.Web;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
using Umbraco.Web;
|
||||
using Umbraco.ModelsBuilder;
|
||||
using Umbraco.ModelsBuilder.Umbraco;
|
||||
|
||||
namespace Umbraco.Web.PublishedModels
|
||||
{
|
||||
[PublishedModel(""type1"")]
|
||||
public partial class Type1 : PublishedContentModel
|
||||
{
|
||||
// helpers
|
||||
#pragma warning disable 0109 // new is redundant
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute(""Umbraco.ModelsBuilder"", """ + version + @""")]
|
||||
public new const string ModelTypeAlias = ""type1"";
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute(""Umbraco.ModelsBuilder"", """ + version + @""")]
|
||||
public new const PublishedItemType ModelItemType = PublishedItemType.Content;
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute(""Umbraco.ModelsBuilder"", """ + version + @""")]
|
||||
public new static IPublishedContentType GetModelContentType()
|
||||
=> PublishedModelUtility.GetModelContentType(ModelItemType, ModelTypeAlias);
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute(""Umbraco.ModelsBuilder"", """ + version + @""")]
|
||||
public static IPublishedPropertyType GetModelPropertyType<TValue>(Expression<Func<Type1, TValue>> selector)
|
||||
=> PublishedModelUtility.GetModelPropertyType(GetModelContentType(), selector);
|
||||
#pragma warning restore 0109
|
||||
|
||||
// ctor
|
||||
public Type1(IPublishedContent content)
|
||||
: base(content)
|
||||
{ }
|
||||
|
||||
// properties
|
||||
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute(""Umbraco.ModelsBuilder"", """ + version + @""")]
|
||||
[ImplementPropertyType(""foo"")]
|
||||
public global::System.Collections.Generic.IEnumerable<global::Foo> Foo => this.Value<global::System.Collections.Generic.IEnumerable<global::Foo>>(""foo"");
|
||||
}
|
||||
}
|
||||
";
|
||||
Console.WriteLine(gen);
|
||||
Assert.AreEqual(expected.ClearLf(), gen);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateAmbiguous()
|
||||
{
|
||||
// NOTE: since
|
||||
|
||||
var type1 = new TypeModel
|
||||
{
|
||||
Id = 1,
|
||||
Alias = "type1",
|
||||
ClrName = "Type1",
|
||||
ParentId = 0,
|
||||
BaseType = null,
|
||||
ItemType = TypeModel.ItemTypes.Content,
|
||||
IsMixin = true,
|
||||
};
|
||||
type1.Properties.Add(new PropertyModel
|
||||
{
|
||||
Alias = "prop1",
|
||||
ClrName = "Prop1",
|
||||
ModelClrType = typeof(IPublishedContent),
|
||||
});
|
||||
type1.Properties.Add(new PropertyModel
|
||||
{
|
||||
Alias = "prop2",
|
||||
ClrName = "Prop2",
|
||||
ModelClrType = typeof(System.Text.StringBuilder),
|
||||
});
|
||||
type1.Properties.Add(new PropertyModel
|
||||
{
|
||||
Alias = "prop3",
|
||||
ClrName = "Prop3",
|
||||
ModelClrType = typeof(global::Umbraco.Core.IO.FileSecurityException),
|
||||
});
|
||||
var types = new[] { type1 };
|
||||
|
||||
var code = new Dictionary<string, string>
|
||||
{
|
||||
};
|
||||
|
||||
var builder = new TextBuilder(Mock.Of<IModelsBuilderConfig>(), types);
|
||||
builder.ModelsNamespace = "Umbraco.ModelsBuilder.Models"; // forces conflict with Umbraco.ModelsBuilder.Umbraco
|
||||
var btypes = builder.TypeModels;
|
||||
|
||||
var sb = new StringBuilder();
|
||||
foreach (var model in builder.GetModelsToGenerate())
|
||||
builder.Generate(sb, model);
|
||||
var gen = sb.ToString();
|
||||
|
||||
Console.WriteLine(gen);
|
||||
|
||||
Assert.IsTrue(gen.Contains(" global::Umbraco.Core.Models.PublishedContent.IPublishedContent Prop1"));
|
||||
Assert.IsTrue(gen.Contains(" global::System.Text.StringBuilder Prop2"));
|
||||
Assert.IsTrue(gen.Contains(" global::Umbraco.Core.IO.FileSecurityException Prop3"));
|
||||
}
|
||||
|
||||
[TestCase("int", typeof(int))]
|
||||
[TestCase("global::System.Collections.Generic.IEnumerable<int>", typeof(IEnumerable<int>))]
|
||||
[TestCase("global::Umbraco.ModelsBuilder.Tests.BuilderTestsClass1", typeof(BuilderTestsClass1))]
|
||||
[TestCase("global::Umbraco.ModelsBuilder.Tests.BuilderTests.Class1", typeof(Class1))]
|
||||
public void WriteClrType(string expected, Type input)
|
||||
{
|
||||
// note - these assertions differ from the original tests in MB because in the embedded version, the result of Builder.IsAmbiguousSymbol is always true
|
||||
// which means global:: syntax will be applied to most things
|
||||
|
||||
var builder = new TextBuilder();
|
||||
builder.ModelsNamespaceForTests = "ModelsNamespace";
|
||||
var sb = new StringBuilder();
|
||||
builder.WriteClrType(sb, input);
|
||||
Assert.AreEqual(expected, sb.ToString());
|
||||
}
|
||||
|
||||
[TestCase("int", typeof(int))]
|
||||
[TestCase("global::System.Collections.Generic.IEnumerable<int>", typeof(IEnumerable<int>))]
|
||||
[TestCase("global::Umbraco.ModelsBuilder.Tests.BuilderTestsClass1", typeof(BuilderTestsClass1))]
|
||||
[TestCase("global::Umbraco.ModelsBuilder.Tests.BuilderTests.Class1", typeof(Class1))]
|
||||
public void WriteClrTypeUsing(string expected, Type input)
|
||||
{
|
||||
// note - these assertions differ from the original tests in MB because in the embedded version, the result of Builder.IsAmbiguousSymbol is always true
|
||||
// which means global:: syntax will be applied to most things
|
||||
|
||||
var builder = new TextBuilder();
|
||||
builder.Using.Add("Umbraco.ModelsBuilder.Tests");
|
||||
builder.ModelsNamespaceForTests = "ModelsNamespace";
|
||||
var sb = new StringBuilder();
|
||||
builder.WriteClrType(sb, input);
|
||||
Assert.AreEqual(expected, sb.ToString());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WriteClrType_WithUsing()
|
||||
{
|
||||
var builder = new TextBuilder();
|
||||
builder.Using.Add("System.Text");
|
||||
builder.ModelsNamespaceForTests = "Umbraco.ModelsBuilder.Tests.Models";
|
||||
var sb = new StringBuilder();
|
||||
builder.WriteClrType(sb, typeof(StringBuilder));
|
||||
|
||||
// note - these assertions differ from the original tests in MB because in the embedded version, the result of Builder.IsAmbiguousSymbol is always true
|
||||
// which means global:: syntax will be applied to most things
|
||||
|
||||
Assert.AreEqual("global::System.Text.StringBuilder", sb.ToString());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WriteClrTypeAnother_WithoutUsing()
|
||||
{
|
||||
var builder = new TextBuilder();
|
||||
builder.ModelsNamespaceForTests = "Umbraco.ModelsBuilder.Tests.Models";
|
||||
var sb = new StringBuilder();
|
||||
builder.WriteClrType(sb, typeof(StringBuilder));
|
||||
Assert.AreEqual("global::System.Text.StringBuilder", sb.ToString());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WriteClrType_Ambiguous1()
|
||||
{
|
||||
var builder = new TextBuilder();
|
||||
builder.Using.Add("System.Text");
|
||||
builder.Using.Add("Umbraco.ModelsBuilder.Tests");
|
||||
builder.ModelsNamespaceForTests = "SomeRandomNamespace";
|
||||
var sb = new StringBuilder();
|
||||
builder.WriteClrType(sb, typeof(System.Text.ASCIIEncoding));
|
||||
|
||||
// note - these assertions differ from the original tests in MB because in the embedded version, the result of Builder.IsAmbiguousSymbol is always true
|
||||
// which means global:: syntax will be applied to most things
|
||||
|
||||
Assert.AreEqual("global::System.Text.ASCIIEncoding", sb.ToString());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WriteClrType_Ambiguous()
|
||||
{
|
||||
var builder = new TextBuilder();
|
||||
builder.Using.Add("System.Text");
|
||||
builder.Using.Add("Umbraco.ModelsBuilder.Tests");
|
||||
builder.ModelsNamespaceForTests = "SomeBorkedNamespace";
|
||||
var sb = new StringBuilder();
|
||||
builder.WriteClrType(sb, typeof(System.Text.ASCIIEncoding));
|
||||
|
||||
// note - these assertions differ from the original tests in MB because in the embedded version, the result of Builder.IsAmbiguousSymbol is always true
|
||||
// which means global:: syntax will be applied to most things
|
||||
|
||||
Assert.AreEqual("global::System.Text.ASCIIEncoding", sb.ToString());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WriteClrType_Ambiguous2()
|
||||
{
|
||||
var builder = new TextBuilder();
|
||||
builder.Using.Add("System.Text");
|
||||
builder.Using.Add("Umbraco.ModelsBuilder.Tests");
|
||||
builder.ModelsNamespaceForTests = "SomeRandomNamespace";
|
||||
var sb = new StringBuilder();
|
||||
builder.WriteClrType(sb, typeof(ASCIIEncoding));
|
||||
|
||||
// note - these assertions differ from the original tests in MB because in the embedded version, the result of Builder.IsAmbiguousSymbol is always true
|
||||
// which means global:: syntax will be applied to most things
|
||||
|
||||
Assert.AreEqual("global::Umbraco.ModelsBuilder.Tests.ASCIIEncoding", sb.ToString());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WriteClrType_AmbiguousNot()
|
||||
{
|
||||
var builder = new TextBuilder();
|
||||
builder.Using.Add("System.Text");
|
||||
builder.Using.Add("Umbraco.ModelsBuilder.Tests");
|
||||
builder.ModelsNamespaceForTests = "Umbraco.ModelsBuilder.Tests.Models";
|
||||
var sb = new StringBuilder();
|
||||
builder.WriteClrType(sb, typeof(ASCIIEncoding));
|
||||
|
||||
// note - these assertions differ from the original tests in MB because in the embedded version, the result of Builder.IsAmbiguousSymbol is always true
|
||||
// which means global:: syntax will be applied to most things
|
||||
|
||||
Assert.AreEqual("global::Umbraco.ModelsBuilder.Tests.ASCIIEncoding", sb.ToString());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WriteClrType_AmbiguousWithNested()
|
||||
{
|
||||
var builder = new TextBuilder();
|
||||
builder.Using.Add("System.Text");
|
||||
builder.Using.Add("Umbraco.ModelsBuilder.Tests");
|
||||
builder.ModelsNamespaceForTests = "SomeRandomNamespace";
|
||||
var sb = new StringBuilder();
|
||||
builder.WriteClrType(sb, typeof(ASCIIEncoding.Nested));
|
||||
|
||||
// note - these assertions differ from the original tests in MB because in the embedded version, the result of Builder.IsAmbiguousSymbol is always true
|
||||
// which means global:: syntax will be applied to most things
|
||||
|
||||
Assert.AreEqual("global::Umbraco.ModelsBuilder.Tests.ASCIIEncoding.Nested", sb.ToString());
|
||||
}
|
||||
|
||||
public class Class1 { }
|
||||
}
|
||||
|
||||
// make it public to be ambiguous (see above)
|
||||
public class ASCIIEncoding
|
||||
{
|
||||
// can we handle nested types?
|
||||
public class Nested { }
|
||||
}
|
||||
|
||||
class BuilderTestsClass1 {}
|
||||
}
|
||||
|
||||
namespace SomeBorkedNamespace
|
||||
{
|
||||
public class System { }
|
||||
}
|
||||
49
src/Umbraco.Tests/ModelsBuilder/ConfigTests.cs
Normal file
49
src/Umbraco.Tests/ModelsBuilder/ConfigTests.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
using System.Configuration;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.ModelsBuilder.Configuration;
|
||||
|
||||
namespace Umbraco.ModelsBuilder.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class ModelsBuilderConfigTests
|
||||
{
|
||||
[Test]
|
||||
public void Test1()
|
||||
{
|
||||
var config = new ModelsBuilderConfig(modelsNamespace: "test1");
|
||||
Assert.AreEqual("test1", config.ModelsNamespace);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Test2()
|
||||
{
|
||||
var config = new ModelsBuilderConfig(modelsNamespace: "test2");
|
||||
Assert.AreEqual("test2", config.ModelsNamespace);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DefaultModelsNamespace()
|
||||
{
|
||||
var config = new ModelsBuilderConfig();
|
||||
Assert.AreEqual(ModelsBuilderConfig.DefaultModelsNamespace, config.ModelsNamespace);
|
||||
}
|
||||
|
||||
[TestCase("c:/path/to/root", "~/dir/models", false, "c:\\path\\to\\root\\dir\\models")]
|
||||
[TestCase("c:/path/to/root", "~/../../dir/models", true, "c:\\path\\dir\\models")]
|
||||
[TestCase("c:/path/to/root", "c:/another/path/to/elsewhere", true, "c:\\another\\path\\to\\elsewhere")]
|
||||
public void GetModelsDirectoryTests(string root, string config, bool acceptUnsafe, string expected)
|
||||
{
|
||||
Assert.AreEqual(expected, ModelsBuilderConfig.GetModelsDirectory(root, config, acceptUnsafe));
|
||||
}
|
||||
|
||||
[TestCase("c:/path/to/root", "~/../../dir/models", false)]
|
||||
[TestCase("c:/path/to/root", "c:/another/path/to/elsewhere", false)]
|
||||
public void GetModelsDirectoryThrowsTests(string root, string config, bool acceptUnsafe)
|
||||
{
|
||||
Assert.Throws<ConfigurationErrorsException>(() =>
|
||||
{
|
||||
var modelsDirectory = ModelsBuilderConfig.GetModelsDirectory(root, config, acceptUnsafe);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
16
src/Umbraco.Tests/ModelsBuilder/StringExtensions.cs
Normal file
16
src/Umbraco.Tests/ModelsBuilder/StringExtensions.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Umbraco.ModelsBuilder.Tests
|
||||
{
|
||||
public static class StringExtensions
|
||||
{
|
||||
public static string ClearLf(this string s)
|
||||
{
|
||||
return s.Replace("\r", "");
|
||||
}
|
||||
}
|
||||
}
|
||||
63
src/Umbraco.Tests/ModelsBuilder/UmbracoApplicationTests.cs
Normal file
63
src/Umbraco.Tests/ModelsBuilder/UmbracoApplicationTests.cs
Normal file
@@ -0,0 +1,63 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.ModelsBuilder.Building;
|
||||
using Umbraco.ModelsBuilder.Umbraco;
|
||||
|
||||
namespace Umbraco.ModelsBuilder.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class UmbracoApplicationTests
|
||||
{
|
||||
//[Test]
|
||||
//public void Test()
|
||||
//{
|
||||
// // start and terminate
|
||||
// using (var app = Application.GetApplication(TestOptions.ConnectionString, TestOptions.DatabaseProvider))
|
||||
// { }
|
||||
|
||||
// // start and terminate
|
||||
// using (var app = Application.GetApplication(TestOptions.ConnectionString, TestOptions.DatabaseProvider))
|
||||
// { }
|
||||
|
||||
// // start, use and terminate
|
||||
// using (var app = Application.GetApplication(TestOptions.ConnectionString, TestOptions.DatabaseProvider))
|
||||
// {
|
||||
// var types = app.GetContentTypes();
|
||||
// }
|
||||
//}
|
||||
|
||||
[Test]
|
||||
public void ThrowsOnDuplicateAliases()
|
||||
{
|
||||
var typeModels = new List<TypeModel>
|
||||
{
|
||||
new TypeModel { ItemType = TypeModel.ItemTypes.Content, Alias = "content1" },
|
||||
new TypeModel { ItemType = TypeModel.ItemTypes.Content, Alias = "content2" },
|
||||
new TypeModel { ItemType = TypeModel.ItemTypes.Media, Alias = "media1" },
|
||||
new TypeModel { ItemType = TypeModel.ItemTypes.Media, Alias = "media2" },
|
||||
new TypeModel { ItemType = TypeModel.ItemTypes.Member, Alias = "member1" },
|
||||
new TypeModel { ItemType = TypeModel.ItemTypes.Member, Alias = "member2" },
|
||||
};
|
||||
|
||||
Assert.AreEqual(6, UmbracoServices.EnsureDistinctAliases(typeModels).Count);
|
||||
|
||||
typeModels.Add(new TypeModel { ItemType = TypeModel.ItemTypes.Media, Alias = "content1" });
|
||||
|
||||
try
|
||||
{
|
||||
UmbracoServices.EnsureDistinctAliases(typeModels);
|
||||
}
|
||||
catch (NotSupportedException e)
|
||||
{
|
||||
Console.WriteLine(e.Message);
|
||||
return;
|
||||
}
|
||||
|
||||
Assert.Fail("Expected NotSupportedException.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -134,6 +134,10 @@
|
||||
<Compile Include="Mapping\MappingTests.cs" />
|
||||
<Compile Include="Migrations\MigrationPlanTests.cs" />
|
||||
<Compile Include="Migrations\MigrationTests.cs" />
|
||||
<Compile Include="ModelsBuilder\BuilderTests.cs" />
|
||||
<Compile Include="ModelsBuilder\ConfigTests.cs" />
|
||||
<Compile Include="ModelsBuilder\StringExtensions.cs" />
|
||||
<Compile Include="ModelsBuilder\UmbracoApplicationTests.cs" />
|
||||
<Compile Include="Models\ContentScheduleTests.cs" />
|
||||
<Compile Include="Models\CultureImpactTests.cs" />
|
||||
<Compile Include="Models\PathValidationTests.cs" />
|
||||
@@ -549,6 +553,10 @@
|
||||
<Project>{31785BC3-256C-4613-B2F5-A1B0BDDED8C1}</Project>
|
||||
<Name>Umbraco.Core</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Umbraco.ModelsBuilder\Umbraco.ModelsBuilder.csproj">
|
||||
<Project>{52ac0ba8-a60e-4e36-897b-e8b97a54ed1c}</Project>
|
||||
<Name>Umbraco.ModelsBuilder</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Umbraco.Web\Umbraco.Web.csproj">
|
||||
<Project>{651E1350-91B6-44B7-BD60-7207006D7003}</Project>
|
||||
<Name>Umbraco.Web</Name>
|
||||
|
||||
Reference in New Issue
Block a user