/// <summary> /// Get pdb file path<br/> /// 获取pdb文件的路径<br/> /// </summary> /// <param name="info">Plugin information</param> /// <returns></returns> public static string AssemblyPdbPath(this PluginInfo info) { return(Path.Combine(info.BinDirectory(), $"{info.DirectoryName()}.pdb")); }
/// <summary> /// Get source directory<br/> /// 获取源代码目录的路径<br/> /// </summary> /// <param name="info">Plugin information</param> /// <returns></returns> public static string SourceDirectory(this PluginInfo info) { return(Path.Combine(info.Directory, "src")); }
/// <summary> /// Get binary directory<br/> /// Path contains target platform name<br/> /// 获取程序集目录的路径<br/> /// 路径会包含平台名称<br/> /// </summary> /// <param name="info">Plugin information</param> /// <returns></returns> public static string BinDirectory(this PluginInfo info) { var compilerService = Application.Ioc.Resolve <ICompilerService>(); return(Path.Combine(info.Directory, "bin", compilerService.TargetPlatform)); }
/// <summary> /// Get directory name<br/> /// 获取目录名称<br/> /// </summary> /// <param name="info">Plugin information</param> /// <returns></returns> public static string DirectoryName(this PluginInfo info) { return(Path.GetFileName(info.Directory)); }
/// <summary> /// Compile plugin<br/> /// 编译插件<br/> /// </summary> /// <param name="info">Plugin information</param> public static void Compile(this PluginInfo info) { // Get source files and releated paths var sourceDirectory = info.SourceDirectory(); var sourceFiles = info.SourceFiles(); var assemblyName = info.DirectoryName(); var assemblyPath = info.AssemblyPath(); var assemblyPdbPath = info.AssemblyPdbPath(); var compileInfoPath = info.CompileInfoPath(); // Load reference assemblies var assemblyLoader = Application.Ioc.Resolve <IAssemblyLoader>(); foreach (var reference in info.References) { assemblyLoader.Load(reference); } // Check if recompile is needed // If no source files exists then no need to compile var existCompileInfo = ""; if (File.Exists(compileInfoPath)) { existCompileInfo = File.ReadAllText(compileInfoPath); } var compileInfo = string.Join("\r\n", sourceFiles .Select(s => new { path = s.Substring(sourceDirectory.Length + 1), time = File.GetLastWriteTime(s) }) // Relative path and modify time .OrderBy(s => s.path) // Order by path .Select(s => $"{s.path} {s.time}")); // Generate line if (sourceFiles.Length > 0 && compileInfo != existCompileInfo) { // Rename old files if (File.Exists(assemblyPath)) { File.Move(assemblyPath, $"{assemblyPath}.{DateTime.UtcNow.Ticks}.old"); } if (File.Exists(assemblyPdbPath)) { File.Move(assemblyPdbPath, $"{assemblyPdbPath}.{DateTime.UtcNow.Ticks}.old"); } // Invoke compile service // Default use debug configuration Directory.CreateDirectory(Path.GetDirectoryName(assemblyPath)); var configManager = Application.Ioc.Resolve <WebsiteConfigManager>(); var release = configManager.WebsiteConfig.Extra.GetOrDefault <bool?>( ExtraConfigKeys.CompilePluginsWithReleaseConfiguration) ?? false; var compilerService = Application.Ioc.Resolve <ICompilerService>(); var options = new CompilationOptions(); options.Release = release; options.GeneratePdbFile = true; compilerService.Compile(sourceFiles, assemblyName, assemblyPath, options); // Write compile information File.WriteAllText(compileInfoPath, compileInfo); // Remove old files, maybe they are locking but that's not matter Directory.EnumerateFiles(info.BinDirectory(), "*.old") .ForEach(path => { try { File.Delete(path); } catch { } }); } }
/// <summary> /// Get compile infomation path<br/> /// Contains source code paths and it's modify time,<br/> /// use to determine if recompile is needed<br/> /// 获取编译信息的路径<br/> /// 编译信息包含了源代码列表和它的修改时间, 用于检测是否需要重新编译<br/> /// </summary> /// <param name="info">Plugin information</param> /// <returns></returns> public static string CompileInfoPath(this PluginInfo info) { return(Path.Combine(info.BinDirectory(), "CompileInfo.txt")); }
/// <summary> /// Compile plugin<br/> /// 编译插件<br/> /// </summary> /// <param name="info">Plugin information</param> public static void Compile(this PluginInfo info) { // Get source files and releated paths var sourceDirectory = info.SourceDirectory(); var sourceFiles = info.SourceFiles(); var assemblyName = info.DirectoryName(); var assemblyPath = info.AssemblyPath(); var assemblyPdbPath = info.AssemblyPdbPath(); var compileInfoPath = info.CompileInfoPath(); // Load reference assemblies var assemblyLoader = Application.Ioc.Resolve <IAssemblyLoader>(); foreach (var reference in info.References) { assemblyLoader.Load(reference); } // Check if recompile is needed // If no source files exists then no need to compile var existCompileInfo = ""; if (File.Exists(compileInfoPath)) { existCompileInfo = File.ReadAllText(compileInfoPath); } var compileInfoBuilder = new StringBuilder(); compileInfoBuilder.AppendLine(Application.FullVersion); sourceFiles .Select(s => new { path = s.Substring(sourceDirectory.Length + 1), time = File.GetLastWriteTime(s) }) // Relative path and modify time .OrderBy(s => s.path) // Order by path .Select(s => $"{s.path} {s.time}") .ForEach(s => compileInfoBuilder.AppendLine(s)); var compileInfo = compileInfoBuilder.ToString(); if (sourceFiles.Length > 0 && compileInfo != existCompileInfo) { // Rename old files if (File.Exists(assemblyPath)) { File.Move(assemblyPath, $"{assemblyPath}.{DateTime.UtcNow.Ticks}.old"); } if (File.Exists(assemblyPdbPath)) { File.Move(assemblyPdbPath, $"{assemblyPdbPath}.{DateTime.UtcNow.Ticks}.old"); } // Invoke compile service // Default use debug configuration Directory.CreateDirectory(Path.GetDirectoryName(assemblyPath)); var configManager = Application.Ioc.Resolve <WebsiteConfigManager>(); var release = configManager.WebsiteConfig.Extra.GetOrDefault <bool?>( ExtraConfigKeys.CompilePluginsWithReleaseConfiguration) ?? false; var compilerService = Application.Ioc.Resolve <ICompilerService>(); var options = new CompilationOptions(); options.Release = release; options.GeneratePdbFile = true; compilerService.Compile(sourceFiles, assemblyName, assemblyPath, options); // Write compile information File.WriteAllText(compileInfoPath, compileInfo); // Remove old files, maybe they are locking but that's not matter Directory.EnumerateFiles(info.BinDirectory(), "*.old") .ForEach(path => { try { File.Delete(path); } catch { /* ignore error */ } }); // Call gc collect to avoid OOM #pragma warning disable S1215 // "GC.Collect" should not be called GC.Collect(); #pragma warning restore S1215 // "GC.Collect" should not be called GC.WaitForFullGCComplete(-1); GC.WaitForPendingFinalizers(); } }
/// <summary> /// Check whether to load this plugin or not<br/> /// 检查是否要加载此插件<br/> /// </summary> protected virtual bool ShouldLoadPlugin(PluginInfo pluginInfo) { return(true); }