[Mono-list] Scripting the Linux OS with Mono

Abe Gillespie abe.gillespie at gmail.com
Fri Nov 11 16:39:43 EST 2005


Dude, you totally rock!  I'll be giving this a try this weekend.

-Abe

On 11/11/05, Elliott Draper <el at eldiablo.co.uk> wrote:
> 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 <kornelpal at hotmail.com> 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" <abe.gillespie at gmail.com>
> >>To: "MonoList" <mono-list at 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 at lists.ximian.com
> >>http://lists.ximian.com/mailman/listinfo/mono-list
> >>
> >>
> >>
> >>
> >_______________________________________________
> >Mono-list maillist  -  Mono-list at 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 <el at eldiablo.co.uk>");
>         }
>
>         /// <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
>     }
> }
>
>
>


More information about the Mono-list mailing list