Hi Abe,

Abe Gillespie wrote:

*snip
mono script_host.exe MyScript.cs myarg1 myarg2

*snip
Has anyone out there done something or started a project like this?
Give the attached source code a try :-) I'm not claiming it's perfect, but it's something I knocked up while I was bored this afternoon, and you may be able to use it or tweak it to what you need. It uses the features of CodeDom, available both in .Net and Mono, to compile the source file to an in-memory assembly, where the code can then be executed. The file "MonoScript.cs" can be compiled on its own to provide the actual script execution tool, and also attached is a sample "script" file ("Test.cs") that you can use to give it a bash. Simply compile the MonoScript tool:

mcs MonoScript.cs

And then it's as easy as running:

mono MonoScript.exe --sourceFile:Test.cs

If for example your source file has a reference to System.Data then you can simply run:

mono MonoScript.exe --sourceFile:Test.cs --references:System.Data.dll

For the full usage of the program, run:

mono MonoScript.exe --displayUsage:true

Any arguments you specify that MonoScript doesn't recognize will be forwarded onto the "script" application, you can see this by appending as many arguments as you want to the test script:

mono MonoScript.exe --sourceFile:Test.cs test1 test2 test3

Have a play, and give me a shout if you run into any bugs or problems with it and I'll do my best to fix them, failing that, jump right in and tweak the code yourself ;-)

If anyone else finds the code useful, let me know and I'll get the entire thing (project files, a build file maybe, a bigger testsuite perhaps?) up on my website as a package. Likewise if anyone has any comments, let me have 'em!

-Abe
Cheers,
-= El =-

On 11/10/05, Kornél Pál <[EMAIL PROTECTED]> wrote:
Hi,

You have to compile C# code using mcs that will result in a .exe assembly
that can be executed using mono:

$mcs some.cs
$mono some.exe

If you prefer you can write a shell script that will do this as a single
step.

Kornél

----- Original Message -----
From: "Abe Gillespie" <[EMAIL PROTECTED]>
To: "MonoList" <mono-list@lists.ximian.com>
Sent: Friday, November 11, 2005 1:02 AM
Subject: [Mono-list] Scripting the Linux OS with Mono


Hey all,

I was wondering if there's any easy way to run C# scripts in Mono.
I'm fairly new to Linux (just at about a year) and I'd like to avoid
learning yet another language (Perl, sh, etc.).  Has anyone written a
.Net program that takes a file as input and runs that code?  Perhaps
Mono can do this natively?  How cool would it be to have startup
scripts written in C#?!

Thanks for the help as always.
-Abe
_______________________________________________
Mono-list maillist  -  Mono-list@lists.ximian.com
http://lists.ximian.com/mailman/listinfo/mono-list


_______________________________________________
Mono-list maillist  -  Mono-list@lists.ximian.com
http://lists.ximian.com/mailman/listinfo/mono-list

using System;

