[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