netclectic
6/11/2013 - 3:38 AM

ScriptCs as embedded scripting engine for .Net application with NuGet support

ScriptCs as embedded scripting engine for .Net application with NuGet support

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="FluentAutomation.SeleniumWebDriver" version="2.0.0.2" targetFramework="net45" />
	<package id="Newtonsoft.Json" version="5.0.5" targetFramework="net45" />
	<package id="ScriptCs.ClrDiagnostics" targetFramework="net45" />
</packages>
// AutoFac configuration
public class ScriptModule : Autofac.Module
{
    protected override void Load(ContainerBuilder builder)
    {
        builder
            .RegisterType<ScriptCs.FileSystem>()
            .As<ScriptCs.IFileSystem>()
            .SingleInstance();
        
        builder
            .RegisterType<ConsoleOutLogger>()
            .As<ILog>()
            .SingleInstance()
            .WithParameter("logName", @"Custom ScriptCs from C#") 
            .WithParameter("logLevel", Common.Logging.LogLevel.All)
            .WithParameter("showLevel", true)
            .WithParameter("showDateTime", true) 
            .WithParameter("showLogName", true) 
            .WithParameter("dateTimeFormat", @"yyyy-mm-dd hh:mm:ss"); 
         
        builder
            .RegisterType<FilePreProcessor>()
            .As<IFilePreProcessor>()
            .SingleInstance();
        
        builder
            .RegisterType<ScriptHostFactory>()
            .As<IScriptHostFactory>()
            .SingleInstance();
        
        builder
            .RegisterType<RoslynScriptEngine>()
            .As<IScriptEngine>();
            
        builder
            .RegisterType<ScriptExecutor>()
            .As<IScriptExecutor>();
        
        builder
            .RegisterType<NugetInstallationProvider>()
            .As<IInstallationProvider>()
            .SingleInstance();
        
        builder
            .RegisterType<PackageAssemblyResolver>()
            .As<IPackageAssemblyResolver>()
            .SingleInstance();
        
        builder
            .RegisterType<PackageContainer>()
            .As<IPackageContainer>()
            .SingleInstance();
        
        builder
            .RegisterType<PackageInstaller>()
            .As<IPackageInstaller>()
            .SingleInstance();
        
        builder
            .RegisterType<PackageManager>()
            .As<IPackageManager>()
            .SingleInstance();
        
        builder
            .RegisterType<ScriptPackResolver>()
            .As<IScriptPackResolver>()
            .SingleInstance();
            
        builder
            .RegisterType<ExecuteScriptCs>();
    }
}
void Main()
{
    const string scriptPath = @".\EmbededScriptCsWithNuGetSupport.csx";
    
    // AutoFac container
    var builder = new ContainerBuilder();
    
    // register ScripotCs specific module
    builder.RegisterModule(new ScriptModule());
    
    using(var container = builder.Build())
    {
        using (var scope = container.BeginLifetimeScope())
        {
            var logger = scope.Resolve<ILog>();
            var executeScriptCs = scope.Resolve<ExecuteScriptCs>();
        
            try
            {
                executeScriptCs.Run(scriptPath);
            }
            catch(Exception ex)
            {
                logger.Error(ex);
                throw;
            }
        }
    }
}
public class ExecuteScriptCs
{
    // dependencies
    private readonly ILog logger;
    private readonly ScriptCs.IFileSystem fileSystem;
    private readonly IPackageAssemblyResolver packageAssemblyResolver;
    private readonly IPackageInstaller packageInstaller;
    private readonly IScriptPackResolver scriptPackResolver;
    private readonly IScriptExecutor scriptExecutor;
     
