예제 #1
0
        static void Main(string[] args)
        {
            var cli = new CommandLineApplication();

            cli.ResponseFileHandling = ResponseFileHandling.ParseArgsAsLineSeparated;
            cli.HelpOption();
            var paths          = cli.Argument("paths", "The input dlls or directories of dlls to instrument", true).IsRequired();
            var outputOption   = cli.Option("-o|--output <DIR>", "The directory where output files will be written", CommandOptionType.SingleValue);
            var refPathsOption = cli.Option("-r|--reference <DIR>", "Directory to search for references", CommandOptionType.MultipleValue);
            var exRegexOption  = cli.Option("-x|--exclude <REGEX>", "A regular expression used to exclude methods for instrumentation.", CommandOptionType.MultipleValue);
            var incRegexOption = cli.Option("-i|--include <REGEX>", "A regular expression used to include methods for instrumentation.", CommandOptionType.MultipleValue);

            cli.OnExecute(() =>
            {
                var processors  = new List <InstrumentationProcessor>();
                var directories = new HashSet <string>();
                foreach (var path in paths.Values)
                {
                    if (File.Exists(path))
                    {
                        if (path.EndsWith(".dll"))
                        {
                            processors.Add(new FileProcessor(path));
                            string dir = Path.GetDirectoryName(Path.GetFullPath(path));
                            directories.Add(dir);
                        }
                        else if (path.EndsWith(".zip"))
                        {
                            processors.Add(new ZipProcessor(path));
                        }
                    }
                    else if (Directory.Exists(path))
                    {
                        processors.Add(new DirectoryProcessor(path));
                        directories.Add(path);
                    }
                }

                if (processors.Count == 0)
                {
                    Console.WriteLine("No assemblies found");
                    return;
                }

                string toolsAsmPath = LocateToolsAssembly();
                var globalResolver  = new DefaultAssemblyResolver();
                foreach (var dir in directories)
                {
                    globalResolver.AddSearchDirectory(dir);
                }

                foreach (var refPath in refPathsOption.Values)
                {
                    globalResolver.AddSearchDirectory(refPath);
                }

#if DEBUG
                string resolverPaths = Environment.GetEnvironmentVariable("MTGINSTR_RESOLVERPATH");
                if (resolverPaths != null)
                {
                    Console.WriteLine("Adding debugging assembly resolver logic");
                    foreach (var path in resolverPaths.Split(";"))
                    {
                        Console.WriteLine($"Added resolver path: {path}");
                        globalResolver.AddSearchDirectory(path);
                    }
                }
#endif

                var readerParams = new ReaderParameters()
                {
                    AssemblyResolver = globalResolver
                };

                var toolsAsm = AssemblyDefinition.ReadAssembly(toolsAsmPath, readerParams);

                string outputDirectory = Environment.CurrentDirectory;
                if (outputOption.HasValue())
                {
                    outputDirectory = outputOption.Value();
                    Console.WriteLine($"Output directory: {outputDirectory}");
                }

                var toolsContext = new ToolsAssemblyContext(toolsAsm);

                var opts = new InstrumenterOptions();
                opts.Excludes.AddRange(exRegexOption.Values);
                opts.Includes.AddRange(incRegexOption.Values);

                var instrumenter      = new AssemblyInstrumenter(toolsContext, opts);
                var processingContext = new ProcessingContext()
                {
                    OutputDirectory = outputDirectory,
                    Instrumenter    = instrumenter,
                    ReaderParams    = readerParams
                };

                int success = 0;
                foreach (var processor in processors)
                {
                    try
                    {
                        Console.WriteLine($"Processing {processor.DisplayName}");

                        processor.Process(processingContext);

                        Console.WriteLine($"Done processing {processor.DisplayName}");

                        success++;
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine($"Error processing {processor.DisplayName}");
                        Console.WriteLine($"Error details: {e}");
                    }
                }

                if (success > 0)
                {
                    Console.WriteLine($"Successfully processed {success} items");
                }
            });

            cli.Execute(args);
        }
예제 #2
0
        public override void Process(ProcessingContext context)
        {
            using var inputZipFs   = File.OpenRead(ZipFile);
            using var inputArchive = new ZipArchive(inputZipFs);

            string outputFile = Path.Combine(context.OutputDirectory, Path.GetFileName(ZipFile));

            using var outputZipFs   = new FileStream(outputFile, FileMode.Create);
            using var outputArchive = new ZipArchive(outputZipFs, ZipArchiveMode.Create);

            bool   isModZip      = false;
            var    metadataEntry = inputArchive.GetEntry("metadata.txt");
            string primaryDll    = null;

            if (metadataEntry != null)
            {
                isModZip   = true;
                primaryDll = GetPrimaryDllName(metadataEntry);
                if (primaryDll != null)
                {
                    Console.WriteLine("Appears to be a mod zip. Handling primary dll only.");
                }
            }

            foreach (var entry in inputArchive.Entries)
            {
                using var entryStream = entry.Open();

                bool shouldProcess = entry.FullName.EndsWith(".dll");
                if (isModZip && primaryDll != null)
                {
                    shouldProcess = entry.Name == primaryDll;
                }

                if (shouldProcess)
                {
                    // we need a seekable stream to read so we have to move the whole uncompressed file into memory.
                    int length = checked ((int)entry.Length);
                    using var inputMs = new MemoryStream(length);
                    entryStream.CopyTo(inputMs);
                    inputMs.Seek(0, SeekOrigin.Begin);

                    using var asmDef = context.Instrumenter.InstrumentStream(inputMs, context.ReaderParams);
                    var outputEntry = outputArchive.CreateEntry(entry.FullName);

                    // also need a seekable stream for output... sigh
                    using var outputMs = new MemoryStream();
                    asmDef.Write(outputMs);
                    outputMs.Seek(0, SeekOrigin.Begin);

                    using var outputStream = outputEntry.Open();
                    outputMs.CopyTo(outputStream);
                }
                else
                {
                    var outputEntry = outputArchive.CreateEntry(entry.FullName);
                    using var outputStream = outputEntry.Open();
                    entryStream.CopyTo(outputStream);
                }
            }
        }
 public abstract void Process(ProcessingContext context);