public class MonoScriptTest
{
        //This simply displays the amount of arguments passed into it
        public static void Main(string[] args)
        {
                Console.WriteLine(string.Format("MonoScript: test script, {0} 
arguments",args.Length.ToString()));
        }
}
using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections.Specialized;
using System.Reflection;

namespace MonoScript
{
    /// <summary>
    /// This allows the execution of a .cs file as if it were a program, 
compiling it on the fly then executing it
    /// 
    /// Example syntax:
    /// 
    /// MonoScript /s:myscript.cs /r:System.Drawing.dll                 This 
would execute the code within the
    /// file myscript.cs, and reference System.Drawing.dll when compiling it
    /// 
    /// MonoScript /s:myscript.cs /r:System.Data.dll /n:true /v:true    This 
would compile the code within the
    /// file myscript.cs, reference System.Data.dll when doing it, stop the 
MonoScript logo from displaying
    /// when run, and also ensure that ONLY compilation takes place, not 
execution, for validation purposes
    /// </summary>
    class MonoScript
    {
        /// <summary>
        /// These are our options for the script to execute
        /// </summary>
        static MonoScriptOptions Options;

        /// <summary>
        /// Main entry point
        /// </summary>
        /// <param name="args"></param>
        static void Main(string[] args)
        {
            //Create our options from the command line args
            Options = new MonoScriptOptions(args);

            //Only show the logo if we haven't been told not to
            if(!Options.NoLogo)
                Logo();

            //If the user has requested the program usage, then show it here
            if (Options.DisplayUsage)
            {
                Usage();
                return;
            }

            //This will hold our in-memory compiled assembly
            Assembly assembly = null;

            try
            {
                //Compile our script to an assembly
                assembly = CompileFile();

                //Ensure we have an assembly
                if (assembly == null)
                    throw new Exception("No assembly generated!");
            }
            catch (Exception ex)
            {
                //Display any errors found while compiling
                Console.WriteLine(string.Format(
                    "Exception caught while compiling script:{0}{1}{0}",
                    Environment.NewLine,
                    ex.ToString()));

                return;
            }

            //If we are only validating (compiling) the script, then exit here
            if (Options.ValidateOnly)
            {
                Console.WriteLine("Validation complete");
                return;
            }

            try
            {
                //Execute the script
                ExecuteAssembly(assembly);
            }
            catch (Exception ex)
            {
                //Catch any errors while executing it
                Console.WriteLine(string.Format(
                    "Exception caught while executing script:{0}{1}{0}",
                    Environment.NewLine,
                    ex.ToString()));

                return;
            }
        }

        /// <summary>
        /// This outputs the program logo
        /// </summary>
        static void Logo()
        {
            Console.WriteLine("MonoScript: (c) 2005, Elliott Draper <[EMAIL 
PROTECTED]>");
        }

        /// <summary>
        /// This outputs the usage of the app
        /// </summary>
        static void Usage()
        {
            Console.WriteLine("Usage: MonoScript --sourceFile:[VALUE] [ARGS] 
where [ARGS] can optionally be one of the following:");
            Console.WriteLine("--references:[VALUE], -r:[VALUE], /r:[VALUE]     
:       any references needed to compile the script");
            Console.WriteLine("--noLogo:[VALUE], -n:[VALUE], /n:[VALUE]         
:       stops from showing the MonoScript logo");
            Console.WriteLine("--displayUsage:[VALUE], -d:[VALUE], /d:[VALUE]   
:       displays this usage info");
            Console.WriteLine("--validateOnly:[VALUE], -v:[VALUE], /v:[VALUE]   
:       validates the script by compiling it, but doesn't execute it");
        }

        /// <summary>
        /// This compiles the specified file into an assembly, exceptioning on 
error
        /// </summary>
        /// <returns></returns>
        static Assembly CompileFile()
        {
            //Setup the parameters
            CompilerParameters parameters = new CompilerParameters();
            foreach (string reference in Options.References)
                parameters.ReferencedAssemblies.Add(reference);
                parameters.GenerateInMemory = true;

            //Create the provider and compiler
            CodeDomProvider provider = new 
Microsoft.CSharp.CSharpCodeProvider();
            if (provider == null)
                throw new Exception("Cannot create C# code provider!");
            ICodeCompiler compiler = provider.CreateCompiler();
            if (compiler == null)
                throw new Exception("Cannot create C# compiler!");
            //Compile the file with the specified parameters
            CompilerResults results = compiler.CompileAssemblyFromFile(
                parameters,
                Options.SourceFile);
            //Grab and validate the results
            if (results == null)
                throw new Exception("Could not retrieve results from 
compilation!");
            if (results.Errors.HasErrors)
                throw new Exception(results.Errors[0].ErrorText);
            //Return the compiled assembly            
            return results.CompiledAssembly;
        }

        /// <summary>
        /// This executes the specified compiled assembly
        /// </summary>
        /// <param name="assembly"></param>
        static void ExecuteAssembly(Assembly assembly)
        {
            //Invoke the entry point found for the assembly, with the specified 
arguments
            GetEntryPoint(assembly).GetMethod("Main").Invoke(null, new 
object[1] { Options.ScriptArgs });
        }

        /// <summary>
        /// This attempts to locate a type with a static "Main" method within 
the generated script assembly
        /// </summary>
        /// <param name="assembly"></param>
        /// <returns></returns>
        static Type GetEntryPoint(Assembly assembly)
        {
            //Loop through all of the generated types
            foreach (Type type in assembly.GetTypes())
            {
                //If we find one that has a static Main method, lets return it
                if (type.GetMethod("Main") != null && 
type.GetMethod("Main").IsStatic)
                    return type;
            }
            //If we get to here, we got no entry point :-(
            throw new Exception("Unable to find a class with a valid entry 
point within the script!");
        }
    }

    /// <summary>
    /// This contains options for calling MonoScript with
    /// </summary>
    class MonoScriptOptions
    {
        #region Private Variables

        private string[] _references = new string[0];
        private string _sourceFile;
        private bool _noLogo = false;
        private bool _displayUsage = false;
        private bool _validateOnly = false;
        private StringCollection optionArgs = new StringCollection();

        #endregion

        #region Properties

        /// <summary>
        /// This specifies that no logo should be shown for the MonoScript app
        /// </summary>
        public bool NoLogo
        {
            get
            {
                return _noLogo;
            }
        }

        /// <summary>
        /// This specifies that the MonoScript usage should be displayed
        /// </summary>
        public bool DisplayUsage
        {
            get
            {
                return _displayUsage;
            }
        }

        /// <summary>
        /// This specifies that the source file shouldn't be executed as a 
script; just that it should be 
        /// compiled and validated to ensure it is a valid source file
        /// </summary>
        public bool ValidateOnly
        {
            get
            {
                return _validateOnly;
            }
        }

        /// <summary>
        /// Any assembly references needed to compile the script
        /// </summary>
        public string[] References
        {
            get
            {
                return _references;
            }
        }

        /// <summary>
        /// The source file acting as the script
        /// </summary>
        public string SourceFile
        {
            get
            {
                if(_sourceFile==null)
                        throw new Exception("No source file specified!");
                return _sourceFile;
            }
        }

        /// <summary>
        /// The arguments to call the script with
        /// </summary>
        public string[] ScriptArgs
        {
            get
            {
                string[] args = new string[optionArgs.Count];
                for (int i = 0; i < args.Length; i++)
                    args[i] = optionArgs[i];
                return args;
            }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor
        /// </summary>
        public MonoScriptOptions(string[] args)
        {
            //Validate
            if(args==null||args.Length==0)
                throw new Exception("No arguments specified!");

            //Add in args
            optionArgs.AddRange(args);

            //Fill out options
            _sourceFile = GetArgument("sourceFile");

            string noLogo = GetArgument("noLogo");
            _noLogo = (noLogo != null && noLogo.ToLower() == "true") ? true : 
false;

            string displayUsage = GetArgument("displayUsage");
            _displayUsage = (displayUsage != null && displayUsage.ToLower() == 
"true") ? true : false;

            string validateOnly = GetArgument("validateOnly");
            _validateOnly = (validateOnly != null && validateOnly.ToLower() == 
"true") ? true : false;

            string references = GetArgument("references");
            if(references!=null)
                _references = references.Split(Convert.ToChar(","));
        }

        #endregion

        #region Methods

        /// <summary>
        /// This retrieves an argument value from the list of arguments
        /// If it finds a requested argument, it then removes it from the list 
of arguments
        /// 
        /// If you request the argument for the command "references", any 
argument such as:
        /// --references:[VALUE]
        /// -r:[VALUE]
        /// /r:[VALUE]
        /// 
        /// will all result in the returning of "[VALUE]"
        /// If more than one is specified, they will be taken in the above order
        /// </summary>
        /// <param name="requestedCmd"></param>
        /// <returns></returns>
        private string GetArgument(string requestedCmd)
        {
            //These variables are used throughout
            string value = null;
            string arg = null;
            //Loop through all arguments
            for(int i=0;i<optionArgs.Count;i++)
            {
                arg = optionArgs[i];
                //Prepare the first format of the requested command to search 
for
                string cmd = string.Format("--{0}:", requestedCmd);
                if (arg.IndexOf(cmd) != -1)
                {
                    //If it's found, then set the value, and break the loop
                    value = arg.Substring(
                        0 + cmd.Length,
                        arg.Length - cmd.Length);
                    break;
                }
                //Try the next format of the requested command
                cmd = string.Format("-{0}:", requestedCmd[0]);
                if (arg.IndexOf(cmd) != -1)
                {
                    //Again, if found, set the value and break out of the loop
                    value = arg.Substring(
                        0 + cmd.Length,
                        arg.Length - cmd.Length);
                    break;
                }
                //Finally try the last format of the requested command
                cmd = string.Format("/{0}:", requestedCmd[0]);
                if (arg.IndexOf(cmd) != -1)
                {
                    //Set value, break loop
                    value = arg.Substring(
                        0 + cmd.Length,
                        arg.Length - cmd.Length);
                    break;
                }
            }

            //If we have got here with a value set, then we found our argument 
value, so remove the argument,
            //and return our value
            if (value != null)
            {
                optionArgs.Remove(arg);
                return value;
            }

            //Otherwise, return null
            return null;
        }

        #endregion
    }
}
_______________________________________________
Mono-list maillist  -  Mono-list@lists.ximian.com
http://lists.ximian.com/mailman/listinfo/mono-list

Reply via email to