    public ExecuteScriptCs(ILog logger, ScriptCs.IFileSystem fileSystem, 
                            IPackageAssemblyResolver packageAssemblyResolver, 
                            IPackageInstaller packageInstaller, IScriptPackResolver scriptPackResolver, 
                            IScriptExecutor scriptExecutor)
    {
        this.logger = logger;
        this.fileSystem = fileSystem;
        this.packageAssemblyResolver = packageAssemblyResolver;
        this.packageInstaller = packageInstaller;
        this.scriptPackResolver = scriptPackResolver;
        this.scriptExecutor = scriptExecutor;
    }
    
    // run script from file
    public void Run(string scriptPath)
    {
        // preserve current directory
        var previousCurrentDirectory = Environment.CurrentDirectory;
        
        try
        {
            // set directory to where script is
            // required to find NuGet dependencies
            Environment.CurrentDirectory = Path.GetDirectoryName(scriptPath);
        
            // prepare NuGet dependencies, download them if required
            var nuGetReferences = PreparePackages(
                                            scriptPath,
                                            fileSystem, packageAssemblyResolver,
                                            packageInstaller, logger.Info);
            
            // get script packs: not fully tested yet        
            var scriptPacks = scriptPackResolver.GetPacks();
            
            // execute script from file
            scriptExecutor.Initialize(nuGetReferences, scriptPacks);
            scriptExecutor.Execute(scriptPath);
        }
        finally 
        {
            // restore current directory
            Environment.CurrentDirectory = previousCurrentDirectory;
        }
    }
    
    // prepare NuGet dependencies, download them if required
    private static IEnumerable<string> PreparePackages(
                            string scriptPath,
                            ScriptCs.IFileSystem fileSystem, IPackageAssemblyResolver packageAssemblyResolver,
                            IPackageInstaller packageInstaller, Action<string> outputCallback = null)
    {
        var workingDirectory = Path.GetDirectoryName(scriptPath);
        var binDirectory = Path.Combine(workingDirectory, ScriptCs.Constants.BinFolder);
    
        var packages = packageAssemblyResolver.GetPackages(workingDirectory);
        
        packageInstaller.InstallPackages(
                            packages,
                            allowPreRelease: true, packageInstalled: outputCallback);
    
        // current implementeation of RoslynCTP required dependencies to be in 'bin' folder
        if (!fileSystem.DirectoryExists(binDirectory))
        {
            fileSystem.CreateDirectory(binDirectory);
        }
    
        // copy dependencies one by one from 'packages' to 'bin'
        foreach(var assemblyName 
                    in packageAssemblyResolver.GetAssemblyNames(workingDirectory, outputCallback))
        {
            var assemblyFileName = Path.GetFileName(assemblyName);
            var destFile = Path.Combine(binDirectory, assemblyFileName);
        
            var sourceFileLastWriteTime = fileSystem.GetLastWriteTime(assemblyName);
            var destFileLastWriteTime = fileSystem.GetLastWriteTime(destFile);
    
            if (sourceFileLastWriteTime == destFileLastWriteTime)
            {
                outputCallback(string.Format("Skipped: '{0}' because it is already exists", assemblyName));
            }
            else
            {
                fileSystem.Copy(assemblyName, destFile, overwrite: true);
                
                if(outputCallback != null)
                {
                    outputCallback(string.Format("Copy: '{0}' to '{1}'", assemblyName, destFile));
                }
            }        
            
            yield return destFile;
        }
    }
}
// ScriptCs sample with Newtonsoft.Json — just for test
using Newtonsoft.Json;

var message = new { messaeg = "Hello, world!", timestamp = DateTime.Now };

Console.WriteLine(
  		JsonConvert.SerializeObject(
				message, 
				Newtonsoft.Json.Formatting.Indented));

ScriptCs as embedded scripting engine for .Net application with NuGet support

This gist contains:

  • ExecuteScriptCs.cs — class that are able to execute ScriptCs from another .Net application
  • ScriptModule.cs — AutoFac configuration for ScriptCs/NuGet dependencies
  • Program.cs — command-line example
  • Sample.csx — sample ScriptCs script
  • packages.config — NuGet packages configuration

Support: ScriptCs 0.5.0.0