using System;
namespace umbraco.scripting{
/// <summary>
/// Something like a proxy to IronPython. Does some initial settings and calls.
/// Maps IronPython's StandardOutput and StandardError to a simple string.
/// </summary>
public class python
{
protected internal static PythonEngine Engine;
protected static System.IO.MemoryStream ms;
protected static System.IO.StreamReader sr;
protected internal static System.Collections.Hashtable scripts;
static python()
{
Engine = new PythonEngine();
initEnv();
loadScripts();
ms = new System.IO.MemoryStream();
sr = new System.IO.StreamReader(ms);
Engine.SetStandardOutput(ms);
Engine.SetStandardError(ms);
}
/// <summary>
/// To be able to import umbraco dll's we have to append the umbraco path to python.
/// It should also be possible to import other python scripts from umbracos python folder.
/// And finally to run run some custom init stuff the script site.py in umbraco's
/// root folder will be executed.
/// </summary>
/// <returns></returns>
private static void initEnv()
{
// Add umbracos bin folder to python's path
string path = System.Web.HttpContext.Current.Server.MapPath(GlobalSettings.Path + "\\..\\bin");
Engine.AddToPath(path);
// Add umbracos python folder to python's path
path = System.Web.HttpContext.Current.Server.MapPath(GlobalSettings.Path + "\\..\\python");
Engine.AddToPath(path);
// execute the site.py to do all the initial stuff
string initFile = System.Web.HttpContext.Current.Server.MapPath(GlobalSettings.Path + "\\..\\site.py");
Engine.ExecuteFile(initFile);
}
/// <summary>
///
/// </summary>
/// <returns></returns>
private static void loadScripts()
{
scripts = new System.Collections.Hashtable();
string path = System.Web.HttpContext.Current.Server.MapPath(GlobalSettings.Path + "\\..\\python");
System.IO.DirectoryInfo dir = new System.IO.DirectoryInfo(path);
foreach (System.IO.FileInfo f in dir.GetFiles("*.py"))
{
if (!f.Name.EndsWith("_temp.py"))
{
try
{
scripts[f.FullName] = Engine.CompileFile(f.FullName );
}
catch
{
scripts[f.FullName] = Engine.Compile("print 'error in file " + f.Name + "'");
}
}
}
}
/// <summary>
/// Executes a python command like in console
/// </summary>
/// <param name="expression">command to execute</param>
/// <returns>returns standard out of executed command</returns>
public static string execute(string expression)
{
if (!(expression == null))
{
string ret;
ms.SetLength(0);
ms.Flush();
try
{
Engine.Execute(expression);
ms.Position = 0;
ret = sr.ReadToEnd();
}
catch (Exception ex)
{
ret = ex.Message;
}
return ret;
}
else
{
return string.Empty;
}
}
/// <summary>
/// Executes a python script like in console
/// </summary>
/// <param name="file">absolute path to script</param>
/// <returns>returns standard out of executed script</returns>
public static string executeFile(string file)
{
if (System.IO.File.Exists(file))
{
string ret;
ms.SetLength(0);
ms.Flush();
scripts[file].GetType().InvokeMember("Execute", System.Reflection.BindingFlags.InvokeMethod, null, scripts[file], null);
ms.Position = 0;
ret = sr.ReadToEnd();
return ret;
}
else
{
return "The File " + file + " could not be found.";
}
}
/// <summary>
/// Compiles a python script and add it to umbraco's script collection.
/// If compilation fails then an exception will be raised.
/// </summary>
/// <param name="file">absolute path to script</param>
/// <returns></returns>
public static void compileFile(string file)
{
loadScripts();
scripts[file] = Engine.CompileFile(file);
}
/// <summary>
/// Compiles a python script.
/// If compilation fails then an exception will be raised.
/// </summary>
/// <param name="file">absolute path to script</param>
/// <returns></returns>
public static void tryCompile(string file)
{
Engine.CompileFile(file);
}
}
/// <summary>
/// The Class PythonEngine is just a wrapper for the real class IronPython.Hosting.PythonEngine
/// in IronPython. In this manner we does not need a hard reference to the IronPython assembly.
/// I've implemented only the methods i need for my purpose.
/// </summary>
public class PythonEngine
{
protected object Engine;
public PythonEngine()
{
string path = System.Web.HttpContext.Current.Server.MapPath(GlobalSettings.Path + "\\..\\bin\\IronPython.dll");
System.Reflection.Assembly asm = System.Reflection.Assembly.LoadFile(path);
System.Type EngineType = asm.GetType("IronPython.Hosting.PythonEngine");
Engine = System.Activator.CreateInstance(EngineType);
}
public void AddToPath(string path)
{
Engine.GetType().InvokeMember("AddToPath", System.Reflection.BindingFlags.InvokeMethod, null, Engine, new object[] { path });
}
public void SetStandardOutput(System.IO.Stream stream)
{
Engine.GetType().InvokeMember("SetStandardOutput", System.Reflection.BindingFlags.InvokeMethod, null, Engine, new object[] { stream });
}
public void SetStandardError(System.IO.Stream stream)
{
Engine.GetType().InvokeMember("SetStandardError", System.Reflection.BindingFlags.InvokeMethod, null, Engine, new object[] { stream });
}
public void ExecuteFile(string FileName)
{
Engine.GetType().InvokeMember("ExecuteFile", System.Reflection.BindingFlags.InvokeMethod, null, Engine, new object[] { FileName });
}
public void Execute(string ScriptCode)
{
Engine.GetType().InvokeMember("Execute", System.Reflection.BindingFlags.InvokeMethod, null, Engine, new object[] { ScriptCode });
}
public Object CompileFile(string FileName)
{
return Engine.GetType().InvokeMember("CompileFile", System.Reflection.BindingFlags.InvokeMethod, null, Engine, new object[] { FileName });
}
public Object Compile(string Expression)
{
return Engine.GetType().InvokeMember("Compile", System.Reflection.BindingFlags.InvokeMethod, null, Engine, new object[] { Expression });
}
public Object CreateModule(string Modulename, bool publish)
{
return Engine.GetType().InvokeMember("CreateModule", System.Reflection.BindingFlags.InvokeMethod, null, Engine, new object[] { Modulename, publish });
}
public System.Collections.IDictionary Globals
{
set
{
Engine.GetType().InvokeMember("Globals", System.Reflection.BindingFlags.SetProperty, null, Engine, new object[] { value });
}
get
{
return (System.Collections.IDictionary)Engine.GetType().InvokeMember("Globals", System.Reflection.BindingFlags.GetProperty, null, Engine, null);
}
}
}
}
|