/// <param name="cfg">IModeCSharp configuration</param> /// <param name="msbuild">Flag of supporting MSBuild properties.</param> /// <returns>Prepared list of references</returns> protected string[] constructReferences(IModeCSharp cfg, bool msbuild) { if (cfg.References == null) { return(new string[] { }); } if (!cfg.SmartReferences) { return(cfg.References .Where(r => !String.IsNullOrEmpty(r)) .Select(r => (msbuild)? cmd.MSBuild.parse(r) : r) .ToArray()); } GAC gac = new GAC(); return(cfg.References .Where(r => !String.IsNullOrEmpty(r)) .Select(r => gac.getPathToAssembly( (msbuild)? cmd.MSBuild.parse(r) : r, true ) ) .ToArray()); }
/// <summary> /// Only compiling user code. /// Use the safe compileAndGetType for work with the end-type. /// </summary> /// <param name="evt">Configured event.</param> /// <returns>Compiled user code.</returns> protected CompilerResults onlyCompile(ISolutionEvent evt) { Log.Trace("[Compiler] start new compilation."); IModeCSharp cfg = (IModeCSharp)evt.Mode; string command = cfg.Command; if (String.IsNullOrWhiteSpace(command)) { throw new InvalidArgumentException("[Compiler] code is not found. abort;"); } command = parse(evt, command); string output = outputCacheFile(evt); Log.Debug("[Compiler] output: '{0}' /GenerateInMemory: {1}", output, cfg.GenerateInMemory); if (File.Exists(output)) { Log.Trace("[Compiler] clear cache."); File.Delete(output); } CompilerParameters parameters = new CompilerParameters() { GenerateExecutable = false, GenerateInMemory = cfg.GenerateInMemory, CompilerOptions = cfg.CompilerOptions, TreatWarningsAsErrors = cfg.TreatWarningsAsErrors, WarningLevel = cfg.WarningLevel, // use prefix from fileName() to avoid random names if used GenerateInMemory OutputAssembly = (!cfg.GenerateInMemory)? output : Path.Combine(Path.GetTempPath(), fileName(evt)) }; // Assembly references string[] references = constructReferences(cfg, evt.SupportMSBuild); Log.Trace("[Compiler] final references: '{0}'", String.Join("; ", references)); parameters.ReferencedAssemblies.AddRange(references); parameters.ReferencedAssemblies.Add(typeof(ISolutionEvent).Assembly.Location); // to support ICommand & ISolutionEvent parameters.ReferencedAssemblies.Add(typeof(Bridge.IEvent).Assembly.Location); // to support Bridge // ready to work with provider CompilerResults compiled = toBinary(command, parameters, cfg); // messages about errors & warnings foreach (CompilerError msg in compiled.Errors) { Log._.NLog.Log((msg.IsWarning)? LogLevel.Warn : LogLevel.Error, "[Compiler] '{0}'", msg.ToString()); } if (compiled.Errors.HasErrors) { throw new CompilerException("[Compiler] found errors. abort;"); } return(compiled); }
/// <summary> /// Recalculate hash for IModeCSharp mode and save in user settings. /// </summary> /// <param name="mode"></param> protected void updateHash(IModeCSharp mode) { if (mode.CacheData == null) { mode.CacheData = new UserValue(LinkType.CacheHeader); } // calculate hash only for objects below object[] toHash = new object[] { mode.Command, mode.References, mode.OutputPath, mode.CompilerOptions, mode.TreatWarningsAsErrors, mode.WarningLevel, mode.FilesMode }; mode.CacheData.Manager.CacheHeader.Hash = toHash.MD5Hash(); mode.CacheData.Manager.CacheHeader.Algorithm = HashType.MD5; mode.CacheData.Manager.CacheHeader.Updated = DateTime.Now.ToFileTimeUtc(); Settings.CfgManager.UserConfig.save(); }
/// <summary> /// Checks requirement of compiling source code. /// </summary> /// <param name="evt">Configured event.</param> /// <returns>true value if needed compilation, otherwise we can use compiled version from cache.</returns> protected bool isRequiresCompilation(ISolutionEvent evt) { IModeCSharp cfg = ((IModeCSharp)evt.Mode); string cache = fileName(evt); Log.Trace("[Cache] Checks: '{0}','{1}','{2}','{3}'", cfg.GenerateInMemory, cfg.CachingBytecode, evt.Name, cache); if (cfg.GenerateInMemory || !cfg.CachingBytecode || String.IsNullOrEmpty(cache)) { return(true); } if (cfg.CacheData == null) { Log.Trace("[Cache] hash data is empty."); return(true); } FileInfo f = new FileInfo(outputCacheFile(evt)); if (!f.Exists) { Log.Info("[Cache] Binary '{0}' is not found in '{1}'. Compile new.", cache, f.FullName); return(true); } string actual = cfg.CacheData.Manager.CacheHeader.Hash; if (!hashEquals(f.FullName, actual)) { Log.Info("[Cache] hash code '{0}' is invalid. Compile new.", actual); return(true); } return(false); }
/// <summary> /// To reset cache data. /// </summary> /// <param name="mode"></param> public void cacheReset(IMode mode) { if (mode.Type == ModeType.CSharp) { IModeCSharp cfg = (IModeCSharp)mode; if (cfg.CacheData != null) { cfg.CacheData.Manager.reset(); } } }
private string outputCacheFile(ISolutionEvent evt) { IModeCSharp cfg = (IModeCSharp)evt.Mode; string path = (cfg.OutputPath) ?? String.Empty; if (evt.SupportMSBuild) { path = cmd.MSBuild.parse(path); } return(Path.Combine(BasePathToCache, path, fileName(evt))); }
/// <summary> /// Prepare data to removing from cache. /// </summary> /// <param name="mode">Data from used mode.</param> public void cacheToRemove(IMode mode) { if (mode.Type == ModeType.CSharp) { IModeCSharp cfg = (IModeCSharp)mode; if (cfg.CacheData == null) { return; } Settings.CfgUser.toRemoveFromCache(cfg.CacheData); cacheUnlink(mode); } }
/// <summary> /// Compiling user code with getting the result type for next step. /// </summary> /// <param name="evt">Configured event.</param> /// <returns>The Type for work with user code.</returns> protected Type compileAndGetType(ISolutionEvent evt) { IModeCSharp cfg = (IModeCSharp)evt.Mode; if (!cfg.GenerateInMemory) { CompilerResults compiled = onlyCompile(evt); return(load(compiled.PathToAssembly, null)); } Log.Trace("Uses memory for getting type."); // be careful, this should automatically load assembly with blocking file if not used GenerateInMemory // therefore, use this only with GenerateInMemory == true return(onlyCompile(evt).CompiledAssembly.GetType(MAIN_CLASS)); }
/// <summary> /// How to store hash value in assembly. /// </summary> /// <param name="cfg">IModeCSharp configuration.</param> /// <returns>Formatted hash value for assembly.</returns> protected virtual string formatHashForAsm(IModeCSharp cfg) { if (!cfg.CachingBytecode) { return(String.Empty); } if (cfg.CacheData == null || String.IsNullOrEmpty(cfg.CacheData.Manager.CacheHeader.Hash)) { updateHash(cfg); } string hash = cfg.CacheData.Manager.CacheHeader.Hash; if (String.IsNullOrEmpty(hash)) { return(String.Empty); } return(String.Format("[assembly: System.Reflection.AssemblyProduct(\"{0}\")]", hash)); }
/// <summary> /// Final step to generate binary. /// </summary> /// <param name="source">Source code or list of files.</param> /// <param name="parameters">Compiler settings.</param> /// <param name="cfg">Settings of IModeCSharp.</param> /// <returns></returns> protected CompilerResults toBinary(string source, CompilerParameters parameters, IModeCSharp cfg) { string hash = formatHashForAsm(cfg); CSharpCodeProvider provider = new CSharpCodeProvider(); if (!cfg.FilesMode) { return(provider.CompileAssemblyFromSource(parameters, source, hash)); } Log.Trace("[Compiler] use as list of files with source code."); if (String.IsNullOrEmpty(hash)) { return(provider.CompileAssemblyFromFile(parameters, filesFromCommand(source).ExtractFiles())); } using (TempAssemblyInfo f = new TempAssemblyInfo(hash)) { return(provider.CompileAssemblyFromFile(parameters, filesFromCommand(String.Format("{0}\n{1}", source, f.FullPath)).ExtractFiles())); } }
/// <summary> /// Recalculate hash for IModeCSharp mode and save in user settings. /// </summary> /// <param name="mode"></param> protected void updateHash(IModeCSharp mode) { if(mode.CacheData == null) { mode.CacheData = new UserValue(LinkType.CacheHeader); } // calculate hash only for objects below object[] toHash = new object[] { mode.Command, mode.References, mode.OutputPath, mode.CompilerOptions, mode.TreatWarningsAsErrors, mode.WarningLevel, mode.FilesMode }; mode.CacheData.Manager.CacheHeader.Hash = toHash.MD5Hash(); mode.CacheData.Manager.CacheHeader.Algorithm = HashType.MD5; mode.CacheData.Manager.CacheHeader.Updated = DateTime.Now.ToFileTimeUtc(); Settings.CfgManager.UserConfig.save(); }
/// <summary> /// Final step to generate binary. /// </summary> /// <param name="source">Source code or list of files.</param> /// <param name="parameters">Compiler settings.</param> /// <param name="cfg">Settings of IModeCSharp.</param> /// <returns></returns> protected CompilerResults toBinary(string source, CompilerParameters parameters, IModeCSharp cfg) { string hash = formatHashForAsm(cfg); CSharpCodeProvider provider = new CSharpCodeProvider(); if(!cfg.FilesMode) { return provider.CompileAssemblyFromSource(parameters, source, hash); } Log.Trace("[Compiler] use as list of files with source code."); if(String.IsNullOrEmpty(hash)) { return provider.CompileAssemblyFromFile(parameters, extractFiles(filesFromCommand(source))); } using(TempAssemblyInfo f = new TempAssemblyInfo(hash)) { return provider.CompileAssemblyFromFile(parameters, extractFiles(filesFromCommand(String.Format("{0}\n{1}", source, f.FullPath)))); } }
/// <summary> /// How to store hash value in assembly. /// </summary> /// <param name="cfg">IModeCSharp configuration.</param> /// <returns>Formatted hash value for assembly.</returns> protected virtual string formatHashForAsm(IModeCSharp cfg) { if(!cfg.CachingBytecode) { return String.Empty; } if(cfg.CacheData == null || String.IsNullOrEmpty(cfg.CacheData.Manager.CacheHeader.Hash)) { updateHash(cfg); } string hash = cfg.CacheData.Manager.CacheHeader.Hash; if(String.IsNullOrEmpty(hash)) { return String.Empty; } return String.Format("[assembly: System.Reflection.AssemblyProduct(\"{0}\")]", hash); }
/// <param name="cfg">IModeCSharp configuration</param> /// <param name="msbuild">Flag of supporting MSBuild properties.</param> /// <returns>Prepared list of references</returns> protected string[] constructReferences(IModeCSharp cfg, bool msbuild) { if(cfg.References == null) { return new string[] { }; } if(!cfg.SmartReferences) { return cfg.References .Where(r => !String.IsNullOrEmpty(r)) .Select(r => (msbuild)? cmd.MSBuild.parse(r) : r) .ToArray(); } GAC gac = new GAC(); return cfg.References .Where(r => !String.IsNullOrEmpty(r)) .Select(r => gac.getPathToAssembly( (msbuild)? cmd.MSBuild.parse(r) : r, true ) ) .ToArray(); }