From dabafcc972975d6cf0c4123667564c5e824735be Mon Sep 17 00:00:00 2001 From: hartvig Date: Wed, 8 Dec 2010 07:09:45 +0000 Subject: [PATCH] MacroEngine massage [TFS Changeset #81621] --- umbraco.Juno/Properties/AssemblyInfo.cs | 36 ++++ umbraco.Juno/umbraco.Juno.csproj | 58 +++++ umbraco.Juno/umbraco.Juno.csproj.vspscc | 10 + .../DLRScriptingEngine.cs | 57 +++++ umbraco.MacroEngines.Juno/DynamicNode.cs | 82 ++++++++ .../Properties/AssemblyInfo.cs | 36 ++++ .../Razor/CSharpRazorProvider.cs | 33 +++ .../Razor/IRazorProvider.cs | 26 +++ umbraco.MacroEngines.Juno/Razor/ITemplate.cs | 58 +++++ umbraco.MacroEngines.Juno/Razor/Razor.cs | 87 ++++++++ .../Razor/RazorCompiler.cs | 108 ++++++++++ .../Razor/TemplateBase.cs | 146 +++++++++++++ .../Razor/TemplateException.cs | 37 ++++ .../Razor/VBRazorProvider.cs | 33 +++ umbraco.MacroEngines.Juno/RazorEngine.cs | 74 +++++++ .../Scripting/MacroScript.cs | 65 ++++++ .../Scripting/ScriptEngine.cs | 199 ++++++++++++++++++ .../umbraco.MacroEngines.csproj | 96 +++++++++ umbraco.MacroEngines/DLRScriptingEngine.cs | 6 +- umbraco.MacroEngines/Scripting/MacroScript.cs | 2 +- .../Scripting/ScriptEngine.cs | 2 +- ...roj => umbraco.MacroEngines.Legacy.csproj} | 6 +- umbraco.sln | 9 +- 23 files changed, 1255 insertions(+), 11 deletions(-) create mode 100644 umbraco.Juno/Properties/AssemblyInfo.cs create mode 100644 umbraco.Juno/umbraco.Juno.csproj create mode 100644 umbraco.Juno/umbraco.Juno.csproj.vspscc create mode 100644 umbraco.MacroEngines.Juno/DLRScriptingEngine.cs create mode 100644 umbraco.MacroEngines.Juno/DynamicNode.cs create mode 100644 umbraco.MacroEngines.Juno/Properties/AssemblyInfo.cs create mode 100644 umbraco.MacroEngines.Juno/Razor/CSharpRazorProvider.cs create mode 100644 umbraco.MacroEngines.Juno/Razor/IRazorProvider.cs create mode 100644 umbraco.MacroEngines.Juno/Razor/ITemplate.cs create mode 100644 umbraco.MacroEngines.Juno/Razor/Razor.cs create mode 100644 umbraco.MacroEngines.Juno/Razor/RazorCompiler.cs create mode 100644 umbraco.MacroEngines.Juno/Razor/TemplateBase.cs create mode 100644 umbraco.MacroEngines.Juno/Razor/TemplateException.cs create mode 100644 umbraco.MacroEngines.Juno/Razor/VBRazorProvider.cs create mode 100644 umbraco.MacroEngines.Juno/RazorEngine.cs create mode 100644 umbraco.MacroEngines.Juno/Scripting/MacroScript.cs create mode 100644 umbraco.MacroEngines.Juno/Scripting/ScriptEngine.cs create mode 100644 umbraco.MacroEngines.Juno/umbraco.MacroEngines.csproj rename umbraco.MacroEngines/{umbraco.MacroEngines.csproj => umbraco.MacroEngines.Legacy.csproj} (93%) diff --git a/umbraco.Juno/Properties/AssemblyInfo.cs b/umbraco.Juno/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..d5b59a2a3d --- /dev/null +++ b/umbraco.Juno/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("umbraco.Juno")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("umbraco.Juno")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2010")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("6a24821f-2031-4e6b-af37-c045c9de9ce3")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/umbraco.Juno/umbraco.Juno.csproj b/umbraco.Juno/umbraco.Juno.csproj new file mode 100644 index 0000000000..015aca1f88 --- /dev/null +++ b/umbraco.Juno/umbraco.Juno.csproj @@ -0,0 +1,58 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {6C9A6403-6457-4989-BF20-A575535B89AF} + Library + Properties + umbraco.Juno + umbraco.Juno + v4.0 + 512 + SAK + SAK + SAK + SAK + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/umbraco.Juno/umbraco.Juno.csproj.vspscc b/umbraco.Juno/umbraco.Juno.csproj.vspscc new file mode 100644 index 0000000000..feffdecaa4 --- /dev/null +++ b/umbraco.Juno/umbraco.Juno.csproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" +} diff --git a/umbraco.MacroEngines.Juno/DLRScriptingEngine.cs b/umbraco.MacroEngines.Juno/DLRScriptingEngine.cs new file mode 100644 index 0000000000..37c3acb2d2 --- /dev/null +++ b/umbraco.MacroEngines.Juno/DLRScriptingEngine.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using umbraco.cms.businesslogic.macro; +using umbraco.interfaces; +using umbraco.IO; +using umbraco.MacroEngines.Scripting; + +namespace umbraco.MacroEngines +{ + public class DLRScriptingEngine : IMacroEngine + { + #region IMacroEngine Members + + public string Name + { + get { return "Umbraco DLR Macro Engine"; } + } + + public List SupportedExtensions + { + get + { + var exts = new List {"py", "rb"}; + return exts; + } + } + + public Dictionary SupportedProperties + { + get { throw new NotImplementedException(); } + } + + + public bool Validate(string code, INode currentPage, out string errorMessage) + { + throw new NotImplementedException(); + } + + public string Execute(MacroModel macro, INode currentPage) + { + string fileEnding = macro.ScriptName.Substring(macro.ScriptName.LastIndexOf('.')).Trim('.'); + + MacroScriptEngine mse = MacroScriptEngine.LoadEngineByFileExtension(fileEnding); + + var vars = new SortedDictionary {{"currentPage", currentPage}}; + foreach (MacroPropertyModel prop in macro.Properties) + { + vars.Add(prop.Key, prop.Value); + } + mse.ScriptVariables = vars; + + return mse.ExecuteFile(IOHelper.MapPath(SystemDirectories.Python + "/" + macro.ScriptName)); + } + + #endregion + } +} \ No newline at end of file diff --git a/umbraco.MacroEngines.Juno/DynamicNode.cs b/umbraco.MacroEngines.Juno/DynamicNode.cs new file mode 100644 index 0000000000..df4c0fb6d9 --- /dev/null +++ b/umbraco.MacroEngines.Juno/DynamicNode.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using System.Dynamic; +using System.Linq; +using System.Text; +using umbraco.interfaces; +using umbraco.presentation.nodeFactory; + +namespace umbraco.MacroEngines +{ + public class DynamicNode : DynamicObject + { + private INode n; + public DynamicNode(INode n) + { + this.n = n; + } + + public List GetChildrenAsList + { + get + { + List nodes = new List(); + foreach(Node nn in n.ChildrenAsList) + nodes.Add(new DynamicNode(nn)); + + return nodes; + } + } + + public override bool TryGetMember(GetMemberBinder binder, out object result) + { + + var name = binder.Name; + + if (name == "ChildrenAsList" || name == "Children") + { + result = GetChildrenAsList; + return true; + } else if (name == "Parent") + { + result = new DynamicNode(n.Parent); + return true; + } + + var data = n.GetProperty(name); + // check for nicer support of Pascal Casing EVEN if alias is camelCasing: + if (data == null && name.Substring(0,1).ToUpper() == name.Substring(0,1)) + { + data = n.GetProperty(name.Substring(0, 1).ToLower() + name.Substring((1))); + } + + + if (data != null) + { + result = data.Value; + return true; + } else + { + try + { + result = n.GetType().InvokeMember(binder.Name, + System.Reflection.BindingFlags.GetProperty | + System.Reflection.BindingFlags.Instance | + System.Reflection.BindingFlags.Public | + System.Reflection.BindingFlags.NonPublic, + null, + n, + null); + return true; + } catch + { + result = ""; + return false; + } + } + + + return base.TryGetMember(binder, out result); + } + } +} diff --git a/umbraco.MacroEngines.Juno/Properties/AssemblyInfo.cs b/umbraco.MacroEngines.Juno/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..142b376615 --- /dev/null +++ b/umbraco.MacroEngines.Juno/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("umbraco.MacroEngines")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("umbraco.MacroEngines")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2010")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("207a5ae9-5f35-4dec-a649-d3cf4d0efbd9")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/umbraco.MacroEngines.Juno/Razor/CSharpRazorProvider.cs b/umbraco.MacroEngines.Juno/Razor/CSharpRazorProvider.cs new file mode 100644 index 0000000000..e9b9f8d4c9 --- /dev/null +++ b/umbraco.MacroEngines.Juno/Razor/CSharpRazorProvider.cs @@ -0,0 +1,33 @@ +namespace umbraco.MacroEngines.Razor +{ + using System.CodeDom.Compiler; + using System.Web.Razor; + + using Microsoft.CSharp; + + /// + /// Provides a razor provider that supports the C# syntax. + /// + public class CSharpRazorProvider : IRazorProvider + { + #region Methods + /// + /// Creates a code language service. + /// + /// Creates a language service. + public RazorCodeLanguage CreateLanguageService() + { + return new CSharpRazorCodeLanguage(); + } + + /// + /// Creates a . + /// + /// The a code dom provider. + public CodeDomProvider CreateCodeDomProvider() + { + return new CSharpCodeProvider(); + } + #endregion + } +} \ No newline at end of file diff --git a/umbraco.MacroEngines.Juno/Razor/IRazorProvider.cs b/umbraco.MacroEngines.Juno/Razor/IRazorProvider.cs new file mode 100644 index 0000000000..b66a602322 --- /dev/null +++ b/umbraco.MacroEngines.Juno/Razor/IRazorProvider.cs @@ -0,0 +1,26 @@ +namespace umbraco.MacroEngines.Razor +{ + using System.CodeDom; + using System.CodeDom.Compiler; + using System.Web.Razor; + + /// + /// Defines a provider used to create associated compiler types. + /// + public interface IRazorProvider + { + #region Methods + /// + /// Creates a code language service. + /// + /// Creates a language service. + RazorCodeLanguage CreateLanguageService(); + + /// + /// Creates a . + /// + /// The a code dom provider. + CodeDomProvider CreateCodeDomProvider(); + #endregion + } +} \ No newline at end of file diff --git a/umbraco.MacroEngines.Juno/Razor/ITemplate.cs b/umbraco.MacroEngines.Juno/Razor/ITemplate.cs new file mode 100644 index 0000000000..9a549bab65 --- /dev/null +++ b/umbraco.MacroEngines.Juno/Razor/ITemplate.cs @@ -0,0 +1,58 @@ +using System.Dynamic; +namespace umbraco.MacroEngines.Razor +{ + /// + /// A razor template. + /// + public interface ITemplate + { + #region Properties + /// + /// Gets the parsed result of the template. + /// + string Result { get; } + #endregion + + #region Methods + /// + /// Clears the template. + /// + void Clear(); + + /// + /// Executes the template. + /// + void Execute(); + + /// + /// Writes the specified object to the template. + /// + /// + void Write(object @object); + + /// + /// Writes a literal to the template. + /// + /// + void WriteLiteral(string literal); + #endregion + } + + /// + /// A razor template with a model. + /// + /// The model type + public interface ITemplate : ITemplate + { + #region Properties + /// + /// Gets or sets the model. + /// + TModel Model { get; set; } + #endregion + } + + public interface ITemplateDynamic : ITemplate { + dynamic Model { get; set; } + } +} \ No newline at end of file diff --git a/umbraco.MacroEngines.Juno/Razor/Razor.cs b/umbraco.MacroEngines.Juno/Razor/Razor.cs new file mode 100644 index 0000000000..54b084b29d --- /dev/null +++ b/umbraco.MacroEngines.Juno/Razor/Razor.cs @@ -0,0 +1,87 @@ +namespace umbraco.MacroEngines.Razor +{ + using System; + using System.Collections.Generic; + + /// + /// Process razor templates. + /// + public static class Razor + { + #region Fields + private static RazorCompiler Compiler; + private static readonly IDictionary Templates; + #endregion + + #region Constructor + /// + /// Statically initialises the type. + /// + static Razor() + { + Compiler = new RazorCompiler(new CSharpRazorProvider()); + Templates = new Dictionary(); + } + #endregion + + #region Methods + /// + /// Gets an for the specified template. + /// + /// The template to parse. + /// The model to use in the template. + /// [Optional] The name of the template. + /// + private static ITemplate GetTemplate(string template, Type modelType, string name = null) + { + if (!string.IsNullOrEmpty(name)) + { + if (Templates.ContainsKey(name)) + return Templates[name]; + } + + var instance = Compiler.CreateTemplate(template, modelType); + + if (!string.IsNullOrEmpty(name)) + { + if (!Templates.ContainsKey(name)) + Templates.Add(name, instance); + } + + return instance; + } + + /// + /// Parses the specified template using the specified model. + /// + /// The model type. + /// The template to parse. + /// The model to use in the template. + /// [Optional] A name for the template used for caching. + /// The parsed template. + public static string Parse(string template, T model, string name = null) + { + var instance = GetTemplate(template, typeof(T), name); + if (instance is ITemplate) + ((ITemplate)instance).Model = model; + else if (instance is ITemplateDynamic) + ((ITemplateDynamic)instance).Model = model; + + instance.Execute(); + return instance.Result; + } + + /// + /// Sets the razor provider used for compiling templates. + /// + /// The razor provider. + public static void SetRazorProvider(IRazorProvider provider) + { + if (provider == null) + throw new ArgumentNullException("provider"); + + Compiler = new RazorCompiler(provider); + } + #endregion + } +} \ No newline at end of file diff --git a/umbraco.MacroEngines.Juno/Razor/RazorCompiler.cs b/umbraco.MacroEngines.Juno/Razor/RazorCompiler.cs new file mode 100644 index 0000000000..94c2525352 --- /dev/null +++ b/umbraco.MacroEngines.Juno/Razor/RazorCompiler.cs @@ -0,0 +1,108 @@ +using System.CodeDom; + +namespace umbraco.MacroEngines.Razor { + using System; + using System.CodeDom.Compiler; + using System.IO; + using System.Text; + using System.Text.RegularExpressions; + using System.Web.Razor; + using System.Web.Razor.Parser; + using System.Runtime.CompilerServices; + + /// + /// Compiles razor templates. + /// + internal class RazorCompiler { + #region Fields + private readonly IRazorProvider provider; + #endregion + + #region Constructor + /// + /// Initialises a new instance of . + /// + /// The provider used to compile templates. + public RazorCompiler(IRazorProvider provider) { + if (provider == null) + throw new ArgumentNullException("provider"); + + this.provider = provider; + } + #endregion + + #region Methods + /// + /// Compiles the template. + /// + /// The class name of the dynamic type. + /// The template to compile. + /// [Optional] The mode type. + private CompilerResults Compile(string className, string template, Type modelType = null) { + var languageService = provider.CreateLanguageService(); + var codeDom = provider.CreateCodeDomProvider(); + var host = new RazorEngineHost(languageService); + + var generator = languageService.CreateCodeGenerator(className, "Razor.Dynamic", null, host); + var parser = new RazorParser(languageService.CreateCodeParser(), new HtmlMarkupParser()); + + // Umbraco hack for use with DynamicNode + bool anonymousType = modelType.FullName == "umbraco.MacroEngines.DynamicNode" || (modelType.IsClass && modelType.IsSealed && modelType.BaseType == typeof(object) && modelType.Name.StartsWith("<>") && modelType.GetCustomAttributes(typeof(CompilerGeneratedAttribute), true) != null); + + //There's no simple way of determining if an object is an anonymous type - this seems like a problem + Type baseType = (modelType == null) + ? typeof(TemplateBase) + : (anonymousType + ? typeof(TemplateBaseDynamic) + : typeof(TemplateBase<>).MakeGenericType(modelType)); + + generator.GeneratedClass.BaseTypes.Add(baseType); + + using (var reader = new StreamReader(new MemoryStream(Encoding.ASCII.GetBytes(template)))) { + parser.Parse(reader, generator); + } + + var statement = new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), "Clear"); + generator.GeneratedExecuteMethod.Statements.Insert(0, new CodeExpressionStatement(statement)); + + var builder = new StringBuilder(); + using (var writer = new StringWriter(builder)) { + codeDom.GenerateCodeFromCompileUnit(generator.GeneratedCode, writer, new CodeGeneratorOptions()); + } + + var @params = new CompilerParameters(); + foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) { + if (!assembly.IsDynamic) + @params.ReferencedAssemblies.Add(assembly.Location); + } + + @params.GenerateInMemory = true; + @params.IncludeDebugInformation = false; + @params.GenerateExecutable = false; + @params.CompilerOptions = "/target:library /optimize"; + + var result = codeDom.CompileAssemblyFromSource(@params, new[] { builder.ToString() }); + return result; + } + + /// + /// Creates a from the specified template string. + /// + /// The template to compile. + /// [Optional] The model type. + /// An instance of . + public ITemplate CreateTemplate(string template, Type modelType = null) { + string className = Regex.Replace(Guid.NewGuid().ToString("N"), @"[^A-Za-z]*", ""); + + var result = Compile(className, template, modelType); + + if (result.Errors != null && result.Errors.Count > 0) + throw new TemplateException(result.Errors); + + ITemplate instance = (ITemplate)result.CompiledAssembly.CreateInstance("Razor.Dynamic." + className); + + return instance; + } + #endregion + } +} \ No newline at end of file diff --git a/umbraco.MacroEngines.Juno/Razor/TemplateBase.cs b/umbraco.MacroEngines.Juno/Razor/TemplateBase.cs new file mode 100644 index 0000000000..6a88a5b6cb --- /dev/null +++ b/umbraco.MacroEngines.Juno/Razor/TemplateBase.cs @@ -0,0 +1,146 @@ +namespace umbraco.MacroEngines.Razor +{ + using System.Text; + using System.IO; + using System.Globalization; + using System.Dynamic; + using System; + using System.Runtime.CompilerServices; + + /// + /// Provides a base implementation of a template. + /// + public abstract class TemplateBase : ITemplate + { + #region Fields + private TextWriter builder = new StringWriter(CultureInfo.InvariantCulture); + + #endregion + + #region Properties + /// + /// Gets the parsed result of the template. + /// + public string Result { get { return builder.ToString(); } } + #endregion + + #region Methods + /// + /// Clears the template. + /// + public void Clear() + { + builder = new StringWriter(CultureInfo.InvariantCulture); + } + + /// + /// Executes the template. + /// + public virtual void Execute() { } + + /// + /// Writes the specified object to the template. + /// + /// + public void Write(object @object) + { + if (@object == null) + return; + + builder.Write(@object); + } + + /// + /// Writes a literal to the template. + /// + /// + public void WriteLiteral(string literal) + { + if (literal == null) + return; + + builder.Write(literal); + } + #endregion + } + + /// + /// Provides a base implementation of a template. + /// + /// The model type. + public abstract class TemplateBase : TemplateBase, ITemplate + { + #region Properties + public TModel Model { get; set; } + + /// + /// Gets or sets the model. + /// + #endregion + + } + + /// + /// Inherits form TemplateBase and provides an anonymous type implementation + /// + public abstract class TemplateBaseDynamic : TemplateBase, ITemplateDynamic + { + + dynamic model; + + /// + /// Gets or sets an anonymous type model + /// + public dynamic Model + { + get + { + return model; + } + set + { + model = new RazorDynamicObject() { Model = value }; + } + } + + + /// + /// Dynamic object that we'll utilize to return anonymous type parameters + /// + class RazorDynamicObject : DynamicObject + { + internal object Model { get; set; } + public override bool TryGetMember(GetMemberBinder binder, out object result) + { + bool isDynamicNode = false; + object tempResult = null; + try + { + if (Model.GetType().FullName == "RazorControl.DynamicNode") + { + isDynamicNode = ((DynamicObject)Model).TryGetMember(binder, out tempResult); + } + + } + catch + { + result = ""; + } + if (!isDynamicNode) + { + tempResult = Model.GetType().InvokeMember(binder.Name, + System.Reflection.BindingFlags.GetProperty | + System.Reflection.BindingFlags.Instance | + System.Reflection.BindingFlags.Public | + System.Reflection.BindingFlags.NonPublic, + null, + Model, + null); + } + result = tempResult; + return true; + } + } + + } +} \ No newline at end of file diff --git a/umbraco.MacroEngines.Juno/Razor/TemplateException.cs b/umbraco.MacroEngines.Juno/Razor/TemplateException.cs new file mode 100644 index 0000000000..27a65976d1 --- /dev/null +++ b/umbraco.MacroEngines.Juno/Razor/TemplateException.cs @@ -0,0 +1,37 @@ +namespace umbraco.MacroEngines.Razor +{ + using System; + using System.CodeDom.Compiler; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Linq; + + /// + /// Defines an exception that occurs during compilation of a template. + /// + public class TemplateException : Exception + { + #region Constructors + /// + /// Initialises a new instance of + /// + /// The collection of compilation errors. + internal TemplateException(CompilerErrorCollection errors) : base("Unable to compile template.") + { + var list = new List(); + foreach (CompilerError error in errors) + { + list.Add(error); + } + Errors = new ReadOnlyCollection(list); + } + #endregion + + #region Properties + /// + /// Gets the collection of compiler errors. + /// + public ReadOnlyCollection Errors { get; private set; } + #endregion + } +} \ No newline at end of file diff --git a/umbraco.MacroEngines.Juno/Razor/VBRazorProvider.cs b/umbraco.MacroEngines.Juno/Razor/VBRazorProvider.cs new file mode 100644 index 0000000000..a18c388fed --- /dev/null +++ b/umbraco.MacroEngines.Juno/Razor/VBRazorProvider.cs @@ -0,0 +1,33 @@ +namespace umbraco.MacroEngines.Razor +{ + using System.CodeDom.Compiler; + using System.Web.Razor; + + using Microsoft.VisualBasic; + + /// + /// Provides a razor provider that supports the VB syntax. + /// + public class VBRazorProvider : IRazorProvider + { + #region Methods + /// + /// Creates a code language service. + /// + /// Creates a language service. + public RazorCodeLanguage CreateLanguageService() + { + return new VBRazorCodeLanguage(); + } + + /// + /// Creates a . + /// + /// The a code dom provider. + public CodeDomProvider CreateCodeDomProvider() + { + return new VBCodeProvider(); + } + #endregion + } +} \ No newline at end of file diff --git a/umbraco.MacroEngines.Juno/RazorEngine.cs b/umbraco.MacroEngines.Juno/RazorEngine.cs new file mode 100644 index 0000000000..b1b96eee68 --- /dev/null +++ b/umbraco.MacroEngines.Juno/RazorEngine.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Web; +using umbraco.cms.businesslogic.macro; +using umbraco.interfaces; +using umbraco.IO; + +namespace umbraco.MacroEngines +{ + public class RazorEngine : IMacroEngine + { + public string Name + { + get { return "Razor Enggine"; } + } + + public List SupportedExtensions + { + get + { + var exts = new List { "razor" }; + return exts; + } + } + + public Dictionary SupportedProperties + { + get { throw new NotImplementedException(); } + } + + public bool Validate(string code, INode currentPage, out string errorMessage) + { + throw new NotImplementedException(); + } + + public string Execute(MacroModel macro, INode currentPage) + { + string result = String.Empty; + string template = !String.IsNullOrEmpty(macro.ScriptCode) ? macro.ScriptCode : loadScript(IOHelper.MapPath(SystemDirectories.Python + "/" + macro.ScriptName)); + try + { + //TODO: Add caching support + // if (CacheTemplate) + // result = Razor.Parse(template, new DynamicNode(currentPage), this.ID + "_razorTemplate"); + // else + // { + result = Razor.Razor.Parse(template, new DynamicNode(currentPage)); + } + // } + catch (Exception ee) + { + result = string.Format( + "

Razor Macro Engine

An error occured while rendering the following code:

{0}

{1}
", + ee.ToString(), + HttpContext.Current.Server.HtmlEncode(template)); + } + + return result; + } + + private string loadScript(string scriptName) + { + if (File.Exists(scriptName)) + { + return File.ReadAllText(scriptName); + } + + return String.Empty; + } + } +} diff --git a/umbraco.MacroEngines.Juno/Scripting/MacroScript.cs b/umbraco.MacroEngines.Juno/Scripting/MacroScript.cs new file mode 100644 index 0000000000..973f949ce6 --- /dev/null +++ b/umbraco.MacroEngines.Juno/Scripting/MacroScript.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Microsoft.Scripting.Hosting; + +namespace umbraco.MacroEngines.Scripting +{ + public class MacroScript + { + public static string Execute(string script, string scriptType, Hashtable variables) + { + MacroScriptEngine mse = new MacroScriptEngine(scriptType); + mse.ScriptVariables = ConvertHashTable(variables); + mse.Script = script; + return mse.Execute(); + } + + public static string Evaluate(string script, string scriptType, Hashtable variables) + { + MacroScriptEngine mse = new MacroScriptEngine(scriptType); + mse.ScriptVariables = ConvertHashTable(variables); + mse.Script = script; + return mse.Evaluate(); + } + + public static string ExecuteFile(string path, Hashtable variables) + { + string fileEnding = path.Substring(path.LastIndexOf('.')).Trim('.'); + + MacroScriptEngine mse = MacroScriptEngine.LoadEngineByFileExtension(fileEnding); + mse.ScriptVariables = ConvertHashTable(variables); + + return mse.ExecuteFile(path); + } + + //friendly helpers.... + public static string ExecutePython(string script, Hashtable variables) + { + return Execute(script, "python", variables); + } + + public static string ExecuteRuby(string script, Hashtable variables) + { + return Execute(script, "ruby", variables); + } + + private static SortedDictionary ConvertHashTable(Hashtable ht) + { + SortedDictionary retval = new SortedDictionary(); + foreach (DictionaryEntry de in ht) + { + retval.Add(de.Key.ToString(), de.Value); + } + + return retval; + } + + public static List GetAvailableLanguages() + { + return ScriptRuntimeSetup.ReadConfiguration().LanguageSetups.ToList(); + } + } +} diff --git a/umbraco.MacroEngines.Juno/Scripting/ScriptEngine.cs b/umbraco.MacroEngines.Juno/Scripting/ScriptEngine.cs new file mode 100644 index 0000000000..bcec3b5ab8 --- /dev/null +++ b/umbraco.MacroEngines.Juno/Scripting/ScriptEngine.cs @@ -0,0 +1,199 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using Microsoft.Scripting; +using Microsoft.Scripting.Hosting; + +namespace umbraco.MacroEngines.Scripting +{ + internal class MacroScriptEngine + { + ScriptRuntime m_runTime; + ScriptEngine m_engine; + ExceptionOperations m_exceptionOperations; + SortedDictionary m_inputVariables; + SortedDictionary m_outputVariables; + string m_script; + MemoryStream m_output; + + internal MacroScriptEngine() { } + + internal MacroScriptEngine(string scriptType) + { + loadRunTime(); + m_engine = m_runTime.GetEngine(scriptType); + m_exceptionOperations = m_engine.GetService(); + } + + internal static MacroScriptEngine LoadEngineByFileExtension(string fileExtension) + { + MacroScriptEngine mse = new MacroScriptEngine(); + mse.loadRunTime(); + mse.m_engine = mse.m_runTime.GetEngineByFileExtension(fileExtension); + mse.m_exceptionOperations = mse.m_engine.GetService(); + return mse; + } + + internal static MacroScriptEngine GetEngineByType(string scriptType) + { + MacroScriptEngine mse = new MacroScriptEngine(); + mse.loadRunTime(); + mse.m_engine = mse.m_runTime.GetEngine(scriptType); + mse.m_exceptionOperations = mse.m_engine.GetService(); + return mse; + } + + private void loadRunTime() + { + m_output = new MemoryStream(); + m_runTime = ScriptRuntime.CreateFromConfiguration(); + + m_runTime.IO.SetOutput(m_output, new StreamWriter(m_output)); + m_runTime.IO.SetErrorOutput(m_output, new StreamWriter(m_output)); + + Assembly pluginsAssembly = Assembly.LoadFile(IO.IOHelper.MapPath(IO.SystemDirectories.Bin + "/umbraco.dll")); + m_runTime.LoadAssembly(pluginsAssembly); + + m_runTime.LoadAssembly(typeof(String).Assembly); + m_runTime.LoadAssembly(typeof(Uri).Assembly); + m_runTime.LoadAssembly(typeof(umbraco.presentation.nodeFactory.Node).Assembly); + } + + + internal SortedDictionary ScriptVariables + { + set { m_inputVariables = value; } + } + + internal SortedDictionary OutPutVariables + { + get { return m_outputVariables; } + } + + internal string Script + { + set { m_script = value; } + } + + internal ExceptionOperations ExceptionOperations + { + get { return m_exceptionOperations; } + } + + internal string Evaluate() + { + //Create structures + SourceCodeKind sc = SourceCodeKind.Expression; + ScriptSource source = m_engine.CreateScriptSourceFromString(m_script, sc); + ScriptScope scope = m_engine.CreateScope(); + + //Fill input variables + foreach (KeyValuePair variable in m_inputVariables) + { + scope.SetVariable(variable.Key, variable.Value); + } + + string result = ""; + + try + { + object r = source.Execute(scope); + + if (r != null) + result = r.ToString(); + } + catch (Exception e) + { + umbraco.BusinessLogic.Log.Add(umbraco.BusinessLogic.LogTypes.Debug, -1, e.ToString()); + result = m_exceptionOperations.FormatException(e); + } + + return result; + } + + internal string Execute() + { + SourceCodeKind sc = SourceCodeKind.Statements; + ScriptSource source = m_engine.CreateScriptSourceFromString(m_script, sc); + ScriptScope scope = m_engine.CreateScope(); + + //Fill input variables + foreach (KeyValuePair variable in m_inputVariables) + { + scope.SetVariable(variable.Key, variable.Value); + } + + source.Execute(scope); + + m_outputVariables = new SortedDictionary(); + foreach (string variable in scope.GetVariableNames()) + { + m_outputVariables.Add(variable, scope.GetVariable(variable)); + } + + return ReadFromStream(m_output); + } + + internal string ExecuteFile(string path) + { + string rbCode; + + // OpenText will strip the BOM and keep the Unicode intact + using (var rdr = File.OpenText(path)) + { + rbCode = rdr.ReadToEnd(); + } + + m_script = rbCode; + return Execute(); + } + + internal SortedDictionary _Execute() + { + //Create structures + SourceCodeKind sc = SourceCodeKind.Statements; + ScriptSource source = m_engine.CreateScriptSourceFromString(m_script, sc); + ScriptScope scope = m_engine.CreateScope(); + + //Fill input variables + foreach (KeyValuePair variable in m_inputVariables) + { + scope.SetVariable(variable.Key, variable.Value); + } + + SortedDictionary outputVariables = new SortedDictionary(); + //Execute the script + try + { + + source.Execute(scope); + //Recover variables + foreach (string variable in scope.GetVariableNames()) + { + outputVariables.Add(variable, scope.GetVariable(variable)); + } + } + catch (Exception e) + { + string error = m_exceptionOperations.FormatException(e); + //Do something with the pretty printed error + throw; + } + return outputVariables; + } + + private static string ReadFromStream(MemoryStream ms) + { + int length = (int)ms.Length; + Byte[] bytes = new Byte[length]; + + ms.Seek(0, SeekOrigin.Begin); + ms.Read(bytes, 0, (int)ms.Length); + + return Encoding.GetEncoding("utf-8").GetString(bytes, 0, (int)ms.Length); + } + } +} diff --git a/umbraco.MacroEngines.Juno/umbraco.MacroEngines.csproj b/umbraco.MacroEngines.Juno/umbraco.MacroEngines.csproj new file mode 100644 index 0000000000..2aa193c95f --- /dev/null +++ b/umbraco.MacroEngines.Juno/umbraco.MacroEngines.csproj @@ -0,0 +1,96 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {89C09045-1064-466B-B94A-DB3AFE2A5853} + Library + Properties + umbraco.MacroEngines + umbraco.MacroEngines + v4.0 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\foreign dlls\DLR 4.0\Microsoft.Scripting.dll + + + + + + False + ..\foreign dlls\System.Web.Razor.dll + + + + + + + + + + + + + + + + + + + + + + + + + + {E469A9CE-1BEC-423F-AC44-713CD72457EA} + umbraco.businesslogic + + + {CCD75EC3-63DB-4184-B49D-51C1DD337230} + umbraco.cms + + + {511F6D8D-7717-440A-9A57-A507E9A8B27F} + umbraco.interfaces + + + {651E1350-91B6-44B7-BD60-7207006D7003} + umbraco.presentation + + + + + xcopy "$(TargetPath)" "$(SolutionDir)\umbraco\presentation\bin" /Y +xcopy "$(SolutionDir)foreign dlls\System.Web.Razor.dll" "$(SolutionDir)\umbraco\presentation\bin" /Y + + + \ No newline at end of file diff --git a/umbraco.MacroEngines/DLRScriptingEngine.cs b/umbraco.MacroEngines/DLRScriptingEngine.cs index f9a5e01e21..f406d08844 100644 --- a/umbraco.MacroEngines/DLRScriptingEngine.cs +++ b/umbraco.MacroEngines/DLRScriptingEngine.cs @@ -1,13 +1,11 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; using umbraco.cms.businesslogic.macro; using umbraco.interfaces; using umbraco.IO; -using umbraco.MacroEngines.Scripting; +using umbraco.MacroEngines.Legacy.Scripting; -namespace umbraco.MacroEngines +namespace umbraco.MacroEngines.Legacy { public class DLRScriptingEngine : IMacroEngine { diff --git a/umbraco.MacroEngines/Scripting/MacroScript.cs b/umbraco.MacroEngines/Scripting/MacroScript.cs index 973f949ce6..a5575a5ae9 100644 --- a/umbraco.MacroEngines/Scripting/MacroScript.cs +++ b/umbraco.MacroEngines/Scripting/MacroScript.cs @@ -5,7 +5,7 @@ using System.Linq; using System.Text; using Microsoft.Scripting.Hosting; -namespace umbraco.MacroEngines.Scripting +namespace umbraco.MacroEngines.Legacy.Scripting { public class MacroScript { diff --git a/umbraco.MacroEngines/Scripting/ScriptEngine.cs b/umbraco.MacroEngines/Scripting/ScriptEngine.cs index bcec3b5ab8..c0f97c3f60 100644 --- a/umbraco.MacroEngines/Scripting/ScriptEngine.cs +++ b/umbraco.MacroEngines/Scripting/ScriptEngine.cs @@ -7,7 +7,7 @@ using System.Text; using Microsoft.Scripting; using Microsoft.Scripting.Hosting; -namespace umbraco.MacroEngines.Scripting +namespace umbraco.MacroEngines.Legacy.Scripting { internal class MacroScriptEngine { diff --git a/umbraco.MacroEngines/umbraco.MacroEngines.csproj b/umbraco.MacroEngines/umbraco.MacroEngines.Legacy.csproj similarity index 93% rename from umbraco.MacroEngines/umbraco.MacroEngines.csproj rename to umbraco.MacroEngines/umbraco.MacroEngines.Legacy.csproj index 76dd19286e..75b5b8d5a9 100644 --- a/umbraco.MacroEngines/umbraco.MacroEngines.csproj +++ b/umbraco.MacroEngines/umbraco.MacroEngines.Legacy.csproj @@ -8,9 +8,9 @@ {6AE67079-2C00-476C-81DE-2800D1AC14BC} Library Properties - umbraco.MacroEngines - umbraco.MacroEngines - v3.5 + umbraco.MacroEngines.Legacy + umbraco.MacroEngines.Legacy + v4.0 512 SAK SAK diff --git a/umbraco.sln b/umbraco.sln index 8c441a1420..0dccbb9cdf 100644 --- a/umbraco.sln +++ b/umbraco.sln @@ -105,7 +105,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "assets", "assets", "{194009 EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SqlCE4Umbraco", "components\SQLCE4Umbraco\SqlCE4Umbraco.csproj", "{5BA5425F-27A7-4677-865E-82246498AA2E}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "umbraco.MacroEngines", "umbraco.MacroEngines\umbraco.MacroEngines.csproj", "{6AE67079-2C00-476C-81DE-2800D1AC14BC}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "umbraco.MacroEngines.Legacy", "umbraco.MacroEngines\umbraco.MacroEngines.Legacy.csproj", "{6AE67079-2C00-476C-81DE-2800D1AC14BC}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "umbraco.MacroEngines", "umbraco.MacroEngines.Juno\umbraco.MacroEngines.csproj", "{89C09045-1064-466B-B94A-DB3AFE2A5853}" EndProject Global GlobalSection(TeamFoundationVersionControl) = preSolution @@ -221,9 +223,12 @@ Global {5BA5425F-27A7-4677-865E-82246498AA2E}.Release|Any CPU.ActiveCfg = Release|Any CPU {5BA5425F-27A7-4677-865E-82246498AA2E}.Release|Any CPU.Build.0 = Release|Any CPU {6AE67079-2C00-476C-81DE-2800D1AC14BC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6AE67079-2C00-476C-81DE-2800D1AC14BC}.Debug|Any CPU.Build.0 = Debug|Any CPU {6AE67079-2C00-476C-81DE-2800D1AC14BC}.Release|Any CPU.ActiveCfg = Release|Any CPU {6AE67079-2C00-476C-81DE-2800D1AC14BC}.Release|Any CPU.Build.0 = Release|Any CPU + {89C09045-1064-466B-B94A-DB3AFE2A5853}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {89C09045-1064-466B-B94A-DB3AFE2A5853}.Debug|Any CPU.Build.0 = Debug|Any CPU + {89C09045-1064-466B-B94A-DB3AFE2A5853}.Release|Any CPU.ActiveCfg = Release|Any CPU + {89C09045-1064-466B-B94A-DB3AFE2A5853}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE