using System; using System.Collections.Generic; using System.IO; using System.IO.Compression; using System.Linq; using System.Reflection; namespace Disco.Services.Plugins.ManifestGenerator { class Program { static void Main(string[] args) { if (args.Length != 1) { throw new ArgumentException("Only one command-line argument is expected, the path to the plugin assembly"); } var assemblyPath = args[0]; var assemblyFileInfo = new FileInfo(assemblyPath); // Ensure File Exists if (!assemblyFileInfo.Exists) { throw new ArgumentException($"File not found at: {assemblyFileInfo.FullName}"); } Console.WriteLine("Disco Plugin: Generating Manifest"); AppDomain.CurrentDomain.AssemblyLoad += CurrentDomain_AssemblyLoad; AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve; // Load Plugin Assembly Assembly assembly; try { assembly = Assembly.LoadFile(assemblyFileInfo.FullName); } catch (Exception ex) { throw new Exception($"Unable to load the Assembly: {assemblyFileInfo.FullName}", ex); } // Load Reference Assemblies foreach (var referenceAssembly in assemblyFileInfo.Directory.GetFiles("*.dll")) { if (referenceAssembly.FullName != assemblyFileInfo.FullName) { if (!PluginManifest.PluginExcludedAssemblies.Any(excludeAssembly => referenceAssembly.Name.StartsWith(excludeAssembly, StringComparison.OrdinalIgnoreCase))) { try { Assembly.LoadFile(referenceAssembly.FullName); } catch (Exception ex) { Console.WriteLine($"Disco Plugin: Warning: Unable to load reference '{referenceAssembly.FullName}'; {ex.Message}"); } } } } // Create Manifest var manifest = PluginManifest.FromPluginAssembly(assembly); var manifestFilePath = Path.Combine(assemblyFileInfo.DirectoryName, "manifest.json"); File.WriteAllText(manifestFilePath, manifest.ToManifestFile()); Console.WriteLine("Disco Plugin: Manifest Created"); Console.WriteLine("Disco Plugin: Building Package"); var packageFileName = $"{manifest.Id}-{manifest.Version}.discoPlugin"; var packageFilePath = Path.Combine(assemblyFileInfo.DirectoryName, packageFileName); // Delete Existing Package Files foreach (var existingPackages in assemblyFileInfo.Directory.EnumerateFiles($"{manifest.Id}*.discoPlugin")) { existingPackages.Delete(); } // Exclude Disco Provided Assemblies List excludedFiles = PluginManifest.PluginExcludedAssemblies.ToList(); // Exclude the Package File excludedFiles.Add(packageFileName); using (FileStream packageStream = new FileStream(packageFilePath, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.None)) { using (ZipArchive package = new ZipArchive(packageStream, ZipArchiveMode.Create)) { BuildZipPackage(package, string.Empty, assemblyFileInfo.Directory, excludedFiles); } } Console.WriteLine($"Disco Plugin: Package Build: '{packageFileName}'"); } static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) { Console.WriteLine("CurrentDomain_AssemblyResolve: {0} - {1}", args.Name, args.RequestingAssembly.FullName); foreach (var loadedAssembly in AppDomain.CurrentDomain.GetAssemblies()) { if (loadedAssembly.FullName == args.Name) return loadedAssembly; } return null; } static void CurrentDomain_AssemblyLoad(object sender, AssemblyLoadEventArgs args) { Console.WriteLine("CurrentDomain_AssemblyLoad: {0} - {1}", args.LoadedAssembly.FullName, args.LoadedAssembly.Location); } static void BuildZipPackage(ZipArchive package, string relativePath, DirectoryInfo directory, List excludedFiles) { foreach (var subDirectory in directory.EnumerateDirectories()) { BuildZipPackage(package, string.Concat(relativePath, subDirectory.Name, "\\"), subDirectory, excludedFiles); } foreach (var file in directory.EnumerateFiles()) { if (!excludedFiles.Any(excludeRule => file.Name.StartsWith(excludeRule, StringComparison.OrdinalIgnoreCase))) { var archiveEntry = package.CreateEntry(string.Concat(relativePath, file.Name), CompressionLevel.Fastest); using (var archiveStream = archiveEntry.Open()) { using (var fileStream = file.OpenRead()) { fileStream.CopyTo(archiveStream); } } } } } } }