/// <summary> /// Generates the name of the cache directory for the specified script file. /// </summary> /// <param name="file">Script file name.</param> /// <returns>Cache directory name.</returns> public static string GetCacheDirectory(string file) { string commonCacheDir = Path.Combine(CSScript.GetScriptTempDir(), "cache"); string cacheDir; string directoryPath = Path.GetDirectoryName(Path.GetFullPath(file)); string dirHash; if (Runtime.IsWin) { //Win is not case-sensitive so ensure, both lower and capital case path yield the same hash dirHash = directoryPath.ToLower().GetHashCodeEx().ToString(); } else { dirHash = directoryPath.GetHashCodeEx().ToString(); } cacheDir = Path.Combine(commonCacheDir, dirHash); if (!Directory.Exists(cacheDir)) { try { Directory.CreateDirectory(cacheDir); } catch (UnauthorizedAccessException) { var parentDir = commonCacheDir; if (!Directory.Exists(commonCacheDir)) { parentDir = Path.GetDirectoryName(commonCacheDir); // GetScriptTempDir() } throw new Exception("You do not have write privileges for the CS-Script cache directory (" + parentDir + "). " + "Make sure you have sufficient privileges or use an alternative location as the CS-Script " + "temporary directory (cscs -config:set=CustomTempDirectory=<new temp dir>)"); } } string infoFile = Path.Combine(cacheDir, "css_info.txt"); if (!File.Exists(infoFile)) { try { using (var sw = new StreamWriter(infoFile)) { sw.WriteLine(Environment.Version.ToString()); sw.WriteLine(directoryPath); } } catch { //there can be many reasons for the failure (e.g. file is already locked by another writer), //which in most of the cases does not constitute the error but rather a runtime condition } } return(cacheDir); }
/// <summary> /// Compiles the specified script text. /// </summary> /// <param name="scriptText">The script text.</param> /// <param name="scriptFile">The script file.</param> /// <param name="info">The information.</param> /// <returns>The method result.</returns> override protected (byte[] asm, byte[] pdb) Compile(string scriptText, string scriptFile, CompileInfo info) { string tempScriptFile = null; string injection_file = null; try { if (scriptFile == null) { tempScriptFile = CSScript.GetScriptTempFile(); File.WriteAllText(tempScriptFile, scriptText); } var project = Project.GenerateProjectFor(tempScriptFile ?? scriptFile); var refs = project.Refs.Concat(this.GetReferencedAssembliesFiles()).Distinct().ToArray(); var sources = project.Files; if (info?.AssemblyFile != null) { injection_file = CoreExtensions.GetScriptedCodeAttributeInjectionCode(info.AssemblyFile); sources = sources.Concat(new[] { injection_file }).ToArray(); } int scriptHash = 0; if (IsCachingEnabled) { var hashableCode = new StringBuilder(); hashableCode.Append($"{scriptText}.{scriptFile?.GetFullPath()}"); foreach (string dependencyScript in sources) { hashableCode.Append(File.ReadAllText(dependencyScript).GetHashCode()); } scriptHash = $"{scriptText}.{scriptFile?.GetFullPath()}".GetHashCode(); // not very sophisticated (e.g. not all ref asms are // included in hashing) // but adequate if (scriptCache.ContainsKey(scriptHash)) { return(scriptCache[scriptHash]); } } (byte[], byte[])result = CompileAssemblyFromFileBatch_with_Csc(sources, refs, info?.AssemblyFile, this.IsDebug, info); if (IsCachingEnabled) { scriptCache[scriptHash] = result; } return(result); } finally { if (this.IsDebug) { CSScript.NoteTempFile(tempScriptFile); } else { tempScriptFile.FileDelete(rethrow: false); } injection_file.FileDelete(rethrow: false); CSScript.StartPurgingOldTempFiles(ignoreCurrentProcessScripts: true); } }
/// <summary> /// Wraps C# code fragment into auto-generated class (type name <c>DynamicClass</c>), evaluates it and loads /// the class to the current AppDomain. /// </summary> /// <example>The following is the simple example of the LoadMethod usage: /// <code> /// dynamic script = CSScript.RoslynEvaluator /// .LoadMethod(@"int Product(int a, int b) /// { /// return a * b; /// }"); /// /// int result = script.Product(3, 2); /// </code> /// </example> /// <param name="code">The C# script text.</param> /// <returns>Instance of the first class defined in the script.</returns> public object LoadMethod(string code) { string scriptText = CSScript.WrapMethodToAutoClass(code, false, false); return(LoadCodeByName(scriptText, $"*.{Globals.DynamicWrapperClassName}")); }
/// <summary> /// Wraps C# code fragment into auto-generated class (type name <c>DynamicClass</c>), evaluates it and loads /// the class to the current AppDomain. /// <para> /// After initializing the class instance it is aligned to the interface specified by the parameter <c>T</c>. /// </para> /// </summary> /// <example>The following is the simple example of the interface alignment: /// <code> /// public interface ICalc /// { /// int Sum(int a, int b); /// int Div(int a, int b); /// } /// .... /// ICalc script = CSScript.RoslynEvaluator /// .LoadMethod<ICalc>(@"public int Sum(int a, int b) /// { /// return a + b; /// } /// public int Div(int a, int b) /// { /// return a/b; /// }"); /// int result = script.Div(15, 3); /// </code> /// </example> /// <typeparam name="T">The type of the interface type the script class instance should be aligned to.</typeparam> /// <param name="code">The C# script text.</param> /// <returns>Aligned to the <c>T</c> interface instance of the auto-generated class defined in the script.</returns> public T LoadMethod <T>(string code) where T : class { string scriptText = CSScript.WrapMethodToAutoClass(code, false, false, typeof(T).FullName); return(LoadCode <T>(scriptText)); }
/// <summary> /// Wraps C# code fragment into auto-generated class (type name <c>DynamicClass</c>) and evaluates it. /// <para> /// This method is a logical equivalent of <see cref="CSScriptLib.IEvaluator.CompileCode"/> but is allows you to define /// your script class by specifying class method instead of whole class declaration.</para> /// </summary> /// <example> ///<code> /// dynamic script = CSScript.RoslynEvaluator /// .CompileMethod(@"int Sum(int a, int b) /// { /// return a+b; /// }") /// .CreateObject("*"); /// /// var result = script.Sum(7, 3); /// </code> /// </example> /// <param name="code">The C# code.</param> /// <returns>The compiled assembly.</returns> public Assembly CompileMethod(string code) { string scriptText = CSScript.WrapMethodToAutoClass(code, false, false); return(CompileCode(scriptText)); }